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