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