Esempio n. 1
0
/* A generic wait function for threads that poll that will wait a specified
 * time tdiff waiting on a work restart request. Returns zero if the condition
 * was met (work restart requested) or ETIMEDOUT if not.
 */
int restart_wait(struct thr_info *thr, unsigned int mstime)
{
	struct timeval tv_timer, tv_now, tv_timeout;
	fd_set rfds;
	SOCKETTYPE wrn = thr->work_restart_notifier[0];
	int rv;
	
	if (unlikely(thr->work_restart_notifier[1] == INVSOCK))
	{
		// This is a bug!
		applog(LOG_ERR, "%"PRIpreprv": restart_wait called without a work_restart_notifier", thr->cgpu->proc_repr);
		cgsleep_ms(mstime);
		return (thr->work_restart ? 0 : ETIMEDOUT);
	}
	
	timer_set_now(&tv_now);
	timer_set_delay(&tv_timer, &tv_now, mstime * 1000);
	while (true)
	{
		FD_ZERO(&rfds);
		FD_SET(wrn, &rfds);
		tv_timeout = tv_timer;
		rv = select(wrn + 1, &rfds, NULL, NULL, select_timeout(&tv_timeout, &tv_now));
		if (rv == 0)
			return ETIMEDOUT;
		if (rv > 0)
		{
			if (thr->work_restart)
				return 0;
			notifier_read(thr->work_restart_notifier);
		}
		timer_set_now(&tv_now);
	}
}
Esempio n. 2
0
int clildfolw(int *fdsin, int fdsnum)
{
    printf("[%d] child start\n", getpid());

    int *fdsout = new int[fdsnum];
    while (true)
    {
        if (g_signal.HandleSignals() < 0)
            break;

        memset(fdsout, 0, sizeof(int)* fdsnum);
        int nRet = select_timeout(fdsin, fdsnum, fdsout, NULL);
        if (nRet <= 0)
        {
            printf("[%d] select_timeout failed\n", getpid());
            break;
        }

        for (int i = 0; i < nRet; i++)
        {
            if (fdsout[i] != 0)
            {
                printf("[%d] select fd OK %d\n", getpid(), fdsout[i]);
                
                char buff[128] = { 0 };
                int len = read(fdsout[i], buff, 1);
                if (len == 0)
                {
                    printf("[%d] socket close %s,%d\n", getpid(), strerror(errno),fdsout[i]);
                    delete fdsout;
                    return 0;
                }
                if (len < 0)
                {
                    printf("[%d] read failed %s,%d\n", getpid(), strerror(errno),fdsout[i]);
                    continue;
                }
                if (len == 1)
                    printf("[%d] read 1 byte :%s\n", getpid(), buff);

            }
        }
    }
    delete fdsout;
    return 0;
}
Esempio n. 3
0
static
void do_notifier_select(struct thr_info *thr, struct timeval *tvp_timeout)
{
	struct cgpu_info *cgpu = thr->cgpu;
	struct timeval tv_now;
	int maxfd;
	fd_set rfds;
	
	timer_set_now(&tv_now);
	FD_ZERO(&rfds);
	FD_SET(thr->notifier[0], &rfds);
	maxfd = thr->notifier[0];
	FD_SET(thr->work_restart_notifier[0], &rfds);
	set_maxfd(&maxfd, thr->work_restart_notifier[0]);
	if (thr->mutex_request[1] != INVSOCK)
	{
		FD_SET(thr->mutex_request[0], &rfds);
		set_maxfd(&maxfd, thr->mutex_request[0]);
	}
	if (select(maxfd + 1, &rfds, NULL, NULL, select_timeout(tvp_timeout, &tv_now)) < 0)
		return;
	if (thr->mutex_request[1] != INVSOCK && FD_ISSET(thr->mutex_request[0], &rfds))
	{
		// FIXME: This can only handle one request at a time!
		pthread_mutex_t *mutexp = &cgpu->device_mutex;
		notifier_read(thr->mutex_request);
		mutex_lock(mutexp);
		pthread_cond_signal(&cgpu->device_cond);
		pthread_cond_wait(&cgpu->device_cond, mutexp);
		mutex_unlock(mutexp);
	}
	if (FD_ISSET(thr->notifier[0], &rfds)) {
		notifier_read(thr->notifier);
	}
	if (FD_ISSET(thr->work_restart_notifier[0], &rfds))
		notifier_read(thr->work_restart_notifier);
}
Esempio n. 4
0
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line arguments */
{
  int			i;		/* Looping var */
  char			*opt;		/* Option character */
  int			fg;		/* Run in the foreground */
  int			fds;		/* Number of ready descriptors */
  cupsd_client_t	*con;		/* Current client */
  cupsd_job_t		*job;		/* Current job */
  cupsd_listener_t	*lis;		/* Current listener */
  time_t		current_time,	/* Current time */
			activity,	/* Client activity timer */
			senddoc_time,	/* Send-Document time */
			expire_time,	/* Subscription expire time */
			report_time,	/* Malloc/client/job report time */
			event_time;	/* Last event notification time */
  long			timeout;	/* Timeout for cupsdDoSelect() */
  struct rlimit		limit;		/* Runtime limit */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
  struct sigaction	action;		/* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
#ifdef __sgi
  cups_file_t		*fp;		/* Fake lpsched lock file */
  struct stat		statbuf;	/* Needed for checking lpsched FIFO */
#endif /* __sgi */
  int			run_as_child = 0;
					/* Needed for background fork/exec */
#ifdef __APPLE__
  int			use_sysman = !getuid();
					/* Use system management functions? */
#else
  time_t		netif_time = 0;	/* Time since last network update */
#endif /* __APPLE__ */
#if HAVE_LAUNCHD
  int			launchd_idle_exit;
					/* Idle exit on select timeout? */
#endif	/* HAVE_LAUNCHD */


#ifdef HAVE_GETEUID
 /*
  * Check for setuid invocation, which we do not support!
  */

  if (getuid() != geteuid())
  {
    fputs("cupsd: Cannot run as a setuid program\n", stderr);
    return (1);
  }
#endif /* HAVE_GETEUID */

 /*
  * Check for command-line arguments...
  */

  fg = 0;

#ifdef HAVE_LAUNCHD
  if (getenv("CUPSD_LAUNCHD"))
  {
    Launchd = 1;
    fg      = 1;
  }
#endif /* HAVE_LAUNCHD */

  for (i = 1; i < argc; i ++)
    if (argv[i][0] == '-')
      for (opt = argv[i] + 1; *opt != '\0'; opt ++)
        switch (*opt)
	{
	  case 'C' : /* Run as child with config file */
              run_as_child = 1;
	      fg           = -1;

	  case 'c' : /* Configuration file */
	      i ++;
	      if (i >= argc)
	      {
	        _cupsLangPuts(stderr, _("cupsd: Expected config filename "
		                        "after \"-c\" option."));
	        usage(1);
	      }

              if (argv[i][0] == '/')
	      {
	       /*
	        * Absolute directory...
		*/

		cupsdSetString(&ConfigurationFile, argv[i]);
              }
	      else
	      {
	       /*
	        * Relative directory...
		*/

                char *current;		/* Current directory */


	       /*
	        * Allocate a buffer for the current working directory to
		* reduce run-time stack usage; this approximates the
		* behavior of some implementations of getcwd() when they
		* are passed a NULL pointer.
	        */

                if ((current = malloc(1024)) == NULL)
		{
		  _cupsLangPuts(stderr,
		                _("cupsd: Unable to get current directory."));
                  return (1);
		}

		if (!getcwd(current, 1024))
		{
		  _cupsLangPuts(stderr,
		                _("cupsd: Unable to get current directory."));
                  free(current);
		  return (1);
		}

		cupsdSetStringf(&ConfigurationFile, "%s/%s", current, argv[i]);
		free(current);
              }
	      break;

          case 'f' : /* Run in foreground... */
	      fg = 1;
	      break;

          case 'F' : /* Run in foreground, but disconnect from terminal... */
	      fg = -1;
	      break;

          case 'h' : /* Show usage/help */
	      usage(0);
	      break;

          case 'l' : /* Started by launchd... */
#ifdef HAVE_LAUNCHD
	      Launchd = 1;
	      fg      = 1;
#else
	      _cupsLangPuts(stderr, _("cupsd: launchd(8) support not compiled "
	                              "in, running in normal mode."));
              fg = 0;
#endif /* HAVE_LAUNCHD */
	      break;

          case 'p' : /* Stop immediately for profiling */
              fputs("cupsd: -p (startup profiling) is for internal testing "
                    "use only!\n", stderr);
	      stop_scheduler = 1;
	      fg             = 1;
	      break;

          case 'P' : /* Disable security profiles */
              fputs("cupsd: -P (disable security profiles) is for internal "
                    "testing use only!\n", stderr);
	      UseProfiles = 0;
	      break;

#ifdef __APPLE__
          case 'S' : /* Disable system management functions */
              fputs("cupsd: -S (disable system management) for internal "
                    "testing use only!\n", stderr);
	      use_sysman = 0;
	      break;
#endif /* __APPLE__ */

          case 't' : /* Test the cupsd.conf file... */
	      TestConfigFile = 1;
	      fg             = 1;
	      break;

	  default : /* Unknown option */
              _cupsLangPrintf(stderr, _("cupsd: Unknown option \"%c\" - "
	                                "aborting."), *opt);
	      usage(1);
	      break;
	}
    else
    {
      _cupsLangPrintf(stderr, _("cupsd: Unknown argument \"%s\" - aborting."),
                      argv[i]);
      usage(1);
    }

  if (!ConfigurationFile)
    cupsdSetString(&ConfigurationFile, CUPS_SERVERROOT "/cupsd.conf");

 /*
  * If the user hasn't specified "-f", run in the background...
  */

  if (!fg)
  {
   /*
    * Setup signal handlers for the parent...
    */

#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
    sigset(SIGUSR1, parent_handler);
    sigset(SIGCHLD, parent_handler);

    sigset(SIGHUP, SIG_IGN);
#elif defined(HAVE_SIGACTION)
    memset(&action, 0, sizeof(action));
    sigemptyset(&action.sa_mask);
    sigaddset(&action.sa_mask, SIGUSR1);
    action.sa_handler = parent_handler;
    sigaction(SIGUSR1, &action, NULL);
    sigaction(SIGCHLD, &action, NULL);

    sigemptyset(&action.sa_mask);
    action.sa_handler = SIG_IGN;
    sigaction(SIGHUP, &action, NULL);
#else
    signal(SIGUSR1, parent_handler);
    signal(SIGCLD, parent_handler);

    signal(SIGHUP, SIG_IGN);
#endif /* HAVE_SIGSET */

    if (fork() > 0)
    {
     /*
      * OK, wait for the child to startup and send us SIGUSR1 or to crash
      * and the OS send us SIGCHLD...  We also need to ignore SIGHUP which
      * might be sent by the init script to restart the scheduler...
      */

      for (; parent_signal == 0;)
        sleep(1);

      if (parent_signal == SIGUSR1)
        return (0);

      if (wait(&i) < 0)
      {
        perror("cupsd");
	return (1);
      }
      else if (WIFEXITED(i))
      {
        fprintf(stderr, "cupsd: Child exited with status %d\n",
	        WEXITSTATUS(i));
	return (2);
      }
      else
      {
        fprintf(stderr, "cupsd: Child exited on signal %d\n", WTERMSIG(i));
	return (3);
      }
    }

#ifdef __OpenBSD__
   /*
    * Call _thread_sys_closefrom() so the child process doesn't reset the
    * parent's file descriptors to be blocking.  This is a workaround for a
    * limitation of userland libpthread on OpenBSD.
    */

    _thread_sys_closefrom(0);
#endif /* __OpenBSD__ */

   /*
    * Since CoreFoundation and DBUS both create fork-unsafe data on execution of
    * a program, and since this kind of really unfriendly behavior seems to be
    * more common these days in system libraries, we need to re-execute the
    * background cupsd with the "-C" option to avoid problems.  Unfortunately,
    * we also have to assume that argv[0] contains the name of the cupsd
    * executable - there is no portable way to get the real pathname...
    */

    execlp(argv[0], argv[0], "-C", ConfigurationFile, (char *)0);
    exit(errno);
  }

  if (fg < 1)
  {
   /*
    * Make sure we aren't tying up any filesystems...
    */

    chdir("/");

#ifndef DEBUG
   /*
    * Disable core dumps...
    */

    getrlimit(RLIMIT_CORE, &limit);
    limit.rlim_cur = 0;
    setrlimit(RLIMIT_CORE, &limit);

   /*
    * Disconnect from the controlling terminal...
    */

    setsid();

   /*
    * Close all open files...
    */

    getrlimit(RLIMIT_NOFILE, &limit);

    for (i = 0; i < limit.rlim_cur && i < 1024; i ++)
      close(i);

   /*
    * Redirect stdin/out/err to /dev/null...
    */

    if ((i = open("/dev/null", O_RDONLY)) != 0)
    {
      dup2(i, 0);
      close(i);
    }

    if ((i = open("/dev/null", O_WRONLY)) != 1)
    {
      dup2(i, 1);
      close(i);
    }

    if ((i = open("/dev/null", O_WRONLY)) != 2)
    {
      dup2(i, 2);
      close(i);
    }
#endif /* DEBUG */
  }

 /*
  * Set the timezone info...
  */

  tzset();

#ifdef LC_TIME
  setlocale(LC_TIME, "");
#endif /* LC_TIME */

 /*
  * Set the maximum number of files...
  */

  getrlimit(RLIMIT_NOFILE, &limit);

#if !defined(HAVE_POLL) && !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE)
  if (limit.rlim_max > FD_SETSIZE)
    MaxFDs = FD_SETSIZE;
  else
#endif /* !HAVE_POLL && !HAVE_EPOLL && !HAVE_KQUEUE */
#ifdef RLIM_INFINITY
  if (limit.rlim_max == RLIM_INFINITY)
    MaxFDs = 16384;
  else
#endif /* RLIM_INFINITY */
    MaxFDs = limit.rlim_max;

  limit.rlim_cur = MaxFDs;

  setrlimit(RLIMIT_NOFILE, &limit);

  cupsdStartSelect();

 /*
  * Read configuration...
  */

  if (!cupsdReadConfiguration())
  {
    if (TestConfigFile)
      printf("%s contains errors\n", ConfigurationFile);
    else
      syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
	     ConfigurationFile);
    return (1);
  }
  else if (TestConfigFile)
  {
    printf("%s is OK\n", ConfigurationFile);
    return (0);
  }

 /*
  * Clean out old temp files and printer cache data.
  */

  if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)))
    cupsdCleanFiles(TempDir, NULL);

  cupsdCleanFiles(CacheDir, "*.ipp");

