]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/util.c
2 * Mini-daemon utility functions for CUPS.
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2005 by Easy Software Products.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
11 * Include necessary headers...
20 extern char **environ
;
21 #endif /* __APPLE__ */
25 * 'cupsdCompareNames()' - Compare two names.
27 * This function basically does a _cups_strcasecmp() of the two strings,
28 * but is also aware of numbers so that "a2" < "a100".
31 int /* O - Result of comparison */
32 cupsdCompareNames(const char *s
, /* I - First string */
33 const char *t
) /* I - Second string */
35 int diff
, /* Difference between digits */
36 digits
; /* Number of digits */
40 * Loop through both names, returning only when a difference is
41 * seen. Also, compare whole numbers rather than just characters, too!
46 if (isdigit(*s
& 255) && isdigit(*t
& 255))
49 * Got a number; start by skipping leading 0's...
58 * Skip equal digits...
61 while (isdigit(*s
& 255) && *s
== *t
)
68 * Bounce out if *s and *t aren't both digits...
71 if (isdigit(*s
& 255) && !isdigit(*t
& 255))
73 else if (!isdigit(*s
& 255) && isdigit(*t
& 255))
75 else if (!isdigit(*s
& 255) || !isdigit(*t
& 255))
84 * Figure out how many more digits there are...
91 while (isdigit(*s
& 255))
97 while (isdigit(*t
& 255))
104 * Return if the number or value of the digits is different...
114 else if (tolower(*s
) < tolower(*t
))
116 else if (tolower(*s
) > tolower(*t
))
126 * Return the results of the final comparison...
139 * 'cupsdCreateStringsArray()' - Create a CUPS array of strings.
142 cups_array_t
* /* O - CUPS array */
143 cupsdCreateStringsArray(const char *s
) /* I - Comma-delimited strings */
148 return (_cupsArrayNewStrings(s
, ','));
153 * 'cupsdExec()' - Run a program with the correct environment.
155 * On macOS, we need to update the CFProcessPath environment variable that
156 * is passed in the environment so the child can access its bundled resources.
159 int /* O - exec() status */
160 cupsdExec(const char *command
, /* I - Full path to program */
161 char **argv
) /* I - Command-line arguments */
164 int i
, j
; /* Looping vars */
165 char *envp
[500], /* Array of environment variables */
166 cfprocesspath
[1024], /* CFProcessPath environment variable */
167 linkpath
[1024]; /* Link path for symlinks... */
168 int linkbytes
; /* Bytes for link path */
172 * Some macOS programs are bundled and need the CFProcessPath environment
173 * variable defined. If the command is a symlink, resolve the link and point
174 * to the resolved location, otherwise, use the command path itself.
177 if ((linkbytes
= readlink(command
, linkpath
, sizeof(linkpath
) - 1)) > 0)
180 * Yes, this is a symlink to the actual program, nul-terminate and
184 linkpath
[linkbytes
] = '\0';
186 if (linkpath
[0] == '/')
187 snprintf(cfprocesspath
, sizeof(cfprocesspath
), "CFProcessPath=%s",
190 snprintf(cfprocesspath
, sizeof(cfprocesspath
), "CFProcessPath=%s/%s",
191 dirname((char *)command
), linkpath
);
194 snprintf(cfprocesspath
, sizeof(cfprocesspath
), "CFProcessPath=%s", command
);
196 envp
[0] = cfprocesspath
;
199 * Copy the rest of the environment except for any CFProcessPath that may
200 * already be there...
204 environ
[j
] && i
< (int)(sizeof(envp
) / sizeof(envp
[0]) - 1);
206 if (strncmp(environ
[j
], "CFProcessPath=", 14))
207 envp
[i
++] = environ
[j
];
212 * Use execve() to run the program...
215 return (execve(command
, argv
, envp
));
219 * On other operating systems, just call execv() to use the same environment
220 * variables as the parent...
223 return (execv(command
, argv
));
224 #endif /* __APPLE__ */
229 * 'cupsdPipeCommand()' - Read output from a command.
232 cups_file_t
* /* O - CUPS file or NULL on error */
233 cupsdPipeCommand(int *pid
, /* O - Process ID or 0 on error */
234 const char *command
, /* I - Command to run */
235 char **argv
, /* I - Arguments to pass to command */
236 uid_t user
) /* I - User to run as or 0 for current */
238 int fd
, /* Temporary file descriptor */
239 fds
[2]; /* Pipe file descriptors */
243 * First create the pipe...
253 * Set the "close on exec" flag on each end of the pipe...
256 if (fcntl(fds
[0], F_SETFD
, fcntl(fds
[0], F_GETFD
) | FD_CLOEXEC
))
266 if (fcntl(fds
[1], F_SETFD
, fcntl(fds
[1], F_GETFD
) | FD_CLOEXEC
))
277 * Then run the command...
280 if ((*pid
= fork()) < 0)
295 * Child comes here...
298 if (!getuid() && user
)
299 setuid(user
); /* Run as restricted user */
301 if ((fd
= open("/dev/null", O_RDONLY
)) > 0)
303 dup2(fd
, 0); /* </dev/null */
307 dup2(fds
[1], 1); /* >pipe */
310 cupsdExec(command
, argv
);
315 * Parent comes here, open the input side of the pipe...
320 return (cupsFileOpenFd(fds
[0], "r"));
325 * 'cupsdSendIPPGroup()' - Send a group tag.
329 cupsdSendIPPGroup(ipp_tag_t group_tag
) /* I - Group tag */
332 * Send IPP group tag (1 byte)...
340 * 'cupsdSendIPPHeader()' - Send the IPP response header.
345 ipp_status_t status_code
, /* I - Status code */
346 int request_id
) /* I - Request ID */
349 * Send IPP/1.1 response header: version number (2 bytes), status code
350 * (2 bytes), and request ID (4 bytes)...
352 * TODO: Add version number (IPP/2.x and IPP/1.0) support.
358 putchar(status_code
>> 8);
359 putchar(status_code
);
361 putchar(request_id
>> 24);
362 putchar(request_id
>> 16);
363 putchar(request_id
>> 8);
369 * 'cupsdSendIPPInteger()' - Send an integer attribute.
374 ipp_tag_t value_tag
, /* I - Value tag */
375 const char *name
, /* I - Attribute name */
376 int value
) /* I - Attribute value */
378 size_t len
; /* Length of attribute name */
382 * Send IPP integer value: value tag (1 byte), name length (2 bytes),
383 * name string (without nul), value length (2 bytes), and value (4 bytes)...
389 putchar((int)(len
>> 8));
397 putchar(value
>> 24);
398 putchar(value
>> 16);
405 * 'cupsdSendIPPString()' - Send a string attribute.
410 ipp_tag_t value_tag
, /* I - Value tag */
411 const char *name
, /* I - Attribute name */
412 const char *value
) /* I - Attribute value */
414 size_t len
; /* Length of attribute name */
418 * Send IPP string value: value tag (1 byte), name length (2 bytes),
419 * name string (without nul), value length (2 bytes), and value string
426 putchar((int)(len
>> 8));
432 putchar((int)(len
>> 8));
435 fputs(value
, stdout
);
440 * 'cupsdSendIPPTrailer()' - Send the end-of-message tag.
444 cupsdSendIPPTrailer(void)
446 putchar(IPP_TAG_END
);