Blame scheduler/sysman.c

Packit 2fc92b
/*
Packit 2fc92b
 * System management functions for the CUPS scheduler.
Packit 2fc92b
 *
Packit 2fc92b
 * Copyright 2007-2017 by Apple Inc.
Packit 2fc92b
 * Copyright 2006 by Easy Software Products.
Packit 2fc92b
 *
Packit 2fc92b
 * These coded instructions, statements, and computer programs are the
Packit 2fc92b
 * property of Apple Inc. and are protected by Federal copyright
Packit 2fc92b
 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
Packit 2fc92b
 * which should have been included with this file.  If this file is
Packit 2fc92b
 * missing or damaged, see the license at "http://www.cups.org/".
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * Include necessary headers...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
#include "cupsd.h"
Packit 2fc92b
#ifdef __APPLE__
Packit 2fc92b
#  include <xpc/xpc.h>
Packit 2fc92b
#  include <IOKit/pwr_mgt/IOPMLib.h>
Packit 2fc92b
#endif /* __APPLE__ */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * The system management functions cover disk and power management which
Packit 2fc92b
 * are primarily used for portable computers.
Packit 2fc92b
 *
Packit 2fc92b
 * Disk management involves delaying the write of certain configuration
Packit 2fc92b
 * and state files to minimize the number of times the disk has to spin
Packit 2fc92b
 * up or flash to be written to.
Packit 2fc92b
 *
Packit 2fc92b
 * Power management support is currently only implemented on macOS, but
Packit 2fc92b
 * essentially we use four functions to let the OS know when it is OK to
Packit 2fc92b
 * put the system to sleep, typically when we are not in the middle of
Packit 2fc92b
 * printing a job.  And on macOS we can also "sleep print" - basically the
Packit 2fc92b
 * system only wakes up long enough to service network requests and process
Packit 2fc92b
 * print jobs.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdCleanDirty()' - Write dirty config and state files.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
