Jordan,
Following (at the end of this post) is the code for a Unix daemon
(daemon.c). It is setup to run on both System V and BSD. I am not familar
with Linux. In any case, you link in the object built from this code with
your main C program. After you've setup your environment in your main
module, call daemon_start( 1 ). You do not need to start it as a background
process, since it will fork itself and kill the child, anyway. The main
thing the daemon does is disassociate itself from any terminals and ensures
zombie processes are left in the environment.
Apart from starting the daemon, you'll need to setup an infinite loop in
your main module. Here's a snippet from a main module we use to query a
table, scg_system, that our applications in windows write to if they need to
execute a report on our Unix database server: The only thing scg_system has
is a varchar field for the reports command line, a status to tell if the
command line has been run yet, and a time stamp. We use the status of 1 to
tell if scg_sysd has read the row to execute the command line (so it won't
execute it again); 2 to indicate that scg_sysd successfully executed the
command; and 3 if scg_sysd tried, but could not execute the command, in
which case the error is logged by the LogError() function.
A good way to test your daemon, is to just setup main(), call
daemon_start(), and then in your infinite loop open a tty and write to it ,
then close the tty. After the wait() in your main() program, another child
will be forked and it will write to the tty again. Once you're satisfied
it works, just kill the process. Warning: Do not test a daemon on a
production system. It is not difficult to code in an error that might cause
the program to start forking until it fills-up the process table.
/*
* check for an open database before continuing. This first loop is used
because the daemon is started when the system
* inits and the database will not yet be running.
*/
while( 1 ) {
if( !fork( ) ) {
i = nCreateTable( ); /* nCreateTable() returns 0 when it has
successfully checked for/created the table */
fprintf( fp, "%d", i ); /* write 1-char stat to tmp for parent
*/
fclose( fp );
exit( i );
} else {
wait( (int*)0 ); /* wait for child to exit */
if( ( fp = fopen( szTmpNam, "r" ) ) == NULL ) {
LogError( "Can't open tmp file(2)", 0 );
exit( 1 );
}
fread( szBuf, sizeof( szBuf ), 256, fp ); /* get status */
fclose( fp ); /* close and unlink tmpfile */
unlink( szTmpNam );
status = atoi( szBuf );
if( !status ) break; /* the database is started;
scg_system exists */
signal( SIGALRM, alarm_catch );
alarm( nSLEEPTIME ); /* nSLEEPTIME is the number of
seconds to sleep */
pause( );
tmpnam( szTmpNam );
if( ( fp = fopen( szTmpNam, "w+" ) ) == NULL ) {
LogError( "Can't open tmp file(3)", 0 );
exit( 1 );
}
}
} /* end while */
fclose( fp );
unlink( szTmpNam );
/* this is the processing loop */
while( 1 ) {
if( !fork() ) {
nRunDBCommands( ); /* look up the command line and system() the
command */
exit( 0 );
} else {
wait( (int*) 0 );
signal( SIGALRM, alarm_catch );
alarm( nSLEEPTIME );
pause( );
}
} /* end while */
/* alarm catcher doesn't need to do anything. It could call alarm(), but we
did it in the while loop */
int alarm_catch()
{
return(0);
} /* end alarm_catch */
/********** here's daemon.c ************/
/*
* daemon.c - start process as a UNIX daemon
*
* syntax: void daemon_start( int ignsigcld )
*
* description: daemon is called by the main process to disconnect
* the process from any terminals and/or group
* leader roles. The nonzero ignsigcld flag is
* to handle SIGCLDs so zombies don't clog.
*
* databases/files accessed:
* name type description
* ==== ==== ===========
* scg_system table hold command lines to be executed by scg_sysd
*
* function calls:
* name description
* ==== ===========
*
* global variables:
* name type description
* ==== ==== ===========
*
* edit history:
* Date Programmer Description
* ==== ========== ===========
* Thu Oct 24 02:34:24 EDT 1996 jlp baselined for fm_sysd.ec
*
* Programmer's Note:
*/
static char ident[] ="SCG Id: @(#) daemon.c 1.1.0.0. 10/14/97 17:00:50";
/*
* defines
*/
/*
* externals
*/
extern int errno ;
/*
* includes
*/
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include "SCGdefs.h"
/*
* globals
*/
/*
* function declarations
*/
/*
*****************************
*** Function definitions ***
*****************************
*/
#ifdef SIGSTP
#include <sys/file.h>
#include <sys/ioctl.h>
#endif
/* ignsigcld is nonzero to handle SIGCLDs so zombies don't clog the system
*/
void daemon_start( int ignsigcld )
{
int nChildPID, fd ;
strcpy( FUNC,"daemon_start") ;
/*
* If we were started by init (process 1) from the /etc/inittab
* file there's no need to detach. This test is unreliable due
* to an unavoidable ambiguity; if the process is started by
* some other process and orphaned (parent terminates before
* we are started)
*/
if (getppid() == 1) goto out ;
/*
* Ignore the terminal stop signals (BSD)
*/
#ifdef SIGTOU
signal(SIGTOU, SIG_IGN) ;
#endif
#ifdef SIGTTIN
signal(SIGTTIN, SIG_IGN) ;
#endif
#ifdef SIGTSTP
signal(SIGTSTP, SIG_IGN) ;
#endif
/*
* If we were not started in the backgroung, fork and let
* the parent exit. This also guarantees the first child
* is not a process group leader
*/
nChildPID = fork() ;
if (nChildPID < 0) {
LogError( "daemon: Can't fork first child", 0 );
exit(-1) ;
}
if (nChildPID > 0) exit(0); /* we are parent */
/*
* First child process
* Disassociate from controlling terminal and process group.
* Ensure the process can't reacquire a new controlling terminal
*/
#ifdef SIGSTP /* BSD */
if (setpgrp(0, getpid()) == -1) {
LogError( "daemon: Can't change process group (1)", 0 );
exit(-1) ;
}
if ((fd - open("/dev/tty", O_RDWR)) >= 0) {
ioctl(fd, TIOCNOTTY, (char *)0) ; /* lose cont. tty */
close(fd) ;
}
#else /* System V */
if (setpgrp() == -1) {
LogError( "daemon: Can't change process group (2)", 0 ) ;
exit(-1) ;
}
signal(SIGHUP, SIG_IGN) ; /* immune from pgrp leader death */
if ((nChildPID = fork()) < 0) {
LogError( "daemon: Can't fork second child", 0 ) ;
exit(-1) ;
}
else if (nChildPID > 0) exit(0) ; /* first child */
#endif
/* second child */
out:
/*
* close any open file descriptors
*/
for (fd = 0; fd < _NFILE; fd++) close(fd) ;
errno = 0; /* probably set from EBADF from a close */
/*
* Move the current directory to root to ensure not
* in a mounted file system
*/
chdir("/") ;
/*
* clear inherited file creation mask
*/
umask(0) ;
/*
* See if the caller isn't interested in the exit status
* of its children and doesn't want to have them become
* zombies and clog up the system. With System V all we
* need to do is ignorre the signal. With BSD, however,
* we have to catch each signal and execute the wait3()
* system call.
*/
if (ignsigcld) {
#ifdef SIGSTP
int sig_child() ;
signal(SIGCLD, sig_child) ;
#else
signal(SIGCLD,SIG_IGN) ;
#endif
}
} /* end daemon_start */
/* eof: daemon.c */
--
HTH,
James Potts
"Richard Lynch" <[EMAIL PROTECTED]> wrote in message
038001c13140$8e0bf1e0$6401a8c0@Lynchux100">news:038001c13140$8e0bf1e0$6401a8c0@Lynchux100...
> You could just log the IP into a database, and then look it up later in
> another script in a "cron" job. You'll need PHP installed as a
stand-alone
> binary (aka CGI) and you'll want to read:
>
> man 5 crontab
>
> You could use select distinct and then would only need to look up each IP
> once for a user that viewed many pages.
>
> If you wait too long, though, the IPs will change on you for DHCP clients.
> Still the same country probably though.
>
> To answer your original question :-) what you are talking about is called
> "fork" (like a fork in the road) and you do it something not unlike this:
>
> exec("/path/to/some/other/script &", $results, $errorcode);
> echo implode("<BR>\n", $results);
> if ($errorcode){
> echo "OS Error: $errorcode. Usually path/permissions. man
> errno<BR>\n";
> }
>
> It's the & symbol that tells the shell to fork.
>
> The other script in question has to, errrr, I forget exactly, but I think
it
> has to *NOT* bind up stdin, stdout, or stderr, because then Apache and PHP
> are waiting for that output...
>
> Search the archives for "fork" and "&" and "exec" and you should find more
> posts.
>
> --
> WARNING [EMAIL PROTECTED] address is an endangered species -- Use
> [EMAIL PROTECTED]
> Wanna help me out? Like Music? Buy a CD: http://l-i-e.com/artists.htm
> Volunteer a little time: http://chatmusic.com/volunteer.htm
> ----- Original Message -----
> From: Jordan Pickup <[EMAIL PROTECTED]>
> Newsgroups: php.general
> To: <[EMAIL PROTECTED]>
> Sent: Monday, August 27, 2001 4:03 PM
> Subject: A Separate Process?
>
>
> > Is there any way to make a separate process in PHP?
> >
> > I do real-time stats collection on my site and one of the things I
collect
> > is the domain of the user (to get their country).
> >
> > Sometimes getting the domain name takes a few seconds to come back and
the
> > user has to wait for that time before their page displays.
> >
> > Is there any way to split of a separate process - that doesn't end when
> the
> > current process ends - to do the stats collecting so that the user
doesn't
> > have to wait?
> >
> > Or, if not, is there some way to tell the browser that it has all the
data
> > (so that it will finish rendering the page and run my javascript) and
the
> > script can continue running and do the ns lookup?
> >
> > I'm sorry if this question has been asked and answered before but I
> couldn't
> > find an answer anywhere else... and the archive for this list seems to
be
> > down.
> >
> > Jordan
>
--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
To contact the list administrators, e-mail: [EMAIL PROTECTED]