2 * "$Id: main.c 4993 2006-01-26 19:27:40Z mike $"
4 * Scheduler main loop for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * main() - Main entry for the CUPS scheduler.
27 * cupsdClosePipe() - Close a pipe as necessary.
28 * cupsdOpenPipe() - Create a pipe which is closed on exec.
29 * cupsdCatchChildSignals() - Catch SIGCHLD signals...
30 * cupsdHoldSignals() - Hold child and termination signals.
31 * cupsdIgnoreChildSignals() - Ignore SIGCHLD signals...
32 * cupsdReleaseSignals() - Release signals for delivery.
33 * cupsdSetString() - Set a string value.
34 * cupsdSetStringf() - Set a formatted string value.
35 * parent_handler() - Catch USR1/CHLD signals...
36 * process_children() - Process all dead children...
37 * sigchld_handler() - Handle 'child' signals from old processes.
38 * sighup_handler() - Handle 'hangup' signals to reconfigure the
40 * sigterm_handler() - Handle 'terminate' signals that stop the
42 * select_timeout() - Calculate the select timeout value.
43 * usage() - Show scheduler usage.
47 * Include necessary headers...
52 #include <sys/resource.h>
56 #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
58 #endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
61 #endif /* HAVE_NOTIFY_H */
68 static void parent_handler(int sig
);
69 static void process_children(void);
70 static void sigchld_handler(int sig
);
71 static void sighup_handler(int sig
);
72 static void sigterm_handler(int sig
);
73 static long select_timeout(int fds
);
74 static void usage(void);
81 static int parent_signal
= 0; /* Set to signal number from child */
82 static int holdcount
= 0; /* Number of times "hold" was called */
83 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
84 static sigset_t holdmask
; /* Old POSIX signal mask */
85 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
86 static int dead_children
= 0; /* Dead children? */
87 static int stop_scheduler
= 0; /* Should the scheduler stop? */
91 * 'main()' - Main entry for the CUPS scheduler.
94 int /* O - Exit status */
95 main(int argc
, /* I - Number of command-line arguments */
96 char *argv
[]) /* I - Command-line arguments */
98 int i
; /* Looping var */
99 char *opt
; /* Option character */
100 int fg
; /* Run in the foreground */
101 int fds
; /* Number of ready descriptors select returns */
102 fd_set
*input
, /* Input set for select() */
103 *output
; /* Output set for select() */
104 cupsd_client_t
*con
; /* Current client */
105 cupsd_job_t
*job
; /* Current job */
106 cupsd_listener_t
*lis
; /* Current listener */
107 time_t current_time
, /* Current time */
108 activity
, /* Activity timer */
109 browse_time
, /* Next browse send time */
110 senddoc_time
, /* Send-Document time */
111 expire_time
; /* Subscription expire time */
113 time_t mallinfo_time
; /* Malloc information time */
114 #endif /* HAVE_MALLINFO */
115 struct timeval timeout
; /* select() timeout */
116 struct rlimit limit
; /* Runtime limit */
117 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
118 struct sigaction action
; /* Actions for POSIX signals */
119 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
121 cups_file_t
*fp
; /* Fake lpsched lock file */
122 struct stat statbuf
; /* Needed for checking lpsched FIFO */
127 * Check for command-line arguments...
132 for (i
= 1; i
< argc
; i
++)
133 if (argv
[i
][0] == '-')
134 for (opt
= argv
[i
] + 1; *opt
!= '\0'; opt
++)
137 case 'c' : /* Configuration file */
142 if (argv
[i
][0] == '/')
145 * Absolute directory...
148 cupsdSetString(&ConfigurationFile
, argv
[i
]);
153 * Relative directory...
156 char current
[1024]; /* Current directory */
159 getcwd(current
, sizeof(current
));
160 cupsdSetStringf(&ConfigurationFile
, "%s/%s", current
, argv
[i
]);
164 case 'f' : /* Run in foreground... */
168 case 'F' : /* Run in foreground, but still disconnect from terminal... */
172 default : /* Unknown option */
173 fprintf(stderr
, "cupsd: Unknown option \'%c\' - aborting!\n",
180 fprintf(stderr
, "cupsd: Unknown argument \'%s\' - aborting!\n", argv
[i
]);
184 if (!ConfigurationFile
)
185 cupsdSetString(&ConfigurationFile
, CUPS_SERVERROOT
"/cupsd.conf");
188 * If the user hasn't specified "-f", run in the background...
194 * Setup signal handlers for the parent...
197 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
198 sigset(SIGUSR1
, parent_handler
);
199 sigset(SIGCHLD
, parent_handler
);
201 sigset(SIGHUP
, SIG_IGN
);
202 #elif defined(HAVE_SIGACTION)
203 memset(&action
, 0, sizeof(action
));
204 sigemptyset(&action
.sa_mask
);
205 sigaddset(&action
.sa_mask
, SIGUSR1
);
206 action
.sa_handler
= parent_handler
;
207 sigaction(SIGUSR1
, &action
, NULL
);
208 sigaction(SIGCHLD
, &action
, NULL
);
210 sigemptyset(&action
.sa_mask
);
211 action
.sa_handler
= SIG_IGN
;
212 sigaction(SIGHUP
, &action
, NULL
);
214 signal(SIGUSR1
, parent_handler
);
215 signal(SIGCLD
, parent_handler
);
217 signal(SIGHUP
, SIG_IGN
);
218 #endif /* HAVE_SIGSET */
223 * OK, wait for the child to startup and send us SIGUSR1 or to crash
224 * and the OS send us SIGCHLD... We also need to ignore SIGHUP which
225 * might be sent by the init script to restart the scheduler...
228 for (; parent_signal
== 0;)
231 if (parent_signal
== SIGUSR1
)
239 else if (WIFEXITED(i
))
241 fprintf(stderr
, "cupsd: Child exited with status %d!\n", WEXITSTATUS(i
));
246 fprintf(stderr
, "cupsd: Child exited on signal %d!\n", WTERMSIG(i
));
255 * Make sure we aren't tying up any filesystems...
262 * Disable core dumps...
265 getrlimit(RLIMIT_CORE
, &limit
);
267 setrlimit(RLIMIT_CORE
, &limit
);
270 * Disconnect from the controlling terminal...
276 * Close all open files...
279 getrlimit(RLIMIT_NOFILE
, &limit
);
281 for (i
= 0; i
< limit
.rlim_cur
; i
++)
287 * Set the timezone info...
293 setlocale(LC_TIME
, "");
297 * Set the maximum number of files...
300 getrlimit(RLIMIT_NOFILE
, &limit
);
302 if (limit
.rlim_max
> CUPS_MAX_FDS
)
303 MaxFDs
= CUPS_MAX_FDS
;
305 MaxFDs
= limit
.rlim_max
;
307 limit
.rlim_cur
= MaxFDs
;
309 setrlimit(RLIMIT_NOFILE
, &limit
);
312 * Allocate memory for the input and output sets...
315 SetSize
= (MaxFDs
+ 31) / 8 + 4;
316 if (SetSize
< sizeof(fd_set
))
317 SetSize
= sizeof(fd_set
);
319 InputSet
= (fd_set
*)calloc(1, SetSize
);
320 OutputSet
= (fd_set
*)calloc(1, SetSize
);
321 input
= (fd_set
*)calloc(1, SetSize
);
322 output
= (fd_set
*)calloc(1, SetSize
);
324 if (InputSet
== NULL
|| OutputSet
== NULL
|| input
== NULL
|| output
== NULL
)
326 syslog(LOG_LPR
, "Unable to allocate memory for select() sets - exiting!");
331 * Read configuration...
334 if (!cupsdReadConfiguration())
336 syslog(LOG_LPR
, "Unable to read configuration file \'%s\' - exiting!",
342 * Catch hangup and child signals and ignore broken pipes...
345 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
347 sigset(SIGHUP
, sigterm_handler
);
349 sigset(SIGHUP
, sighup_handler
);
351 sigset(SIGPIPE
, SIG_IGN
);
352 sigset(SIGTERM
, sigterm_handler
);
353 #elif defined(HAVE_SIGACTION)
354 memset(&action
, 0, sizeof(action
));
356 sigemptyset(&action
.sa_mask
);
357 sigaddset(&action
.sa_mask
, SIGHUP
);
360 action
.sa_handler
= sigterm_handler
;
362 action
.sa_handler
= sighup_handler
;
364 sigaction(SIGHUP
, &action
, NULL
);
366 sigemptyset(&action
.sa_mask
);
367 action
.sa_handler
= SIG_IGN
;
368 sigaction(SIGPIPE
, &action
, NULL
);
370 sigemptyset(&action
.sa_mask
);
371 sigaddset(&action
.sa_mask
, SIGTERM
);
372 sigaddset(&action
.sa_mask
, SIGCHLD
);
373 action
.sa_handler
= sigterm_handler
;
374 sigaction(SIGTERM
, &action
, NULL
);
377 signal(SIGHUP
, sigterm_handler
);
379 signal(SIGHUP
, sighup_handler
);
381 signal(SIGPIPE
, SIG_IGN
);
382 signal(SIGTERM
, sigterm_handler
);
383 #endif /* HAVE_SIGSET */
387 * Try to create a fake lpsched lock file if one is not already there.
388 * Some Adobe applications need it under IRIX in order to enable
392 if ((fp
= cupsFileOpen("/var/spool/lp/SCHEDLOCK", "w")) == NULL
)
394 syslog(LOG_LPR
, "Unable to create fake lpsched lock file "
395 "\"/var/spool/lp/SCHEDLOCK\"\' - %s!",
400 fchmod(cupsFileNumber(fp
), 0644);
401 fchown(cupsFileNumber(fp
), User
, Group
);
408 * Initialize authentication certificates...
414 * If we are running in the background, signal the parent process that
415 * we are up and running...
421 * Send a signal to the parent process, but only if the parent is
422 * not PID 1 (init). This avoids accidentally shutting down the
423 * system on OpenBSD if you CTRL-C the server before it is up...
426 i
= getppid(); /* Save parent PID to avoid race condition */
433 * If the administrator has configured the server to run as an unpriviledged
434 * user, change to that user now...
440 setgroups(1, &Group
);
448 cupsdCatchChildSignals();
451 * Start any pending print jobs...
462 #endif /* HAVE_MALLINFO */
463 browse_time
= time(NULL
);
464 senddoc_time
= time(NULL
);
465 expire_time
= time(NULL
);
468 while (!stop_scheduler
)
471 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
472 "main: Top of loop, dead_children=%d, NeedReload=%d",
473 dead_children
, NeedReload
);
477 * Check if there are dead children to handle...
484 * Check if we need to load the server configuration file...
490 * Close any idle clients...
495 for (i
= NumClients
, con
= Clients
; i
> 0; i
--, con
++)
496 if (con
->http
.state
== HTTP_WAITING
)
498 cupsdCloseClient(con
);
502 con
->http
.keep_alive
= HTTP_KEEPALIVE_OFF
;
504 cupsdPauseListening();
508 * Check for any active jobs...
511 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
513 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
514 if (job
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
518 * Restart if all clients are closed and all jobs finished, or
519 * if the reload timeout has elapsed...
522 if ((NumClients
== 0 && (!job
|| NeedReload
!= RELOAD_ALL
)) ||
523 (time(NULL
) - ReloadTime
) >= ReloadTimeout
)
525 if (!cupsdReadConfiguration())
527 syslog(LOG_LPR
, "Unable to read configuration file \'%s\' - exiting!",
535 * Check for available input or ready output. If select() returns
536 * 0 or -1, something bad happened and we should exit immediately.
538 * Note that we at least have one listening socket open at all
542 memcpy(input
, InputSet
, SetSize
);
543 memcpy(output
, OutputSet
, SetSize
);
545 timeout
.tv_sec
= select_timeout(fds
);
548 if ((fds
= select(MaxFDs
, input
, output
, NULL
, &timeout
)) < 0)
550 char s
[16384], /* String buffer */
551 *sptr
; /* Pointer into buffer */
552 int slen
; /* Length of string buffer */
556 * Got an error from select!
559 if (errno
== EINTR
) /* Just interrupted by a signal */
563 * Log all sorts of debug info to help track down the problem.
566 cupsdLogMessage(CUPSD_LOG_EMERG
, "select() failed - %s!",
569 strcpy(s
, "InputSet =");
573 for (i
= 0; i
< MaxFDs
; i
++)
574 if (FD_ISSET(i
, InputSet
))
576 snprintf(sptr
, sizeof(s
) - slen
, " %d", i
);
577 slen
+= strlen(sptr
);
578 sptr
+= strlen(sptr
);
581 cupsdLogMessage(CUPSD_LOG_EMERG
, s
);
583 strcpy(s
, "OutputSet =");
587 for (i
= 0; i
< MaxFDs
; i
++)
588 if (FD_ISSET(i
, OutputSet
))
590 snprintf(sptr
, sizeof(s
) - slen
, " %d", i
);
591 slen
+= strlen(sptr
);
592 sptr
+= strlen(sptr
);
595 cupsdLogMessage(CUPSD_LOG_EMERG
, s
);
597 for (i
= 0, con
= Clients
; i
< NumClients
; i
++, con
++)
598 cupsdLogMessage(CUPSD_LOG_EMERG
,
599 "Clients[%d] = %d, file = %d, state = %d",
600 i
, con
->http
.fd
, con
->file
, con
->http
.state
);
602 for (i
= 0, lis
= Listeners
; i
< NumListeners
; i
++, lis
++)
603 cupsdLogMessage(CUPSD_LOG_EMERG
, "Listeners[%d] = %d", i
, lis
->fd
);
605 cupsdLogMessage(CUPSD_LOG_EMERG
, "BrowseSocket = %d", BrowseSocket
);
607 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
609 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
610 cupsdLogMessage(CUPSD_LOG_EMERG
, "Jobs[%d] = %d < [%d %d] > [%d %d]",
612 job
->status_buffer
? job
->status_buffer
->fd
: -1,
613 job
->print_pipes
[0], job
->print_pipes
[1],
614 job
->back_pipes
[0], job
->back_pipes
[1]);
618 current_time
= time(NULL
);
621 * Check for status info from job filters...
624 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
626 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
627 if (job
->status_buffer
&& FD_ISSET(job
->status_buffer
->fd
, input
))
630 * Clear the input bit to avoid updating the next job
631 * using the same status pipe file descriptor...
634 FD_CLR(job
->status_buffer
->fd
, input
);
637 * Read any status messages from the filters...
644 * Update CGI messages as needed...
647 if (CGIPipes
[0] >= 0 && FD_ISSET(CGIPipes
[0], input
))
651 * Update notifier messages as needed...
654 if (NotifierPipes
[0] >= 0 && FD_ISSET(NotifierPipes
[0], input
))
655 cupsdUpdateNotifierStatus();
658 * Expire subscriptions as needed...
661 if (cupsArrayCount(Subscriptions
) > 0 && current_time
> expire_time
)
663 cupsdExpireSubscriptions(NULL
, NULL
);
665 expire_time
= current_time
;
669 * Update the browse list as needed...
672 if (Browsing
&& BrowseRemoteProtocols
)
674 if (BrowseSocket
>= 0 && FD_ISSET(BrowseSocket
, input
))
675 cupsdUpdateCUPSBrowse();
677 if (PollPipe
>= 0 && FD_ISSET(PollPipe
, input
))
678 cupsdUpdatePolling();
681 if (((BrowseLocalProtocols
| BrowseRemoteProtocols
) & BROWSE_SLP
) &&
682 BrowseSLPRefresh
<= current_time
)
683 cupsdUpdateSLPBrowse();
684 #endif /* HAVE_LIBSLP */
687 if (Browsing
&& BrowseLocalProtocols
&& current_time
> browse_time
)
689 cupsdSendBrowseList();
690 browse_time
= current_time
;
694 * Check for new connections on the "listen" sockets...
697 for (i
= NumListeners
, lis
= Listeners
; i
> 0; i
--, lis
++)
698 if (lis
->fd
>= 0 && FD_ISSET(lis
->fd
, input
))
700 FD_CLR(lis
->fd
, input
);
701 cupsdAcceptClient(lis
);
705 * Check for new data on the client sockets...
708 for (i
= NumClients
, con
= Clients
; i
> 0; i
--, con
++)
711 * Process the input buffer...
714 if (FD_ISSET(con
->http
.fd
, input
) || con
->http
.used
)
716 FD_CLR(con
->http
.fd
, input
);
718 if (!cupsdReadClient(con
))
721 FD_CLR(con
->file
, input
);
729 * Write data as needed...
732 if (con
->pipe_pid
&& FD_ISSET(con
->file
, input
))
735 * Keep track of pending input from the file/pipe separately
736 * so that we don't needlessly spin on select() when the web
737 * client is not ready to receive data...
740 FD_CLR(con
->file
, input
);
744 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "main: Data ready file %d!",
748 if (!FD_ISSET(con
->http
.fd
, output
))
750 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
751 "main: Removing fd %d from InputSet...", con
->file
);
752 FD_CLR(con
->file
, InputSet
);
756 if (FD_ISSET(con
->http
.fd
, output
))
758 FD_CLR(con
->http
.fd
, output
);
760 if (!con
->pipe_pid
|| con
->file_ready
)
761 if (!cupsdWriteClient(con
))
769 * Check the activity and close old clients...
772 activity
= current_time
- Timeout
;
773 if (con
->http
.activity
< activity
&& !con
->pipe_pid
)
775 cupsdLogMessage(CUPSD_LOG_DEBUG
,
776 "Closing client %d after %d seconds of inactivity...",
777 con
->http
.fd
, Timeout
);
779 cupsdCloseClient(con
);
786 * Update any pending multi-file documents...
789 if ((current_time
- senddoc_time
) >= 10)
792 senddoc_time
= current_time
;
797 * Log memory usage every minute...
800 if ((current_time
- mallinfo_time
) >= 60 && LogLevel
>= CUPSD_LOG_DEBUG
)
802 struct mallinfo mem
; /* Malloc information */
806 cupsdLogMessage(CUPSD_LOG_DEBUG
,
807 "mallinfo: arena = %d, used = %d, free = %d\n",
808 mem
.arena
, mem
.usmblks
+ mem
.uordblks
,
809 mem
.fsmblks
+ mem
.fordblks
);
810 mallinfo_time
= current_time
;
812 #endif /* HAVE_MALLINFO */
815 * Update the root certificate once every 5 minutes...
818 if ((current_time
- RootCertTime
) >= RootCertDuration
&& RootCertDuration
&&
822 * Update the root certificate...
826 cupsdAddCert(0, "root");
830 * Handle OS-specific event notification for any events that have
831 * accumulated. Don't send these more than once a second...
834 if (LastEvent
&& (time(NULL
) - LastEventTime
) > 1)
836 #ifdef HAVE_NOTIFY_POST
837 if (LastEvent
& CUPSD_EVENT_PRINTER_CHANGED
)
839 cupsdLogMessage(CUPSD_LOG_DEBUG
,
840 "notify_post(\"com.apple.printerListChange\")");
841 notify_post("com.apple.printerListChange");
844 if (LastEvent
& CUPSD_EVENT_PRINTER_STATE_CHANGED
)
846 cupsdLogMessage(CUPSD_LOG_DEBUG
,
847 "notify_post(\"com.apple.printerHistoryChange\")");
848 notify_post("com.apple.printerHistoryChange");
851 if (LastEvent
& (CUPSD_EVENT_JOB_STATE_CHANGED
|
852 CUPSD_EVENT_JOB_CONFIG_CHANGED
|
853 CUPSD_EVENT_JOB_PROGRESS
))
855 cupsdLogMessage(CUPSD_LOG_DEBUG
,
856 "notify_post(\"com.apple.jobChange\")");
857 notify_post("com.apple.jobChange");
859 #endif /* HAVE_NOTIFY_POST */
862 * Reset the accumulated events and notification time...
865 LastEventTime
= time(NULL
);
866 LastEvent
= CUPSD_EVENT_NONE
;
871 * Log a message based on what happened...
875 cupsdLogMessage(CUPSD_LOG_INFO
, "Scheduler shutting down normally.");
877 cupsdLogMessage(CUPSD_LOG_ERROR
,
878 "Scheduler shutting down due to program error.");
881 * Close all network clients and stop all jobs...
890 * Remove the fake IRIX lpsched lock file, but only if the existing
891 * file is not a FIFO which indicates that the real IRIX lpsched is
895 if (!stat("/var/spool/lp/FIFO", &statbuf
))
896 if (!S_ISFIFO(statbuf
.st_mode
))
897 unlink("/var/spool/lp/SCHEDLOCK");
901 * Free memory used by FD sets and return...
909 return (!stop_scheduler
);
914 * 'cupsdClosePipe()' - Close a pipe as necessary.
918 cupsdClosePipe(int *fds
) /* I - Pipe file descriptors (2) */
921 * Close file descriptors as needed...
939 * 'cupsdOpenPipe()' - Create a pipe which is closed on exec.
942 int /* O - 0 on success, -1 on error */
943 cupsdOpenPipe(int *fds
) /* O - Pipe file descriptors (2) */
953 * Set the "close on exec" flag on each end of the pipe...
956 if (fcntl(fds
[0], F_SETFD
, fcntl(fds
[0], F_GETFD
) | FD_CLOEXEC
))
963 if (fcntl(fds
[1], F_SETFD
, fcntl(fds
[1], F_GETFD
) | FD_CLOEXEC
))
971 * Return 0 indicating success...
979 * 'cupsdCatchChildSignals()' - Catch SIGCHLD signals...
983 cupsdCatchChildSignals(void)
985 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
986 struct sigaction action
; /* Actions for POSIX signals */
987 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
990 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
991 sigset(SIGCHLD
, sigchld_handler
);
992 #elif defined(HAVE_SIGACTION)
993 memset(&action
, 0, sizeof(action
));
995 sigemptyset(&action
.sa_mask
);
996 sigaddset(&action
.sa_mask
, SIGTERM
);
997 sigaddset(&action
.sa_mask
, SIGCHLD
);
998 action
.sa_handler
= sigchld_handler
;
999 sigaction(SIGCHLD
, &action
, NULL
);
1001 signal(SIGCLD
, sigchld_handler
); /* No, SIGCLD isn't a typo... */
1002 #endif /* HAVE_SIGSET */
1007 * 'cupsdClearString()' - Clear a string.
1011 cupsdClearString(char **s
) /* O - String value */
1022 * 'cupsdHoldSignals()' - Hold child and termination signals.
1026 cupsdHoldSignals(void)
1028 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1029 sigset_t newmask
; /* New POSIX signal mask */
1030 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1040 #elif defined(HAVE_SIGACTION)
1041 sigemptyset(&newmask
);
1042 sigaddset(&newmask
, SIGTERM
);
1043 sigaddset(&newmask
, SIGCHLD
);
1044 sigprocmask(SIG_BLOCK
, &newmask
, &holdmask
);
1045 #endif /* HAVE_SIGSET */
1050 * 'cupsdIgnoreChildSignals()' - Ignore SIGCHLD signals...
1052 * We don't really ignore them, we set the signal handler to SIG_DFL,
1053 * since some OS's rely on signals for the wait4() function to work.
1057 cupsdIgnoreChildSignals(void)
1059 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1060 struct sigaction action
; /* Actions for POSIX signals */
1061 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1064 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
1065 sigset(SIGCHLD
, SIG_DFL
);
1066 #elif defined(HAVE_SIGACTION)
1067 memset(&action
, 0, sizeof(action
));
1069 sigemptyset(&action
.sa_mask
);
1070 sigaddset(&action
.sa_mask
, SIGCHLD
);
1071 action
.sa_handler
= SIG_DFL
;
1072 sigaction(SIGCHLD
, &action
, NULL
);
1074 signal(SIGCLD
, SIG_DFL
); /* No, SIGCLD isn't a typo... */
1075 #endif /* HAVE_SIGSET */
1080 * 'cupsdReleaseSignals()' - Release signals for delivery.
1084 cupsdReleaseSignals(void)
1093 #elif defined(HAVE_SIGACTION)
1094 sigprocmask(SIG_SETMASK
, &holdmask
, NULL
);
1095 #endif /* HAVE_SIGSET */
1100 * 'cupsdSetString()' - Set a string value.
1104 cupsdSetString(char **s
, /* O - New string */
1105 const char *v
) /* I - String value */
1121 * 'cupsdSetStringf()' - Set a formatted string value.
1125 cupsdSetStringf(char **s
, /* O - New string */
1126 const char *f
, /* I - Printf-style format string */
1127 ...) /* I - Additional args as needed */
1129 char v
[4096]; /* Formatting string value */
1130 va_list ap
; /* Argument pointer */
1131 char *olds
; /* Old string */
1142 vsnprintf(v
, sizeof(v
), f
, ap
);
1156 * 'parent_handler()' - Catch USR1/CHLD signals...
1160 parent_handler(int sig
) /* I - Signal */
1163 * Store the signal we got from the OS and return...
1166 parent_signal
= sig
;
1171 * 'process_children()' - Process all dead children...
1175 process_children(void)
1177 int status
; /* Exit status of child */
1178 int pid
; /* Process ID of child */
1179 cupsd_job_t
*job
; /* Current job */
1180 int i
; /* Looping var */
1183 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "process_children()");
1186 * Reset the dead_children flag...
1192 * Collect the exit status of some children...
1196 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0)
1197 #elif defined(HAVE_WAIT3)
1198 while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0)
1200 if ((pid
= wait(&status
)) > 0)
1201 #endif /* HAVE_WAITPID */
1203 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
1204 "process_children: pid = %d, status = %d\n", pid
, status
);
1207 * Ignore SIGTERM errors - that comes when a job is cancelled...
1210 if (status
== SIGTERM
)
1215 if (WIFEXITED(status
))
1216 cupsdLogMessage(CUPSD_LOG_ERROR
, "PID %d stopped with status %d!", pid
,
1217 WEXITSTATUS(status
));
1219 cupsdLogMessage(CUPSD_LOG_ERROR
, "PID %d crashed on signal %d!", pid
,
1222 if (LogLevel
< CUPSD_LOG_DEBUG
)
1223 cupsdLogMessage(CUPSD_LOG_INFO
,
1224 "Hint: Try setting the LogLevel to \"debug\" to find out more.");
1227 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "PID %d exited with no errors.", pid
);
1230 * Delete certificates for CGI processes...
1234 cupsdDeleteCert(pid
);
1237 * Lookup the PID in the jobs list...
1240 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
1242 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
1243 if (job
->state
!= NULL
&&
1244 job
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
1246 for (i
= 0; job
->filters
[i
]; i
++)
1247 if (job
->filters
[i
] == pid
)
1250 if (job
->filters
[i
] || job
->backend
== pid
)
1253 * OK, this process has gone away; what's left?
1256 if (job
->filters
[i
])
1257 job
->filters
[i
] = -pid
;
1259 job
->backend
= -pid
;
1261 if (status
&& job
->status
>= 0)
1264 * An error occurred; save the exit status so we know to stop
1265 * the printer or cancel the job when all of the filters finish...
1267 * A negative status indicates that the backend failed and the
1268 * printer needs to be stopped.
1271 if (job
->filters
[i
])
1272 job
->status
= status
; /* Filter failed */
1274 job
->status
= -status
; /* Backend failed */
1278 * If this is not the last file in a job, see if all of the
1279 * filters are done, and if so move to the next file.
1282 if (job
->current_file
< job
->num_files
)
1284 for (i
= 0; job
->filters
[i
] < 0; i
++);
1286 if (!job
->filters
[i
])
1289 * Process the next file...
1292 cupsdFinishJob(job
);
1303 * 'sigchld_handler()' - Handle 'child' signals from old processes.
1307 sigchld_handler(int sig
) /* I - Signal number */
1312 * Flag that we have dead children...
1318 * Reset the signal handler as needed...
1321 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1322 signal(SIGCLD
, sigchld_handler
);
1323 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1328 * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler.
1332 sighup_handler(int sig
) /* I - Signal number */
1336 NeedReload
= RELOAD_ALL
;
1337 ReloadTime
= time(NULL
);
1339 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1340 signal(SIGHUP
, sighup_handler
);
1341 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1346 * 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler.
1350 sigterm_handler(int sig
) /* I - Signal */
1352 (void)sig
; /* remove compiler warnings... */
1355 * Flag that we should stop and return...
1363 * 'select_timeout()' - Calculate the select timeout value.
1367 static long /* O - Number of seconds */
1368 select_timeout(int fds
) /* I - Number of ready descriptors select returned */
1370 int i
; /* Looping var */
1371 long timeout
; /* Timeout for select */
1372 time_t now
; /* Current time */
1373 cupsd_client_t
*con
; /* Client information */
1374 cupsd_printer_t
*p
; /* Printer information */
1375 cupsd_job_t
*job
; /* Job information */
1376 cupsd_subscription_t
*sub
; /* Subscription information */
1377 const char *why
; /* Debugging aid */
1381 * Check to see if any of the clients have pending data to be
1382 * processed; if so, the timeout should be 0...
1385 for (i
= NumClients
, con
= Clients
; i
> 0; i
--, con
++)
1386 if (con
->http
.used
> 0)
1390 * If select has been active in the last second (fds != 0) or we have
1391 * many resources in use then don't bother trying to optimize the
1392 * timeout, just make it 1 second.
1395 if (fds
|| NumClients
> 50)
1399 * If we had a recent event notification, timeout in 1 second...
1406 * Otherwise, check all of the possible events that we need to wake for...
1410 timeout
= now
+ 86400; /* 86400 == 1 day */
1414 * Check the activity and close old clients...
1417 for (i
= NumClients
, con
= Clients
; i
> 0; i
--, con
++)
1418 if ((con
->http
.activity
+ Timeout
) < timeout
)
1420 timeout
= con
->http
.activity
+ Timeout
;
1421 why
= "timeout a client connection";
1425 * Update the browse list as needed...
1428 if (Browsing
&& BrowseLocalProtocols
)
1431 if ((BrowseLocalProtocols
& BROWSE_SLP
) && (BrowseSLPRefresh
< timeout
))
1433 timeout
= BrowseSLPRefresh
;
1434 why
= "update SLP browsing";
1436 #endif /* HAVE_LIBSLP */
1438 if (BrowseLocalProtocols
& BROWSE_CUPS
)
1440 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1442 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1444 if (p
->type
& CUPS_PRINTER_REMOTE
)
1446 if ((p
->browse_time
+ BrowseTimeout
) < timeout
)
1448 timeout
= p
->browse_time
+ BrowseTimeout
;
1449 why
= "browse timeout a printer";
1452 else if (!(p
->type
& CUPS_PRINTER_IMPLICIT
))
1454 if (BrowseInterval
&& (p
->browse_time
+ BrowseInterval
) < timeout
)
1456 timeout
= p
->browse_time
+ BrowseInterval
;
1457 why
= "send browse update";
1465 * Check for any active jobs...
1468 if (timeout
> (now
+ 10) && ActiveJobs
)
1470 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
1472 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
1473 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
)
1476 why
= "process active jobs";
1481 #ifdef HAVE_MALLINFO
1483 * Log memory usage every minute...
1486 if (LogLevel
>= CUPSD_LOG_DEBUG
&& (mallinfo_time
+ 60) < timeout
)
1488 timeout
= mallinfo_time
+ 60;
1489 why
= "display memory usage";
1491 #endif /* HAVE_MALLINFO */
1494 * Update the root certificate when needed...
1497 if (!RunUser
&& RootCertDuration
&&
1498 (RootCertTime
+ RootCertDuration
) < timeout
)
1500 timeout
= RootCertTime
+ RootCertDuration
;
1501 why
= "update root certificate";
1505 * Expire subscriptions as needed...
1508 for (sub
= (cupsd_subscription_t
*)cupsArrayFirst(Subscriptions
);
1510 sub
= (cupsd_subscription_t
*)cupsArrayNext(Subscriptions
))
1511 if (!sub
->job
&& sub
->expire
< timeout
)
1513 timeout
= sub
->expire
;
1514 why
= "expire subscription";
1518 * Adjust from absolute to relative time. If p->browse_time above
1519 * was 0 then we can end up with a negative value here, so check.
1520 * We add 1 second to the timeout since events occur after the
1521 * timeout expires, and limit the timeout to 86400 seconds (1 day)
1522 * to avoid select() timeout limits present on some operating
1526 timeout
= timeout
- now
+ 1;
1530 else if (timeout
> 86400)
1534 * Log and return the timeout value...
1537 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "select_timeout: %ld seconds to %s",
1545 * 'usage()' - Show scheduler usage.
1551 fputs("Usage: cupsd [-c config-file] [-f] [-F]\n", stderr
);
1557 * End of "$Id: main.c 4993 2006-01-26 19:27:40Z mike $".