cupsdCleanDirty(void)
Packit 2fc92b
{
Packit 2fc92b
  if (DirtyFiles & CUPSD_DIRTY_PRINTERS)
Packit 2fc92b
    cupsdSaveAllPrinters();
Packit 2fc92b
Packit 2fc92b
  if (DirtyFiles & CUPSD_DIRTY_CLASSES)
Packit 2fc92b
    cupsdSaveAllClasses();
Packit 2fc92b
Packit 2fc92b
  if (DirtyFiles & CUPSD_DIRTY_PRINTCAP)
Packit 2fc92b
    cupsdWritePrintcap();
Packit 2fc92b
Packit 2fc92b
  if (DirtyFiles & CUPSD_DIRTY_JOBS)
Packit 2fc92b
  {
Packit 2fc92b
    cupsd_job_t	*job;			/* Current job */
Packit 2fc92b
Packit 2fc92b
    cupsdSaveAllJobs();
Packit 2fc92b
Packit 2fc92b
    for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
Packit 2fc92b
         job;
Packit 2fc92b
	 job = (cupsd_job_t *)cupsArrayNext(Jobs))
Packit 2fc92b
      if (job->dirty)
Packit 2fc92b
        cupsdSaveJob(job);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  if (DirtyFiles & CUPSD_DIRTY_SUBSCRIPTIONS)
Packit 2fc92b
    cupsdSaveAllSubscriptions();
Packit 2fc92b
Packit 2fc92b
  DirtyFiles     = CUPSD_DIRTY_NONE;
Packit 2fc92b
  DirtyCleanTime = 0;
Packit 2fc92b
Packit 2fc92b
  cupsdSetBusyState(0);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdMarkDirty()' - Mark config or state files as needing a write.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
cupsdMarkDirty(int what)		/* I - What file(s) are dirty? */
Packit 2fc92b
{
Packit 2fc92b
  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdMarkDirty(%c%c%c%c%c)",
Packit 2fc92b
		  (what & CUPSD_DIRTY_PRINTERS) ? 'P' : '-',
Packit 2fc92b
		  (what & CUPSD_DIRTY_CLASSES) ? 'C' : '-',
Packit 2fc92b
		  (what & CUPSD_DIRTY_PRINTCAP) ? 'p' : '-',
Packit 2fc92b
		  (what & CUPSD_DIRTY_JOBS) ? 'J' : '-',
Packit 2fc92b
		  (what & CUPSD_DIRTY_SUBSCRIPTIONS) ? 'S' : '-');
Packit 2fc92b
Packit 2fc92b
  if (what == CUPSD_DIRTY_PRINTCAP && !Printcap)
Packit 2fc92b
    return;
Packit 2fc92b
Packit 2fc92b
  DirtyFiles |= what;
Packit 2fc92b
Packit 2fc92b
  if (!DirtyCleanTime)
Packit 2fc92b
    DirtyCleanTime = time(NULL) + DirtyCleanInterval;
Packit 2fc92b
Packit 2fc92b
  cupsdSetBusyState(0);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdSetBusyState()' - Let the system know when we are busy doing something.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
cupsdSetBusyState(int working)          /* I - Doing significant work? */
Packit 2fc92b
{
Packit 2fc92b
  int			i;		/* Looping var */
Packit 2fc92b
  cupsd_job_t		*job;		/* Current job */
Packit 2fc92b
  cupsd_printer_t	*p;		/* Current printer */
Packit 2fc92b
  int			newbusy;	/* New busy state */
Packit 2fc92b
  static int		busy = 0;	/* Current busy state */
Packit 2fc92b
  static const char * const busy_text[] =
Packit 2fc92b
  {					/* Text for busy states */
Packit 2fc92b
    "Not busy",
Packit 2fc92b
    "Dirty files",
Packit 2fc92b
    "Printing jobs",
Packit 2fc92b
    "Printing jobs and dirty files",
Packit 2fc92b
    "Active clients",
Packit 2fc92b
    "Active clients and dirty files",
Packit 2fc92b
    "Active clients and printing jobs",
Packit 2fc92b
    "Active clients, printing jobs, and dirty files"
Packit 2fc92b
  };
Packit 2fc92b
#ifdef __APPLE__
Packit 2fc92b
  static int tran = 0;	/* Current busy transaction */
Packit 2fc92b
  static IOPMAssertionID keep_awake = 0;/* Keep the system awake while printing */
Packit 2fc92b
#endif /* __APPLE__ */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Figure out how busy we are...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  newbusy = (DirtyCleanTime ? 1 : 0) |
Packit 2fc92b
	    ((working || cupsArrayCount(ActiveClients) > 0) ? 4 : 0);
Packit 2fc92b
Packit 2fc92b
  for (job = (cupsd_job_t *)cupsArrayFirst(PrintingJobs);
Packit 2fc92b
       job;
Packit 2fc92b
       job = (cupsd_job_t *)cupsArrayNext(PrintingJobs))
Packit 2fc92b
  {
Packit 2fc92b
    if ((p = job->printer) != NULL)
Packit 2fc92b
    {
Packit 2fc92b
      for (i = 0; i < p->num_reasons; i ++)
Packit 2fc92b
	if (!strcmp(p->reasons[i], "connecting-to-device"))
Packit 2fc92b
	  break;
Packit 2fc92b
Packit 2fc92b
      if (!p->num_reasons || i >= p->num_reasons)
Packit 2fc92b
	break;
Packit 2fc92b
    }
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  if (job)
Packit 2fc92b
    newbusy |= 2;
Packit 2fc92b
Packit 2fc92b
  cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
                  "cupsdSetBusyState: newbusy=\"%s\", busy=\"%s\"",
Packit 2fc92b
                  busy_text[newbusy], busy_text[busy]);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Manage state changes...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if (newbusy != busy)
Packit 2fc92b
  {
Packit 2fc92b
    busy = newbusy;
Packit 2fc92b
Packit 2fc92b
#ifdef __APPLE__
Packit 2fc92b
    if (busy && !tran)
Packit 2fc92b
    {
Packit 2fc92b
      xpc_transaction_begin();
Packit 2fc92b
      tran = 1;
Packit 2fc92b
    }
Packit 2fc92b
    else if (!busy && tran)
Packit 2fc92b
    {
Packit 2fc92b
      xpc_transaction_end();
Packit 2fc92b
      tran = 0;
Packit 2fc92b
    }
Packit 2fc92b
#endif /* __APPLE__ */
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
#ifdef __APPLE__
Packit 2fc92b
  if (cupsArrayCount(PrintingJobs) > 0 && !keep_awake)
Packit 2fc92b
  {
Packit 2fc92b
    cupsdLogMessage(CUPSD_LOG_DEBUG, "Asserting NetworkClientActive.");
Packit 2fc92b
Packit 2fc92b
    IOPMAssertionCreateWithName(kIOPMAssertNetworkClientActive,
Packit 2fc92b
				kIOPMAssertionLevelOn,
Packit 2fc92b
				CFSTR("org.cups.cupsd"), &keep_awake);
Packit 2fc92b
  }
Packit 2fc92b
  else if (cupsArrayCount(PrintingJobs) == 0 && keep_awake)
Packit 2fc92b
  {
Packit 2fc92b
    cupsdLogMessage(CUPSD_LOG_DEBUG, "Releasing power assertion.");
Packit 2fc92b
    IOPMAssertionRelease(keep_awake);
Packit 2fc92b
    keep_awake = 0;
Packit 2fc92b
  }
Packit 2fc92b
#endif /* __APPLE__ */
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
#ifdef __APPLE__
Packit 2fc92b
/*
Packit 2fc92b
 * This is the Apple-specific system event code.  It works by creating
Packit 2fc92b
 * a worker thread that waits for events from the OS and relays them
Packit 2fc92b
 * to the main thread via a traditional pipe.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * Include MacOS-specific headers...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
#  include <notify.h>
Packit 2fc92b
#  include <IOKit/IOKitLib.h>
Packit 2fc92b
#  include <IOKit/IOMessage.h>
Packit 2fc92b
#  include <IOKit/ps/IOPowerSources.h>
Packit 2fc92b
#  include <IOKit/pwr_mgt/IOPMLib.h>
Packit 2fc92b
#  include <SystemConfiguration/SystemConfiguration.h>
Packit 2fc92b
#  include <pthread.h>
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * Constants...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
#  define SYSEVENT_CANSLEEP	0x1	/* Decide whether to allow sleep or not */
Packit 2fc92b
#  define SYSEVENT_WILLSLEEP	0x2	/* Computer will go to sleep */
Packit 2fc92b
#  define SYSEVENT_WOKE		0x4	/* Computer woke from sleep */
Packit 2fc92b
#  define SYSEVENT_NETCHANGED	0x8	/* Network changed */
Packit 2fc92b
#  define SYSEVENT_NAMECHANGED	0x10	/* Computer name changed */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * Structures...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
typedef struct cupsd_sysevent_s		/*** System event data ****/
Packit 2fc92b
{
Packit 2fc92b
  unsigned char	event;			/* Event bit field */
Packit 2fc92b
  io_connect_t	powerKernelPort;	/* Power context data */
Packit 2fc92b
  long		powerNotificationID;	/* Power event data */
Packit 2fc92b
} cupsd_sysevent_t;
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
typedef struct cupsd_thread_data_s	/*** Thread context data  ****/
Packit 2fc92b
{
Packit 2fc92b
  cupsd_sysevent_t	sysevent;	/* System event */
Packit 2fc92b
  CFRunLoopTimerRef	timerRef;	/* Timer to delay some change *
Packit 2fc92b
					 * notifications              */
Packit 2fc92b
} cupsd_thread_data_t;
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * Local globals...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static pthread_t	SysEventThread = NULL;
Packit 2fc92b
					/* Thread to host a runloop */
Packit 2fc92b
static pthread_mutex_t	SysEventThreadMutex = { 0 };
Packit 2fc92b
					/* Coordinates access to shared gloabals */
Packit 2fc92b
static pthread_cond_t	SysEventThreadCond = { 0 };
Packit 2fc92b
					/* Thread initialization complete condition */
Packit 2fc92b
static CFRunLoopRef	SysEventRunloop = NULL;
Packit 2fc92b
					/* The runloop. Access must be protected! */
Packit 2fc92b
static CFStringRef	ComputerNameKey = NULL,
Packit 2fc92b
					/* Computer name key */
Packit 2fc92b
			BTMMKey = NULL,	/* Back to My Mac key */
Packit 2fc92b
			NetworkGlobalKeyIPv4 = NULL,
Packit 2fc92b
					/* Network global IPv4 key */
Packit 2fc92b
			NetworkGlobalKeyIPv6 = NULL,
Packit 2fc92b
					/* Network global IPv6 key */
Packit 2fc92b
			NetworkGlobalKeyDNS = NULL,
Packit 2fc92b
					/* Network global DNS key */
Packit 2fc92b
			HostNamesKey = NULL,
Packit 2fc92b
					/* Host name key */
Packit 2fc92b
			NetworkInterfaceKeyIPv4 = NULL,
Packit 2fc92b
					/* Netowrk interface key */
Packit 2fc92b
			NetworkInterfaceKeyIPv6 = NULL;
Packit 2fc92b
					/* Netowrk interface key */
Packit 2fc92b
static cupsd_sysevent_t	LastSysEvent;	/* Last system event (for delayed sleep) */
Packit 2fc92b
static int		NameChanged = 0;/* Did we get a 'name changed' event during sleep? */
Packit 2fc92b
static int		PSToken = 0;	/* Power source notifications */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * Local functions...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static void	*sysEventThreadEntry(void);
Packit 2fc92b
static void	sysEventPowerNotifier(void *context, io_service_t service,
Packit 2fc92b
		                      natural_t messageType,
Packit 2fc92b
				      void *messageArgument);
Packit 2fc92b
static void	sysEventConfigurationNotifier(SCDynamicStoreRef store,
Packit 2fc92b
		                              CFArrayRef changedKeys,
Packit 2fc92b
					      void *context);
Packit 2fc92b
static void	sysEventTimerNotifier(CFRunLoopTimerRef timer, void *context);
Packit 2fc92b
static void	sysUpdate(void);
Packit 2fc92b
static void	sysUpdateNames(void);
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdAllowSleep()' - Tell the OS it is now OK to sleep.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
cupsdAllowSleep(void)
Packit 2fc92b
{
Packit 2fc92b
  cupsdCleanDirty();
Packit 2fc92b
Packit 2fc92b
  cupsdLogMessage(CUPSD_LOG_DEBUG, "Allowing system sleep.");
Packit 2fc92b
  IOAllowPowerChange(LastSysEvent.powerKernelPort,
Packit 2fc92b
		     LastSysEvent.powerNotificationID);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdStartSystemMonitor()' - Start monitoring for system change.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
cupsdStartSystemMonitor(void)
Packit 2fc92b
{
Packit 2fc92b
  int	flags;				/* fcntl flags on pipe */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartSystemMonitor()");
Packit 2fc92b
Packit 2fc92b
  if (cupsdOpenPipe(SysEventPipes))
Packit 2fc92b
  {
Packit 2fc92b
    cupsdLogMessage(CUPSD_LOG_ERROR, "System event monitor pipe() failed - %s!",
Packit 2fc92b
                    strerror(errno));
Packit 2fc92b
    return;
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  cupsdAddSelect(SysEventPipes[0], (cupsd_selfunc_t)sysUpdate, NULL, NULL);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Set non-blocking mode on the descriptor we will be receiving notification
Packit 2fc92b
  * events on.
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  flags = fcntl(SysEventPipes[0], F_GETFL, 0);
Packit 2fc92b
  fcntl(SysEventPipes[0], F_SETFL, flags | O_NONBLOCK);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Start the thread that runs the runloop...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  pthread_mutex_init(&SysEventThreadMutex, NULL);
Packit 2fc92b
  pthread_cond_init(&SysEventThreadCond, NULL);
Packit 2fc92b
  pthread_create(&SysEventThread, NULL, (void *(*)(void *))sysEventThreadEntry, NULL);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Monitor for power source changes via dispatch queue...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartSystemMonitor: IOPSGetTimeRemainingEstimate=%f", IOPSGetTimeRemainingEstimate());
Packit 2fc92b
  ACPower = IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited;
Packit 2fc92b
  notify_register_dispatch(kIOPSNotifyPowerSource, &PSToken, dispatch_get_main_queue(), ^(int t) { (void)t;
Packit 2fc92b
      ACPower = IOPSGetTimeRemainingEstimate() == kIOPSTimeRemainingUnlimited; });
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdStopSystemMonitor()' - Stop monitoring for system change.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
cupsdStopSystemMonitor(void)
Packit 2fc92b
{
Packit 2fc92b
  CFRunLoopRef	rl;			/* The event handler runloop */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStopSystemMonitor()");
Packit 2fc92b
Packit 2fc92b
  if (SysEventThread)
Packit 2fc92b
  {
Packit 2fc92b
   /*
Packit 2fc92b
    * Make sure the thread has completed it's initialization and
Packit 2fc92b
    * stored it's runloop reference in the shared global.
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    pthread_mutex_lock(&SysEventThreadMutex);
Packit 2fc92b
Packit 2fc92b
    if (!SysEventRunloop)
Packit 2fc92b
      pthread_cond_wait(&SysEventThreadCond, &SysEventThreadMutex);
Packit 2fc92b
Packit 2fc92b
    rl              = SysEventRunloop;
Packit 2fc92b
    SysEventRunloop = NULL;
Packit 2fc92b
Packit 2fc92b
    pthread_mutex_unlock(&SysEventThreadMutex);
Packit 2fc92b
Packit 2fc92b
    if (rl)
Packit 2fc92b
      CFRunLoopStop(rl);
Packit 2fc92b
Packit 2fc92b
    pthread_join(SysEventThread, NULL);
Packit 2fc92b
    pthread_mutex_destroy(&SysEventThreadMutex);
Packit 2fc92b
    pthread_cond_destroy(&SysEventThreadCond);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  if (SysEventPipes[0] >= 0)
Packit 2fc92b
  {
Packit 2fc92b
    cupsdRemoveSelect(SysEventPipes[0]);
Packit 2fc92b
    cupsdClosePipe(SysEventPipes);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  if (PSToken != 0)
Packit 2fc92b
  {
Packit 2fc92b
    notify_cancel(PSToken);
Packit 2fc92b
    PSToken = 0;
Packit 2fc92b
  }
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'sysEventThreadEntry()' - A thread to receive power and computer name
Packit 2fc92b
 *                           change notifications.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static void *				/* O - Return status/value */
Packit 2fc92b
sysEventThreadEntry(void)
Packit 2fc92b
{
Packit 2fc92b
  io_object_t		powerNotifierObj;
Packit 2fc92b
					/* Power notifier object */
Packit 2fc92b
  IONotificationPortRef powerNotifierPort;
Packit 2fc92b
					/* Power notifier port */
Packit 2fc92b
  SCDynamicStoreRef	store    = NULL;/* System Config dynamic store */
Packit 2fc92b
  CFRunLoopSourceRef	powerRLS = NULL,/* Power runloop source */
Packit 2fc92b
			storeRLS = NULL;/* System Config runloop source */
Packit 2fc92b
  CFStringRef		key[6],		/* System Config keys */
Packit 2fc92b
			pattern[2];	/* System Config patterns */
Packit 2fc92b
  CFArrayRef		keys = NULL,	/* System Config key array*/
Packit 2fc92b
			patterns = NULL;/* System Config pattern array */
Packit 2fc92b
  SCDynamicStoreContext	storeContext;	/* Dynamic store context */
Packit 2fc92b
  CFRunLoopTimerContext timerContext;	/* Timer context */
Packit 2fc92b
  cupsd_thread_data_t	threadData;	/* Thread context data for the *
Packit 2fc92b
					 * runloop notifiers           */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Register for power state change notifications
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  bzero(&threadData, sizeof(threadData));
Packit 2fc92b
Packit 2fc92b
  threadData.sysevent.powerKernelPort =
Packit 2fc92b
      IORegisterForSystemPower(&threadData, &powerNotifierPort,
Packit 2fc92b
                               sysEventPowerNotifier, &powerNotifierObj);
Packit 2fc92b
Packit 2fc92b
  if (threadData.sysevent.powerKernelPort)
Packit 2fc92b
  {
Packit 2fc92b
    powerRLS = IONotificationPortGetRunLoopSource(powerNotifierPort);
Packit 2fc92b
    CFRunLoopAddSource(CFRunLoopGetCurrent(), powerRLS, kCFRunLoopDefaultMode);
Packit 2fc92b
  }
Packit 2fc92b
  else
Packit 2fc92b
    DEBUG_puts("sysEventThreadEntry: error registering for system power "
Packit 2fc92b
               "notifications");
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Register for system configuration change notifications
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  bzero(&storeContext, sizeof(storeContext));
Packit 2fc92b
  storeContext.info = &threadData;
Packit 2fc92b
Packit 2fc92b
  store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"),
Packit 2fc92b
                               sysEventConfigurationNotifier, &storeContext);
Packit 2fc92b
Packit 2fc92b
  if (!ComputerNameKey)
Packit 2fc92b
    ComputerNameKey = SCDynamicStoreKeyCreateComputerName(kCFAllocatorDefault);
Packit 2fc92b
Packit 2fc92b
  if (!BTMMKey)
Packit 2fc92b
    BTMMKey = SCDynamicStoreKeyCreate(kCFAllocatorDefault,
Packit 2fc92b
                                      CFSTR("Setup:/Network/BackToMyMac"));
Packit 2fc92b
Packit 2fc92b
  if (!NetworkGlobalKeyIPv4)
Packit 2fc92b
    NetworkGlobalKeyIPv4 =
Packit 2fc92b
        SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault,
Packit 2fc92b
                                                   kSCDynamicStoreDomainState,
Packit 2fc92b
						   kSCEntNetIPv4);
Packit 2fc92b
Packit 2fc92b
  if (!NetworkGlobalKeyIPv6)
Packit 2fc92b
    NetworkGlobalKeyIPv6 =
Packit 2fc92b
        SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault,
Packit 2fc92b
                                                   kSCDynamicStoreDomainState,
Packit 2fc92b
						   kSCEntNetIPv6);
Packit 2fc92b
Packit 2fc92b
  if (!NetworkGlobalKeyDNS)
Packit 2fc92b
    NetworkGlobalKeyDNS =
Packit 2fc92b
	SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault,
Packit 2fc92b
						   kSCDynamicStoreDomainState,
Packit 2fc92b
						   kSCEntNetDNS);
Packit 2fc92b
Packit 2fc92b
  if (!HostNamesKey)
Packit 2fc92b
    HostNamesKey = SCDynamicStoreKeyCreateHostNames(kCFAllocatorDefault);
Packit 2fc92b
Packit 2fc92b
  if (!NetworkInterfaceKeyIPv4)
Packit 2fc92b
    NetworkInterfaceKeyIPv4 =
Packit 2fc92b
        SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault,
Packit 2fc92b
	                                              kSCDynamicStoreDomainState,
Packit 2fc92b
						      kSCCompAnyRegex,
Packit 2fc92b
						      kSCEntNetIPv4);
Packit 2fc92b
Packit 2fc92b
  if (!NetworkInterfaceKeyIPv6)
Packit 2fc92b
    NetworkInterfaceKeyIPv6 =
Packit 2fc92b
        SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault,
Packit 2fc92b
	                                              kSCDynamicStoreDomainState,
Packit 2fc92b
						      kSCCompAnyRegex,
Packit 2fc92b
						      kSCEntNetIPv6);
Packit 2fc92b
Packit 2fc92b
  if (store && ComputerNameKey && HostNamesKey &&
Packit 2fc92b
      NetworkGlobalKeyIPv4 && NetworkGlobalKeyIPv6 && NetworkGlobalKeyDNS &&
Packit 2fc92b
      NetworkInterfaceKeyIPv4 && NetworkInterfaceKeyIPv6)
Packit 2fc92b
  {
Packit 2fc92b
    key[0]     = ComputerNameKey;
Packit 2fc92b
    key[1]     = BTMMKey;
Packit 2fc92b
    key[2]     = NetworkGlobalKeyIPv4;
Packit 2fc92b
    key[3]     = NetworkGlobalKeyIPv6;
Packit 2fc92b
    key[4]     = NetworkGlobalKeyDNS;
Packit 2fc92b
    key[5]     = HostNamesKey;
Packit 2fc92b
Packit 2fc92b
    pattern[0] = NetworkInterfaceKeyIPv4;
Packit 2fc92b
    pattern[1] = NetworkInterfaceKeyIPv6;
Packit 2fc92b
Packit 2fc92b
    keys     = CFArrayCreate(kCFAllocatorDefault, (const void **)key,
Packit 2fc92b
			     sizeof(key) / sizeof(key[0]),
Packit 2fc92b
			     &kCFTypeArrayCallBacks);
Packit 2fc92b
Packit 2fc92b
    patterns = CFArrayCreate(kCFAllocatorDefault, (const void **)pattern,
Packit 2fc92b
                             sizeof(pattern) / sizeof(pattern[0]),
Packit 2fc92b
			     &kCFTypeArrayCallBacks);
Packit 2fc92b
Packit 2fc92b
    if (keys && patterns &&
Packit 2fc92b
        SCDynamicStoreSetNotificationKeys(store, keys, patterns))
Packit 2fc92b
    {
Packit 2fc92b
      if ((storeRLS = SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault,
Packit 2fc92b
                                                        store, 0)) != NULL)
Packit 2fc92b
      {
Packit 2fc92b
	CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRLS,
Packit 2fc92b
	                   kCFRunLoopDefaultMode);
Packit 2fc92b
      }
Packit 2fc92b
      else
Packit 2fc92b
	DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreateRunLoopSource "
Packit 2fc92b
	              "failed: %s\n", SCErrorString(SCError())));
Packit 2fc92b
    }
