Blame scheduler/util.c

Packit 2fc92b
/*
Packit 2fc92b
 * Mini-daemon utility functions for CUPS.
Packit 2fc92b
 *
Packit 2fc92b
 * Copyright 2007-2014 by Apple Inc.
Packit 2fc92b
 * Copyright 1997-2005 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
 * Include necessary headers...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
#include "util.h"
Packit 2fc92b
#include <unistd.h>
Packit 2fc92b
#include <sys/stat.h>
Packit 2fc92b
#include <fcntl.h>
Packit 2fc92b
#ifdef __APPLE__
Packit 2fc92b
#  include <libgen.h>
Packit 2fc92b
extern char **environ;
Packit 2fc92b
#endif /* __APPLE__ */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdCompareNames()' - Compare two names.
Packit 2fc92b
 *
Packit 2fc92b
 * This function basically does a _cups_strcasecmp() of the two strings,
Packit 2fc92b
 * but is also aware of numbers so that "a2" < "a100".
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
int					/* O - Result of comparison */
Packit 2fc92b
cupsdCompareNames(const char *s,	/* I - First string */
Packit 2fc92b
                  const char *t)	/* I - Second string */
Packit 2fc92b
{
Packit 2fc92b
  int		diff,			/* Difference between digits */
Packit 2fc92b
		digits;			/* Number of digits */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Loop through both names, returning only when a difference is
Packit 2fc92b
  * seen.  Also, compare whole numbers rather than just characters, too!
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  while (*s && *t)
Packit 2fc92b
  {
Packit 2fc92b
    if (isdigit(*s & 255) && isdigit(*t & 255))
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * Got a number; start by skipping leading 0's...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      while (*s == '0')
Packit 2fc92b
        s ++;
Packit 2fc92b
      while (*t == '0')
Packit 2fc92b
        t ++;
Packit 2fc92b
Packit 2fc92b
     /*
Packit 2fc92b
      * Skip equal digits...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      while (isdigit(*s & 255) && *s == *t)
Packit 2fc92b
      {
Packit 2fc92b
        s ++;
Packit 2fc92b
	t ++;
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
     /*
Packit 2fc92b
      * Bounce out if *s and *t aren't both digits...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      if (isdigit(*s & 255) && !isdigit(*t & 255))
Packit 2fc92b
        return (1);
Packit 2fc92b
      else if (!isdigit(*s & 255) && isdigit(*t & 255))
Packit 2fc92b
        return (-1);
Packit 2fc92b
      else if (!isdigit(*s & 255) || !isdigit(*t & 255))
Packit 2fc92b
        continue;
Packit 2fc92b
Packit 2fc92b
      if (*s < *t)
Packit 2fc92b
        diff = -1;
Packit 2fc92b
      else
Packit 2fc92b
        diff = 1;
Packit 2fc92b
Packit 2fc92b
     /*
Packit 2fc92b
      * Figure out how many more digits there are...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      digits = 0;
Packit 2fc92b
      s ++;
Packit 2fc92b
      t ++;
Packit 2fc92b
Packit 2fc92b
      while (isdigit(*s & 255))
Packit 2fc92b
      {
Packit 2fc92b
        digits ++;
Packit 2fc92b
	s ++;
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
      while (isdigit(*t & 255))
Packit 2fc92b
      {
Packit 2fc92b
        digits --;
Packit 2fc92b
	t ++;
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
     /*
Packit 2fc92b
      * Return if the number or value of the digits is different...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      if (digits < 0)
Packit 2fc92b
        return (-1);
Packit 2fc92b
      else if (digits > 0)
Packit 2fc92b
        return (1);
Packit 2fc92b
      else if (diff)
Packit 2fc92b
        return (diff);
Packit 2fc92b
    }
Packit 2fc92b
    else if (tolower(*s) < tolower(*t))
Packit 2fc92b
      return (-1);
Packit 2fc92b
    else if (tolower(*s) > tolower(*t))
Packit 2fc92b
      return (1);
Packit 2fc92b
    else
Packit 2fc92b
    {
Packit 2fc92b
      s ++;
Packit 2fc92b
      t ++;
Packit 2fc92b
    }
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Return the results of the final comparison...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if (*s)
Packit 2fc92b
    return (1);
Packit 2fc92b
  else if (*t)
Packit 2fc92b
    return (-1);
Packit 2fc92b
  else
Packit 2fc92b
    return (0);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdCreateStringsArray()' - Create a CUPS array of strings.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
cups_array_t *				/* O - CUPS array */
Packit 2fc92b
cupsdCreateStringsArray(const char *s)	/* I - Comma-delimited strings */
Packit 2fc92b
{
Packit 2fc92b
  if (!s || !*s)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
  else
Packit 2fc92b
    return (_cupsArrayNewStrings(s, ','));
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdExec()' - Run a program with the correct environment.
Packit 2fc92b
 *
Packit 2fc92b
 * On macOS, we need to update the CFProcessPath environment variable that
Packit 2fc92b
 * is passed in the environment so the child can access its bundled resources.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
int					/* O - exec() status */
Packit 2fc92b
cupsdExec(const char *command,		/* I - Full path to program */
Packit 2fc92b
          char       **argv)		/* I - Command-line arguments */
Packit 2fc92b
{
Packit 2fc92b
#ifdef __APPLE__
Packit 2fc92b
  int	i, j;				/* Looping vars */
Packit 2fc92b
  char	*envp[500],			/* Array of environment variables */
Packit 2fc92b
	cfprocesspath[1024],		/* CFProcessPath environment variable */
Packit 2fc92b
	linkpath[1024];			/* Link path for symlinks... */
Packit 2fc92b
  int	linkbytes;			/* Bytes for link path */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Some macOS programs are bundled and need the CFProcessPath environment
Packit 2fc92b
  * variable defined.  If the command is a symlink, resolve the link and point
Packit 2fc92b
  * to the resolved location, otherwise, use the command path itself.
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0)
Packit 2fc92b
  {
Packit 2fc92b
   /*
Packit 2fc92b
    * Yes, this is a symlink to the actual program, nul-terminate and
Packit 2fc92b
    * use it...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    linkpath[linkbytes] = '\0';
Packit 2fc92b
Packit 2fc92b
    if (linkpath[0] == '/')
Packit 2fc92b
      snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s",
Packit 2fc92b
	       linkpath);
Packit 2fc92b
    else
Packit 2fc92b
      snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s/%s",
Packit 2fc92b
	       dirname((char *)command), linkpath);
Packit 2fc92b
  }
Packit 2fc92b
  else
Packit 2fc92b
    snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s", command);
Packit 2fc92b
Packit 2fc92b
  envp[0] = cfprocesspath;
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Copy the rest of the environment except for any CFProcessPath that may
Packit 2fc92b
  * already be there...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  for (i = 1, j = 0;
Packit 2fc92b
       environ[j] && i < (int)(sizeof(envp) / sizeof(envp[0]) - 1);
Packit 2fc92b
       j ++)
Packit 2fc92b
    if (strncmp(environ[j], "CFProcessPath=", 14))
Packit 2fc92b
      envp[i ++] = environ[j];
Packit 2fc92b
Packit 2fc92b
  envp[i] = NULL;
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Use execve() to run the program...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  return (execve(command, argv, envp));
Packit 2fc92b
Packit 2fc92b
#else
Packit 2fc92b
 /*
Packit 2fc92b
  * On other operating systems, just call execv() to use the same environment
Packit 2fc92b
  * variables as the parent...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  return (execv(command, argv));
Packit 2fc92b
#endif /* __APPLE__ */
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdPipeCommand()' - Read output from a command.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
cups_file_t *				/* O - CUPS file or NULL on error */
Packit 2fc92b
cupsdPipeCommand(int        *pid,	/* O - Process ID or 0 on error */
Packit 2fc92b
                 const char *command,	/* I - Command to run */
Packit 2fc92b
                 char       **argv,	/* I - Arguments to pass to command */
Packit 2fc92b
		 uid_t      user)	/* I - User to run as or 0 for current */
Packit 2fc92b
{
Packit 2fc92b
  int	fd,				/* Temporary file descriptor */
Packit 2fc92b
	fds[2];				/* Pipe file descriptors */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * First create the pipe...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if (pipe(fds))
Packit 2fc92b
  {
Packit 2fc92b
    *pid = 0;
Packit 2fc92b
    return (NULL);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Set the "close on exec" flag on each end of the pipe...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
Packit 2fc92b
  {
Packit 2fc92b
    close(fds[0]);
Packit 2fc92b
    close(fds[1]);
Packit 2fc92b
Packit 2fc92b
    *pid = 0;
Packit 2fc92b
Packit 2fc92b
    return (NULL);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
Packit 2fc92b
  {
Packit 2fc92b
    close(fds[0]);
Packit 2fc92b
    close(fds[1]);
Packit 2fc92b
Packit 2fc92b
    *pid = 0;
Packit 2fc92b
Packit 2fc92b
    return (NULL);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Then run the command...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if ((*pid = fork()) < 0)
Packit 2fc92b
  {
Packit 2fc92b
   /*
Packit 2fc92b
    * Unable to fork!
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    *pid = 0;
Packit 2fc92b
    close(fds[0]);
Packit 2fc92b
    close(fds[1]);
Packit 2fc92b
Packit 2fc92b
    return (NULL);
Packit 2fc92b
  }
Packit 2fc92b
  else if (!*pid)
Packit 2fc92b
  {
Packit 2fc92b
   /*
Packit 2fc92b
    * Child comes here...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    if (!getuid() && user)
Packit 2fc92b
      setuid(user);			/* Run as restricted user */
Packit 2fc92b
Packit 2fc92b
    if ((fd = open("/dev/null", O_RDONLY)) > 0)
Packit 2fc92b
    {
Packit 2fc92b
      dup2(fd, 0);			/* 
Packit 2fc92b
      close(fd);
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    dup2(fds[1], 1);			/* >pipe */
Packit 2fc92b
    close(fds[1]);
Packit 2fc92b
Packit 2fc92b
    cupsdExec(command, argv);
Packit 2fc92b
    exit(errno);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Parent comes here, open the input side of the pipe...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  close(fds[1]);
Packit 2fc92b
Packit 2fc92b
  return (cupsFileOpenFd(fds[0], "r"));
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdSendIPPGroup()' - Send a group tag.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
cupsdSendIPPGroup(ipp_tag_t group_tag)	/* I - Group tag */
Packit 2fc92b
{
Packit 2fc92b
 /*
Packit 2fc92b
  * Send IPP group tag (1 byte)...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  putchar(group_tag);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdSendIPPHeader()' - Send the IPP response header.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
cupsdSendIPPHeader(
Packit 2fc92b
    ipp_status_t status_code,		/* I - Status code */
Packit 2fc92b
    int          request_id)		/* I - Request ID */
Packit 2fc92b
{
Packit 2fc92b
 /*
Packit 2fc92b
  * Send IPP/1.1 response header: version number (2 bytes), status code
Packit 2fc92b
  * (2 bytes), and request ID (4 bytes)...
Packit 2fc92b
  *
Packit 2fc92b
  * TODO: Add version number (IPP/2.x and IPP/1.0) support.
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  putchar(1);
Packit 2fc92b
  putchar(1);
Packit 2fc92b
Packit 2fc92b
  putchar(status_code >> 8);
Packit 2fc92b
  putchar(status_code);
Packit 2fc92b
Packit 2fc92b
  putchar(request_id >> 24);
Packit 2fc92b
  putchar(request_id >> 16);
Packit 2fc92b
  putchar(request_id >> 8);
Packit 2fc92b
  putchar(request_id);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdSendIPPInteger()' - Send an integer attribute.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
cupsdSendIPPInteger(
Packit 2fc92b
    ipp_tag_t  value_tag,		/* I - Value tag */
Packit 2fc92b
    const char *name,			/* I - Attribute name */
Packit 2fc92b
    int        value)			/* I - Attribute value */
Packit 2fc92b
{
Packit 2fc92b
  size_t	len;			/* Length of attribute name */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Send IPP integer value: value tag (1 byte), name length (2 bytes),
Packit 2fc92b
  * name string (without nul), value length (2 bytes), and value (4 bytes)...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  putchar(value_tag);
Packit 2fc92b
Packit 2fc92b
  len = strlen(name);
Packit 2fc92b
  putchar((int)(len >> 8));
Packit 2fc92b
  putchar((int)len);
Packit 2fc92b
Packit 2fc92b
  fputs(name, stdout);
Packit 2fc92b
Packit 2fc92b
  putchar(0);
Packit 2fc92b
  putchar(4);
Packit 2fc92b
Packit 2fc92b
  putchar(value >> 24);
Packit 2fc92b
  putchar(value >> 16);
Packit 2fc92b
  putchar(value >> 8);
Packit 2fc92b
  putchar(value);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdSendIPPString()' - Send a string attribute.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
cupsdSendIPPString(
Packit 2fc92b
    ipp_tag_t  value_tag,		/* I - Value tag */
Packit 2fc92b
    const char *name,			/* I - Attribute name */
Packit 2fc92b
    const char *value)			/* I - Attribute value */
Packit 2fc92b
{
Packit 2fc92b
  size_t	len;			/* Length of attribute name */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Send IPP string value: value tag (1 byte), name length (2 bytes),
Packit 2fc92b
  * name string (without nul), value length (2 bytes), and value string
Packit 2fc92b
  * (without nul)...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  putchar(value_tag);
Packit 2fc92b
Packit 2fc92b
  len = strlen(name);
Packit 2fc92b
  putchar((int)(len >> 8));
Packit 2fc92b
  putchar((int)len);
Packit 2fc92b
Packit 2fc92b
  fputs(name, stdout);
Packit 2fc92b
Packit 2fc92b
  len = strlen(value);
Packit 2fc92b
  putchar((int)(len >> 8));
Packit 2fc92b
  putchar((int)len);
Packit 2fc92b
Packit 2fc92b
  fputs(value, stdout);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'cupsdSendIPPTrailer()' - Send the end-of-message tag.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
cupsdSendIPPTrailer(void)
Packit 2fc92b
{
Packit 2fc92b
  putchar(IPP_TAG_END);
Packit 2fc92b
  fflush(stdout);
Packit 2fc92b
}