2 * System management functions for the CUPS scheduler.
4 * Copyright 2007-2018 by Apple Inc.
5 * Copyright 2006 by Easy Software Products.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
12 * Include necessary headers...
17 # include <IOKit/pwr_mgt/IOPMLib.h>
18 #endif /* __APPLE__ */
22 * The system management functions cover disk and power management which
23 * are primarily used for portable computers.
25 * Disk management involves delaying the write of certain configuration
26 * and state files to minimize the number of times the disk has to spin
27 * up or flash to be written to.
29 * Power management support is currently only implemented on macOS, but
30 * essentially we use four functions to let the OS know when it is OK to
31 * put the system to sleep, typically when we are not in the middle of
32 * printing a job. And on macOS we can also "sleep print" - basically the
33 * system only wakes up long enough to service network requests and process
39 * 'cupsdCleanDirty()' - Write dirty config and state files.
45 if (DirtyFiles & CUPSD_DIRTY_PRINTERS)
46 cupsdSaveAllPrinters();
48 if (DirtyFiles & CUPSD_DIRTY_CLASSES)
49 cupsdSaveAllClasses();
51 if (DirtyFiles & CUPSD_DIRTY_PRINTCAP)
54 if (DirtyFiles & CUPSD_DIRTY_JOBS)
56 cupsd_job_t *job; /* Current job */
60 for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
62 job = (cupsd_job_t *)cupsArrayNext(Jobs))
67 if (DirtyFiles & CUPSD_DIRTY_SUBSCRIPTIONS)
68 cupsdSaveAllSubscriptions();
70 DirtyFiles = CUPSD_DIRTY_NONE;
78 * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
82 cupsdMarkDirty(int what) /* I - What file(s) are dirty? */
84 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdMarkDirty(%c%c%c%c%c)",
85 (what & CUPSD_DIRTY_PRINTERS) ? 'P' : '-',
86 (what & CUPSD_DIRTY_CLASSES) ? 'C' : '-',
87 (what & CUPSD_DIRTY_PRINTCAP) ? 'p' : '-',
88 (what & CUPSD_DIRTY_JOBS) ? 'J' : '-',
89 (what & CUPSD_DIRTY_SUBSCRIPTIONS) ? 'S' : '-');
91 if (what == CUPSD_DIRTY_PRINTCAP && !Printcap)
97 DirtyCleanTime = time(NULL) + DirtyCleanInterval;
104 * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
108 cupsdSetBusyState(int working) /* I - Doing significant work? */
110 int i; /* Looping var */
111 cupsd_job_t *job; /* Current job */
112 cupsd_printer_t *p; /* Current printer */
113 int newbusy; /* New busy state */
114 static int busy = 0; /* Current busy state */
115 static const char * const busy_text[] =
116 { /* Text for busy states */
120 "Printing jobs and dirty files",
122 "Active clients and dirty files",
123 "Active clients and printing jobs",
124 "Active clients, printing jobs, and dirty files"
127 static IOPMAssertionID keep_awake = 0;/* Keep the system awake while printing */
128 #endif /* __APPLE__ */
132 * Figure out how busy we are...
135 newbusy = (DirtyCleanTime ? 1 : 0) |
136 ((working || cupsArrayCount(ActiveClients) > 0) ? 4 : 0);
138 for (job = (cupsd_job_t *)cupsArrayFirst(PrintingJobs);
140 job = (cupsd_job_t *)cupsArrayNext(PrintingJobs))
142 if ((p = job->printer) != NULL)
144 for (i = 0; i < p->num_reasons; i ++)
145 if (!strcmp(p->reasons[i], "connecting-to-device"))
148 if (!p->num_reasons || i >= p->num_reasons)
156 cupsdLogMessage(CUPSD_LOG_DEBUG,
157 "cupsdSetBusyState: newbusy=\"%s\", busy=\"%s\"",
158 busy_text[newbusy], busy_text[busy]);
161 * Manage state changes...
168 if (cupsArrayCount(PrintingJobs) > 0 && !keep_awake)
170 cupsdLogMessage(CUPSD_LOG_DEBUG, "Asserting NetworkClientActive.");
172 IOPMAssertionCreateWithName(kIOPMAssertNetworkClientActive,
173 kIOPMAssertionLevelOn,
174 CFSTR("org.cups.cupsd"), &keep_awake);
176 else if (cupsArrayCount(PrintingJobs) == 0 && keep_awake)
178 cupsdLogMessage(CUPSD_LOG_DEBUG, "Releasing power assertion.");
179 IOPMAssertionRelease(keep_awake);
182 #endif /* __APPLE__ */
188 * This is the Apple-specific system event code. It works by creating
189 * a worker thread that waits for events from the OS and relays them
190 * to the main thread via a traditional pipe.
194 * Include MacOS-specific headers...
198 # include <IOKit/IOKitLib.h>
199 # include <IOKit/IOMessage.h>
200 # include <IOKit/ps/IOPowerSources.h>
201 # include <IOKit/pwr_mgt/IOPMLib.h>
202 # include <SystemConfiguration/SystemConfiguration.h>
203 # include <pthread.h>
210 # define SYSEVENT_CANSLEEP 0x1 /* Decide whether to allow sleep or not */
211 # define SYSEVENT_WILLSLEEP 0x2 /* Computer will go to sleep */
212 # define SYSEVENT_WOKE 0x4 /* Computer woke from sleep */
213 # define SYSEVENT_NETCHANGED 0x8 /* Network changed */
214 # define SYSEVENT_NAMECHANGED 0x10 /* Computer name changed */
221 typedef struct cupsd_sysevent_s /*** System event data ****/
223 unsigned char event; /* Event bit field */
224 io_connect_t powerKernelPort; /* Power context data */
225 long powerNotificationID; /* Power event data */
229 typedef struct cupsd_thread_data_s /*** Thread context data ****/
231 cupsd_sysevent_t sysevent; /* System event */
232 CFRunLoopTimerRef timerRef; /* Timer to delay some change *
234 } cupsd_thread_data_t;
241 static pthread_t SysEventThread = NULL;
242 /* Thread to host a runloop */
243 static pthread_mutex_t SysEventThreadMutex = { 0 };
244 /* Coordinates access to shared gloabals */
245 static pthread_cond_t SysEventThreadCond = { 0 };
246 /* Thread initialization complete condition */
247 static CFRunLoopRef SysEventRunloop = NULL;
248 /* The runloop. Access must be protected! */
249 static CFStringRef ComputerNameKey = NULL,
250 /* Computer name key */
251 BTMMKey = NULL, /* Back to My Mac key */
252 NetworkGlobalKeyIPv4 = NULL,
253 /* Network global IPv4 key */
254 NetworkGlobalKeyIPv6 = NULL,
255 /* Network global IPv6 key */
256 NetworkGlobalKeyDNS = NULL,
257 /* Network global DNS key */
260 NetworkInterfaceKeyIPv4 = NULL,
261 /* Netowrk interface key */
262 NetworkInterfaceKeyIPv6 = NULL;
263 /* Netowrk interface key */
264 static cupsd_sysevent_t LastSysEvent; /* Last system event (for delayed sleep) */
265 static int NameChanged = 0;/* Did we get a 'name changed' event during sleep? */
266 static int PSToken = 0; /* Power source notifications */
273 static void *sysEventThreadEntry(void);
274 static void sysEventPowerNotifier(void *context, io_service_t service,
275 natural_t messageType,
276 void *messageArgument);
277 static void sysEventConfigurationNotifier(SCDynamicStoreRef store,
278 CFArrayRef changedKeys,
280 static void sysEventTimerNotifier(CFRunLoopTimerRef timer, void *context);
281 static void sysUpdate(void);
282 static void sysUpdateNames(void);
286 * 'cupsdAllowSleep()' - Tell the OS it is now OK to sleep.
290 cupsdAllowSleep(void)
294 cupsdLogMessage(CUPSD_LOG_DEBUG, "Allowing system sleep.");
295 IOAllowPowerChange(LastSysEvent.powerKernelPort,
296 LastSysEvent.powerNotificationID);
301 * 'cupsdStartSystemMonitor()' - Start monitoring for system change.
305 cupsdStartSystemMonitor(void)
307 int flags; /* fcntl flags on pipe */
310 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartSystemMonitor()");
312 if (cupsdOpenPipe(SysEventPipes))
314 cupsdLogMessage(CUPSD_LOG_ERROR, "System event monitor pipe() failed - %s!",
319 cupsdAddSelect(SysEventPipes[0], (cupsd_selfunc_t)sysUpdate, NULL, NULL);
322 * Set non-blocking mode on the descriptor we will be receiving notification
326 flags = fcntl(SysEventPipes[0], F_GETFL, 0);
327 fcntl(SysEventPipes[0], F_SETFL, flags | O_NONBLOCK);
330 * Start the thread that runs the runloop...
333 pthread_mutex_init(&SysEventThreadMutex, NULL);
334 pthread_cond_init(&SysEventThreadCond, NULL);
335 pthread_create(&SysEventThread, NULL, (void *(*)(void *))sysEventThreadEntry, NULL);
338 * Monitor for power source changes via dispatch queue...
341 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartSystemMonitor: IOPSGetTimeRemainingEstimate=%f", IOPSGetTimeRemainingEstimate());
342 ACPower = IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited;
343 notify_register_dispatch(kIOPSNotifyPowerSource, &PSToken, dispatch_get_main_queue(), ^(int t) { (void)t;
344 ACPower = IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited; });
349 * 'cupsdStopSystemMonitor()' - Stop monitoring for system change.
353 cupsdStopSystemMonitor(void)
355 CFRunLoopRef rl; /* The event handler runloop */
358 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStopSystemMonitor()");
363 * Make sure the thread has completed it's initialization and
364 * stored it's runloop reference in the shared global.
367 pthread_mutex_lock(&SysEventThreadMutex);
369 if (!SysEventRunloop)
370 pthread_cond_wait(&SysEventThreadCond, &SysEventThreadMutex);
372 rl = SysEventRunloop;
373 SysEventRunloop = NULL;
375 pthread_mutex_unlock(&SysEventThreadMutex);
380 pthread_join(SysEventThread, NULL);
381 pthread_mutex_destroy(&SysEventThreadMutex);
382 pthread_cond_destroy(&SysEventThreadCond);
385 if (SysEventPipes[0] >= 0)
387 cupsdRemoveSelect(SysEventPipes[0]);
388 cupsdClosePipe(SysEventPipes);
393 notify_cancel(PSToken);
400 * 'sysEventThreadEntry()' - A thread to receive power and computer name
401 * change notifications.
404 static void * /* O - Return status/value */
405 sysEventThreadEntry(void)
407 io_object_t powerNotifierObj;
408 /* Power notifier object */
409 IONotificationPortRef powerNotifierPort;
410 /* Power notifier port */
411 SCDynamicStoreRef store = NULL;/* System Config dynamic store */
412 CFRunLoopSourceRef powerRLS = NULL,/* Power runloop source */
413 storeRLS = NULL;/* System Config runloop source */
414 CFStringRef key[6], /* System Config keys */
415 pattern[2]; /* System Config patterns */
416 CFArrayRef keys = NULL, /* System Config key array*/
417 patterns = NULL;/* System Config pattern array */
418 SCDynamicStoreContext storeContext; /* Dynamic store context */
419 CFRunLoopTimerContext timerContext; /* Timer context */
420 cupsd_thread_data_t threadData; /* Thread context data for the *
421 * runloop notifiers */
425 * Register for power state change notifications
428 bzero(&threadData, sizeof(threadData));
430 threadData.sysevent.powerKernelPort =
431 IORegisterForSystemPower(&threadData, &powerNotifierPort,
432 sysEventPowerNotifier, &powerNotifierObj);
434 if (threadData.sysevent.powerKernelPort)
436 powerRLS = IONotificationPortGetRunLoopSource(powerNotifierPort);
437 CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRLS, kCFRunLoopDefaultMode);
441 * Register for system configuration change notifications
444 bzero(&storeContext, sizeof(storeContext));
445 storeContext.info = &threadData;
447 store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"),
448 sysEventConfigurationNotifier, &storeContext);
450 if (!ComputerNameKey)
451 ComputerNameKey = SCDynamicStoreKeyCreateComputerName(kCFAllocatorDefault);
454 BTMMKey = SCDynamicStoreKeyCreate(kCFAllocatorDefault,
455 CFSTR("Setup:/Network/BackToMyMac"));
457 if (!NetworkGlobalKeyIPv4)
458 NetworkGlobalKeyIPv4 =
459 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault,
460 kSCDynamicStoreDomainState,
463 if (!NetworkGlobalKeyIPv6)
464 NetworkGlobalKeyIPv6 =
465 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault,
466 kSCDynamicStoreDomainState,
469 if (!NetworkGlobalKeyDNS)
470 NetworkGlobalKeyDNS =
471 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault,
472 kSCDynamicStoreDomainState,
476 HostNamesKey = SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault);
478 if (!NetworkInterfaceKeyIPv4)
479 NetworkInterfaceKeyIPv4 =
480 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault,
481 kSCDynamicStoreDomainState,
485 if (!NetworkInterfaceKeyIPv6)
486 NetworkInterfaceKeyIPv6 =
487 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault,
488 kSCDynamicStoreDomainState,
492 if (store && ComputerNameKey && HostNamesKey &&
493 NetworkGlobalKeyIPv4 && NetworkGlobalKeyIPv6 && NetworkGlobalKeyDNS &&
494 NetworkInterfaceKeyIPv4 && NetworkInterfaceKeyIPv6)
496 key[0] = ComputerNameKey;
498 key[2] = NetworkGlobalKeyIPv4;
499 key[3] = NetworkGlobalKeyIPv6;
500 key[4] = NetworkGlobalKeyDNS;
501 key[5] = HostNamesKey;
503 pattern[0] = NetworkInterfaceKeyIPv4;
504 pattern[1] = NetworkInterfaceKeyIPv6;
506 keys = CFArrayCreate(kCFAllocatorDefault, (const void **)key,
507 sizeof(key) / sizeof(key[0]),
508 &kCFTypeArrayCallBacks);
510 patterns = CFArrayCreate(kCFAllocatorDefault, (const void **)pattern,
511 sizeof(pattern) / sizeof(pattern[0]),
512 &kCFTypeArrayCallBacks);
514 if (keys && patterns &&
515 SCDynamicStoreSetNotificationKeys(store, keys, patterns))
517 if ((storeRLS = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault,
520 CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS,
521 kCFRunLoopDefaultMode);
533 * Set up a timer to delay the wake change notifications.
535 * The initial time is set a decade or so into the future, we'll adjust
539 bzero(&timerContext, sizeof(timerContext));
540 timerContext.info = &threadData;
542 threadData.timerRef =
543 CFRunLoopTimerCreate(kCFAllocatorDefault,
544 CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
545 86400L * 365L * 10L, 0, 0, sysEventTimerNotifier,
547 CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData.timerRef,
548 kCFRunLoopDefaultMode);
551 * Store our runloop in a global so the main thread can use it to stop us.
554 pthread_mutex_lock(&SysEventThreadMutex);
556 SysEventRunloop = CFRunLoopGetCurrent();
558 pthread_cond_signal(&SysEventThreadCond);
559 pthread_mutex_unlock(&SysEventThreadMutex);
562 * Disappear into the runloop until it's stopped by the main thread.
568 * Clean up before exiting.
571 if (threadData.timerRef)
573 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData.timerRef,
574 kCFRunLoopDefaultMode);
575 CFRelease(threadData.timerRef);
578 if (threadData.sysevent.powerKernelPort)
580 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS,
581 kCFRunLoopDefaultMode);
582 IODeregisterForSystemPower(&powerNotifierObj);
583 IOServiceClose(threadData.sysevent.powerKernelPort);
584 IONotificationPortDestroy(powerNotifierPort);
589 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS,
590 kCFRunLoopDefaultMode);
591 CFRunLoopSourceInvalidate(storeRLS);
603 * 'sysEventPowerNotifier()' - Handle power notification events.
607 sysEventPowerNotifier(
608 void *context, /* I - Thread context data */
609 io_service_t service, /* I - Unused service info */
610 natural_t messageType, /* I - Type of message */
611 void *messageArgument) /* I - Message data */
613 int sendit = 1; /* Send event to main thread? *
614 * (0 = no, 1 = yes, 2 = delayed */
615 cupsd_thread_data_t *threadData; /* Thread context data */
618 threadData = (cupsd_thread_data_t *)context;
620 (void)service; /* anti-compiler-warning-code */
624 case kIOMessageCanSystemPowerOff :
625 case kIOMessageCanSystemSleep :
626 threadData->sysevent.event |= SYSEVENT_CANSLEEP;
629 case kIOMessageSystemWillRestart :
630 case kIOMessageSystemWillPowerOff :
631 case kIOMessageSystemWillSleep :
632 threadData->sysevent.event |= SYSEVENT_WILLSLEEP;
633 threadData->sysevent.event &= ~SYSEVENT_WOKE;
636 case kIOMessageSystemHasPoweredOn :
638 * Because powered on is followed by a net-changed event, delay
643 threadData->sysevent.event |= SYSEVENT_WOKE;
646 case kIOMessageSystemWillNotPowerOff :
647 case kIOMessageSystemWillNotSleep :
648 # ifdef kIOMessageSystemWillPowerOn
649 case kIOMessageSystemWillPowerOn :
650 # endif /* kIOMessageSystemWillPowerOn */
658 case kIOMessageCanSystemPowerOff :
659 cupsdLogMessage(CUPSD_LOG_DEBUG,
660 "Got kIOMessageCanSystemPowerOff message.");
662 case kIOMessageCanSystemSleep :
663 cupsdLogMessage(CUPSD_LOG_DEBUG,
664 "Got kIOMessageCannSystemSleep message.");
666 case kIOMessageSystemWillRestart :
667 cupsdLogMessage(CUPSD_LOG_DEBUG,
668 "Got kIOMessageSystemWillRestart message.");
670 case kIOMessageSystemWillPowerOff :
671 cupsdLogMessage(CUPSD_LOG_DEBUG,
672 "Got kIOMessageSystemWillPowerOff message.");
674 case kIOMessageSystemWillSleep :
675 cupsdLogMessage(CUPSD_LOG_DEBUG,
676 "Got kIOMessageSystemWillSleep message.");
678 case kIOMessageSystemHasPoweredOn :
679 cupsdLogMessage(CUPSD_LOG_DEBUG,
680 "Got kIOMessageSystemHasPoweredOn message.");
682 case kIOMessageSystemWillNotPowerOff :
683 cupsdLogMessage(CUPSD_LOG_DEBUG,
684 "Got kIOMessageSystemWillNotPowerOff message.");
686 case kIOMessageSystemWillNotSleep :
687 cupsdLogMessage(CUPSD_LOG_DEBUG,
688 "Got kIOMessageSystemWillNotSleep message.");
690 # ifdef kIOMessageSystemWillPowerOn
691 case kIOMessageSystemWillPowerOn :
692 cupsdLogMessage(CUPSD_LOG_DEBUG,
693 "Got kIOMessageSystemWillPowerOn message.");
695 # endif /* kIOMessageSystemWillPowerOn */
697 cupsdLogMessage(CUPSD_LOG_DEBUG, "Got unknown power message %d.",
703 IOAllowPowerChange(threadData->sysevent.powerKernelPort,
704 (long)messageArgument);
707 threadData->sysevent.powerNotificationID = (long)messageArgument;
712 * Send the event to the main thread now.
715 write(SysEventPipes[1], &threadData->sysevent,
716 sizeof(threadData->sysevent));
717 threadData->sysevent.event = 0;
722 * Send the event to the main thread after 1 to 2 seconds.
725 CFRunLoopTimerSetNextFireDate(threadData->timerRef,
726 CFAbsoluteTimeGetCurrent() + 2);
733 * 'sysEventConfigurationNotifier()' - Network configuration change notification
738 sysEventConfigurationNotifier(
739 SCDynamicStoreRef store, /* I - System data (unused) */
740 CFArrayRef changedKeys, /* I - Changed data */
741 void *context) /* I - Thread context data */
743 cupsd_thread_data_t *threadData; /* Thread context data */
746 threadData = (cupsd_thread_data_t *)context;
748 (void)store; /* anti-compiler-warning-code */
750 CFRange range = CFRangeMake(0, CFArrayGetCount(changedKeys));
752 if (CFArrayContainsValue(changedKeys, range, ComputerNameKey) ||
753 CFArrayContainsValue(changedKeys, range, BTMMKey))
754 threadData->sysevent.event |= SYSEVENT_NAMECHANGED;
757 threadData->sysevent.event |= SYSEVENT_NETCHANGED;
760 * Indicate the network interface list needs updating...
767 * Because we registered for several different kinds of change notifications
768 * this callback usually gets called several times in a row. We use a timer to
769 * de-bounce these so we only end up generating one event for the main thread.
772 CFRunLoopTimerSetNextFireDate(threadData->timerRef,
773 CFAbsoluteTimeGetCurrent() + 5);
778 * 'sysEventTimerNotifier()' - Handle delayed event notifications.
782 sysEventTimerNotifier(
783 CFRunLoopTimerRef timer, /* I - Timer information */
784 void *context) /* I - Thread context data */
786 cupsd_thread_data_t *threadData; /* Thread context data */
791 threadData = (cupsd_thread_data_t *)context;
794 * If an event is still pending send it to the main thread.
797 if (threadData->sysevent.event)
799 write(SysEventPipes[1], &threadData->sysevent,
800 sizeof(threadData->sysevent));
801 threadData->sysevent.event = 0;
807 * 'sysUpdate()' - Update the current system state.
813 int i; /* Looping var */
814 cupsd_sysevent_t sysevent; /* The system event */
815 cupsd_printer_t *p; /* Printer information */
819 * Drain the event pipe...
822 while (read((int)SysEventPipes[0], &sysevent, sizeof(sysevent))
825 if (sysevent.event & SYSEVENT_CANSLEEP)
828 * If there are active printers that don't have the connecting-to-device
829 * or cups-waiting-for-job-completed printer-state-reason then cancel the
830 * sleep request, i.e., these reasons indicate a job that is not actively
834 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
836 p = (cupsd_printer_t *)cupsArrayNext(Printers))
840 for (i = 0; i < p->num_reasons; i ++)
841 if (!strcmp(p->reasons[i], "connecting-to-device") ||
842 !strcmp(p->reasons[i], "cups-waiting-for-job-completed"))
845 if (!p->num_reasons || i >= p->num_reasons)
852 cupsdLogMessage(CUPSD_LOG_INFO,
853 "System sleep canceled because printer %s is active.",
855 IOCancelPowerChange(sysevent.powerKernelPort,
856 sysevent.powerNotificationID);
860 cupsdLogMessage(CUPSD_LOG_DEBUG, "System wants to sleep.");
861 IOAllowPowerChange(sysevent.powerKernelPort,
862 sysevent.powerNotificationID);
866 if (sysevent.event & SYSEVENT_WILLSLEEP)
868 cupsdLogMessage(CUPSD_LOG_DEBUG, "System going to sleep.");
875 * If we have no printing jobs, allow the power change immediately.
876 * Otherwise set the SleepJobs time to 10 seconds in the future when
877 * we'll take more drastic measures...
880 if (cupsArrayCount(PrintingJobs) == 0)
882 cupsdLogMessage(CUPSD_LOG_DEBUG, "Allowing system sleep.");
883 IOAllowPowerChange(sysevent.powerKernelPort,
884 sysevent.powerNotificationID);
889 * If there are active printers that don't have the connecting-to-device
890 * or cups-waiting-for-job-completed printer-state-reasons then delay the
891 * sleep request, i.e., these reasons indicate a job is active...
894 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
896 p = (cupsd_printer_t *)cupsArrayNext(Printers))
900 for (i = 0; i < p->num_reasons; i ++)
901 if (!strcmp(p->reasons[i], "connecting-to-device") ||
902 !strcmp(p->reasons[i], "cups-waiting-for-job-completed"))
905 if (!p->num_reasons || i >= p->num_reasons)
912 cupsdLogMessage(CUPSD_LOG_INFO,
913 "System sleep delayed because printer %s is active.",
916 LastSysEvent = sysevent;
917 SleepJobs = time(NULL) + 10;
921 cupsdLogMessage(CUPSD_LOG_DEBUG, "Allowing system sleep.");
922 IOAllowPowerChange(sysevent.powerKernelPort,
923 sysevent.powerNotificationID);
928 if (sysevent.event & SYSEVENT_WOKE)
930 cupsdLogMessage(CUPSD_LOG_DEBUG, "System woke from sleep.");
931 IOAllowPowerChange(sysevent.powerKernelPort,
932 sysevent.powerNotificationID);
936 * Make sure jobs that were queued prior to the system going to sleep don't
937 * get canceled right away...
942 cupsd_job_t *job; /* Current job */
944 for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
946 job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
948 if (job->cancel_time)
950 ipp_attribute_t *cancel_after = ippFindAttribute(job->attrs,
955 job->cancel_time = time(NULL) + ippGetInteger(cancel_after, 0);
957 job->cancel_time = time(NULL) + MaxJobTime;
968 if (sysevent.event & SYSEVENT_NETCHANGED)
971 cupsdLogMessage(CUPSD_LOG_DEBUG,
972 "System network configuration changed - "
973 "ignored while sleeping.");
975 cupsdLogMessage(CUPSD_LOG_DEBUG,
976 "System network configuration changed.");
979 if (sysevent.event & SYSEVENT_NAMECHANGED)
985 cupsdLogMessage(CUPSD_LOG_DEBUG,
986 "Computer name or BTMM domains changed - ignored while "
991 cupsdLogMessage(CUPSD_LOG_DEBUG,
992 "Computer name or BTMM domains changed.");
1002 * 'sysUpdateNames()' - Update computer and/or BTMM domains.
1006 sysUpdateNames(void)
1008 cupsd_printer_t *p; /* Current printer */
1014 * De-register the individual printers...
1017 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1019 p = (cupsd_printer_t *)cupsArrayNext(Printers))
1020 cupsdDeregisterPrinter(p, 1);
1022 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1024 * Update the computer name and BTMM domain list...
1027 cupsdUpdateDNSSDName();
1028 # endif /* HAVE_DNSSD || HAVE_AVAHI */
1031 * Now re-register them...
1034 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1036 p = (cupsd_printer_t *)cupsArrayNext(Printers))
1037 cupsdRegisterPrinter(p);
1039 #endif /* __APPLE__ */