Packit 2fc92b
    else
Packit 2fc92b
      DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreSetNotificationKeys "
Packit 2fc92b
                    "failed: %s\n", SCErrorString(SCError())));
Packit 2fc92b
  }
Packit 2fc92b
  else
Packit 2fc92b
    DEBUG_printf(("sysEventThreadEntry: SCDynamicStoreCreate failed: %s\n",
Packit 2fc92b
                  SCErrorString(SCError())));
Packit 2fc92b
Packit 2fc92b
  if (keys)
Packit 2fc92b
    CFRelease(keys);
Packit 2fc92b
Packit 2fc92b
  if (patterns)
Packit 2fc92b
    CFRelease(patterns);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Set up a timer to delay the wake change notifications.
Packit 2fc92b
  *
Packit 2fc92b
  * The initial time is set a decade or so into the future, we'll adjust
Packit 2fc92b
  * this later.
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  bzero(&timerContext, sizeof(timerContext));
Packit 2fc92b
  timerContext.info = &threadData;
Packit 2fc92b
Packit 2fc92b
  threadData.timerRef =
Packit 2fc92b
      CFRunLoopTimerCreate(kCFAllocatorDefault,
Packit 2fc92b
                           CFAbsoluteTimeGetCurrent() + (86400L * 365L * 10L),
Packit 2fc92b
			   86400L * 365L * 10L, 0, 0, sysEventTimerNotifier,
Packit 2fc92b
			   &timerContext);
