This is a discussion on CGI starting and stopping daemons. within the Apache Web Server forums, part of the Web Server and Related Forums category; I'm writing a CGI app that will provide a user interface to real hardware devices that are part of ...
|
|||||||
| FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
|
|||
|
I'm writing a CGI app that will provide a user interface to real hardware
devices that are part of the server, namely one or more SCSI tape drives. I have a perfectly functional console app that controls the SCSI device the way I want. It writes its pid to a file when it starts and sets it back to zero when it terminates. No other instance of this process can be started if one is already running. The process also writes it current state, every time it changes, to a status file. The process needs to run as a daemon. It needs to be started as a background process. It never returns, unless its pid is sent a kill signal. It will, most likely be started in /etc/rc.d/rc.local. I want to write a CGI app in C/C++. When the CGI app starts up, it reads the pid and status files. If the process is not running, it offers a "start" button. If the process is running, it offers a "stop" button. It calls back to the same CGI app with an argument to the app of start or stop that calls commands at the prompt using popen(). Like this: command = popen("process_name device_name &", "r"); // start command = popen((string("kill -HUP ") + pid).c_str(), "r"); // stop I think I need to stick a fork in it somewhere. the CGI shell has to terminate and that would kill the background process, right? There are also some issues as to who should own the SCSI device and the pid and status files. I did a chmod u+s as root to the console app that the CGI app calls. When I call the code above to start the process, it does return. A call to ps axf, from the console as root, shows that the console tape app is running, but the pid file still shows zero, the status file says "down" and the program doesn't work. Obviously, I can't kill a pid of zero. Any thoughts on this situation would be most appreciated! Thanks. Have a great day! James. :o) |
|
|||
|
"James Lehman" <james[remove]@akrobiz.com> wrote in message
news:zzKwc.1299$Jp.59508@ord-read.news.verio.net... > I'm writing a CGI app that will provide a user interface to real hardware > devices that are part of the server, namely one or more SCSI tape drives. I > have a perfectly functional console app that controls the SCSI device the > way I want. It writes its pid to a file when it starts and sets it back to > zero when it terminates. No other instance of this process can be started if > one is already running. The process also writes it current state, every time > it changes, to a status file. The process needs to run as a daemon. It needs > to be started as a background process. It never returns, unless its pid is > sent a kill signal. It will, most likely be started in /etc/rc.d/rc.local. > > I want to write a CGI app in C/C++. When the CGI app starts up, it reads the C/C++ is not a language, choose one or the other and stick to it. > pid and status files. If the process is not running, it offers a "start" > button. If the process is running, it offers a "stop" button. It calls back > to the same CGI app with an argument to the app of start or stop that calls > commands at the prompt using popen(). Like this: > > command = popen("process_name device_name &", "r"); // start > command = popen((string("kill -HUP ") + pid).c_str(), "r"); // stop > You probably don't want to use popen and you almost certainly do not want to use the & operator to "backgroundify" what you're running. > I think I need to stick a fork in it somewhere. the CGI shell has to > terminate and that would kill the background process, right? Yes, you do, maybe even two. If you fork one process from the CGI script, the parent will be required to wait() on its child, otherwise you will get zombies and that's a bad thing. You can either ignore SIGCHILD (man 3 signal) or fork two children. You then almost certainly want to be using one of the exec() family of functions. Try something like this: int forkpid; forkpid = fork(); if (forkpid ==0) { /* we're the child */ if (fork() == 0) { /* we're the child of the child */ execl("program") } exit(0); } else { while (wait(NULL) != forkpid) {} } > There are also some issues as to who should own the SCSI device and the pid > and status files. > > I did a chmod u+s as root to the console app that the CGI app calls. When I > call the code above to start the process, it does return. A call to ps axf, > from the console as root, shows that the console tape app is running, but > the pid file still shows zero, the status file says "down" and the program > doesn't work. Obviously, I can't kill a pid of zero. what does ps aux tell you is the pid of the application that's running? Sounds like a zombie to me.. > > Any thoughts on this situation would be most appreciated! You might try comp.unix.programmer in future as this isn't really an apache specific question. > > Thanks. > Have a great day! James. :o) > > > |
|
|||
|
> C/C++ is not a language, choose one or the other and stick to it.
I use classes with inheritance and virtual function to define my device, my tape, my specific tape drive, etc. The application also relies heavily on file descriptors, ioctl calls and signal trapping with a termination function. That's what I call C/C++. Parts of it a pure C. Parts of it are pure C++. I've also written polymorphic object oriented programming (POOP) in pure C. http://freshmeat.net/projects/ezfb/?...01%2C111%2C112 I know the difference between C and C++. > You probably don't want to use popen and you almost certainly do not want to > use the & operator to "backgroundify" what you're running. Why? It works like this from a script like /etc/rc.d/rc.local. I don't get how forking twice would get me anywhere better than once. > what does ps aux tell you is the pid of the application that's running? > Sounds like a zombie to me.. The process has a real number, but since root didn't start it, when I kill it or killall, I get no message of its termination. It's just gone. Since it has no effect on the pid or the status file, it can be started many times. This has a horrible effect on the machine in general. > You might try comp.unix.programmer in future as this isn't really an apache > specific question. Well it sort-of-is. It has everything to do with what the user apache can do on a machine that has lots of stuff owned by root AND it has to do specifically with the hidden shell that runs the CGI app that is inside of Apache and how it relates to a real shell in a real console. Smile. Be Happy. Look at some art. http://www.akrobiz.com/pc/gallery_index.html Take care. James. :o) |
|
|||
|
James Lehman wrote: >>C/C++ is not a language, choose one or the other and stick to it. > > > I use classes with inheritance and virtual function to define my device, my > tape, my specific tape drive, etc. The application also relies heavily on > file descriptors, ioctl calls and signal trapping with a termination > function. That's what I call C/C++. Parts of it a pure C. Parts of it are > pure C++. > > I've also written polymorphic object oriented programming (POOP) in pure C. > http://freshmeat.net/projects/ezfb/?...01%2C111%2C112 > > I know the difference between C and C++. > > >>You probably don't want to use popen and you almost certainly do not want > > to > >>use the & operator to "backgroundify" what you're running. > > > Why? It works like this from a script like /etc/rc.d/rc.local. > > I don't get how forking twice would get me anywhere better than once. > > >>what does ps aux tell you is the pid of the application that's running? >>Sounds like a zombie to me.. > > > The process has a real number, but since root didn't start it, when I kill > it or killall, I get no message of its termination. It's just gone. Since it > has no effect on the pid or the status file, it can be started many times. > This has a horrible effect on the machine in general. > > >>You might try comp.unix.programmer in future as this isn't really an > > apache > >>specific question. > > > Well it sort-of-is. It has everything to do with what the user apache can do > on a machine that has lots of stuff owned by root AND it has to do > specifically with the hidden shell that runs the CGI app that is inside of > Apache and how it relates to a real shell in a real console. > > Smile. Be Happy. Look at some art. > http://www.akrobiz.com/pc/gallery_index.html > > Take care. James. :o) > > > > Apache won't recognize that that a CGI script is done until the CGI script and all of its subprocesses exit (or at least send an EOF to stdout). Here is the proper method [adapted from Unix Network Programming Volume 1 - W. Richard Stevens]. // Block the hangup (HUP) signal. This is sent to all child processes // when their parent dies. The hangup signal's default action is to // terminate the proces. If we don't block it, the next statement // will terminate the parent. signal( SIGHUP, SIG_IGN ); // Now, we fork and exit the parent. This places the process in the // background, if ( fork() != 0 ) exit( 0 ); // At this point, we are in the background, but still attached to the // current login session (or CGI execution). We need to make it the // leader of it's own session. This will prevent it from receiving // hang up signals when the CGI script dies. setsid(); // Now, to be sure that we don't later send output that assigns us a // controlling terminal, we need to close all open file descriptors. // UNIX doesn't provide a way to either close all open files or to // determine how many descriptors we are using. We close the first // sixteen which should be PLENTY in a newly started app (we can // usually get away with just three, but we err on the side of safety // here). If you have a log file open a this point, it may well be // closed. Open your log file AFTER this segment of code. for ( int x = 0 ; x < 16 ; x++ ) close( x ); // Now, to go from the background process to a full daemon, we need to // fork yet again. This will make the process detached from any // session as it's session leader (the process from the first fork) // will be dead. signal( SIGHUP, SIG_IGN ); if ( fork() != 0 ) exit( 0 ); // You are now a properly created demon process and may do anything // else you like at this point. There is no stdout to printf() to. Hope this helps. Tim |
|
|||
|
Thanks for the info.
This looks pretty complicated. Since my goal is to start and stop another process, I think I will rewrite that process to look at the contents of a control file. If the file says "go", then go. If the files says "stop" then stop. The process can stay up the whole time and just act according to the control file. It will be very easy to write to a file and exit from a CGI script. That way, there is a complete separation from the CGI app and the daemon. I don't have to worry about who owns what. Take care. James. :o) "Tim Orbaker" <tim@orb.aker.com> wrote in message news:ZaadnbAbA6Xc61ndRVn-uA@wideopenwest.com... > > > James Lehman wrote: > >>C/C++ is not a language, choose one or the other and stick to it. > > > > > > I use classes with inheritance and virtual function to define my device, my > > tape, my specific tape drive, etc. The application also relies heavily on > > file descriptors, ioctl calls and signal trapping with a termination > > function. That's what I call C/C++. Parts of it a pure C. Parts of it are > > pure C++. > > > > I've also written polymorphic object oriented programming (POOP) in pure C. > > http://freshmeat.net/projects/ezfb/?...01%2C111%2C112 > > > > I know the difference between C and C++. > > > > > >>You probably don't want to use popen and you almost certainly do not want > > > > to > > > >>use the & operator to "backgroundify" what you're running. > > > > > > Why? It works like this from a script like /etc/rc.d/rc.local. > > > > I don't get how forking twice would get me anywhere better than once. > > > > > >>what does ps aux tell you is the pid of the application that's running? > >>Sounds like a zombie to me.. > > > > > > The process has a real number, but since root didn't start it, when I kill > > it or killall, I get no message of its termination. It's just gone. Since it > > has no effect on the pid or the status file, it can be started many times. > > This has a horrible effect on the machine in general. > > > > > >>You might try comp.unix.programmer in future as this isn't really an > > > > apache > > > >>specific question. > > > > > > Well it sort-of-is. It has everything to do with what the user apache can do > > on a machine that has lots of stuff owned by root AND it has to do > > specifically with the hidden shell that runs the CGI app that is inside of > > Apache and how it relates to a real shell in a real console. > > > > Smile. Be Happy. Look at some art. > > http://www.akrobiz.com/pc/gallery_index.html > > > > Take care. James. :o) > > > > > > > > > > Apache won't recognize that that a CGI script is done until the CGI > script and all of its subprocesses exit (or at least send an EOF to > stdout). Here is the proper method [adapted from Unix Network > Programming Volume 1 - W. Richard Stevens]. > > > // Block the hangup (HUP) signal. This is sent to all child processes > // when their parent dies. The hangup signal's default action is to > // terminate the proces. If we don't block it, the next statement > // will terminate the parent. > > signal( SIGHUP, SIG_IGN ); > > // Now, we fork and exit the parent. This places the process in the > // background, > if ( fork() != 0 ) exit( 0 ); > > // At this point, we are in the background, but still attached to the > // current login session (or CGI execution). We need to make it the > // leader of it's own session. This will prevent it from receiving > // hang up signals when the CGI script dies. > setsid(); > > // Now, to be sure that we don't later send output that assigns us a > // controlling terminal, we need to close all open file descriptors. > // UNIX doesn't provide a way to either close all open files or to > // determine how many descriptors we are using. We close the first > // sixteen which should be PLENTY in a newly started app (we can > // usually get away with just three, but we err on the side of safety > // here). If you have a log file open a this point, it may well be > // closed. Open your log file AFTER this segment of code. > for ( int x = 0 ; x < 16 ; x++ ) close( x ); > > // Now, to go from the background process to a full daemon, we need to > // fork yet again. This will make the process detached from any > // session as it's session leader (the process from the first fork) > // will be dead. > signal( SIGHUP, SIG_IGN ); > if ( fork() != 0 ) exit( 0 ); > > // You are now a properly created demon process and may do anything > // else you like at this point. There is no stdout to printf() to. > > Hope this helps. > > Tim > > > |