Reputation: 1539
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
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
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