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