#if HAVE_LAUNCHD
  if (Launchd)
  {
   /*
    * If we were started by launchd get the listen sockets file descriptors...
    */

    launchd_checkin();
    launchd_checkout();
  }
#endif /* HAVE_LAUNCHD */

 /*
  * Startup the server...
  */

  httpInitialize();

  cupsdStartServer();

 /*
  * Catch hangup and child signals and ignore broken pipes...
  */

#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
  sigset(SIGCHLD, sigchld_handler);
  sigset(SIGHUP, sighup_handler);
  sigset(SIGPIPE, SIG_IGN);
  sigset(SIGTERM, sigterm_handler);
#elif defined(HAVE_SIGACTION)
  memset(&action, 0, sizeof(action));

  sigemptyset(&action.sa_mask);
  sigaddset(&action.sa_mask, SIGTERM);
  sigaddset(&action.sa_mask, SIGCHLD);
  action.sa_handler = sigchld_handler;
  sigaction(SIGCHLD, &action, NULL);

  sigemptyset(&action.sa_mask);
  sigaddset(&action.sa_mask, SIGHUP);
  action.sa_handler = sighup_handler;
  sigaction(SIGHUP, &action, NULL);

  sigemptyset(&action.sa_mask);
  action.sa_handler = SIG_IGN;
  sigaction(SIGPIPE, &action, NULL);

  sigemptyset(&action.sa_mask);
  sigaddset(&action.sa_mask, SIGTERM);
  sigaddset(&action.sa_mask, SIGCHLD);
  action.sa_handler = sigterm_handler;
  sigaction(SIGTERM, &action, NULL);
#else
  signal(SIGCLD, sigchld_handler);	/* No, SIGCLD isn't a typo... */
  signal(SIGHUP, sighup_handler);
  signal(SIGPIPE, SIG_IGN);
  signal(SIGTERM, sigterm_handler);
#endif /* HAVE_SIGSET */

#ifdef __sgi
 /*
  * Try to create a fake lpsched lock file if one is not already there.
  * Some Adobe applications need it under IRIX in order to enable
  * printing...
  */

  if ((fp = cupsFileOpen("/var/spool/lp/SCHEDLOCK", "w")) == NULL)
  {
    syslog(LOG_LPR, "Unable to create fake lpsched lock file "
                    "\"/var/spool/lp/SCHEDLOCK\"\' - %s!",
           strerror(errno));
  }
  else
  {
    fchmod(cupsFileNumber(fp), 0644);
    fchown(cupsFileNumber(fp), User, Group);

    cupsFileClose(fp);
  }
