2 * System management functions for the CUPS scheduler.
4 * Copyright 2007-2017 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...
18 # include <IOKit/pwr_mgt/IOPMLib.h>
19 #endif /* __APPLE__ */
23 * The system management functions cover disk and power management which
24 * are primarily used for portable computers.
26 * Disk management involves delaying the write of certain configuration
27 * and state files to minimize the number of times the disk has to spin
28 * up or flash to be written to.
30 * Power management support is currently only implemented on macOS, but
31 * essentially we use four functions to let the OS know when it is OK to
32 * put the system to sleep, typically when we are not in the middle of
33 * printing a job. And on macOS we can also "sleep print" - basically the
34 * system only wakes up long enough to service network requests and process
40 * 'cupsdCleanDirty()' - Write dirty config and state files.
46 if (DirtyFiles
& CUPSD_DIRTY_PRINTERS
)
47 cupsdSaveAllPrinters();
49 if (DirtyFiles
& CUPSD_DIRTY_CLASSES
)
50 cupsdSaveAllClasses();
52 if (DirtyFiles
& CUPSD_DIRTY_PRINTCAP
)
55 if (DirtyFiles
& CUPSD_DIRTY_JOBS
)
57 cupsd_job_t
*job
; /* Current job */
61 for (job
= (cupsd_job_t
*)cupsArrayFirst(Jobs
);
63 job
= (cupsd_job_t
*)cupsArrayNext(Jobs
))
68 if (DirtyFiles
& CUPSD_DIRTY_SUBSCRIPTIONS
)
69 cupsdSaveAllSubscriptions();
71 DirtyFiles
= CUPSD_DIRTY_NONE
;
79 * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
83 cupsdMarkDirty(int what
) /* I - What file(s) are dirty? */
85 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdMarkDirty(%c%c%c%c%c)",
86 (what
& CUPSD_DIRTY_PRINTERS
) ? 'P' : '-',
87 (what
& CUPSD_DIRTY_CLASSES
) ? 'C' : '-',
88 (what
& CUPSD_DIRTY_PRINTCAP
) ? 'p' : '-',
89 (what
& CUPSD_DIRTY_JOBS
) ? 'J' : '-',
90 (what
& CUPSD_DIRTY_SUBSCRIPTIONS
) ? 'S' : '-');
92 if (what
== CUPSD_DIRTY_PRINTCAP
&& !Printcap
)
98 DirtyCleanTime
= time(NULL
) + DirtyCleanInterval
;
100 cupsdSetBusyState(0);
105 * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
109 cupsdSetBusyState(int working
) /* I - Doing significant work? */
111 int i
; /* Looping var */
112 cupsd_job_t
*job
; /* Current job */
113 cupsd_printer_t
*p
; /* Current printer */
114 int newbusy
; /* New busy state */
115 static int busy
= 0; /* Current busy state */
116 static const char * const busy_text
[] =
117 { /* Text for busy states */
121 "Printing jobs and dirty files",
123 "Active clients and dirty files",
124 "Active clients and printing jobs",
125 "Active clients, printing jobs, and dirty files"
128 static int tran
= 0; /* Current busy transaction */
129 static IOPMAssertionID keep_awake
= 0;/* Keep the system awake while printing */
130 #endif /* __APPLE__ */
134 * Figure out how busy we are...
137 newbusy
= (DirtyCleanTime
? 1 : 0) |
138 ((working
|| cupsArrayCount(ActiveClients
) > 0) ? 4 : 0);
140 for (job
= (cupsd_job_t
*)cupsArrayFirst(PrintingJobs
);
142 job
= (cupsd_job_t
*)cupsArrayNext(PrintingJobs
))
144 if ((p
= job
->printer
) != NULL
)
146 for (i
= 0; i
< p
->num_reasons
; i
++)
147 if (!strcmp(p
->reasons
[i
], "connecting-to-device"))
150 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
158 cupsdLogMessage(CUPSD_LOG_DEBUG
,
159 "cupsdSetBusyState: newbusy=\"%s\", busy=\"%s\"",
160 busy_text
[newbusy
], busy_text
[busy
]);
163 * Manage state changes...
173 xpc_transaction_begin();
176 else if (!busy
&& tran
)
178 xpc_transaction_end();
181 #endif /* __APPLE__ */
185 if (cupsArrayCount(PrintingJobs
) > 0 && !keep_awake
)
187 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Asserting NetworkClientActive.");
189 IOPMAssertionCreateWithName(kIOPMAssertNetworkClientActive
,
190 kIOPMAssertionLevelOn
,
191 CFSTR("org.cups.cupsd"), &keep_awake
);
193 else if (cupsArrayCount(PrintingJobs
) == 0 && keep_awake
)
195 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Releasing power assertion.");
196 IOPMAssertionRelease(keep_awake
);
199 #endif /* __APPLE__ */
205 * This is the Apple-specific system event code. It works by creating
206 * a worker thread that waits for events from the OS and relays them
207 * to the main thread via a traditional pipe.
211 * Include MacOS-specific headers...
215 # include <IOKit/IOKitLib.h>
216 # include <IOKit/IOMessage.h>
217 # include <IOKit/ps/IOPowerSources.h>
218 # include <IOKit/pwr_mgt/IOPMLib.h>
219 # include <SystemConfiguration/SystemConfiguration.h>
220 # include <pthread.h>
227 # define SYSEVENT_CANSLEEP 0x1 /* Decide whether to allow sleep or not */
228 # define SYSEVENT_WILLSLEEP 0x2 /* Computer will go to sleep */
229 # define SYSEVENT_WOKE 0x4 /* Computer woke from sleep */
230 # define SYSEVENT_NETCHANGED 0x8 /* Network changed */
231 # define SYSEVENT_NAMECHANGED 0x10 /* Computer name changed */
238 typedef struct cupsd_sysevent_s
/*** System event data ****/
240 unsigned char event
; /* Event bit field */
241 io_connect_t powerKernelPort
; /* Power context data */
242 long powerNotificationID
; /* Power event data */
246 typedef struct cupsd_thread_data_s
/*** Thread context data ****/
248 cupsd_sysevent_t sysevent
; /* System event */
249 CFRunLoopTimerRef timerRef
; /* Timer to delay some change *
251 } cupsd_thread_data_t
;
258 static pthread_t SysEventThread
= NULL
;
259 /* Thread to host a runloop */
260 static pthread_mutex_t SysEventThreadMutex
= { 0 };
261 /* Coordinates access to shared gloabals */
262 static pthread_cond_t SysEventThreadCond
= { 0 };
263 /* Thread initialization complete condition */
264 static CFRunLoopRef SysEventRunloop
= NULL
;
265 /* The runloop. Access must be protected! */
266 static CFStringRef ComputerNameKey
= NULL
,
267 /* Computer name key */
268 BTMMKey
= NULL
, /* Back to My Mac key */
269 NetworkGlobalKeyIPv4
= NULL
,
270 /* Network global IPv4 key */
271 NetworkGlobalKeyIPv6
= NULL
,
272 /* Network global IPv6 key */
273 NetworkGlobalKeyDNS
= NULL
,
274 /* Network global DNS key */
277 NetworkInterfaceKeyIPv4
= NULL
,
278 /* Netowrk interface key */
279 NetworkInterfaceKeyIPv6
= NULL
;
280 /* Netowrk interface key */
281 static cupsd_sysevent_t LastSysEvent
; /* Last system event (for delayed sleep) */
282 static int NameChanged
= 0;/* Did we get a 'name changed' event during sleep? */
283 static int PSToken
= 0; /* Power source notifications */
290 static void *sysEventThreadEntry(void);
291 static void sysEventPowerNotifier(void *context
, io_service_t service
,
292 natural_t messageType
,
293 void *messageArgument
);
294 static void sysEventConfigurationNotifier(SCDynamicStoreRef store
,
295 CFArrayRef changedKeys
,
297 static void sysEventTimerNotifier(CFRunLoopTimerRef timer
, void *context
);
298 static void sysUpdate(void);
299 static void sysUpdateNames(void);
303 * 'cupsdAllowSleep()' - Tell the OS it is now OK to sleep.
307 cupsdAllowSleep(void)
311 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
312 IOAllowPowerChange(LastSysEvent
.powerKernelPort
,
313 LastSysEvent
.powerNotificationID
);
318 * 'cupsdStartSystemMonitor()' - Start monitoring for system change.
322 cupsdStartSystemMonitor(void)
324 int flags
; /* fcntl flags on pipe */
327 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStartSystemMonitor()");
329 if (cupsdOpenPipe(SysEventPipes
))
331 cupsdLogMessage(CUPSD_LOG_ERROR
, "System event monitor pipe() failed - %s!",
336 cupsdAddSelect(SysEventPipes
[0], (cupsd_selfunc_t
)sysUpdate
, NULL
, NULL
);
339 * Set non-blocking mode on the descriptor we will be receiving notification
343 flags
= fcntl(SysEventPipes
[0], F_GETFL
, 0);
344 fcntl(SysEventPipes
[0], F_SETFL
, flags
| O_NONBLOCK
);
347 * Start the thread that runs the runloop...
350 pthread_mutex_init(&SysEventThreadMutex
, NULL
);
351 pthread_cond_init(&SysEventThreadCond
, NULL
);
352 pthread_create(&SysEventThread
, NULL
, (void *(*)(void *))sysEventThreadEntry
, NULL
);
355 * Monitor for power source changes via dispatch queue...
358 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStartSystemMonitor: IOPSGetTimeRemainingEstimate=%f", IOPSGetTimeRemainingEstimate());
359 ACPower
= IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited
;
360 notify_register_dispatch(kIOPSNotifyPowerSource
, &PSToken
, dispatch_get_main_queue(), ^(int t
) { (void)t
;
361 ACPower
= IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited
; });
366 * 'cupsdStopSystemMonitor()' - Stop monitoring for system change.
370 cupsdStopSystemMonitor(void)
372 CFRunLoopRef rl
; /* The event handler runloop */
375 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "cupsdStopSystemMonitor()");
380 * Make sure the thread has completed it's initialization and
381 * stored it's runloop reference in the shared global.
384 pthread_mutex_lock(&SysEventThreadMutex
);
386 if (!SysEventRunloop
)
387 pthread_cond_wait(&SysEventThreadCond
, &SysEventThreadMutex
);
389 rl
= SysEventRunloop
;
390 SysEventRunloop
= NULL
;
392 pthread_mutex_unlock(&SysEventThreadMutex
);
397 pthread_join(SysEventThread
, NULL
);
398 pthread_mutex_destroy(&SysEventThreadMutex
);
399 pthread_cond_destroy(&SysEventThreadCond
);
402 if (SysEventPipes
[0] >= 0)
404 cupsdRemoveSelect(SysEventPipes
[0]);
405 cupsdClosePipe(SysEventPipes
);
410 notify_cancel(PSToken
);
417 * 'sysEventThreadEntry()' - A thread to receive power and computer name
418 * change notifications.
421 static void * /* O - Return status/value */
422 sysEventThreadEntry(void)
424 io_object_t powerNotifierObj
;
425 /* Power notifier object */
426 IONotificationPortRef powerNotifierPort
;
427 /* Power notifier port */
428 SCDynamicStoreRef store
= NULL
;/* System Config dynamic store */
429 CFRunLoopSourceRef powerRLS
= NULL
,/* Power runloop source */
430 storeRLS
= NULL
;/* System Config runloop source */
431 CFStringRef key
[6], /* System Config keys */
432 pattern
[2]; /* System Config patterns */
433 CFArrayRef keys
= NULL
, /* System Config key array*/
434 patterns
= NULL
;/* System Config pattern array */
435 SCDynamicStoreContext storeContext
; /* Dynamic store context */
436 CFRunLoopTimerContext timerContext
; /* Timer context */
437 cupsd_thread_data_t threadData
; /* Thread context data for the *
438 * runloop notifiers */
442 * Register for power state change notifications
445 bzero(&threadData
, sizeof(threadData
));
447 threadData
.sysevent
.powerKernelPort
=
448 IORegisterForSystemPower(&threadData
, &powerNotifierPort
,
449 sysEventPowerNotifier
, &powerNotifierObj
);
451 if (threadData
.sysevent
.powerKernelPort
)
453 powerRLS
= IONotificationPortGetRunLoopSource(powerNotifierPort
);
454 CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRLS
, kCFRunLoopDefaultMode
);
457 DEBUG_puts("sysEventThreadEntry: error registering for system power "
461 * Register for system configuration change notifications
464 bzero(&storeContext
, sizeof(storeContext
));
465 storeContext
.info
= &threadData
;
467 store
= SCDynamicStoreCreate(kCFAllocatorDefault
, CFSTR("cupsd"),
468 sysEventConfigurationNotifier
, &storeContext
);
470 if (!ComputerNameKey
)
471 ComputerNameKey
= SCDynamicStoreKeyCreateComputerName(kCFAllocatorDefault
);
474 BTMMKey
= SCDynamicStoreKeyCreate(kCFAllocatorDefault
,
475 CFSTR("Setup:/Network/BackToMyMac"));
477 if (!NetworkGlobalKeyIPv4
)
478 NetworkGlobalKeyIPv4
=
479 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
480 kSCDynamicStoreDomainState
,
483 if (!NetworkGlobalKeyIPv6
)
484 NetworkGlobalKeyIPv6
=
485 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
486 kSCDynamicStoreDomainState
,
489 if (!NetworkGlobalKeyDNS
)
490 NetworkGlobalKeyDNS
=
491 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
492 kSCDynamicStoreDomainState
,
496 HostNamesKey
= SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault
);
498 if (!NetworkInterfaceKeyIPv4
)
499 NetworkInterfaceKeyIPv4
=
500 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
501 kSCDynamicStoreDomainState
,
505 if (!NetworkInterfaceKeyIPv6
)
506 NetworkInterfaceKeyIPv6
=
507 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
508 kSCDynamicStoreDomainState
,
512 if (store
&& ComputerNameKey
&& HostNamesKey
&&
513 NetworkGlobalKeyIPv4
&& NetworkGlobalKeyIPv6
&& NetworkGlobalKeyDNS
&&
514 NetworkInterfaceKeyIPv4
&& NetworkInterfaceKeyIPv6
)
516 key
[0] = ComputerNameKey
;
518 key
[2] = NetworkGlobalKeyIPv4
;
519 key
[3] = NetworkGlobalKeyIPv6
;
520 key
[4] = NetworkGlobalKeyDNS
;
521 key
[5] = HostNamesKey
;
523 pattern
[0] = NetworkInterfaceKeyIPv4
;
524 pattern
[1] = NetworkInterfaceKeyIPv6
;
526 keys
= CFArrayCreate(kCFAllocatorDefault
, (const void **)key
,
527 sizeof(key
) / sizeof(key
[0]),
528 &kCFTypeArrayCallBacks
);
530 patterns
= CFArrayCreate(kCFAllocatorDefault
, (const void **)pattern
,
531 sizeof(pattern
) / sizeof(pattern
[0]),
532 &kCFTypeArrayCallBacks
);
534 if (keys
&& patterns
&&
535 SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
537 if ((storeRLS
= SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault
,
540 CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS
,
541 kCFRunLoopDefaultMode
);
544 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreateRunLoopSource "
545 "failed: %s\n", SCErrorString(SCError())));
548 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreSetNotificationKeys "
549 "failed: %s\n", SCErrorString(SCError())));
552 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreate failed: %s\n",
553 SCErrorString(SCError())));
562 * Set up a timer to delay the wake change notifications.
564 * The initial time is set a decade or so into the future, we'll adjust
568 bzero(&timerContext
, sizeof(timerContext
));
569 timerContext
.info
= &threadData
;
571 threadData
.timerRef
=
572 CFRunLoopTimerCreate(kCFAllocatorDefault
,
573 CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
574 86400L * 365L * 10L, 0, 0, sysEventTimerNotifier
,
576 CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
577 kCFRunLoopDefaultMode
);
580 * Store our runloop in a global so the main thread can use it to stop us.
583 pthread_mutex_lock(&SysEventThreadMutex
);
585 SysEventRunloop
= CFRunLoopGetCurrent();
587 pthread_cond_signal(&SysEventThreadCond
);
588 pthread_mutex_unlock(&SysEventThreadMutex
);
591 * Disappear into the runloop until it's stopped by the main thread.
597 * Clean up before exiting.
600 if (threadData
.timerRef
)
602 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
603 kCFRunLoopDefaultMode
);
604 CFRelease(threadData
.timerRef
);
607 if (threadData
.sysevent
.powerKernelPort
)
609 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS
,
610 kCFRunLoopDefaultMode
);
611 IODeregisterForSystemPower(&powerNotifierObj
);
612 IOServiceClose(threadData
.sysevent
.powerKernelPort
);
613 IONotificationPortDestroy(powerNotifierPort
);
618 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS
,
619 kCFRunLoopDefaultMode
);
620 CFRunLoopSourceInvalidate(storeRLS
);
632 * 'sysEventPowerNotifier()' - Handle power notification events.
636 sysEventPowerNotifier(
637 void *context
, /* I - Thread context data */
638 io_service_t service
, /* I - Unused service info */
639 natural_t messageType
, /* I - Type of message */
640 void *messageArgument
) /* I - Message data */
642 int sendit
= 1; /* Send event to main thread? *
643 * (0 = no, 1 = yes, 2 = delayed */
644 cupsd_thread_data_t
*threadData
; /* Thread context data */
647 threadData
= (cupsd_thread_data_t
*)context
;
649 (void)service
; /* anti-compiler-warning-code */
653 case kIOMessageCanSystemPowerOff
:
654 case kIOMessageCanSystemSleep
:
655 threadData
->sysevent
.event
|= SYSEVENT_CANSLEEP
;
658 case kIOMessageSystemWillRestart
:
659 case kIOMessageSystemWillPowerOff
:
660 case kIOMessageSystemWillSleep
:
661 threadData
->sysevent
.event
|= SYSEVENT_WILLSLEEP
;
662 threadData
->sysevent
.event
&= ~SYSEVENT_WOKE
;
665 case kIOMessageSystemHasPoweredOn
:
667 * Because powered on is followed by a net-changed event, delay
672 threadData
->sysevent
.event
|= SYSEVENT_WOKE
;
675 case kIOMessageSystemWillNotPowerOff
:
676 case kIOMessageSystemWillNotSleep
:
677 # ifdef kIOMessageSystemWillPowerOn
678 case kIOMessageSystemWillPowerOn
:
679 # endif /* kIOMessageSystemWillPowerOn */
687 case kIOMessageCanSystemPowerOff
:
688 cupsdLogMessage(CUPSD_LOG_DEBUG
,
689 "Got kIOMessageCanSystemPowerOff message.");
691 case kIOMessageCanSystemSleep
:
692 cupsdLogMessage(CUPSD_LOG_DEBUG
,
693 "Got kIOMessageCannSystemSleep message.");
695 case kIOMessageSystemWillRestart
:
696 cupsdLogMessage(CUPSD_LOG_DEBUG
,
697 "Got kIOMessageSystemWillRestart message.");
699 case kIOMessageSystemWillPowerOff
:
700 cupsdLogMessage(CUPSD_LOG_DEBUG
,
701 "Got kIOMessageSystemWillPowerOff message.");
703 case kIOMessageSystemWillSleep
:
704 cupsdLogMessage(CUPSD_LOG_DEBUG
,
705 "Got kIOMessageSystemWillSleep message.");
707 case kIOMessageSystemHasPoweredOn
:
708 cupsdLogMessage(CUPSD_LOG_DEBUG
,
709 "Got kIOMessageSystemHasPoweredOn message.");
711 case kIOMessageSystemWillNotPowerOff
:
712 cupsdLogMessage(CUPSD_LOG_DEBUG
,
713 "Got kIOMessageSystemWillNotPowerOff message.");
715 case kIOMessageSystemWillNotSleep
:
716 cupsdLogMessage(CUPSD_LOG_DEBUG
,
717 "Got kIOMessageSystemWillNotSleep message.");
719 # ifdef kIOMessageSystemWillPowerOn
720 case kIOMessageSystemWillPowerOn
:
721 cupsdLogMessage(CUPSD_LOG_DEBUG
,
722 "Got kIOMessageSystemWillPowerOn message.");
724 # endif /* kIOMessageSystemWillPowerOn */
726 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Got unknown power message %d.",
732 IOAllowPowerChange(threadData
->sysevent
.powerKernelPort
,
733 (long)messageArgument
);
736 threadData
->sysevent
.powerNotificationID
= (long)messageArgument
;
741 * Send the event to the main thread now.
744 write(SysEventPipes
[1], &threadData
->sysevent
,
745 sizeof(threadData
->sysevent
));
746 threadData
->sysevent
.event
= 0;
751 * Send the event to the main thread after 1 to 2 seconds.
754 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
755 CFAbsoluteTimeGetCurrent() + 2);
762 * 'sysEventConfigurationNotifier()' - Network configuration change notification
767 sysEventConfigurationNotifier(
768 SCDynamicStoreRef store
, /* I - System data (unused) */
769 CFArrayRef changedKeys
, /* I - Changed data */
770 void *context
) /* I - Thread context data */
772 cupsd_thread_data_t
*threadData
; /* Thread context data */
775 threadData
= (cupsd_thread_data_t
*)context
;
777 (void)store
; /* anti-compiler-warning-code */
779 CFRange range
= CFRangeMake(0, CFArrayGetCount(changedKeys
));
781 if (CFArrayContainsValue(changedKeys
, range
, ComputerNameKey
) ||
782 CFArrayContainsValue(changedKeys
, range
, BTMMKey
))
783 threadData
->sysevent
.event
|= SYSEVENT_NAMECHANGED
;
786 threadData
->sysevent
.event
|= SYSEVENT_NETCHANGED
;
789 * Indicate the network interface list needs updating...
796 * Because we registered for several different kinds of change notifications
797 * this callback usually gets called several times in a row. We use a timer to
798 * de-bounce these so we only end up generating one event for the main thread.
801 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
802 CFAbsoluteTimeGetCurrent() + 5);
807 * 'sysEventTimerNotifier()' - Handle delayed event notifications.
811 sysEventTimerNotifier(
812 CFRunLoopTimerRef timer
, /* I - Timer information */
813 void *context
) /* I - Thread context data */
815 cupsd_thread_data_t
*threadData
; /* Thread context data */
820 threadData
= (cupsd_thread_data_t
*)context
;
823 * If an event is still pending send it to the main thread.
826 if (threadData
->sysevent
.event
)
828 write(SysEventPipes
[1], &threadData
->sysevent
,
829 sizeof(threadData
->sysevent
));
830 threadData
->sysevent
.event
= 0;
836 * 'sysUpdate()' - Update the current system state.
842 int i
; /* Looping var */
843 cupsd_sysevent_t sysevent
; /* The system event */
844 cupsd_printer_t
*p
; /* Printer information */
848 * Drain the event pipe...
851 while (read((int)SysEventPipes
[0], &sysevent
, sizeof(sysevent
))
854 if (sysevent
.event
& SYSEVENT_CANSLEEP
)
857 * If there are active printers that don't have the connecting-to-device
858 * or cups-waiting-for-job-completed printer-state-reason then cancel the
859 * sleep request, i.e., these reasons indicate a job that is not actively
863 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
865 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
869 for (i
= 0; i
< p
->num_reasons
; i
++)
870 if (!strcmp(p
->reasons
[i
], "connecting-to-device") ||
871 !strcmp(p
->reasons
[i
], "cups-waiting-for-job-completed"))
874 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
881 cupsdLogMessage(CUPSD_LOG_INFO
,
882 "System sleep canceled because printer %s is active.",
884 IOCancelPowerChange(sysevent
.powerKernelPort
,
885 sysevent
.powerNotificationID
);
889 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System wants to sleep.");
890 IOAllowPowerChange(sysevent
.powerKernelPort
,
891 sysevent
.powerNotificationID
);
895 if (sysevent
.event
& SYSEVENT_WILLSLEEP
)
897 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System going to sleep.");
904 * If we have no printing jobs, allow the power change immediately.
905 * Otherwise set the SleepJobs time to 10 seconds in the future when
906 * we'll take more drastic measures...
909 if (cupsArrayCount(PrintingJobs
) == 0)
911 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
912 IOAllowPowerChange(sysevent
.powerKernelPort
,
913 sysevent
.powerNotificationID
);
918 * If there are active printers that don't have the connecting-to-device
919 * or cups-waiting-for-job-completed printer-state-reasons then delay the
920 * sleep request, i.e., these reasons indicate a job is active...
923 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
925 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
929 for (i
= 0; i
< p
->num_reasons
; i
++)
930 if (!strcmp(p
->reasons
[i
], "connecting-to-device") ||
931 !strcmp(p
->reasons
[i
], "cups-waiting-for-job-completed"))
934 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
941 cupsdLogMessage(CUPSD_LOG_INFO
,
942 "System sleep delayed because printer %s is active.",
945 LastSysEvent
= sysevent
;
946 SleepJobs
= time(NULL
) + 10;
950 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
951 IOAllowPowerChange(sysevent
.powerKernelPort
,
952 sysevent
.powerNotificationID
);
957 if (sysevent
.event
& SYSEVENT_WOKE
)
959 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System woke from sleep.");
960 IOAllowPowerChange(sysevent
.powerKernelPort
,
961 sysevent
.powerNotificationID
);
965 * Make sure jobs that were queued prior to the system going to sleep don't
966 * get canceled right away...
971 cupsd_job_t
*job
; /* Current job */
973 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
975 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
977 if (job
->cancel_time
)
979 ipp_attribute_t
*cancel_after
= ippFindAttribute(job
->attrs
,
984 job
->cancel_time
= time(NULL
) + ippGetInteger(cancel_after
, 0);
986 job
->cancel_time
= time(NULL
) + MaxJobTime
;
997 if (sysevent
.event
& SYSEVENT_NETCHANGED
)
1000 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1001 "System network configuration changed - "
1002 "ignored while sleeping.");
1004 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1005 "System network configuration changed.");
1008 if (sysevent
.event
& SYSEVENT_NAMECHANGED
)
1014 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1015 "Computer name or BTMM domains changed - ignored while "
1020 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1021 "Computer name or BTMM domains changed.");
1031 * 'sysUpdateNames()' - Update computer and/or BTMM domains.
1035 sysUpdateNames(void)
1037 cupsd_printer_t
*p
; /* Current printer */
1043 * De-register the individual printers...
1046 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1048 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1049 cupsdDeregisterPrinter(p
, 1);
1051 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1053 * Update the computer name and BTMM domain list...
1056 cupsdUpdateDNSSDName();
1057 # endif /* HAVE_DNSSD || HAVE_AVAHI */
1060 * Now re-register them...
1063 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1065 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1066 cupsdRegisterPrinter(p
);
1068 #endif /* __APPLE__ */