]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/main.c
4 * Scheduler main loop for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2005 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 * CatchChildSignals() - Catch SIGCHLD signals...
30 * HoldSignals() - Hold child and termination signals.
31 * IgnoreChildSignals() - Ignore SIGCHLD signals...
32 * ReleaseSignals() - Release signals for delivery.
33 * SetString() - Set a string value.
34 * SetStringf() - 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 scheduler.
39 * sigterm_handler() - Handle 'terminate' signals that stop the scheduler.
40 * select_timeout() - Calculate the select timeout value.
41 * usage() - Show scheduler usage.
45 * Include necessary headers...
50 #include <sys/resource.h>
54 #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
56 #endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
63 static void parent_handler(int sig
);
64 static void process_children(void);
65 static void sigchld_handler(int sig
);
66 static void sighup_handler(int sig
);
67 static void sigterm_handler(int sig
);
68 static long select_timeout(int fds
);
69 static void usage(void);
76 static int parent_signal
= 0; /* Set to signal number from child */
77 static int holdcount
= 0; /* Number of times "hold" was called */
78 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
79 static sigset_t holdmask
; /* Old POSIX signal mask */
80 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
81 static int dead_children
= 0; /* Dead children? */
82 static int stop_scheduler
= 0; /* Should the scheduler stop? */
86 * 'main()' - Main entry for the CUPS scheduler.
89 int /* O - Exit status */
90 main(int argc
, /* I - Number of command-line arguments */
91 char *argv
[]) /* I - Command-line arguments */
93 int i
; /* Looping var */
94 char *opt
; /* Option character */
95 int fg
; /* Run in the foreground */
96 int fds
; /* Number of ready descriptors select returns */
97 fd_set
*input
, /* Input set for select() */
98 *output
; /* Output set for select() */
99 client_t
*con
; /* Current client */
100 job_t
*job
, /* Current job */
101 *next
; /* Next job */
102 listener_t
*lis
; /* Current listener */
103 time_t activity
; /* Activity timer */
104 time_t browse_time
; /* Next browse send time */
105 time_t senddoc_time
; /* Send-Document time */
107 time_t mallinfo_time
; /* Malloc information time */
108 #endif /* HAVE_MALLINFO */
109 struct timeval timeout
; /* select() timeout */
110 struct rlimit limit
; /* Runtime limit */
111 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
112 struct sigaction action
; /* Actions for POSIX signals */
113 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
115 cups_file_t
*fp
; /* Fake lpsched lock file */
116 struct stat statbuf
; /* Needed for checking lpsched FIFO */
121 * Check for command-line arguments...
126 for (i
= 1; i
< argc
; i
++)
127 if (argv
[i
][0] == '-')
128 for (opt
= argv
[i
] + 1; *opt
!= '\0'; opt
++)
131 case 'c' : /* Configuration file */
136 if (argv
[i
][0] == '/')
139 * Absolute directory...
142 SetString(&ConfigurationFile
, argv
[i
]);
147 * Relative directory...
150 char current
[1024]; /* Current directory */
153 getcwd(current
, sizeof(current
));
154 SetStringf(&ConfigurationFile
, "%s/%s", current
, argv
[i
]);
158 case 'f' : /* Run in foreground... */
162 case 'F' : /* Run in foreground, but still disconnect from terminal... */
166 default : /* Unknown option */
167 fprintf(stderr
, "cupsd: Unknown option \'%c\' - aborting!\n", *opt
);
173 fprintf(stderr
, "cupsd: Unknown argument \'%s\' - aborting!\n", argv
[i
]);
177 if (!ConfigurationFile
)
178 SetString(&ConfigurationFile
, CUPS_SERVERROOT
"/cupsd.conf");
181 * If the user hasn't specified "-f", run in the background...
187 * Setup signal handlers for the parent...
190 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
191 sigset(SIGUSR1
, parent_handler
);
192 sigset(SIGCHLD
, parent_handler
);
194 sigset(SIGHUP
, SIG_IGN
);
195 #elif defined(HAVE_SIGACTION)
196 memset(&action
, 0, sizeof(action
));
197 sigemptyset(&action
.sa_mask
);
198 sigaddset(&action
.sa_mask
, SIGUSR1
);
199 action
.sa_handler
= parent_handler
;
200 sigaction(SIGUSR1
, &action
, NULL
);
201 sigaction(SIGCHLD
, &action
, NULL
);
203 sigemptyset(&action
.sa_mask
);
204 action
.sa_handler
= SIG_IGN
;
205 sigaction(SIGHUP
, &action
, NULL
);
207 signal(SIGUSR1
, parent_handler
);
208 signal(SIGCLD
, parent_handler
);
210 signal(SIGHUP
, SIG_IGN
);
211 #endif /* HAVE_SIGSET */
216 * OK, wait for the child to startup and send us SIGUSR1 or to crash
217 * and the OS send us SIGCHLD... We also need to ignore SIGHUP which
218 * might be sent by the init script to restart the scheduler...
221 for (; parent_signal
== 0;)
224 if (parent_signal
== SIGUSR1
)
232 else if (WIFEXITED(i
))
234 fprintf(stderr
, "cupsd: Child exited with status %d!\n", WEXITSTATUS(i
));
239 fprintf(stderr
, "cupsd: Child exited on signal %d!\n", WTERMSIG(i
));
248 * Make sure we aren't tying up any filesystems...
255 * Disable core dumps...
258 getrlimit(RLIMIT_CORE
, &limit
);
260 setrlimit(RLIMIT_CORE
, &limit
);
263 * Disconnect from the controlling terminal...
269 * Close all open files...
272 getrlimit(RLIMIT_NOFILE
, &limit
);
274 for (i
= 0; i
< limit
.rlim_cur
; i
++)
280 * Set the timezone info...
283 if (getenv("TZ") != NULL
)
284 SetStringf(&TZ
, "TZ=%s", getenv("TZ"));
291 setlocale(LC_TIME
, "");
295 * Set the maximum number of files...
298 getrlimit(RLIMIT_NOFILE
, &limit
);
300 if (limit
.rlim_max
> CUPS_MAX_FDS
)
301 MaxFDs
= CUPS_MAX_FDS
;
303 MaxFDs
= limit
.rlim_max
;
305 limit
.rlim_cur
= MaxFDs
;
307 setrlimit(RLIMIT_NOFILE
, &limit
);
310 * Allocate memory for the input and output sets...
313 SetSize
= (MaxFDs
+ 31) / 8 + 4;
314 if (SetSize
< sizeof(fd_set
))
315 SetSize
= sizeof(fd_set
);
317 InputSet
= (fd_set
*)calloc(1, SetSize
);
318 OutputSet
= (fd_set
*)calloc(1, SetSize
);
319 input
= (fd_set
*)calloc(1, SetSize
);
320 output
= (fd_set
*)calloc(1, SetSize
);
322 if (InputSet
== NULL
|| OutputSet
== NULL
|| input
== NULL
|| output
== NULL
)
324 syslog(LOG_LPR
, "Unable to allocate memory for select() sets - exiting!");
329 * Read configuration...
332 if (!ReadConfiguration())
334 syslog(LOG_LPR
, "Unable to read configuration file \'%s\' - exiting!",
340 * Catch hangup and child signals and ignore broken pipes...
343 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
345 sigset(SIGHUP
, sigterm_handler
);
347 sigset(SIGHUP
, sighup_handler
);
349 sigset(SIGPIPE
, SIG_IGN
);
350 sigset(SIGTERM
, sigterm_handler
);
351 #elif defined(HAVE_SIGACTION)
352 memset(&action
, 0, sizeof(action
));
354 sigemptyset(&action
.sa_mask
);
355 sigaddset(&action
.sa_mask
, SIGHUP
);
358 action
.sa_handler
= sigterm_handler
;
360 action
.sa_handler
= sighup_handler
;
362 sigaction(SIGHUP
, &action
, NULL
);
364 sigemptyset(&action
.sa_mask
);
365 action
.sa_handler
= SIG_IGN
;
366 sigaction(SIGPIPE
, &action
, NULL
);
368 sigemptyset(&action
.sa_mask
);
369 sigaddset(&action
.sa_mask
, SIGTERM
);
370 sigaddset(&action
.sa_mask
, SIGCHLD
);
371 action
.sa_handler
= sigterm_handler
;
372 sigaction(SIGTERM
, &action
, NULL
);
375 signal(SIGHUP
, sigterm_handler
);
377 signal(SIGHUP
, sighup_handler
);
379 signal(SIGPIPE
, SIG_IGN
);
380 signal(SIGTERM
, sigterm_handler
);
381 #endif /* HAVE_SIGSET */
385 * Try to create a fake lpsched lock file if one is not already there.
386 * Some Adobe applications need it under IRIX in order to enable
390 if ((fp
= cupsFileOpen("/var/spool/lp/SCHEDLOCK", "w")) == NULL
)
392 syslog(LOG_LPR
, "Unable to create fake lpsched lock file "
393 "\"/var/spool/lp/SCHEDLOCK\"\' - %s!",
398 fchmod(cupsFileNumber(fp
), 0644);
399 fchown(cupsFileNumber(fp
), User
, Group
);
406 * Initialize authentication certificates...
412 * If we are running in the background, signal the parent process that
413 * we are up and running...
419 * Send a signal to the parent process, but only if the parent is
420 * not PID 1 (init). This avoids accidentally shutting down the
421 * system on OpenBSD if you CTRL-C the server before it is up...
424 i
= getppid(); /* Save parent PID to avoid race condition */
431 * If the administrator has configured the server to run as an unpriviledged
432 * user, change to that user now...
438 setgroups(1, &Group
);
449 * Start any pending print jobs...
460 #endif /* HAVE_MALLINFO */
461 browse_time
= time(NULL
);
462 senddoc_time
= time(NULL
);
465 while (!stop_scheduler
)
468 LogMessage(L_DEBUG2
, "main: Top of loop, dead_children=%d, NeedReload=%d",
469 dead_children
, NeedReload
);
473 * Check if there are dead children to handle...
480 * Check if we need to load the server configuration file...
486 * Close any idle clients...
491 for (i
= NumClients
, con
= Clients
; i
> 0; i
--, con
++)
492 if (con
->http
.state
== HTTP_WAITING
)
498 con
->http
.keep_alive
= HTTP_KEEPALIVE_OFF
;
504 * Check for any active jobs...
507 for (job
= Jobs
; job
; job
= job
->next
)
508 if (job
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
512 * Restart if all clients are closed and all jobs finished, or
513 * if the reload timeout has elapsed...
516 if ((NumClients
== 0 && (!job
|| NeedReload
!= RELOAD_ALL
)) ||
517 (time(NULL
) - ReloadTime
) >= ReloadTimeout
)
519 if (!ReadConfiguration())
521 syslog(LOG_LPR
, "Unable to read configuration file \'%s\' - exiting!",
529 * Check for available input or ready output. If select() returns
530 * 0 or -1, something bad happened and we should exit immediately.
532 * Note that we at least have one listening socket open at all
536 memcpy(input
, InputSet
, SetSize
);
537 memcpy(output
, OutputSet
, SetSize
);
539 timeout
.tv_sec
= select_timeout(fds
);
542 if ((fds
= select(MaxFDs
, input
, output
, NULL
, &timeout
)) < 0)
544 char s
[16384], /* String buffer */
545 *sptr
; /* Pointer into buffer */
546 int slen
; /* Length of string buffer */
550 * Got an error from select!
553 if (errno
== EINTR
) /* Just interrupted by a signal */
557 * Log all sorts of debug info to help track down the problem.
560 LogMessage(L_EMERG
, "select() failed - %s!", strerror(errno
));
562 strcpy(s
, "InputSet =");
566 for (i
= 0; i
< MaxFDs
; i
++)
567 if (FD_ISSET(i
, InputSet
))
569 snprintf(sptr
, sizeof(s
) - slen
, " %d", i
);
570 slen
+= strlen(sptr
);
571 sptr
+= strlen(sptr
);
574 LogMessage(L_EMERG
, s
);
576 strcpy(s
, "OutputSet =");
580 for (i
= 0; i
< MaxFDs
; i
++)
581 if (FD_ISSET(i
, OutputSet
))
583 snprintf(sptr
, sizeof(s
) - slen
, " %d", i
);
584 slen
+= strlen(sptr
);
585 sptr
+= strlen(sptr
);
588 LogMessage(L_EMERG
, s
);
590 for (i
= 0, con
= Clients
; i
< NumClients
; i
++, con
++)
591 LogMessage(L_EMERG
, "Clients[%d] = %d, file = %d, state = %d",
592 i
, con
->http
.fd
, con
->file
, con
->http
.state
);
594 for (i
= 0, lis
= Listeners
; i
< NumListeners
; i
++, lis
++)
595 LogMessage(L_EMERG
, "Listeners[%d] = %d", i
, lis
->fd
);
597 LogMessage(L_EMERG
, "BrowseSocket = %d", BrowseSocket
);
599 for (job
= Jobs
; job
!= NULL
; job
= job
->next
)
600 LogMessage(L_EMERG
, "Jobs[%d] = %d < [%d %d] > [%d %d]",
601 job
->id
, job
->status_buffer
? job
->status_buffer
->fd
: -1,
602 job
->print_pipes
[0], job
->print_pipes
[1],
603 job
->back_pipes
[0], job
->back_pipes
[1]);
609 * Check for status info from job filters...
612 for (job
= Jobs
; job
!= NULL
; job
= next
)
616 if (job
->status_buffer
&& FD_ISSET(job
->status_buffer
->fd
, input
))
619 * Clear the input bit to avoid updating the next job
620 * using the same status pipe file descriptor...
623 FD_CLR(job
->status_buffer
->fd
, input
);
626 * Read any status messages from the filters...
634 * Update CGI messages as needed...
637 if (CGIPipes
[0] >= 0 && FD_ISSET(CGIPipes
[0], input
))
641 * Update the browse list as needed...
644 if (Browsing
&& (BrowseLocalProtocols
| BrowseRemoteProtocols
))
646 if (BrowseSocket
>= 0 && FD_ISSET(BrowseSocket
, input
))
649 if (PollPipe
>= 0 && FD_ISSET(PollPipe
, input
))
653 if (((BrowseLocalProtocols
| BrowseRemoteProtocols
) & BROWSE_SLP
) &&
654 BrowseSLPRefresh
<= time(NULL
))
656 #endif /* HAVE_LIBSLP */
658 if (time(NULL
) > browse_time
)
661 browse_time
= time(NULL
);
666 * Check for new connections on the "listen" sockets...
669 for (i
= NumListeners
, lis
= Listeners
; i
> 0; i
--, lis
++)
670 if (FD_ISSET(lis
->fd
, input
))
672 FD_CLR(lis
->fd
, input
);
677 * Check for new data on the client sockets...
680 for (i
= NumClients
, con
= Clients
; i
> 0; i
--, con
++)
683 * Process the input buffer...
686 if (FD_ISSET(con
->http
.fd
, input
) || con
->http
.used
)
688 FD_CLR(con
->http
.fd
, input
);
690 if (!ReadClient(con
))
693 FD_CLR(con
->file
, input
);
701 * Write data as needed...
704 if (con
->pipe_pid
&& FD_ISSET(con
->file
, input
))
707 * Keep track of pending input from the file/pipe separately
708 * so that we don't needlessly spin on select() when the web
709 * client is not ready to receive data...
712 FD_CLR(con
->file
, input
);
716 LogMessage(L_DEBUG2
, "main: Data ready file %d!", con
->file
);
719 if (!FD_ISSET(con
->http
.fd
, output
))
721 LogMessage(L_DEBUG2
, "main: Removing fd %d from InputSet...", con
->file
);
722 FD_CLR(con
->file
, InputSet
);
726 if (FD_ISSET(con
->http
.fd
, output
))
728 FD_CLR(con
->http
.fd
, output
);
730 if (!con
->pipe_pid
|| con
->file_ready
)
731 if (!WriteClient(con
))
739 * Check the activity and close old clients...
742 activity
= time(NULL
) - Timeout
;
743 if (con
->http
.activity
< activity
&& !con
->pipe_pid
)
745 LogMessage(L_DEBUG
, "Closing client %d after %d seconds of inactivity...",
746 con
->http
.fd
, Timeout
);
755 * Update any pending multi-file documents...
758 if ((time(NULL
) - senddoc_time
) >= 10)
761 senddoc_time
= time(NULL
);
766 * Log memory usage every minute...
769 if ((time(NULL
) - mallinfo_time
) >= 60 && LogLevel
>= L_DEBUG
)
771 struct mallinfo mem
; /* Malloc information */
775 LogMessage(L_DEBUG
, "mallinfo: arena = %d, used = %d, free = %d\n",
776 mem
.arena
, mem
.usmblks
+ mem
.uordblks
,
777 mem
.fsmblks
+ mem
.fordblks
);
778 mallinfo_time
= time(NULL
);
780 #endif /* HAVE_MALLINFO */
783 * Update the root certificate once every 5 minutes...
786 if ((time(NULL
) - RootCertTime
) >= RootCertDuration
&& RootCertDuration
&&
790 * Update the root certificate...
799 * Log a message based on what happened...
803 LogMessage(L_INFO
, "Scheduler shutting down normally.");
805 LogMessage(L_ERROR
, "Scheduler shutting down due to program error.");
808 * Close all network clients and stop all jobs...
817 * Remove the fake IRIX lpsched lock file, but only if the existing
818 * file is not a FIFO which indicates that the real IRIX lpsched is
822 if (!stat("/var/spool/lp/FIFO", &statbuf
))
823 if (!S_ISFIFO(statbuf
.st_mode
))
824 unlink("/var/spool/lp/SCHEDLOCK");
828 * Free memory used by FD sets and return...
836 return (!stop_scheduler
);
841 * 'cupsdClosePipe()' - Close a pipe as necessary.
845 cupsdClosePipe(int *fds
) /* I - Pipe file descriptors (2) */
848 * Close file descriptors as needed...
866 * 'cupsdOpenPipe()' - Create a pipe which is closed on exec.
869 int /* O - 0 on success, -1 on error */
870 cupsdOpenPipe(int *fds
) /* O - Pipe file descriptors (2) */
880 * Set the "close on exec" flag on each end of the pipe...
883 if (fcntl(fds
[0], F_SETFD
, fcntl(fds
[0], F_GETFD
) | FD_CLOEXEC
))
890 if (fcntl(fds
[1], F_SETFD
, fcntl(fds
[1], F_GETFD
) | FD_CLOEXEC
))
898 * Return 0 indicating success...
906 * 'CatchChildSignals()' - Catch SIGCHLD signals...
910 CatchChildSignals(void)
912 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
913 struct sigaction action
; /* Actions for POSIX signals */
914 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
917 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
918 sigset(SIGCHLD
, sigchld_handler
);
919 #elif defined(HAVE_SIGACTION)
920 memset(&action
, 0, sizeof(action
));
922 sigemptyset(&action
.sa_mask
);
923 sigaddset(&action
.sa_mask
, SIGTERM
);
924 sigaddset(&action
.sa_mask
, SIGCHLD
);
925 action
.sa_handler
= sigchld_handler
;
926 sigaction(SIGCHLD
, &action
, NULL
);
928 signal(SIGCLD
, sigchld_handler
); /* No, SIGCLD isn't a typo... */
929 #endif /* HAVE_SIGSET */
934 * 'ClearString()' - Clear a string.
938 ClearString(char **s
) /* O - String value */
949 * 'HoldSignals()' - Hold child and termination signals.
955 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
956 sigset_t newmask
; /* New POSIX signal mask */
957 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
967 #elif defined(HAVE_SIGACTION)
968 sigemptyset(&newmask
);
969 sigaddset(&newmask
, SIGTERM
);
970 sigaddset(&newmask
, SIGCHLD
);
971 sigprocmask(SIG_BLOCK
, &newmask
, &holdmask
);
972 #endif /* HAVE_SIGSET */
977 * 'IgnoreChildSignals()' - Ignore SIGCHLD signals...
979 * We don't really ignore them, we set the signal handler to SIG_DFL,
980 * since some OS's rely on signals for the wait4() function to work.
984 IgnoreChildSignals(void)
986 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
987 struct sigaction action
; /* Actions for POSIX signals */
988 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
991 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
992 sigset(SIGCHLD
, SIG_DFL
);
993 #elif defined(HAVE_SIGACTION)
994 memset(&action
, 0, sizeof(action
));
996 sigemptyset(&action
.sa_mask
);
997 sigaddset(&action
.sa_mask
, SIGCHLD
);
998 action
.sa_handler
= SIG_DFL
;
999 sigaction(SIGCHLD
, &action
, NULL
);
1001 signal(SIGCLD
, SIG_DFL
); /* No, SIGCLD isn't a typo... */
1002 #endif /* HAVE_SIGSET */
1007 * 'ReleaseSignals()' - Release signals for delivery.
1011 ReleaseSignals(void)
1020 #elif defined(HAVE_SIGACTION)
1021 sigprocmask(SIG_SETMASK
, &holdmask
, NULL
);
1022 #endif /* HAVE_SIGSET */
1027 * 'SetString()' - Set a string value.
1031 SetString(char **s
, /* O - New string */
1032 const char *v
) /* I - String value */
1048 * 'SetStringf()' - Set a formatted string value.
1052 SetStringf(char **s
, /* O - New string */
1053 const char *f
, /* I - Printf-style format string */
1054 ...) /* I - Additional args as needed */
1056 char v
[1024]; /* Formatting string value */
1057 va_list ap
; /* Argument pointer */
1058 char *olds
; /* Old string */
1069 vsnprintf(v
, sizeof(v
), f
, ap
);
1083 * 'parent_handler()' - Catch USR1/CHLD signals...
1087 parent_handler(int sig
) /* I - Signal */
1090 * Store the signal we got from the OS and return...
1093 parent_signal
= sig
;
1098 * 'process_children()' - Process all dead children...
1102 process_children(void)
1104 int status
; /* Exit status of child */
1105 int pid
; /* Process ID of child */
1106 job_t
*job
; /* Current job */
1107 int i
; /* Looping var */
1110 LogMessage(L_DEBUG2
, "process_children()");
1113 * Reset the dead_children flag...
1119 * Collect the exit status of some children...
1123 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0)
1124 #elif defined(HAVE_WAIT3)
1125 while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0)
1127 if ((pid
= wait(&status
)) > 0)
1128 #endif /* HAVE_WAITPID */
1130 LogMessage(L_DEBUG2
, "process_children: pid = %d, status = %d\n", pid
, status
);
1133 * Ignore SIGTERM errors - that comes when a job is cancelled...
1136 if (status
== SIGTERM
)
1141 if (WIFEXITED(status
))
1142 LogMessage(L_ERROR
, "PID %d stopped with status %d!", pid
,
1143 WEXITSTATUS(status
));
1145 LogMessage(L_ERROR
, "PID %d crashed on signal %d!", pid
,
1148 if (LogLevel
< L_DEBUG
)
1149 LogMessage(L_INFO
, "Hint: Try setting the LogLevel to \"debug\" to find out more.");
1152 LogMessage(L_DEBUG2
, "PID %d exited with no errors.", pid
);
1155 * Delete certificates for CGI processes...
1162 * Lookup the PID in the jobs list...
1165 for (job
= Jobs
; job
!= NULL
; job
= job
->next
)
1166 if (job
->state
!= NULL
&&
1167 job
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
1169 for (i
= 0; job
->filters
[i
]; i
++)
1170 if (job
->filters
[i
] == pid
)
1173 if (job
->filters
[i
] || job
->backend
== pid
)
1176 * OK, this process has gone away; what's left?
1179 if (job
->filters
[i
])
1180 job
->filters
[i
] = -pid
;
1182 job
->backend
= -pid
;
1184 if (status
&& job
->status
>= 0)
1187 * An error occurred; save the exit status so we know to stop
1188 * the printer or cancel the job when all of the filters finish...
1190 * A negative status indicates that the backend failed and the
1191 * printer needs to be stopped.
1194 if (job
->filters
[i
])
1195 job
->status
= status
; /* Filter failed */
1197 job
->status
= -status
; /* Backend failed */
1201 * If this is not the last file in a job, see if all of the
1202 * filters are done, and if so move to the next file.
1205 if (job
->current_file
< job
->num_files
)
1207 for (i
= 0; job
->filters
[i
] < 0; i
++);
1209 if (!job
->filters
[i
])
1212 * Process the next file...
1226 * 'sigchld_handler()' - Handle 'child' signals from old processes.
1230 sigchld_handler(int sig
) /* I - Signal number */
1235 * Flag that we have dead children...
1241 * Reset the signal handler as needed...
1244 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1245 signal(SIGCLD
, sigchld_handler
);
1246 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1251 * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler.
1255 sighup_handler(int sig
) /* I - Signal number */
1259 NeedReload
= RELOAD_ALL
;
1260 ReloadTime
= time(NULL
);
1262 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1263 signal(SIGHUP
, sighup_handler
);
1264 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1269 * 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler.
1273 sigterm_handler(int sig
) /* I - Signal */
1275 (void)sig
; /* remove compiler warnings... */
1278 * Flag that we should stop and return...
1286 * 'select_timeout()' - Calculate the select timeout value.
1290 static long /* O - Number of seconds */
1291 select_timeout(int fds
) /* I - Number of ready descriptors select returned */
1293 int i
; /* Looping var */
1294 long timeout
; /* Timeout for select */
1295 time_t now
; /* Current time */
1296 client_t
*con
; /* Client information */
1297 printer_t
*p
; /* Printer information */
1298 job_t
*job
; /* Job information */
1299 const char *why
; /* Debugging aid */
1303 * Check to see if any of the clients have pending data to be
1304 * processed; if so, the timeout should be 0...
1307 for (i
= NumClients
, con
= Clients
; i
> 0; i
--, con
++)
1308 if (con
->http
.used
> 0)
1312 * If select has been active in the last second (fds != 0) or we have
1313 * many resources in use then don't bother trying to optimize the
1314 * timeout, just make it 1 second.
1317 if (fds
|| NumClients
> 50)
1321 * Otherwise, check all of the possible events that we need to wake for...
1325 timeout
= now
+ 86400; /* 86400 == 1 day */
1329 * Check the activity and close old clients...
1332 for (i
= NumClients
, con
= Clients
; i
> 0; i
--, con
++)
1333 if ((con
->http
.activity
+ Timeout
) < timeout
)
1335 timeout
= con
->http
.activity
+ Timeout
;
1336 why
= "timeout a client connection";
1340 * Update the browse list as needed...
1343 if (Browsing
&& BrowseLocalProtocols
)
1346 if ((BrowseLocalProtocols
& BROWSE_SLP
) && (BrowseSLPRefresh
< timeout
))
1348 timeout
= BrowseSLPRefresh
;
1349 why
= "update SLP browsing";
1351 #endif /* HAVE_LIBSLP */
1353 if (BrowseLocalProtocols
& BROWSE_CUPS
)
1355 for (p
= Printers
; p
!= NULL
; p
= p
->next
)
1357 if (p
->type
& CUPS_PRINTER_REMOTE
)
1359 if ((p
->browse_time
+ BrowseTimeout
) < timeout
)
1361 timeout
= p
->browse_time
+ BrowseTimeout
;
1362 why
= "browse timeout a printer";
1365 else if (!(p
->type
& CUPS_PRINTER_IMPLICIT
))
1367 if (BrowseInterval
&& (p
->browse_time
+ BrowseInterval
) < timeout
)
1369 timeout
= p
->browse_time
+ BrowseInterval
;
1370 why
= "send browse update";
1378 * Check for any active jobs...
1381 if (timeout
> (now
+ 10))
1383 for (job
= Jobs
; job
!= NULL
; job
= job
->next
)
1384 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
)
1387 why
= "process active jobs";
1392 #ifdef HAVE_MALLINFO
1394 * Log memory usage every minute...
1397 if (LogLevel
>= L_DEBUG
&& (mallinfo_time
+ 60) < timeout
)
1399 timeout
= mallinfo_time
+ 60;
1400 why
= "display memory usage";
1402 #endif /* HAVE_MALLINFO */
1405 * Update the root certificate when needed...
1408 if (!RunUser
&& RootCertDuration
&&
1409 (RootCertTime
+ RootCertDuration
) < timeout
)
1411 timeout
= RootCertTime
+ RootCertDuration
;
1412 why
= "update root certificate";
1416 * Adjust from absolute to relative time. If p->browse_time above
1417 * was 0 then we can end up with a negative value here, so check.
1418 * We add 1 second to the timeout since events occur after the
1419 * timeout expires, and limit the timeout to 86400 seconds (1 day)
1420 * to avoid select() timeout limits present on some operating
1424 timeout
= timeout
- now
+ 1;
1428 else if (timeout
> 86400)
1432 * Log and return the timeout value...
1435 LogMessage(L_DEBUG2
, "select_timeout: %ld seconds to %s", timeout
, why
);
1442 * 'usage()' - Show scheduler usage.
1448 fputs("Usage: cupsd [-c config-file] [-f] [-F]\n", stderr
);