4 * System management functions for the CUPS scheduler.
6 * Copyright 2007-2013 by Apple Inc.
7 * Copyright 2006 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * cupsdCleanDirty() - Write dirty config and state files.
18 * cupsdMarkDirty() - Mark config or state files as needing a
20 * cupsdSetBusyState() - Let the system know when we are busy
22 * cupsdAllowSleep() - Tell the OS it is now OK to sleep.
23 * cupsdStartSystemMonitor() - Start monitoring for system change.
24 * cupsdStopSystemMonitor() - Stop monitoring for system change.
25 * sysEventThreadEntry() - A thread to receive power and computer
26 * name change notifications.
27 * sysEventPowerNotifier() - Handle power notification events.
28 * sysEventConfigurationNotifier() - Computer name changed notification
30 * sysEventTimerNotifier() - Handle delayed event notifications.
31 * sysUpdate() - Update the current system state.
36 * Include necessary headers...
40 #ifdef HAVE_VPROC_TRANSACTION_BEGIN
42 #endif /* HAVE_VPROC_TRANSACTION_BEGIN */
44 # include <IOKit/pwr_mgt/IOPMLib.h>
45 # ifdef HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H
46 # include <IOKit/pwr_mgt/IOPMLibPrivate.h>
47 # endif /* HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H */
48 #endif /* __APPLE__ */
52 * The system management functions cover disk and power management which
53 * are primarily used on portable computers.
55 * Disk management involves delaying the write of certain configuration
56 * and state files to minimize the number of times the disk has to spin
59 * Power management support is currently only implemented on MacOS X, but
60 * essentially we use four functions to let the OS know when it is OK to
61 * put the system to sleep, typically when we are not in the middle of
64 * Once put to sleep, we invalidate all remote printers since it is common
65 * to wake up in a new location/on a new wireless network.
72 #if defined(kIOPMAssertionTypeDenySystemSleep) || defined(kIOPMAssertRemoteAccess)
73 static IOPMAssertionID keep_awake
= 0; /* Keep the system awake while printing */
74 #endif /* kIOPMAssertionTypeDenySystemSleep || kIOPMAssertRemoteAccess */
78 * 'cupsdCleanDirty()' - Write dirty config and state files.
84 if (DirtyFiles
& CUPSD_DIRTY_PRINTERS
)
85 cupsdSaveAllPrinters();
87 if (DirtyFiles
& CUPSD_DIRTY_CLASSES
)
88 cupsdSaveAllClasses();
90 if (DirtyFiles
& CUPSD_DIRTY_PRINTCAP
)
93 if (DirtyFiles
& CUPSD_DIRTY_JOBS
)
95 cupsd_job_t
*job
; /* Current job */
99 for (job
= (cupsd_job_t
*)cupsArrayFirst(Jobs
);
101 job
= (cupsd_job_t
*)cupsArrayNext(Jobs
))
106 if (DirtyFiles
& CUPSD_DIRTY_SUBSCRIPTIONS
)
107 cupsdSaveAllSubscriptions();
109 DirtyFiles
= CUPSD_DIRTY_NONE
;
117 * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
121 cupsdMarkDirty(int what
) /* I - What file(s) are dirty? */
123 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdMarkDirty(%c%c%c%c%c)",
124 (what
& CUPSD_DIRTY_PRINTERS
) ? 'P' : '-',
125 (what
& CUPSD_DIRTY_CLASSES
) ? 'C' : '-',
126 (what
& CUPSD_DIRTY_PRINTCAP
) ? 'p' : '-',
127 (what
& CUPSD_DIRTY_JOBS
) ? 'J' : '-',
128 (what
& CUPSD_DIRTY_SUBSCRIPTIONS
) ? 'S' : '-');
130 if (what
== CUPSD_DIRTY_PRINTCAP
&& !Printcap
)
136 DirtyCleanTime
= time(NULL
) + DirtyCleanInterval
;
143 * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
147 cupsdSetBusyState(void)
149 int i
; /* Looping var */
150 cupsd_job_t
*job
; /* Current job */
151 cupsd_printer_t
*p
; /* Current printer */
152 int newbusy
; /* New busy state */
153 static int busy
= 0; /* Current busy state */
154 static const char * const busy_text
[] =
155 { /* Text for busy states */
159 "Printing jobs and dirty files",
161 "Active clients and dirty files",
162 "Active clients and printing jobs",
163 "Active clients, printing jobs, and dirty files"
165 #ifdef HAVE_VPROC_TRANSACTION_BEGIN
166 static vproc_transaction_t vtran
= 0; /* Current busy transaction */
167 #endif /* HAVE_VPROC_TRANSACTION_BEGIN */
171 * Figure out how busy we are...
174 newbusy
= (DirtyCleanTime
? 1 : 0) |
175 (cupsArrayCount(ActiveClients
) ? 4 : 0);
177 for (job
= (cupsd_job_t
*)cupsArrayFirst(PrintingJobs
);
179 job
= (cupsd_job_t
*)cupsArrayNext(PrintingJobs
))
181 if ((p
= job
->printer
) != NULL
)
183 for (i
= 0; i
< p
->num_reasons
; i
++)
184 if (!strcmp(p
->reasons
[i
], "connecting-to-device"))
187 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
195 cupsdLogMessage(CUPSD_LOG_DEBUG
,
196 "cupsdSetBusyState: newbusy=\"%s\", busy=\"%s\"",
197 busy_text
[newbusy
], busy_text
[busy
]);
200 * Manage state changes...
207 #ifdef HAVE_VPROC_TRANSACTION_BEGIN
209 vtran
= vproc_transaction_begin(NULL
);
210 else if (!busy
&& vtran
)
212 vproc_transaction_end(NULL
, vtran
);
215 #endif /* HAVE_VPROC_TRANSACTION_BEGIN */
218 #if defined(kIOPMAssertionTypeDenySystemSleep) || defined(kIOPMAssertRemoteAccess)
219 if (cupsArrayCount(PrintingJobs
) > 0 && !keep_awake
)
221 # ifdef kIOPMAssertionTypeRemoteAccess
222 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Asserting RemoteAccess.");
224 IOPMAssertionCreateWithName(kIOPMAssertionTypeRemoteAccess
,
225 kIOPMAssertionLevelOn
,
226 CFSTR("org.cups.cupsd"), &keep_awake
);
229 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Asserting DenySystemSleep.");
231 IOPMAssertionCreateWithName(kIOPMAssertionTypeDenySystemSleep
,
232 kIOPMAssertionLevelOn
,
233 CFSTR("org.cups.cupsd"), &keep_awake
);
235 # endif /* kIOPMAssertionTypeRemoteAccess */
237 else if (cupsArrayCount(PrintingJobs
) == 0 && keep_awake
)
239 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Releasing power assertion.");
240 IOPMAssertionRelease(keep_awake
);
243 #endif /* kIOPMAssertionTypeDenySystemSleep || kIOPMAssertionTypeRemoteAccess */
249 * This is the Apple-specific system event code. It works by creating
250 * a worker thread that waits for events from the OS and relays them
251 * to the main thread via a traditional pipe.
255 * Include MacOS-specific headers...
258 # include <IOKit/IOKitLib.h>
259 # include <IOKit/IOMessage.h>
260 # include <IOKit/pwr_mgt/IOPMLib.h>
261 # include <SystemConfiguration/SystemConfiguration.h>
262 # include <pthread.h>
269 # define SYSEVENT_CANSLEEP 0x1 /* Decide whether to allow sleep or not */
270 # define SYSEVENT_WILLSLEEP 0x2 /* Computer will go to sleep */
271 # define SYSEVENT_WOKE 0x4 /* Computer woke from sleep */
272 # define SYSEVENT_NETCHANGED 0x8 /* Network changed */
273 # define SYSEVENT_NAMECHANGED 0x10 /* Computer name changed */
280 typedef struct cupsd_sysevent_s
/*** System event data ****/
282 unsigned char event
; /* Event bit field */
283 io_connect_t powerKernelPort
; /* Power context data */
284 long powerNotificationID
; /* Power event data */
288 typedef struct cupsd_thread_data_s
/*** Thread context data ****/
290 cupsd_sysevent_t sysevent
; /* System event */
291 CFRunLoopTimerRef timerRef
; /* Timer to delay some change *
293 } cupsd_thread_data_t
;
300 static pthread_t SysEventThread
= NULL
;
301 /* Thread to host a runloop */
302 static pthread_mutex_t SysEventThreadMutex
= { 0 };
303 /* Coordinates access to shared gloabals */
304 static pthread_cond_t SysEventThreadCond
= { 0 };
305 /* Thread initialization complete condition */
306 static CFRunLoopRef SysEventRunloop
= NULL
;
307 /* The runloop. Access must be protected! */
308 static CFStringRef ComputerNameKey
= NULL
,
309 /* Computer name key */
310 BTMMKey
= NULL
, /* Back to My Mac key */
311 NetworkGlobalKeyIPv4
= NULL
,
312 /* Network global IPv4 key */
313 NetworkGlobalKeyIPv6
= NULL
,
314 /* Network global IPv6 key */
315 NetworkGlobalKeyDNS
= NULL
,
316 /* Network global DNS key */
319 NetworkInterfaceKeyIPv4
= NULL
,
320 /* Netowrk interface key */
321 NetworkInterfaceKeyIPv6
= NULL
;
322 /* Netowrk interface key */
323 static cupsd_sysevent_t LastSysEvent
; /* Last system event (for delayed sleep) */
330 static void *sysEventThreadEntry(void);
331 static void sysEventPowerNotifier(void *context
, io_service_t service
,
332 natural_t messageType
,
333 void *messageArgument
);
334 static void sysEventConfigurationNotifier(SCDynamicStoreRef store
,
335 CFArrayRef changedKeys
,
337 static void sysEventTimerNotifier(CFRunLoopTimerRef timer
, void *context
);
338 static void sysUpdate(void);
342 * 'cupsdAllowSleep()' - Tell the OS it is now OK to sleep.
346 cupsdAllowSleep(void)
350 IOAllowPowerChange(LastSysEvent
.powerKernelPort
,
351 LastSysEvent
.powerNotificationID
);
356 * 'cupsdStartSystemMonitor()' - Start monitoring for system change.
360 cupsdStartSystemMonitor(void)
362 int flags
; /* fcntl flags on pipe */
365 if (cupsdOpenPipe(SysEventPipes
))
367 cupsdLogMessage(CUPSD_LOG_ERROR
, "System event monitor pipe() failed - %s!",
372 cupsdAddSelect(SysEventPipes
[0], (cupsd_selfunc_t
)sysUpdate
, NULL
, NULL
);
375 * Set non-blocking mode on the descriptor we will be receiving notification
379 flags
= fcntl(SysEventPipes
[0], F_GETFL
, 0);
380 fcntl(SysEventPipes
[0], F_SETFL
, flags
| O_NONBLOCK
);
383 * Start the thread that runs the runloop...
386 pthread_mutex_init(&SysEventThreadMutex
, NULL
);
387 pthread_cond_init(&SysEventThreadCond
, NULL
);
388 pthread_create(&SysEventThread
, NULL
, (void *(*)())sysEventThreadEntry
, NULL
);
393 * 'cupsdStopSystemMonitor()' - Stop monitoring for system change.
397 cupsdStopSystemMonitor(void)
399 CFRunLoopRef rl
; /* The event handler runloop */
405 * Make sure the thread has completed it's initialization and
406 * stored it's runloop reference in the shared global.
409 pthread_mutex_lock(&SysEventThreadMutex
);
411 if (!SysEventRunloop
)
412 pthread_cond_wait(&SysEventThreadCond
, &SysEventThreadMutex
);
414 rl
= SysEventRunloop
;
415 SysEventRunloop
= NULL
;
417 pthread_mutex_unlock(&SysEventThreadMutex
);
422 pthread_join(SysEventThread
, NULL
);
423 pthread_mutex_destroy(&SysEventThreadMutex
);
424 pthread_cond_destroy(&SysEventThreadCond
);
427 if (SysEventPipes
[0] >= 0)
429 cupsdRemoveSelect(SysEventPipes
[0]);
430 cupsdClosePipe(SysEventPipes
);
436 * 'sysEventThreadEntry()' - A thread to receive power and computer name
437 * change notifications.
440 static void * /* O - Return status/value */
441 sysEventThreadEntry(void)
443 io_object_t powerNotifierObj
;
444 /* Power notifier object */
445 IONotificationPortRef powerNotifierPort
;
446 /* Power notifier port */
447 SCDynamicStoreRef store
= NULL
;/* System Config dynamic store */
448 CFRunLoopSourceRef powerRLS
= NULL
,/* Power runloop source */
449 storeRLS
= NULL
;/* System Config runloop source */
450 CFStringRef key
[6], /* System Config keys */
451 pattern
[2]; /* System Config patterns */
452 CFArrayRef keys
= NULL
, /* System Config key array*/
453 patterns
= NULL
;/* System Config pattern array */
454 SCDynamicStoreContext storeContext
; /* Dynamic store context */
455 CFRunLoopTimerContext timerContext
; /* Timer context */
456 cupsd_thread_data_t threadData
; /* Thread context data for the *
457 * runloop notifiers */
461 * Register for power state change notifications
464 bzero(&threadData
, sizeof(threadData
));
466 threadData
.sysevent
.powerKernelPort
=
467 IORegisterForSystemPower(&threadData
, &powerNotifierPort
,
468 sysEventPowerNotifier
, &powerNotifierObj
);
470 if (threadData
.sysevent
.powerKernelPort
)
472 powerRLS
= IONotificationPortGetRunLoopSource(powerNotifierPort
);
473 CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRLS
, kCFRunLoopDefaultMode
);
476 DEBUG_puts("sysEventThreadEntry: error registering for system power "
480 * Register for system configuration change notifications
483 bzero(&storeContext
, sizeof(storeContext
));
484 storeContext
.info
= &threadData
;
486 store
= SCDynamicStoreCreate(kCFAllocatorDefault
, CFSTR("cupsd"),
487 sysEventConfigurationNotifier
, &storeContext
);
489 if (!ComputerNameKey
)
490 ComputerNameKey
= SCDynamicStoreKeyCreateComputerName(kCFAllocatorDefault
);
493 BTMMKey
= SCDynamicStoreKeyCreate(kCFAllocatorDefault
,
494 CFSTR("Setup:/Network/BackToMyMac"));
496 if (!NetworkGlobalKeyIPv4
)
497 NetworkGlobalKeyIPv4
=
498 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
499 kSCDynamicStoreDomainState
,
502 if (!NetworkGlobalKeyIPv6
)
503 NetworkGlobalKeyIPv6
=
504 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
505 kSCDynamicStoreDomainState
,
508 if (!NetworkGlobalKeyDNS
)
509 NetworkGlobalKeyDNS
=
510 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
511 kSCDynamicStoreDomainState
,
515 HostNamesKey
= SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault
);
517 if (!NetworkInterfaceKeyIPv4
)
518 NetworkInterfaceKeyIPv4
=
519 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
520 kSCDynamicStoreDomainState
,
524 if (!NetworkInterfaceKeyIPv6
)
525 NetworkInterfaceKeyIPv6
=
526 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
527 kSCDynamicStoreDomainState
,
531 if (store
&& ComputerNameKey
&& HostNamesKey
&&
532 NetworkGlobalKeyIPv4
&& NetworkGlobalKeyIPv6
&& NetworkGlobalKeyDNS
&&
533 NetworkInterfaceKeyIPv4
&& NetworkInterfaceKeyIPv6
)
535 key
[0] = ComputerNameKey
;
537 key
[2] = NetworkGlobalKeyIPv4
;
538 key
[3] = NetworkGlobalKeyIPv6
;
539 key
[4] = NetworkGlobalKeyDNS
;
540 key
[5] = HostNamesKey
;
542 pattern
[0] = NetworkInterfaceKeyIPv4
;
543 pattern
[1] = NetworkInterfaceKeyIPv6
;
545 keys
= CFArrayCreate(kCFAllocatorDefault
, (const void **)key
,
546 sizeof(key
) / sizeof(key
[0]),
547 &kCFTypeArrayCallBacks
);
549 patterns
= CFArrayCreate(kCFAllocatorDefault
, (const void **)pattern
,
550 sizeof(pattern
) / sizeof(pattern
[0]),
551 &kCFTypeArrayCallBacks
);
553 if (keys
&& patterns
&&
554 SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
556 if ((storeRLS
= SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault
,
559 CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS
,
560 kCFRunLoopDefaultMode
);
563 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreateRunLoopSource "
564 "failed: %s\n", SCErrorString(SCError())));
567 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreSetNotificationKeys "
568 "failed: %s\n", SCErrorString(SCError())));
571 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreate failed: %s\n",
572 SCErrorString(SCError())));
581 * Set up a timer to delay the wake change notifications.
583 * The initial time is set a decade or so into the future, we'll adjust
587 bzero(&timerContext
, sizeof(timerContext
));
588 timerContext
.info
= &threadData
;
590 threadData
.timerRef
=
591 CFRunLoopTimerCreate(kCFAllocatorDefault
,
592 CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
593 86400L * 365L * 10L, 0, 0, sysEventTimerNotifier
,
595 CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
596 kCFRunLoopDefaultMode
);
599 * Store our runloop in a global so the main thread can use it to stop us.
602 pthread_mutex_lock(&SysEventThreadMutex
);
604 SysEventRunloop
= CFRunLoopGetCurrent();
606 pthread_cond_signal(&SysEventThreadCond
);
607 pthread_mutex_unlock(&SysEventThreadMutex
);
610 * Disappear into the runloop until it's stopped by the main thread.
616 * Clean up before exiting.
619 if (threadData
.timerRef
)
621 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
622 kCFRunLoopDefaultMode
);
623 CFRelease(threadData
.timerRef
);
626 if (threadData
.sysevent
.powerKernelPort
)
628 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS
,
629 kCFRunLoopDefaultMode
);
630 IODeregisterForSystemPower(&powerNotifierObj
);
631 IOServiceClose(threadData
.sysevent
.powerKernelPort
);
632 IONotificationPortDestroy(powerNotifierPort
);
637 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS
,
638 kCFRunLoopDefaultMode
);
639 CFRunLoopSourceInvalidate(storeRLS
);
651 * 'sysEventPowerNotifier()' - Handle power notification events.
655 sysEventPowerNotifier(
656 void *context
, /* I - Thread context data */
657 io_service_t service
, /* I - Unused service info */
658 natural_t messageType
, /* I - Type of message */
659 void *messageArgument
) /* I - Message data */
661 int sendit
= 1; /* Send event to main thread? *
662 * (0 = no, 1 = yes, 2 = delayed */
663 cupsd_thread_data_t
*threadData
; /* Thread context data */
666 threadData
= (cupsd_thread_data_t
*)context
;
668 (void)service
; /* anti-compiler-warning-code */
672 case kIOMessageCanSystemPowerOff
:
673 case kIOMessageCanSystemSleep
:
674 threadData
->sysevent
.event
|= SYSEVENT_CANSLEEP
;
677 case kIOMessageSystemWillRestart
:
678 case kIOMessageSystemWillPowerOff
:
679 case kIOMessageSystemWillSleep
:
680 threadData
->sysevent
.event
|= SYSEVENT_WILLSLEEP
;
683 case kIOMessageSystemHasPoweredOn
:
685 * Because powered on is followed by a net-changed event, delay
690 threadData
->sysevent
.event
|= SYSEVENT_WOKE
;
693 case kIOMessageSystemWillNotPowerOff
:
694 case kIOMessageSystemWillNotSleep
:
695 # ifdef kIOMessageSystemWillPowerOn
696 case kIOMessageSystemWillPowerOn
:
697 # endif /* kIOMessageSystemWillPowerOn */
704 IOAllowPowerChange(threadData
->sysevent
.powerKernelPort
,
705 (long)messageArgument
);
708 threadData
->sysevent
.powerNotificationID
= (long)messageArgument
;
713 * Send the event to the main thread now.
716 write(SysEventPipes
[1], &threadData
->sysevent
,
717 sizeof(threadData
->sysevent
));
718 threadData
->sysevent
.event
= 0;
723 * Send the event to the main thread after 1 to 2 seconds.
726 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
727 CFAbsoluteTimeGetCurrent() + 2);
734 * 'sysEventConfigurationNotifier()' - Network configuration change notification
739 sysEventConfigurationNotifier(
740 SCDynamicStoreRef store
, /* I - System data (unused) */
741 CFArrayRef changedKeys
, /* I - Changed data */
742 void *context
) /* I - Thread context data */
744 cupsd_thread_data_t
*threadData
; /* Thread context data */
747 threadData
= (cupsd_thread_data_t
*)context
;
749 (void)store
; /* anti-compiler-warning-code */
751 CFRange range
= CFRangeMake(0, CFArrayGetCount(changedKeys
));
753 if (CFArrayContainsValue(changedKeys
, range
, ComputerNameKey
) ||
754 CFArrayContainsValue(changedKeys
, range
, BTMMKey
))
755 threadData
->sysevent
.event
|= SYSEVENT_NAMECHANGED
;
758 threadData
->sysevent
.event
|= SYSEVENT_NETCHANGED
;
761 * Indicate the network interface list needs updating...
768 * Because we registered for several different kinds of change notifications
769 * this callback usually gets called several times in a row. We use a timer to
770 * de-bounce these so we only end up generating one event for the main thread.
773 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
774 CFAbsoluteTimeGetCurrent() + 5);
779 * 'sysEventTimerNotifier()' - Handle delayed event notifications.
783 sysEventTimerNotifier(
784 CFRunLoopTimerRef timer
, /* I - Timer information */
785 void *context
) /* I - Thread context data */
787 cupsd_thread_data_t
*threadData
; /* Thread context data */
792 threadData
= (cupsd_thread_data_t
*)context
;
795 * If an event is still pending send it to the main thread.
798 if (threadData
->sysevent
.event
)
800 write(SysEventPipes
[1], &threadData
->sysevent
,
801 sizeof(threadData
->sysevent
));
802 threadData
->sysevent
.event
= 0;
808 * 'sysUpdate()' - Update the current system state.
814 int i
; /* Looping var */
815 cupsd_sysevent_t sysevent
; /* The system event */
816 cupsd_printer_t
*p
; /* Printer information */
820 * Drain the event pipe...
823 while (read((int)SysEventPipes
[0], &sysevent
, sizeof(sysevent
))
826 if (sysevent
.event
& SYSEVENT_CANSLEEP
)
829 * If there are active printers that don't have the connecting-to-device
830 * printer-state-reason then cancel the sleep request (i.e. this reason
831 * indicates a job that is not yet connected to the printer)...
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"))
844 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
851 cupsdLogMessage(CUPSD_LOG_INFO
,
852 "System sleep canceled because printer %s is active",
854 IOCancelPowerChange(sysevent
.powerKernelPort
,
855 sysevent
.powerNotificationID
);
859 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System wants to sleep");
860 IOAllowPowerChange(sysevent
.powerKernelPort
,
861 sysevent
.powerNotificationID
);
865 if (sysevent
.event
& SYSEVENT_WILLSLEEP
)
867 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System going to sleep");
871 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
873 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
875 cupsdLogMessage(CUPSD_LOG_DEBUG
,
876 "Deregistering local printer \"%s\"", p
->name
);
877 cupsdDeregisterPrinter(p
, 0);
882 #ifdef kIOPMAssertionTypeDenySystemSleep
884 * Remove our assertion as needed since the user wants the system to
885 * sleep (different than idle sleep)...
890 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Releasing dark wake assertion.");
891 IOPMAssertionRelease(keep_awake
);
894 #endif /* kIOPMAssertionTypeDenySystemSleep */
897 * If we have no printing jobs, allow the power change immediately.
898 * Otherwise set the SleepJobs time to 15 seconds in the future when
899 * we'll take more drastic measures...
902 if (cupsArrayCount(PrintingJobs
) == 0)
903 IOAllowPowerChange(sysevent
.powerKernelPort
,
904 sysevent
.powerNotificationID
);
908 * If there are active printers that don't have the connecting-to-device
909 * printer-state-reason then delay the sleep request (i.e. this reason
910 * indicates a job that is not yet connected to the printer)...
913 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
915 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
919 for (i
= 0; i
< p
->num_reasons
; i
++)
920 if (!strcmp(p
->reasons
[i
], "connecting-to-device"))
923 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
930 LastSysEvent
= sysevent
;
931 SleepJobs
= time(NULL
) + 10;
935 IOAllowPowerChange(sysevent
.powerKernelPort
,
936 sysevent
.powerNotificationID
);
941 if (sysevent
.event
& SYSEVENT_WOKE
)
943 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System woke from sleep");
944 IOAllowPowerChange(sysevent
.powerKernelPort
,
945 sysevent
.powerNotificationID
);
948 #ifdef kIOPMAssertionTypeDenySystemSleep
949 if (cupsArrayCount(PrintingJobs
) > 0 && !keep_awake
)
951 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Asserting dark wake.");
952 IOPMAssertionCreateWithName(kIOPMAssertionTypeDenySystemSleep
,
953 kIOPMAssertionLevelOn
,
954 CFSTR("org.cups.cupsd"), &keep_awake
);
956 #endif /* kIOPMAssertionTypeDenySystemSleep */
961 if (sysevent
.event
& SYSEVENT_NETCHANGED
)
964 cupsdLogMessage(CUPSD_LOG_DEBUG
,
965 "System network configuration changed");
967 cupsdLogMessage(CUPSD_LOG_DEBUG
,
968 "System network configuration changed; "
969 "ignored while sleeping");
972 if (sysevent
.event
& SYSEVENT_NAMECHANGED
)
976 cupsdLogMessage(CUPSD_LOG_DEBUG
,
977 "Computer name or BTMM domains changed");
980 * De-register the individual printers...
983 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
985 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
986 cupsdDeregisterPrinter(p
, 1);
988 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
990 * Update the computer name and BTMM domain list...
993 cupsdUpdateDNSSDName();
994 # endif /* HAVE_DNSSD || HAVE_AVAHI */
997 * Now re-register them...
1000 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1002 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1003 cupsdRegisterPrinter(p
);
1006 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1007 "Computer name or BTMM domains changed; ignored while "
1012 #endif /* __APPLE__ */