#endif /* __sgi */

 /*
  * Initialize authentication certificates...
  */

  cupsdInitCerts();

 /*
  * If we are running in the background, signal the parent process that
  * we are up and running...
  */

  if (!fg || run_as_child)
  {
   /*
    * Send a signal to the parent process, but only if the parent is
    * not PID 1 (init).  This avoids accidentally shutting down the
    * system on OpenBSD if you CTRL-C the server before it is up...
    */

    i = getppid();	/* Save parent PID to avoid race condition */

    if (i != 1)
      kill(i, SIGUSR1);
  }

#ifdef __APPLE__
 /*
  * Start power management framework...
  */

  if (use_sysman)
    cupsdStartSystemMonitor();
#endif /* __APPLE__ */

 /*
  * Send server-started event...
  */

#ifdef HAVE_LAUNCHD
  if (Launchd)
    cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL,
                  "Scheduler started via launchd.");
  else
#endif /* HAVE_LAUNCHD */
  if (fg)
    cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL,
                  "Scheduler started in foreground.");
  else
    cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL,
                  "Scheduler started in background.");

 /*
  * Start any pending print jobs...
  */

  cupsdCheckJobs();

 /*
  * Loop forever...
  */

  current_time  = time(NULL);
  event_time    = current_time;
  expire_time   = current_time;
  fds           = 1;
  report_time   = 0;
  senddoc_time  = current_time;

  while (!stop_scheduler)
  {
   /*
    * Check if there are dead children to handle...
    */

    if (dead_children)
      process_children();

   /*
    * Check if we need to load the server configuration file...
    */

    if (NeedReload)
    {
     /*
      * Close any idle clients...
      */

      if (cupsArrayCount(Clients) > 0)
      {
	for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
	     con;
	     con = (cupsd_client_t *)cupsArrayNext(Clients))
	  if (con->http.state == HTTP_WAITING)
	    cupsdCloseClient(con);
	  else
	    con->http.keep_alive = HTTP_KEEPALIVE_OFF;

        cupsdPauseListening();
      }

     /*
      * Restart if all clients are closed and all jobs finished, or
      * if the reload timeout has elapsed...
      */

      if ((cupsArrayCount(Clients) == 0 &&
           (cupsArrayCount(PrintingJobs) == 0 || NeedReload != RELOAD_ALL)) ||
          (time(NULL) - ReloadTime) >= ReloadTimeout)
      {
       /*
	* Shutdown the server...
	*/

        DoingShutdown = 1;

	cupsdStopServer();

       /*
	* Read configuration...
	*/

        if (!cupsdReadConfiguration())
        {
          syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
		 ConfigurationFile);
          break;
	}

#if HAVE_LAUNCHD
	if (Launchd)
	{
	 /*
	  * If we were started by launchd, get the listen socket file
	  * descriptors...
	  */

	  launchd_checkin();
	  launchd_checkout();
	}
#endif /* HAVE_LAUNCHD */

       /*
        * Startup the server...
        */

        DoingShutdown = 0;

        cupsdStartServer();

       /*
        * Send a server-restarted event...
	*/

        cupsdAddEvent(CUPSD_EVENT_SERVER_RESTARTED, NULL, NULL,
                      "Scheduler restarted.");
      }
    }

   /*
    * Check for available input or ready output.  If cupsdDoSelect()
    * returns 0 or -1, something bad happened and we should exit
    * immediately.
    *
    * Note that we at least have one listening socket open at all
    * times.
    */

    if ((timeout = select_timeout(fds)) > 1 && LastEvent)
      timeout = 1;

#if HAVE_LAUNCHD
   /*
    * If no other work is scheduled and we're being controlled by
    * launchd then timeout after 'LaunchdTimeout' seconds of
    * inactivity...
    */

    if (timeout == 86400 && Launchd && LaunchdTimeout &&
        !cupsArrayCount(ActiveJobs) &&
	(!Browsing || !BrowseLocalProtocols || !cupsArrayCount(Printers)))
    {
      timeout		= LaunchdTimeout;
      launchd_idle_exit = 1;
    }
    else
      launchd_idle_exit = 0;
#endif	/* HAVE_LAUNCHD */

    if ((fds = cupsdDoSelect(timeout)) < 0)
    {
     /*
      * Got an error from select!
      */

#ifdef HAVE_DNSSD
      cupsd_printer_t	*p;		/* Current printer */
#endif /* HAVE_DNSSD */


      if (errno == EINTR)		/* Just interrupted by a signal */
        continue;

     /*
      * Log all sorts of debug info to help track down the problem.
      */

      cupsdLogMessage(CUPSD_LOG_EMERG, "cupsdDoSelect() failed - %s!",
                      strerror(errno));

      for (i = 0, con = (cupsd_client_t *)cupsArrayFirst(Clients);
	   con;
	   i ++, con = (cupsd_client_t *)cupsArrayNext(Clients))
        cupsdLogMessage(CUPSD_LOG_EMERG,
	                "Clients[%d] = %d, file = %d, state = %d",
	                i, con->http.fd, con->file, con->http.state);

      for (i = 0, lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
           lis;
	   i ++, lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
        cupsdLogMessage(CUPSD_LOG_EMERG, "Listeners[%d] = %d", i, lis->fd);

      cupsdLogMessage(CUPSD_LOG_EMERG, "CGIPipes[0] = %d", CGIPipes[0]);

#ifdef __APPLE__
      cupsdLogMessage(CUPSD_LOG_EMERG, "SysEventPipes[0] = %d",
                      SysEventPipes[0]);
#endif /* __APPLE__ */

      for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
	   job;
	   job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
        cupsdLogMessage(CUPSD_LOG_EMERG, "Jobs[%d] = %d < [%d %d] > [%d %d]",
	        	job->id,
			job->status_buffer ? job->status_buffer->fd : -1,
			job->print_pipes[0], job->print_pipes[1],
			job->back_pipes[0], job->back_pipes[1]);

#ifdef HAVE_DNSSD
      for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
	   p;
	   p = (cupsd_printer_t *)cupsArrayNext(Printers))
        cupsdLogMessage(CUPSD_LOG_EMERG, "printer[%s] reg_name=\"%s\"", p->name,
	                p->reg_name ? p->reg_name : "(null)");
#endif /* HAVE_DNSSD */

      break;
    }

    current_time = time(NULL);

   /*
    * Write dirty config/state files...
    */

    if (DirtyCleanTime && current_time >= DirtyCleanTime)
      cupsdCleanDirty();

#ifdef __APPLE__
   /*
    * If we are going to sleep and still have pending jobs, stop them after
    * a period of time...
    */

    if (SleepJobs > 0 && current_time >= SleepJobs &&
        cupsArrayCount(PrintingJobs) > 0)
    {
      SleepJobs = 0;
      cupsdStopAllJobs(CUPSD_JOB_DEFAULT, 5);
    }
#endif /* __APPLE__ */

#ifndef __APPLE__
   /*
    * Update the network interfaces once a minute...
    */

    if ((current_time - netif_time) >= 60)
    {
      netif_time  = current_time;
      NetIFUpdate = 1;
    }
#endif /* !__APPLE__ */

#if HAVE_LAUNCHD
   /*
    * If no other work was scheduled and we're being controlled by launchd
    * then timeout after 'LaunchdTimeout' seconds of inactivity...
    */

    if (!fds && launchd_idle_exit)
    {
      cupsdLogMessage(CUPSD_LOG_INFO,
                      "Printer sharing is off and there are no jobs pending, "
		      "will restart on demand.");
      stop_scheduler = 1;
      break;
    }
#endif /* HAVE_LAUNCHD */

   /*
    * Resume listening for new connections as needed...
    */

    if (ListeningPaused && ListeningPaused <= current_time &&
        cupsArrayCount(Clients) < MaxClients)
      cupsdResumeListening();

   /*
    * Expire subscriptions and unload completed jobs as needed...
    */

    if (current_time > expire_time)
    {
      if (cupsArrayCount(Subscriptions) > 0)
        cupsdExpireSubscriptions(NULL, NULL);

      cupsdUnloadCompletedJobs();

      expire_time = current_time;
    }

#ifndef HAVE_AUTHORIZATION_H
   /*
    * Update the root certificate once every 5 minutes if we have client
    * connections...
    */

    if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration &&
        !RunUser && cupsArrayCount(Clients))
    {
     /*
      * Update the root certificate...
      */

      cupsdDeleteCert(0);
      cupsdAddCert(0, "root", NULL);
    }
