Revert manifest to default one
[external/cups.git] / scheduler / util.c
1 /*
2  * "$Id: util.c 9793 2011-05-20 03:49:49Z mike $"
3  *
4  *   Mini-daemon utility functions for CUPS.
5  *
6  *   Copyright 2007-2011 by Apple Inc.
7  *   Copyright 1997-2005 by Easy Software Products.
8  *
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/".
14  *
15  * Contents:
16  *
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.
26  */
27
28 /*
29  * Include necessary headers...
30  */
31
32 #include "util.h"
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #ifdef __APPLE__
37 #  include <libgen.h>
38 extern char **environ;
39 #endif /* __APPLE__ */
40
41
42 /*
43  * 'cupsdCompareNames()' - Compare two names.
44  *
45  * This function basically does a _cups_strcasecmp() of the two strings,
46  * but is also aware of numbers so that "a2" < "a100".
47  */
48
49 int                                     /* O - Result of comparison */
50 cupsdCompareNames(const char *s,        /* I - First string */
51                   const char *t)        /* I - Second string */
52 {
53   int           diff,                   /* Difference between digits */
54                 digits;                 /* Number of digits */
55
56
57  /*
58   * Loop through both names, returning only when a difference is
59   * seen.  Also, compare whole numbers rather than just characters, too!
60   */
61
62   while (*s && *t)
63   {
64     if (isdigit(*s & 255) && isdigit(*t & 255))
65     {
66      /*
67       * Got a number; start by skipping leading 0's...
68       */
69
70       while (*s == '0')
71         s ++;
72       while (*t == '0')
73         t ++;
74
75      /*
76       * Skip equal digits...
77       */
78
79       while (isdigit(*s & 255) && *s == *t)
80       {
81         s ++;
82         t ++;
83       }
84
85      /*
86       * Bounce out if *s and *t aren't both digits...
87       */
88
89       if (isdigit(*s & 255) && !isdigit(*t & 255))
90         return (1);
91       else if (!isdigit(*s & 255) && isdigit(*t & 255))
92         return (-1);
93       else if (!isdigit(*s & 255) || !isdigit(*t & 255))
94         continue;
95
96       if (*s < *t)
97         diff = -1;
98       else
99         diff = 1;
100
101      /*
102       * Figure out how many more digits there are...
103       */
104
105       digits = 0;
106       s ++;
107       t ++;
108
109       while (isdigit(*s & 255))
110       {
111         digits ++;
112         s ++;
113       }
114
115       while (isdigit(*t & 255))
116       {
117         digits --;
118         t ++;
119       }
120
121      /*
122       * Return if the number or value of the digits is different...
123       */
124
125       if (digits < 0)
126         return (-1);
127       else if (digits > 0)
128         return (1);
129       else if (diff)
130         return (diff);
131     }
132     else if (tolower(*s) < tolower(*t))
133       return (-1);
134     else if (tolower(*s) > tolower(*t))
135       return (1);
136     else
137     {
138       s ++;
139       t ++;
140     }
141   }
142
143  /*
144   * Return the results of the final comparison...
145   */
146
147   if (*s)
148     return (1);
149   else if (*t)
150     return (-1);
151   else
152     return (0);
153 }
154
155
156 /*
157  * 'cupsdCreateStringsArray()' - Create a CUPS array of strings.
158  */
159
160 cups_array_t *                          /* O - CUPS array */
161 cupsdCreateStringsArray(const char *s)  /* I - Comma-delimited strings */
162 {
163   if (!s || !*s)
164     return (NULL);
165   else
166     return (_cupsArrayNewStrings(s));
167 }
168
169
170 /*
171  * 'cupsdExec()' - Run a program with the correct environment.
172  *
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.
175  */
176
177 int                                     /* O - exec() status */
178 cupsdExec(const char *command,          /* I - Full path to program */
179           char       **argv)            /* I - Command-line arguments */
180 {
181 #ifdef __APPLE__
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 */
187
188
189  /*
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.
193   */
194
195   if ((linkbytes = readlink(command, linkpath, sizeof(linkpath) - 1)) > 0)
196   {
197    /*
198     * Yes, this is a symlink to the actual program, nul-terminate and
199     * use it...
200     */
201
202     linkpath[linkbytes] = '\0';
203
204     if (linkpath[0] == '/')
205       snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s",
206                linkpath);
207     else
208       snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s/%s",
209                dirname((char *)command), linkpath);
210   }
211   else
212     snprintf(cfprocesspath, sizeof(cfprocesspath), "CFProcessPath=%s", command);
213
214   envp[0] = cfprocesspath;
215
216  /*
217   * Copy the rest of the environment except for any CFProcessPath that may
218   * already be there...
219   */
220
221   for (i = 1, j = 0;
222        environ[j] && i < (int)(sizeof(envp) / sizeof(envp[0]) - 1);
223        j ++)
224     if (strncmp(environ[j], "CFProcessPath=", 14))
225       envp[i ++] = environ[j];
226
227   envp[i] = NULL;
228
229  /*
230   * Use execve() to run the program...
231   */
232
233   return (execve(command, argv, envp));
234
235 #else
236  /*
237   * On other operating systems, just call execv() to use the same environment
238   * variables as the parent...
239   */
240
241   return (execv(command, argv));
242 #endif /* __APPLE__ */
243 }
244
245
246 /*
247  * 'cupsdPipeCommand()' - Read output from a command.
248  */
249
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 */
255 {
256   int   fd,                             /* Temporary file descriptor */
257         fds[2];                         /* Pipe file descriptors */
258
259
260  /*
261   * First create the pipe...
262   */
263
264   if (pipe(fds))
265   {
266     *pid = 0;
267     return (NULL);
268   }
269
270  /*
271   * Set the "close on exec" flag on each end of the pipe...
272   */
273
274   if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
275   {
276     close(fds[0]);
277     close(fds[1]);
278
279     *pid = 0;
280
281     return (NULL);
282   }
283
284   if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
285   {
286     close(fds[0]);
287     close(fds[1]);
288
289     *pid = 0;
290
291     return (NULL);
292   }
293
294  /*
295   * Then run the command...
296   */
297
298   if ((*pid = fork()) < 0)
299   {
300    /*
301     * Unable to fork!
302     */
303
304     *pid = 0;
305     close(fds[0]);
306     close(fds[1]);
307
308     return (NULL);
309   }
310   else if (!*pid)
311   {
312    /*
313     * Child comes here...
314     */
315
316     if (!getuid() && user)
317       setuid(user);                     /* Run as restricted user */
318
319     if ((fd = open("/dev/null", O_RDONLY)) > 0)
320     {
321       dup2(fd, 0);                      /* </dev/null */
322       close(fd);
323     }
324
325     dup2(fds[1], 1);                    /* >pipe */
326     close(fds[1]);
327
328     cupsdExec(command, argv);
329     exit(errno);
330   }
331
332  /*
333   * Parent comes here, open the input side of the pipe...
334   */
335
336   close(fds[1]);
337
338   return (cupsFileOpenFd(fds[0], "r"));
339 }
340
341
342 /*
343  * 'cupsdSendIPPGroup()' - Send a group tag.
344  */
345
346 void
347 cupsdSendIPPGroup(ipp_tag_t group_tag)  /* I - Group tag */
348 {
349  /*
350   * Send IPP group tag (1 byte)...
351   */
352
353   putchar(group_tag);
354 }
355
356
357 /*
358  * 'cupsdSendIPPHeader()' - Send the IPP response header.
359  */
360
361 void
362 cupsdSendIPPHeader(
363     ipp_status_t status_code,           /* I - Status code */
364     int          request_id)            /* I - Request ID */
365 {
366  /*
367   * Send IPP/1.1 response header: version number (2 bytes), status code
368   * (2 bytes), and request ID (4 bytes)...
369   *
370   * TODO: Add version number (IPP/2.x and IPP/1.0) support.
371   */
372
373   putchar(1);
374   putchar(1);
375
376   putchar(status_code >> 8);
377   putchar(status_code);
378
379   putchar(request_id >> 24);
380   putchar(request_id >> 16);
381   putchar(request_id >> 8);
382   putchar(request_id);
383 }
384
385
386 /*
387  * 'cupsdSendIPPInteger()' - Send an integer attribute.
388  */
389
390 void
391 cupsdSendIPPInteger(
392     ipp_tag_t  value_tag,               /* I - Value tag */
393     const char *name,                   /* I - Attribute name */
394     int        value)                   /* I - Attribute value */
395 {
396   size_t        len;                    /* Length of attribute name */
397
398
399  /*
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)...
402   */
403
404   putchar(value_tag);
405
406   len = strlen(name);
407   putchar(len >> 8);
408   putchar(len);
409
410   fputs(name, stdout);
411
412   putchar(0);
413   putchar(4);
414
415   putchar(value >> 24);
416   putchar(value >> 16);
417   putchar(value >> 8);
418   putchar(value);
419 }
420
421
422 /*
423  * 'cupsdSendIPPString()' - Send a string attribute.
424  */
425
426 void
427 cupsdSendIPPString(
428     ipp_tag_t  value_tag,               /* I - Value tag */
429     const char *name,                   /* I - Attribute name */
430     const char *value)                  /* I - Attribute value */
431 {
432   size_t        len;                    /* Length of attribute name */
433
434
435  /*
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
438   * (without nul)...
439   */
440
441   putchar(value_tag);
442
443   len = strlen(name);
444   putchar(len >> 8);
445   putchar(len);
446
447   fputs(name, stdout);
448
449   len = strlen(value);
450   putchar(len >> 8);
451   putchar(len);
452
453   fputs(value, stdout);
454 }
455
456
457 /*
458  * 'cupsdSendIPPTrailer()' - Send the end-of-message tag.
459  */
460
461 void
462 cupsdSendIPPTrailer(void)
463 {
464   putchar(IPP_TAG_END);
465   fflush(stdout);
466 }
467
468
469 /*
470  * End of "$Id: util.c 9793 2011-05-20 03:49:49Z mike $".
471  */