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