2 * "$Id: util.c 9793 2011-05-20 03:49:49Z mike $"
4 * Mini-daemon utility functions for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2005 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * cupsdCompareNames() - Compare two names.
18 * cupsdCreateStringsArray() - Create a CUPS array of strings.
19 * cupsdExec() - Run a program with the correct environment.
20 * cupsdPipeCommand() - Read output from a command.
21 * cupsdSendIPPGroup() - Send a group tag.
22 * cupsdSendIPPHeader() - Send the IPP response header.
23 * cupsdSendIPPInteger() - Send an integer attribute.
24 * cupsdSendIPPString() - Send a string attribute.
25 * cupsdSendIPPTrailer() - Send the end-of-message tag.
29 * Include necessary headers...
38 extern char **environ;
39 #endif /* __APPLE__ */
43 * 'cupsdCompareNames()' - Compare two names.
45 * This function basically does a _cups_strcasecmp() of the two strings,
46 * but is also aware of numbers so that "a2" < "a100".
49 int /* O - Result of comparison */
50 cupsdCompareNames(const char *s, /* I - First string */
51 const char *t) /* I - Second string */
53 int diff, /* Difference between digits */
54 digits; /* Number of digits */
58 * Loop through both names, returning only when a difference is
59 * seen. Also, compare whole numbers rather than just characters, too!
64 if (isdigit(*s & 255) && isdigit(*t & 255))
67 * Got a number; start by skipping leading 0's...
76 * Skip equal digits...
79 while (isdigit(*s & 255) && *s == *t)
86 * Bounce out if *s and *t aren't both digits...
89 if (isdigit(*s & 255) && !isdigit(*t & 255))
91 else if (!isdigit(*s & 255) && isdigit(*t & 255))
93 else if (!isdigit(*s & 255) || !isdigit(*t & 255))
102 * Figure out how many more digits there are...
109 while (isdigit(*s & 255))
115 while (isdigit(*t & 255))
122 * Return if the number or value of the digits is different...
132 else if (tolower(*s) < tolower(*t))
134 else if (tolower(*s) > tolower(*t))
144 * Return the results of the final comparison...
157 * 'cupsdCreateStringsArray()' - Create a CUPS array of strings.
160 cups_array_t * /* O - CUPS array */
161 cupsdCreateStringsArray(const char *s) /* I - Comma-delimited strings */
166 return (_cupsArrayNewStrings(s));
171 * 'cupsdExec()' - Run a program with the correct environment.
173 * On Mac OS X, we need to update the CFProcessPath environment variable that
174 * is passed in the environment so the child can access its bundled resources.
177 int /* O - exec() status */
178 cupsdExec(const char *command, /* I - Full path to program */
179 char **argv) /* I - Command-line arguments */
182 int i, j; /* Looping vars */
183 char *envp[500], /* Array of environment variables */
184 cfprocesspath[1024], /* CFProcessPath environment variable */
185 linkpath[1024]; /* Link path for symlinks... */
186 int linkbytes; /* Bytes for link path */
190 * Some Mac OS X programs are bundled and need the CFProcessPath environment
191 * variable defined. If the command is a symlink, resolve the link and point
192 * to the resolved location, otherwise, use the command path itself.
195 if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0)
198 * Yes, this is a symlink to the actual program, nul-terminate and
202 linkpath[linkbytes] = '\0';
204 if (linkpath[0] == '/')
205 snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s",
208 snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s/%s",
209 dirname((char *)command), linkpath);
212 snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s", command);
214 envp[0] = cfprocesspath;
217 * Copy the rest of the environment except for any CFProcessPath that may
218 * already be there...
222 environ[j] && i < (int)(sizeof(envp) / sizeof(envp[0]) - 1);
224 if (strncmp(environ[j], "CFProcessPath=", 14))
225 envp[i ++] = environ[j];
230 * Use execve() to run the program...
233 return (execve(command, argv, envp));
237 * On other operating systems, just call execv() to use the same environment
238 * variables as the parent...
241 return (execv(command, argv));
242 #endif /* __APPLE__ */
247 * 'cupsdPipeCommand()' - Read output from a command.
250 cups_file_t * /* O - CUPS file or NULL on error */
251 cupsdPipeCommand(int *pid, /* O - Process ID or 0 on error */
252 const char *command, /* I - Command to run */
253 char **argv, /* I - Arguments to pass to command */
254 int user) /* I - User to run as or 0 for current */
256 int fd, /* Temporary file descriptor */
257 fds[2]; /* Pipe file descriptors */
261 * First create the pipe...
271 * Set the "close on exec" flag on each end of the pipe...
274 if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
284 if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
295 * Then run the command...
298 if ((*pid = fork()) < 0)
313 * Child comes here...
316 if (!getuid() && user)
317 setuid(user); /* Run as restricted user */
319 if ((fd = open("/dev/null", O_RDONLY)) > 0)
321 dup2(fd, 0); /* </dev/null */
325 dup2(fds[1], 1); /* >pipe */
328 cupsdExec(command, argv);
333 * Parent comes here, open the input side of the pipe...
338 return (cupsFileOpenFd(fds[0], "r"));
343 * 'cupsdSendIPPGroup()' - Send a group tag.
347 cupsdSendIPPGroup(ipp_tag_t group_tag) /* I - Group tag */
350 * Send IPP group tag (1 byte)...
358 * 'cupsdSendIPPHeader()' - Send the IPP response header.
363 ipp_status_t status_code, /* I - Status code */
364 int request_id) /* I - Request ID */
367 * Send IPP/1.1 response header: version number (2 bytes), status code
368 * (2 bytes), and request ID (4 bytes)...
370 * TODO: Add version number (IPP/2.x and IPP/1.0) support.
376 putchar(status_code >> 8);
377 putchar(status_code);
379 putchar(request_id >> 24);
380 putchar(request_id >> 16);
381 putchar(request_id >> 8);
387 * 'cupsdSendIPPInteger()' - Send an integer attribute.
392 ipp_tag_t value_tag, /* I - Value tag */
393 const char *name, /* I - Attribute name */
394 int value) /* I - Attribute value */
396 size_t len; /* Length of attribute name */
400 * Send IPP integer value: value tag (1 byte), name length (2 bytes),
401 * name string (without nul), value length (2 bytes), and value (4 bytes)...
415 putchar(value >> 24);
416 putchar(value >> 16);
423 * 'cupsdSendIPPString()' - Send a string attribute.
428 ipp_tag_t value_tag, /* I - Value tag */
429 const char *name, /* I - Attribute name */
430 const char *value) /* I - Attribute value */
432 size_t len; /* Length of attribute name */
436 * Send IPP string value: value tag (1 byte), name length (2 bytes),
437 * name string (without nul), value length (2 bytes), and value string
453 fputs(value, stdout);
458 * 'cupsdSendIPPTrailer()' - Send the end-of-message tag.
462 cupsdSendIPPTrailer(void)
464 putchar(IPP_TAG_END);
470 * End of "$Id: util.c 9793 2011-05-20 03:49:49Z mike $".