Packit 2fc92b
  CFRunLoopAddTimer(CFRunLoopGetCurrent(), threadData.timerRef,
Packit 2fc92b
                    kCFRunLoopDefaultMode);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Store our runloop in a global so the main thread can use it to stop us.
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  pthread_mutex_lock(&SysEventThreadMutex);
Packit 2fc92b
Packit 2fc92b
  SysEventRunloop = CFRunLoopGetCurrent();
Packit 2fc92b
Packit 2fc92b
  pthread_cond_signal(&SysEventThreadCond);
Packit 2fc92b
  pthread_mutex_unlock(&SysEventThreadMutex);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Disappear into the runloop until it's stopped by the main thread.
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  CFRunLoopRun();
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Clean up before exiting.
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if (threadData.timerRef)
Packit 2fc92b
  {
Packit 2fc92b
    CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), threadData.timerRef,
Packit 2fc92b
                         kCFRunLoopDefaultMode);
Packit 2fc92b
    CFRelease(threadData.timerRef);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  if (threadData.sysevent.powerKernelPort)
Packit 2fc92b
  {
Packit 2fc92b
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerRLS,
Packit 2fc92b
                          kCFRunLoopDefaultMode);
Packit 2fc92b
    IODeregisterForSystemPower(&powerNotifierObj);
