• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Main loop for the CUPS scheduler.
3  *
4  * Copyright © 2020-2024 by OpenPrinting.
5  * Copyright © 2007-2019 by Apple Inc.
6  * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
7  *
8  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
9  * information.
10  */
11 
12 /*
13  * Include necessary headers...
14  */
15 
16 #define _MAIN_C_
17 #include "cupsd.h"
18 #include <sys/resource.h>
19 #ifdef __APPLE__
20 #  include <xpc/xpc.h>
21 #  include <pthread/qos.h>
22 #endif /* __APPLE__ */
23 #ifdef HAVE_ASL_H
24 #  include <asl.h>
25 #elif defined(HAVE_SYSTEMD_SD_JOURNAL_H)
26 #  define SD_JOURNAL_SUPPRESS_LOCATION
27 #  include <systemd/sd-journal.h>
28 #endif /* HAVE_ASL_H */
29 #include <syslog.h>
30 #include <grp.h>
31 
32 #ifdef HAVE_LAUNCH_H
33 #  include <launch.h>
34 #endif /* HAVE_LAUNCH_H */
35 
36 #ifdef HAVE_SYSTEMD
37 #  include <systemd/sd-daemon.h>
38 #endif /* HAVE_SYSTEMD */
39 
40 #ifdef HAVE_ONDEMAND
41 #  define CUPS_KEEPALIVE CUPS_CACHEDIR "/org.cups.cupsd"
42 					/* Name of the KeepAlive file */
43 #endif /* HAVE_ONDEMAND */
44 
45 #if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
46 #  include <malloc.h>
47 #endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
48 
49 #ifdef HAVE_NOTIFY_H
50 #  include <notify.h>
51 #endif /* HAVE_NOTIFY_H */
52 
53 #ifdef HAVE_DBUS
54 #  include <dbus/dbus.h>
55 #endif /* HAVE_DBUS */
56 
57 #ifdef HAVE_SYS_PARAM_H
58 #  include <sys/param.h>
59 #endif /* HAVE_SYS_PARAM_H */
60 
61 
62 /*
63  * Local functions...
64  */
65 
66 static void		parent_handler(int sig);
67 static void		process_children(void);
68 static void		sigchld_handler(int sig);
69 static void		sighup_handler(int sig);
70 static void		sigterm_handler(int sig);
71 static long		select_timeout(int fds);
72 static void		service_checkin(void);
73 static void		service_checkout(int shutdown);
74 static void		usage(int status) _CUPS_NORETURN;
75 
76 
77 /*
78  * Local globals...
79  */
80 
81 static int		parent_signal = 0;
82 					/* Set to signal number from child */
83 static int		holdcount = 0;	/* Number of times "hold" was called */
84 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
85 static sigset_t		holdmask;	/* Old POSIX signal mask */
86 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
87 static int		dead_children = 0;
88 					/* Dead children? */
89 static int		stop_scheduler = 0;
90 					/* Should the scheduler stop? */
91 static time_t           local_timeout = 0;
92                                         /* Next local printer timeout */
93 
94 
95 /*
96  * 'main()' - Main entry for the CUPS scheduler.
97  */
98 
99 int					/* O - Exit status */
main(int argc,char * argv[])100 main(int  argc,				/* I - Number of command-line args */
101      char *argv[])			/* I - Command-line arguments */
102 {
103   int			i;		/* Looping var */
104   char			*opt;		/* Option character */
105   int			close_all = 1,	/* Close all file descriptors? */
106 			disconnect = 1,	/* Disconnect from controlling terminal? */
107 			fg = 0,		/* Run in foreground? */
108 			run_as_child = 0,
109 					/* Running as child process? */
110 			print_profile = 0;
111 					/* Print the sandbox profile to stdout? */
112   int			fds;		/* Number of ready descriptors */
113   cupsd_client_t	*con;		/* Current client */
114   cupsd_job_t		*job;		/* Current job */
115   cupsd_listener_t	*lis;		/* Current listener */
116   time_t		current_time,	/* Current time */
117 			activity,	/* Client activity timer */
118 			senddoc_time,	/* Send-Document time */
119 			expire_time,	/* Subscription expire time */
120 			report_time,	/* Malloc/client/job report time */
121 			event_time;	/* Last event notification time */
122   long			timeout;	/* Timeout for cupsdDoSelect() */
123   struct rlimit		limit;		/* Runtime limit */
124 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
125   struct sigaction	action;		/* Actions for POSIX signals */
126 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
127 #ifdef __APPLE__
128   int			use_sysman = 1;	/* Use system management functions? */
129 #else
130   time_t		netif_time = 0;	/* Time since last network update */
131 #endif /* __APPLE__ */
132 #if defined(HAVE_ONDEMAND)
133   int			service_idle_exit = 0;
134 					/* Idle exit on select timeout? */
135 #endif /* HAVE_ONDEMAND */
136 
137 
138 #ifdef HAVE_GETEUID
139  /*
140   * Check for setuid invocation, which we do not support!
141   */
142 
143   if (getuid() != geteuid())
144   {
145     fputs("cupsd: Cannot run as a setuid program.\n", stderr);
146     return (1);
147   }
148 #endif /* HAVE_GETEUID */
149 
150  /*
151   * Check for command-line arguments...
152   */
153 
154   fg = 0;
155 
156   for (i = 1; i < argc; i ++)
157   {
158     if (!strcmp(argv[i], "--help"))
159       usage(0);
160     else if (argv[i][0] == '-')
161     {
162       for (opt = argv[i] + 1; *opt != '\0'; opt ++)
163       {
164         switch (*opt)
165 	{
166 	  case 'C' : /* Run as child with config file */
167               run_as_child = 1;
168 	      fg           = 1;
169 	      close_all    = 0;
170 
171 	  case 'c' : /* Configuration file */
172 	      i ++;
173 	      if (i >= argc)
174 	      {
175 	        _cupsLangPuts(stderr, _("cupsd: Expected config filename "
176 		                        "after \"-c\" option."));
177 	        usage(1);
178 	      }
179 
180               if (argv[i][0] == '/')
181 	      {
182 	       /*
183 	        * Absolute directory...
184 		*/
185 
186 		cupsdSetString(&ConfigurationFile, argv[i]);
187               }
188 	      else
189 	      {
190 	       /*
191 	        * Relative directory...
192 		*/
193 
194                 char *current;		/* Current directory */
195 
196 	       /*
197 	        * Allocate a buffer for the current working directory to
198 		* reduce run-time stack usage; this approximates the
199 		* behavior of some implementations of getcwd() when they
200 		* are passed a NULL pointer.
201 	        */
202 
203                 if ((current = malloc(1024)) == NULL)
204 		{
205 		  _cupsLangPuts(stderr,
206 		                _("cupsd: Unable to get current directory."));
207                   return (1);
208 		}
209 
210 		if (!getcwd(current, 1024))
211 		{
212 		  _cupsLangPuts(stderr,
213 		                _("cupsd: Unable to get current directory."));
214                   free(current);
215 		  return (1);
216 		}
217 
218 		cupsdSetStringf(&ConfigurationFile, "%s/%s", current, argv[i]);
219 		free(current);
220               }
221 	      break;
222 
223           case 'f' : /* Run in foreground... */
224 	      fg         = 1;
225 	      disconnect = 0;
226 	      close_all  = 0;
227 	      break;
228 
229           case 'F' : /* Run in foreground, but disconnect from terminal... */
230 	      fg        = 1;
231 	      close_all = 0;
232 	      break;
233 
234           case 'h' : /* Show usage/help */
235 	      usage(0);
236 
237           case 'l' : /* Started by launchd/systemd/upstart... */
238 #ifdef HAVE_ONDEMAND
239 	      OnDemand   = 1;
240 	      fg         = 1;
241 	      close_all  = 0;
242 	      disconnect = 0;
243 #else
244 	      _cupsLangPuts(stderr, _("cupsd: On-demand support not compiled "
245 	                              "in, running in normal mode."));
246               fg         = 0;
247 	      disconnect = 1;
248 	      close_all  = 1;
249 #endif /* HAVE_ONDEMAND */
250 	      break;
251 
252           case 'p' : /* Stop immediately for profiling */
253               fputs("cupsd: -p (startup profiling) is for internal testing "
254                     "use only!\n", stderr);
255 	      stop_scheduler = 1;
256 	      fg             = 1;
257 	      disconnect     = 0;
258 	      close_all      = 0;
259 	      break;
260 
261           case 'P' : /* Disable security profiles */
262               fputs("cupsd: -P (disable sandboxing) is for internal testing use only.\n", stderr);
263 	      UseSandboxing = 0;
264 	      break;
265 
266           case 's' : /* Set cups-files.conf location */
267               i ++;
268 	      if (i >= argc)
269 	      {
270 	        _cupsLangPuts(stderr, _("cupsd: Expected cups-files.conf "
271 	                                "filename after \"-s\" option."));
272 	        usage(1);
273 	      }
274 
275               if (argv[i][0] != '/')
276 	      {
277 	       /*
278 	        * Relative filename not allowed...
279 		*/
280 
281 	        _cupsLangPuts(stderr, _("cupsd: Relative cups-files.conf "
282 	                                "filename not allowed."));
283 	        usage(1);
284               }
285 
286 	      cupsdSetString(&CupsFilesFile, argv[i]);
287 	      break;
288 
289 #ifdef __APPLE__
290           case 'S' : /* Disable system management functions */
291               fputs("cupsd: -S (disable system management) for internal "
292                     "testing use only!\n", stderr);
293 	      use_sysman = 0;
294 	      break;
295 #endif /* __APPLE__ */
296 
297           case 't' : /* Test the cupsd.conf file... */
298 	      TestConfigFile = 1;
299 	      fg             = 1;
300 	      disconnect     = 0;
301 	      close_all      = 0;
302 	      break;
303 
304           case 'T' : /* Print security profile */
305               print_profile = 1;
306               fg            = 1;
307               disconnect    = 0;
308               close_all     = 0;
309               break;
310 
311 	  default : /* Unknown option */
312               _cupsLangPrintf(stderr, _("cupsd: Unknown option \"%c\" - "
313 	                                "aborting."), *opt);
314 	      usage(1);
315 	}
316       }
317     }
318     else
319     {
320       _cupsLangPrintf(stderr, _("cupsd: Unknown argument \"%s\" - aborting."),
321                       argv[i]);
322       usage(1);
323     }
324   }
325 
326   if (!ConfigurationFile)
327     cupsdSetString(&ConfigurationFile, CUPS_SERVERROOT "/cupsd.conf");
328 
329   if (!CupsFilesFile)
330   {
331     char	*filename,		/* Copy of cupsd.conf filename */
332 		*slash;			/* Final slash in cupsd.conf filename */
333     size_t	len;			/* Size of buffer */
334 
335     len = strlen(ConfigurationFile) + 15;
336     if ((filename = malloc(len)) == NULL)
337     {
338       _cupsLangPrintf(stderr,
339 		      _("cupsd: Unable to get path to "
340 			"cups-files.conf file."));
341       return (1);
342     }
343 
344     strlcpy(filename, ConfigurationFile, len);
345     if ((slash = strrchr(filename, '/')) == NULL)
346     {
347       free(filename);
348       _cupsLangPrintf(stderr,
349 		      _("cupsd: Unable to get path to "
350 			"cups-files.conf file."));
351       return (1);
352     }
353 
354     strlcpy(slash, "/cups-files.conf", len - (size_t)(slash - filename));
355     cupsdSetString(&CupsFilesFile, filename);
356     free(filename);
357   }
358 
359   if (disconnect)
360   {
361    /*
362     * Make sure we aren't tying up any filesystems...
363     */
364 
365     chdir("/");
366 
367    /*
368     * Disconnect from the controlling terminal...
369     */
370 
371     setsid();
372   }
373 
374   if (close_all)
375   {
376    /*
377     * Close all open files...
378     */
379 
380     getrlimit(RLIMIT_NOFILE, &limit);
381 
382     for (i = 0; i < (int)limit.rlim_cur && i < 1024; i ++)
383       close(i);
384 
385    /*
386     * Redirect stdin/out/err to /dev/null...
387     */
388 
389     if ((i = open("/dev/null", O_RDONLY)) != 0)
390     {
391       dup2(i, 0);
392       close(i);
393     }
394 
395     if ((i = open("/dev/null", O_WRONLY)) != 1)
396     {
397       dup2(i, 1);
398       close(i);
399     }
400 
401     if ((i = open("/dev/null", O_WRONLY)) != 2)
402     {
403       dup2(i, 2);
404       close(i);
405     }
406   }
407   else
408     LogStderr = cupsFileStderr();
409 
410  /*
411   * Run in the background as needed...
412   */
413 
414   if (!fg)
415   {
416    /*
417     * Setup signal handlers for the parent...
418     */
419 
420 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
421     sigset(SIGUSR1, parent_handler);
422     sigset(SIGCHLD, parent_handler);
423 
424     sigset(SIGHUP, SIG_IGN);
425 #elif defined(HAVE_SIGACTION)
426     memset(&action, 0, sizeof(action));
427     sigemptyset(&action.sa_mask);
428     sigaddset(&action.sa_mask, SIGUSR1);
429     action.sa_handler = parent_handler;
430     sigaction(SIGUSR1, &action, NULL);
431     sigaction(SIGCHLD, &action, NULL);
432 
433     sigemptyset(&action.sa_mask);
434     action.sa_handler = SIG_IGN;
435     sigaction(SIGHUP, &action, NULL);
436 #else
437     signal(SIGUSR1, parent_handler);
438     signal(SIGCLD, parent_handler);
439 
440     signal(SIGHUP, SIG_IGN);
441 #endif /* HAVE_SIGSET */
442 
443     if (fork() > 0)
444     {
445      /*
446       * OK, wait for the child to startup and send us SIGUSR1 or to crash
447       * and the OS send us SIGCHLD...  We also need to ignore SIGHUP which
448       * might be sent by the init script to restart the scheduler...
449       */
450 
451       for (; parent_signal == 0;)
452         sleep(1);
453 
454       if (parent_signal == SIGUSR1)
455         return (0);
456 
457       if (wait(&i) < 0)
458       {
459         perror("cupsd");
460 	return (1);
461       }
462       else if (WIFEXITED(i))
463       {
464         fprintf(stderr, "cupsd: Child exited with status %d\n",
465 	        WEXITSTATUS(i));
466 	return (2);
467       }
468       else
469       {
470         fprintf(stderr, "cupsd: Child exited on signal %d\n", WTERMSIG(i));
471 	return (3);
472       }
473     }
474 
475 #if defined(__OpenBSD__) && OpenBSD < 201211
476    /*
477     * Call _thread_sys_closefrom() so the child process doesn't reset the
478     * parent's file descriptors to be blocking.  This is a workaround for a
479     * limitation of userland libpthread on older versions of OpenBSD.
480     */
481 
482     _thread_sys_closefrom(0);
483 #endif /* __OpenBSD__ && OpenBSD < 201211 */
484 
485    /*
486     * Since many system libraries create fork-unsafe data on execution of a
487     * program, we need to re-execute the background cupsd with the "-C" and "-s"
488     * options to avoid problems.  Unfortunately, we also have to assume that
489     * argv[0] contains the name of the cupsd executable - there is no portable
490     * way to get the real pathname...
491     */
492 
493     execlp(argv[0], argv[0], "-C", ConfigurationFile, "-s", CupsFilesFile, (char *)0);
494     exit(errno);
495   }
496 
497  /*
498   * Let the system know we are busy while we bring up cupsd...
499   */
500 
501   cupsdSetBusyState(1);
502 
503  /*
504   * Set the timezone info...
505   */
506 
507   tzset();
508 
509 #ifdef LC_TIME
510   setlocale(LC_TIME, "");
511 #endif /* LC_TIME */
512 
513 #ifdef HAVE_DBUS_THREADS_INIT
514  /*
515   * Enable threading support for D-BUS...
516   */
517 
518   dbus_threads_init_default();
519 #endif /* HAVE_DBUS_THREADS_INIT */
520 
521  /*
522   * Set the maximum number of files, which for practical reasons can be limited
523   * to the number of TCP port number values (64k-1)...
524   */
525 
526   limit.rlim_max = 0;
527   getrlimit(RLIMIT_NOFILE, &limit);
528 
529 #if !defined(HAVE_POLL) && !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE)
530   if ((MaxFDs = limit.rlim_max) > FD_SETSIZE || MaxFDs <= 0)
531     MaxFDs = FD_SETSIZE;
532 #else
533   if ((MaxFDs = limit.rlim_max) > 65535 || MaxFDs <= 0)
534     MaxFDs = 65535;
535 #endif /* RLIM_INFINITY */
536 
537   limit.rlim_cur = (rlim_t)MaxFDs;
538 
539   setrlimit(RLIMIT_NOFILE, &limit);
540 
541   cupsdStartSelect();
542 
543  /*
544   * Read configuration...
545   */
546 
547   if (!cupsdReadConfiguration())
548     return (1);
549   else if (TestConfigFile)
550   {
551     printf("\"%s\" is OK.\n", CupsFilesFile);
552     printf("\"%s\" is OK.\n", ConfigurationFile);
553     return (0);
554   }
555   else if (print_profile)
556   {
557     cups_file_t	*fp;			/* File pointer */
558     const char	*profile = cupsdCreateProfile(42, 0);
559 					/* Profile */
560     char	line[1024];		/* Line from file */
561 
562 
563     if ((fp = cupsFileOpen(profile, "r")) == NULL)
564     {
565       printf("Unable to open profile file \"%s\": %s\n", profile ? profile : "(null)", strerror(errno));
566       return (1);
567     }
568 
569     while (cupsFileGets(fp, line, sizeof(line)))
570       puts(line);
571 
572     cupsFileClose(fp);
573 
574     return (0);
575   }
576 
577  /*
578   * Clean out old temp files and printer cache data.
579   */
580 
581   if (!RequestRoot || !strncmp(TempDir, RequestRoot, strlen(RequestRoot)))
582     cupsdCleanFiles(TempDir, NULL);
583 
584   cupsdCleanFiles(CacheDir, "*.ipp");
585 
586  /*
587   * If we were started on demand by launchd or systemd get the listen sockets
588   * file descriptors...
589   */
590 
591   service_checkin();
592   service_checkout(0);
593 
594  /*
595   * Startup the server...
596   */
597 
598   httpInitialize();
599 
600   cupsdStartServer();
601 
602  /*
603   * Catch hangup and child signals and ignore broken pipes...
604   */
605 
606 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
607   sigset(SIGCHLD, sigchld_handler);
608   sigset(SIGHUP, sighup_handler);
609   sigset(SIGPIPE, SIG_IGN);
610   sigset(SIGTERM, sigterm_handler);
611 #elif defined(HAVE_SIGACTION)
612   memset(&action, 0, sizeof(action));
613 
614   sigemptyset(&action.sa_mask);
615   sigaddset(&action.sa_mask, SIGTERM);
616   sigaddset(&action.sa_mask, SIGCHLD);
617   action.sa_handler = sigchld_handler;
618   sigaction(SIGCHLD, &action, NULL);
619 
620   sigemptyset(&action.sa_mask);
621   sigaddset(&action.sa_mask, SIGHUP);
622   action.sa_handler = sighup_handler;
623   sigaction(SIGHUP, &action, NULL);
624 
625   sigemptyset(&action.sa_mask);
626   action.sa_handler = SIG_IGN;
627   sigaction(SIGPIPE, &action, NULL);
628 
629   sigemptyset(&action.sa_mask);
630   sigaddset(&action.sa_mask, SIGTERM);
631   sigaddset(&action.sa_mask, SIGCHLD);
632   action.sa_handler = sigterm_handler;
633   sigaction(SIGTERM, &action, NULL);
634 #else
635   signal(SIGCLD, sigchld_handler);	/* No, SIGCLD isn't a typo... */
636   signal(SIGHUP, sighup_handler);
637   signal(SIGPIPE, SIG_IGN);
638   signal(SIGTERM, sigterm_handler);
639 #endif /* HAVE_SIGSET */
640 
641  /*
642   * Initialize authentication certificates...
643   */
644 
645   cupsdInitCerts();
646 
647  /*
648   * If we are running in the background, signal the parent process that
649   * we are up and running...
650   */
651 
652   if (!fg || run_as_child)
653   {
654    /*
655     * Send a signal to the parent process, but only if the parent is
656     * not PID 1 (init).  This avoids accidentally shutting down the
657     * system on OpenBSD if you CTRL-C the server before it is up...
658     */
659 
660     i = getppid();	/* Save parent PID to avoid race condition */
661 
662     if (i != 1)
663       kill(i, SIGUSR1);
664   }
665 
666 #ifdef __APPLE__
667  /*
668   * Start power management framework...
669   */
670 
671   if (use_sysman)
672     cupsdStartSystemMonitor();
673 #endif /* __APPLE__ */
674 
675  /*
676   * Send server-started event...
677   */
678 
679 #ifdef HAVE_ONDEMAND
680   if (OnDemand)
681   {
682     cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL, "Scheduler started on demand.");
683 
684 #  ifdef HAVE_SYSTEMD
685     sd_notifyf(0, "READY=1\n"
686 		  "STATUS=Scheduler is running...\n"
687 		  "MAINPID=%lu", (unsigned long)getpid());
688 #  endif /* HAVE_SYSTEMD */
689   }
690   else
691 
692 #endif /* HAVE_ONDEMAND */
693   if (fg)
694     cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL, "Scheduler started in foreground.");
695   else
696     cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL, "Scheduler started in background.");
697 
698   cupsdSetBusyState(0);
699 
700  /*
701   * Start any pending print jobs...
702   */
703 
704   cupsdCheckJobs();
705 
706  /*
707   * Loop forever...
708   */
709 
710   current_time  = time(NULL);
711   event_time    = current_time;
712   expire_time   = current_time;
713   local_timeout = 0;
714   fds           = 1;
715   report_time   = 0;
716   senddoc_time  = current_time;
717 
718   while (!stop_scheduler)
719   {
720    /*
721     * Check if there are dead children to handle...
722     */
723 
724     if (dead_children)
725       process_children();
726 
727    /*
728     * Check if we need to load the server configuration file...
729     */
730 
731     if (NeedReload)
732     {
733      /*
734       * Close any idle clients...
735       */
736 
737       if (cupsArrayCount(Clients) > 0)
738       {
739 	for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
740 	     con;
741 	     con = (cupsd_client_t *)cupsArrayNext(Clients))
742 	  if (httpGetState(con->http) == HTTP_WAITING)
743 	    cupsdCloseClient(con);
744 	  else
745 	    con->http->keep_alive = HTTP_KEEPALIVE_OFF;
746 
747         cupsdPauseListening();
748       }
749 
750      /*
751       * Restart if all clients are closed and all jobs finished, or
752       * if the reload timeout has elapsed...
753       */
754 
755       if ((cupsArrayCount(Clients) == 0 &&
756            (cupsArrayCount(PrintingJobs) == 0 || NeedReload != RELOAD_ALL)) ||
757           (time(NULL) - ReloadTime) >= ReloadTimeout)
758       {
759        /*
760 	* Shutdown the server...
761 	*/
762 
763 #ifdef HAVE_ONDEMAND
764 	if (OnDemand)
765 	{
766 #  ifndef HAVE_SYSTEMD /* Issue #5640: systemd doesn't actually support launch-on-demand services, need to fake it */
767 	  stop_scheduler = 1;
768 #  endif /* HAVE_SYSTEMD */
769 	  break;
770 	}
771 #endif /* HAVE_ONDEMAND */
772 
773         DoingShutdown = 1;
774 
775 	cupsdStopServer();
776 
777        /*
778 	* Read configuration...
779 	*/
780 
781         if (!cupsdReadConfiguration())
782         {
783 #ifdef HAVE_SYSTEMD_SD_JOURNAL_H
784 	  sd_journal_print(LOG_ERR, "Unable to read configuration file \"%s\" - exiting.", ConfigurationFile);
785 #else
786           syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting.", ConfigurationFile);
787 #endif /* HAVE_SYSTEMD_SD_JOURNAL_H */
788 
789           break;
790 	}
791 
792        /*
793         * Startup the server...
794         */
795 
796         DoingShutdown = 0;
797 
798         cupsdStartServer();
799 
800        /*
801         * Send a server-restarted event...
802 	*/
803 
804         cupsdAddEvent(CUPSD_EVENT_SERVER_RESTARTED, NULL, NULL,
805                       "Scheduler restarted.");
806       }
807     }
808 
809    /*
810     * Check for available input or ready output.  If cupsdDoSelect()
811     * returns 0 or -1, something bad happened and we should exit
812     * immediately.
813     *
814     * Note that we at least have one listening socket open at all
815     * times.
816     */
817 
818     if ((timeout = select_timeout(fds)) > 1 && LastEvent)
819       timeout = 1;
820 
821 #ifdef HAVE_ONDEMAND
822    /*
823     * If no other work is scheduled and we're being controlled by launchd,
824     * systemd, etc. then timeout after 'IdleExitTimeout' seconds of
825     * inactivity...
826     */
827 
828     if (timeout == 86400 && OnDemand && IdleExitTimeout &&
829 #  ifdef HAVE_SYSTEMD
830         !WebInterface &&
831 #  endif /* HAVE_SYSTEMD */
832         !cupsArrayCount(ActiveJobs))
833     {
834       cupsd_printer_t *p = NULL;	/* Current printer */
835 
836       if (Browsing && BrowseLocalProtocols)
837       {
838         for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers))
839           if (p->shared)
840             break;
841       }
842 
843       if (!p)
844       {
845 	timeout		  = IdleExitTimeout;
846 	service_idle_exit = 1;
847       }
848     }
849     else
850       service_idle_exit = 0;
851 #endif	/* HAVE_ONDEMAND */
852 
853     if ((fds = cupsdDoSelect(timeout)) < 0)
854     {
855      /*
856       * Got an error from select!
857       */
858 
859 #ifdef HAVE_DNSSD
860       cupsd_printer_t	*p;		/* Current printer */
861 #endif /* HAVE_DNSSD */
862 
863       if (errno == EINTR)		/* Just interrupted by a signal */
864         continue;
865 
866      /*
867       * Log all sorts of debug info to help track down the problem.
868       */
869 
870       cupsdLogMessage(CUPSD_LOG_EMERG, "cupsdDoSelect() failed - %s!",
871                       strerror(errno));
872 
873       for (i = 0, con = (cupsd_client_t *)cupsArrayFirst(Clients);
874 	   con;
875 	   i ++, con = (cupsd_client_t *)cupsArrayNext(Clients))
876         cupsdLogMessage(CUPSD_LOG_EMERG,
877 	                "Clients[%d] = %d, file = %d, state = %d",
878 	                i, con->number, con->file, httpGetState(con->http));
879 
880       for (i = 0, lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
881            lis;
882 	   i ++, lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
883         cupsdLogMessage(CUPSD_LOG_EMERG, "Listeners[%d] = %d", i, lis->fd);
884 
885       cupsdLogMessage(CUPSD_LOG_EMERG, "CGIPipes[0] = %d", CGIPipes[0]);
886 
887 #ifdef __APPLE__
888       cupsdLogMessage(CUPSD_LOG_EMERG, "SysEventPipes[0] = %d",
889                       SysEventPipes[0]);
890 #endif /* __APPLE__ */
891 
892       for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
893 	   job;
894 	   job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
895         cupsdLogMessage(CUPSD_LOG_EMERG, "Jobs[%d] = %d < [%d %d] > [%d %d]",
896 	        	job->id,
897 			job->status_buffer ? job->status_buffer->fd : -1,
898 			job->print_pipes[0], job->print_pipes[1],
899 			job->back_pipes[0], job->back_pipes[1]);
900 
901 #ifdef HAVE_DNSSD
902       for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
903 	   p;
904 	   p = (cupsd_printer_t *)cupsArrayNext(Printers))
905         cupsdLogMessage(CUPSD_LOG_EMERG, "printer[%s] reg_name=\"%s\"", p->name,
906 	                p->reg_name ? p->reg_name : "(null)");
907 #endif /* HAVE_DNSSD */
908 
909       break;
910     }
911 
912     current_time = time(NULL);
913 
914    /*
915     * Write dirty config/state files...
916     */
917 
918     if (DirtyCleanTime && current_time >= DirtyCleanTime)
919       cupsdCleanDirty();
920 
921 #ifdef __APPLE__
922    /*
923     * If we are going to sleep and still have pending jobs, stop them after
924     * a period of time...
925     */
926 
927     if (SleepJobs > 0 && current_time >= SleepJobs &&
928         cupsArrayCount(PrintingJobs) > 0)
929     {
930       SleepJobs = 0;
931       cupsdStopAllJobs(CUPSD_JOB_DEFAULT, 5);
932     }
933 #endif /* __APPLE__ */
934 
935 #ifndef __APPLE__
936    /*
937     * Update the network interfaces once a minute...
938     */
939 
940     if ((current_time - netif_time) >= 60)
941     {
942       netif_time  = current_time;
943       NetIFUpdate = 1;
944     }
945 #endif /* !__APPLE__ */
946 
947 #ifdef HAVE_ONDEMAND
948    /*
949     * If no other work was scheduled and we're being controlled by launchd,
950     * systemd, or upstart then timeout after 'LaunchdTimeout' seconds of
951     * inactivity...
952     */
953 
954     if (!fds && service_idle_exit)
955     {
956       cupsdLogMessage(CUPSD_LOG_INFO,
957                       "Printer sharing is off and there are no jobs pending, "
958 		      "will restart on demand.");
959       stop_scheduler = 1;
960       break;
961     }
962 #endif /* HAVE_ONDEMAND */
963 
964    /*
965     * Resume listening for new connections as needed...
966     */
967 
968     if (ListeningPaused && ListeningPaused <= current_time &&
969         cupsArrayCount(Clients) < MaxClients)
970       cupsdResumeListening();
971 
972    /*
973     * Expire subscriptions and unload completed jobs as needed...
974     */
975 
976     if (current_time > expire_time)
977     {
978       cupsdExpireSubscriptions(NULL, NULL);
979 
980       cupsdUnloadCompletedJobs();
981 
982       expire_time = current_time;
983     }
984 
985    /*
986     * Delete stale local printers...
987     */
988 
989     if (current_time >= local_timeout)
990     {
991       cupsdDeleteTemporaryPrinters(0);
992       local_timeout = 0;
993     }
994 
995 #ifndef HAVE_AUTHORIZATION_H
996    /*
997     * Update the root certificate once every 5 minutes if we have client
998     * connections...
999     */
1000 
1001     if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration &&
1002         !RunUser && cupsArrayCount(Clients))
1003     {
1004      /*
1005       * Update the root certificate...
1006       */
1007 
1008       cupsdDeleteCert(0);
1009       cupsdAddCert(0, "root", cupsdDefaultAuthType());
1010     }
1011 #endif /* !HAVE_AUTHORIZATION_H */
1012 
1013    /*
1014     * Clean job history...
1015     */
1016 
1017     if (JobHistoryUpdate && current_time >= JobHistoryUpdate)
1018       cupsdCleanJobs();
1019 
1020    /*
1021     * Update any pending multi-file documents...
1022     */
1023 
1024     if ((current_time - senddoc_time) >= 10)
1025     {
1026       cupsdCheckJobs();
1027       senddoc_time = current_time;
1028     }
1029 
1030    /*
1031     * Check for new data on the client sockets...
1032     */
1033 
1034     for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
1035 	 con;
1036 	 con = (cupsd_client_t *)cupsArrayNext(Clients))
1037     {
1038      /*
1039       * Process pending data in the input buffer...
1040       */
1041 
1042       if (httpGetReady(con->http))
1043       {
1044         cupsdReadClient(con);
1045 	continue;
1046       }
1047 
1048      /*
1049       * Check the activity and close old clients...
1050       */
1051 
1052       activity = current_time - Timeout;
1053       if (httpGetActivity(con->http) < activity && !con->pipe_pid)
1054       {
1055         cupsdLogMessage(CUPSD_LOG_DEBUG, "Closing client %d after %d seconds of inactivity.", con->number, Timeout);
1056 
1057         cupsdCloseClient(con);
1058         continue;
1059       }
1060     }
1061 
1062    /*
1063     * Log statistics at most once a minute when in debug mode...
1064     */
1065 
1066     if ((current_time - report_time) >= 60 && LogLevel >= CUPSD_LOG_DEBUG)
1067     {
1068       size_t		string_count,	/* String count */
1069 			alloc_bytes,	/* Allocated string bytes */
1070 			total_bytes;	/* Total string bytes */
1071 #ifdef HAVE_MALLINFO
1072       struct mallinfo	mem;		/* Malloc information */
1073 
1074 
1075       mem = mallinfo();
1076       cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-arena=%lu", mem.arena);
1077       cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-used=%lu",
1078                       mem.usmblks + mem.uordblks);
1079       cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-free=%lu",
1080 		      mem.fsmblks + mem.fordblks);
1081 #endif /* HAVE_MALLINFO */
1082 
1083       cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: clients=%d",
1084                       cupsArrayCount(Clients));
1085       cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: jobs=%d",
1086                       cupsArrayCount(Jobs));
1087       cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: jobs-active=%d",
1088                       cupsArrayCount(ActiveJobs));
1089       cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: printers=%d",
1090                       cupsArrayCount(Printers));
1091 
1092       string_count = _cupsStrStatistics(&alloc_bytes, &total_bytes);
1093       cupsdLogMessage(CUPSD_LOG_DEBUG,
1094                       "Report: stringpool-string-count=" CUPS_LLFMT,
1095 		      CUPS_LLCAST string_count);
1096       cupsdLogMessage(CUPSD_LOG_DEBUG,
1097                       "Report: stringpool-alloc-bytes=" CUPS_LLFMT,
1098 		      CUPS_LLCAST alloc_bytes);
1099       cupsdLogMessage(CUPSD_LOG_DEBUG,
1100                       "Report: stringpool-total-bytes=" CUPS_LLFMT,
1101 		      CUPS_LLCAST total_bytes);
1102 
1103       report_time = current_time;
1104     }
1105 
1106    /*
1107     * Handle OS-specific event notification for any events that have
1108     * accumulated.  Don't send these more than once a second...
1109     */
1110 
1111     if (LastEvent && (current_time - event_time) >= 1)
1112     {
1113 #ifdef HAVE_NOTIFY_POST
1114       if (LastEvent & (CUPSD_EVENT_PRINTER_ADDED |
1115                        CUPSD_EVENT_PRINTER_DELETED |
1116                        CUPSD_EVENT_PRINTER_MODIFIED))
1117       {
1118         cupsdLogMessage(CUPSD_LOG_DEBUG2,
1119 	                "notify_post(\"com.apple.printerListChange\")");
1120 	notify_post("com.apple.printerListChange");
1121       }
1122 
1123       if (LastEvent & CUPSD_EVENT_PRINTER_STATE_CHANGED)
1124       {
1125         cupsdLogMessage(CUPSD_LOG_DEBUG2,
1126 	                "notify_post(\"com.apple.printerHistoryChange\")");
1127 	notify_post("com.apple.printerHistoryChange");
1128       }
1129 
1130       if (LastEvent & (CUPSD_EVENT_JOB_STATE_CHANGED |
1131                        CUPSD_EVENT_JOB_CONFIG_CHANGED |
1132                        CUPSD_EVENT_JOB_PROGRESS))
1133       {
1134         cupsdLogMessage(CUPSD_LOG_DEBUG2,
1135 	                "notify_post(\"com.apple.jobChange\")");
1136 	notify_post("com.apple.jobChange");
1137       }
1138 #endif /* HAVE_NOTIFY_POST */
1139 
1140      /*
1141       * Reset the accumulated events...
1142       */
1143 
1144       LastEvent  = CUPSD_EVENT_NONE;
1145       event_time = current_time;
1146     }
1147   }
1148 
1149  /*
1150   * Log a message based on what happened...
1151   */
1152 
1153   if (stop_scheduler)
1154   {
1155     cupsdLogMessage(CUPSD_LOG_INFO, "Scheduler shutting down normally.");
1156     cupsdAddEvent(CUPSD_EVENT_SERVER_STOPPED, NULL, NULL,
1157                   "Scheduler shutting down normally.");
1158   }
1159   else
1160   {
1161     cupsdLogMessage(CUPSD_LOG_ERROR,
1162                     "Scheduler shutting down due to program error.");
1163     cupsdAddEvent(CUPSD_EVENT_SERVER_STOPPED, NULL, NULL,
1164                   "Scheduler shutting down due to program error.");
1165   }
1166 
1167  /*
1168   * Close all network clients...
1169   */
1170 
1171   DoingShutdown = 1;
1172 
1173   cupsdStopServer();
1174 
1175  /*
1176   * Update the KeepAlive/PID file as needed...
1177   */
1178 
1179   service_checkout(1);
1180 
1181  /*
1182   * Stop all jobs...
1183   */
1184 
1185   cupsdFreeAllJobs();
1186 
1187  /*
1188   * Delete all temporary printers...
1189   */
1190 
1191   cupsdDeleteTemporaryPrinters(1);
1192 
1193 #ifdef __APPLE__
1194  /*
1195   * Stop monitoring system event monitoring...
1196   */
1197 
1198   if (use_sysman)
1199     cupsdStopSystemMonitor();
1200 #endif /* __APPLE__ */
1201 
1202   cupsdStopSelect();
1203 
1204   return (!stop_scheduler);
1205 }
1206 
1207 
1208 /*
1209  * 'cupsdAddString()' - Copy and add a string to an array.
1210  */
1211 
1212 int					/* O  - 1 on success, 0 on failure */
cupsdAddString(cups_array_t ** a,const char * s)1213 cupsdAddString(cups_array_t **a,	/* IO - String array */
1214                const char   *s)		/* I  - String to copy and add */
1215 {
1216   if (!*a)
1217     *a = cupsArrayNew3((cups_array_func_t)strcmp, NULL,
1218 		       (cups_ahash_func_t)NULL, 0,
1219 		       (cups_acopy_func_t)strdup,
1220 		       (cups_afree_func_t)free);
1221 
1222   return (cupsArrayAdd(*a, (char *)s));
1223 }
1224 
1225 
1226 /*
1227  * 'cupsdCheckProcess()' - Tell the main loop to check for dead children.
1228  */
1229 
1230 void
cupsdCheckProcess(void)1231 cupsdCheckProcess(void)
1232 {
1233  /*
1234   * Flag that we have dead children...
1235   */
1236 
1237   dead_children = 1;
1238 }
1239 
1240 
1241 /*
1242  * 'cupsdClearString()' - Clear a string.
1243  */
1244 
1245 void
cupsdClearString(char ** s)1246 cupsdClearString(char **s)		/* O - String value */
1247 {
1248   if (s && *s)
1249   {
1250     free(*s);
1251     *s = NULL;
1252   }
1253 }
1254 
1255 
1256 /*
1257  * 'cupsdFreeStrings()' - Free an array of strings.
1258  */
1259 
1260 void
cupsdFreeStrings(cups_array_t ** a)1261 cupsdFreeStrings(cups_array_t **a)	/* IO - String array */
1262 {
1263   if (*a)
1264   {
1265     cupsArrayDelete(*a);
1266     *a = NULL;
1267   }
1268 }
1269 
1270 
1271 /*
1272  * 'cupsdHoldSignals()' - Hold child and termination signals.
1273  */
1274 
1275 void
cupsdHoldSignals(void)1276 cupsdHoldSignals(void)
1277 {
1278 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1279   sigset_t		newmask;	/* New POSIX signal mask */
1280 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1281 
1282 
1283   holdcount ++;
1284   if (holdcount > 1)
1285     return;
1286 
1287 #ifdef HAVE_SIGSET
1288   sighold(SIGTERM);
1289   sighold(SIGCHLD);
1290 #elif defined(HAVE_SIGACTION)
1291   sigemptyset(&newmask);
1292   sigaddset(&newmask, SIGTERM);
1293   sigaddset(&newmask, SIGCHLD);
1294   sigprocmask(SIG_BLOCK, &newmask, &holdmask);
1295 #endif /* HAVE_SIGSET */
1296 }
1297 
1298 
1299 /*
1300  * 'cupsdReleaseSignals()' - Release signals for delivery.
1301  */
1302 
1303 void
cupsdReleaseSignals(void)1304 cupsdReleaseSignals(void)
1305 {
1306   holdcount --;
1307   if (holdcount > 0)
1308     return;
1309 
1310 #ifdef HAVE_SIGSET
1311   sigrelse(SIGTERM);
1312   sigrelse(SIGCHLD);
1313 #elif defined(HAVE_SIGACTION)
1314   sigprocmask(SIG_SETMASK, &holdmask, NULL);
1315 #endif /* HAVE_SIGSET */
1316 }
1317 
1318 
1319 /*
1320  * 'cupsdSetString()' - Set a string value.
1321  */
1322 
1323 void
cupsdSetString(char ** s,const char * v)1324 cupsdSetString(char       **s,		/* O - New string */
1325                const char *v)		/* I - String value */
1326 {
1327   if (!s || *s == v)
1328     return;
1329 
1330   if (*s)
1331     free(*s);
1332 
1333   if (v)
1334     *s = strdup(v);
1335   else
1336     *s = NULL;
1337 }
1338 
1339 
1340 /*
1341  * 'cupsdSetStringf()' - Set a formatted string value.
1342  */
1343 
1344 void
cupsdSetStringf(char ** s,const char * f,...)1345 cupsdSetStringf(char       **s,		/* O - New string */
1346                 const char *f,		/* I - Printf-style format string */
1347 	        ...)			/* I - Additional args as needed */
1348 {
1349   char		v[65536 + 64];		/* Formatting string value */
1350   va_list	ap;			/* Argument pointer */
1351   char		*olds;			/* Old string */
1352 
1353 
1354   if (!s)
1355     return;
1356 
1357   olds = *s;
1358 
1359   if (f)
1360   {
1361     va_start(ap, f);
1362     vsnprintf(v, sizeof(v), f, ap);
1363     va_end(ap);
1364 
1365     *s = strdup(v);
1366   }
1367   else
1368     *s = NULL;
1369 
1370   if (olds)
1371     free(olds);
1372 }
1373 
1374 
1375 /*
1376  * 'parent_handler()' - Catch USR1/CHLD signals...
1377  */
1378 
1379 static void
parent_handler(int sig)1380 parent_handler(int sig)			/* I - Signal */
1381 {
1382  /*
1383   * Store the signal we got from the OS and return...
1384   */
1385 
1386   parent_signal = sig;
1387 }
1388 
1389 
1390 /*
1391  * 'process_children()' - Process all dead children...
1392  */
1393 
1394 static void
process_children(void)1395 process_children(void)
1396 {
1397   int		status;			/* Exit status of child */
1398   int		pid,			/* Process ID of child */
1399 		job_id;			/* Job ID of child */
1400   cupsd_job_t	*job;			/* Current job */
1401   size_t		i;			/* Looping var */
1402   char		name[1024];		/* Process name */
1403   const char	*type;			/* Type of program */
1404 
1405 
1406   cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_children()");
1407 
1408  /*
1409   * Reset the dead_children flag...
1410   */
1411 
1412   dead_children = 0;
1413 
1414  /*
1415   * Collect the exit status of some children...
1416   */
1417 
1418 #ifdef HAVE_WAITPID
1419   while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
1420 #elif defined(HAVE_WAIT3)
1421   while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
1422 #else
1423   if ((pid = wait(&status)) > 0)
1424 #endif /* HAVE_WAITPID */
1425   {
1426    /*
1427     * Collect the name of the process that finished...
1428     */
1429 
1430     cupsdFinishProcess(pid, name, sizeof(name), &job_id);
1431 
1432    /*
1433     * Delete certificates for CGI processes...
1434     */
1435 
1436     cupsdDeleteCert(pid);
1437 
1438    /*
1439     * Handle completed job filters...
1440     */
1441 
1442     if (job_id > 0)
1443       job = cupsdFindJob(job_id);
1444     else
1445       job  = NULL;
1446 
1447     if (job)
1448     {
1449       for (i = 0; job->filters[i]; i ++)
1450 	if (job->filters[i] == pid)
1451 	  break;
1452 
1453       if (job->filters[i] || job->backend == pid)
1454       {
1455        /*
1456 	* OK, this process has gone away; what's left?
1457 	*/
1458 
1459 	if (job->filters[i])
1460 	{
1461 	  job->filters[i] = -pid;
1462 	  type            = "Filter";
1463 	}
1464 	else
1465 	{
1466 	  job->backend = -pid;
1467 	  type         = "Backend";
1468 	}
1469 
1470 	if (status && status != SIGTERM && status != SIGKILL &&
1471 	    status != SIGPIPE)
1472 	{
1473 	 /*
1474 	  * An error occurred; save the exit status so we know to stop
1475 	  * the printer or cancel the job when all of the filters finish...
1476 	  *
1477 	  * A negative status indicates that the backend failed and the
1478 	  * printer needs to be stopped.
1479 	  *
1480 	  * In order to preserve the most serious status, we always log
1481 	  * when a process dies due to a signal (e.g. SIGABRT, SIGSEGV,
1482 	  * and SIGBUS) and prefer to log the backend exit status over a
1483 	  * filter's.
1484 	  */
1485 
1486 	  int old_status = abs(job->status);
1487 
1488           if (WIFSIGNALED(status) ||	/* This process crashed, or */
1489               !job->status ||		/* No process had a status, or */
1490               (!job->filters[i] && WIFEXITED(old_status)))
1491           {				/* Backend and filter didn't crash */
1492 	    if (job->filters[i])
1493 	    {
1494 	      job->status = status;	/* Filter failed */
1495 	    }
1496 	    else
1497 	    {
1498 	      job->status = -status;	/* Backend failed */
1499 
1500 	      if (job->current_file < job->num_files)
1501 	        cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_FORCE, "Canceling multi-file job due to backend failure.");
1502 	    }
1503           }
1504 
1505 	  if (job->state_value == IPP_JOB_PROCESSING &&
1506 	      job->status_level > CUPSD_LOG_ERROR &&
1507 	      (job->filters[i] || !WIFEXITED(status)))
1508 	  {
1509 	    char	message[1024];	/* New printer-state-message */
1510 
1511 
1512 	    job->status_level = CUPSD_LOG_ERROR;
1513 
1514 	    snprintf(message, sizeof(message), "%s failed", type);
1515 
1516             if (job->printer)
1517 	    {
1518 	      strlcpy(job->printer->state_message, message,
1519 		       sizeof(job->printer->state_message));
1520 	    }
1521 
1522 	    if (!job->attrs)
1523 	      cupsdLoadJob(job);
1524 
1525 	    if (!job->printer_message && job->attrs)
1526 	    {
1527 	      if ((job->printer_message =
1528 	               ippFindAttribute(job->attrs, "job-printer-state-message",
1529 					IPP_TAG_TEXT)) == NULL)
1530 		job->printer_message = ippAddString(job->attrs, IPP_TAG_JOB,
1531 		                                    IPP_TAG_TEXT,
1532 						    "job-printer-state-message",
1533 						    NULL, NULL);
1534 	    }
1535 
1536 	    if (job->printer_message)
1537 	      ippSetString(job->attrs, &job->printer_message, 0, message);
1538 	  }
1539 	}
1540 
1541        /*
1542 	* If this is not the last file in a job, see if all of the
1543 	* filters are done, and if so move to the next file.
1544 	*/
1545 
1546 	if (job->state_value >= IPP_JOB_CANCELED)
1547 	{
1548 	 /*
1549 	  * Remove the job from the active list if there are no processes still
1550 	  * running for it...
1551 	  */
1552 
1553 	  for (i = 0; job->filters[i] < 0; i++);
1554 
1555 	  if (!job->filters[i] && job->backend <= 0)
1556 	    cupsArrayRemove(ActiveJobs, job);
1557 	}
1558 	else if (job->current_file < job->num_files && job->printer)
1559 	{
1560 	  for (i = 0; job->filters[i] < 0; i ++);
1561 
1562 	  if (!job->filters[i] &&
1563 	      (!job->printer->pc || !job->printer->pc->single_file ||
1564 	       job->backend <= 0))
1565 	  {
1566 	   /*
1567 	    * Process the next file...
1568 	    */
1569 
1570 	    cupsdContinueJob(job);
1571 	  }
1572 	}
1573       }
1574     }
1575 
1576    /*
1577     * Show the exit status as needed, ignoring SIGTERM and SIGKILL errors
1578     * since they come when we kill/end a process...
1579     */
1580 
1581     if (status == SIGTERM || status == SIGKILL)
1582     {
1583       cupsdLogJob(job, CUPSD_LOG_DEBUG,
1584 		  "PID %d (%s) was terminated normally with signal %d.", pid,
1585 		  name, status);
1586     }
1587     else if (status == SIGPIPE)
1588     {
1589       cupsdLogJob(job, CUPSD_LOG_DEBUG,
1590 		  "PID %d (%s) did not catch or ignore signal %d.", pid, name,
1591 		  status);
1592     }
1593     else if (status)
1594     {
1595       if (WIFEXITED(status))
1596       {
1597         int code = WEXITSTATUS(status);	/* Exit code */
1598 
1599         if (code > 100)
1600 	  cupsdLogJob(job, CUPSD_LOG_DEBUG,
1601 		      "PID %d (%s) stopped with status %d (%s)", pid, name,
1602 		      code, strerror(code - 100));
1603 	else
1604 	  cupsdLogJob(job, CUPSD_LOG_DEBUG,
1605 		      "PID %d (%s) stopped with status %d.", pid, name, code);
1606       }
1607       else
1608 	cupsdLogJob(job, CUPSD_LOG_DEBUG, "PID %d (%s) crashed on signal %d.",
1609 		    pid, name, WTERMSIG(status));
1610 
1611       if (LogLevel < CUPSD_LOG_DEBUG)
1612         cupsdLogJob(job, CUPSD_LOG_INFO,
1613 		    "Hint: Try setting the LogLevel to \"debug\" to find out "
1614 		    "more.");
1615     }
1616     else
1617       cupsdLogJob(job, CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.",
1618 		  pid, name);
1619   }
1620 
1621  /*
1622   * If wait*() is interrupted by a signal, tell main() to call us again...
1623   */
1624 
1625   if (pid && errno == EINTR)
1626     dead_children = 1;
1627 }
1628 
1629 
1630 /*
1631  * 'select_timeout()' - Calculate the select timeout value.
1632  *
1633  */
1634 
1635 static long				/* O - Number of seconds */
select_timeout(int fds)1636 select_timeout(int fds)			/* I - Number of descriptors returned */
1637 {
1638   long			timeout;	/* Timeout for select */
1639   time_t		now;		/* Current time */
1640   cupsd_client_t	*con;		/* Client information */
1641   cupsd_job_t		*job;		/* Job information */
1642   const char		*why;		/* Debugging aid */
1643 
1644 
1645   cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout: JobHistoryUpdate=%ld",
1646 		  (long)JobHistoryUpdate);
1647 
1648  /*
1649   * Check to see if any of the clients have pending data to be
1650   * processed; if so, the timeout should be 0...
1651   */
1652 
1653   for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
1654        con;
1655        con = (cupsd_client_t *)cupsArrayNext(Clients))
1656     if (httpGetReady(con->http))
1657       return (0);
1658 
1659  /*
1660   * If select has been active in the last second (fds > 0) or we have
1661   * many resources in use then don't bother trying to optimize the
1662   * timeout, just make it 1 second.
1663   */
1664 
1665   if (fds > 0 || cupsArrayCount(Clients) > 50)
1666     return (1);
1667 
1668  /*
1669   * Otherwise, check all of the possible events that we need to wake for...
1670   */
1671 
1672   now     = time(NULL);
1673   timeout = now + 86400;		/* 86400 == 1 day */
1674   why     = "do nothing";
1675 
1676 #ifdef __APPLE__
1677  /*
1678   * When going to sleep, wake up to abort jobs that don't complete in time.
1679   */
1680 
1681   if (SleepJobs > 0 && SleepJobs < timeout)
1682   {
1683     timeout = SleepJobs;
1684     why     = "abort jobs before sleeping";
1685   }
1686 #endif /* __APPLE__ */
1687 
1688  /*
1689   * Check whether we are accepting new connections...
1690   */
1691 
1692   if (ListeningPaused > 0 && cupsArrayCount(Clients) < MaxClients &&
1693       ListeningPaused < timeout)
1694   {
1695     if (ListeningPaused <= now)
1696       timeout = now;
1697     else
1698       timeout = ListeningPaused;
1699 
1700     why = "resume listening";
1701   }
1702 
1703  /*
1704   * Check the activity and close old clients...
1705   */
1706 
1707   for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
1708        con;
1709        con = (cupsd_client_t *)cupsArrayNext(Clients))
1710     if ((httpGetActivity(con->http) + Timeout) < timeout)
1711     {
1712       timeout = httpGetActivity(con->http) + Timeout;
1713       why     = "timeout a client connection";
1714     }
1715 
1716  /*
1717   * Write out changes to configuration and state files...
1718   */
1719 
1720   if (DirtyCleanTime && timeout > DirtyCleanTime)
1721   {
1722     timeout = DirtyCleanTime;
1723     why     = "write dirty config/state files";
1724   }
1725 
1726  /*
1727   * Check for any job activity...
1728   */
1729   if (JobHistoryUpdate && timeout > JobHistoryUpdate)
1730   {
1731     timeout = JobHistoryUpdate;
1732     why     = "update job history";
1733   }
1734 
1735   for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
1736        job;
1737        job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
1738   {
1739     if (job->cancel_time && job->cancel_time < timeout)
1740     {
1741       timeout = job->cancel_time;
1742       why     = "cancel stuck jobs";
1743     }
1744 
1745     if (job->kill_time && job->kill_time < timeout)
1746     {
1747       timeout = job->kill_time;
1748       why     = "kill unresponsive jobs";
1749     }
1750 
1751     if (job->state_value == IPP_JOB_HELD && job->hold_until < timeout)
1752     {
1753       timeout = job->hold_until;
1754       why     = "release held jobs";
1755     }
1756 
1757     if (job->state_value == IPP_JOB_PENDING && timeout > (now + 10))
1758     {
1759       timeout = now + 10;
1760       why     = "start pending jobs";
1761       break;
1762     }
1763   }
1764 
1765  /*
1766   * Adjust from absolute to relative time.  We add 1 second to the timeout since
1767   * events occur after the timeout expires, and limit the timeout to 86400
1768   * seconds (1 day) to avoid select() timeout limits present on some operating
1769   * systems...
1770   */
1771 
1772   timeout = timeout - now + 1;
1773 
1774   if (timeout < 1)
1775     timeout = 1;
1776   else if (timeout > 86400)
1777     timeout = 86400;
1778 
1779  /*
1780   * Log and return the timeout value...
1781   */
1782 
1783   cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout(%d): %ld seconds to %s",
1784                   fds, timeout, why);
1785 
1786   return (timeout);
1787 }
1788 
1789 
1790 /*
1791  * 'sigchld_handler()' - Handle 'child' signals from old processes.
1792  */
1793 
1794 static void
sigchld_handler(int sig)1795 sigchld_handler(int sig)		/* I - Signal number */
1796 {
1797   (void)sig;
1798 
1799  /*
1800   * Flag that we have dead children...
1801   */
1802 
1803   dead_children = 1;
1804 
1805  /*
1806   * Reset the signal handler as needed...
1807   */
1808 
1809 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1810   signal(SIGCLD, sigchld_handler);
1811 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1812 }
1813 
1814 
1815 /*
1816  * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler.
1817  */
1818 
1819 static void
sighup_handler(int sig)1820 sighup_handler(int sig)			/* I - Signal number */
1821 {
1822   (void)sig;
1823 
1824   NeedReload = RELOAD_ALL;
1825   ReloadTime = time(NULL);
1826 
1827 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1828   signal(SIGHUP, sighup_handler);
1829 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1830 }
1831 
1832 
1833 /*
1834  * 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler.
1835  */
1836 
1837 static void
sigterm_handler(int sig)1838 sigterm_handler(int sig)		/* I - Signal number */
1839 {
1840   (void)sig;	/* remove compiler warnings... */
1841 
1842  /*
1843   * Flag that we should stop and return...
1844   */
1845 
1846   stop_scheduler = 1;
1847 }
1848 
1849 
1850 #ifdef HAVE_ONDEMAND
1851 /*
1852  * 'service_add_listener()' - Bind an open fd as a Listener.
1853  */
1854 
1855 static void
service_add_listener(int fd,int idx)1856 service_add_listener(int fd,		/* I - Socket file descriptor */
1857                      int idx)		/* I - Listener number, for logging */
1858 {
1859   cupsd_listener_t	*lis;		/* Listeners array */
1860   http_addr_t		addr;		/* Address variable */
1861   socklen_t		addrlen;	/* Length of address */
1862   char			s[256];		/* String address */
1863 
1864 
1865   addrlen = sizeof(addr);
1866 
1867   if (getsockname(fd, (struct sockaddr *)&addr, &addrlen))
1868   {
1869     cupsdLogMessage(CUPSD_LOG_ERROR, "service_add_listener: Unable to get local address for listener #%d: %s", idx + 1, strerror(errno));
1870     return;
1871   }
1872 
1873   cupsdLogMessage(CUPSD_LOG_DEBUG, "service_add_listener: Listener #%d at fd %d, \"%s\".", idx + 1, fd, httpAddrString(&addr, s, sizeof(s)));
1874 
1875  /*
1876   * Try to match the on-demand socket address to one of the listeners...
1877   */
1878 
1879   for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
1880        lis;
1881        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
1882     if (httpAddrEqual(&lis->address, &addr))
1883       break;
1884 
1885   /*
1886    * Add a new listener If there's no match...
1887    */
1888 
1889   if (lis)
1890   {
1891     cupsdLogMessage(CUPSD_LOG_DEBUG, "service_add_listener: Matched existing listener #%d to %s.", idx + 1, httpAddrString(&(lis->address), s, sizeof(s)));
1892   }
1893   else
1894   {
1895     cupsdLogMessage(CUPSD_LOG_DEBUG, "service_add_listener: Adding new listener #%d for %s.", idx + 1, httpAddrString(&addr, s, sizeof(s)));
1896 
1897     if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
1898     {
1899       cupsdLogMessage(CUPSD_LOG_ERROR, "service_add_listener: Unable to allocate listener: %s.", strerror(errno));
1900       exit(EXIT_FAILURE);
1901     }
1902 
1903     cupsArrayAdd(Listeners, lis);
1904 
1905     memcpy(&lis->address, &addr, sizeof(lis->address));
1906   }
1907 
1908   lis->fd        = fd;
1909   lis->on_demand = 1;
1910 
1911 #  ifdef HAVE_TLS
1912   if (httpAddrPort(&(lis->address)) == 443)
1913     lis->encryption = HTTP_ENCRYPT_ALWAYS;
1914 #  endif /* HAVE_TLS */
1915 }
1916 #endif /* HAVE_ONDEMAND */
1917 
1918 
1919 /*
1920  * 'service_checkin()' - Check-in with launchd and collect the listening fds.
1921  */
1922 
1923 static void
service_checkin(void)1924 service_checkin(void)
1925 {
1926   cupsdLogMessage(CUPSD_LOG_DEBUG, "service_checkin: pid=%d", (int)getpid());
1927 
1928 #ifdef HAVE_LAUNCHD
1929   if (OnDemand)
1930   {
1931     int       error;                        /* Check-in error, if any */
1932     size_t    i,                            /* Looping var */
1933               count;                        /* Number of listeners */
1934     int       *ld_sockets;                  /* Listener sockets */
1935 
1936 #  ifdef __APPLE__
1937    /*
1938     * Force "user initiated" priority for the main thread...
1939     */
1940 
1941     pthread_set_qos_class_self_np(QOS_CLASS_USER_INITIATED, 0);
1942 #  endif /* __APPLE__ */
1943 
1944    /*
1945     * Check-in with launchd...
1946     */
1947 
1948     if ((error = launch_activate_socket("Listeners", &ld_sockets, &count)) != 0)
1949     {
1950       cupsdLogMessage(CUPSD_LOG_ERROR, "service_checkin: Unable to get listener sockets: %s", strerror(error));
1951       exit(EXIT_FAILURE);
1952     }
1953 
1954    /*
1955     * Try to match the launchd sockets to the cupsd listeners...
1956     */
1957 
1958     cupsdLogMessage(CUPSD_LOG_DEBUG, "service_checkin: %d listeners.", (int)count);
1959 
1960     for (i = 0; i < count; i ++)
1961       service_add_listener(ld_sockets[i], (int)i);
1962 
1963     free(ld_sockets);
1964 
1965 #  ifdef __APPLE__
1966     xpc_transaction_begin();
1967 #  endif /* __APPLE__ */
1968   }
1969 
1970 #elif defined(HAVE_SYSTEMD)
1971   if (OnDemand)
1972   {
1973     int         i,                      /* Looping var */
1974                 count;                  /* Number of listeners */
1975 
1976    /*
1977     * Check-in with systemd...
1978     */
1979 
1980     if ((count = sd_listen_fds(0)) < 0)
1981     {
1982       cupsdLogMessage(CUPSD_LOG_ERROR, "service_checkin: Unable to get listener sockets: %s", strerror(-count));
1983       exit(EXIT_FAILURE);
1984     }
1985 
1986    /*
1987     * Try to match the systemd sockets to the cupsd listeners...
1988     */
1989 
1990     cupsdLogMessage(CUPSD_LOG_DEBUG, "service_checkin: %d listeners.", count);
1991 
1992     for (i = 0; i < count; i ++)
1993       service_add_listener(SD_LISTEN_FDS_START + i, i);
1994   }
1995 
1996 #elif defined(HAVE_UPSTART)
1997   if (OnDemand)
1998   {
1999     const char    *e;                   /* Environment var */
2000     int           fd;                   /* File descriptor */
2001 
2002 
2003     if (!(e = getenv("UPSTART_EVENTS")))
2004     {
2005       cupsdLogMessage(CUPSD_LOG_ERROR, "service_checkin: We did not get started via Upstart.");
2006       exit(EXIT_FAILURE);
2007     }
2008 
2009     if (strcasecmp(e, "socket"))
2010     {
2011       cupsdLogMessage(CUPSD_LOG_ERROR, "service_checkin: We did not get triggered via an Upstart socket event.");
2012       exit(EXIT_FAILURE);
2013     }
2014 
2015     if ((e = getenv("UPSTART_FDS")) == NULL)
2016     {
2017       cupsdLogMessage(CUPSD_LOG_ERROR, "service_checkin: Unable to get listener sockets from UPSTART_FDS.");
2018       exit(EXIT_FAILURE);
2019     }
2020 
2021     cupsdLogMessage(CUPSD_LOG_DEBUG, "service_checkin: UPSTART_FDS=%s", e);
2022 
2023     fd = atoi(e);
2024     if (fd < 0)
2025     {
2026       cupsdLogMessage(CUPSD_LOG_ERROR, "service_checkin: Could not parse UPSTART_FDS: %s", strerror(errno));
2027       exit(EXIT_FAILURE);
2028     }
2029 
2030    /*
2031     * Upstart only supports a single on-demand socket file descriptor...
2032     */
2033 
2034     service_add_listener(fd, 0);
2035   }
2036 #endif /* HAVE_LAUNCHD */
2037 
2038   if (cupsArrayCount(Listeners) == 0)
2039   {
2040    /*
2041     * No listeners!
2042     */
2043 
2044     cupsdLogMessage(CUPSD_LOG_EMERG, "No listener sockets present.");
2045 
2046    /*
2047     * Commit suicide...
2048     */
2049 
2050     cupsdEndProcess(getpid(), 0);
2051   }
2052 }
2053 
2054 
2055 /*
2056  * 'service_checkout()' - Update the KeepAlive/PID file as needed.
2057  */
2058 
2059 static void
service_checkout(int shutdown)2060 service_checkout(int shutdown)          /* I - Shutting down? */
2061 {
2062   cups_file_t   *fp;			/* File */
2063   char          pidfile[1024];          /* PID/KeepAlive file */
2064 
2065 
2066  /*
2067   * When running on-demand, use the KeepAlive file, otherwise write a PID file
2068   * to StateDir...
2069   */
2070 
2071 #ifdef HAVE_ONDEMAND
2072   if (OnDemand)
2073   {
2074     int shared_printers = 0;		/* Do we have shared printers? */
2075 
2076     strlcpy(pidfile, CUPS_KEEPALIVE, sizeof(pidfile));
2077 
2078    /*
2079     * If printer sharing is on see if there are any actual shared printers...
2080     */
2081 
2082     if (Browsing && BrowseLocalProtocols)
2083     {
2084       cupsd_printer_t *p = NULL;	/* Current printer */
2085 
2086       for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers))
2087       {
2088         if (p->shared)
2089           break;
2090       }
2091 
2092       shared_printers = (p != NULL);
2093     }
2094 
2095     if (cupsArrayCount(ActiveJobs) ||	/* Active jobs */
2096         WebInterface ||			/* Web interface enabled */
2097         NeedReload ||			/* Doing a reload */
2098         shared_printers)                /* Printers being shared */
2099     {
2100      /*
2101       * Create or remove the "keep-alive" file based on whether there are active
2102       * jobs or shared printers to advertise...
2103       */
2104 
2105       shutdown = 0;
2106     }
2107   }
2108   else
2109 #endif /* HAVE_ONDEMAND */
2110   snprintf(pidfile, sizeof(pidfile), "%s/cupsd.pid", StateDir);
2111 
2112   if (shutdown)
2113   {
2114     cupsdLogMessage(CUPSD_LOG_DEBUG, "Removing KeepAlive/PID file \"%s\".", pidfile);
2115 
2116     unlink(pidfile);
2117   }
2118   else
2119   {
2120     cupsdLogMessage(CUPSD_LOG_DEBUG, "Creating KeepAlive/PID file \"%s\".", pidfile);
2121 
2122     if ((fp = cupsFileOpen(pidfile, "w")) != NULL)
2123     {
2124      /*
2125       * Save the PID in the file...
2126       */
2127 
2128       cupsFilePrintf(fp, "%d\n", (int)getpid());
2129       cupsFileClose(fp);
2130     }
2131     else
2132       cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create KeepAlive/PID file \"%s\": %s", pidfile, strerror(errno));
2133   }
2134 
2135 #  ifdef __APPLE__
2136   if (OnDemand && shutdown)
2137     xpc_transaction_end();
2138 #  endif /* __APPLE__ */
2139 }
2140 
2141 
2142 /*
2143  * 'usage()' - Show scheduler usage.
2144  */
2145 
2146 static void
usage(int status)2147 usage(int status)			/* O - Exit status */
2148 {
2149   FILE	*fp = status ? stderr : stdout;	/* Output file */
2150 
2151 
2152   _cupsLangPuts(fp, _("Usage: cupsd [options]"));
2153   _cupsLangPuts(fp, _("Options:"));
2154   _cupsLangPuts(fp, _("-c cupsd.conf           Set cupsd.conf file to use."));
2155   _cupsLangPuts(fp, _("-f                      Run in the foreground."));
2156   _cupsLangPuts(fp, _("-F                      Run in the foreground but detach from console."));
2157   _cupsLangPuts(fp, _("-h                      Show this usage message."));
2158 #ifdef HAVE_ONDEMAND
2159   _cupsLangPuts(fp, _("-l                      Run cupsd on demand."));
2160 #endif /* HAVE_ONDEMAND */
2161   _cupsLangPuts(fp, _("-s cups-files.conf      Set cups-files.conf file to use."));
2162   _cupsLangPuts(fp, _("-t                      Test the configuration file."));
2163 
2164   exit(status);
2165 }
2166