#endif /* !HAVE_AUTHORIZATION_H */

   /*
    * Check for new data on the client sockets...
    */

    for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
	 con;
	 con = (cupsd_client_t *)cupsArrayNext(Clients))
    {
     /*
      * Process pending data in the input buffer...
      */

      if (con->http.used)
      {
        cupsdReadClient(con);
	continue;
      }

     /*
      * Check the activity and close old clients...
      */

      activity = current_time - Timeout;
      if (con->http.activity < activity && !con->pipe_pid)
      {
        cupsdLogMessage(CUPSD_LOG_DEBUG,
	                "Closing client %d after %d seconds of inactivity...",
	                con->http.fd, Timeout);

        cupsdCloseClient(con);
        continue;
      }
    }

   /*
    * Update any pending multi-file documents...
    */

    if ((current_time - senddoc_time) >= 10)
    {
      cupsdCheckJobs();
      senddoc_time = current_time;
    }

   /*
    * Clean job history...
    */

    if (JobHistoryUpdate && current_time >= JobHistoryUpdate)
      cupsdCleanJobs();

   /*
    * Log statistics at most once a minute when in debug mode...
    */

    if ((current_time - report_time) >= 60 && LogLevel >= CUPSD_LOG_DEBUG)
    {
      size_t		string_count,	/* String count */
			alloc_bytes,	/* Allocated string bytes */
			total_bytes;	/* Total string bytes */
#ifdef HAVE_MALLINFO
      struct mallinfo	mem;		/* Malloc information */


      mem = mallinfo();
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-arena=%lu", mem.arena);
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-used=%lu",
                      mem.usmblks + mem.uordblks);
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-free=%lu",
		      mem.fsmblks + mem.fordblks);
#endif /* HAVE_MALLINFO */

      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: clients=%d",
                      cupsArrayCount(Clients));
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: jobs=%d",
                      cupsArrayCount(Jobs));
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: jobs-active=%d",
                      cupsArrayCount(ActiveJobs));
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: printers=%d",
                      cupsArrayCount(Printers));

      string_count = _cupsStrStatistics(&alloc_bytes, &total_bytes);
      cupsdLogMessage(CUPSD_LOG_DEBUG,
                      "Report: stringpool-string-count=" CUPS_LLFMT,
		      CUPS_LLCAST string_count);
      cupsdLogMessage(CUPSD_LOG_DEBUG,
                      "Report: stringpool-alloc-bytes=" CUPS_LLFMT,
		      CUPS_LLCAST alloc_bytes);
      cupsdLogMessage(CUPSD_LOG_DEBUG,
                      "Report: stringpool-total-bytes=" CUPS_LLFMT,
		      CUPS_LLCAST total_bytes);

      report_time = current_time;
    }

   /*
    * Handle OS-specific event notification for any events that have
    * accumulated.  Don't send these more than once a second...
    */

    if (LastEvent && (current_time - event_time) >= 1)
    {
#ifdef HAVE_NOTIFY_POST
      if (LastEvent & (CUPSD_EVENT_PRINTER_ADDED |
                       CUPSD_EVENT_PRINTER_DELETED |
                       CUPSD_EVENT_PRINTER_MODIFIED))
      {
        cupsdLogMessage(CUPSD_LOG_DEBUG2,
	                "notify_post(\"com.apple.printerListChange\")");
	notify_post("com.apple.printerListChange");
      }

      if (LastEvent & CUPSD_EVENT_PRINTER_STATE_CHANGED)
      {
        cupsdLogMessage(CUPSD_LOG_DEBUG2,
	                "notify_post(\"com.apple.printerHistoryChange\")");
	notify_post("com.apple.printerHistoryChange");
      }

      if (LastEvent & (CUPSD_EVENT_JOB_STATE_CHANGED |
                       CUPSD_EVENT_JOB_CONFIG_CHANGED |
                       CUPSD_EVENT_JOB_PROGRESS))
      {
        cupsdLogMessage(CUPSD_LOG_DEBUG2,
	                "notify_post(\"com.apple.jobChange\")");
	notify_post("com.apple.jobChange");
      }
#endif /* HAVE_NOTIFY_POST */

     /*
      * Reset the accumulated events...
      */

      LastEvent  = CUPSD_EVENT_NONE;
      event_time = current_time;
    }
  }

 /*
  * Log a message based on what happened...
  */

  if (stop_scheduler)
  {
    cupsdLogMessage(CUPSD_LOG_INFO, "Scheduler shutting down normally.");
    cupsdAddEvent(CUPSD_EVENT_SERVER_STOPPED, NULL, NULL,
                  "Scheduler shutting down normally.");
  }
  else
  {
    cupsdLogMessage(CUPSD_LOG_ERROR,
                    "Scheduler shutting down due to program error.");
    cupsdAddEvent(CUPSD_EVENT_SERVER_STOPPED, NULL, NULL,
                  "Scheduler shutting down due to program error.");
  }

 /*
  * Close all network clients...
  */

  DoingShutdown = 1;

  cupsdStopServer();

#ifdef HAVE_LAUNCHD
 /*
  * Update the launchd KeepAlive file as needed...
  */

  if (Launchd)
    launchd_checkout();
#endif /* HAVE_LAUNCHD */

 /*
  * Stop all jobs...
  */

  cupsdFreeAllJobs();

#ifdef __APPLE__
 /*
  * Stop monitoring system event monitoring...
  */

  if (use_sysman)
    cupsdStopSystemMonitor();
#endif /* __APPLE__ */

#ifdef HAVE_GSSAPI
 /*
  * Free the scheduler's Kerberos context...
  */

#  ifdef __APPLE__
 /*
  * If the weak-linked GSSAPI/Kerberos library is not present, don't try
  * to use it...
  */

  if (krb5_init_context != NULL)
#  endif /* __APPLE__ */
  if (KerberosContext)
    krb5_free_context(KerberosContext);
#endif /* HAVE_GSSAPI */

#ifdef __sgi
 /*
  * Remove the fake IRIX lpsched lock file, but only if the existing
  * file is not a FIFO which indicates that the real IRIX lpsched is
  * running...
  */

  if (!stat("/var/spool/lp/FIFO", &statbuf))
    if (!S_ISFIFO(statbuf.st_mode))
      unlink("/var/spool/lp/SCHEDLOCK");
#endif /* __sgi */

  cupsdStopSelect();

  return (!stop_scheduler);
}
Esempio n. 5
0
void session_loop(void(*loophandler)()) {

	fd_set readfd, writefd;
	struct timeval timeout;
	int val;

	/* main loop, select()s for all sockets in use */
	for(;;) {
		const int writequeue_has_space = (ses.writequeue_len <= 2*TRANS_MAX_PAYLOAD_LEN);

		timeout.tv_sec = select_timeout();
		timeout.tv_usec = 0;
		FD_ZERO(&writefd);
		FD_ZERO(&readfd);
		dropbear_assert(ses.payload == NULL);

		/* We get woken up when signal handlers write to this pipe.
		   SIGCHLD in svr-chansession is the only one currently. */
		FD_SET(ses.signal_pipe[0], &readfd);
		ses.channel_signal_pending = 0;

		/* set up for channels which can be read/written */
		setchannelfds(&readfd, &writefd, writequeue_has_space);

		/* Pending connections to test */
		set_connect_fds(&writefd);

		/* We delay reading from the input socket during initial setup until
		after we have written out our initial KEXINIT packet (empty writequeue). 
		This means our initial packet can be in-flight while we're doing a blocking
		read for the remote ident.
		We also avoid reading from the socket if the writequeue is full, that avoids
		replies backing up */
		if (ses.sock_in != -1 
			&& (ses.remoteident || isempty(&ses.writequeue)) 
			&& writequeue_has_space) {
			FD_SET(ses.sock_in, &readfd);
		}

		/* Ordering is important, this test must occur after any other function
		might have queued packets (such as connection handlers) */
		if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
			FD_SET(ses.sock_out, &writefd);
		}

		val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);

		if (exitflag) {
			dropbear_exit("Terminated by signal");
		}
		
		if (val < 0 && errno != EINTR) {
			dropbear_exit("Error in select");
		}

		if (val <= 0) {
			/* If we were interrupted or the select timed out, we still
			 * want to iterate over channels etc for reading, to handle
			 * server processes exiting etc. 
			 * We don't want to read/write FDs. */
			FD_ZERO(&writefd);
			FD_ZERO(&readfd);
		}
		
		/* We'll just empty out the pipe if required. We don't do
		any thing with the data, since the pipe's purpose is purely to
		wake up the select() above. */
		if (FD_ISSET(ses.signal_pipe[0], &readfd)) {
			char x;
			TRACE(("signal pipe set"))
			while (read(ses.signal_pipe[0], &x, 1) > 0) {}
			ses.channel_signal_pending = 1;
		}

		/* check for auth timeout, rekeying required etc */
		checktimeouts();

		/* process session socket's incoming data */
		if (ses.sock_in != -1) {
			if (FD_ISSET(ses.sock_in, &readfd)) {
				if (!ses.remoteident) {
					/* blocking read of the version string */
					read_session_identification();
				} else {
					read_packet();
				}
			}
			
			/* Process the decrypted packet. After this, the read buffer
			 * will be ready for a new packet */
			if (ses.payload != NULL) {
				process_packet();
			}
		}

		/* if required, flush out any queued reply packets that
		were being held up during a KEX */
		maybe_flush_reply_queue();

		handle_connect_fds(&writefd);

		/* process pipes etc for the channels, ses.dataallowed == 0
		 * during rekeying ) */
		channelio(&readfd, &writefd);

		/* process session socket's outgoing data */
		if (ses.sock_out != -1) {
			if (!isempty(&ses.writequeue)) {
				write_packet();
			}
		}


		if (loophandler) {
			loophandler();
		}

	} /* for(;;) */