Packit 2fc92b
    IOServiceClose(threadData.sysevent.powerKernelPort);
Packit 2fc92b
    IONotificationPortDestroy(powerNotifierPort);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  if (storeRLS)
Packit 2fc92b
  {
Packit 2fc92b
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), storeRLS,
Packit 2fc92b
                          kCFRunLoopDefaultMode);
Packit 2fc92b
    CFRunLoopSourceInvalidate(storeRLS);
Packit 2fc92b
    CFRelease(storeRLS);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  if (store)
Packit 2fc92b
    CFRelease(store);
Packit 2fc92b
Packit 2fc92b
  pthread_exit(NULL);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'sysEventPowerNotifier()' - Handle power notification events.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static void
Packit 2fc92b
sysEventPowerNotifier(
Packit 2fc92b
    void         *context,		/* I - Thread context data */
Packit 2fc92b
    io_service_t service,		/* I - Unused service info */
Packit 2fc92b
    natural_t    messageType,		/* I - Type of message */
Packit 2fc92b
    void         *messageArgument)	/* I - Message data */
Packit 2fc92b
{
Packit 2fc92b
  int			sendit = 1;	/* Send event to main thread?    *
Packit 2fc92b
					 * (0 = no, 1 = yes, 2 = delayed */
Packit 2fc92b
  cupsd_thread_data_t	*threadData;	/* Thread context data */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  threadData = (cupsd_thread_data_t *)context;
Packit 2fc92b
Packit 2fc92b
  (void)service;			/* anti-compiler-warning-code */
Packit 2fc92b
Packit 2fc92b
  switch (messageType)
Packit 2fc92b
  {
Packit 2fc92b
    case kIOMessageCanSystemPowerOff :
Packit 2fc92b
    case kIOMessageCanSystemSleep :
Packit 2fc92b
	threadData->sysevent.event |= SYSEVENT_CANSLEEP;
Packit 2fc92b
	break;
Packit 2fc92b
Packit 2fc92b
    case kIOMessageSystemWillRestart :
Packit 2fc92b
    case kIOMessageSystemWillPowerOff :
Packit 2fc92b
    case kIOMessageSystemWillSleep :
Packit 2fc92b
	threadData->sysevent.event |= SYSEVENT_WILLSLEEP;
Packit 2fc92b
	threadData->sysevent.event &= ~SYSEVENT_WOKE;
Packit 2fc92b
	break;
Packit 2fc92b
Packit 2fc92b
    case kIOMessageSystemHasPoweredOn :
Packit 2fc92b
       /*
Packit 2fc92b
	* Because powered on is followed by a net-changed event, delay
Packit 2fc92b
	* before sending it.
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
        sendit = 2;
Packit 2fc92b
	threadData->sysevent.event |= SYSEVENT_WOKE;
Packit 2fc92b
	break;
Packit 2fc92b
Packit 2fc92b
    case kIOMessageSystemWillNotPowerOff :
Packit 2fc92b
    case kIOMessageSystemWillNotSleep :
Packit 2fc92b
#  ifdef kIOMessageSystemWillPowerOn
Packit 2fc92b
    case kIOMessageSystemWillPowerOn :
Packit 2fc92b
#  endif /* kIOMessageSystemWillPowerOn */
Packit 2fc92b
    default:
Packit 2fc92b
	sendit = 0;
Packit 2fc92b
	break;
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  switch (messageType)
Packit 2fc92b
  {
Packit 2fc92b
    case kIOMessageCanSystemPowerOff :
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
                        "Got kIOMessageCanSystemPowerOff message.");
Packit 2fc92b
	break;
Packit 2fc92b
    case kIOMessageCanSystemSleep :
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
                        "Got kIOMessageCannSystemSleep message.");
Packit 2fc92b
	break;
Packit 2fc92b
    case kIOMessageSystemWillRestart :
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
                        "Got kIOMessageSystemWillRestart message.");
