isakbob
isakbob

Reputation: 1539

Can I prevent the user from running my C++ program in the background?

I have a polling program in C++ that cannot run cleanly as a background process. Therefore I want to prevent the user from being able to use & after invoking the name of my program in a Linux terminal.

How can I prevent the user from invoking & after the name of my script?

Upvotes: 3

Views: 323

Answers (2)

isakbob
isakbob

Reputation: 1539

It is bad practice to do this. The UNIX convention is to assume that the user is doing the right thing and make accommodations accordingly. Either modify the program to make it run cleanly as a background process, or presume the user will pipe the output to something like /dev/null or a log.

Upvotes: 0

Ted Lyngmo
Ted Lyngmo

Reputation: 117178

While I agree with the comments saying that you should generally trust the users, this tries to answer the question as I've come to understand it from reading the comments ("If my program runs in the background, the command terminal is usable and operational, but the output of the program obscures user input and displaces the prompt").

This will not prevent the program from running, but streaming to std::cout will be discarded so the program can run without disturbing the user. Redirecting the output to a file or a pipe will still work.

#define _POSIX_SOURCE

#include <iostream>
#include <stdexcept>

#include <stdio.h>   // fileno
#include <unistd.h>  // isatty
#include <signal.h>  // signal
#include <fcntl.h>   // fcntl
#include <termios.h> // tcgetattr/tcsetattr

void handle_input(int /*sig*/) {
    signal(SIGTTIN, SIG_IGN);
    std::cin.setstate(std::ios::failbit);
}

void handle_output(int /*sig*/) {
    signal(SIGTTOU, SIG_IGN);
    std::cout.setstate(std::ios::failbit);
}

class TCAttr {
    int m_fd;
    termios m_attr;
public:
    TCAttr(int fd) : m_fd(fd), m_attr() {
        // get input, output and local attributes
        if(tcgetattr(m_fd, &m_attr) != 0)
            m_fd = -1;
    }
    TCAttr(FILE* fp) : TCAttr(fileno(fp)) {}
    TCAttr() : m_fd(-1), m_attr() {}
    ~TCAttr() {
        // restore original input, output and local attributes
        if(m_fd>=0)
            tcsetattr(m_fd, TCSADRAIN, &m_attr);
    }
    //
    bool set_lmode(tcflag_t flag) {
        termios tmp;
        if(tcgetattr(m_fd, &tmp)!=0) return false;
        tmp.c_lflag = flag;
        return tcsetattr(m_fd, TCSADRAIN, &tmp)==0;
    }
    bool add_lmode(tcflag_t flag) {
        termios tmp;
        if(tcgetattr(m_fd, &tmp)!=0) return false;
        tmp.c_lflag |= flag;
        return tcsetattr(m_fd, TCSADRAIN, &tmp)==0;
    }
    bool remove_lmode(tcflag_t flag) {
        termios tmp;
        if(tcgetattr(m_fd, &tmp)!=0) return false;
        tmp.c_lflag &= ~flag;
        return tcsetattr(m_fd, TCSADRAIN, &tmp)==0;
    }
};

int main() {
    TCAttr tca(stdout);

    if(isatty(fileno(stdin))) {
        // if tty input is requested in background mode
        // SIGTTIN will be sent
        signal(SIGTTIN, handle_input);
    }

    if(isatty(fileno(stdout))) {
        // if tty output is requested in background mode
        // SIGTTOU will be sent
        signal(SIGTTOU, handle_output);
        tca.add_lmode(TOSTOP);
    }

    std::cout << "Thanks for not streaming to a tty in background mode\n";
    std::string name;
    std::cin >> name;
    std::cout << name << "\n";
}

Upvotes: 1

Related Questions