Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
srohatgi01
GitHub Repository: srohatgi01/cups
Path: blob/master/scheduler/main.c
1090 views
1
/*
2
* Main loop for the CUPS scheduler.
3
*
4
* Copyright © 2021-2022 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 */
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...
523
*/
524
525
getrlimit(RLIMIT_NOFILE, &limit);
526
527
#if !defined(HAVE_POLL) && !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE)
528
if (limit.rlim_max > FD_SETSIZE)
529
MaxFDs = FD_SETSIZE;
530
else
531
#endif /* !HAVE_POLL && !HAVE_EPOLL && !HAVE_KQUEUE */
532
#ifdef RLIM_INFINITY
533
if (limit.rlim_max == RLIM_INFINITY)
534
MaxFDs = 16384;
535
else
536
#endif /* RLIM_INFINITY */
537
MaxFDs = limit.rlim_max;
538
539
limit.rlim_cur = (rlim_t)MaxFDs;
540
541
setrlimit(RLIMIT_NOFILE, &limit);
542
543
cupsdStartSelect();
544
545
/*
546
* Read configuration...
547
*/
548
549
if (!cupsdReadConfiguration())
550
return (1);
551
else if (TestConfigFile)
552
{
553
printf("\"%s\" is OK.\n", CupsFilesFile);
554
printf("\"%s\" is OK.\n", ConfigurationFile);
555
return (0);
556
}
557
else if (print_profile)
558
{
559
cups_file_t *fp; /* File pointer */
560
const char *profile = cupsdCreateProfile(42, 0);
561
/* Profile */
562
char line[1024]; /* Line from file */
563
564
565
if ((fp = cupsFileOpen(profile, "r")) == NULL)
566
{
567
printf("Unable to open profile file \"%s\": %s\n", profile ? profile : "(null)", strerror(errno));
568
return (1);
569
}
570
571
while (cupsFileGets(fp, line, sizeof(line)))
572
puts(line);
573
574
cupsFileClose(fp);
575
576
return (0);
577
}
578
579
/*
580
* Clean out old temp files and printer cache data.
581
*/
582
583
if (!RequestRoot || !strncmp(TempDir, RequestRoot, strlen(RequestRoot)))
584
cupsdCleanFiles(TempDir, NULL);
585
586
cupsdCleanFiles(CacheDir, "*.ipp");
587
588
/*
589
* If we were started on demand by launchd or systemd get the listen sockets
590
* file descriptors...
591
*/
592
593
service_checkin();
594
service_checkout(0);
595
596
/*
597
* Startup the server...
598
*/
599
600
httpInitialize();
601
602
cupsdStartServer();
603
604
/*
605
* Catch hangup and child signals and ignore broken pipes...
606
*/
607
608
#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
609
sigset(SIGCHLD, sigchld_handler);
610
sigset(SIGHUP, sighup_handler);
611
sigset(SIGPIPE, SIG_IGN);
612
sigset(SIGTERM, sigterm_handler);
613
#elif defined(HAVE_SIGACTION)
614
memset(&action, 0, sizeof(action));
615
616
sigemptyset(&action.sa_mask);
617
sigaddset(&action.sa_mask, SIGTERM);
618
sigaddset(&action.sa_mask, SIGCHLD);
619
action.sa_handler = sigchld_handler;
620
sigaction(SIGCHLD, &action, NULL);
621
622
sigemptyset(&action.sa_mask);
623
sigaddset(&action.sa_mask, SIGHUP);
624
action.sa_handler = sighup_handler;
625
sigaction(SIGHUP, &action, NULL);
626
627
sigemptyset(&action.sa_mask);
628
action.sa_handler = SIG_IGN;
629
sigaction(SIGPIPE, &action, NULL);
630
631
sigemptyset(&action.sa_mask);
632
sigaddset(&action.sa_mask, SIGTERM);
633
sigaddset(&action.sa_mask, SIGCHLD);
634
action.sa_handler = sigterm_handler;
635
sigaction(SIGTERM, &action, NULL);
636
#else
637
signal(SIGCLD, sigchld_handler); /* No, SIGCLD isn't a typo... */
638
signal(SIGHUP, sighup_handler);
639
signal(SIGPIPE, SIG_IGN);
640
signal(SIGTERM, sigterm_handler);
641
#endif /* HAVE_SIGSET */
642
643
/*
644
* Initialize authentication certificates...
645
*/
646
647
cupsdInitCerts();
648
649
/*
650
* If we are running in the background, signal the parent process that
651
* we are up and running...
652
*/
653
654
if (!fg || run_as_child)
655
{
656
/*
657
* Send a signal to the parent process, but only if the parent is
658
* not PID 1 (init). This avoids accidentally shutting down the
659
* system on OpenBSD if you CTRL-C the server before it is up...
660
*/
661
662
i = getppid(); /* Save parent PID to avoid race condition */
663
664
if (i != 1)
665
kill(i, SIGUSR1);
666
}
667
668
#ifdef __APPLE__
669
/*
670
* Start power management framework...
671
*/
672
673
if (use_sysman)
674
cupsdStartSystemMonitor();
675
#endif /* __APPLE__ */
676
677
/*
678
* Send server-started event...
679
*/
680
681
#ifdef HAVE_ONDEMAND
682
if (OnDemand)
683
{
684
cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL, "Scheduler started on demand.");
685
686
# ifdef HAVE_SYSTEMD
687
sd_notifyf(0, "READY=1\n"
688
"STATUS=Scheduler is running...\n"
689
"MAINPID=%lu", (unsigned long)getpid());
690
# endif /* HAVE_SYSTEMD */
691
}
692
else
693
694
#endif /* HAVE_ONDEMAND */
695
if (fg)
696
cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL, "Scheduler started in foreground.");
697
else
698
cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL, "Scheduler started in background.");
699
700
cupsdSetBusyState(0);
701
702
/*
703
* Start any pending print jobs...
704
*/
705
706
cupsdCheckJobs();
707
708
/*
709
* Loop forever...
710
*/
711
712
current_time = time(NULL);
713
event_time = current_time;
714
expire_time = current_time;
715
local_timeout = 0;
716
fds = 1;
717
report_time = 0;
718
senddoc_time = current_time;
719
720
while (!stop_scheduler)
721
{
722
/*
723
* Check if there are dead children to handle...
724
*/
725
726
if (dead_children)
727
process_children();
728
729
/*
730
* Check if we need to load the server configuration file...
731
*/
732
733
if (NeedReload)
734
{
735
/*
736
* Close any idle clients...
737
*/
738
739
if (cupsArrayCount(Clients) > 0)
740
{
741
for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
742
con;
743
con = (cupsd_client_t *)cupsArrayNext(Clients))
744
if (httpGetState(con->http) == HTTP_WAITING)
745
cupsdCloseClient(con);
746
else
747
con->http->keep_alive = HTTP_KEEPALIVE_OFF;
748
749
cupsdPauseListening();
750
}
751
752
/*
753
* Restart if all clients are closed and all jobs finished, or
754
* if the reload timeout has elapsed...
755
*/
756
757
if ((cupsArrayCount(Clients) == 0 &&
758
(cupsArrayCount(PrintingJobs) == 0 || NeedReload != RELOAD_ALL)) ||
759
(time(NULL) - ReloadTime) >= ReloadTimeout)
760
{
761
/*
762
* Shutdown the server...
763
*/
764
765
#ifdef HAVE_ONDEMAND
766
if (OnDemand)
767
{
768
# ifndef HAVE_SYSTEMD /* Issue #5640: systemd doesn't actually support launch-on-demand services, need to fake it */
769
stop_scheduler = 1;
770
# endif /* HAVE_SYSTEMD */
771
break;
772
}
773
#endif /* HAVE_ONDEMAND */
774
775
DoingShutdown = 1;
776
777
cupsdStopServer();
778
779
/*
780
* Read configuration...
781
*/
782
783
if (!cupsdReadConfiguration())
784
{
785
#ifdef HAVE_SYSTEMD_SD_JOURNAL_H
786
sd_journal_print(LOG_ERR, "Unable to read configuration file \"%s\" - exiting.", ConfigurationFile);
787
#else
788
syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting.", ConfigurationFile);
789
#endif /* HAVE_SYSTEMD_SD_JOURNAL_H */
790
791
break;
792
}
793
794
/*
795
* Startup the server...
796
*/
797
798
DoingShutdown = 0;
799
800
cupsdStartServer();
801
802
/*
803
* Send a server-restarted event...
804
*/
805
806
cupsdAddEvent(CUPSD_EVENT_SERVER_RESTARTED, NULL, NULL,
807
"Scheduler restarted.");
808
}
809
}
810
811
/*
812
* Check for available input or ready output. If cupsdDoSelect()
813
* returns 0 or -1, something bad happened and we should exit
814
* immediately.
815
*
816
* Note that we at least have one listening socket open at all
817
* times.
818
*/
819
820
if ((timeout = select_timeout(fds)) > 1 && LastEvent)
821
timeout = 1;
822
823
#ifdef HAVE_ONDEMAND
824
/*
825
* If no other work is scheduled and we're being controlled by launchd,
826
* systemd, etc. then timeout after 'IdleExitTimeout' seconds of
827
* inactivity...
828
*/
829
830
if (timeout == 86400 && OnDemand && IdleExitTimeout &&
831
# ifdef HAVE_SYSTEMD
832
!WebInterface &&
833
# endif /* HAVE_SYSTEMD */
834
!cupsArrayCount(ActiveJobs))
835
{
836
cupsd_printer_t *p = NULL; /* Current printer */
837
838
if (Browsing && BrowseLocalProtocols)
839
{
840
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers))
841
if (p->shared)
842
break;
843
}
844
845
if (!p)
846
{
847
timeout = IdleExitTimeout;
848
service_idle_exit = 1;
849
}
850
}
851
else
852
service_idle_exit = 0;
853
#endif /* HAVE_ONDEMAND */
854
855
if ((fds = cupsdDoSelect(timeout)) < 0)
856
{
857
/*
858
* Got an error from select!
859
*/
860
861
#ifdef HAVE_DNSSD
862
cupsd_printer_t *p; /* Current printer */
863
#endif /* HAVE_DNSSD */
864
865
if (errno == EINTR) /* Just interrupted by a signal */
866
continue;
867
868
/*
869
* Log all sorts of debug info to help track down the problem.
870
*/
871
872
cupsdLogMessage(CUPSD_LOG_EMERG, "cupsdDoSelect() failed - %s!",
873
strerror(errno));
874
875
for (i = 0, con = (cupsd_client_t *)cupsArrayFirst(Clients);
876
con;
877
i ++, con = (cupsd_client_t *)cupsArrayNext(Clients))
878
cupsdLogMessage(CUPSD_LOG_EMERG,
879
"Clients[%d] = %d, file = %d, state = %d",
880
i, con->number, con->file, httpGetState(con->http));
881
882
for (i = 0, lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
883
lis;
884
i ++, lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
885
cupsdLogMessage(CUPSD_LOG_EMERG, "Listeners[%d] = %d", i, lis->fd);
886
887
cupsdLogMessage(CUPSD_LOG_EMERG, "CGIPipes[0] = %d", CGIPipes[0]);
888
889
#ifdef __APPLE__
890
cupsdLogMessage(CUPSD_LOG_EMERG, "SysEventPipes[0] = %d",
891
SysEventPipes[0]);
892
#endif /* __APPLE__ */
893
894
for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
895
job;
896
job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
897
cupsdLogMessage(CUPSD_LOG_EMERG, "Jobs[%d] = %d < [%d %d] > [%d %d]",
898
job->id,
899
job->status_buffer ? job->status_buffer->fd : -1,
900
job->print_pipes[0], job->print_pipes[1],
901
job->back_pipes[0], job->back_pipes[1]);
902
903
#ifdef HAVE_DNSSD
904
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
905
p;
906
p = (cupsd_printer_t *)cupsArrayNext(Printers))
907
cupsdLogMessage(CUPSD_LOG_EMERG, "printer[%s] reg_name=\"%s\"", p->name,
908
p->reg_name ? p->reg_name : "(null)");
909
#endif /* HAVE_DNSSD */
910
911
break;
912
}
913
914
current_time = time(NULL);
915
916
/*
917
* Write dirty config/state files...
918
*/
919
920
if (DirtyCleanTime && current_time >= DirtyCleanTime)
921
cupsdCleanDirty();
922
923
#ifdef __APPLE__
924
/*
925
* If we are going to sleep and still have pending jobs, stop them after
926
* a period of time...
927
*/
928
929
if (SleepJobs > 0 && current_time >= SleepJobs &&
930
cupsArrayCount(PrintingJobs) > 0)
931
{
932
SleepJobs = 0;
933
cupsdStopAllJobs(CUPSD_JOB_DEFAULT, 5);
934
}
935
#endif /* __APPLE__ */
936
937
#ifndef __APPLE__
938
/*
939
* Update the network interfaces once a minute...
940
*/
941
942
if ((current_time - netif_time) >= 60)
943
{
944
netif_time = current_time;
945
NetIFUpdate = 1;
946
}
947
#endif /* !__APPLE__ */
948
949
#ifdef HAVE_ONDEMAND
950
/*
951
* If no other work was scheduled and we're being controlled by launchd,
952
* systemd, or upstart then timeout after 'LaunchdTimeout' seconds of
953
* inactivity...
954
*/
955
956
if (!fds && service_idle_exit)
957
{
958
cupsdLogMessage(CUPSD_LOG_INFO,
959
"Printer sharing is off and there are no jobs pending, "
960
"will restart on demand.");
961
stop_scheduler = 1;
962
break;
963
}
964
#endif /* HAVE_ONDEMAND */
965
966
/*
967
* Resume listening for new connections as needed...
968
*/
969
970
if (ListeningPaused && ListeningPaused <= current_time &&
971
cupsArrayCount(Clients) < MaxClients)
972
cupsdResumeListening();
973
974
/*
975
* Expire subscriptions and unload completed jobs as needed...
976
*/
977
978
if (current_time > expire_time)
979
{
980
cupsdExpireSubscriptions(NULL, NULL);
981
982
cupsdUnloadCompletedJobs();
983
984
expire_time = current_time;
985
}
986
987
/*
988
* Delete stale local printers...
989
*/
990
991
if (current_time >= local_timeout)
992
{
993
cupsdDeleteTemporaryPrinters(0);
994
local_timeout = 0;
995
}
996
997
#ifndef HAVE_AUTHORIZATION_H
998
/*
999
* Update the root certificate once every 5 minutes if we have client
1000
* connections...
1001
*/
1002
1003
if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration &&
1004
!RunUser && cupsArrayCount(Clients))
1005
{
1006
/*
1007
* Update the root certificate...
1008
*/
1009
1010
cupsdDeleteCert(0);
1011
cupsdAddCert(0, "root", cupsdDefaultAuthType());
1012
}
1013
#endif /* !HAVE_AUTHORIZATION_H */
1014
1015
/*
1016
* Clean job history...
1017
*/
1018
1019
if (JobHistoryUpdate && current_time >= JobHistoryUpdate)
1020
cupsdCleanJobs();
1021
1022
/*
1023
* Update any pending multi-file documents...
1024
*/
1025
1026
if ((current_time - senddoc_time) >= 10)
1027
{
1028
cupsdCheckJobs();
1029
senddoc_time = current_time;
1030
}
1031
1032
/*
1033
* Check for new data on the client sockets...
1034
*/
1035
1036
for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
1037
con;
1038
con = (cupsd_client_t *)cupsArrayNext(Clients))
1039
{
1040
/*
1041
* Process pending data in the input buffer...
1042
*/
1043
1044
if (httpGetReady(con->http))
1045
{
1046
cupsdReadClient(con);
1047
continue;
1048
}
1049
1050
/*
1051
* Check the activity and close old clients...
1052
*/
1053
1054
activity = current_time - Timeout;
1055
if (httpGetActivity(con->http) < activity && !con->pipe_pid)
1056
{
1057
cupsdLogMessage(CUPSD_LOG_DEBUG, "Closing client %d after %d seconds of inactivity.", con->number, Timeout);
1058
1059
cupsdCloseClient(con);
1060
continue;
1061
}
1062
}
1063
1064
/*
1065
* Log statistics at most once a minute when in debug mode...
1066
*/
1067
1068
if ((current_time - report_time) >= 60 && LogLevel >= CUPSD_LOG_DEBUG)
1069
{
1070
size_t string_count, /* String count */
1071
alloc_bytes, /* Allocated string bytes */
1072
total_bytes; /* Total string bytes */
1073
#ifdef HAVE_MALLINFO
1074
struct mallinfo mem; /* Malloc information */
1075
1076
1077
mem = mallinfo();
1078
cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-arena=%lu", mem.arena);
1079
cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-used=%lu",
1080
mem.usmblks + mem.uordblks);
1081
cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-free=%lu",
1082
mem.fsmblks + mem.fordblks);
1083
#endif /* HAVE_MALLINFO */
1084
1085
cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: clients=%d",
1086
cupsArrayCount(Clients));
1087
cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: jobs=%d",
1088
cupsArrayCount(Jobs));
1089
cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: jobs-active=%d",
1090
cupsArrayCount(ActiveJobs));
1091
cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: printers=%d",
1092
cupsArrayCount(Printers));
1093
1094
string_count = _cupsStrStatistics(&alloc_bytes, &total_bytes);
1095
cupsdLogMessage(CUPSD_LOG_DEBUG,
1096
"Report: stringpool-string-count=" CUPS_LLFMT,
1097
CUPS_LLCAST string_count);
1098
cupsdLogMessage(CUPSD_LOG_DEBUG,
1099
"Report: stringpool-alloc-bytes=" CUPS_LLFMT,
1100
CUPS_LLCAST alloc_bytes);
1101
cupsdLogMessage(CUPSD_LOG_DEBUG,
1102
"Report: stringpool-total-bytes=" CUPS_LLFMT,
1103
CUPS_LLCAST total_bytes);
1104
1105
report_time = current_time;
1106
}
1107
1108
/*
1109
* Handle OS-specific event notification for any events that have
1110
* accumulated. Don't send these more than once a second...
1111
*/
1112
1113
if (LastEvent && (current_time - event_time) >= 1)
1114
{
1115
#ifdef HAVE_NOTIFY_POST
1116
if (LastEvent & (CUPSD_EVENT_PRINTER_ADDED |
1117
CUPSD_EVENT_PRINTER_DELETED |
1118
CUPSD_EVENT_PRINTER_MODIFIED))
1119
{
1120
cupsdLogMessage(CUPSD_LOG_DEBUG2,
1121
"notify_post(\"com.apple.printerListChange\")");
1122
notify_post("com.apple.printerListChange");
1123
}
1124
1125
if (LastEvent & CUPSD_EVENT_PRINTER_STATE_CHANGED)
1126
{
1127
cupsdLogMessage(CUPSD_LOG_DEBUG2,
1128
"notify_post(\"com.apple.printerHistoryChange\")");
1129
notify_post("com.apple.printerHistoryChange");
1130
}
1131
1132
if (LastEvent & (CUPSD_EVENT_JOB_STATE_CHANGED |
1133
CUPSD_EVENT_JOB_CONFIG_CHANGED |
1134
CUPSD_EVENT_JOB_PROGRESS))
1135
{
1136
cupsdLogMessage(CUPSD_LOG_DEBUG2,
1137
"notify_post(\"com.apple.jobChange\")");
1138
notify_post("com.apple.jobChange");
1139
}
1140
#endif /* HAVE_NOTIFY_POST */
1141
1142
/*
1143
* Reset the accumulated events...
1144
*/
1145
1146
LastEvent = CUPSD_EVENT_NONE;
1147
event_time = current_time;
1148
}
1149
}
1150
1151
/*
1152
* Log a message based on what happened...
1153
*/
1154
1155
if (stop_scheduler)
1156
{
1157
cupsdLogMessage(CUPSD_LOG_INFO, "Scheduler shutting down normally.");
1158
cupsdAddEvent(CUPSD_EVENT_SERVER_STOPPED, NULL, NULL,
1159
"Scheduler shutting down normally.");
1160
}
1161
else
1162
{
1163
cupsdLogMessage(CUPSD_LOG_ERROR,
1164
"Scheduler shutting down due to program error.");
1165
cupsdAddEvent(CUPSD_EVENT_SERVER_STOPPED, NULL, NULL,
1166
"Scheduler shutting down due to program error.");
1167
}
1168
1169
/*
1170
* Close all network clients...
1171
*/
1172
1173
DoingShutdown = 1;
1174
1175
cupsdStopServer();
1176
1177
/*
1178
* Update the KeepAlive/PID file as needed...
1179
*/
1180
1181
service_checkout(1);
1182
1183
/*
1184
* Stop all jobs...
1185
*/
1186
1187
cupsdFreeAllJobs();
1188
1189
/*
1190
* Delete all temporary printers...
1191
*/
1192
1193
cupsdDeleteTemporaryPrinters(1);
1194
1195
#ifdef __APPLE__
1196
/*
1197
* Stop monitoring system event monitoring...
1198
*/
1199
1200
if (use_sysman)
1201
cupsdStopSystemMonitor();
1202
#endif /* __APPLE__ */
1203
1204
cupsdStopSelect();
1205
1206
return (!stop_scheduler);
1207
}
1208
1209
1210
/*
1211
* 'cupsdAddString()' - Copy and add a string to an array.
1212
*/
1213
1214
int /* O - 1 on success, 0 on failure */
1215
cupsdAddString(cups_array_t **a, /* IO - String array */
1216
const char *s) /* I - String to copy and add */
1217
{
1218
if (!*a)
1219
*a = cupsArrayNew3((cups_array_func_t)strcmp, NULL,
1220
(cups_ahash_func_t)NULL, 0,
1221
(cups_acopy_func_t)strdup,
1222
(cups_afree_func_t)free);
1223
1224
return (cupsArrayAdd(*a, (char *)s));
1225
}
1226
1227
1228
/*
1229
* 'cupsdCheckProcess()' - Tell the main loop to check for dead children.
1230
*/
1231
1232
void
1233
cupsdCheckProcess(void)
1234
{
1235
/*
1236
* Flag that we have dead children...
1237
*/
1238
1239
dead_children = 1;
1240
}
1241
1242
1243
/*
1244
* 'cupsdClearString()' - Clear a string.
1245
*/
1246
1247
void
1248
cupsdClearString(char **s) /* O - String value */
1249
{
1250
if (s && *s)
1251
{
1252
free(*s);
1253
*s = NULL;
1254
}
1255
}
1256
1257
1258
/*
1259
* 'cupsdFreeStrings()' - Free an array of strings.
1260
*/
1261
1262
void
1263
cupsdFreeStrings(cups_array_t **a) /* IO - String array */
1264
{
1265
if (*a)
1266
{
1267
cupsArrayDelete(*a);
1268
*a = NULL;
1269
}
1270
}
1271
1272
1273
/*
1274
* 'cupsdHoldSignals()' - Hold child and termination signals.
1275
*/
1276
1277
void
1278
cupsdHoldSignals(void)
1279
{
1280
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
1281
sigset_t newmask; /* New POSIX signal mask */
1282
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
1283
1284
1285
holdcount ++;
1286
if (holdcount > 1)
1287
return;
1288
1289
#ifdef HAVE_SIGSET
1290
sighold(SIGTERM);
1291
sighold(SIGCHLD);
1292
#elif defined(HAVE_SIGACTION)
1293
sigemptyset(&newmask);
1294
sigaddset(&newmask, SIGTERM);
1295
sigaddset(&newmask, SIGCHLD);
1296
sigprocmask(SIG_BLOCK, &newmask, &holdmask);
1297
#endif /* HAVE_SIGSET */
1298
}
1299
1300
1301
/*
1302
* 'cupsdReleaseSignals()' - Release signals for delivery.
1303
*/
1304
1305
void
1306
cupsdReleaseSignals(void)
1307
{
1308
holdcount --;
1309
if (holdcount > 0)
1310
return;
1311
1312
#ifdef HAVE_SIGSET
1313
sigrelse(SIGTERM);
1314
sigrelse(SIGCHLD);
1315
#elif defined(HAVE_SIGACTION)
1316
sigprocmask(SIG_SETMASK, &holdmask, NULL);
1317
#endif /* HAVE_SIGSET */
1318
}
1319
1320
1321
/*
1322
* 'cupsdSetString()' - Set a string value.
1323
*/
1324
1325
void
1326
cupsdSetString(char **s, /* O - New string */
1327
const char *v) /* I - String value */
1328
{
1329
if (!s || *s == v)
1330
return;
1331
1332
if (*s)
1333
free(*s);
1334
1335
if (v)
1336
*s = strdup(v);
1337
else
1338
*s = NULL;
1339
}
1340
1341
1342
/*
1343
* 'cupsdSetStringf()' - Set a formatted string value.
1344
*/
1345
1346
void
1347
cupsdSetStringf(char **s, /* O - New string */
1348
const char *f, /* I - Printf-style format string */
1349
...) /* I - Additional args as needed */
1350
{
1351
char v[65536 + 64]; /* Formatting string value */
1352
va_list ap; /* Argument pointer */
1353
char *olds; /* Old string */
1354
1355
1356
if (!s)
1357
return;
1358
1359
olds = *s;
1360
1361
if (f)
1362
{
1363
va_start(ap, f);
1364
vsnprintf(v, sizeof(v), f, ap);
1365
va_end(ap);
1366
1367
*s = strdup(v);
1368
}
1369
else
1370
*s = NULL;
1371
1372
if (olds)
1373
free(olds);
1374
}
1375
1376
1377
/*
1378
* 'parent_handler()' - Catch USR1/CHLD signals...
1379
*/
1380
1381
static void
1382
parent_handler(int sig) /* I - Signal */
1383
{
1384
/*
1385
* Store the signal we got from the OS and return...
1386
*/
1387
1388
parent_signal = sig;
1389
}
1390
1391
1392
/*
1393
* 'process_children()' - Process all dead children...
1394
*/
1395
1396
static void
1397
process_children(void)
1398
{
1399
int status; /* Exit status of child */
1400
int pid, /* Process ID of child */
1401
job_id; /* Job ID of child */
1402
cupsd_job_t *job; /* Current job */
1403
size_t i; /* Looping var */
1404
char name[1024]; /* Process name */
1405
const char *type; /* Type of program */
1406
1407
1408
cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_children()");
1409
1410
/*
1411
* Reset the dead_children flag...
1412
*/
1413
1414
dead_children = 0;
1415
1416
/*
1417
* Collect the exit status of some children...
1418
*/
1419
1420
#ifdef HAVE_WAITPID
1421
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
1422
#elif defined(HAVE_WAIT3)
1423
while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
1424
#else
1425
if ((pid = wait(&status)) > 0)
1426
#endif /* HAVE_WAITPID */
1427
{
1428
/*
1429
* Collect the name of the process that finished...
1430
*/
1431
1432
cupsdFinishProcess(pid, name, sizeof(name), &job_id);
1433
1434
/*
1435
* Delete certificates for CGI processes...
1436
*/
1437
1438
cupsdDeleteCert(pid);
1439
1440
/*
1441
* Handle completed job filters...
1442
*/
1443
1444
if (job_id > 0)
1445
job = cupsdFindJob(job_id);
1446
else
1447
job = NULL;
1448
1449
if (job)
1450
{
1451
for (i = 0; job->filters[i]; i ++)
1452
if (job->filters[i] == pid)
1453
break;
1454
1455
if (job->filters[i] || job->backend == pid)
1456
{
1457
/*
1458
* OK, this process has gone away; what's left?
1459
*/
1460
1461
if (job->filters[i])
1462
{
1463
job->filters[i] = -pid;
1464
type = "Filter";
1465
}
1466
else
1467
{
1468
job->backend = -pid;
1469
type = "Backend";
1470
}
1471
1472
if (status && status != SIGTERM && status != SIGKILL &&
1473
status != SIGPIPE)
1474
{
1475
/*
1476
* An error occurred; save the exit status so we know to stop
1477
* the printer or cancel the job when all of the filters finish...
1478
*
1479
* A negative status indicates that the backend failed and the
1480
* printer needs to be stopped.
1481
*
1482
* In order to preserve the most serious status, we always log
1483
* when a process dies due to a signal (e.g. SIGABRT, SIGSEGV,
1484
* and SIGBUS) and prefer to log the backend exit status over a
1485
* filter's.
1486
*/
1487
1488
int old_status = abs(job->status);
1489
1490
if (WIFSIGNALED(status) || /* This process crashed, or */
1491
!job->status || /* No process had a status, or */
1492
(!job->filters[i] && WIFEXITED(old_status)))
1493
{ /* Backend and filter didn't crash */
1494
if (job->filters[i])
1495
{
1496
job->status = status; /* Filter failed */
1497
}
1498
else
1499
{
1500
job->status = -status; /* Backend failed */
1501
1502
if (job->current_file < job->num_files)
1503
cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_FORCE, "Canceling multi-file job due to backend failure.");
1504
}
1505
}
1506
1507
if (job->state_value == IPP_JOB_PROCESSING &&
1508
job->status_level > CUPSD_LOG_ERROR &&
1509
(job->filters[i] || !WIFEXITED(status)))
1510
{
1511
char message[1024]; /* New printer-state-message */
1512
1513
1514
job->status_level = CUPSD_LOG_ERROR;
1515
1516
snprintf(message, sizeof(message), "%s failed", type);
1517
1518
if (job->printer)
1519
{
1520
strlcpy(job->printer->state_message, message,
1521
sizeof(job->printer->state_message));
1522
}
1523
1524
if (!job->attrs)
1525
cupsdLoadJob(job);
1526
1527
if (!job->printer_message && job->attrs)
1528
{
1529
if ((job->printer_message =
1530
ippFindAttribute(job->attrs, "job-printer-state-message",
1531
IPP_TAG_TEXT)) == NULL)
1532
job->printer_message = ippAddString(job->attrs, IPP_TAG_JOB,
1533
IPP_TAG_TEXT,
1534
"job-printer-state-message",
1535
NULL, NULL);
1536
}
1537
1538
if (job->printer_message)
1539
ippSetString(job->attrs, &job->printer_message, 0, message);
1540
}
1541
}
1542
1543
/*
1544
* If this is not the last file in a job, see if all of the
1545
* filters are done, and if so move to the next file.
1546
*/
1547
1548
if (job->state_value >= IPP_JOB_CANCELED)
1549
{
1550
/*
1551
* Remove the job from the active list if there are no processes still
1552
* running for it...
1553
*/
1554
1555
for (i = 0; job->filters[i] < 0; i++);
1556
1557
if (!job->filters[i] && job->backend <= 0)
1558
cupsArrayRemove(ActiveJobs, job);
1559
}
1560
else if (job->current_file < job->num_files && job->printer)
1561
{
1562
for (i = 0; job->filters[i] < 0; i ++);
1563
1564
if (!job->filters[i] &&
1565
(!job->printer->pc || !job->printer->pc->single_file ||
1566
job->backend <= 0))
1567
{
1568
/*
1569
* Process the next file...
1570
*/
1571
1572
cupsdContinueJob(job);
1573
}
1574
}
1575
}
1576
}
1577
1578
/*
1579
* Show the exit status as needed, ignoring SIGTERM and SIGKILL errors
1580
* since they come when we kill/end a process...
1581
*/
1582
1583
if (status == SIGTERM || status == SIGKILL)
1584
{
1585
cupsdLogJob(job, CUPSD_LOG_DEBUG,
1586
"PID %d (%s) was terminated normally with signal %d.", pid,
1587
name, status);
1588
}
1589
else if (status == SIGPIPE)
1590
{
1591
cupsdLogJob(job, CUPSD_LOG_DEBUG,
1592
"PID %d (%s) did not catch or ignore signal %d.", pid, name,
1593
status);
1594
}
1595
else if (status)
1596
{
1597
if (WIFEXITED(status))
1598
{
1599
int code = WEXITSTATUS(status); /* Exit code */
1600
1601
if (code > 100)
1602
cupsdLogJob(job, CUPSD_LOG_DEBUG,
1603
"PID %d (%s) stopped with status %d (%s)", pid, name,
1604
code, strerror(code - 100));
1605
else
1606
cupsdLogJob(job, CUPSD_LOG_DEBUG,
1607
"PID %d (%s) stopped with status %d.", pid, name, code);
1608
}
1609
else
1610
cupsdLogJob(job, CUPSD_LOG_DEBUG, "PID %d (%s) crashed on signal %d.",
1611
pid, name, WTERMSIG(status));
1612
1613
if (LogLevel < CUPSD_LOG_DEBUG)
1614
cupsdLogJob(job, CUPSD_LOG_INFO,
1615
"Hint: Try setting the LogLevel to \"debug\" to find out "
1616
"more.");
1617
}
1618
else
1619
cupsdLogJob(job, CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.",
1620
pid, name);
1621
}
1622
1623
/*
1624
* If wait*() is interrupted by a signal, tell main() to call us again...
1625
*/
1626
1627
if (pid && errno == EINTR)
1628
dead_children = 1;
1629
}
1630
1631
1632
/*
1633
* 'select_timeout()' - Calculate the select timeout value.
1634
*
1635
*/
1636
1637
static long /* O - Number of seconds */
1638
select_timeout(int fds) /* I - Number of descriptors returned */
1639
{
1640
long timeout; /* Timeout for select */
1641
time_t now; /* Current time */
1642
cupsd_client_t *con; /* Client information */
1643
cupsd_job_t *job; /* Job information */
1644
const char *why; /* Debugging aid */
1645
1646
1647
cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout: JobHistoryUpdate=%ld",
1648
(long)JobHistoryUpdate);
1649
1650
/*
1651
* Check to see if any of the clients have pending data to be
1652
* processed; if so, the timeout should be 0...
1653
*/
1654
1655
for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
1656
con;
1657
con = (cupsd_client_t *)cupsArrayNext(Clients))
1658
if (httpGetReady(con->http))
1659
return (0);
1660
1661
/*
1662
* If select has been active in the last second (fds > 0) or we have
1663
* many resources in use then don't bother trying to optimize the
1664
* timeout, just make it 1 second.
1665
*/
1666
1667
if (fds > 0 || cupsArrayCount(Clients) > 50)
1668
return (1);
1669
1670
/*
1671
* Otherwise, check all of the possible events that we need to wake for...
1672
*/
1673
1674
now = time(NULL);
1675
timeout = now + 86400; /* 86400 == 1 day */
1676
why = "do nothing";
1677
1678
#ifdef __APPLE__
1679
/*
1680
* When going to sleep, wake up to abort jobs that don't complete in time.
1681
*/
1682
1683
if (SleepJobs > 0 && SleepJobs < timeout)
1684
{
1685
timeout = SleepJobs;
1686
why = "abort jobs before sleeping";
1687
}
1688
#endif /* __APPLE__ */
1689
1690
/*
1691
* Check whether we are accepting new connections...
1692
*/
1693
1694
if (ListeningPaused > 0 && cupsArrayCount(Clients) < MaxClients &&
1695
ListeningPaused < timeout)
1696
{
1697
if (ListeningPaused <= now)
1698
timeout = now;
1699
else
1700
timeout = ListeningPaused;
1701
1702
why = "resume listening";
1703
}
1704
1705
/*
1706
* Check the activity and close old clients...
1707
*/
1708
1709
for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
1710
con;
1711
con = (cupsd_client_t *)cupsArrayNext(Clients))
1712
if ((httpGetActivity(con->http) + Timeout) < timeout)
1713
{
1714
timeout = httpGetActivity(con->http) + Timeout;
1715
why = "timeout a client connection";
1716
}
1717
1718
/*
1719
* Write out changes to configuration and state files...
1720
*/
1721
1722
if (DirtyCleanTime && timeout > DirtyCleanTime)
1723
{
1724
timeout = DirtyCleanTime;
1725
why = "write dirty config/state files";
1726
}
1727
1728
/*
1729
* Check for any job activity...
1730
*/
1731
if (JobHistoryUpdate && timeout > JobHistoryUpdate)
1732
{
1733
timeout = JobHistoryUpdate;
1734
why = "update job history";
1735
}
1736
1737
for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
1738
job;
1739
job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
1740
{
1741
if (job->cancel_time && job->cancel_time < timeout)
1742
{
1743
timeout = job->cancel_time;
1744
why = "cancel stuck jobs";
1745
}
1746
1747
if (job->kill_time && job->kill_time < timeout)
1748
{
1749
timeout = job->kill_time;
1750
why = "kill unresponsive jobs";
1751
}
1752
1753
if (job->state_value == IPP_JOB_HELD && job->hold_until < timeout)
1754
{
1755
timeout = job->hold_until;
1756
why = "release held jobs";
1757
}
1758
1759
if (job->state_value == IPP_JOB_PENDING && timeout > (now + 10))
1760
{
1761
timeout = now + 10;
1762
why = "start pending jobs";
1763
break;
1764
}
1765
}
1766
1767
/*
1768
* Adjust from absolute to relative time. We add 1 second to the timeout since
1769
* events occur after the timeout expires, and limit the timeout to 86400
1770
* seconds (1 day) to avoid select() timeout limits present on some operating
1771
* systems...
1772
*/
1773
1774
timeout = timeout - now + 1;
1775
1776
if (timeout < 1)
1777
timeout = 1;
1778
else if (timeout > 86400)
1779
timeout = 86400;
1780
1781
/*
1782
* Log and return the timeout value...
1783
*/
1784
1785
cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout(%d): %ld seconds to %s",
1786
fds, timeout, why);
1787
1788
return (timeout);
1789
}
1790
1791
1792
/*
1793
* 'sigchld_handler()' - Handle 'child' signals from old processes.
1794
*/
1795
1796
static void
1797
sigchld_handler(int sig) /* I - Signal number */
1798
{
1799
(void)sig;
1800
1801
/*
1802
* Flag that we have dead children...
1803
*/
1804
1805
dead_children = 1;
1806
1807
/*
1808
* Reset the signal handler as needed...
1809
*/
1810
1811
#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1812
signal(SIGCLD, sigchld_handler);
1813
#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1814
}
1815
1816
1817
/*
1818
* 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler.
1819
*/
1820
1821
static void
1822
sighup_handler(int sig) /* I - Signal number */
1823
{
1824
(void)sig;
1825
1826
NeedReload = RELOAD_ALL;
1827
ReloadTime = time(NULL);
1828
1829
#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1830
signal(SIGHUP, sighup_handler);
1831
#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1832
}
1833
1834
1835
/*
1836
* 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler.
1837
*/
1838
1839
static void
1840
sigterm_handler(int sig) /* I - Signal number */
1841
{
1842
(void)sig; /* remove compiler warnings... */
1843
1844
/*
1845
* Flag that we should stop and return...
1846
*/
1847
1848
stop_scheduler = 1;
1849
}
1850
1851
1852
#ifdef HAVE_ONDEMAND
1853
/*
1854
* 'service_add_listener()' - Bind an open fd as a Listener.
1855
*/
1856
1857
static void
1858
service_add_listener(int fd, /* I - Socket file descriptor */
1859
int idx) /* I - Listener number, for logging */
1860
{
1861
cupsd_listener_t *lis; /* Listeners array */
1862
http_addr_t addr; /* Address variable */
1863
socklen_t addrlen; /* Length of address */
1864
char s[256]; /* String address */
1865
1866
1867
addrlen = sizeof(addr);
1868
1869
if (getsockname(fd, (struct sockaddr *)&addr, &addrlen))
1870
{
1871
cupsdLogMessage(CUPSD_LOG_ERROR, "service_add_listener: Unable to get local address for listener #%d: %s", idx + 1, strerror(errno));
1872
return;
1873
}
1874
1875
cupsdLogMessage(CUPSD_LOG_DEBUG, "service_add_listener: Listener #%d at fd %d, \"%s\".", idx + 1, fd, httpAddrString(&addr, s, sizeof(s)));
1876
1877
/*
1878
* Try to match the on-demand socket address to one of the listeners...
1879
*/
1880
1881
for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
1882
lis;
1883
lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
1884
if (httpAddrEqual(&lis->address, &addr))
1885
break;
1886
1887
/*
1888
* Add a new listener If there's no match...
1889
*/
1890
1891
if (lis)
1892
{
1893
cupsdLogMessage(CUPSD_LOG_DEBUG, "service_add_listener: Matched existing listener #%d to %s.", idx + 1, httpAddrString(&(lis->address), s, sizeof(s)));
1894
}
1895
else
1896
{
1897
cupsdLogMessage(CUPSD_LOG_DEBUG, "service_add_listener: Adding new listener #%d for %s.", idx + 1, httpAddrString(&addr, s, sizeof(s)));
1898
1899
if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
1900
{
1901
cupsdLogMessage(CUPSD_LOG_ERROR, "service_add_listener: Unable to allocate listener: %s.", strerror(errno));
1902
exit(EXIT_FAILURE);
1903
}
1904
1905
cupsArrayAdd(Listeners, lis);
1906
1907
memcpy(&lis->address, &addr, sizeof(lis->address));
1908
}
1909
1910
lis->fd = fd;
1911
lis->on_demand = 1;
1912
1913
# ifdef HAVE_TLS
1914
if (httpAddrPort(&(lis->address)) == 443)
1915
lis->encryption = HTTP_ENCRYPT_ALWAYS;
1916
# endif /* HAVE_TLS */
1917
}
1918
#endif /* HAVE_ONDEMAND */
1919
1920
1921
/*
1922
* 'service_checkin()' - Check-in with launchd and collect the listening fds.
1923
*/
1924
1925
static void
1926
service_checkin(void)
1927
{
1928
cupsdLogMessage(CUPSD_LOG_DEBUG, "service_checkin: pid=%d", (int)getpid());
1929
1930
#ifdef HAVE_LAUNCHD
1931
if (OnDemand)
1932
{
1933
int error; /* Check-in error, if any */
1934
size_t i, /* Looping var */
1935
count; /* Number of listeners */
1936
int *ld_sockets; /* Listener sockets */
1937
1938
# ifdef __APPLE__
1939
/*
1940
* Force "user initiated" priority for the main thread...
1941
*/
1942
1943
pthread_set_qos_class_self_np(QOS_CLASS_USER_INITIATED, 0);
1944
# endif /* __APPLE__ */
1945
1946
/*
1947
* Check-in with launchd...
1948
*/
1949
1950
if ((error = launch_activate_socket("Listeners", &ld_sockets, &count)) != 0)
1951
{
1952
cupsdLogMessage(CUPSD_LOG_ERROR, "service_checkin: Unable to get listener sockets: %s", strerror(error));
1953
exit(EXIT_FAILURE);
1954
}
1955
1956
/*
1957
* Try to match the launchd sockets to the cupsd listeners...
1958
*/
1959
1960
cupsdLogMessage(CUPSD_LOG_DEBUG, "service_checkin: %d listeners.", (int)count);
1961
1962
for (i = 0; i < count; i ++)
1963
service_add_listener(ld_sockets[i], (int)i);
1964
1965
free(ld_sockets);
1966
1967
# ifdef __APPLE__
1968
xpc_transaction_begin();
1969
# endif /* __APPLE__ */
1970
}
1971
1972
#elif defined(HAVE_SYSTEMD)
1973
if (OnDemand)
1974
{
1975
int i, /* Looping var */
1976
count; /* Number of listeners */
1977
1978
/*
1979
* Check-in with systemd...
1980
*/
1981
1982
if ((count = sd_listen_fds(0)) < 0)
1983
{
1984
cupsdLogMessage(CUPSD_LOG_ERROR, "service_checkin: Unable to get listener sockets: %s", strerror(-count));
1985
exit(EXIT_FAILURE);
1986
}
1987
1988
/*
1989
* Try to match the systemd sockets to the cupsd listeners...
1990
*/
1991
1992
cupsdLogMessage(CUPSD_LOG_DEBUG, "service_checkin: %d listeners.", count);
1993
1994
for (i = 0; i < count; i ++)
1995
service_add_listener(SD_LISTEN_FDS_START + i, i);
1996
}
1997
1998
#elif defined(HAVE_UPSTART)
1999
if (OnDemand)
2000
{
2001
const char *e; /* Environment var */
2002
int fd; /* File descriptor */
2003
2004
2005
if (!(e = getenv("UPSTART_EVENTS")))
2006
{
2007
cupsdLogMessage(CUPSD_LOG_ERROR, "service_checkin: We did not get started via Upstart.");
2008
exit(EXIT_FAILURE);
2009
}
2010
2011
if (strcasecmp(e, "socket"))
2012
{
2013
cupsdLogMessage(CUPSD_LOG_ERROR, "service_checkin: We did not get triggered via an Upstart socket event.");
2014
exit(EXIT_FAILURE);
2015
}
2016
2017
if ((e = getenv("UPSTART_FDS")) == NULL)
2018
{
2019
cupsdLogMessage(CUPSD_LOG_ERROR, "service_checkin: Unable to get listener sockets from UPSTART_FDS.");
2020
exit(EXIT_FAILURE);
2021
}
2022
2023
cupsdLogMessage(CUPSD_LOG_DEBUG, "service_checkin: UPSTART_FDS=%s", e);
2024
2025
fd = atoi(e);
2026
if (fd < 0)
2027
{
2028
cupsdLogMessage(CUPSD_LOG_ERROR, "service_checkin: Could not parse UPSTART_FDS: %s", strerror(errno));
2029
exit(EXIT_FAILURE);
2030
}
2031
2032
/*
2033
* Upstart only supports a single on-demand socket file descriptor...
2034
*/
2035
2036
service_add_listener(fd, 0);
2037
}
2038
#endif /* HAVE_LAUNCHD */
2039
}
2040
2041
2042
/*
2043
* 'service_checkout()' - Update the KeepAlive/PID file as needed.
2044
*/
2045
2046
static void
2047
service_checkout(int shutdown) /* I - Shutting down? */
2048
{
2049
cups_file_t *fp; /* File */
2050
char pidfile[1024]; /* PID/KeepAlive file */
2051
2052
2053
/*
2054
* When running on-demand, use the KeepAlive file, otherwise write a PID file
2055
* to StateDir...
2056
*/
2057
2058
#ifdef HAVE_ONDEMAND
2059
if (OnDemand)
2060
{
2061
int shared_printers = 0; /* Do we have shared printers? */
2062
2063
strlcpy(pidfile, CUPS_KEEPALIVE, sizeof(pidfile));
2064
2065
/*
2066
* If printer sharing is on see if there are any actual shared printers...
2067
*/
2068
2069
if (Browsing && BrowseLocalProtocols)
2070
{
2071
cupsd_printer_t *p = NULL; /* Current printer */
2072
2073
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers))
2074
{
2075
if (p->shared)
2076
break;
2077
}
2078
2079
shared_printers = (p != NULL);
2080
}
2081
2082
if (cupsArrayCount(ActiveJobs) || /* Active jobs */
2083
WebInterface || /* Web interface enabled */
2084
NeedReload || /* Doing a reload */
2085
shared_printers) /* Printers being shared */
2086
{
2087
/*
2088
* Create or remove the "keep-alive" file based on whether there are active
2089
* jobs or shared printers to advertise...
2090
*/
2091
2092
shutdown = 0;
2093
}
2094
}
2095
else
2096
#endif /* HAVE_ONDEMAND */
2097
snprintf(pidfile, sizeof(pidfile), "%s/cupsd.pid", StateDir);
2098
2099
if (shutdown)
2100
{
2101
cupsdLogMessage(CUPSD_LOG_DEBUG, "Removing KeepAlive/PID file \"%s\".", pidfile);
2102
2103
unlink(pidfile);
2104
}
2105
else
2106
{
2107
cupsdLogMessage(CUPSD_LOG_DEBUG, "Creating KeepAlive/PID file \"%s\".", pidfile);
2108
2109
if ((fp = cupsFileOpen(pidfile, "w")) != NULL)
2110
{
2111
/*
2112
* Save the PID in the file...
2113
*/
2114
2115
cupsFilePrintf(fp, "%d\n", (int)getpid());
2116
cupsFileClose(fp);
2117
}
2118
else
2119
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create KeepAlive/PID file \"%s\": %s", pidfile, strerror(errno));
2120
}
2121
2122
# ifdef __APPLE__
2123
if (OnDemand && shutdown)
2124
xpc_transaction_end();
2125
# endif /* __APPLE__ */
2126
}
2127
2128
2129
/*
2130
* 'usage()' - Show scheduler usage.
2131
*/
2132
2133
static void
2134
usage(int status) /* O - Exit status */
2135
{
2136
FILE *fp = status ? stderr : stdout; /* Output file */
2137
2138
2139
_cupsLangPuts(fp, _("Usage: cupsd [options]"));
2140
_cupsLangPuts(fp, _("Options:"));
2141
_cupsLangPuts(fp, _("-c cupsd.conf Set cupsd.conf file to use."));
2142
_cupsLangPuts(fp, _("-f Run in the foreground."));
2143
_cupsLangPuts(fp, _("-F Run in the foreground but detach from console."));
2144
_cupsLangPuts(fp, _("-h Show this usage message."));
2145
#ifdef HAVE_ONDEMAND
2146
_cupsLangPuts(fp, _("-l Run cupsd on demand."));
2147
#endif /* HAVE_ONDEMAND */
2148
_cupsLangPuts(fp, _("-s cups-files.conf Set cups-files.conf file to use."));
2149
_cupsLangPuts(fp, _("-t Test the configuration file."));
2150
2151
exit(status);
2152
}
2153
2154