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