]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/util.c
2 * "$Id: util.c 7621 2008-06-06 18:55:35Z mike $"
4 * Mini-daemon utility functions for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2009 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 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 */
163 cups_array_t
*a
; /* CUPS array */
164 const char *start
, /* Start of string */
165 *end
; /* End of string */
166 char *ptr
; /* New string */
172 if ((a
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
)) != NULL
)
174 for (start
= end
= s
; *end
; start
= end
+ 1)
177 * Find the end of the current delimited string...
180 if ((end
= strchr(start
, ',')) == NULL
)
181 end
= start
+ strlen(start
);
184 * Duplicate the string and add it to the array...
187 if ((ptr
= calloc(1, end
- start
+ 1)) == NULL
)
190 memcpy(ptr
, start
, end
- start
);
191 cupsArrayAdd(a
, ptr
);
200 * 'cupsdExec()' - Run a program with the correct environment.
202 * On Mac OS X, we need to update the CFProcessPath environment variable that
203 * is passed in the environment so the child can access its bundled resources.
206 int /* O - exec() status */
207 cupsdExec(const char *command
, /* I - Full path to program */
208 char **argv
) /* I - Command-line arguments */
211 int i
, j
; /* Looping vars */
212 char *envp
[500], /* Array of environment variables */
213 cfprocesspath
[1024], /* CFProcessPath environment variable */
214 linkpath
[1024]; /* Link path for symlinks... */
215 int linkbytes
; /* Bytes for link path */
219 * Some Mac OS X programs are bundled and need the CFProcessPath environment
220 * variable defined. If the command is a symlink, resolve the link and point
221 * to the resolved location, otherwise, use the command path itself.
224 if ((linkbytes
= readlink(command
, linkpath
, sizeof(linkpath
) - 1)) > 0)
227 * Yes, this is a symlink to the actual program, nul-terminate and
231 linkpath
[linkbytes
] = '\0';
233 if (linkpath
[0] == '/')
234 snprintf(cfprocesspath
, sizeof(cfprocesspath
), "CFProcessPath=%s",
237 snprintf(cfprocesspath
, sizeof(cfprocesspath
), "CFProcessPath=%s/%s",
238 dirname((char *)command
), linkpath
);
241 snprintf(cfprocesspath
, sizeof(cfprocesspath
), "CFProcessPath=%s", command
);
243 envp
[0] = cfprocesspath
;
246 * Copy the rest of the environment except for any CFProcessPath that may
247 * already be there...
251 environ
[j
] && i
< (int)(sizeof(envp
) / sizeof(envp
[0]) - 1);
253 if (strncmp(environ
[j
], "CFProcessPath=", 14))
254 envp
[i
++] = environ
[j
];
259 * Use execve() to run the program...
262 return (execve(command
, argv
, envp
));
266 * On other operating systems, just call execv() to use the same environment
267 * variables as the parent...
270 return (execv(command
, argv
));
271 #endif /* __APPLE__ */
276 * 'cupsdPipeCommand()' - Read output from a command.
279 cups_file_t
* /* O - CUPS file or NULL on error */
280 cupsdPipeCommand(int *pid
, /* O - Process ID or 0 on error */
281 const char *command
, /* I - Command to run */
282 char **argv
, /* I - Arguments to pass to command */
283 int user
) /* I - User to run as or 0 for current */
285 int fd
, /* Temporary file descriptor */
286 fds
[2]; /* Pipe file descriptors */
290 * First create the pipe...
300 * Set the "close on exec" flag on each end of the pipe...
303 if (fcntl(fds
[0], F_SETFD
, fcntl(fds
[0], F_GETFD
) | FD_CLOEXEC
))
313 if (fcntl(fds
[1], F_SETFD
, fcntl(fds
[1], F_GETFD
) | FD_CLOEXEC
))
324 * Then run the command...
327 if ((*pid
= fork()) < 0)
342 * Child comes here...
345 if (!getuid() && user
)
346 setuid(user
); /* Run as restricted user */
348 if ((fd
= open("/dev/null", O_RDONLY
)) > 0)
350 dup2(fd
, 0); /* </dev/null */
354 dup2(fds
[1], 1); /* >pipe */
357 cupsdExec(command
, argv
);
362 * Parent comes here, open the input side of the pipe...
367 return (cupsFileOpenFd(fds
[0], "r"));
372 * 'cupsdSendIPPGroup()' - Send a group tag.
376 cupsdSendIPPGroup(ipp_tag_t group_tag
) /* I - Group tag */
379 * Send IPP group tag (1 byte)...
387 * 'cupsdSendIPPHeader()' - Send the IPP response header.
392 ipp_status_t status_code
, /* I - Status code */
393 int request_id
) /* I - Request ID */
396 * Send IPP/1.1 response header: version number (2 bytes), status code
397 * (2 bytes), and request ID (4 bytes)...
399 * TODO: Add version number (IPP/2.x and IPP/1.0) support.
405 putchar(status_code
>> 8);
406 putchar(status_code
);
408 putchar(request_id
>> 24);
409 putchar(request_id
>> 16);
410 putchar(request_id
>> 8);
416 * 'cupsdSendIPPInteger()' - Send an integer attribute.
421 ipp_tag_t value_tag
, /* I - Value tag */
422 const char *name
, /* I - Attribute name */
423 int value
) /* I - Attribute value */
425 size_t len
; /* Length of attribute name */
429 * Send IPP integer value: value tag (1 byte), name length (2 bytes),
430 * name string (without nul), value length (2 bytes), and value (4 bytes)...
444 putchar(value
>> 24);
445 putchar(value
>> 16);
452 * 'cupsdSendIPPString()' - Send a string attribute.
457 ipp_tag_t value_tag
, /* I - Value tag */
458 const char *name
, /* I - Attribute name */
459 const char *value
) /* I - Attribute value */
461 size_t len
; /* Length of attribute name */
465 * Send IPP string value: value tag (1 byte), name length (2 bytes),
466 * name string (without nul), value length (2 bytes), and value string
482 fputs(value
, stdout
);
487 * 'cupsdSendIPPTrailer()' - Send the end-of-message tag.
491 cupsdSendIPPTrailer(void)
493 putchar(IPP_TAG_END
);
499 * End of "$Id: util.c 7621 2008-06-06 18:55:35Z mike $".