Packit 2fc92b
	break;
Packit 2fc92b
    case kIOMessageSystemWillPowerOff :
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
                        "Got kIOMessageSystemWillPowerOff message.");
Packit 2fc92b
	break;
Packit 2fc92b
    case kIOMessageSystemWillSleep :
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
                        "Got kIOMessageSystemWillSleep message.");
Packit 2fc92b
	break;
Packit 2fc92b
    case kIOMessageSystemHasPoweredOn :
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
                        "Got kIOMessageSystemHasPoweredOn message.");
Packit 2fc92b
	break;
Packit 2fc92b
    case kIOMessageSystemWillNotPowerOff :
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
                        "Got kIOMessageSystemWillNotPowerOff message.");
Packit 2fc92b
	break;
Packit 2fc92b
    case kIOMessageSystemWillNotSleep :
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
                        "Got kIOMessageSystemWillNotSleep message.");
Packit 2fc92b
	break;
Packit 2fc92b
#  ifdef kIOMessageSystemWillPowerOn
Packit 2fc92b
    case kIOMessageSystemWillPowerOn :
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
                        "Got kIOMessageSystemWillPowerOn message.");
Packit 2fc92b
	break;
Packit 2fc92b
#  endif /* kIOMessageSystemWillPowerOn */
Packit 2fc92b
    default:
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG, "Got unknown power message %d.",
Packit 2fc92b
                        (int)messageType);
Packit 2fc92b
	break;
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  if (sendit == 0)
Packit 2fc92b
    IOAllowPowerChange(threadData->sysevent.powerKernelPort,
Packit 2fc92b
                       (long)messageArgument);
Packit 2fc92b
  else
Packit 2fc92b
  {
Packit 2fc92b
    threadData->sysevent.powerNotificationID = (long)messageArgument;
Packit 2fc92b
Packit 2fc92b
    if (sendit == 1)
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * Send the event to the main thread now.
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      write(SysEventPipes[1], &threadData->sysevent,
Packit 2fc92b
	    sizeof(threadData->sysevent));
Packit 2fc92b
      threadData->sysevent.event = 0;
Packit 2fc92b
    }
Packit 2fc92b
    else
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * Send the event to the main thread after 1 to 2 seconds.
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      CFRunLoopTimerSetNextFireDate(threadData->timerRef,
Packit 2fc92b
                                    CFAbsoluteTimeGetCurrent() + 2);
Packit 2fc92b
    }
Packit 2fc92b
  }
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'sysEventConfigurationNotifier()' - Network configuration change notification
Packit 2fc92b
 *                                     callback.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static void
Packit 2fc92b
sysEventConfigurationNotifier(
Packit 2fc92b
    SCDynamicStoreRef store,		/* I - System data (unused) */
Packit 2fc92b
    CFArrayRef        changedKeys,	/* I - Changed data */
Packit 2fc92b
    void              *context)		/* I - Thread context data */
