]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/sysman.c
Merge changes from CUPS 1.4svn-r7932.
[thirdparty/cups.git] / scheduler / sysman.c
1 /*
2 * "$Id: sysman.c 7676 2008-06-18 23:42:37Z mike $"
3 *
4 * System management definitions for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 2006 by Easy Software Products.
8 *
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/".
14 *
15 * Contents:
16 *
17 * cupsdCleanDirty() - Write dirty config and state files.
18 * cupsdMarkDirty() - Mark config or state files as needing a
19 * write.
20 * cupsdSetBusyState() - Let the system know when we are busy
21 * doing something.
22 * cupsdStartSystemMonitor() - Start monitoring for system change.
23 * cupsdStopSystemMonitor() - Stop monitoring for system change.
24 * sysEventThreadEntry() - A thread to receive power and computer
25 * name change notifications.
26 * sysEventPowerNotifier() - Handle power notification events.
27 * sysEventConfigurationNotifier() - Computer name changed notification
28 * callback.
29 * sysEventTimerNotifier() - Handle delayed event notifications.
30 * sysUpdate() - Update the current system state.
31 */
32
33
34 /*
35 * Include necessary headers...
36 */
37
38 #include "cupsd.h"
39
40
41 /*
42 * The system management functions cover disk and power management which
43 * are primarily used on portable computers.
44 *
45 * Disk management involves delaying the write of certain configuration
46 * and state files to minimize the number of times the disk has to spin
47 * up.
48 *
49 * Power management support is currently only implemented on MacOS X, but
50 * essentially we use four functions to let the OS know when it is OK to
51 * put the system to idle sleep, typically when we are not in the middle of
52 * printing a job.
53 *
54 * Once put to sleep, we invalidate all remote printers since it is common
55 * to wake up in a new location/on a new wireless network.
56 */
57
58
59 /*
60 * 'cupsdCleanDirty()' - Write dirty config and state files.
61 */
62
63 void
64 cupsdCleanDirty(void)
65 {
66 if (DirtyFiles & CUPSD_DIRTY_PRINTERS)
67 cupsdSaveAllPrinters();
68
69 if (DirtyFiles & CUPSD_DIRTY_CLASSES)
70 cupsdSaveAllClasses();
71
72 if (DirtyFiles & CUPSD_DIRTY_REMOTE)
73 cupsdSaveRemoteCache();
74
75 if (DirtyFiles & CUPSD_DIRTY_PRINTCAP)
76 cupsdWritePrintcap();
77
78 if (DirtyFiles & CUPSD_DIRTY_JOBS)
79 {
80 cupsd_job_t *job; /* Current job */
81
82 cupsdSaveAllJobs();
83
84 for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
85 job;
86 job = (cupsd_job_t *)cupsArrayNext(Jobs))
87 if (job->dirty)
88 cupsdSaveJob(job);
89 }
90
91 if (DirtyFiles & CUPSD_DIRTY_SUBSCRIPTIONS)
92 cupsdSaveAllSubscriptions();
93
94 DirtyFiles = CUPSD_DIRTY_NONE;
95 DirtyCleanTime = 0;
96
97 cupsdSetBusyState();
98 }
99
100
101 /*
102 * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
103 */
104
105 void
106 cupsdMarkDirty(int what) /* I - What file(s) are dirty? */
107 {
108 if (what == CUPSD_DIRTY_PRINTCAP && !Printcap)
109 return;
110
111 DirtyFiles |= what;
112
113 if (!DirtyCleanTime)
114 DirtyCleanTime = time(NULL) + DirtyCleanInterval;
115
116 cupsdSetBusyState();
117 }
118
119
120 /*
121 * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
122 */
123
124 void
125 cupsdSetBusyState(void)
126 {
127 int newbusy; /* New busy state */
128 static int busy = 0; /* Current busy state */
129 static const char * const busy_text[] =
130 { /* Text for busy states */
131 "Not busy",
132 "Dirty files",
133 "Printing jobs",
134 "Printing jobs and dirty files",
135 "Active clients",
136 "Active clients and dirty files",
137 "Active clients and printing jobs",
138 "Active clients, printing jobs, and dirty files"
139 };
140
141
142 newbusy = (DirtyCleanTime ? 1 : 0) |
143 (cupsArrayCount(PrintingJobs) ? 2 : 0) |
144 (cupsArrayCount(ActiveClients) ? 4 : 0);
145
146 if (newbusy != busy)
147 {
148 busy = newbusy;
149
150 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetBusyState: %s", busy_text[busy]);
151 }
152 }
153
154
155 #ifdef __APPLE__
156 /*
157 * This is the Apple-specific system event code. It works by creating
158 * a worker thread that waits for events from the OS and relays them
159 * to the main thread via a traditional pipe.
160 */
161
162 /*
163 * Include MacOS-specific headers...
164 */
165
166 # include <IOKit/IOKitLib.h>
167 # include <IOKit/IOMessage.h>
168 # include <IOKit/pwr_mgt/IOPMLib.h>
169 # include <SystemConfiguration/SystemConfiguration.h>
170 # include <pthread.h>
171
172
173 /*
174 * Constants...
175 */
176
177 # define SYSEVENT_CANSLEEP 0x1 /* Decide whether to allow sleep or not */
178 # define SYSEVENT_WILLSLEEP 0x2 /* Computer will go to sleep */
179 # define SYSEVENT_WOKE 0x4 /* Computer woke from sleep */
180 # define SYSEVENT_NETCHANGED 0x8 /* Network changed */
181 # define SYSEVENT_NAMECHANGED 0x10 /* Computer name changed */
182
183
184 /*
185 * Structures...
186 */
187
188 typedef struct cupsd_sysevent_s /*** System event data ****/
189 {
190 unsigned char event; /* Event bit field */
191 io_connect_t powerKernelPort; /* Power context data */
192 long powerNotificationID; /* Power event data */
193 } cupsd_sysevent_t;
194
195
196 typedef struct cupsd_thread_data_s /*** Thread context data ****/
197 {
198 cupsd_sysevent_t sysevent; /* System event */
199 CFRunLoopTimerRef timerRef; /* Timer to delay some change *
200 * notifications */
201 } cupsd_thread_data_t;
202
203
204 /*
205 * Local globals...
206 */
207
208 static pthread_t SysEventThread = NULL;
209 /* Thread to host a runloop */
210 static pthread_mutex_t SysEventThreadMutex = { 0 };
211 /* Coordinates access to shared gloabals */
212 static pthread_cond_t SysEventThreadCond = { 0 };
213 /* Thread initialization complete condition */
214 static CFRunLoopRef SysEventRunloop = NULL;
215 /* The runloop. Access must be protected! */
216 static CFStringRef ComputerNameKey = NULL,
217 /* Computer name key */
218 NetworkGlobalKeyIPv4 = NULL,
219 /* Network global IPv4 key */
220 NetworkGlobalKeyIPv6 = NULL,
221 /* Network global IPv6 key */
222 NetworkGlobalKeyDNS = NULL,
223 /* Network global DNS key */
224 HostNamesKey = NULL,
225 /* Host name key */
226 NetworkInterfaceKeyIPv4 = NULL,
227 /* Netowrk interface key */
228 NetworkInterfaceKeyIPv6 = NULL;
229 /* Netowrk interface key */
230
231
232 /*
233 * Local functions...
234 */
235
236 static void *sysEventThreadEntry(void);
237 static void sysEventPowerNotifier(void *context, io_service_t service,
238 natural_t messageType,
239 void *messageArgument);
240 static void sysEventConfigurationNotifier(SCDynamicStoreRef store,
241 CFArrayRef changedKeys,
242 void *context);
243 static void sysEventTimerNotifier(CFRunLoopTimerRef timer, void *context);
244 static void sysUpdate(void);
245
246
247 /*
248 * 'cupsdStartSystemMonitor()' - Start monitoring for system change.
249 */
250
251 void
252 cupsdStartSystemMonitor(void)
253 {
254 int flags; /* fcntl flags on pipe */
255
256
257 if (cupsdOpenPipe(SysEventPipes))
258 {
259 cupsdLogMessage(CUPSD_LOG_ERROR, "System event monitor pipe() failed - %s!",
260 strerror(errno));
261 return;
262 }
263
264 cupsdAddSelect(SysEventPipes[0], (cupsd_selfunc_t)sysUpdate, NULL, NULL);
265
266 /*
267 * Set non-blocking mode on the descriptor we will be receiving notification
268 * events on.
269 */
270
271 flags = fcntl(SysEventPipes[0], F_GETFL, 0);
272 fcntl(SysEventPipes[0], F_SETFL, flags | O_NONBLOCK);
273
274 /*
275 * Start the thread that runs the runloop...
276 */
277
278 pthread_mutex_init(&SysEventThreadMutex, NULL);
279 pthread_cond_init(&SysEventThreadCond, NULL);
280 pthread_create(&SysEventThread, NULL, (void *(*)())sysEventThreadEntry, NULL);
281 }
282
283
284 /*
285 * 'cupsdStopSystemMonitor()' - Stop monitoring for system change.
286 */
287
288 void
289 cupsdStopSystemMonitor(void)
290 {
291 CFRunLoopRef rl; /* The event handler runloop */
292
293
294 if (SysEventThread)
295 {
296 /*
297 * Make sure the thread has completed it's initialization and
298 * stored it's runloop reference in the shared global.
299 */
300
301 pthread_mutex_lock(&SysEventThreadMutex);
302
303 if (!SysEventRunloop)
304 pthread_cond_wait(&SysEventThreadCond, &SysEventThreadMutex);
305
306 rl = SysEventRunloop;
307 SysEventRunloop = NULL;
308
309 pthread_mutex_unlock(&SysEventThreadMutex);
310
311 if (rl)
312 CFRunLoopStop(rl);
313
314 pthread_join(SysEventThread, NULL);
315 pthread_mutex_destroy(&SysEventThreadMutex);
316 pthread_cond_destroy(&SysEventThreadCond);
317 }
318
319 if (SysEventPipes[0] >= 0)
320 {
321 cupsdRemoveSelect(SysEventPipes[0]);
322 cupsdClosePipe(SysEventPipes);
323 }
324 }
325
326
327 /*
328 * 'sysEventThreadEntry()' - A thread to receive power and computer name
329 * change notifications.
330 */
331
332 static void * /* O - Return status/value */
333 sysEventThreadEntry(void)
334 {
335 io_object_t powerNotifierObj;
336 /* Power notifier object */
337 IONotificationPortRef powerNotifierPort;
338 /* Power notifier port */
339 SCDynamicStoreRef store = NULL;/* System Config dynamic store */
340 CFRunLoopSourceRef powerRLS = NULL,/* Power runloop source */
341 storeRLS = NULL;/* System Config runloop source */
342 CFStringRef key[5], /* System Config keys */
343 pattern[2]; /* System Config patterns */
344 CFArrayRef keys = NULL, /* System Config key array*/
345 patterns = NULL;/* System Config pattern array */
346 SCDynamicStoreContext storeContext; /* Dynamic store context */
347 CFRunLoopTimerContext timerContext; /* Timer context */
348 cupsd_thread_data_t threadData; /* Thread context data for the *
349 * runloop notifiers */
350
351
352 /*
353 * Register for power state change notifications
354 */
355
356 bzero(&threadData, sizeof(threadData));
357
358 threadData.sysevent.powerKernelPort =
359 IORegisterForSystemPower(&threadData, &powerNotifierPort,
360 sysEventPowerNotifier, &powerNotifierObj);
361
362 if (threadData.sysevent.powerKernelPort)
363 {
364 powerRLS = IONotificationPortGetRunLoopSource(powerNotifierPort);
365 CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRLS, kCFRunLoopDefaultMode);
366 }
367 else
368 DEBUG_puts("sysEventThreadEntry: error registering for system power "
369 "notifications");
370
371 /*
372 * Register for system configuration change notifications
373 */
374
375 bzero(&storeContext, sizeof(storeContext));
376 storeContext.info = &threadData;
377
378 store = SCDynamicStoreCreate(NULL, CFSTR("cupsd"),
379 sysEventConfigurationNotifier, &storeContext);
380
381 if (!ComputerNameKey)
382 ComputerNameKey = SCDynamicStoreKeyCreateComputerName(NULL);
383
384 if (!NetworkGlobalKeyIPv4)
385 NetworkGlobalKeyIPv4 =
386 SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
387 kSCDynamicStoreDomainState,
388 kSCEntNetIPv4);
389
390 if (!NetworkGlobalKeyIPv6)
391 NetworkGlobalKeyIPv6 =
392 SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
393 kSCDynamicStoreDomainState,
394 kSCEntNetIPv6);
395
396 if (!NetworkGlobalKeyDNS)
397 NetworkGlobalKeyDNS =
398 SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
399 kSCDynamicStoreDomainState,
400 kSCEntNetDNS);
401
402 if (!HostNamesKey)
403 HostNamesKey = SCDynamicStoreKeyCreateHostNames(NULL);
404
405 if (!NetworkInterfaceKeyIPv4)
406 NetworkInterfaceKeyIPv4 =
407 SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
408 kSCDynamicStoreDomainState,
409 kSCCompAnyRegex,
410 kSCEntNetIPv4);
411
412 if (!NetworkInterfaceKeyIPv6)
413 NetworkInterfaceKeyIPv6 =
414 SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
415 kSCDynamicStoreDomainState,
416 kSCCompAnyRegex,
417 kSCEntNetIPv6);
418
419 if (store && ComputerNameKey && HostNamesKey &&
420 NetworkGlobalKeyIPv4 && NetworkGlobalKeyIPv6 && NetworkGlobalKeyDNS &&
421 NetworkInterfaceKeyIPv4 && NetworkInterfaceKeyIPv6)
422 {
423 key[0] = ComputerNameKey;
424 key[1] = NetworkGlobalKeyIPv4;
425 key[2] = NetworkGlobalKeyIPv6;
426 key[3] = NetworkGlobalKeyDNS;
427 key[4] = HostNamesKey;
428
429 pattern[0] = NetworkInterfaceKeyIPv4;
430 pattern[1] = NetworkInterfaceKeyIPv6;
431
432 keys = CFArrayCreate(NULL, (const void **)key,
433 sizeof(key) / sizeof(key[0]),
434 &kCFTypeArrayCallBacks);
435
436 patterns = CFArrayCreate(NULL, (const void **)pattern,
437 sizeof(pattern) / sizeof(pattern[0]),
438 &kCFTypeArrayCallBacks);
439
440 if (keys && patterns &&
441 SCDynamicStoreSetNotificationKeys(store, keys, patterns))
442 {
443 if ((storeRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0))
444 != NULL)
445 {
446 CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS,
447 kCFRunLoopDefaultMode);
448 }
449 else
450 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreateRunLoopSource "
451 "failed: %s\n", SCErrorString(SCError())));
452 }
453 else
454 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreSetNotificationKeys "
455 "failed: %s\n", SCErrorString(SCError())));
456 }
457 else
458 DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreate failed: %s\n",
459 SCErrorString(SCError())));
460
461 if (keys)
462 CFRelease(keys);
463
464 if (patterns)
465 CFRelease(patterns);
466
467 /*
468 * Set up a timer to delay the wake change notifications.
469 *
470 * The initial time is set a decade or so into the future, we'll adjust
471 * this later.
472 */
473
474 bzero(&timerContext, sizeof(timerContext));
475 timerContext.info = &threadData;
476
477 threadData.timerRef =
478 CFRunLoopTimerCreate(NULL,
479 CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
480 86400L * 365L * 10L, 0, 0, sysEventTimerNotifier,
481 &timerContext);
482 CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData.timerRef,
483 kCFRunLoopDefaultMode);
484
485 /*
486 * Store our runloop in a global so the main thread can use it to stop us.
487 */
488
489 pthread_mutex_lock(&SysEventThreadMutex);
490
491 SysEventRunloop = CFRunLoopGetCurrent();
492
493 pthread_cond_signal(&SysEventThreadCond);
494 pthread_mutex_unlock(&SysEventThreadMutex);
495
496 /*
497 * Disappear into the runloop until it's stopped by the main thread.
498 */
499
500 CFRunLoopRun();
501
502 /*
503 * Clean up before exiting.
504 */
505
506 if (threadData.timerRef)
507 {
508 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData.timerRef,
509 kCFRunLoopDefaultMode);
510 CFRelease(threadData.timerRef);
511 }
512
513 if (threadData.sysevent.powerKernelPort)
514 {
515 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS,
516 kCFRunLoopDefaultMode);
517 IODeregisterForSystemPower(&powerNotifierObj);
518 IOServiceClose(threadData.sysevent.powerKernelPort);
519 IONotificationPortDestroy(powerNotifierPort);
520 }
521
522 if (storeRLS)
523 {
524 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS,
525 kCFRunLoopDefaultMode);
526 CFRunLoopSourceInvalidate(storeRLS);
527 CFRelease(storeRLS);
528 }
529
530 if (store)
531 CFRelease(store);
532
533 pthread_exit(NULL);
534 }
535
536
537 /*
538 * 'sysEventPowerNotifier()' - Handle power notification events.
539 */
540
541 static void
542 sysEventPowerNotifier(
543 void *context, /* I - Thread context data */
544 io_service_t service, /* I - Unused service info */
545 natural_t messageType, /* I - Type of message */
546 void *messageArgument) /* I - Message data */
547 {
548 int sendit = 1; /* Send event to main thread? *
549 * (0 = no, 1 = yes, 2 = delayed */
550 cupsd_thread_data_t *threadData; /* Thread context data */
551
552
553 threadData = (cupsd_thread_data_t *)context;
554
555 (void)service; /* anti-compiler-warning-code */
556
557 switch (messageType)
558 {
559 case kIOMessageCanSystemPowerOff:
560 case kIOMessageCanSystemSleep:
561 threadData->sysevent.event |= SYSEVENT_CANSLEEP;
562 break;
563
564 case kIOMessageSystemWillRestart:
565 case kIOMessageSystemWillPowerOff:
566 case kIOMessageSystemWillSleep:
567 threadData->sysevent.event |= SYSEVENT_WILLSLEEP;
568 break;
569
570 case kIOMessageSystemHasPoweredOn:
571 /*
572 * Because powered on is followed by a net-changed event, delay
573 * before sending it.
574 */
575
576 sendit = 2;
577 threadData->sysevent.event |= SYSEVENT_WOKE;
578 break;
579
580 case kIOMessageSystemWillNotPowerOff:
581 case kIOMessageSystemWillNotSleep:
582 #ifdef kIOMessageSystemWillPowerOn
583 case kIOMessageSystemWillPowerOn:
584 #endif /* kIOMessageSystemWillPowerOn */
585 default:
586 sendit = 0;
587 break;
588 }
589
590 if (sendit == 0)
591 IOAllowPowerChange(threadData->sysevent.powerKernelPort,
592 (long)messageArgument);
593 else
594 {
595 threadData->sysevent.powerNotificationID = (long)messageArgument;
596
597 if (sendit == 1)
598 {
599 /*
600 * Send the event to the main thread now.
601 */
602
603 write(SysEventPipes[1], &threadData->sysevent,
604 sizeof(threadData->sysevent));
605 threadData->sysevent.event = 0;
606 }
607 else
608 {
609 /*
610 * Send the event to the main thread after 1 to 2 seconds.
611 */
612
613 CFRunLoopTimerSetNextFireDate(threadData->timerRef,
614 CFAbsoluteTimeGetCurrent() + 2);
615 }
616 }
617 }
618
619
620 /*
621 * 'sysEventConfigurationNotifier()' - Computer name changed notification
622 * callback.
623 */
624
625 static void
626 sysEventConfigurationNotifier(
627 SCDynamicStoreRef store, /* I - System data (unused) */
628 CFArrayRef changedKeys, /* I - Changed data */
629 void *context) /* I - Thread context data */
630 {
631 cupsd_thread_data_t *threadData; /* Thread context data */
632
633
634 threadData = (cupsd_thread_data_t *)context;
635
636 (void)store; /* anti-compiler-warning-code */
637
638 CFRange range = CFRangeMake(0, CFArrayGetCount(changedKeys));
639
640 if (CFArrayContainsValue(changedKeys, range, ComputerNameKey))
641 threadData->sysevent.event |= SYSEVENT_NAMECHANGED;
642 else
643 {
644 threadData->sysevent.event |= SYSEVENT_NETCHANGED;
645
646 /*
647 * Indicate the network interface list needs updating...
648 */
649
650 NetIFUpdate = 1;
651 }
652
653 /*
654 * Because we registered for several different kinds of change notifications
655 * this callback usually gets called several times in a row. We use a timer to
656 * de-bounce these so we only end up generating one event for the main thread.
657 */
658
659 CFRunLoopTimerSetNextFireDate(threadData->timerRef,
660 CFAbsoluteTimeGetCurrent() + 5);
661 }
662
663
664 /*
665 * 'sysEventTimerNotifier()' - Handle delayed event notifications.
666 */
667
668 static void
669 sysEventTimerNotifier(
670 CFRunLoopTimerRef timer, /* I - Timer information */
671 void *context) /* I - Thread context data */
672 {
673 cupsd_thread_data_t *threadData; /* Thread context data */
674
675
676 threadData = (cupsd_thread_data_t *)context;
677
678 /*
679 * If an event is still pending send it to the main thread.
680 */
681
682 if (threadData->sysevent.event)
683 {
684 write(SysEventPipes[1], &threadData->sysevent,
685 sizeof(threadData->sysevent));
686 threadData->sysevent.event = 0;
687 }
688 }
689
690
691 /*
692 * 'sysUpdate()' - Update the current system state.
693 */
694
695 static void
696 sysUpdate(void)
697 {
698 int i; /* Looping var */
699 cupsd_sysevent_t sysevent; /* The system event */
700 cupsd_printer_t *p; /* Printer information */
701
702
703 /*
704 * Drain the event pipe...
705 */
706
707 while (read((int)SysEventPipes[0], &sysevent, sizeof(sysevent))
708 == sizeof(sysevent))
709 {
710 if (sysevent.event & SYSEVENT_CANSLEEP)
711 {
712 /*
713 * If there are active printers that don't have the connecting-to-device
714 * printer-state-reason then cancel the sleep request (i.e. this reason
715 * indicates a job that is not yet connected to the printer)...
716 */
717
718 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
719 p;
720 p = (cupsd_printer_t *)cupsArrayNext(Printers))
721 {
722 if (p->job)
723 {
724 for (i = 0; i < p->num_reasons; i ++)
725 if (!strcmp(p->reasons[i], "connecting-to-device"))
726 break;
727
728 if (!p->num_reasons || i >= p->num_reasons)
729 break;
730 }
731 }
732
733 if (p)
734 {
735 cupsdLogMessage(CUPSD_LOG_INFO,
736 "System sleep canceled because printer %s is active",
737 p->name);
738 IOCancelPowerChange(sysevent.powerKernelPort,
739 sysevent.powerNotificationID);
740 }
741 else
742 {
743 cupsdLogMessage(CUPSD_LOG_DEBUG, "System wants to sleep");
744 IOAllowPowerChange(sysevent.powerKernelPort,
745 sysevent.powerNotificationID);
746 }
747 }
748
749 if (sysevent.event & SYSEVENT_WILLSLEEP)
750 {
751 cupsdLogMessage(CUPSD_LOG_DEBUG, "System going to sleep");
752
753 Sleeping = 1;
754
755 cupsdStopAllJobs(0);
756
757 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
758 p;
759 p = (cupsd_printer_t *)cupsArrayNext(Printers))
760 {
761 if (p->type & CUPS_PRINTER_DISCOVERED)
762 {
763 cupsdLogMessage(CUPSD_LOG_DEBUG,
764 "Deleting remote destination \"%s\"", p->name);
765 cupsArraySave(Printers);
766 cupsdDeletePrinter(p, 0);
767 cupsArrayRestore(Printers);
768 }
769 else
770 {
771 cupsdLogMessage(CUPSD_LOG_DEBUG,
772 "Deregistering local printer \"%s\"", p->name);
773 cupsdDeregisterPrinter(p, 0);
774 }
775 }
776
777 cupsdCleanDirty();
778
779 IOAllowPowerChange(sysevent.powerKernelPort,
780 sysevent.powerNotificationID);
781 }
782
783 if (sysevent.event & SYSEVENT_WOKE)
784 {
785 cupsdLogMessage(CUPSD_LOG_DEBUG, "System woke from sleep");
786 IOAllowPowerChange(sysevent.powerKernelPort,
787 sysevent.powerNotificationID);
788 Sleeping = 0;
789 cupsdCheckJobs();
790 }
791
792 if (sysevent.event & SYSEVENT_NETCHANGED)
793 {
794 if (!Sleeping)
795 {
796 cupsdLogMessage(CUPSD_LOG_DEBUG,
797 "System network configuration changed");
798
799 /*
800 * Resetting browse_time before calling cupsdSendBrowseList causes
801 * browse packets to be sent for local shared printers.
802 */
803
804 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
805 p;
806 p = (cupsd_printer_t *)cupsArrayNext(Printers))
807 p->browse_time = 0;
808
809 cupsdSendBrowseList();
810 cupsdRestartPolling();
811 }
812 else
813 cupsdLogMessage(CUPSD_LOG_DEBUG,
814 "System network configuration changed; "
815 "ignored while sleeping");
816 }
817
818 if (sysevent.event & SYSEVENT_NAMECHANGED)
819 {
820 if (!Sleeping)
821 {
822 cupsdLogMessage(CUPSD_LOG_DEBUG, "Computer name changed");
823
824 /*
825 * De-register the individual printers...
826 */
827
828 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
829 p;
830 p = (cupsd_printer_t *)cupsArrayNext(Printers))
831 cupsdDeregisterPrinter(p, 1);
832
833 /*
834 * Update the computer name...
835 */
836
837 cupsdUpdateDNSSDName();
838
839 /*
840 * Now re-register them...
841 */
842
843 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
844 p;
845 p = (cupsd_printer_t *)cupsArrayNext(Printers))
846 {
847 p->browse_time = 0;
848 cupsdRegisterPrinter(p);
849 }
850 }
851 else
852 cupsdLogMessage(CUPSD_LOG_DEBUG,
853 "Computer name changed; ignored while sleeping");
854 }
855 }
856 }
857 #endif /* __APPLE__ */
858
859
860 /*
861 * End of "$Id: sysman.c 7676 2008-06-18 23:42:37Z mike $".
862 */