Esempio n. 6
0
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[]			/* I - Command-line arguments */
#ifdef PRINT_AUXV
     ,
     char* envp[]
#endif
     )
{
  int			i;		/* Looping var */
  char			*opt;		/* Option character */
  int			fg;		/* Run in the foreground */
  int			fds;		/* Number of ready descriptors */
  cupsd_client_t	*con;		/* Current client */
  cupsd_job_t		*job;		/* Current job */
  cupsd_listener_t	*lis;		/* Current listener */
  time_t		current_time,	/* Current time */
			activity,	/* Client activity timer */
			browse_time,	/* Next browse send time */
			senddoc_time,	/* Send-Document time */
			expire_time,	/* Subscription expire time */
			report_time,	/* Malloc/client/job report time */
			event_time;	/* Last time an event notification was done */
  long			timeout;	/* Timeout for cupsdDoSelect() */
  struct rlimit		limit;		/* Runtime limit */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
  struct sigaction	action;		/* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
#ifdef __sgi
  cups_file_t		*fp;		/* Fake lpsched lock file */
  struct stat		statbuf;	/* Needed for checking lpsched FIFO */
#endif /* __sgi */
#ifdef __APPLE__
  int			run_as_child = 0;
					/* Needed for Mac OS X fork/exec */
#else
  time_t		netif_time = 0;	/* Time since last network update */
#endif /* __APPLE__ */
#if HAVE_LAUNCHD
  int			launchd_idle_exit;
					/* Idle exit on select timeout? */
#endif	/* HAVE_LAUNCHD */
    

#ifdef PRINT_AUXV
  Elf32_auxv_t *auxv;
  while(*envp++ != NULL);

  for (auxv = (Elf32_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++)
    {
      if (auxv->a_type == AT_SYSINFO)
	{
	  printf("AT_RANDOM is 0x%x\n", auxv->a_un.a_val);
	}
      
    }
#endif
 
#if UNDERSTAND_CUPS
  printf("[main.c::main()] cups has just started in main()\n");
#endif
  
  int count = 0;
  int loops_desired = -1; // loop forever unless this is set

#ifdef HAVE_GETEUID
  /*
  * Check for setuid invocation, which we do not support!
  */
  if (getuid() != geteuid())
  {
    fputs("cupsd: Cannot run as a setuid program!\n", stderr);
    return (1);
  }
#if UNDERSTAND_CUPS
  printf("[main.c::main()] uid = %d, euid = %d\n", getuid(), geteuid());
#endif
#endif /* HAVE_GETEUID */
  
 /*
  * Check for command-line arguments...
  */
#if UNDERSTAND_CUPS
  printf("[main.c::main()] parsing command line arguments \n");
#endif
  
  fg = 0;

#ifdef HAVE_LAUNCHD
  if (getenv("CUPSD_LAUNCHD"))
  {
    Launchd = 1;
    fg      = 1;
  }
#endif /* HAVE_LAUNCHD */

  for (i = 1; i < argc; i ++)
    if (argv[i][0] == '-')
      for (opt = argv[i] + 1; *opt != '\0'; opt ++)
        switch (*opt)
	{
#ifdef __APPLE__
	  case 'C' : /* Run as child with config file */
              run_as_child = 1;
	      fg           = -1;
#endif /* __APPLE__ */

	  case 'c' : /* Configuration file */
	      i ++;
	      if (i >= argc)
	      {
	        _cupsLangPuts(stderr, _("cupsd: Expected config filename "
		                        "after \"-c\" option!\n"));
	        usage(1);
	      }

              if (argv[i][0] == '/')
	      {
	       /*
	        * Absolute directory...
		*/

		cupsdSetString(&ConfigurationFile, argv[i]);
              }
	      else
	      {
	       /*
	        * Relative directory...
		*/

                char *current;		/* Current directory */


	       /*
	        * Allocate a buffer for the current working directory to
		* reduce run-time stack usage; this approximates the
		* behavior of some implementations of getcwd() when they
		* are passed a NULL pointer.
	        */

                if ((current = malloc(1024)) == NULL)
		{
		  _cupsLangPuts(stderr,
		                _("cupsd: Unable to get current directory!\n"));
                  return (1);
		}

		if (!getcwd(current, 1024))
		{
		  _cupsLangPuts(stderr,
		                _("cupsd: Unable to get current directory!\n"));
                  free(current);
		  return (1);
		}

		cupsdSetStringf(&ConfigurationFile, "%s/%s", current, argv[i]);
		free(current);
              }
	      break;

          case 'f' : /* Run in foreground... */
	    fg = 1;
	    break;
	    
          case 'F' : /* Run in foreground, but disconnect from terminal... */
	    fg = -1;
	    break;
	    
          case 'h' : /* Show usage/help */
	    usage(0);
	    break;
	    
          case 'l' : /* Started by launchd... */
#ifdef HAVE_LAUNCHD
	    Launchd = 1;
	    fg      = 1;
#else
	    _cupsLangPuts(stderr, _("cupsd: launchd(8) support not compiled "
				    "in, running in normal mode.\n"));
	    fg = 0;
#endif /* HAVE_LAUNCHD */
	      break;
	      
	case 'p' : /* Stop immediately for profiling */
	  puts("Warning: -p option is for internal testing use only!");
	  stop_scheduler = 1;
	  fg             = 1;
	  break;
	  
	/// XXX RAZA
	case 'x' : /* Number of Iterations to Perform */
	  i ++;
	  loops_desired = atoi(argv[i]);
	  break;
	  
	default : /* Unknown option */
	  _cupsLangPrintf(stderr, _("cupsd: Unknown option \"%c\" - "
				    "aborting!\n"), *opt);
	  usage(1);
	  break;
	}
    else
      {
	_cupsLangPrintf(stderr, _("cupsd: Unknown argument \"%s\" - aborting!\n"),
			argv[i]);
	usage(1);
      }

#if UNDERSTAND_CUPS
  printf("[main.c::main()] done parsing command line arguments \n");
  printf("[main.c::main()] num_loops = %d, foreground = %d\n", loops_desired, fg);
#endif

  if (!ConfigurationFile)
    cupsdSetString(&ConfigurationFile, CUPS_SERVERROOT "/cupsd.conf");

  printf("[main.c::main()] configuration file = %s\n", ConfigurationFile);
  
  /*
   * If the user hasn't specified "-f", run in the background...
  */

  if (!fg)
  {
   /*
    * Setup signal handlers for the parent...
    */

#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
    sigset(SIGUSR1, parent_handler);
    sigset(SIGCHLD, parent_handler);

    sigset(SIGHUP, SIG_IGN);
#elif defined(HAVE_SIGACTION)
    memset(&action, 0, sizeof(action));
    sigemptyset(&action.sa_mask);
    sigaddset(&action.sa_mask, SIGUSR1);
    action.sa_handler = parent_handler;
    sigaction(SIGUSR1, &action, NULL);
    sigaction(SIGCHLD, &action, NULL);

    sigemptyset(&action.sa_mask);
    action.sa_handler = SIG_IGN;
    sigaction(SIGHUP, &action, NULL);
#else
    signal(SIGUSR1, parent_handler);
    signal(SIGCLD, parent_handler);

    signal(SIGHUP, SIG_IGN);
#endif /* HAVE_SIGSET */

    if (fork() > 0)
    {
     /*
      * OK, wait for the child to startup and send us SIGUSR1 or to crash
      * and the OS send us SIGCHLD...  We also need to ignore SIGHUP which
      * might be sent by the init script to restart the scheduler...
      */

      for (; parent_signal == 0;)
        sleep(1);

      if (parent_signal == SIGUSR1)
        return (0);

      if (wait(&i) < 0)
      {
        perror("cupsd");
	return (1);
      }
      else if (WIFEXITED(i))
      {
        fprintf(stderr, "cupsd: Child exited with status %d!\n",
	        WEXITSTATUS(i));
	return (2);
      }
      else
      {
        fprintf(stderr, "cupsd: Child exited on signal %d!\n", WTERMSIG(i));
	return (3);
      }
    }

#ifdef __APPLE__
   /*
    * Since CoreFoundation has an overly-agressive check for whether a
    * process has forked but not exec'd (whether CF has been called or
    * not...), we now have to exec ourselves with the "-f" option to
    * eliminate their bogus warning messages.
    */

    execlp(argv[0], argv[0], "-C", ConfigurationFile, (char *)0);
    exit(errno);
#endif /* __APPLE__ */
  }

  if (fg < 1)
  {
   /*
    * Make sure we aren't tying up any filesystems...
    */

    chdir("/");

#ifndef DEBUG
   /*
    * Disable core dumps...
    */

    getrlimit(RLIMIT_CORE, &limit);
    limit.rlim_cur = 0;
    setrlimit(RLIMIT_CORE, &limit);

   /*
    * Disconnect from the controlling terminal...
    */

    setsid();

   /*
    * Close all open files...
    */

    getrlimit(RLIMIT_NOFILE, &limit);

    for (i = 0; i < limit.rlim_cur && i < 1024; i ++)
      close(i);
#endif /* DEBUG */
  }

 /*
  * Set the timezone info...
  */
#if UNDERSTAND_CUPS
  printf("[main.c::main()] setting timezone info, tzset()\n");
#endif

  tzset();

#ifdef LC_TIME
  setlocale(LC_TIME, "");
#if UNDERSTAND_CUPS
  printf("[main.c::main()] setting locale info, setlocale()\n");
#endif
#endif /* LC_TIME */

 /*
  * Set the maximum number of files...
  */
  getrlimit(RLIMIT_NOFILE, &limit);

#if !defined(HAVE_POLL) && !defined(HAVE_EPOLL) && !defined(HAVE_KQUEUE)
  if (limit.rlim_max > FD_SETSIZE)
    MaxFDs = FD_SETSIZE;
  else
#endif /* !HAVE_POLL && !HAVE_EPOLL && !HAVE_KQUEUE */
#ifdef RLIM_INFINITY
  if (limit.rlim_max == RLIM_INFINITY)
    MaxFDs = 16384;
  else
#endif /* RLIM_INFINITY */
    MaxFDs = limit.rlim_max;

  limit.rlim_cur = MaxFDs;

  setrlimit(RLIMIT_NOFILE, &limit);

#if UNDERSTAND_CUPS
  printf("[main.c::main()] set the maximum nuber of files = %d\n", MaxFDs);
#endif

  cupsdStartSelect();

#if UNDERSTAND_CUPS
  printf("[main.c::main()] done with cupsdStartSelect() i.e. polling engine\n");
#endif

 /*
  * Read configuration...
  */

  if (!cupsdReadConfiguration())
  {
    syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
           ConfigurationFile);
    return (1);
  }

  printf("[main.c::main()] done with cupsdReadConfiguration\n");
  
  if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)))
  {
   /*
    * Clean out the temporary directory...
    */

    cups_dir_t		*dir;		/* Temporary directory */
    cups_dentry_t	*dent;		/* Directory entry */
    char		tempfile[1024];	/* Temporary filename */

    printf("[main.c::main()] cleaning temp dir = %s\n", TempDir);

    if ((dir = cupsDirOpen(TempDir)) != NULL)
    {
      cupsdLogMessage(CUPSD_LOG_INFO,
                      "Cleaning out old temporary files in \"%s\"...", TempDir);

      while ((dent = cupsDirRead(dir)) != NULL)
      {
        snprintf(tempfile, sizeof(tempfile), "%s/%s", TempDir, dent->filename);
	printf("[main.c::main()] deleting temp file = %s\n", tempfile);

	if (cupsdRemoveFile(tempfile)) {
	  cupsdLogMessage(CUPSD_LOG_ERROR,
	                  "Unable to remove temporary file \"%s\" - %s",
	                  tempfile, strerror(errno));
	  printf("[main.c::main()] failed in deleting temp file = %s\n", tempfile);
	} 
	else {
	  cupsdLogMessage(CUPSD_LOG_DEBUG, "Removed temporary file \"%s\"...",
			              tempfile);
	  printf("[main.c::main()] deleted temp file = %s\n", tempfile);
	}
      }

      cupsDirClose(dir);
    }
    else {
      cupsdLogMessage(CUPSD_LOG_ERROR,
                      "Unable to open temporary directory \"%s\" - %s",
		                  TempDir, strerror(errno));
      printf("[main.c::main()] couldn't open temp dir = %s\n", TempDir);
    }

    printf("[main.c::main()] DONE cleaning temp dir = %s\n", TempDir);
  }

