Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #162313 > unrolled thread
| Started by | John Forkosh <forkosh@panix.com> |
|---|---|
| First post | 2021-08-11 13:53 +0000 |
| Last post | 2021-08-12 03:17 +0000 |
| Articles | 7 — 4 participants |
Back to article view | Back to comp.lang.c
How can a daemon process open() the stdout of someone who signals it? John Forkosh <forkosh@panix.com> - 2021-08-11 13:53 +0000
Re: How can a daemon process open() the stdout of someone who signals it? Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-08-11 15:41 +0000
Re: How can a daemon process open() the stdout of someone who signals it? John Forkosh <forkosh@panix.com> - 2021-08-12 03:11 +0000
Re: How can a daemon process open() the stdout of someone who signals it? Vir Campestris <vir.campestris@invalid.invalid> - 2021-08-13 21:30 +0100
Re: How can a daemon process open() the stdout of someone who signals it? Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2021-08-14 14:25 +0000
Re: How can a daemon process open() the stdout of someone who signals it? Kaz Kylheku <563-365-8930@kylheku.com> - 2021-08-11 18:10 +0000
Re: How can a daemon process open() the stdout of someone who signals it? John Forkosh <forkosh@panix.com> - 2021-08-12 03:17 +0000
| From | John Forkosh <forkosh@panix.com> |
|---|---|
| Date | 2021-08-11 13:53 +0000 |
| Subject | How can a daemon process open() the stdout of someone who signals it? |
| Message-ID | <sf0kp8$ki0$1@reader1.panix.com> |
Specifically, below's the little test program I wrote.
It works fine, but isn't programmed to do exactly what I want
because I can't figure out how to program that.
It runs as a daemon, just sitting on a pause() until
it catches a signal, via killall -SIGINT testdaemon
and then it just writes a dummy line with date/time and
#running processes to a log file. Just a "Hello, World" test.
But what I want is to write some stuff to the stdout
of the process that sent the signal to testdaemon.
Note that the testhandler() function has an
if(0)fprintf(stdout,etc). So my question is,
what do I do to open()/fopen()/whatever the user's
(whoever sent testdaemon the sigint) stdout?
And then close it after the test handler completes,
just before the daemon goes back to pause().
So, for definiteness, here's the little testdaemon code,
/* ---
* usage: nohup ./testdaemon
* then: killall -SIGINT testdaemon
* -------------------------------------- */
/* --- standard headers --- */
#include <stdio.h>
#include <stdlib.h>
/* --- required for daemonize() --- */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/* --- required for signals --- */
#include <signal.h>
/* --- additional data --- */
#if !defined(LOGFILE)
#define LOGFILE "/home/username/testdaemon.log"
#endif
/* --- entry point --- */
void testhand ( int signal ) { /* test handler for all signals */
if(0) fprintf(stdout,"testhand> trapped signal#%d\n",signal);
switch(signal) {
default: break;
case SIGINT:
system("echo `date` ... ps ax = `ps ax|wc` >> " LOGFILE);
break;
} /* --- end-of-switch(signal) --- */
return;
} /* --- end-of-function testhand() --- */
/* --- entry point --- */
int main ( int argc, char *argv[] ) {
/* --- allocations and declarations --- */
int signal=SIGINT, sethandler(); /* signal to send daemon */
void (*handler)() = testhand; /* set up test handler */
int sleepsecs = 9; /* log info every sleepsecs seconds */
int daemonize(), isdaemon=daemonize(); /* run process as daemon */
if ( isdaemon ) /* running as daemon */
if ( sethandler(signal,handler) == 0 ) /* established handler */
while ( 1 ) pause(); /* killall -SIGINT testdaemon */
exit ( 0 );
} /* --- end-of-function main() --- */
And, if you're interested, or want to use them,
here are the more general daemonize() and sethandler() functions
/*===========================================================================
* Function: sethandler ( signal, handler )
* Purpose: Set handler() function for signal.
* --------------------------------------------------------------------------
* Arguments: signal (I) int containing signal (e.g., SIGALRM)
* to be trapped by handler.
* handler (I) function pointer to handler function.
* --------------------------------------------------------------------------
* Returns: (int) sigaction() return value.
* --------------------------------------------------------------------------
* Notes: o
*=========================================================================*/
/* --- entry point --- */
int sethandler ( int signal, void (*handler)() ) {
/* --- allocations and declarations --- */
struct sigaction newaction; /* new action for signal */
int action = (-1); /* sigaction() return value */
/* --- establish signal handler by calling sigaction() --- */
newaction.sa_handler = handler; /* set handler address */
newaction.sa_flags = SA_RESTART; /* resume after running handler */
sigemptyset(&newaction.sa_mask); /* no additional signals blocked */
action = sigaction(signal, &newaction, NULL); /* 0=success, -1=failure */
return(action); /* back to caller with result */
} /* --- end-of-function sethandler() --- */
/* ==========================================================================
* Function: int daemonize ( void )
* Purpose: runs process as daemon
* --------------------------------------------------------------------------
* Arguments: -none
* --------------------------------------------------------------------------
* Returns: ( int ) 1=success, 0=failure
* --------------------------------------------------------------------------
* Notes: o
* ======================================================================= */
/* --- entry point --- */
int daemonize ( void ) {
/* --- allocations and declarations --- */
int status = 0; /* init to signal failure */
pid_t pid, sid; /* process, session id */
/* --- fork off the parent process --- */
if ( (pid = fork()) < 0 ) goto end_of_job; /* failed to fork */
if ( pid > 0 ) exit(EXIT_SUCCESS); /* exit parent process */
/* --- change the file mode mask --- */
umask(0);
/* --- create a new sid for the child process --- */
if ( (sid = setsid()) < 0 ) goto end_of_job;
/* --- change the current working directory --- */
if ( chdir("/") < 0 ) goto end_of_job;
/* --- close out the standard file descriptors --- */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
/* --- back to caller as daemon --- */
status = 1; /* signal success to caller */
end_of_job:
return status;
} /* --- end-of-function daemonize() --- */
--
John Forkosh ( mailto: j@f.com where j=john and f=forkosh )
[toc] | [next] | [standalone]
| From | Lew Pitcher <lew.pitcher@digitalfreehold.ca> |
|---|---|
| Date | 2021-08-11 15:41 +0000 |
| Message-ID | <sf0r3g$ksq$1@dont-email.me> |
| In reply to | #162313 |
On Wed, 11 Aug 2021 13:53:44 +0000, John Forkosh wrote: > Specifically, below's the little test program I wrote. > It works fine, but isn't programmed to do exactly what I want > because I can't figure out how to program that. > > It runs as a daemon, Just to be clear, comp.lang.c is not the correct forum to discuss daemons and system-specific development. You probably want one of the comp.os.unix or comp.os.linux groups for a comprehensive answer. > just sitting on a pause() until > it catches a signal, via killall -SIGINT testdaemon > and then it just writes a dummy line with date/time and > #running processes to a log file. Just a "Hello, World" test. > > But what I want is to write some stuff to the stdout > of the process that sent the signal to testdaemon. In your daemon, you will want to - establish which process signalled, - establish which file the signalling process uses as stdout - open that file (if possible), write your data, and then close it You can get the PID of the signalling process from the siginfo_t si_pid value. With the signaller's PID, you /may/ be able to obtain the path of the signaller's stdout file from the symlink named by /proc/<PID>/fd/1. Note that individual /proc files are usually read-protected so that only the relevant process's UID and GID can read them. Once you retrieve the path of the signaller's stdout file, you can try to open it. It may not exist as a filesystem entity (it may be a pipe, for instance) or it may be write-protected, but if you can open it for write access (correction: /append/ access), you can write your data and close the file. > Note that the testhandler() function has an > if(0)fprintf(stdout,etc). So my question is, > what do I do to open()/fopen()/whatever the user's > (whoever sent testdaemon the sigint) stdout? > And then close it after the test handler completes, > just before the daemon goes back to pause(). > > So, for definiteness, here's the little testdaemon code, [code snipped] HTH -- Lew Pitcher "In Skills, We Trust"
[toc] | [prev] | [next] | [standalone]
| From | John Forkosh <forkosh@panix.com> |
|---|---|
| Date | 2021-08-12 03:11 +0000 |
| Message-ID | <sf23hf$jle$1@reader1.panix.com> |
| In reply to | #162319 |
Lew Pitcher <lew.pitcher@digitalfreehold.ca> wrote: > John Forkosh wrote: > >> Specifically, below's the little test program I wrote. >> It works fine, but isn't programmed to do exactly what I want >> because I can't figure out how to program that. >> >> It runs as a daemon, > > Just to be clear, comp.lang.c is not the correct forum to discuss > daemons and system-specific development. You probably want > one of the comp.os.unix or comp.os.linux groups for a comprehensive > answer. My bad if it's the wrong ng. That thought had occurred to me before posting here, but it's obviously both a C-related and Unix-related question, and I felt that (a)the C-related part dominated, and that (b)C developers were more likely familiar with Unix than vice versa. Anyway, thanks for the answer and suggestions. Definitely gives me some possible approaches to pursue. I'd tried googling, looking through my copy of Stevens, etc, but failed to find anything useful. But your remarks are definitely leading to some useful googling, filling in the details (although, like you say, it's still not clear whether or not it can actually work as intended). Thanks again. >> just sitting on a pause() until >> it catches a signal, via killall -SIGINT testdaemon >> and then it just writes a dummy line with date/time and >> #running processes to a log file. Just a "Hello, World" test. >> >> But what I want is to write some stuff to the stdout >> of the process that sent the signal to testdaemon. > > In your daemon, you will want to > - establish which process signalled, > - establish which file the signalling process uses as stdout > - open that file (if possible), write your data, and then close it > > You can get the PID of the signalling process from the > siginfo_t si_pid value. > > With the signaller's PID, you /may/ be able to obtain the path of the > signaller's stdout file from the symlink named by /proc/<PID>/fd/1. > Note that individual /proc files are usually read-protected so that > only the relevant process's UID and GID can read them. > > Once you retrieve the path of the signaller's stdout file, you can try > to open it. It may not exist as a filesystem entity (it may be a pipe, > for instance) or it may be write-protected, but if you can open it for > write access (correction: /append/ access), you can write your data > and close the file. > >> Note that the testhandler() function has an >> if(0)fprintf(stdout,etc). So my question is, >> what do I do to open()/fopen()/whatever the user's >> (whoever sent testdaemon the sigint) stdout? >> And then close it after the test handler completes, >> just before the daemon goes back to pause(). >> >> So, for definiteness, here's the little testdaemon code, > [code snipped] > > HTH -- John Forkosh ( mailto: j@f.com where j=john and f=forkosh )
[toc] | [prev] | [next] | [standalone]
| From | Vir Campestris <vir.campestris@invalid.invalid> |
|---|---|
| Date | 2021-08-13 21:30 +0100 |
| Message-ID | <sf6kpl$2u4$2@dont-email.me> |
| In reply to | #162319 |
On 11/08/2021 16:41, Lew Pitcher wrote: > Once you retrieve the path of the signaller's stdout file, you can try > to open it. It may not exist as a filesystem entity (it may be a pipe, > for instance) or it may be write-protected, but if you can open it for > write access (correction:/append/ access), you can write your data > and close the file. Yeah... but... the original process will then carry on writing its data to that file, and will write it at the location that it "knows" the end is. Which is where it was before the daemon touched it. And is quite possibly nothing to do with the data last written by the signaller, which will be in the buffers of its internal file handling code. Kaz seems to be on the right path. Good luck! Andy
[toc] | [prev] | [next] | [standalone]
| From | Lew Pitcher <lew.pitcher@digitalfreehold.ca> |
|---|---|
| Date | 2021-08-14 14:25 +0000 |
| Message-ID | <sf8jp7$dao$1@dont-email.me> |
| In reply to | #162375 |
On Fri, 13 Aug 2021 21:30:45 +0100, Vir Campestris wrote: > On 11/08/2021 16:41, Lew Pitcher wrote: >> Once you retrieve the path of the signaller's stdout file, you can try >> to open it. It may not exist as a filesystem entity (it may be a pipe, >> for instance) or it may be write-protected, but if you can open it for >> write access (correction:/append/ access), you can write your data >> and close the file. > > Yeah... but... the original process will then carry on writing its data > to that file, and will write it at the location that it "knows" the end > is. Which is where it was before the daemon touched it. And is quite > possibly nothing to do with the data last written by the signaller, > which will be in the buffers of its internal file handling code. Agreed. Even with "append", the "client" process may write over the daemon's output. FWIW, I do not believe that the OP can achieve the goal as stated in the original post. Like Kaz, I believe that co-operative changes in both client and daemon provide the only viable solution. /My/ post pointed out the challenges (and roadblocks) that I saw in the OP's apparently preferred solution. > Kaz seems to be on the right path. Good luck! -- Lew Pitcher "In Skills, We Trust"
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <563-365-8930@kylheku.com> |
|---|---|
| Date | 2021-08-11 18:10 +0000 |
| Message-ID | <20210811110000.589@kylheku.com> |
| In reply to | #162313 |
On 2021-08-11, John Forkosh <forkosh@panix.com> wrote: > Specifically, below's the little test program I wrote. > It works fine, but isn't programmed to do exactly what I want > because I can't figure out how to program that. > > It runs as a daemon, just sitting on a pause() until > it catches a signal, via killall -SIGINT testdaemon > and then it just writes a dummy line with date/time and > #running processes to a log file. Just a "Hello, World" test. > > But what I want is to write some stuff to the stdout > of the process that sent the signal to testdaemon. I wouldn't bang my head against the wall by doing it this way. What you can do is implement a little management protocol for your server that uses some inter-process communication mechanism, like sockets. Then write a CLI over the protocol that provides a command language for doing things with the server. The server can send output over the protocol, which the CLI can dump on its standard output. There are things you can try. In Unix, there are ways to send an open file descriptor from one process to another. So it seems like it would be possible to connect to the server somehow, and say "here is file descriptor; please send printed output to it" (it happens to be my standard output). Ooen descriptors can be passed over Unix sockets (AF_UNIX == AF_LOCAL address family) and SystemV streams and maybe other ways. I don't think signal handling can pass an open descriptor, so it couldn't literally work they way you want: get a signal from some process, and then obtain a descriptor from it. More like, process opens an AF_UNIX socket to the server, and passes the desired file descriptor. -- TXR Programming Language: http://nongnu.org/txr Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
[toc] | [prev] | [next] | [standalone]
| From | John Forkosh <forkosh@panix.com> |
|---|---|
| Date | 2021-08-12 03:17 +0000 |
| Message-ID | <sf23rs$jle$2@reader1.panix.com> |
| In reply to | #162327 |
Kaz Kylheku <563-365-8930@kylheku.com> wrote: > John Forkosh <forkosh@panix.com> wrote: >> Specifically, below's the little test program I wrote. >> It works fine, but isn't programmed to do exactly what I want >> because I can't figure out how to program that. >> >> It runs as a daemon, just sitting on a pause() until >> it catches a signal, via killall -SIGINT testdaemon >> and then it just writes a dummy line with date/time and >> #running processes to a log file. Just a "Hello, World" test. >> >> But what I want is to write some stuff to the stdout >> of the process that sent the signal to testdaemon. > > I wouldn't bang my head against the wall by doing it this way. > > What you can do is implement a little management protocol for > your server that uses some inter-process communication mechanism, > like sockets. > > Then write a CLI over the protocol that provides a command language > for doing things with the server. > > The server can send output over the protocol, which the CLI can dump on > its standard output. > > There are things you can try. In Unix, there are ways to send an open > file descriptor from one process to another. So it seems like it would > be possible to connect to the server somehow, and say "here is file > descriptor; please send printed output to it" (it happens to be my > standard output). > > Open descriptors can be passed over Unix sockets (AF_UNIX == AF_LOCAL > address family) and SystemV streams and maybe other ways. > > I don't think signal handling can pass an open descriptor, so it > couldn't literally work they way you want: get a signal from > some process, and then obtain a descriptor from it. > > More like, process opens an AF_UNIX socket to the server, > and passes the desired file descriptor. Thanks for the suggestions, Kaz. Sockets sounds like the easiest and most straightforward approach, so I'll be checking that out more carefully first. -- John Forkosh ( mailto: j@f.com where j=john and f=forkosh )
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web