2 * "$Id: sysman.c 7928 2008-09-10 22:14:22Z mike $"
4 * System management functions for the CUPS scheduler.
6 * Copyright 2007-2011 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 #ifdef kIOPMAssertionTypeDenySystemSleep
73 static IOPMAssertionID dark_wake
= 0; /* "Dark wake" assertion for sharing */
74 #endif /* kIOPMAssertionTypeDenySystemSleep */
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_REMOTE
)
91 cupsdSaveRemoteCache();
93 if (DirtyFiles
& CUPSD_DIRTY_PRINTCAP
)
96 if (DirtyFiles
& CUPSD_DIRTY_JOBS
)
98 cupsd_job_t
*job
; /* Current job */
102 for (job
= (cupsd_job_t
*)cupsArrayFirst(Jobs
);
104 job
= (cupsd_job_t
*)cupsArrayNext(Jobs
))
109 if (DirtyFiles
& CUPSD_DIRTY_SUBSCRIPTIONS
)
110 cupsdSaveAllSubscriptions();
112 DirtyFiles
= CUPSD_DIRTY_NONE
;
120 * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
124 cupsdMarkDirty(int what
) /* I - What file(s) are dirty? */
126 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdMarkDirty(%c%c%c%c%c%c)",
127 (what
& CUPSD_DIRTY_PRINTERS
) ? 'P' : '-',
128 (what
& CUPSD_DIRTY_CLASSES
) ? 'C' : '-',
129 (what
& CUPSD_DIRTY_REMOTE
) ? 'R' : '-',
130 (what
& CUPSD_DIRTY_PRINTCAP
) ? 'p' : '-',
131 (what
& CUPSD_DIRTY_JOBS
) ? 'J' : '-',
132 (what
& CUPSD_DIRTY_SUBSCRIPTIONS
) ? 'S' : '-');
134 if (what
== CUPSD_DIRTY_PRINTCAP
&& !Printcap
)
140 DirtyCleanTime
= time(NULL
) + DirtyCleanInterval
;
147 * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
151 cupsdSetBusyState(void)
153 int i
; /* Looping var */
154 cupsd_job_t
*job
; /* Current job */
155 cupsd_printer_t
*p
; /* Current printer */
156 int newbusy
; /* New busy state */
157 static int busy
= 0; /* Current busy state */
158 static const char * const busy_text
[] =
159 { /* Text for busy states */
163 "Printing jobs and dirty files",
165 "Active clients and dirty files",
166 "Active clients and printing jobs",
167 "Active clients, printing jobs, and dirty files"
169 #ifdef HAVE_VPROC_TRANSACTION_BEGIN
170 static vproc_transaction_t vtran
= 0; /* Current busy transaction */
171 #endif /* HAVE_VPROC_TRANSACTION_BEGIN */
175 * Figure out how busy we are...
178 newbusy
= (DirtyCleanTime
? 1 : 0) |
179 (cupsArrayCount(ActiveClients
) ? 4 : 0);
181 for (job
= (cupsd_job_t
*)cupsArrayFirst(PrintingJobs
);
183 job
= (cupsd_job_t
*)cupsArrayNext(PrintingJobs
))
185 if ((p
= job
->printer
) != NULL
)
187 for (i
= 0; i
< p
->num_reasons
; i
++)
188 if (!strcmp(p
->reasons
[i
], "connecting-to-device"))
191 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
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 */
217 #ifdef kIOPMAssertionTypeDenySystemSleep
218 if ((busy
& 2) && !dark_wake
)
219 IOPMAssertionCreateWithName(kIOPMAssertionTypeDenySystemSleep
,
220 kIOPMAssertionLevelOn
,
221 CFSTR("org.cups.cupsd"), &dark_wake
);
222 else if (!(busy
& 2) && dark_wake
)
224 IOPMAssertionRelease(dark_wake
);
227 #endif /* kIOPMAssertionTypeDenySystemSleep */
229 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdSetBusyState: %s", busy_text
[busy
]);
236 * This is the Apple-specific system event code. It works by creating
237 * a worker thread that waits for events from the OS and relays them
238 * to the main thread via a traditional pipe.
242 * Include MacOS-specific headers...
245 # include <IOKit/IOKitLib.h>
246 # include <IOKit/IOMessage.h>
247 # include <IOKit/pwr_mgt/IOPMLib.h>
248 # include <SystemConfiguration/SystemConfiguration.h>
249 # include <pthread.h>
256 # define SYSEVENT_CANSLEEP 0x1 /* Decide whether to allow sleep or not */
257 # define SYSEVENT_WILLSLEEP 0x2 /* Computer will go to sleep */
258 # define SYSEVENT_WOKE 0x4 /* Computer woke from sleep */
259 # define SYSEVENT_NETCHANGED 0x8 /* Network changed */
260 # define SYSEVENT_NAMECHANGED 0x10 /* Computer name changed */
267 typedef struct cupsd_sysevent_s
/*** System event data ****/
269 unsigned char event
; /* Event bit field */
270 io_connect_t powerKernelPort
; /* Power context data */
271 long powerNotificationID
; /* Power event data */
275 typedef struct cupsd_thread_data_s
/*** Thread context data ****/
277 cupsd_sysevent_t sysevent
; /* System event */
278 CFRunLoopTimerRef timerRef
; /* Timer to delay some change *
280 } cupsd_thread_data_t
;
287 static pthread_t SysEventThread
= NULL
;
288 /* Thread to host a runloop */
289 static pthread_mutex_t SysEventThreadMutex
= { 0 };
290 /* Coordinates access to shared gloabals */
291 static pthread_cond_t SysEventThreadCond
= { 0 };
292 /* Thread initialization complete condition */
293 static CFRunLoopRef SysEventRunloop
= NULL
;
294 /* The runloop. Access must be protected! */
295 static CFStringRef ComputerNameKey
= NULL
,
296 /* Computer name key */
297 BTMMKey
= NULL
, /* Back to My Mac key */
298 NetworkGlobalKeyIPv4
= NULL
,
299 /* Network global IPv4 key */
300 NetworkGlobalKeyIPv6
= NULL
,
301 /* Network global IPv6 key */
302 NetworkGlobalKeyDNS
= NULL
,
303 /* Network global DNS key */
306 NetworkInterfaceKeyIPv4
= NULL
,
307 /* Netowrk interface key */
308 NetworkInterfaceKeyIPv6
= NULL
;
309 /* Netowrk interface key */
310 static cupsd_sysevent_t LastSysEvent
; /* Last system event (for delayed sleep) */
317 static void *sysEventThreadEntry(void);
318 static void sysEventPowerNotifier(void *context
, io_service_t service
,
319 natural_t messageType
,
320 void *messageArgument
);
321 static void sysEventConfigurationNotifier(SCDynamicStoreRef store
,
322 CFArrayRef changedKeys
,
324 static void sysEventTimerNotifier(CFRunLoopTimerRef timer
, void *context
);
325 static void sysUpdate(void);
329 * 'cupsdAllowSleep()' - Tell the OS it is now OK to sleep.
333 cupsdAllowSleep(void)
337 IOAllowPowerChange(LastSysEvent
.powerKernelPort
,
338 LastSysEvent
.powerNotificationID
);
343 * 'cupsdStartSystemMonitor()' - Start monitoring for system change.
347 cupsdStartSystemMonitor(void)
349 int flags
; /* fcntl flags on pipe */
352 if (cupsdOpenPipe(SysEventPipes
))
354 cupsdLogMessage(CUPSD_LOG_ERROR
, "System event monitor pipe() failed - %s!",
359 cupsdAddSelect(SysEventPipes
[0], (cupsd_selfunc_t
)sysUpdate
, NULL
, NULL
);
362 * Set non-blocking mode on the descriptor we will be receiving notification
366 flags
= fcntl(SysEventPipes
[0], F_GETFL
, 0);
367 fcntl(SysEventPipes
[0], F_SETFL
, flags
| O_NONBLOCK
);
370 * Start the thread that runs the runloop...
373 pthread_mutex_init(&SysEventThreadMutex
, NULL
);
374 pthread_cond_init(&SysEventThreadCond
, NULL
);
375 pthread_create(&SysEventThread
, NULL
, (void *(*)())sysEventThreadEntry
, NULL
);
380 * 'cupsdStopSystemMonitor()' - Stop monitoring for system change.
384 cupsdStopSystemMonitor(void)
386 CFRunLoopRef rl
; /* The event handler runloop */
392 * Make sure the thread has completed it's initialization and
393 * stored it's runloop reference in the shared global.
396 pthread_mutex_lock(&SysEventThreadMutex
);
398 if (!SysEventRunloop
)
399 pthread_cond_wait(&SysEventThreadCond
, &SysEventThreadMutex
);
401 rl
= SysEventRunloop
;
402 SysEventRunloop
= NULL
;
404 pthread_mutex_unlock(&SysEventThreadMutex
);
409 pthread_join(SysEventThread
, NULL
);
410 pthread_mutex_destroy(&SysEventThreadMutex
);
411 pthread_cond_destroy(&SysEventThreadCond
);
414 if (SysEventPipes
[0] >= 0)
416 cupsdRemoveSelect(SysEventPipes
[0]);
417 cupsdClosePipe(SysEventPipes
);
423 * 'sysEventThreadEntry()' - A thread to receive power and computer name
424 * change notifications.
427 static void * /* O - Return status/value */
428 sysEventThreadEntry(void)
430 io_object_t powerNotifierObj
;
431 /* Power notifier object */
432 IONotificationPortRef powerNotifierPort
;
433 /* Power notifier port */
434 SCDynamicStoreRef store
= NULL
;/* System Config dynamic store */
435 CFRunLoopSourceRef powerRLS
= NULL
,/* Power runloop source */
436 storeRLS
= NULL
;/* System Config runloop source */
437 CFStringRef key
[6], /* System Config keys */
438 pattern
[2]; /* System Config patterns */
439 CFArrayRef keys
= NULL
, /* System Config key array*/
440 patterns
= NULL
;/* System Config pattern array */
441 SCDynamicStoreContext storeContext
; /* Dynamic store context */
442 CFRunLoopTimerContext timerContext
; /* Timer context */
443 cupsd_thread_data_t threadData
; /* Thread context data for the *
444 * runloop notifiers */
448 * Register for power state change notifications
451 bzero(&threadData
, sizeof(threadData
));
453 threadData
.sysevent
.powerKernelPort
=
454 IORegisterForSystemPower(&threadData
, &powerNotifierPort
,
455 sysEventPowerNotifier
, &powerNotifierObj
);
457 if (threadData
.sysevent
.powerKernelPort
)
459 powerRLS
= IONotificationPortGetRunLoopSource(powerNotifierPort
);
460 CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRLS
, kCFRunLoopDefaultMode
);
463 DEBUG_puts("sysEventThreadEntry: error registering for system power "
467 * Register for system configuration change notifications
470 bzero(&storeContext
, sizeof(storeContext
));
471 storeContext
.info
= &threadData
;
473 store
= SCDynamicStoreCreate(kCFAllocatorDefault
, CFSTR("cupsd"),
474 sysEventConfigurationNotifier
, &storeContext
);
476 if (!ComputerNameKey
)
477 ComputerNameKey
= SCDynamicStoreKeyCreateComputerName(kCFAllocatorDefault
);
480 BTMMKey
= SCDynamicStoreKeyCreate(kCFAllocatorDefault
,
481 CFSTR("Setup:/Network/BackToMyMac"));
483 if (!NetworkGlobalKeyIPv4
)
484 NetworkGlobalKeyIPv4
=
485 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
486 kSCDynamicStoreDomainState
,
489 if (!NetworkGlobalKeyIPv6
)
490 NetworkGlobalKeyIPv6
=
491 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
492 kSCDynamicStoreDomainState
,
495 if (!NetworkGlobalKeyDNS
)
496 NetworkGlobalKeyDNS
=
497 SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault
,
498 kSCDynamicStoreDomainState
,
502 HostNamesKey
= SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault
);
504 if (!NetworkInterfaceKeyIPv4
)
505 NetworkInterfaceKeyIPv4
=
506 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
507 kSCDynamicStoreDomainState
,
511 if (!NetworkInterfaceKeyIPv6
)
512 NetworkInterfaceKeyIPv6
=
513 SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault
,
514 kSCDynamicStoreDomainState
,
518 if (store
&& ComputerNameKey
&& HostNamesKey
&&
519 NetworkGlobalKeyIPv4
&& NetworkGlobalKeyIPv6
&& NetworkGlobalKeyDNS
&&
520 NetworkInterfaceKeyIPv4
&& NetworkInterfaceKeyIPv6
)
522 key
[0] = ComputerNameKey
;
524 key
[2] = NetworkGlobalKeyIPv4
;
525 key
[3] = NetworkGlobalKeyIPv6
;
526 key
[4] = NetworkGlobalKeyDNS
;
527 key
[5] = HostNamesKey
;
529 pattern
[0] = NetworkInterfaceKeyIPv4
;
530 pattern
[1] = NetworkInterfaceKeyIPv6
;
532 keys
= CFArrayCreate(kCFAllocatorDefault
, (const void **)key
,
533 sizeof(key
) / sizeof(key
[0]),
534 &kCFTypeArrayCallBacks
);
536 patterns
= CFArrayCreate(kCFAllocatorDefault
, (const void **)pattern
,
537 sizeof(pattern
) / sizeof(pattern
[0]),
538 &kCFTypeArrayCallBacks
);
540 if (keys
&& patterns
&&
541 SCDynamicStoreSetNotificationKeys(store
, keys
, patterns
))
543 if ((storeRLS
= SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault
,
546 CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS
,
547 kCFRunLoopDefaultMode
);
550 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreateRunLoopSource "
551 "failed: %s\n", SCErrorString(SCError())));
554 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreSetNotificationKeys "
555 "failed: %s\n", SCErrorString(SCError())));
558 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreate failed: %s\n",
559 SCErrorString(SCError())));
568 * Set up a timer to delay the wake change notifications.
570 * The initial time is set a decade or so into the future, we'll adjust
574 bzero(&timerContext
, sizeof(timerContext
));
575 timerContext
.info
= &threadData
;
577 threadData
.timerRef
=
578 CFRunLoopTimerCreate(kCFAllocatorDefault
,
579 CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
580 86400L * 365L * 10L, 0, 0, sysEventTimerNotifier
,
582 CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
583 kCFRunLoopDefaultMode
);
586 * Store our runloop in a global so the main thread can use it to stop us.
589 pthread_mutex_lock(&SysEventThreadMutex
);
591 SysEventRunloop
= CFRunLoopGetCurrent();
593 pthread_cond_signal(&SysEventThreadCond
);
594 pthread_mutex_unlock(&SysEventThreadMutex
);
597 * Disappear into the runloop until it's stopped by the main thread.
603 * Clean up before exiting.
606 if (threadData
.timerRef
)
608 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData
.timerRef
,
609 kCFRunLoopDefaultMode
);
610 CFRelease(threadData
.timerRef
);
613 if (threadData
.sysevent
.powerKernelPort
)
615 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS
,
616 kCFRunLoopDefaultMode
);
617 IODeregisterForSystemPower(&powerNotifierObj
);
618 IOServiceClose(threadData
.sysevent
.powerKernelPort
);
619 IONotificationPortDestroy(powerNotifierPort
);
624 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS
,
625 kCFRunLoopDefaultMode
);
626 CFRunLoopSourceInvalidate(storeRLS
);
638 * 'sysEventPowerNotifier()' - Handle power notification events.
642 sysEventPowerNotifier(
643 void *context
, /* I - Thread context data */
644 io_service_t service
, /* I - Unused service info */
645 natural_t messageType
, /* I - Type of message */
646 void *messageArgument
) /* I - Message data */
648 int sendit
= 1; /* Send event to main thread? *
649 * (0 = no, 1 = yes, 2 = delayed */
650 cupsd_thread_data_t
*threadData
; /* Thread context data */
653 threadData
= (cupsd_thread_data_t
*)context
;
655 (void)service
; /* anti-compiler-warning-code */
659 case kIOMessageCanSystemPowerOff
:
660 case kIOMessageCanSystemSleep
:
661 threadData
->sysevent
.event
|= SYSEVENT_CANSLEEP
;
664 case kIOMessageSystemWillRestart
:
665 case kIOMessageSystemWillPowerOff
:
666 case kIOMessageSystemWillSleep
:
667 threadData
->sysevent
.event
|= SYSEVENT_WILLSLEEP
;
670 case kIOMessageSystemHasPoweredOn
:
672 * Because powered on is followed by a net-changed event, delay
677 threadData
->sysevent
.event
|= SYSEVENT_WOKE
;
680 case kIOMessageSystemWillNotPowerOff
:
681 case kIOMessageSystemWillNotSleep
:
682 # ifdef kIOMessageSystemWillPowerOn
683 case kIOMessageSystemWillPowerOn
:
684 # endif /* kIOMessageSystemWillPowerOn */
691 IOAllowPowerChange(threadData
->sysevent
.powerKernelPort
,
692 (long)messageArgument
);
695 threadData
->sysevent
.powerNotificationID
= (long)messageArgument
;
700 * Send the event to the main thread now.
703 write(SysEventPipes
[1], &threadData
->sysevent
,
704 sizeof(threadData
->sysevent
));
705 threadData
->sysevent
.event
= 0;
710 * Send the event to the main thread after 1 to 2 seconds.
713 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
714 CFAbsoluteTimeGetCurrent() + 2);
721 * 'sysEventConfigurationNotifier()' - Network configuration change notification
726 sysEventConfigurationNotifier(
727 SCDynamicStoreRef store
, /* I - System data (unused) */
728 CFArrayRef changedKeys
, /* I - Changed data */
729 void *context
) /* I - Thread context data */
731 cupsd_thread_data_t
*threadData
; /* Thread context data */
734 threadData
= (cupsd_thread_data_t
*)context
;
736 (void)store
; /* anti-compiler-warning-code */
738 CFRange range
= CFRangeMake(0, CFArrayGetCount(changedKeys
));
740 if (CFArrayContainsValue(changedKeys
, range
, ComputerNameKey
) ||
741 CFArrayContainsValue(changedKeys
, range
, BTMMKey
))
742 threadData
->sysevent
.event
|= SYSEVENT_NAMECHANGED
;
745 threadData
->sysevent
.event
|= SYSEVENT_NETCHANGED
;
748 * Indicate the network interface list needs updating...
755 * Because we registered for several different kinds of change notifications
756 * this callback usually gets called several times in a row. We use a timer to
757 * de-bounce these so we only end up generating one event for the main thread.
760 CFRunLoopTimerSetNextFireDate(threadData
->timerRef
,
761 CFAbsoluteTimeGetCurrent() + 5);
766 * 'sysEventTimerNotifier()' - Handle delayed event notifications.
770 sysEventTimerNotifier(
771 CFRunLoopTimerRef timer
, /* I - Timer information */
772 void *context
) /* I - Thread context data */
774 cupsd_thread_data_t
*threadData
; /* Thread context data */
777 threadData
= (cupsd_thread_data_t
*)context
;
780 * If an event is still pending send it to the main thread.
783 if (threadData
->sysevent
.event
)
785 write(SysEventPipes
[1], &threadData
->sysevent
,
786 sizeof(threadData
->sysevent
));
787 threadData
->sysevent
.event
= 0;
793 * 'sysUpdate()' - Update the current system state.
799 int i
; /* Looping var */
800 cupsd_sysevent_t sysevent
; /* The system event */
801 cupsd_printer_t
*p
; /* Printer information */
805 * Drain the event pipe...
808 while (read((int)SysEventPipes
[0], &sysevent
, sizeof(sysevent
))
811 if (sysevent
.event
& SYSEVENT_CANSLEEP
)
814 * If there are active printers that don't have the connecting-to-device
815 * printer-state-reason then cancel the sleep request (i.e. this reason
816 * indicates a job that is not yet connected to the printer)...
819 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
821 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
825 for (i
= 0; i
< p
->num_reasons
; i
++)
826 if (!strcmp(p
->reasons
[i
], "connecting-to-device"))
829 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
836 cupsdLogMessage(CUPSD_LOG_INFO
,
837 "System sleep canceled because printer %s is active",
839 IOCancelPowerChange(sysevent
.powerKernelPort
,
840 sysevent
.powerNotificationID
);
844 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System wants to sleep");
845 IOAllowPowerChange(sysevent
.powerKernelPort
,
846 sysevent
.powerNotificationID
);
850 if (sysevent
.event
& SYSEVENT_WILLSLEEP
)
852 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System going to sleep");
856 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
858 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
860 if (p
->type
& CUPS_PRINTER_DISCOVERED
)
862 cupsdLogMessage(CUPSD_LOG_DEBUG
,
863 "Deleting remote destination \"%s\"", p
->name
);
864 cupsArraySave(Printers
);
865 cupsdDeletePrinter(p
, 0);
866 cupsArrayRestore(Printers
);
870 cupsdLogMessage(CUPSD_LOG_DEBUG
,
871 "Deregistering local printer \"%s\"", p
->name
);
872 cupsdDeregisterPrinter(p
, 0);
879 * If we have no printing jobs, allow the power change immediately.
880 * Otherwise set the SleepJobs time to 15 seconds in the future when
881 * we'll take more drastic measures...
884 if (cupsArrayCount(PrintingJobs
) == 0)
885 IOAllowPowerChange(sysevent
.powerKernelPort
,
886 sysevent
.powerNotificationID
);
890 * If there are active printers that don't have the connecting-to-device
891 * printer-state-reason then delay the sleep request (i.e. this reason
892 * indicates a job that is not yet connected to the printer)...
895 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
897 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
901 for (i
= 0; i
< p
->num_reasons
; i
++)
902 if (!strcmp(p
->reasons
[i
], "connecting-to-device"))
905 if (!p
->num_reasons
|| i
>= p
->num_reasons
)
912 LastSysEvent
= sysevent
;
913 SleepJobs
= time(NULL
) + 10;
917 IOAllowPowerChange(sysevent
.powerKernelPort
,
918 sysevent
.powerNotificationID
);
923 if (sysevent
.event
& SYSEVENT_WOKE
)
925 cupsdLogMessage(CUPSD_LOG_DEBUG
, "System woke from sleep");
926 IOAllowPowerChange(sysevent
.powerKernelPort
,
927 sysevent
.powerNotificationID
);
932 if (sysevent
.event
& SYSEVENT_NETCHANGED
)
936 cupsdLogMessage(CUPSD_LOG_DEBUG
,
937 "System network configuration changed");
940 * Resetting browse_time before calling cupsdSendBrowseList causes
941 * browse packets to be sent for local shared printers.
944 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
946 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
949 cupsdSendBrowseList();
950 cupsdRestartPolling();
953 cupsdLogMessage(CUPSD_LOG_DEBUG
,
954 "System network configuration changed; "
955 "ignored while sleeping");
958 if (sysevent
.event
& SYSEVENT_NAMECHANGED
)
962 cupsdLogMessage(CUPSD_LOG_DEBUG
,
963 "Computer name or BTMM domains changed");
966 * De-register the individual printers...
969 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
971 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
972 cupsdDeregisterPrinter(p
, 1);
975 * Update the computer name and BTMM domain list...
978 cupsdUpdateDNSSDName();
981 * Now re-register them...
984 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
986 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
989 cupsdRegisterPrinter(p
);
993 cupsdLogMessage(CUPSD_LOG_DEBUG
,
994 "Computer name or BTMM domains changed; ignored while "
999 #endif /* __APPLE__ */
1003 * End of "$Id: sysman.c 7928 2008-09-10 22:14:22Z mike $".