#if HAVE_LAUNCHD
  if (Launchd)
  {
   /*
    * If we were started by launchd get the listen sockets file descriptors...
    */
    printf("[main.c::main()] launchd check in \n");
    launchd_checkin();
  }
#endif /* HAVE_LAUNCHD */

#if defined(__APPLE__) && defined(HAVE_DLFCN_H)
 /*
  * Load Print Service quota enforcement library (X Server only)
  */

  PSQLibRef = dlopen(PSQLibPath, RTLD_LAZY);

  if (PSQLibRef)
    PSQUpdateQuotaProc = dlsym(PSQLibRef, PSQLibFuncName);
#endif /* __APPLE__ && HAVE_DLFCN_H */

#ifdef HAVE_GSSAPI
#  ifdef __APPLE__
 /*
  * If the weak-linked GSSAPI/Kerberos library is not present, don't try
  * to use it...
  */

  if (krb5_init_context != NULL)
#  endif /* __APPLE__ */

 /*
  * Setup a Kerberos context for the scheduler to use...
  */
  if (krb5_init_context(&KerberosContext))
  {
    KerberosContext = NULL;

    printf("[main.c::main()] unable to use krb5_init_context() \n");

    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize Kerberos context");
  }
  else
    {
      printf("[main.c::main()] used krb5_init_context() \n");
    }
#endif /* HAVE_GSSAPI */

 /*
  * Startup the server...
  */

  cupsdStartServer();

 /*
  * Catch hangup and child signals and ignore broken pipes...
  */

#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
  sigset(SIGCHLD, sigchld_handler);
  sigset(SIGHUP, sighup_handler);
  sigset(SIGPIPE, SIG_IGN);
  sigset(SIGTERM, sigterm_handler);
  printf("[main.c::main()] used system V signals over POSIX\n");
#elif defined(HAVE_SIGACTION)
  printf("[main.c::main()] used HAVE_SIGACTION\n");

  memset(&action, 0, sizeof(action));
  sigemptyset(&action.sa_mask);
  sigaddset(&action.sa_mask, SIGTERM);
  sigaddset(&action.sa_mask, SIGCHLD);
  action.sa_handler = sigchld_handler;
  sigaction(SIGCHLD, &action, NULL);

  sigemptyset(&action.sa_mask);
  sigaddset(&action.sa_mask, SIGHUP);
  action.sa_handler = sighup_handler;
  sigaction(SIGHUP, &action, NULL);

  sigemptyset(&action.sa_mask);
  action.sa_handler = SIG_IGN;
  sigaction(SIGPIPE, &action, NULL);

  sigemptyset(&action.sa_mask);
  sigaddset(&action.sa_mask, SIGTERM);
  sigaddset(&action.sa_mask, SIGCHLD);
  action.sa_handler = sigterm_handler;
  sigaction(SIGTERM, &action, NULL);
#else
  printf("[main.c::main()]last signal options\n");
  signal(SIGCLD, sigchld_handler);	/* No, SIGCLD isn't a typo... */
  signal(SIGHUP, sighup_handler);
  signal(SIGPIPE, SIG_IGN);
  signal(SIGTERM, sigterm_handler);
  
#endif /* HAVE_SIGSET */

#ifdef __sgi
 /*
  * Try to create a fake lpsched lock file if one is not already there.
  * Some Adobe applications need it under IRIX in order to enable
  * printing...
  */
  printf("[main.c::main()] creating fake lpsched lock file \n");
  if ((fp = cupsFileOpen("/var/spool/lp/SCHEDLOCK", "w")) == NULL)
  {
    syslog(LOG_LPR, "Unable to create fake lpsched lock file "
                    "\"/var/spool/lp/SCHEDLOCK\"\' - %s!",
           strerror(errno));
  }
  else
  {
    fchmod(cupsFileNumber(fp), 0644);
    fchown(cupsFileNumber(fp), User, Group);

    cupsFileClose(fp);
  }
#endif /* __sgi */

 /*
  * Initialize authentication certificates...
  */

  cupsdInitCerts();

 /*
  * If we are running in the background, signal the parent process that
  * we are up and running...
  */

#ifdef __APPLE__
  if (!fg || run_as_child)
#else
  if (!fg)
#endif /* __APPLE__ */
  {
   /*
    * Send a signal to the parent process, but only if the parent is
    * not PID 1 (init).  This avoids accidentally shutting down the
    * system on OpenBSD if you CTRL-C the server before it is up...
    */

    i = getppid();	/* Save parent PID to avoid race condition */

    if (i != 1)
      kill(i, SIGUSR1);
  }

