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