Packit 2fc92b
{
Packit 2fc92b
  cupsd_thread_data_t	*threadData;	/* Thread context data */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  threadData = (cupsd_thread_data_t *)context;
Packit 2fc92b
Packit 2fc92b
  (void)store;				/* anti-compiler-warning-code */
Packit 2fc92b
Packit 2fc92b
  CFRange range = CFRangeMake(0, CFArrayGetCount(changedKeys));
Packit 2fc92b
Packit 2fc92b
  if (CFArrayContainsValue(changedKeys, range, ComputerNameKey) ||
Packit 2fc92b
      CFArrayContainsValue(changedKeys, range, BTMMKey))
Packit 2fc92b
    threadData->sysevent.event |= SYSEVENT_NAMECHANGED;
Packit 2fc92b
  else
Packit 2fc92b
  {
Packit 2fc92b
    threadData->sysevent.event |= SYSEVENT_NETCHANGED;
Packit 2fc92b
Packit 2fc92b
   /*
Packit 2fc92b
    * Indicate the network interface list needs updating...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    NetIFUpdate = 1;
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Because we registered for several different kinds of change notifications
Packit 2fc92b
  * this callback usually gets called several times in a row. We use a timer to
Packit 2fc92b
  * de-bounce these so we only end up generating one event for the main thread.
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  CFRunLoopTimerSetNextFireDate(threadData->timerRef,
Packit 2fc92b
  				CFAbsoluteTimeGetCurrent() + 5);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'sysEventTimerNotifier()' - Handle delayed event notifications.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static void
Packit 2fc92b
sysEventTimerNotifier(
Packit 2fc92b
    CFRunLoopTimerRef timer,		/* I - Timer information */
Packit 2fc92b
    void              *context)		/* I - Thread context data */
Packit 2fc92b
{
Packit 2fc92b
  cupsd_thread_data_t	*threadData;	/* Thread context data */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  (void)timer;
Packit 2fc92b
Packit 2fc92b
  threadData = (cupsd_thread_data_t *)context;
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * If an event is still pending send it to the main thread.
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if (threadData->sysevent.event)
Packit 2fc92b
  {
Packit 2fc92b
    write(SysEventPipes[1], &threadData->sysevent,
Packit 2fc92b
          sizeof(threadData->sysevent));
Packit 2fc92b
    threadData->sysevent.event = 0;
Packit 2fc92b
  }
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'sysUpdate()' - Update the current system state.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static void
Packit 2fc92b
sysUpdate(void)
Packit 2fc92b
{
Packit 2fc92b
  int			i;		/* Looping var */
Packit 2fc92b
  cupsd_sysevent_t	sysevent;	/* The system event */
Packit 2fc92b
  cupsd_printer_t	*p;		/* Printer information */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Drain the event pipe...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  while (read((int)SysEventPipes[0], &sysevent, sizeof(sysevent))
Packit 2fc92b
             == sizeof(sysevent))
Packit 2fc92b
  {
Packit 2fc92b
    if (sysevent.event & SYSEVENT_CANSLEEP)
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * If there are active printers that don't have the connecting-to-device
Packit 2fc92b
      * or cups-waiting-for-job-completed printer-state-reason then cancel the
Packit 2fc92b
      * sleep request, i.e., these reasons indicate a job that is not actively
Packit 2fc92b
      * doing anything...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
Packit 2fc92b
           p;
Packit 2fc92b
	   p = (cupsd_printer_t *)cupsArrayNext(Printers))
Packit 2fc92b
      {
Packit 2fc92b
        if (p->job)
Packit 2fc92b
        {
Packit 2fc92b
	  for (i = 0; i < p->num_reasons; i ++)
Packit 2fc92b
	    if (!strcmp(p->reasons[i], "connecting-to-device") ||
Packit 2fc92b
	        !strcmp(p->reasons[i], "cups-waiting-for-job-completed"))
Packit 2fc92b
	      break;
Packit 2fc92b
Packit 2fc92b
	  if (!p->num_reasons || i >= p->num_reasons)
Packit 2fc92b
	    break;
Packit 2fc92b
        }
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
      if (p)
Packit 2fc92b
      {
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_INFO,
Packit 2fc92b
	                "System sleep canceled because printer %s is active.",
Packit 2fc92b
	                p->name);
Packit 2fc92b
        IOCancelPowerChange(sysevent.powerKernelPort,
Packit 2fc92b
	                    sysevent.powerNotificationID);
Packit 2fc92b
      }
Packit 2fc92b
      else
Packit 2fc92b
      {
Packit 2fc92b
	cupsdLogMessage(CUPSD_LOG_DEBUG, "System wants to sleep.");
Packit 2fc92b
        IOAllowPowerChange(sysevent.powerKernelPort,
Packit 2fc92b
	                   sysevent.powerNotificationID);
Packit 2fc92b
      }
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    if (sysevent.event & SYSEVENT_WILLSLEEP)
Packit 2fc92b
    {
Packit 2fc92b
      cupsdLogMessage(CUPSD_LOG_DEBUG, "System going to sleep.");
Packit 2fc92b
Packit 2fc92b
      Sleeping = 1;
Packit 2fc92b
Packit 2fc92b
      cupsdCleanDirty();
Packit 2fc92b
Packit 2fc92b
     /*
Packit 2fc92b
      * If we have no printing jobs, allow the power change immediately.
Packit 2fc92b
      * Otherwise set the SleepJobs time to 10 seconds in the future when
Packit 2fc92b
      * we'll take more drastic measures...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      if (cupsArrayCount(PrintingJobs) == 0)
Packit 2fc92b
      {
Packit 2fc92b
	cupsdLogMessage(CUPSD_LOG_DEBUG, "Allowing system sleep.");
Packit 2fc92b
	IOAllowPowerChange(sysevent.powerKernelPort,
Packit 2fc92b
			   sysevent.powerNotificationID);
Packit 2fc92b
      }
Packit 2fc92b
      else
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
	* If there are active printers that don't have the connecting-to-device
Packit 2fc92b
	* or cups-waiting-for-job-completed printer-state-reasons then delay the
Packit 2fc92b
	* sleep request, i.e., these reasons indicate a job is active...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
	for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
Packit 2fc92b
	     p;
Packit 2fc92b
	     p = (cupsd_printer_t *)cupsArrayNext(Printers))
Packit 2fc92b
	{
Packit 2fc92b
	  if (p->job)
Packit 2fc92b
	  {
Packit 2fc92b
	    for (i = 0; i < p->num_reasons; i ++)
Packit 2fc92b
	      if (!strcmp(p->reasons[i], "connecting-to-device") ||
Packit 2fc92b
	          !strcmp(p->reasons[i], "cups-waiting-for-job-completed"))
Packit 2fc92b
		break;
Packit 2fc92b
Packit 2fc92b
	    if (!p->num_reasons || i >= p->num_reasons)
Packit 2fc92b
	      break;
Packit 2fc92b
	  }
Packit 2fc92b
	}
Packit 2fc92b
Packit 2fc92b
	if (p)
Packit 2fc92b
	{
Packit 2fc92b
	  cupsdLogMessage(CUPSD_LOG_INFO,
Packit 2fc92b
			  "System sleep delayed because printer %s is active.",
Packit 2fc92b
			  p->name);
Packit 2fc92b
Packit 2fc92b
	  LastSysEvent = sysevent;
Packit 2fc92b
	  SleepJobs    = time(NULL) + 10;
Packit 2fc92b
	}
Packit 2fc92b
	else
Packit 2fc92b
	{
Packit 2fc92b
	  cupsdLogMessage(CUPSD_LOG_DEBUG, "Allowing system sleep.");
Packit 2fc92b
	  IOAllowPowerChange(sysevent.powerKernelPort,
Packit 2fc92b
			     sysevent.powerNotificationID);
Packit 2fc92b
	}
Packit 2fc92b
      }
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    if (sysevent.event & SYSEVENT_WOKE)
Packit 2fc92b
    {
Packit 2fc92b
      cupsdLogMessage(CUPSD_LOG_DEBUG, "System woke from sleep.");
Packit 2fc92b
      IOAllowPowerChange(sysevent.powerKernelPort,
Packit 2fc92b
                         sysevent.powerNotificationID);
Packit 2fc92b
      Sleeping = 0;
Packit 2fc92b
Packit 2fc92b
     /*
Packit 2fc92b
      * Make sure jobs that were queued prior to the system going to sleep don't
Packit 2fc92b
      * get canceled right away...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      if (MaxJobTime > 0)
Packit 2fc92b
      {
Packit 2fc92b
        cupsd_job_t	*job;		/* Current job */
Packit 2fc92b
Packit 2fc92b
        for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
Packit 2fc92b
             job;
Packit 2fc92b
             job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
Packit 2fc92b
        {
Packit 2fc92b
          if (job->cancel_time)
Packit 2fc92b
          {
Packit 2fc92b
            ipp_attribute_t *cancel_after = ippFindAttribute(job->attrs,
Packit 2fc92b
                                                             "job-cancel-after",
Packit 2fc92b
                                                             IPP_TAG_INTEGER);
Packit 2fc92b
Packit 2fc92b
            if (cancel_after)
Packit 2fc92b
              job->cancel_time = time(NULL) + ippGetInteger(cancel_after, 0);
Packit 2fc92b
            else
Packit 2fc92b
              job->cancel_time = time(NULL) + MaxJobTime;
Packit 2fc92b
          }
Packit 2fc92b
        }
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
      if (NameChanged)
Packit 2fc92b
        sysUpdateNames();
Packit 2fc92b
Packit 2fc92b
      cupsdCheckJobs();
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    if (sysevent.event & SYSEVENT_NETCHANGED)
Packit 2fc92b
    {
Packit 2fc92b
      if (Sleeping)
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
	                "System network configuration changed - "
Packit 2fc92b
			"ignored while sleeping.");
Packit 2fc92b
      else
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
	                "System network configuration changed.");
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    if (sysevent.event & SYSEVENT_NAMECHANGED)
Packit 2fc92b
    {
Packit 2fc92b
      if (Sleeping)
Packit 2fc92b
      {
Packit 2fc92b
        NameChanged = 1;
Packit 2fc92b
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
	                "Computer name or BTMM domains changed - ignored while "
Packit 2fc92b
			"sleeping.");
Packit 2fc92b
      }
Packit 2fc92b
      else
Packit 2fc92b
      {
Packit 2fc92b
        cupsdLogMessage(CUPSD_LOG_DEBUG,
Packit 2fc92b
	                "Computer name or BTMM domains changed.");
Packit 2fc92b
Packit 2fc92b
        sysUpdateNames();
Packit 2fc92b
      }
Packit 2fc92b
    }
Packit 2fc92b
  }
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'sysUpdateNames()' - Update computer and/or BTMM domains.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static void
Packit 2fc92b
sysUpdateNames(void)
Packit 2fc92b
{
Packit 2fc92b
  cupsd_printer_t	*p;		/* Current printer */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  NameChanged = 0;
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * De-register the individual printers...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
Packit 2fc92b
       p;
Packit 2fc92b
       p = (cupsd_printer_t *)cupsArrayNext(Printers))
Packit 2fc92b
    cupsdDeregisterPrinter(p, 1);
Packit 2fc92b
Packit 2fc92b
#  if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
Packit 2fc92b
 /*
Packit 2fc92b
  * Update the computer name and BTMM domain list...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  cupsdUpdateDNSSDName();
Packit 2fc92b
#  endif /* HAVE_DNSSD || HAVE_AVAHI */
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Now re-register them...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
Packit 2fc92b
       p;
Packit 2fc92b
       p = (cupsd_printer_t *)cupsArrayNext(Printers))
Packit 2fc92b
    cupsdRegisterPrinter(p);
Packit 2fc92b
}
Packit 2fc92b
#endif	/* __APPLE__ */