#ifdef __APPLE__
 /*
  * Start power management framework...
  */
  printf("[main.c::main()] starting system monitor (power management) \n");
  cupsdStartSystemMonitor();
#endif /* __APPLE__ */

 /*
  * Start any pending print jobs...
  */

  printf("[main.c::main()] starting any pending print jobs \n");
  cupsdCheckJobs();

 /*
  * Loop forever...
  */

  current_time  = time(NULL);
  browse_time   = current_time;
  event_time    = current_time;
  expire_time   = current_time;
  fds           = 1;
  report_time   = 0;
  senddoc_time  = current_time;

  
  while (!stop_scheduler)
   {
    
    // XXX RAZA
    printf("[main.c::main()] scheduler loop # %d\n", count);
    if (count++ == loops_desired)
      {
	printf("[main.c::main()] stopping scheduler loop\n");
   	stop_scheduler = 1;
	continue;
      } 
    
    printf("[main.c::main()]  Top of loop, dead_children=%d, NeedReload=%d\n",
	   dead_children, NeedReload);    
    
#ifdef DEBUG
    cupsdLogMessage(CUPSD_LOG_DEBUG2,
                    "main: Top of loop, dead_children=%d, NeedReload=%d",
                    dead_children, NeedReload);
#endif /* DEBUG */

    

   /*
    * Check if there are dead children to handle...
    */

    if (dead_children)
      process_children();

   /*
    * Check if we need to load the server configuration file...
    */

    if (NeedReload)
    {
     /*
      * Close any idle clients...
      */

      if (cupsArrayCount(Clients) > 0)
      {
	for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
	     con;
	     con = (cupsd_client_t *)cupsArrayNext(Clients))
	  if (con->http.state == HTTP_WAITING)
	    cupsdCloseClient(con);
	  else
	    con->http.keep_alive = HTTP_KEEPALIVE_OFF;

        cupsdPauseListening();
      }

     /*
      * Check for any active jobs...
      */

      for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
	   job;
	   job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
        if (job->state_value == IPP_JOB_PROCESSING)
	  break;

     /*
      * Restart if all clients are closed and all jobs finished, or
      * if the reload timeout has elapsed...
      */

      if ((cupsArrayCount(Clients) == 0 &&
           (!job || NeedReload != RELOAD_ALL)) ||
          (time(NULL) - ReloadTime) >= ReloadTimeout)
      {
       /*
	* Shutdown the server...
	*/

	cupsdStopServer();

       /*
	* Read configuration...
	*/

        if (!cupsdReadConfiguration())
        {
          syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!",
		 ConfigurationFile);
          break;
	}

#if HAVE_LAUNCHD
	if (Launchd)
	{
	 /*
	  * If we were started by launchd get the listen sockets file descriptors...
	  */

	  launchd_checkin();
	}
#endif /* HAVE_LAUNCHD */

       /*
        * Startup the server...
        */

        cupsdStartServer();
      }
    }

   /*
    * Check for available input or ready output.  If cupsdDoSelect()
    * returns 0 or -1, something bad happened and we should exit
    * immediately.
    *
    * Note that we at least have one listening socket open at all
    * times.
    */

    if ((timeout = select_timeout(fds)) > 1 && LastEvent)
      timeout = 1;

#if HAVE_LAUNCHD
   /*
    * If no other work is scheduled and we're being controlled by
    * launchd then timeout after 'LaunchdTimeout' seconds of
    * inactivity...
    */

    if (timeout == 86400 && Launchd && LaunchdTimeout && !NumPolled &&
        !cupsArrayCount(ActiveJobs) &&
	(!Browsing || 
	 (!BrowseRemoteProtocols && 
	  (!NumBrowsers || !BrowseLocalProtocols ||
	   cupsArrayCount(Printers) == 0))))
    {
      timeout		= LaunchdTimeout;
      launchd_idle_exit = 1;
    }
    else
      launchd_idle_exit = 0;
#endif	/* HAVE_LAUNCHD */

    if ((fds = cupsdDoSelect(timeout)) < 0)
    {
     /*
      * Got an error from select!
      */

#ifdef HAVE_DNSSD
      cupsd_printer_t	*p;		/* Current printer */
#endif /* HAVE_DNSSD */


      if (errno == EINTR)		/* Just interrupted by a signal */
        continue;

     /*
      * Log all sorts of debug info to help track down the problem.
      */

      cupsdLogMessage(CUPSD_LOG_EMERG, "cupsdDoSelect() failed - %s!",
                      strerror(errno));

      for (i = 0, con = (cupsd_client_t *)cupsArrayFirst(Clients);
	   con;
	   i ++, con = (cupsd_client_t *)cupsArrayNext(Clients))
        cupsdLogMessage(CUPSD_LOG_EMERG,
	                "Clients[%d] = %d, file = %d, state = %d",
	                i, con->http.fd, con->file, con->http.state);

      for (i = 0, lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
           lis;
	   i ++, lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
        cupsdLogMessage(CUPSD_LOG_EMERG, "Listeners[%d] = %d", i, lis->fd);

      cupsdLogMessage(CUPSD_LOG_EMERG, "BrowseSocket = %d", BrowseSocket);

      cupsdLogMessage(CUPSD_LOG_EMERG, "CGIPipes[0] = %d", CGIPipes[0]);

#ifdef __APPLE__
      cupsdLogMessage(CUPSD_LOG_EMERG, "SysEventPipes[0] = %d",
                      SysEventPipes[0]);
#endif /* __APPLE__ */

      for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
	   job;
	   job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
        cupsdLogMessage(CUPSD_LOG_EMERG, "Jobs[%d] = %d < [%d %d] > [%d %d]",
	        	job->id,
			job->status_buffer ? job->status_buffer->fd : -1,
			job->print_pipes[0], job->print_pipes[1],
			job->back_pipes[0], job->back_pipes[1]);

#ifdef HAVE_DNSSD
      for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
	   p;
	   p = (cupsd_printer_t *)cupsArrayNext(Printers))
        cupsdLogMessage(CUPSD_LOG_EMERG, "printer[%s] %d", p->name,
	                p->dnssd_ipp_fd);
#endif /* HAVE_DNSSD */

      break;
    }

    current_time = time(NULL);

#ifndef __APPLE__
   /*
    * Update the network interfaces once a minute...
    */

    if ((current_time - netif_time) >= 60)
    {
      netif_time  = current_time;
      NetIFUpdate = 1;
    }
#endif /* !__APPLE__ */

#if HAVE_LAUNCHD
   /*
    * If no other work was scheduled and we're being controlled by launchd
    * then timeout after 'LaunchdTimeout' seconds of inactivity...
    */

    if (!fds && launchd_idle_exit)
    {
      cupsdLogMessage(CUPSD_LOG_INFO,
                      "Printer sharing is off and there are no jobs pending, "
		      "will restart on demand.");
      stop_scheduler = 1;
      break;
    }
#endif /* HAVE_LAUNCHD */

   /*
    * Resume listening for new connections as needed...
    */

    if (ListeningPaused && ListeningPaused <= current_time &&
        cupsArrayCount(Clients) < MaxClients)
      cupsdResumeListening();

   /*
    * Expire subscriptions and unload completed jobs as needed...
    */

    if (current_time > expire_time)
    {
      if (cupsArrayCount(Subscriptions) > 0)
        cupsdExpireSubscriptions(NULL, NULL);

      cupsdUnloadCompletedJobs();

      expire_time = current_time;
    }

   /*
    * Update the browse list as needed...
    */

    if (Browsing)
    {
#ifdef HAVE_LIBSLP
      if ((BrowseRemoteProtocols & BROWSE_SLP) &&
          BrowseSLPRefresh <= current_time)
        cupsdUpdateSLPBrowse();
#endif /* HAVE_LIBSLP */

#ifdef HAVE_LDAP
      if ((BrowseRemoteProtocols & BROWSE_LDAP) &&
          BrowseLDAPRefresh <= current_time)
        cupsdUpdateLDAPBrowse();
#endif /* HAVE_LDAP */
    }

    if (Browsing && current_time > browse_time)
    {
      cupsdSendBrowseList();
      browse_time = current_time;
    }

   /*
    * Update the root certificate once every 5 minutes if we have client
    * connections...
    */

    if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration &&
        !RunUser && cupsArrayCount(Clients))
    {
     /*
      * Update the root certificate...
      */

      cupsdDeleteCert(0);
      cupsdAddCert(0, "root", NULL);
    }

   /*
    * Check for new data on the client sockets...
    */

    for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
	 con;
	 con = (cupsd_client_t *)cupsArrayNext(Clients))
    {
     /*
      * Process pending data in the input buffer...
      */

      if (con->http.used)
      {
        cupsdReadClient(con);
	continue;
      }

     /*
      * Check the activity and close old clients...
      */

      activity = current_time - Timeout;
      if (con->http.activity < activity && !con->pipe_pid)
      {
        cupsdLogMessage(CUPSD_LOG_DEBUG,
	                "Closing client %d after %d seconds of inactivity...",
	                con->http.fd, Timeout);

        cupsdCloseClient(con);
        continue;
      }
    }

   /*
    * Update any pending multi-file documents...
    */

    if ((current_time - senddoc_time) >= 10)
    {
      cupsdCheckJobs();
      senddoc_time = current_time;
    }

   /*
    * Log statistics at most once a minute when in debug mode...
    */

    if ((current_time - report_time) >= 60 && LogLevel >= CUPSD_LOG_DEBUG)
    {
      size_t		string_count,	/* String count */
			alloc_bytes,	/* Allocated string bytes */
			total_bytes;	/* Total string bytes */
#ifdef HAVE_MALLINFO
      struct mallinfo	mem;		/* Malloc information */


      mem = mallinfo();
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-arena=%lu", mem.arena);
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-used=%lu",
                      mem.usmblks + mem.uordblks);
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: malloc-free=%lu",
		      mem.fsmblks + mem.fordblks);
