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/".
18 * Include necessary headers...
22 #ifdef HAVE_VPROC_TRANSACTION_BEGIN
24 #endif /* HAVE_VPROC_TRANSACTION_BEGIN */
26 # include <IOKit/pwr_mgt/IOPMLib.h>
27 #endif /* __APPLE__ */
31 * The system management functions cover disk and power management which
32 * are primarily used on portable computers.
34 * Disk management involves delaying the write of certain configuration
35 * and state files to minimize the number of times the disk has to spin
38 * Power management support is currently only implemented on OS X, but
39 * essentially we use four functions to let the OS know when it is OK to
40 * put the system to sleep, typically when we are not in the middle of
43 * Once put to sleep, we invalidate all remote printers since it is common
44 * to wake up in a new location/on a new wireless network.
48 * 'cupsdCleanDirty()' - Write dirty config and state files.
54 if (DirtyFiles
& CUPSD_DIRTY_PRINTERS
)
55 cupsdSaveAllPrinters();
57 if (DirtyFiles
& CUPSD_DIRTY_CLASSES
)
58 cupsdSaveAllClasses();
60 if (DirtyFiles
& CUPSD_DIRTY_PRINTCAP
)
63 if (DirtyFiles
& CUPSD_DIRTY_JOBS
)
65 cupsd_job_t
*job
; /* Current job */
69 for (job
= (cupsd_job_t
*)cupsArrayFirst(Jobs
);
71 job
= (cupsd_job_t
*)cupsArrayNext(Jobs
))
76 if (DirtyFiles
& CUPSD_DIRTY_SUBSCRIPTIONS
)
77 cupsdSaveAllSubscriptions();
79 DirtyFiles
= CUPSD_DIRTY_NONE
;
87 * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
91 cupsdMarkDirty(int what
) /* I - What file(s) are dirty? */
93 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdMarkDirty(%c%c%c%c%c)",
94 (what
& CUPSD_DIRTY_PRINTERS
) ? 'P' : '-',
95 (what
& CUPSD_DIRTY_CLASSES
) ? 'C' : '-',
96 (what
& CUPSD_DIRTY_PRINTCAP
) ? 'p' : '-',
97 (what
& CUPSD_DIRTY_JOBS
) ? 'J' : '-',
98 (what
& CUPSD_DIRTY_SUBSCRIPTIONS
) ? 'S' : '-');
100 if (what
== CUPSD_DIRTY_PRINTCAP
&& !Printcap
)
106 DirtyCleanTime
= time(NULL
) + DirtyCleanInterval
;
113 * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
117 cupsdSetBusyState(void)
119 int i
; /* Looping var */
120 cupsd_job_t
*job
; /* Current job */
121 cupsd_printer_t
*p
; /* Current printer */
122 int newbusy
; /* New busy state */
123 static int busy
= 0; /* Current busy state */
124 static const char * const busy_text
[] =
125 { /* Text for busy states */
129 "Printing jobs and dirty files",
131 "Active clients and dirty files",
132 "Active clients and printing jobs",
133 "Active clients, printing jobs, and dirty files"
135 #ifdef HAVE_VPROC_TRANSACTION_BEGIN
136 static vproc_transaction_t vtran
= 0; /* Current busy transaction */
137 #endif /* HAVE_VPROC_TRANSACTION_BEGIN */
141 * Figure out how busy we are...
144 newbusy
= (DirtyCleanTime
? 1 : 0) |
145 (cupsArrayCount(ActiveClients
) ? 4 : 0);
147 for (job
= (cupsd_job_t
*)cupsArrayFirst(PrintingJobs
);
149 job
= (cupsd_job_t
*)cupsArrayNext(PrintingJobs
))
151 if ((p
= job
->printer
) != NULL
)
153 for (i
= 0; i
< p
->num_reasons
; i
++)
154 if (!strcmp(p
->reasons
[i
], "connecting-to-device"))
157 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
165 cupsdLogMessage(CUPSD_LOG_DEBUG
,
166 "cupsdSetBusyState: newbusy=\"%s\", busy=\"%s\"",
167 busy_text
[newbusy
], busy_text
[busy
]);
170 * Manage state changes...
177 #ifdef HAVE_VPROC_TRANSACTION_BEGIN
179 vtran
= vproc_transaction_begin(NULL
);
180 else if (!busy
&& vtran
)
182 vproc_transaction_end(NULL
, vtran
);
185 #endif /* HAVE_VPROC_TRANSACTION_BEGIN */
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...
201 # include <IOKit/IOKitLib.h>
202 # include <IOKit/IOMessage.h>
203 # include <IOKit/pwr_mgt/IOPMLib.h>
204 # include <SystemConfiguration/SystemConfiguration.h>
205 # include <pthread.h>
212 # define SYSEVENT_CANSLEEP 0x1 /* Decide whether to allow sleep or not */
213 # define SYSEVENT_WILLSLEEP 0x2 /* Computer will go to sleep */
214 # define SYSEVENT_WOKE 0x4 /* Computer woke from sleep */
215 # define SYSEVENT_NETCHANGED 0x8 /* Network changed */
216 # define SYSEVENT_NAMECHANGED 0x10 /* Computer name changed */
223 typedef struct cupsd_sysevent_s
/*** System event data ****/
225 unsigned char event
; /* Event bit field */
226 io_connect_t powerKernelPort
; /* Power context data */
227 long powerNotificationID
; /* Power event data */
231 typedef struct cupsd_thread_data_s
/*** Thread context data ****/
233 cupsd_sysevent_t sysevent
; /* System event */
234 CFRunLoopTimerRef timerRef
; /* Timer to delay some change *
236 } cupsd_thread_data_t
;
243 static pthread_t SysEventThread
= NULL
;
244 /* Thread to host a runloop */
245 static pthread_mutex_t SysEventThreadMutex
= { 0 };
246 /* Coordinates access to shared gloabals */
247 static pthread_cond_t SysEventThreadCond
= { 0 };
248 /* Thread initialization complete condition */
249 static CFRunLoopRef SysEventRunloop
= NULL
;
250 /* The runloop. Access must be protected! */
251 static CFStringRef ComputerNameKey
= NULL
,
252 /* Computer name key */
253 BTMMKey
= NULL
, /* Back to My Mac key */
254 NetworkGlobalKeyIPv4
= NULL
,
255 /* Network global IPv4 key */
256 NetworkGlobalKeyIPv6
= NULL
,
257 /* Network global IPv6 key */
258 NetworkGlobalKeyDNS
= NULL
,
259 /* Network global DNS key */
262 NetworkInterfaceKeyIPv4
= NULL
,
263 /* Netowrk interface key */
264 NetworkInterfaceKeyIPv6
= NULL
;
265 /* Netowrk interface key */
266 static cupsd_sysevent_t LastSysEvent
; /* Last system event (for delayed sleep) */
267 static int NameChanged
= 0;/* Did we get a 'name changed' event during sleep? */
274 static void *sysEventThreadEntry(void);
275 static void sysEventPowerNotifier(void *context
, io_service_t service
,
276 natural_t messageType
,
277 void *messageArgument
);
278 static void sysEventConfigurationNotifier(SCDynamicStoreRef store
,
279 CFArrayRef changedKeys
,
281 static void sysEventTimerNotifier(CFRunLoopTimerRef timer
, void *context
);
282 static void sysUpdate(void);
283 static void sysUpdateNames(void);
287 * 'cupsdAllowSleep()' - Tell the OS it is now OK to sleep.
291 cupsdAllowSleep(void)
295 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
296 IOAllowPowerChange(LastSysEvent
.powerKernelPort
,
297 LastSysEvent
.powerNotificationID
);
302 * 'cupsdStartSystemMonitor()' - Start monitoring for system change.
306 cupsdStartSystemMonitor(void)
308 int flags
; /* fcntl flags on pipe */
311 if (cupsdOpenPipe(SysEventPipes
))
313 cupsdLogMessage(CUPSD_LOG_ERROR
, "System event monitor pipe() failed - %s!",
318 cupsdAddSelect(SysEventPipes
[0], (cupsd_selfunc_t
)sysUpdate
, NULL
, NULL
);
321 * Set non-blocking mode on the descriptor we will be receiving notification
325 flags
= fcntl(SysEventPipes
[0], F_GETFL
, 0);
326 fcntl(SysEventPipes
[0], F_SETFL
, flags
| O_NONBLOCK
);
329 * Start the thread that runs the runloop...
332 pthread_mutex_init(&SysEventThreadMutex
, NULL
);
333 pthread_cond_init(&SysEventThreadCond
, NULL
);
334 pthread_create(&SysEventThread
, NULL
, (void *(*)())sysEventThreadEntry
, NULL
);
339 * 'cupsdStopSystemMonitor()' - Stop monitoring for system change.
343 cupsdStopSystemMonitor(void)
345 CFRunLoopRef rl
; /* The event handler runloop */
351 * Make sure the thread has completed it's initialization and
352 * stored it's runloop reference in the shared global.
355 pthread_mutex_lock(&SysEventThreadMutex
);
357 if (!SysEventRunloop
)
358 pthread_cond_wait(&SysEventThreadCond
, &SysEventThreadMutex
);
360 rl
= SysEventRunloop
;
361 SysEventRunloop
= NULL
;
363 pthread_mutex_unlock(&SysEventThreadMutex
);
368 pthread_join(SysEventThread
, NULL
);
369 pthread_mutex_destroy(&SysEventThreadMutex
);
370 pthread_cond_destroy(&SysEventThreadCond
);
373 if (SysEventPipes
[0] >= 0)
375 cupsdRemoveSelect(SysEventPipes
[0]);
376 cupsdClosePipe(SysEventPipes
);
382 * 'sysEventThreadEntry()' - A thread to receive power and computer name
383 * change notifications.
386 static void * /* O - Return status/value */
387 sysEventThreadEntry(void)
389 io_object_t powerNotifierObj
;
390 /* Power notifier object */
391 IONotificationPortRef powerNotifierPort
;
392 /* Power notifier port */
393 SCDynamicStoreRef store
= NULL
;/* System Config dynamic store */
394 CFRunLoopSourceRef powerRLS
= NULL
,/* Power runloop source */
395 storeRLS
= NULL
;/* System Config runloop source */
396 CFStringRef key
[6], /* System Config keys */
397 pattern
[2]; /* System Config patterns */
398 CFArrayRef keys
= NULL
, /* System Config key array*/
399 patterns
= NULL
;/* System Config pattern array */
400 SCDynamicStoreContext storeContext
; /* Dynamic store context */
401 CFRunLoopTimerContext timerContext
; /* Timer context */
402 cupsd_thread_data_t threadData
; /* Thread context data for the *
403 * runloop notifiers */
407 * Register for power state change notifications
410 bzero(&threadData
, sizeof(threadData
));
412 threadData
.sysevent
.powerKernelPort
=
413 IORegisterForSystemPower(&threadData
, &powerNotifierPort
,
414 sysEventPowerNotifier
, &powerNotifierObj
);
416 if (threadData
.sysevent
.powerKernelPort
)
418 powerRLS
= IONotificationPortGetRunLoopSource(powerNotifierPort
);
419 CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRLS
, kCFRunLoopDefaultMode
);
422 DEBUG_puts("sysEventThreadEntry: error registering for system power "
426 * Register for system configuration change notifications
429 bzero(&storeContext
, sizeof(storeContext
));
430 storeContext
.info
= &threadData
;
432 store
= SCDynamicStoreCreate(kCFAllocatorDefault
, CFSTR("cupsd"),
433 sysEventConfigurationNotifier
, &storeContext
);
435 if (!ComputerNameKey
)
436 ComputerNameKey
= SCDynamicStoreKeyCreateComputerName(kCFAllocatorDefault
);
439 BTMMKey
= SCDynamicStoreKeyCreate(kCFAllocatorDefault
,
440 CFSTR("Setup:/Network/BackToMyMac"));
442 if (!NetworkGlobalKeyIPv4
)
443 NetworkGlobalKeyIPv4
=
444 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
445 kSCDynamicStoreDomainState
,
448 if (!NetworkGlobalKeyIPv6
)
449 NetworkGlobalKeyIPv6
=
450 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
451 kSCDynamicStoreDomainState
,
454 if (!NetworkGlobalKeyDNS
)
455 NetworkGlobalKeyDNS
=
456 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
457 kSCDynamicStoreDomainState
,
461 HostNamesKey
= SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault
);
463 if (!NetworkInterfaceKeyIPv4
)
464 NetworkInterfaceKeyIPv4
=
465 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
466 kSCDynamicStoreDomainState
,
470 if (!NetworkInterfaceKeyIPv6
)
471 NetworkInterfaceKeyIPv6
=
472 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
473 kSCDynamicStoreDomainState
,
477 if (store
&& ComputerNameKey
&& HostNamesKey
&&
478 NetworkGlobalKeyIPv4
&& NetworkGlobalKeyIPv6
&& NetworkGlobalKeyDNS
&&
479 NetworkInterfaceKeyIPv4
&& NetworkInterfaceKeyIPv6
)
481 key
[0] = ComputerNameKey
;
483 key
[2] = NetworkGlobalKeyIPv4
;
484 key
[3] = NetworkGlobalKeyIPv6
;
485 key
[4] = NetworkGlobalKeyDNS
;
486 key
[5] = HostNamesKey
;
488 pattern
[0] = NetworkInterfaceKeyIPv4
;
489 pattern
[1] = NetworkInterfaceKeyIPv6
;
491 keys
= CFArrayCreate(kCFAllocatorDefault
, (const void **)key
,
492 sizeof(key
) / sizeof(key
[0]),
493 &kCFTypeArrayCallBacks
);
495 patterns
= CFArrayCreate(kCFAllocatorDefault
, (const void **)pattern
,
496 sizeof(pattern
) / sizeof(pattern
[0]),
497 &kCFTypeArrayCallBacks
);
499 if (keys
&& patterns
&&
500 SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
502 if ((storeRLS
= SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault
,
505 CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS
,
506 kCFRunLoopDefaultMode
);
509 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreateRunLoopSource "
510 "failed: %s\n", SCErrorString(SCError())));
513 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreSetNotificationKeys "
514 "failed: %s\n", SCErrorString(SCError())));
517 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreate failed: %s\n",
518 SCErrorString(SCError())));
527 * Set up a timer to delay the wake change notifications.
529 * The initial time is set a decade or so into the future, we'll adjust
533 bzero(&timerContext
, sizeof(timerContext
));
534 timerContext
.info
= &threadData
;
536 threadData
.timerRef
=
537 CFRunLoopTimerCreate(kCFAllocatorDefault
,
538 CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
539 86400L * 365L * 10L, 0, 0, sysEventTimerNotifier
,
541 CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
542 kCFRunLoopDefaultMode
);
545 * Store our runloop in a global so the main thread can use it to stop us.
548 pthread_mutex_lock(&SysEventThreadMutex
);
550 SysEventRunloop
= CFRunLoopGetCurrent();
552 pthread_cond_signal(&SysEventThreadCond
);
553 pthread_mutex_unlock(&SysEventThreadMutex
);
556 * Disappear into the runloop until it's stopped by the main thread.
562 * Clean up before exiting.
565 if (threadData
.timerRef
)
567 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
568 kCFRunLoopDefaultMode
);
569 CFRelease(threadData
.timerRef
);
572 if (threadData
.sysevent
.powerKernelPort
)
574 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS
,
575 kCFRunLoopDefaultMode
);
576 IODeregisterForSystemPower(&powerNotifierObj
);
577 IOServiceClose(threadData
.sysevent
.powerKernelPort
);
578 IONotificationPortDestroy(powerNotifierPort
);
583 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS
,
584 kCFRunLoopDefaultMode
);
585 CFRunLoopSourceInvalidate(storeRLS
);
597 * 'sysEventPowerNotifier()' - Handle power notification events.
601 sysEventPowerNotifier(
602 void *context
, /* I - Thread context data */
603 io_service_t service
, /* I - Unused service info */
604 natural_t messageType
, /* I - Type of message */
605 void *messageArgument
) /* I - Message data */
607 int sendit
= 1; /* Send event to main thread? *
608 * (0 = no, 1 = yes, 2 = delayed */
609 cupsd_thread_data_t
*threadData
; /* Thread context data */
612 threadData
= (cupsd_thread_data_t
*)context
;
614 (void)service
; /* anti-compiler-warning-code */
618 case kIOMessageCanSystemPowerOff
:
619 case kIOMessageCanSystemSleep
:
620 threadData
->sysevent
.event
|= SYSEVENT_CANSLEEP
;
623 case kIOMessageSystemWillRestart
:
624 case kIOMessageSystemWillPowerOff
:
625 case kIOMessageSystemWillSleep
:
626 threadData
->sysevent
.event
|= SYSEVENT_WILLSLEEP
;
627 threadData
->sysevent
.event
&= ~SYSEVENT_WOKE
;
630 case kIOMessageSystemHasPoweredOn
:
632 * Because powered on is followed by a net-changed event, delay
637 threadData
->sysevent
.event
|= SYSEVENT_WOKE
;
640 case kIOMessageSystemWillNotPowerOff
:
641 case kIOMessageSystemWillNotSleep
:
642 # ifdef kIOMessageSystemWillPowerOn
643 case kIOMessageSystemWillPowerOn
:
644 # endif /* kIOMessageSystemWillPowerOn */
652 case kIOMessageCanSystemPowerOff
:
653 cupsdLogMessage(CUPSD_LOG_DEBUG
,
654 "Got kIOMessageCanSystemPowerOff message.");
656 case kIOMessageCanSystemSleep
:
657 cupsdLogMessage(CUPSD_LOG_DEBUG
,
658 "Got kIOMessageCannSystemSleep message.");
660 case kIOMessageSystemWillRestart
:
661 cupsdLogMessage(CUPSD_LOG_DEBUG
,
662 "Got kIOMessageSystemWillRestart message.");
664 case kIOMessageSystemWillPowerOff
:
665 cupsdLogMessage(CUPSD_LOG_DEBUG
,
666 "Got kIOMessageSystemWillPowerOff message.");
668 case kIOMessageSystemWillSleep
:
669 cupsdLogMessage(CUPSD_LOG_DEBUG
,
670 "Got kIOMessageSystemWillSleep message.");
672 case kIOMessageSystemHasPoweredOn
:
673 cupsdLogMessage(CUPSD_LOG_DEBUG
,
674 "Got kIOMessageSystemHasPoweredOn message.");
676 case kIOMessageSystemWillNotPowerOff
:
677 cupsdLogMessage(CUPSD_LOG_DEBUG
,
678 "Got kIOMessageSystemWillNotPowerOff message.");
680 case kIOMessageSystemWillNotSleep
:
681 cupsdLogMessage(CUPSD_LOG_DEBUG
,
682 "Got kIOMessageSystemWillNotSleep message.");
684 # ifdef kIOMessageSystemWillPowerOn
685 case kIOMessageSystemWillPowerOn
:
686 cupsdLogMessage(CUPSD_LOG_DEBUG
,
687 "Got kIOMessageSystemWillPowerOn message.");
689 # endif /* kIOMessageSystemWillPowerOn */
691 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Got unknown power message %d.",
697 IOAllowPowerChange(threadData
->sysevent
.powerKernelPort
,
698 (long)messageArgument
);
701 threadData
->sysevent
.powerNotificationID
= (long)messageArgument
;
706 * Send the event to the main thread now.
709 write(SysEventPipes
[1], &threadData
->sysevent
,
710 sizeof(threadData
->sysevent
));
711 threadData
->sysevent
.event
= 0;
716 * Send the event to the main thread after 1 to 2 seconds.
719 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
720 CFAbsoluteTimeGetCurrent() + 2);
727 * 'sysEventConfigurationNotifier()' - Network configuration change notification
732 sysEventConfigurationNotifier(
733 SCDynamicStoreRef store
, /* I - System data (unused) */
734 CFArrayRef changedKeys
, /* I - Changed data */
735 void *context
) /* I - Thread context data */
737 cupsd_thread_data_t
*threadData
; /* Thread context data */
740 threadData
= (cupsd_thread_data_t
*)context
;
742 (void)store
; /* anti-compiler-warning-code */
744 CFRange range
= CFRangeMake(0, CFArrayGetCount(changedKeys
));
746 if (CFArrayContainsValue(changedKeys
, range
, ComputerNameKey
) ||
747 CFArrayContainsValue(changedKeys
, range
, BTMMKey
))
748 threadData
->sysevent
.event
|= SYSEVENT_NAMECHANGED
;
751 threadData
->sysevent
.event
|= SYSEVENT_NETCHANGED
;
754 * Indicate the network interface list needs updating...
761 * Because we registered for several different kinds of change notifications
762 * this callback usually gets called several times in a row. We use a timer to
763 * de-bounce these so we only end up generating one event for the main thread.
766 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
767 CFAbsoluteTimeGetCurrent() + 5);
772 * 'sysEventTimerNotifier()' - Handle delayed event notifications.
776 sysEventTimerNotifier(
777 CFRunLoopTimerRef timer
, /* I - Timer information */
778 void *context
) /* I - Thread context data */
780 cupsd_thread_data_t
*threadData
; /* Thread context data */
785 threadData
= (cupsd_thread_data_t
*)context
;
788 * If an event is still pending send it to the main thread.
791 if (threadData
->sysevent
.event
)
793 write(SysEventPipes
[1], &threadData
->sysevent
,
794 sizeof(threadData
->sysevent
));
795 threadData
->sysevent
.event
= 0;
801 * 'sysUpdate()' - Update the current system state.
807 int i
; /* Looping var */
808 cupsd_sysevent_t sysevent
; /* The system event */
809 cupsd_printer_t
*p
; /* Printer information */
813 * Drain the event pipe...
816 while (read((int)SysEventPipes
[0], &sysevent
, sizeof(sysevent
))
819 if (sysevent
.event
& SYSEVENT_CANSLEEP
)
822 * If there are active printers that don't have the connecting-to-device
823 * or cups-waiting-for-completed printer-state-reason then cancel the sleep
824 * request, i.e., these reasons indicate a job that is not actively doing
828 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
830 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
834 for (i
= 0; i
< p
->num_reasons
; i
++)
835 if (!strcmp(p
->reasons
[i
], "connecting-to-device") ||
836 !strcmp(p
->reasons
[i
], "cups-waiting-for-completed"))
839 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
846 cupsdLogMessage(CUPSD_LOG_INFO
,
847 "System sleep canceled because printer %s is active.",
849 IOCancelPowerChange(sysevent
.powerKernelPort
,
850 sysevent
.powerNotificationID
);
854 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System wants to sleep.");
855 IOAllowPowerChange(sysevent
.powerKernelPort
,
856 sysevent
.powerNotificationID
);
860 if (sysevent
.event
& SYSEVENT_WILLSLEEP
)
862 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System going to sleep.");
869 * If we have no printing jobs, allow the power change immediately.
870 * Otherwise set the SleepJobs time to 10 seconds in the future when
871 * we'll take more drastic measures...
874 if (cupsArrayCount(PrintingJobs
) == 0)
876 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
877 IOAllowPowerChange(sysevent
.powerKernelPort
,
878 sysevent
.powerNotificationID
);
883 * If there are active printers that don't have the connecting-to-device
884 * or cups-waiting-for-completed printer-state-reasons then delay the
885 * sleep request, i.e., these reasons indicate a job is active...
888 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
890 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
894 for (i
= 0; i
< p
->num_reasons
; i
++)
895 if (!strcmp(p
->reasons
[i
], "connecting-to-device") ||
896 !strcmp(p
->reasons
[i
], "cups-waiting-for-completed"))
899 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
906 cupsdLogMessage(CUPSD_LOG_INFO
,
907 "System sleep delayed because printer %s is active.",
910 LastSysEvent
= sysevent
;
911 SleepJobs
= time(NULL
) + 10;
915 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Allowing system sleep.");
916 IOAllowPowerChange(sysevent
.powerKernelPort
,
917 sysevent
.powerNotificationID
);
922 if (sysevent
.event
& SYSEVENT_WOKE
)
924 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System woke from sleep.");
925 IOAllowPowerChange(sysevent
.powerKernelPort
,
926 sysevent
.powerNotificationID
);
930 * Make sure jobs that were queued prior to the system going to sleep don't
931 * get canceled right away...
936 cupsd_job_t
*job
; /* Current job */
938 for (job
= (cupsd_job_t
*)cupsArrayFirst(ActiveJobs
);
940 job
= (cupsd_job_t
*)cupsArrayNext(ActiveJobs
))
942 if (job
->cancel_time
)
944 ipp_attribute_t
*cancel_after
= ippFindAttribute(job
->attrs
,
949 job
->cancel_time
= time(NULL
) + ippGetInteger(cancel_after
, 0);
951 job
->cancel_time
= time(NULL
) + MaxJobTime
;
962 if (sysevent
.event
& SYSEVENT_NETCHANGED
)
965 cupsdLogMessage(CUPSD_LOG_DEBUG
,
966 "System network configuration changed - "
967 "ignored while sleeping.");
969 cupsdLogMessage(CUPSD_LOG_DEBUG
,
970 "System network configuration changed.");
973 if (sysevent
.event
& SYSEVENT_NAMECHANGED
)
979 cupsdLogMessage(CUPSD_LOG_DEBUG
,
980 "Computer name or BTMM domains changed - ignored while "
985 cupsdLogMessage(CUPSD_LOG_DEBUG
,
986 "Computer name or BTMM domains changed.");
996 * 'sysUpdateNames()' - Update computer and/or BTMM domains.
1000 sysUpdateNames(void)
1002 cupsd_printer_t
*p
; /* Current printer */
1008 * De-register the individual printers...
1011 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1013 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1014 cupsdDeregisterPrinter(p
, 1);
1016 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1018 * Update the computer name and BTMM domain list...
1021 cupsdUpdateDNSSDName();
1022 # endif /* HAVE_DNSSD || HAVE_AVAHI */
1025 * Now re-register them...
1028 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1030 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1031 cupsdRegisterPrinter(p
);
1033 #endif /* __APPLE__ */