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