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
);
440 DEBUG_puts("sysEventThreadEntry: error registering for system power "
444 * Register for system configuration change notifications
447 bzero(&storeContext
, sizeof(storeContext
));
448 storeContext
.info
= &threadData
;
450 store
= SCDynamicStoreCreate(kCFAllocatorDefault
, CFSTR("cupsd"),
451 sysEventConfigurationNotifier
, &storeContext
);
453 if (!ComputerNameKey
)
454 ComputerNameKey
= SCDynamicStoreKeyCreateComputerName(kCFAllocatorDefault
);
457 BTMMKey
= SCDynamicStoreKeyCreate(kCFAllocatorDefault
,
458 CFSTR("Setup:/Network/BackToMyMac"));
460 if (!NetworkGlobalKeyIPv4
)
461 NetworkGlobalKeyIPv4
=
462 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
463 kSCDynamicStoreDomainState
,
466 if (!NetworkGlobalKeyIPv6
)
467 NetworkGlobalKeyIPv6
=
468 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
469 kSCDynamicStoreDomainState
,
472 if (!NetworkGlobalKeyDNS
)
473 NetworkGlobalKeyDNS
=
474 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
475 kSCDynamicStoreDomainState
,
479 HostNamesKey
= SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault
);
481 if (!NetworkInterfaceKeyIPv4
)
482 NetworkInterfaceKeyIPv4
=
483 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
484 kSCDynamicStoreDomainState
,
488 if (!NetworkInterfaceKeyIPv6
)
489 NetworkInterfaceKeyIPv6
=
490 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
491 kSCDynamicStoreDomainState
,
495 if (store
&& ComputerNameKey
&& HostNamesKey
&&
496 NetworkGlobalKeyIPv4
&& NetworkGlobalKeyIPv6
&& NetworkGlobalKeyDNS
&&
497 NetworkInterfaceKeyIPv4
&& NetworkInterfaceKeyIPv6
)
499 key
[0] = ComputerNameKey
;
501 key
[2] = NetworkGlobalKeyIPv4
;
502 key
[3] = NetworkGlobalKeyIPv6
;
503 key
[4] = NetworkGlobalKeyDNS
;
504 key
[5] = HostNamesKey
;
506 pattern
[0] = NetworkInterfaceKeyIPv4
;
507 pattern
[1] = NetworkInterfaceKeyIPv6
;
509 keys
= CFArrayCreate(kCFAllocatorDefault
, (const void **)key
,
510 sizeof(key
) / sizeof(key
[0]),
511 &kCFTypeArrayCallBacks
);
513 patterns
= CFArrayCreate(kCFAllocatorDefault
, (const void **)pattern
,
514 sizeof(pattern
) / sizeof(pattern
[0]),
515 &kCFTypeArrayCallBacks
);
517 if (keys
&& patterns
&&
518 SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
520 if ((storeRLS
= SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault
,
523 CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS
,
524 kCFRunLoopDefaultMode
);
527 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreateRunLoopSource "
528 "failed: %s\n", SCErrorString(SCError())));
531 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreSetNotificationKeys "
532 "failed: %s\n", SCErrorString(SCError())));
535 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreate failed: %s\n",
536 SCErrorString(SCError())));
545 * Set up a timer to delay the wake change notifications.
547 * The initial time is set a decade or so into the future, we'll adjust
551 bzero(&timerContext
, sizeof(timerContext
));
552 timerContext
.info
= &threadData
;
554 threadData
.timerRef
=
555 CFRunLoopTimerCreate(kCFAllocatorDefault
,
556 CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
557 86400L * 365L * 10L, 0, 0, sysEventTimerNotifier
,
559 CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
560 kCFRunLoopDefaultMode
);
563 * Store our runloop in a global so the main thread can use it to stop us.
566 pthread_mutex_lock(&SysEventThreadMutex
);
568 SysEventRunloop
= CFRunLoopGetCurrent();
570 pthread_cond_signal(&SysEventThreadCond
);
571 pthread_mutex_unlock(&SysEventThreadMutex
);
574 * Disappear into the runloop until it's stopped by the main thread.
580 * Clean up before exiting.
583 if (threadData
.timerRef
)
585 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
586 kCFRunLoopDefaultMode
);
587 CFRelease(threadData
.timerRef
);
590 if (threadData
.sysevent
.powerKernelPort
)
592 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS
,
593 kCFRunLoopDefaultMode
);
594 IODeregisterForSystemPower(&powerNotifierObj
);
595 IOServiceClose(threadData
.sysevent
.powerKernelPort
);
596 IONotificationPortDestroy(powerNotifierPort
);
601 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS
,
602 kCFRunLoopDefaultMode
);
603 CFRunLoopSourceInvalidate(storeRLS
);
615 * 'sysEventPowerNotifier()' - Handle power notification events.
619 sysEventPowerNotifier(
620 void *context
, /* I - Thread context data */
621 io_service_t service
, /* I - Unused service info */
622 natural_t messageType
, /* I - Type of message */
623 void *messageArgument
) /* I - Message data */
625 int sendit
= 1; /* Send event to main thread? *
626 * (0 = no, 1 = yes, 2 = delayed */
627 cupsd_thread_data_t
*threadData
; /* Thread context data */
630 threadData
= (cupsd_thread_data_t
*)context
;
632 (void)service
; /* anti-compiler-warning-code */
636 case kIOMessageCanSystemPowerOff
:
637 case kIOMessageCanSystemSleep
:
638 threadData
->sysevent
.event
|= SYSEVENT_CANSLEEP
;
641 case kIOMessageSystemWillRestart
:
642 case kIOMessageSystemWillPowerOff
:
643 case kIOMessageSystemWillSleep
:
644 threadData
->sysevent
.event
|= SYSEVENT_WILLSLEEP
;
645 threadData
->sysevent
.event
&= ~SYSEVENT_WOKE
;
648 case kIOMessageSystemHasPoweredOn
:
650 * Because powered on is followed by a net-changed event, delay
655 threadData
->sysevent
.event
|= SYSEVENT_WOKE
;
658 case kIOMessageSystemWillNotPowerOff
:
659 case kIOMessageSystemWillNotSleep
:
660 # ifdef kIOMessageSystemWillPowerOn
661 case kIOMessageSystemWillPowerOn
:
662 # endif /* kIOMessageSystemWillPowerOn */
670 case kIOMessageCanSystemPowerOff
:
671 cupsdLogMessage(CUPSD_LOG_DEBUG
,
672 "Got kIOMessageCanSystemPowerOff message.");
674 case kIOMessageCanSystemSleep
:
675 cupsdLogMessage(CUPSD_LOG_DEBUG
,
676 "Got kIOMessageCannSystemSleep message.");
678 case kIOMessageSystemWillRestart
:
679 cupsdLogMessage(CUPSD_LOG_DEBUG
,
680 "Got kIOMessageSystemWillRestart message.");
682 case kIOMessageSystemWillPowerOff
:
683 cupsdLogMessage(CUPSD_LOG_DEBUG
,
684 "Got kIOMessageSystemWillPowerOff message.");
686 case kIOMessageSystemWillSleep
:
687 cupsdLogMessage(CUPSD_LOG_DEBUG
,
688 "Got kIOMessageSystemWillSleep message.");
690 case kIOMessageSystemHasPoweredOn
:
691 cupsdLogMessage(CUPSD_LOG_DEBUG
,
692 "Got kIOMessageSystemHasPoweredOn message.");
694 case kIOMessageSystemWillNotPowerOff
:
695 cupsdLogMessage(CUPSD_LOG_DEBUG
,
696 "Got kIOMessageSystemWillNotPowerOff message.");
698 case kIOMessageSystemWillNotSleep
:
699 cupsdLogMessage(CUPSD_LOG_DEBUG
,
700 "Got kIOMessageSystemWillNotSleep message.");
702 # ifdef kIOMessageSystemWillPowerOn
703 case kIOMessageSystemWillPowerOn
:
704 cupsdLogMessage(CUPSD_LOG_DEBUG
,
705 "Got kIOMessageSystemWillPowerOn message.");
707 # endif /* kIOMessageSystemWillPowerOn */
709 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Got unknown power message %d.",
715 IOAllowPowerChange(threadData
->sysevent
.powerKernelPort
,
716 (long)messageArgument
);
719 threadData
->sysevent
.powerNotificationID
= (long)messageArgument
;
724 * Send the event to the main thread now.
727 write(SysEventPipes
[1], &threadData
->sysevent
,
728 sizeof(threadData
->sysevent
));
729 threadData
->sysevent
.event
= 0;
734 * Send the event to the main thread after 1 to 2 seconds.
737 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
738 CFAbsoluteTimeGetCurrent() + 2);
745 * 'sysEventConfigurationNotifier()' - Network configuration change notification
750 sysEventConfigurationNotifier(
751 SCDynamicStoreRef store
, /* I - System data (unused) */
752 CFArrayRef changedKeys
, /* I - Changed data */
753 void *context
) /* I - Thread context data */
755 cupsd_thread_data_t
*threadData
; /* Thread context data */
758 threadData
= (cupsd_thread_data_t
*)context
;
760 (void)store
; /* anti-compiler-warning-code */
762 CFRange range
= CFRangeMake(0, CFArrayGetCount(changedKeys
));
764 if (CFArrayContainsValue(changedKeys
, range
, ComputerNameKey
) ||
765 CFArrayContainsValue(changedKeys
, range
, BTMMKey
))
766 threadData
->sysevent
.event
|= SYSEVENT_NAMECHANGED
;
769 threadData
->sysevent
.event
|= SYSEVENT_NETCHANGED
;
772 * Indicate the network interface list needs updating...
779 * Because we registered for several different kinds of change notifications
780 * this callback usually gets called several times in a row. We use a timer to
781 * de-bounce these so we only end up generating one event for the main thread.
784 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
785 CFAbsoluteTimeGetCurrent() + 5);
790 * 'sysEventTimerNotifier()' - Handle delayed event notifications.
794 sysEventTimerNotifier(
795 CFRunLoopTimerRef timer
, /* I - Timer information */
796 void *context
) /* I - Thread context data */
798 cupsd_thread_data_t
*threadData
; /* Thread context data */
803 threadData
= (cupsd_thread_data_t
*)context
;
806 * If an event is still pending send it to the main thread.
809 if (threadData
->sysevent
.event
)
811 write(SysEventPipes
[1], &threadData
->sysevent
,
812 sizeof(threadData
->sysevent
));
813 threadData
->sysevent
.event
= 0;
819 * 'sysUpdate()' - Update the current system state.
825 int i
; /* Looping var */
826 cupsd_sysevent_t sysevent
; /* The system event */
827 cupsd_printer_t
*p
; /* Printer information */
831 * Drain the event pipe...
834 while (read((int)SysEventPipes
[0], &sysevent
, sizeof(sysevent
))
837 if (sysevent
.event
& SYSEVENT_CANSLEEP
)
840 * If there are active printers that don't have the connecting-to-device
841 * or cups-waiting-for-job-completed printer-state-reason then cancel the
842 * sleep request, i.e., these reasons indicate a job that is not actively
846 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
848 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
852 for (i
= 0; i
< p
->num_reasons
; i
++)
853 if (!strcmp(p
->reasons
[i
], "connecting-to-device") ||
854 !strcmp(p
->reasons
[i
], "cups-waiting-for-job-completed"))
857 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
864 cupsdLogMessage(CUPSD_LOG_INFO
,
865 "System sleep canceled because printer %s is active.",
867 IOCancelPowerChange(sysevent
.powerKernelPort
,
868 sysevent
.powerNotificationID
);
872 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System wants to sleep.");
873 IOAllowPowerChange(sysevent
.powerKernelPort
,
874 sysevent
.powerNotificationID
);
878 if (sysevent
.event
& SYSEVENT_WILLSLEEP
)
880 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System going to sleep.");
887 * If we have no printing jobs, allow the power change immediately.
888 * Otherwise set the SleepJobs time to 10 seconds in the future when
889 * we'll take more drastic measures...
892 if (cupsArrayCount(PrintingJobs
) == 0)
894 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
895 IOAllowPowerChange(sysevent
.powerKernelPort
,
896 sysevent
.powerNotificationID
);
901 * If there are active printers that don't have the connecting-to-device
902 * or cups-waiting-for-job-completed printer-state-reasons then delay the
903 * sleep request, i.e., these reasons indicate a job is active...
906 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
908 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
912 for (i
= 0; i
< p
->num_reasons
; i
++)
913 if (!strcmp(p
->reasons
[i
], "connecting-to-device") ||
914 !strcmp(p
->reasons
[i
], "cups-waiting-for-job-completed"))
917 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
924 cupsdLogMessage(CUPSD_LOG_INFO
,
925 "System sleep delayed because printer %s is active.",
928 LastSysEvent
= sysevent
;
929 SleepJobs
= time(NULL
) + 10;
933 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
934 IOAllowPowerChange(sysevent
.powerKernelPort
,
935 sysevent
.powerNotificationID
);
940 if (sysevent
.event
& SYSEVENT_WOKE
)
942 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System woke from sleep.");
943 IOAllowPowerChange(sysevent
.powerKernelPort
,
944 sysevent
.powerNotificationID
);
948 * Make sure jobs that were queued prior to the system going to sleep don't
949 * get canceled right away...
954 cupsd_job_t
*job
; /* Current job */
956 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
958 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
960 if (job
->cancel_time
)
962 ipp_attribute_t
*cancel_after
= ippFindAttribute(job
->attrs
,
967 job
->cancel_time
= time(NULL
) + ippGetInteger(cancel_after
, 0);
969 job
->cancel_time
= time(NULL
) + MaxJobTime
;
980 if (sysevent
.event
& SYSEVENT_NETCHANGED
)
983 cupsdLogMessage(CUPSD_LOG_DEBUG
,
984 "System network configuration changed - "
985 "ignored while sleeping.");
987 cupsdLogMessage(CUPSD_LOG_DEBUG
,
988 "System network configuration changed.");
991 if (sysevent
.event
& SYSEVENT_NAMECHANGED
)
997 cupsdLogMessage(CUPSD_LOG_DEBUG
,
998 "Computer name or BTMM domains changed - ignored while "
1003 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1004 "Computer name or BTMM domains changed.");
1014 * 'sysUpdateNames()' - Update computer and/or BTMM domains.
1018 sysUpdateNames(void)
1020 cupsd_printer_t
*p
; /* Current printer */
1026 * De-register the individual printers...
1029 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1031 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1032 cupsdDeregisterPrinter(p
, 1);
1034 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1036 * Update the computer name and BTMM domain list...
1039 cupsdUpdateDNSSDName();
1040 # endif /* HAVE_DNSSD || HAVE_AVAHI */
1043 * Now re-register them...
1046 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1048 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1049 cupsdRegisterPrinter(p
);
1051 #endif /* __APPLE__ */