2 * System management functions for the CUPS scheduler.
4 * Copyright 2007-2018 by Apple Inc.
5 * Copyright 2006 by Easy Software Products.
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * missing or damaged, see the license at "http://www.cups.org/".
16 * Include necessary headers...
21 # include <IOKit/pwr_mgt/IOPMLib.h>
22 #endif /* __APPLE__ */
26 * The system management functions cover disk and power management which
27 * are primarily used for portable computers.
29 * Disk management involves delaying the write of certain configuration
30 * and state files to minimize the number of times the disk has to spin
31 * up or flash to be written to.
33 * Power management support is currently only implemented on macOS, but
34 * essentially we use four functions to let the OS know when it is OK to
35 * put the system to sleep, typically when we are not in the middle of
36 * printing a job. And on macOS we can also "sleep print" - basically the
37 * system only wakes up long enough to service network requests and process
43 * 'cupsdCleanDirty()' - Write dirty config and state files.
49 if (DirtyFiles
& CUPSD_DIRTY_PRINTERS
)
50 cupsdSaveAllPrinters();
52 if (DirtyFiles
& CUPSD_DIRTY_CLASSES
)
53 cupsdSaveAllClasses();
55 if (DirtyFiles
& CUPSD_DIRTY_PRINTCAP
)
58 if (DirtyFiles
& CUPSD_DIRTY_JOBS
)
60 cupsd_job_t
*job
; /* Current job */
64 for (job
= (cupsd_job_t
*)cupsArrayFirst(Jobs
);
66 job
= (cupsd_job_t
*)cupsArrayNext(Jobs
))
71 if (DirtyFiles
& CUPSD_DIRTY_SUBSCRIPTIONS
)
72 cupsdSaveAllSubscriptions();
74 DirtyFiles
= CUPSD_DIRTY_NONE
;
82 * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
86 cupsdMarkDirty(int what
) /* I - What file(s) are dirty? */
88 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdMarkDirty(%c%c%c%c%c)",
89 (what
& CUPSD_DIRTY_PRINTERS
) ? 'P' : '-',
90 (what
& CUPSD_DIRTY_CLASSES
) ? 'C' : '-',
91 (what
& CUPSD_DIRTY_PRINTCAP
) ? 'p' : '-',
92 (what
& CUPSD_DIRTY_JOBS
) ? 'J' : '-',
93 (what
& CUPSD_DIRTY_SUBSCRIPTIONS
) ? 'S' : '-');
95 if (what
== CUPSD_DIRTY_PRINTCAP
&& !Printcap
)
101 DirtyCleanTime
= time(NULL
) + DirtyCleanInterval
;
103 cupsdSetBusyState(0);
108 * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
112 cupsdSetBusyState(int working
) /* I - Doing significant work? */
114 int i
; /* Looping var */
115 cupsd_job_t
*job
; /* Current job */
116 cupsd_printer_t
*p
; /* Current printer */
117 int newbusy
; /* New busy state */
118 static int busy
= 0; /* Current busy state */
119 static const char * const busy_text
[] =
120 { /* Text for busy states */
124 "Printing jobs and dirty files",
126 "Active clients and dirty files",
127 "Active clients and printing jobs",
128 "Active clients, printing jobs, and dirty files"
131 static IOPMAssertionID keep_awake
= 0;/* Keep the system awake while printing */
132 #endif /* __APPLE__ */
136 * Figure out how busy we are...
139 newbusy
= (DirtyCleanTime
? 1 : 0) |
140 ((working
|| cupsArrayCount(ActiveClients
) > 0) ? 4 : 0);
142 for (job
= (cupsd_job_t
*)cupsArrayFirst(PrintingJobs
);
144 job
= (cupsd_job_t
*)cupsArrayNext(PrintingJobs
))
146 if ((p
= job
->printer
) != NULL
)
148 for (i
= 0; i
< p
->num_reasons
; i
++)
149 if (!strcmp(p
->reasons
[i
], "connecting-to-device"))
152 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
160 cupsdLogMessage(CUPSD_LOG_DEBUG
,
161 "cupsdSetBusyState: newbusy=\"%s\", busy=\"%s\"",
162 busy_text
[newbusy
], busy_text
[busy
]);
165 * Manage state changes...
172 if (cupsArrayCount(PrintingJobs
) > 0 && !keep_awake
)
174 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Asserting NetworkClientActive.");
176 IOPMAssertionCreateWithName(kIOPMAssertNetworkClientActive
,
177 kIOPMAssertionLevelOn
,
178 CFSTR("org.cups.cupsd"), &keep_awake
);
180 else if (cupsArrayCount(PrintingJobs
) == 0 && keep_awake
)
182 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Releasing power assertion.");
183 IOPMAssertionRelease(keep_awake
);
186 #endif /* __APPLE__ */
192 * This is the Apple-specific system event code. It works by creating
193 * a worker thread that waits for events from the OS and relays them
194 * to the main thread via a traditional pipe.
198 * Include MacOS-specific headers...
202 # include <IOKit/IOKitLib.h>
203 # include <IOKit/IOMessage.h>
204 # include <IOKit/ps/IOPowerSources.h>
205 # include <IOKit/pwr_mgt/IOPMLib.h>
206 # include <SystemConfiguration/SystemConfiguration.h>
207 # include <pthread.h>
214 # define SYSEVENT_CANSLEEP 0x1 /* Decide whether to allow sleep or not */
215 # define SYSEVENT_WILLSLEEP 0x2 /* Computer will go to sleep */
216 # define SYSEVENT_WOKE 0x4 /* Computer woke from sleep */
217 # define SYSEVENT_NETCHANGED 0x8 /* Network changed */
218 # define SYSEVENT_NAMECHANGED 0x10 /* Computer name changed */
225 typedef struct cupsd_sysevent_s
/*** System event data ****/
227 unsigned char event
; /* Event bit field */
228 io_connect_t powerKernelPort
; /* Power context data */
229 long powerNotificationID
; /* Power event data */
233 typedef struct cupsd_thread_data_s
/*** Thread context data ****/
235 cupsd_sysevent_t sysevent
; /* System event */
236 CFRunLoopTimerRef timerRef
; /* Timer to delay some change *
238 } cupsd_thread_data_t
;
245 static pthread_t SysEventThread
= NULL
;
246 /* Thread to host a runloop */
247 static pthread_mutex_t SysEventThreadMutex
= { 0 };
248 /* Coordinates access to shared gloabals */
249 static pthread_cond_t SysEventThreadCond
= { 0 };
250 /* Thread initialization complete condition */
251 static CFRunLoopRef SysEventRunloop
= NULL
;
252 /* The runloop. Access must be protected! */
253 static CFStringRef ComputerNameKey
= NULL
,
254 /* Computer name key */
255 BTMMKey
= NULL
, /* Back to My Mac key */
256 NetworkGlobalKeyIPv4
= NULL
,
257 /* Network global IPv4 key */
258 NetworkGlobalKeyIPv6
= NULL
,
259 /* Network global IPv6 key */
260 NetworkGlobalKeyDNS
= NULL
,
261 /* Network global DNS key */
264 NetworkInterfaceKeyIPv4
= NULL
,
265 /* Netowrk interface key */
266 NetworkInterfaceKeyIPv6
= NULL
;
267 /* Netowrk interface key */
268 static cupsd_sysevent_t LastSysEvent
; /* Last system event (for delayed sleep) */
269 static int NameChanged
= 0;/* Did we get a 'name changed' event during sleep? */
270 static int PSToken
= 0; /* Power source notifications */
277 static void *sysEventThreadEntry(void);
278 static void sysEventPowerNotifier(void *context
, io_service_t service
,
279 natural_t messageType
,
280 void *messageArgument
);
281 static void sysEventConfigurationNotifier(SCDynamicStoreRef store
,
282 CFArrayRef changedKeys
,
284 static void sysEventTimerNotifier(CFRunLoopTimerRef timer
, void *context
);
285 static void sysUpdate(void);
286 static void sysUpdateNames(void);
290 * 'cupsdAllowSleep()' - Tell the OS it is now OK to sleep.
294 cupsdAllowSleep(void)
298 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
299 IOAllowPowerChange(LastSysEvent
.powerKernelPort
,
300 LastSysEvent
.powerNotificationID
);
305 * 'cupsdStartSystemMonitor()' - Start monitoring for system change.
309 cupsdStartSystemMonitor(void)
311 int flags
; /* fcntl flags on pipe */
314 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStartSystemMonitor()");
316 if (cupsdOpenPipe(SysEventPipes
))
318 cupsdLogMessage(CUPSD_LOG_ERROR
, "System event monitor pipe() failed - %s!",
323 cupsdAddSelect(SysEventPipes
[0], (cupsd_selfunc_t
)sysUpdate
, NULL
, NULL
);
326 * Set non-blocking mode on the descriptor we will be receiving notification
330 flags
= fcntl(SysEventPipes
[0], F_GETFL
, 0);
331 fcntl(SysEventPipes
[0], F_SETFL
, flags
| O_NONBLOCK
);
334 * Start the thread that runs the runloop...
337 pthread_mutex_init(&SysEventThreadMutex
, NULL
);
338 pthread_cond_init(&SysEventThreadCond
, NULL
);
339 pthread_create(&SysEventThread
, NULL
, (void *(*)(void *))sysEventThreadEntry
, NULL
);
342 * Monitor for power source changes via dispatch queue...
345 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStartSystemMonitor: IOPSGetTimeRemainingEstimate=%f", IOPSGetTimeRemainingEstimate());
346 ACPower
= IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited
;
347 notify_register_dispatch(kIOPSNotifyPowerSource
, &PSToken
, dispatch_get_main_queue(), ^(int t
) { (void)t
;
348 ACPower
= IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited
; });
353 * 'cupsdStopSystemMonitor()' - Stop monitoring for system change.
357 cupsdStopSystemMonitor(void)
359 CFRunLoopRef rl
; /* The event handler runloop */
362 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStopSystemMonitor()");
367 * Make sure the thread has completed it's initialization and
368 * stored it's runloop reference in the shared global.
371 pthread_mutex_lock(&SysEventThreadMutex
);
373 if (!SysEventRunloop
)
374 pthread_cond_wait(&SysEventThreadCond
, &SysEventThreadMutex
);
376 rl
= SysEventRunloop
;
377 SysEventRunloop
= NULL
;
379 pthread_mutex_unlock(&SysEventThreadMutex
);
384 pthread_join(SysEventThread
, NULL
);
385 pthread_mutex_destroy(&SysEventThreadMutex
);
386 pthread_cond_destroy(&SysEventThreadCond
);
389 if (SysEventPipes
[0] >= 0)
391 cupsdRemoveSelect(SysEventPipes
[0]);
392 cupsdClosePipe(SysEventPipes
);
397 notify_cancel(PSToken
);
404 * 'sysEventThreadEntry()' - A thread to receive power and computer name
405 * change notifications.
408 static void * /* O - Return status/value */
409 sysEventThreadEntry(void)
411 io_object_t powerNotifierObj
;
412 /* Power notifier object */
413 IONotificationPortRef powerNotifierPort
;
414 /* Power notifier port */
415 SCDynamicStoreRef store
= NULL
;/* System Config dynamic store */
416 CFRunLoopSourceRef powerRLS
= NULL
,/* Power runloop source */
417 storeRLS
= NULL
;/* System Config runloop source */
418 CFStringRef key
[6], /* System Config keys */
419 pattern
[2]; /* System Config patterns */
420 CFArrayRef keys
= NULL
, /* System Config key array*/
421 patterns
= NULL
;/* System Config pattern array */
422 SCDynamicStoreContext storeContext
; /* Dynamic store context */
423 CFRunLoopTimerContext timerContext
; /* Timer context */
424 cupsd_thread_data_t threadData
; /* Thread context data for the *
425 * runloop notifiers */
429 * Register for power state change notifications
432 bzero(&threadData
, sizeof(threadData
));
434 threadData
.sysevent
.powerKernelPort
=
435 IORegisterForSystemPower(&threadData
, &powerNotifierPort
,
436 sysEventPowerNotifier
, &powerNotifierObj
);
438 if (threadData
.sysevent
.powerKernelPort
)
440 powerRLS
= IONotificationPortGetRunLoopSource(powerNotifierPort
);
441 CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRLS
, kCFRunLoopDefaultMode
);
444 DEBUG_puts("sysEventThreadEntry: error registering for system power "
448 * Register for system configuration change notifications
451 bzero(&storeContext
, sizeof(storeContext
));
452 storeContext
.info
= &threadData
;
454 store
= SCDynamicStoreCreate(kCFAllocatorDefault
, CFSTR("cupsd"),
455 sysEventConfigurationNotifier
, &storeContext
);
457 if (!ComputerNameKey
)
458 ComputerNameKey
= SCDynamicStoreKeyCreateComputerName(kCFAllocatorDefault
);
461 BTMMKey
= SCDynamicStoreKeyCreate(kCFAllocatorDefault
,
462 CFSTR("Setup:/Network/BackToMyMac"));
464 if (!NetworkGlobalKeyIPv4
)
465 NetworkGlobalKeyIPv4
=
466 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
467 kSCDynamicStoreDomainState
,
470 if (!NetworkGlobalKeyIPv6
)
471 NetworkGlobalKeyIPv6
=
472 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
473 kSCDynamicStoreDomainState
,
476 if (!NetworkGlobalKeyDNS
)
477 NetworkGlobalKeyDNS
=
478 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
479 kSCDynamicStoreDomainState
,
483 HostNamesKey
= SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault
);
485 if (!NetworkInterfaceKeyIPv4
)
486 NetworkInterfaceKeyIPv4
=
487 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
488 kSCDynamicStoreDomainState
,
492 if (!NetworkInterfaceKeyIPv6
)
493 NetworkInterfaceKeyIPv6
=
494 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
495 kSCDynamicStoreDomainState
,
499 if (store
&& ComputerNameKey
&& HostNamesKey
&&
500 NetworkGlobalKeyIPv4
&& NetworkGlobalKeyIPv6
&& NetworkGlobalKeyDNS
&&
501 NetworkInterfaceKeyIPv4
&& NetworkInterfaceKeyIPv6
)
503 key
[0] = ComputerNameKey
;
505 key
[2] = NetworkGlobalKeyIPv4
;
506 key
[3] = NetworkGlobalKeyIPv6
;
507 key
[4] = NetworkGlobalKeyDNS
;
508 key
[5] = HostNamesKey
;
510 pattern
[0] = NetworkInterfaceKeyIPv4
;
511 pattern
[1] = NetworkInterfaceKeyIPv6
;
513 keys
= CFArrayCreate(kCFAllocatorDefault
, (const void **)key
,
514 sizeof(key
) / sizeof(key
[0]),
515 &kCFTypeArrayCallBacks
);
517 patterns
= CFArrayCreate(kCFAllocatorDefault
, (const void **)pattern
,
518 sizeof(pattern
) / sizeof(pattern
[0]),
519 &kCFTypeArrayCallBacks
);
521 if (keys
&& patterns
&&
522 SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
524 if ((storeRLS
= SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault
,
527 CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS
,
528 kCFRunLoopDefaultMode
);
531 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreateRunLoopSource "
532 "failed: %s\n", SCErrorString(SCError())));
535 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreSetNotificationKeys "
536 "failed: %s\n", SCErrorString(SCError())));
539 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreate failed: %s\n",
540 SCErrorString(SCError())));
549 * Set up a timer to delay the wake change notifications.
551 * The initial time is set a decade or so into the future, we'll adjust
555 bzero(&timerContext
, sizeof(timerContext
));
556 timerContext
.info
= &threadData
;
558 threadData
.timerRef
=
559 CFRunLoopTimerCreate(kCFAllocatorDefault
,
560 CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
561 86400L * 365L * 10L, 0, 0, sysEventTimerNotifier
,
563 CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
564 kCFRunLoopDefaultMode
);
567 * Store our runloop in a global so the main thread can use it to stop us.
570 pthread_mutex_lock(&SysEventThreadMutex
);
572 SysEventRunloop
= CFRunLoopGetCurrent();
574 pthread_cond_signal(&SysEventThreadCond
);
575 pthread_mutex_unlock(&SysEventThreadMutex
);
578 * Disappear into the runloop until it's stopped by the main thread.
584 * Clean up before exiting.
587 if (threadData
.timerRef
)
589 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
590 kCFRunLoopDefaultMode
);
591 CFRelease(threadData
.timerRef
);
594 if (threadData
.sysevent
.powerKernelPort
)
596 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS
,
597 kCFRunLoopDefaultMode
);
598 IODeregisterForSystemPower(&powerNotifierObj
);
599 IOServiceClose(threadData
.sysevent
.powerKernelPort
);
600 IONotificationPortDestroy(powerNotifierPort
);
605 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS
,
606 kCFRunLoopDefaultMode
);
607 CFRunLoopSourceInvalidate(storeRLS
);
619 * 'sysEventPowerNotifier()' - Handle power notification events.
623 sysEventPowerNotifier(
624 void *context
, /* I - Thread context data */
625 io_service_t service
, /* I - Unused service info */
626 natural_t messageType
, /* I - Type of message */
627 void *messageArgument
) /* I - Message data */
629 int sendit
= 1; /* Send event to main thread? *
630 * (0 = no, 1 = yes, 2 = delayed */
631 cupsd_thread_data_t
*threadData
; /* Thread context data */
634 threadData
= (cupsd_thread_data_t
*)context
;
636 (void)service
; /* anti-compiler-warning-code */
640 case kIOMessageCanSystemPowerOff
:
641 case kIOMessageCanSystemSleep
:
642 threadData
->sysevent
.event
|= SYSEVENT_CANSLEEP
;
645 case kIOMessageSystemWillRestart
:
646 case kIOMessageSystemWillPowerOff
:
647 case kIOMessageSystemWillSleep
:
648 threadData
->sysevent
.event
|= SYSEVENT_WILLSLEEP
;
649 threadData
->sysevent
.event
&= ~SYSEVENT_WOKE
;
652 case kIOMessageSystemHasPoweredOn
:
654 * Because powered on is followed by a net-changed event, delay
659 threadData
->sysevent
.event
|= SYSEVENT_WOKE
;
662 case kIOMessageSystemWillNotPowerOff
:
663 case kIOMessageSystemWillNotSleep
:
664 # ifdef kIOMessageSystemWillPowerOn
665 case kIOMessageSystemWillPowerOn
:
666 # endif /* kIOMessageSystemWillPowerOn */
674 case kIOMessageCanSystemPowerOff
:
675 cupsdLogMessage(CUPSD_LOG_DEBUG
,
676 "Got kIOMessageCanSystemPowerOff message.");
678 case kIOMessageCanSystemSleep
:
679 cupsdLogMessage(CUPSD_LOG_DEBUG
,
680 "Got kIOMessageCannSystemSleep message.");
682 case kIOMessageSystemWillRestart
:
683 cupsdLogMessage(CUPSD_LOG_DEBUG
,
684 "Got kIOMessageSystemWillRestart message.");
686 case kIOMessageSystemWillPowerOff
:
687 cupsdLogMessage(CUPSD_LOG_DEBUG
,
688 "Got kIOMessageSystemWillPowerOff message.");
690 case kIOMessageSystemWillSleep
:
691 cupsdLogMessage(CUPSD_LOG_DEBUG
,
692 "Got kIOMessageSystemWillSleep message.");
694 case kIOMessageSystemHasPoweredOn
:
695 cupsdLogMessage(CUPSD_LOG_DEBUG
,
696 "Got kIOMessageSystemHasPoweredOn message.");
698 case kIOMessageSystemWillNotPowerOff
:
699 cupsdLogMessage(CUPSD_LOG_DEBUG
,
700 "Got kIOMessageSystemWillNotPowerOff message.");
702 case kIOMessageSystemWillNotSleep
:
703 cupsdLogMessage(CUPSD_LOG_DEBUG
,
704 "Got kIOMessageSystemWillNotSleep message.");
706 # ifdef kIOMessageSystemWillPowerOn
707 case kIOMessageSystemWillPowerOn
:
708 cupsdLogMessage(CUPSD_LOG_DEBUG
,
709 "Got kIOMessageSystemWillPowerOn message.");
711 # endif /* kIOMessageSystemWillPowerOn */
713 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Got unknown power message %d.",
719 IOAllowPowerChange(threadData
->sysevent
.powerKernelPort
,
720 (long)messageArgument
);
723 threadData
->sysevent
.powerNotificationID
= (long)messageArgument
;
728 * Send the event to the main thread now.
731 write(SysEventPipes
[1], &threadData
->sysevent
,
732 sizeof(threadData
->sysevent
));
733 threadData
->sysevent
.event
= 0;
738 * Send the event to the main thread after 1 to 2 seconds.
741 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
742 CFAbsoluteTimeGetCurrent() + 2);
749 * 'sysEventConfigurationNotifier()' - Network configuration change notification
754 sysEventConfigurationNotifier(
755 SCDynamicStoreRef store
, /* I - System data (unused) */
756 CFArrayRef changedKeys
, /* I - Changed data */
757 void *context
) /* I - Thread context data */
759 cupsd_thread_data_t
*threadData
; /* Thread context data */
762 threadData
= (cupsd_thread_data_t
*)context
;
764 (void)store
; /* anti-compiler-warning-code */
766 CFRange range
= CFRangeMake(0, CFArrayGetCount(changedKeys
));
768 if (CFArrayContainsValue(changedKeys
, range
, ComputerNameKey
) ||
769 CFArrayContainsValue(changedKeys
, range
, BTMMKey
))
770 threadData
->sysevent
.event
|= SYSEVENT_NAMECHANGED
;
773 threadData
->sysevent
.event
|= SYSEVENT_NETCHANGED
;
776 * Indicate the network interface list needs updating...
783 * Because we registered for several different kinds of change notifications
784 * this callback usually gets called several times in a row. We use a timer to
785 * de-bounce these so we only end up generating one event for the main thread.
788 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
789 CFAbsoluteTimeGetCurrent() + 5);
794 * 'sysEventTimerNotifier()' - Handle delayed event notifications.
798 sysEventTimerNotifier(
799 CFRunLoopTimerRef timer
, /* I - Timer information */
800 void *context
) /* I - Thread context data */
802 cupsd_thread_data_t
*threadData
; /* Thread context data */
807 threadData
= (cupsd_thread_data_t
*)context
;
810 * If an event is still pending send it to the main thread.
813 if (threadData
->sysevent
.event
)
815 write(SysEventPipes
[1], &threadData
->sysevent
,
816 sizeof(threadData
->sysevent
));
817 threadData
->sysevent
.event
= 0;
823 * 'sysUpdate()' - Update the current system state.
829 int i
; /* Looping var */
830 cupsd_sysevent_t sysevent
; /* The system event */
831 cupsd_printer_t
*p
; /* Printer information */
835 * Drain the event pipe...
838 while (read((int)SysEventPipes
[0], &sysevent
, sizeof(sysevent
))
841 if (sysevent
.event
& SYSEVENT_CANSLEEP
)
844 * If there are active printers that don't have the connecting-to-device
845 * or cups-waiting-for-job-completed printer-state-reason then cancel the
846 * sleep request, i.e., these reasons indicate a job that is not actively
850 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
852 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
856 for (i
= 0; i
< p
->num_reasons
; i
++)
857 if (!strcmp(p
->reasons
[i
], "connecting-to-device") ||
858 !strcmp(p
->reasons
[i
], "cups-waiting-for-job-completed"))
861 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
868 cupsdLogMessage(CUPSD_LOG_INFO
,
869 "System sleep canceled because printer %s is active.",
871 IOCancelPowerChange(sysevent
.powerKernelPort
,
872 sysevent
.powerNotificationID
);
876 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System wants to sleep.");
877 IOAllowPowerChange(sysevent
.powerKernelPort
,
878 sysevent
.powerNotificationID
);
882 if (sysevent
.event
& SYSEVENT_WILLSLEEP
)
884 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System going to sleep.");
891 * If we have no printing jobs, allow the power change immediately.
892 * Otherwise set the SleepJobs time to 10 seconds in the future when
893 * we'll take more drastic measures...
896 if (cupsArrayCount(PrintingJobs
) == 0)
898 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
899 IOAllowPowerChange(sysevent
.powerKernelPort
,
900 sysevent
.powerNotificationID
);
905 * If there are active printers that don't have the connecting-to-device
906 * or cups-waiting-for-job-completed printer-state-reasons then delay the
907 * sleep request, i.e., these reasons indicate a job is active...
910 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
912 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
916 for (i
= 0; i
< p
->num_reasons
; i
++)
917 if (!strcmp(p
->reasons
[i
], "connecting-to-device") ||
918 !strcmp(p
->reasons
[i
], "cups-waiting-for-job-completed"))
921 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
928 cupsdLogMessage(CUPSD_LOG_INFO
,
929 "System sleep delayed because printer %s is active.",
932 LastSysEvent
= sysevent
;
933 SleepJobs
= time(NULL
) + 10;
937 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
938 IOAllowPowerChange(sysevent
.powerKernelPort
,
939 sysevent
.powerNotificationID
);
944 if (sysevent
.event
& SYSEVENT_WOKE
)
946 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System woke from sleep.");
947 IOAllowPowerChange(sysevent
.powerKernelPort
,
948 sysevent
.powerNotificationID
);
952 * Make sure jobs that were queued prior to the system going to sleep don't
953 * get canceled right away...
958 cupsd_job_t
*job
; /* Current job */
960 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
962 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
964 if (job
->cancel_time
)
966 ipp_attribute_t
*cancel_after
= ippFindAttribute(job
->attrs
,
971 job
->cancel_time
= time(NULL
) + ippGetInteger(cancel_after
, 0);
973 job
->cancel_time
= time(NULL
) + MaxJobTime
;
984 if (sysevent
.event
& SYSEVENT_NETCHANGED
)
987 cupsdLogMessage(CUPSD_LOG_DEBUG
,
988 "System network configuration changed - "
989 "ignored while sleeping.");
991 cupsdLogMessage(CUPSD_LOG_DEBUG
,
992 "System network configuration changed.");
995 if (sysevent
.event
& SYSEVENT_NAMECHANGED
)
1001 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1002 "Computer name or BTMM domains changed - ignored while "
1007 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1008 "Computer name or BTMM domains changed.");
1018 * 'sysUpdateNames()' - Update computer and/or BTMM domains.
1022 sysUpdateNames(void)
1024 cupsd_printer_t
*p
; /* Current printer */
1030 * De-register the individual printers...
1033 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1035 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1036 cupsdDeregisterPrinter(p
, 1);
1038 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1040 * Update the computer name and BTMM domain list...
1043 cupsdUpdateDNSSDName();
1044 # endif /* HAVE_DNSSD || HAVE_AVAHI */
1047 * Now re-register them...
1050 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1052 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1053 cupsdRegisterPrinter(p
);
1055 #endif /* __APPLE__ */