#endif /* HAVE_MALLINFO */

      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: clients=%d",
                      cupsArrayCount(Clients));
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: jobs=%d",
                      cupsArrayCount(Jobs));
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: jobs-active=%d",
                      cupsArrayCount(ActiveJobs));
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: printers=%d",
                      cupsArrayCount(Printers));
      cupsdLogMessage(CUPSD_LOG_DEBUG, "Report: printers-implicit=%d",
                      cupsArrayCount(ImplicitPrinters));

      string_count = _cupsStrStatistics(&alloc_bytes, &total_bytes);
      cupsdLogMessage(CUPSD_LOG_DEBUG,
                      "Report: stringpool-string-count=" CUPS_LLFMT,
		      CUPS_LLCAST string_count);
      cupsdLogMessage(CUPSD_LOG_DEBUG,
                      "Report: stringpool-alloc-bytes=" CUPS_LLFMT,
		      CUPS_LLCAST alloc_bytes);
      cupsdLogMessage(CUPSD_LOG_DEBUG,
                      "Report: stringpool-total-bytes=" CUPS_LLFMT,
		      CUPS_LLCAST total_bytes);

      report_time = current_time;
    }

   /*
    * Handle OS-specific event notification for any events that have
    * accumulated.  Don't send these more than once a second...
    */

    if (LastEvent && (current_time - event_time) >= 1)
    {
#ifdef HAVE_NOTIFY_POST
      if (LastEvent & (CUPSD_EVENT_PRINTER_ADDED |
                       CUPSD_EVENT_PRINTER_DELETED |
                       CUPSD_EVENT_PRINTER_MODIFIED))
      {
        cupsdLogMessage(CUPSD_LOG_DEBUG2,
	                "notify_post(\"com.apple.printerListChange\")");
	notify_post("com.apple.printerListChange");
      }

      if (LastEvent & CUPSD_EVENT_PRINTER_STATE_CHANGED)
      {
        cupsdLogMessage(CUPSD_LOG_DEBUG2,
	                "notify_post(\"com.apple.printerHistoryChange\")");
	notify_post("com.apple.printerHistoryChange");
      }

      if (LastEvent & (CUPSD_EVENT_JOB_STATE_CHANGED |
                       CUPSD_EVENT_JOB_CONFIG_CHANGED |
                       CUPSD_EVENT_JOB_PROGRESS))
      {
        cupsdLogMessage(CUPSD_LOG_DEBUG2,
	                "notify_post(\"com.apple.jobChange\")");
	notify_post("com.apple.jobChange");
      }
#endif /* HAVE_NOTIFY_POST */

     /*
      * Reset the accumulated events...
      */

      LastEvent  = CUPSD_EVENT_NONE;
      event_time = current_time;
    }
   }

 /*
  * Log a message based on what happened...
  */

  if (stop_scheduler)
    cupsdLogMessage(CUPSD_LOG_INFO, "Scheduler shutting down normally.");
  else
    cupsdLogMessage(CUPSD_LOG_ERROR,
                    "Scheduler shutting down due to program error.");

 /*
  * Close all network clients...
  */

  cupsdStopServer();

#ifdef HAVE_LAUNCHD
 /*
  * Update the launchd KeepAlive file as needed...
  */

  if (Launchd)
    launchd_checkout();
#endif /* HAVE_LAUNCHD */

 /*
  * Stop all jobs...
  */

  cupsdFreeAllJobs();

#ifdef __APPLE__
 /*
  * Stop monitoring system event monitoring...
  */

  cupsdStopSystemMonitor();
#endif /* __APPLE__ */

#ifdef HAVE_GSSAPI
 /*
  * Free the scheduler's Kerberos context...
  */

#  ifdef __APPLE__
 /*
  * If the weak-linked GSSAPI/Kerberos library is not present, don't try
  * to use it...
  */

  if (krb5_init_context != NULL)
#  endif /* __APPLE__ */
  if (KerberosContext)
    krb5_free_context(KerberosContext);
#endif /* HAVE_GSSAPI */

#ifdef __APPLE__
#ifdef HAVE_DLFCN_H
 /* 
  * Unload Print Service quota enforcement library (X Server only) 
  */

  PSQUpdateQuotaProc = NULL;
  if (PSQLibRef)
  {
    dlclose(PSQLibRef);
    PSQLibRef = NULL;
  }
#endif /* HAVE_DLFCN_H */
#endif	/* __APPLE__ */

#ifdef __sgi
 /*
  * Remove the fake IRIX lpsched lock file, but only if the existing
  * file is not a FIFO which indicates that the real IRIX lpsched is
  * running...
  */

  if (!stat("/var/spool/lp/FIFO", &statbuf))
    if (!S_ISFIFO(statbuf.st_mode))
      unlink("/var/spool/lp/SCHEDLOCK");
#endif /* __sgi */

  cupsdStopSelect();

  return (!stop_scheduler);
}
void session_loop(void(*loophandler)()) {

	fd_set readfd, writefd;
	struct timeval timeout;
	int val;

	/* main loop, select()s for all sockets in use */
	for(;;) {

		timeout.tv_sec = select_timeout();
		timeout.tv_usec = 0;
		FD_ZERO(&writefd);
		FD_ZERO(&readfd);
		dropbear_assert(ses.payload == NULL);
		if (ses.sock_in != -1) {
			FD_SET(ses.sock_in, &readfd);
		}
		if (ses.sock_out != -1 && !isempty(&ses.writequeue)) {
			FD_SET(ses.sock_out, &writefd);
		}
		
		/* We get woken up when signal handlers write to this pipe.
		   SIGCHLD in svr-chansession is the only one currently. */
		FD_SET(ses.signal_pipe[0], &readfd);

		/* set up for channels which require reading/writing */
		if (ses.dataallowed) {
			setchannelfds(&readfd, &writefd);
		}
		val = select(ses.maxfd+1, &readfd, &writefd, NULL, &timeout);

		if (exitflag) {
			dropbear_exit("Terminated by signal");
		}
		
		if (val < 0 && errno != EINTR) {
			dropbear_exit("Error in select");
		}

		if (val <= 0) {
			/* If we were interrupted or the select timed out, we still
			 * want to iterate over channels etc for reading, to handle
			 * server processes exiting etc. 
			 * We don't want to read/write FDs. */
			FD_ZERO(&writefd);
			FD_ZERO(&readfd);
		}
		
		/* We'll just empty out the pipe if required. We don't do
		any thing with the data, since the pipe's purpose is purely to
		wake up the select() above. */
		if (FD_ISSET(ses.signal_pipe[0], &readfd)) {
			char x;
			while (read(ses.signal_pipe[0], &x, 1) > 0) {}
		}

		/* check for auth timeout, rekeying required etc */
		checktimeouts();

		/* process session socket's incoming/outgoing data */
		if (ses.sock_out != -1) {
			if (FD_ISSET(ses.sock_out, &writefd) && !isempty(&ses.writequeue)) {
				write_packet();
			}
		}

		if (ses.sock_in != -1) {
			if (FD_ISSET(ses.sock_in, &readfd)) {
				read_packet();
			}
			
			/* Process the decrypted packet. After this, the read buffer
			 * will be ready for a new packet */
			if (ses.payload != NULL) {
				process_packet();
			}
		}
		
		/* if required, flush out any queued reply packets that
		were being held up during a KEX */
		maybe_flush_reply_queue();

		/* process pipes etc for the channels, ses.dataallowed == 0
		 * during rekeying ) */
		if (ses.dataallowed) {
			channelio(&readfd, &writefd);
		}

		if (loophandler) {
			loophandler();
		}

	} /* for(;;) */
	
	/* Not reached */
}