]>
Commit | Line | Data |
---|---|---|
2d7cba2b | 1 | /* |
34089ee8 | 2 | * "$Id: job.c,v 1.124.2.99 2004/12/16 20:03:22 mike Exp $" |
2d7cba2b | 3 | * |
93894a43 | 4 | * Job management routines for the Common UNIX Printing System (CUPS). |
2d7cba2b | 5 | * |
9639c4de | 6 | * Copyright 1997-2004 by Easy Software Products, all rights reserved. |
2d7cba2b | 7 | * |
8 | * These coded instructions, statements, and computer programs are the | |
9 | * property of Easy Software Products and are protected by Federal | |
10 | * copyright law. Distribution and use rights are outlined in the file | |
11 | * "LICENSE.txt" which should have been included with this file. If this | |
12 | * file is missing or damaged please contact Easy Software Products | |
13 | * at: | |
14 | * | |
15 | * Attn: CUPS Licensing Information | |
16 | * Easy Software Products | |
8784b6a6 | 17 | * 44141 Airport View Drive, Suite 204 |
8650fcf2 | 18 | * Hollywood, Maryland 20636 USA |
2d7cba2b | 19 | * |
edfd3c3d | 20 | * Voice: (301) 373-9600 |
2d7cba2b | 21 | * EMail: cups-info@cups.org |
22 | * WWW: http://www.cups.org | |
23 | * | |
24 | * Contents: | |
25 | * | |
7b1b1c6e | 26 | * AddJob() - Add a new job to the job queue... |
27 | * CancelJob() - Cancel the specified print job. | |
dd9e85de | 28 | * CancelJobs() - Cancel all jobs for the given destination/user... |
7b1b1c6e | 29 | * CheckJobs() - Check the pending jobs and start any if the |
30 | * destination is available. | |
31 | * CleanJobs() - Clean out old jobs. | |
5fe35f41 | 32 | * FreeAllJobs() - Free all jobs from memory. |
7b1b1c6e | 33 | * FindJob() - Find the specified job. |
34 | * GetPrinterJobCount() - Get the number of pending, processing, | |
35 | * or held jobs in a printer or class. | |
36 | * GetUserJobCount() - Get the number of pending, processing, | |
37 | * or held jobs for a user. | |
38 | * HoldJob() - Hold the specified job. | |
39 | * LoadAllJobs() - Load all jobs from disk. | |
7b1b1c6e | 40 | * MoveJob() - Move the specified job to a different |
41 | * destination. | |
42 | * ReleaseJob() - Release the specified job. | |
43 | * RestartJob() - Restart the specified job. | |
44 | * SaveJob() - Save a job to disk. | |
45 | * SetJobHoldUntil() - Set the hold time for a job... | |
46 | * SetJobPriority() - Set the priority of a job, moving it up/down | |
47 | * in the list as needed. | |
48 | * StartJob() - Start a print job. | |
49 | * StopAllJobs() - Stop all print jobs. | |
50 | * StopJob() - Stop a print job. | |
51 | * UpdateJob() - Read a status update from a job's filters. | |
ad717326 | 52 | * ipp_length() - Compute the size of the buffer needed to hold |
53 | * the textual IPP attributes. | |
7b1b1c6e | 54 | * start_process() - Start a background process. |
225b3683 | 55 | * set_hold_until() - Set the hold time and update job-hold-until attribute. |
2d7cba2b | 56 | */ |
57 | ||
58 | /* | |
59 | * Include necessary headers... | |
60 | */ | |
61 | ||
a9de544f | 62 | #include "cupsd.h" |
9d13ae31 | 63 | #include <grp.h> |
a9de544f | 64 | |
65 | ||
d59a189c | 66 | /* |
67 | * Local globals... | |
68 | */ | |
69 | ||
70 | static mime_filter_t gziptoany_filter = | |
71 | { | |
72 | NULL, /* Source type */ | |
73 | NULL, /* Destination type */ | |
74 | 0, /* Cost */ | |
75 | "gziptoany" /* Filter program to run */ | |
76 | }; | |
77 | ||
78 | ||
bfa1abf0 | 79 | /* |
80 | * Local functions... | |
81 | */ | |
82 | ||
ad717326 | 83 | static int ipp_length(ipp_t *ipp); |
7ebf3a09 | 84 | static void set_time(job_t *job, const char *name); |
e09246c8 | 85 | static int start_process(const char *command, char *argv[], |
a2fc3d31 | 86 | char *envp[], int infd, int outfd, |
5c8eff27 | 87 | int errfd, int backfd, int root, |
88 | int *pid); | |
225b3683 | 89 | static void set_hold_until(job_t *job, time_t holdtime); |
bfa1abf0 | 90 | |
91 | ||
93894a43 | 92 | /* |
93 | * 'AddJob()' - Add a new job to the job queue... | |
94 | */ | |
95 | ||
017c50f3 | 96 | job_t * /* O - New job record */ |
97 | AddJob(int priority, /* I - Job priority */ | |
98 | const char *dest) /* I - Job destination */ | |
a9de544f | 99 | { |
017c50f3 | 100 | job_t *job, /* New job record */ |
101 | *current, /* Current job in queue */ | |
102 | *prev; /* Previous job in queue */ | |
a9de544f | 103 | |
104 | ||
105 | job = calloc(sizeof(job_t), 1); | |
106 | ||
18fe941f | 107 | job->id = NextJobId ++; |
108 | job->priority = priority; | |
109 | job->back_pipes[0] = -1; | |
110 | job->back_pipes[1] = -1; | |
111 | job->print_pipes[0] = -1; | |
112 | job->print_pipes[1] = -1; | |
18fe941f | 113 | |
36992080 | 114 | SetString(&job->dest, dest); |
a9de544f | 115 | |
116 | NumJobs ++; | |
117 | ||
9cbd98eb | 118 | for (current = Jobs, prev = NULL; |
119 | current != NULL; | |
120 | prev = current, current = current->next) | |
a9de544f | 121 | if (job->priority > current->priority) |
122 | break; | |
123 | ||
124 | job->next = current; | |
125 | if (prev != NULL) | |
126 | prev->next = job; | |
127 | else | |
128 | Jobs = job; | |
129 | ||
130 | return (job); | |
131 | } | |
132 | ||
133 | ||
93894a43 | 134 | /* |
135 | * 'CancelJob()' - Cancel the specified print job. | |
136 | */ | |
137 | ||
a9de544f | 138 | void |
017c50f3 | 139 | CancelJob(int id, /* I - Job to cancel */ |
140 | int purge) /* I - Purge jobs? */ | |
a9de544f | 141 | { |
017c50f3 | 142 | int i; /* Looping var */ |
143 | job_t *current, /* Current job */ | |
144 | *prev; /* Previous job in list */ | |
145 | char filename[1024]; /* Job filename */ | |
a9de544f | 146 | |
147 | ||
d87b2fe0 | 148 | LogMessage(L_DEBUG, "CancelJob: id = %d", id); |
6abc7437 | 149 | |
a9de544f | 150 | for (current = Jobs, prev = NULL; current != NULL; prev = current, current = current->next) |
151 | if (current->id == id) | |
152 | { | |
6abc7437 | 153 | /* |
154 | * Stop any processes that are working on the current... | |
155 | */ | |
156 | ||
157 | DEBUG_puts("CancelJob: found job in list."); | |
158 | ||
1049abbe | 159 | if (current->state->values[0].integer == IPP_JOB_PROCESSING) |
db911fcb | 160 | StopJob(current->id, 0); |
4979ce3d | 161 | |
162 | current->state->values[0].integer = IPP_JOB_CANCELLED; | |
6abc7437 | 163 | |
a5a07150 | 164 | set_time(current, "time-at-completed"); |
7ebf3a09 | 165 | |
a9de544f | 166 | /* |
bd84e0d1 | 167 | * Remove the print file for good if we aren't preserving jobs or |
168 | * files... | |
a9de544f | 169 | */ |
170 | ||
e09246c8 | 171 | current->current_file = 0; |
172 | ||
f4647930 | 173 | if (!JobHistory || !JobFiles || purge || |
174 | (current->dtype & CUPS_PRINTER_REMOTE)) | |
bd84e0d1 | 175 | for (i = 1; i <= current->num_files; i ++) |
176 | { | |
04de52f8 | 177 | snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, |
bd84e0d1 | 178 | current->id, i); |
179 | unlink(filename); | |
180 | } | |
181 | ||
f4647930 | 182 | if (JobHistory && !purge && !(current->dtype & CUPS_PRINTER_REMOTE)) |
bd84e0d1 | 183 | { |
184 | /* | |
185 | * Save job state info... | |
186 | */ | |
187 | ||
188 | SaveJob(current->id); | |
189 | } | |
a9de544f | 190 | else |
bd84e0d1 | 191 | { |
1049abbe | 192 | /* |
193 | * Remove the job info file... | |
194 | */ | |
195 | ||
04de52f8 | 196 | snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, |
1049abbe | 197 | current->id); |
198 | unlink(filename); | |
199 | ||
bd84e0d1 | 200 | /* |
201 | * Update pointers if we aren't preserving jobs... | |
202 | */ | |
a9de544f | 203 | |
bd84e0d1 | 204 | if (prev == NULL) |
205 | Jobs = current->next; | |
206 | else | |
207 | prev->next = current->next; | |
a9de544f | 208 | |
bd84e0d1 | 209 | /* |
210 | * Free all memory used... | |
211 | */ | |
a9de544f | 212 | |
bd84e0d1 | 213 | if (current->attrs != NULL) |
214 | ippDelete(current->attrs); | |
215 | ||
d59a189c | 216 | if (current->num_files > 0) |
217 | { | |
218 | free(current->compressions); | |
219 | free(current->filetypes); | |
220 | } | |
7ebf3a09 | 221 | |
4efad428 | 222 | ClearString(¤t->username); |
223 | ClearString(¤t->dest); | |
4efad428 | 224 | |
bd84e0d1 | 225 | free(current); |
43fe1146 | 226 | |
227 | NumJobs --; | |
bd84e0d1 | 228 | } |
a9de544f | 229 | |
a9de544f | 230 | return; |
231 | } | |
232 | } | |
233 | ||
234 | ||
93894a43 | 235 | /* |
dd9e85de | 236 | * 'CancelJobs()' - Cancel all jobs for the given destination/user... |
93894a43 | 237 | */ |
238 | ||
a9de544f | 239 | void |
b07e0cc2 | 240 | CancelJobs(const char *dest, /* I - Destination to cancel */ |
241 | const char *username, /* I - Username or NULL */ | |
242 | int purge) /* I - Purge jobs? */ | |
a9de544f | 243 | { |
b07e0cc2 | 244 | job_t *current, /* Current job */ |
245 | *next; /* Next job */ | |
a9de544f | 246 | |
247 | ||
bd972dd1 | 248 | for (current = Jobs; current != NULL;) |
dd9e85de | 249 | if ((dest == NULL || !strcmp(current->dest, dest)) && |
250 | (username == NULL || !strcmp(current->username, username))) | |
a9de544f | 251 | { |
252 | /* | |
dd9e85de | 253 | * Cancel all jobs matching this destination/user... |
a9de544f | 254 | */ |
255 | ||
b07e0cc2 | 256 | next = current->next; |
257 | ||
dd9e85de | 258 | CancelJob(current->id, purge); |
a9de544f | 259 | |
b07e0cc2 | 260 | current = next; |
a9de544f | 261 | } |
262 | else | |
263 | current = current->next; | |
96df88bb | 264 | |
265 | CheckJobs(); | |
93894a43 | 266 | } |
a9de544f | 267 | |
268 | ||
93894a43 | 269 | /* |
270 | * 'CheckJobs()' - Check the pending jobs and start any if the destination | |
271 | * is available. | |
272 | */ | |
273 | ||
274 | void | |
275 | CheckJobs(void) | |
a9de544f | 276 | { |
017c50f3 | 277 | job_t *current, /* Current job in queue */ |
278 | *next; /* Next job in queue */ | |
279 | printer_t *printer, /* Printer destination */ | |
280 | *pclass; /* Printer class destination */ | |
a9de544f | 281 | |
282 | ||
db911fcb | 283 | DEBUG_puts("CheckJobs()"); |
6abc7437 | 284 | |
df7507f5 | 285 | for (current = Jobs; current != NULL; current = next) |
6abc7437 | 286 | { |
35a2ba9d | 287 | /* |
288 | * Save next pointer in case the job is cancelled en-route. | |
289 | */ | |
290 | ||
291 | next = current->next; | |
292 | ||
05ca02bc | 293 | /* |
294 | * Start held jobs if they are ready... | |
295 | */ | |
296 | ||
297 | if (current->state->values[0].integer == IPP_JOB_HELD && | |
298 | current->hold_until && | |
299 | current->hold_until < time(NULL)) | |
300 | current->state->values[0].integer = IPP_JOB_PENDING; | |
301 | ||
bd84e0d1 | 302 | /* |
303 | * Start pending jobs if the destination is available... | |
304 | */ | |
305 | ||
a782f61f | 306 | if (current->state->values[0].integer == IPP_JOB_PENDING && !NeedReload) |
93894a43 | 307 | { |
a2c6b8b1 | 308 | if ((pclass = FindClass(current->dest)) != NULL) |
b5cb0608 | 309 | { |
310 | /* | |
311 | * If the class is remote, just pass it to the remote server... | |
312 | */ | |
313 | ||
314 | if (pclass->type & CUPS_PRINTER_REMOTE) | |
315 | printer = pclass; | |
753453e4 | 316 | else if (pclass->state != IPP_PRINTER_STOPPED) |
b5cb0608 | 317 | printer = FindAvailablePrinter(current->dest); |
753453e4 | 318 | else |
319 | printer = NULL; | |
b5cb0608 | 320 | } |
8b43895a | 321 | else |
322 | printer = FindPrinter(current->dest); | |
a9de544f | 323 | |
a2c6b8b1 | 324 | if (printer != NULL && (printer->type & CUPS_PRINTER_IMPLICIT)) |
325 | { | |
326 | /* | |
327 | * Handle implicit classes... | |
328 | */ | |
329 | ||
753453e4 | 330 | pclass = printer; |
331 | ||
332 | if (pclass->state != IPP_PRINTER_STOPPED) | |
333 | printer = FindAvailablePrinter(current->dest); | |
334 | else | |
335 | printer = NULL; | |
a2c6b8b1 | 336 | } |
337 | ||
338 | if (printer == NULL && pclass == NULL) | |
93894a43 | 339 | { |
340 | /* | |
341 | * Whoa, the printer and/or class for this destination went away; | |
342 | * cancel the job... | |
343 | */ | |
a9de544f | 344 | |
5ea8888e | 345 | LogMessage(L_WARN, "Printer/class %s has gone away; cancelling job %d!", |
d57f94b6 | 346 | current->dest, current->id); |
723c82e1 | 347 | CancelJob(current->id, 1); |
93894a43 | 348 | } |
d57f94b6 | 349 | else if (printer != NULL) |
93894a43 | 350 | { |
351 | /* | |
29a78848 | 352 | * See if the printer is available or remote and not printing a job; |
353 | * if so, start the job... | |
93894a43 | 354 | */ |
355 | ||
29a78848 | 356 | if (printer->state == IPP_PRINTER_IDLE || /* Printer is idle */ |
357 | ((printer->type & CUPS_PRINTER_REMOTE) && /* Printer is remote */ | |
358 | !printer->job)) /* and not printing a job */ | |
93894a43 | 359 | StartJob(current->id, printer); |
93894a43 | 360 | } |
361 | } | |
6abc7437 | 362 | } |
a9de544f | 363 | } |
364 | ||
365 | ||
d7845573 | 366 | /* |
367 | * 'CleanJobs()' - Clean out old jobs. | |
368 | */ | |
369 | ||
370 | void | |
371 | CleanJobs(void) | |
372 | { | |
017c50f3 | 373 | job_t *job, /* Current job */ |
374 | *next; /* Next job */ | |
d7845573 | 375 | |
376 | ||
377 | if (MaxJobs == 0) | |
378 | return; | |
379 | ||
380 | for (job = Jobs; job && NumJobs >= MaxJobs; job = next) | |
381 | { | |
382 | next = job->next; | |
383 | ||
384 | if (job->state->values[0].integer >= IPP_JOB_CANCELLED) | |
385 | CancelJob(job->id, 1); | |
386 | } | |
387 | } | |
388 | ||
389 | ||
017c50f3 | 390 | /* |
391 | * 'FinishJob()' - Finish a job. | |
392 | */ | |
393 | ||
394 | void | |
395 | FinishJob(job_t *job) /* I - Job */ | |
396 | { | |
397 | int job_history; /* Did CancelJob() keep the job? */ | |
398 | cups_ptype_t ptype; /* Printer type (color, small, etc.) */ | |
399 | ||
400 | ||
401 | LogMessage(L_DEBUG, "FinishJob: job %d, file %d is complete.", | |
402 | job->id, job->current_file - 1); | |
403 | ||
294f4cee | 404 | if (job->status_buffer && job->current_file >= job->num_files) |
017c50f3 | 405 | { |
406 | /* | |
407 | * Close the pipe and clear the input bit. | |
408 | */ | |
409 | ||
294f4cee | 410 | LogMessage(L_DEBUG2, "FinishJob: Removing fd %d from InputSet...", |
411 | job->status_buffer->fd); | |
017c50f3 | 412 | |
294f4cee | 413 | FD_CLR(job->status_buffer->fd, InputSet); |
017c50f3 | 414 | |
294f4cee | 415 | LogMessage(L_DEBUG2, "FinishJob: Closing status input pipe %d...", |
416 | job->status_buffer->fd); | |
417 | ||
418 | cupsdStatBufDelete(job->status_buffer); | |
017c50f3 | 419 | |
294f4cee | 420 | job->status_buffer = NULL; |
017c50f3 | 421 | } |
422 | ||
423 | if (job->status < 0) | |
424 | { | |
425 | /* | |
426 | * Backend had errors; stop it... | |
427 | */ | |
428 | ||
429 | ptype = job->printer->type; | |
430 | ||
431 | StopJob(job->id, 0); | |
432 | job->state->values[0].integer = IPP_JOB_PENDING; | |
433 | SaveJob(job->id); | |
434 | ||
435 | /* | |
436 | * If the job was queued to a class, try requeuing it... For | |
437 | * faxes, hold the current job for 5 minutes. | |
438 | */ | |
439 | ||
440 | if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) | |
441 | CheckJobs(); | |
442 | else if (ptype & CUPS_PRINTER_FAX) | |
443 | { | |
444 | /* | |
445 | * See how many times we've tried to send the job; if more than | |
446 | * the limit, cancel the job. | |
447 | */ | |
448 | ||
449 | job->tries ++; | |
450 | ||
451 | if (job->tries >= FaxRetryLimit) | |
452 | { | |
453 | /* | |
454 | * Too many tries... | |
455 | */ | |
456 | ||
457 | LogMessage(L_ERROR, "Canceling fax job %d since it could not be sent after %d tries.", | |
458 | job->id, FaxRetryLimit); | |
459 | CancelJob(job->id, 0); | |
460 | } | |
461 | else | |
462 | { | |
463 | /* | |
464 | * Try again in N seconds... | |
465 | */ | |
466 | ||
467 | set_hold_until(job, time(NULL) + FaxRetryInterval); | |
468 | } | |
469 | ||
470 | CheckJobs(); | |
471 | } | |
472 | } | |
473 | else if (job->status > 0) | |
474 | { | |
475 | /* | |
476 | * Filter had errors; cancel it... | |
477 | */ | |
478 | ||
479 | if (job->current_file < job->num_files) | |
480 | StartJob(job->id, job->printer); | |
481 | else | |
482 | { | |
483 | job_history = JobHistory && !(job->dtype & CUPS_PRINTER_REMOTE); | |
484 | ||
485 | CancelJob(job->id, 0); | |
486 | ||
487 | if (job_history) | |
488 | { | |
489 | job->state->values[0].integer = IPP_JOB_ABORTED; | |
490 | SaveJob(job->id); | |
491 | } | |
492 | ||
493 | CheckJobs(); | |
494 | } | |
495 | } | |
496 | else | |
497 | { | |
498 | /* | |
499 | * Job printed successfully; cancel it... | |
500 | */ | |
501 | ||
502 | if (job->current_file < job->num_files) | |
503 | { | |
504 | FilterLevel -= job->cost; | |
505 | StartJob(job->id, job->printer); | |
506 | } | |
507 | else | |
508 | { | |
509 | job_history = JobHistory && !(job->dtype & CUPS_PRINTER_REMOTE); | |
510 | ||
511 | CancelJob(job->id, 0); | |
512 | ||
513 | if (job_history) | |
514 | { | |
515 | job->state->values[0].integer = IPP_JOB_COMPLETED; | |
516 | SaveJob(job->id); | |
517 | } | |
518 | ||
519 | CheckJobs(); | |
520 | } | |
521 | } | |
522 | } | |
523 | ||
524 | ||
5fe35f41 | 525 | /* |
526 | * 'FreeAllJobs()' - Free all jobs from memory. | |
527 | */ | |
528 | ||
529 | void | |
530 | FreeAllJobs(void) | |
531 | { | |
017c50f3 | 532 | job_t *job, /* Current job */ |
533 | *next; /* Next job */ | |
5fe35f41 | 534 | |
535 | ||
5f46b949 | 536 | HoldSignals(); |
537 | ||
5fe35f41 | 538 | StopAllJobs(); |
539 | ||
540 | for (job = Jobs; job; job = next) | |
541 | { | |
542 | next = job->next; | |
543 | ||
544 | ippDelete(job->attrs); | |
d59a189c | 545 | |
546 | if (job->num_files > 0) | |
547 | { | |
548 | free(job->compressions); | |
549 | free(job->filetypes); | |
550 | } | |
551 | ||
5fe35f41 | 552 | free(job); |
553 | } | |
f219b8a8 | 554 | |
555 | Jobs = NULL; | |
5f46b949 | 556 | |
557 | ReleaseSignals(); | |
5fe35f41 | 558 | } |
559 | ||
560 | ||
93894a43 | 561 | /* |
562 | * 'FindJob()' - Find the specified job. | |
563 | */ | |
564 | ||
017c50f3 | 565 | job_t * /* O - Job data */ |
566 | FindJob(int id) /* I - Job ID */ | |
a9de544f | 567 | { |
017c50f3 | 568 | job_t *current; /* Current job */ |
a9de544f | 569 | |
570 | ||
93894a43 | 571 | for (current = Jobs; current != NULL; current = current->next) |
a9de544f | 572 | if (current->id == id) |
93894a43 | 573 | break; |
a9de544f | 574 | |
93894a43 | 575 | return (current); |
a9de544f | 576 | } |
577 | ||
578 | ||
7b1b1c6e | 579 | /* |
580 | * 'GetPrinterJobCount()' - Get the number of pending, processing, | |
581 | * or held jobs in a printer or class. | |
582 | */ | |
583 | ||
584 | int /* O - Job count */ | |
585 | GetPrinterJobCount(const char *dest) /* I - Printer or class name */ | |
586 | { | |
587 | int count; /* Job count */ | |
588 | job_t *job; /* Current job */ | |
589 | ||
590 | ||
8bc932be | 591 | for (job = Jobs, count = 0; job != NULL; job = job->next) |
7b1b1c6e | 592 | if (job->state->values[0].integer <= IPP_JOB_PROCESSING && |
593 | strcasecmp(job->dest, dest) == 0) | |
594 | count ++; | |
595 | ||
596 | return (count); | |
597 | } | |
598 | ||
599 | ||
600 | /* | |
601 | * 'GetUserJobCount()' - Get the number of pending, processing, | |
602 | * or held jobs for a user. | |
603 | */ | |
604 | ||
605 | int /* O - Job count */ | |
606 | GetUserJobCount(const char *username) /* I - Username */ | |
607 | { | |
608 | int count; /* Job count */ | |
609 | job_t *job; /* Current job */ | |
610 | ||
611 | ||
8bc932be | 612 | for (job = Jobs, count = 0; job != NULL; job = job->next) |
7b1b1c6e | 613 | if (job->state->values[0].integer <= IPP_JOB_PROCESSING && |
614 | strcmp(job->username, username) == 0) | |
615 | count ++; | |
616 | ||
617 | return (count); | |
618 | } | |
619 | ||
620 | ||
bd84e0d1 | 621 | /* |
622 | * 'HoldJob()' - Hold the specified job. | |
623 | */ | |
624 | ||
625 | void | |
017c50f3 | 626 | HoldJob(int id) /* I - Job ID */ |
bd84e0d1 | 627 | { |
017c50f3 | 628 | job_t *job; /* Job data */ |
bd84e0d1 | 629 | |
630 | ||
d87b2fe0 | 631 | LogMessage(L_DEBUG, "HoldJob: id = %d", id); |
962e5a9f | 632 | |
bd84e0d1 | 633 | if ((job = FindJob(id)) == NULL) |
634 | return; | |
635 | ||
1049abbe | 636 | if (job->state->values[0].integer == IPP_JOB_PROCESSING) |
db911fcb | 637 | StopJob(id, 0); |
bd84e0d1 | 638 | |
962e5a9f | 639 | DEBUG_puts("HoldJob: setting state to held..."); |
640 | ||
1049abbe | 641 | job->state->values[0].integer = IPP_JOB_HELD; |
bd84e0d1 | 642 | |
f63a2256 | 643 | SaveJob(id); |
644 | ||
bd84e0d1 | 645 | CheckJobs(); |
646 | } | |
647 | ||
648 | ||
649 | /* | |
650 | * 'LoadAllJobs()' - Load all jobs from disk. | |
651 | */ | |
652 | ||
653 | void | |
654 | LoadAllJobs(void) | |
655 | { | |
017c50f3 | 656 | DIR *dir; /* Directory */ |
657 | DIRENT *dent; /* Directory entry */ | |
658 | char filename[1024]; /* Full filename of job file */ | |
659 | int fd; /* File descriptor */ | |
660 | job_t *job, /* New job */ | |
661 | *current, /* Current job */ | |
662 | *prev; /* Previous job */ | |
663 | int jobid, /* Current job ID */ | |
664 | fileid; /* Current file ID */ | |
665 | ipp_attribute_t *attr; /* Job attribute */ | |
666 | char method[HTTP_MAX_URI], /* Method portion of URI */ | |
667 | username[HTTP_MAX_URI], /* Username portion of URI */ | |
668 | host[HTTP_MAX_URI], /* Host portion of URI */ | |
669 | resource[HTTP_MAX_URI]; /* Resource portion of URI */ | |
670 | int port; /* Port portion of URI */ | |
671 | printer_t *p; /* Printer or class */ | |
672 | const char *dest; /* Destination */ | |
673 | mime_type_t **filetypes; /* New filetypes array */ | |
674 | int *compressions; /* New compressions array */ | |
bd84e0d1 | 675 | |
676 | ||
1049abbe | 677 | /* |
678 | * First open the requests directory... | |
679 | */ | |
bd84e0d1 | 680 | |
56f7cb11 | 681 | LogMessage(L_DEBUG, "LoadAllJobs: Scanning %s...", RequestRoot); |
682 | ||
bf9e2a45 | 683 | NumJobs = 0; |
684 | ||
1049abbe | 685 | if ((dir = opendir(RequestRoot)) == NULL) |
56f7cb11 | 686 | { |
687 | LogMessage(L_ERROR, "LoadAllJobs: Unable to open spool directory %s: %s", | |
688 | RequestRoot, strerror(errno)); | |
1049abbe | 689 | return; |
56f7cb11 | 690 | } |
1049abbe | 691 | |
692 | /* | |
693 | * Read all the c##### files... | |
694 | */ | |
695 | ||
696 | while ((dent = readdir(dir)) != NULL) | |
88f105c5 | 697 | if (NAMLEN(dent) >= 6 && dent->d_name[0] == 'c') |
1049abbe | 698 | { |
699 | /* | |
700 | * Allocate memory for the job... | |
701 | */ | |
702 | ||
703 | if ((job = calloc(sizeof(job_t), 1)) == NULL) | |
704 | { | |
93336dbc | 705 | LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for jobs!"); |
1049abbe | 706 | closedir(dir); |
707 | return; | |
708 | } | |
709 | ||
710 | if ((job->attrs = ippNew()) == NULL) | |
711 | { | |
712 | free(job); | |
93336dbc | 713 | LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for job attributes!"); |
1049abbe | 714 | closedir(dir); |
715 | return; | |
716 | } | |
717 | ||
718 | /* | |
719 | * Assign the job ID... | |
720 | */ | |
721 | ||
017c50f3 | 722 | job->id = atoi(dent->d_name + 1); |
723 | job->back_pipes[0] = -1; | |
724 | job->back_pipes[1] = -1; | |
725 | job->print_pipes[0] = -1; | |
726 | job->print_pipes[1] = -1; | |
1049abbe | 727 | |
56f7cb11 | 728 | LogMessage(L_DEBUG, "LoadAllJobs: Loading attributes for job %d...\n", |
729 | job->id); | |
730 | ||
1049abbe | 731 | if (job->id >= NextJobId) |
732 | NextJobId = job->id + 1; | |
733 | ||
734 | /* | |
735 | * Load the job control file... | |
736 | */ | |
737 | ||
04de52f8 | 738 | snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->d_name); |
99de6da0 | 739 | if ((fd = open(filename, O_RDONLY)) < 0) |
740 | { | |
db911fcb | 741 | LogMessage(L_ERROR, "LoadAllJobs: Unable to open job control file \"%s\" - %s!", |
99de6da0 | 742 | filename, strerror(errno)); |
743 | ippDelete(job->attrs); | |
744 | free(job); | |
db911fcb | 745 | unlink(filename); |
99de6da0 | 746 | continue; |
747 | } | |
db911fcb | 748 | else |
1049abbe | 749 | { |
db911fcb | 750 | if (ippReadFile(fd, job->attrs) != IPP_DATA) |
751 | { | |
752 | LogMessage(L_ERROR, "LoadAllJobs: Unable to read job control file \"%s\"!", | |
753 | filename); | |
754 | close(fd); | |
755 | ippDelete(job->attrs); | |
756 | free(job); | |
757 | unlink(filename); | |
758 | continue; | |
759 | } | |
760 | ||
99de6da0 | 761 | close(fd); |
1049abbe | 762 | } |
763 | ||
8fc34542 | 764 | if ((job->state = ippFindAttribute(job->attrs, "job-state", IPP_TAG_ENUM)) == NULL) |
765 | { | |
766 | LogMessage(L_ERROR, "LoadAllJobs: Missing or bad job-state attribute in control file \"%s\"!", | |
767 | filename); | |
768 | ippDelete(job->attrs); | |
769 | free(job); | |
770 | unlink(filename); | |
771 | continue; | |
772 | } | |
415199da | 773 | |
8be52672 | 774 | if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", IPP_TAG_URI)) == NULL) |
775 | { | |
776 | LogMessage(L_ERROR, "LoadAllJobs: No job-printer-uri attribute in control file \"%s\"!", | |
777 | filename); | |
778 | ippDelete(job->attrs); | |
779 | free(job); | |
723c82e1 | 780 | unlink(filename); |
8be52672 | 781 | continue; |
782 | } | |
783 | ||
1049abbe | 784 | httpSeparate(attr->values[0].string.text, method, username, host, |
785 | &port, resource); | |
786 | ||
bd5510a5 | 787 | if ((dest = ValidateDest(host, resource, &(job->dtype), NULL)) == NULL && |
415199da | 788 | job->state != NULL && |
789 | job->state->values[0].integer <= IPP_JOB_PROCESSING) | |
93d2f0c0 | 790 | { |
791 | /* | |
792 | * Job queued on remote printer or class, so add it... | |
793 | */ | |
723c82e1 | 794 | |
93d2f0c0 | 795 | if (strncmp(resource, "/classes/", 9) == 0) |
796 | { | |
797 | p = AddClass(resource + 9); | |
36992080 | 798 | SetString(&p->make_model, "Remote Class on unknown"); |
93d2f0c0 | 799 | } |
800 | else | |
801 | { | |
802 | p = AddPrinter(resource + 10); | |
36992080 | 803 | SetString(&p->make_model, "Remote Printer on unknown"); |
93d2f0c0 | 804 | } |
723c82e1 | 805 | |
93d2f0c0 | 806 | p->state = IPP_PRINTER_STOPPED; |
807 | p->type |= CUPS_PRINTER_REMOTE; | |
808 | p->browse_time = 2147483647; | |
723c82e1 | 809 | |
36992080 | 810 | SetString(&p->location, "Location Unknown"); |
811 | SetString(&p->info, "No Information Available"); | |
05156f4e | 812 | p->hostname[0] = '\0'; |
723c82e1 | 813 | |
93d2f0c0 | 814 | SetPrinterAttrs(p); |
815 | dest = p->name; | |
816 | } | |
723c82e1 | 817 | |
818 | if (dest == NULL) | |
1049abbe | 819 | { |
5ea8888e | 820 | LogMessage(L_ERROR, "LoadAllJobs: Unable to queue job for destination \"%s\"!", |
1049abbe | 821 | attr->values[0].string.text); |
822 | ippDelete(job->attrs); | |
823 | free(job); | |
723c82e1 | 824 | unlink(filename); |
1049abbe | 825 | continue; |
826 | } | |
827 | ||
36992080 | 828 | SetString(&job->dest, dest); |
1049abbe | 829 | |
3dc4d2a9 | 830 | job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed", |
831 | IPP_TAG_INTEGER); | |
a3e17a89 | 832 | job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME); |
1049abbe | 833 | |
d3d40607 | 834 | if ((attr = ippFindAttribute(job->attrs, "job-priority", IPP_TAG_INTEGER)) == NULL) |
835 | { | |
836 | LogMessage(L_ERROR, "LoadAllJobs: Missing or bad job-priority attribute in control file \"%s\"!", | |
837 | filename); | |
838 | ippDelete(job->attrs); | |
839 | free(job); | |
840 | unlink(filename); | |
841 | continue; | |
842 | } | |
1049abbe | 843 | job->priority = attr->values[0].integer; |
844 | ||
d3d40607 | 845 | if ((attr = ippFindAttribute(job->attrs, "job-originating-user-name", IPP_TAG_NAME)) == NULL) |
846 | { | |
847 | LogMessage(L_ERROR, "LoadAllJobs: Missing or bad job-originating-user-name attribute in control file \"%s\"!", | |
848 | filename); | |
849 | ippDelete(job->attrs); | |
850 | free(job); | |
851 | unlink(filename); | |
852 | continue; | |
853 | } | |
36992080 | 854 | SetString(&job->username, attr->values[0].string.text); |
1049abbe | 855 | |
856 | /* | |
857 | * Insert the job into the array, sorting by job priority and ID... | |
858 | */ | |
859 | ||
9cbd98eb | 860 | for (current = Jobs, prev = NULL; |
861 | current != NULL; | |
862 | prev = current, current = current->next) | |
1049abbe | 863 | if (job->priority > current->priority) |
864 | break; | |
865 | else if (job->priority == current->priority && job->id < current->id) | |
866 | break; | |
867 | ||
868 | job->next = current; | |
869 | if (prev != NULL) | |
870 | prev->next = job; | |
871 | else | |
872 | Jobs = job; | |
6f660540 | 873 | |
874 | NumJobs ++; | |
ec36d2ed | 875 | |
876 | /* | |
877 | * Set the job hold-until time and state... | |
878 | */ | |
879 | ||
880 | if (job->state->values[0].integer == IPP_JOB_HELD) | |
881 | { | |
882 | if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL) | |
883 | attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME); | |
884 | ||
885 | if (attr == NULL) | |
886 | job->state->values[0].integer = IPP_JOB_PENDING; | |
887 | else | |
888 | SetJobHoldUntil(job->id, attr->values[0].string.text); | |
889 | } | |
890 | else if (job->state->values[0].integer == IPP_JOB_PROCESSING) | |
891 | job->state->values[0].integer = IPP_JOB_PENDING; | |
1049abbe | 892 | } |
893 | ||
894 | /* | |
895 | * Read all the d##### files... | |
896 | */ | |
897 | ||
898 | rewinddir(dir); | |
899 | ||
900 | while ((dent = readdir(dir)) != NULL) | |
88f105c5 | 901 | if (NAMLEN(dent) > 7 && dent->d_name[0] == 'd' && strchr(dent->d_name, '-')) |
1049abbe | 902 | { |
903 | /* | |
904 | * Find the job... | |
905 | */ | |
906 | ||
907 | jobid = atoi(dent->d_name + 1); | |
88f105c5 | 908 | fileid = atoi(strchr(dent->d_name, '-') + 1); |
1049abbe | 909 | |
56f7cb11 | 910 | LogMessage(L_DEBUG, "LoadAllJobs: Auto-typing document file %s...", |
911 | dent->d_name); | |
912 | ||
04de52f8 | 913 | snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->d_name); |
1049abbe | 914 | |
915 | if ((job = FindJob(jobid)) == NULL) | |
916 | { | |
93336dbc | 917 | LogMessage(L_ERROR, "LoadAllJobs: Orphaned print file \"%s\"!", |
1049abbe | 918 | filename); |
723c82e1 | 919 | unlink(filename); |
1049abbe | 920 | continue; |
921 | } | |
922 | ||
923 | if (fileid > job->num_files) | |
924 | { | |
925 | if (job->num_files == 0) | |
d59a189c | 926 | { |
927 | compressions = (int *)calloc(fileid, sizeof(int)); | |
928 | filetypes = (mime_type_t **)calloc(fileid, sizeof(mime_type_t *)); | |
929 | } | |
1049abbe | 930 | else |
d59a189c | 931 | { |
932 | compressions = (int *)realloc(job->compressions, | |
933 | sizeof(int) * fileid); | |
934 | filetypes = (mime_type_t **)realloc(job->filetypes, | |
935 | sizeof(mime_type_t *) * fileid); | |
936 | } | |
1049abbe | 937 | |
d59a189c | 938 | if (compressions == NULL || filetypes == NULL) |
1049abbe | 939 | { |
93336dbc | 940 | LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for job file types!"); |
1049abbe | 941 | continue; |
942 | } | |
943 | ||
d59a189c | 944 | job->compressions = compressions; |
945 | job->filetypes = filetypes; | |
946 | job->num_files = fileid; | |
1049abbe | 947 | } |
948 | ||
d59a189c | 949 | job->filetypes[fileid - 1] = mimeFileType(MimeDatabase, filename, |
950 | job->compressions + fileid - 1); | |
35a2ba9d | 951 | |
952 | if (job->filetypes[fileid - 1] == NULL) | |
df7507f5 | 953 | job->filetypes[fileid - 1] = mimeType(MimeDatabase, "application", |
954 | "vnd.cups-raw"); | |
1049abbe | 955 | } |
956 | ||
04de52f8 | 957 | closedir(dir); |
958 | ||
43fe1146 | 959 | /* |
960 | * Clean out old jobs as needed... | |
961 | */ | |
962 | ||
963 | CleanJobs(); | |
bd84e0d1 | 964 | } |
965 | ||
966 | ||
93894a43 | 967 | /* |
968 | * 'MoveJob()' - Move the specified job to a different destination. | |
969 | */ | |
970 | ||
a9de544f | 971 | void |
017c50f3 | 972 | MoveJob(int id, /* I - Job ID */ |
973 | const char *dest) /* I - Destination */ | |
a9de544f | 974 | { |
017c50f3 | 975 | job_t *current; /* Current job */ |
976 | ipp_attribute_t *attr; /* job-printer-uri attribute */ | |
977 | printer_t *p; /* Destination printer or class */ | |
262ed403 | 978 | |
a9de544f | 979 | |
262ed403 | 980 | if ((p = FindPrinter(dest)) == NULL) |
981 | p = FindClass(dest); | |
982 | ||
983 | if (p == NULL) | |
984 | return; | |
a9de544f | 985 | |
93894a43 | 986 | for (current = Jobs; current != NULL; current = current->next) |
a9de544f | 987 | if (current->id == id) |
988 | { | |
753453e4 | 989 | if (current->state->values[0].integer >= IPP_JOB_PROCESSING) |
990 | break; | |
991 | ||
36992080 | 992 | SetString(¤t->dest, dest); |
997cf8b0 | 993 | current->dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE | |
f49663d5 | 994 | CUPS_PRINTER_IMPLICIT); |
1049abbe | 995 | |
262ed403 | 996 | if ((attr = ippFindAttribute(current->attrs, "job-printer-uri", IPP_TAG_URI)) != NULL) |
997 | { | |
998 | free(attr->values[0].string.text); | |
999 | attr->values[0].string.text = strdup(p->uri); | |
1000 | } | |
1001 | ||
1049abbe | 1002 | SaveJob(current->id); |
a9de544f | 1003 | |
1004 | return; | |
1005 | } | |
1006 | } | |
1007 | ||
1008 | ||
bd84e0d1 | 1009 | /* |
f63a2256 | 1010 | * 'ReleaseJob()' - Release the specified job. |
bd84e0d1 | 1011 | */ |
1012 | ||
1013 | void | |
017c50f3 | 1014 | ReleaseJob(int id) /* I - Job ID */ |
bd84e0d1 | 1015 | { |
017c50f3 | 1016 | job_t *job; /* Job data */ |
bd84e0d1 | 1017 | |
1018 | ||
d87b2fe0 | 1019 | LogMessage(L_DEBUG, "ReleaseJob: id = %d", id); |
962e5a9f | 1020 | |
bd84e0d1 | 1021 | if ((job = FindJob(id)) == NULL) |
1022 | return; | |
1023 | ||
1049abbe | 1024 | if (job->state->values[0].integer == IPP_JOB_HELD) |
bd84e0d1 | 1025 | { |
962e5a9f | 1026 | DEBUG_puts("ReleaseJob: setting state to pending..."); |
1027 | ||
1049abbe | 1028 | job->state->values[0].integer = IPP_JOB_PENDING; |
f63a2256 | 1029 | SaveJob(id); |
1030 | CheckJobs(); | |
1031 | } | |
1032 | } | |
1033 | ||
1034 | ||
1035 | /* | |
1036 | * 'RestartJob()' - Restart the specified job. | |
1037 | */ | |
1038 | ||
1039 | void | |
017c50f3 | 1040 | RestartJob(int id) /* I - Job ID */ |
f63a2256 | 1041 | { |
017c50f3 | 1042 | job_t *job; /* Job data */ |
f63a2256 | 1043 | |
1044 | ||
1045 | if ((job = FindJob(id)) == NULL) | |
1046 | return; | |
1047 | ||
1e437ea6 | 1048 | if (job->state->values[0].integer == IPP_JOB_STOPPED || JobFiles) |
f63a2256 | 1049 | { |
53510eae | 1050 | job->tries = 0; |
f63a2256 | 1051 | job->state->values[0].integer = IPP_JOB_PENDING; |
1052 | SaveJob(id); | |
bd84e0d1 | 1053 | CheckJobs(); |
1054 | } | |
1055 | } | |
1056 | ||
1057 | ||
1058 | /* | |
1059 | * 'SaveJob()' - Save a job to disk. | |
1060 | */ | |
1061 | ||
1062 | void | |
017c50f3 | 1063 | SaveJob(int id) /* I - Job ID */ |
bd84e0d1 | 1064 | { |
017c50f3 | 1065 | job_t *job; /* Pointer to job */ |
1066 | char filename[1024]; /* Job control filename */ | |
1067 | int fd; /* File descriptor */ | |
1049abbe | 1068 | |
1069 | ||
1070 | if ((job = FindJob(id)) == NULL) | |
1071 | return; | |
1072 | ||
04de52f8 | 1073 | snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, id); |
99de6da0 | 1074 | |
db911fcb | 1075 | if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) |
99de6da0 | 1076 | { |
db911fcb | 1077 | LogMessage(L_ERROR, "SaveJob: Unable to create job control file \"%s\" - %s.", |
99de6da0 | 1078 | filename, strerror(errno)); |
a2fc3d31 | 1079 | return; |
99de6da0 | 1080 | } |
1081 | ||
1082 | fchmod(fd, 0600); | |
48033118 | 1083 | fchown(fd, RunUser, Group); |
99de6da0 | 1084 | |
db911fcb | 1085 | ippWriteFile(fd, job->attrs); |
6cd03542 | 1086 | |
1087 | LogMessage(L_DEBUG2, "SaveJob: Closing file %d...", fd); | |
1088 | ||
99de6da0 | 1089 | close(fd); |
bd84e0d1 | 1090 | } |
1091 | ||
1092 | ||
e583bc2d | 1093 | /* |
1094 | * 'SetJobHoldUntil()' - Set the hold time for a job... | |
1095 | */ | |
1096 | ||
1097 | void | |
1098 | SetJobHoldUntil(int id, /* I - Job ID */ | |
1099 | const char *when) /* I - When to resume */ | |
1100 | { | |
1101 | job_t *job; /* Pointer to job */ | |
1102 | time_t curtime; /* Current time */ | |
1103 | struct tm *curdate; /* Current date */ | |
1104 | int hour; /* Hold hour */ | |
1105 | int minute; /* Hold minute */ | |
1106 | int second; /* Hold second */ | |
1107 | ||
1108 | ||
d87b2fe0 | 1109 | LogMessage(L_DEBUG, "SetJobHoldUntil(%d, \"%s\")", id, when); |
962e5a9f | 1110 | |
e583bc2d | 1111 | if ((job = FindJob(id)) == NULL) |
1112 | return; | |
1113 | ||
1114 | second = 0; | |
1115 | ||
1116 | if (strcmp(when, "indefinite") == 0) | |
1117 | { | |
1118 | /* | |
1119 | * Hold indefinitely... | |
1120 | */ | |
1121 | ||
1122 | job->hold_until = 0; | |
1123 | } | |
1124 | else if (strcmp(when, "day-time") == 0) | |
1125 | { | |
1126 | /* | |
1127 | * Hold to 6am the next morning unless local time is < 6pm. | |
1128 | */ | |
1129 | ||
1130 | curtime = time(NULL); | |
1131 | curdate = localtime(&curtime); | |
1132 | ||
1133 | if (curdate->tm_hour < 18) | |
1134 | job->hold_until = curtime; | |
1135 | else | |
1136 | job->hold_until = curtime + | |
1137 | ((29 - curdate->tm_hour) * 60 + 59 - | |
1138 | curdate->tm_min) * 60 + 60 - curdate->tm_sec; | |
1139 | } | |
1140 | else if (strcmp(when, "evening") == 0 || strcmp(when, "night") == 0) | |
1141 | { | |
1142 | /* | |
1143 | * Hold to 6pm unless local time is > 6pm or < 6am. | |
1144 | */ | |
1145 | ||
1146 | curtime = time(NULL); | |
1147 | curdate = localtime(&curtime); | |
1148 | ||
1149 | if (curdate->tm_hour < 6 || curdate->tm_hour >= 18) | |
1150 | job->hold_until = curtime; | |
1151 | else | |
1152 | job->hold_until = curtime + | |
1153 | ((17 - curdate->tm_hour) * 60 + 59 - | |
1154 | curdate->tm_min) * 60 + 60 - curdate->tm_sec; | |
1155 | } | |
1156 | else if (strcmp(when, "second-shift") == 0) | |
1157 | { | |
1158 | /* | |
1159 | * Hold to 4pm unless local time is > 4pm. | |
1160 | */ | |
1161 | ||
1162 | curtime = time(NULL); | |
1163 | curdate = localtime(&curtime); | |
1164 | ||
1165 | if (curdate->tm_hour >= 16) | |
1166 | job->hold_until = curtime; | |
1167 | else | |
1168 | job->hold_until = curtime + | |
1169 | ((15 - curdate->tm_hour) * 60 + 59 - | |
1170 | curdate->tm_min) * 60 + 60 - curdate->tm_sec; | |
1171 | } | |
1172 | else if (strcmp(when, "third-shift") == 0) | |
1173 | { | |
1174 | /* | |
1175 | * Hold to 12am unless local time is < 8am. | |
1176 | */ | |
1177 | ||
1178 | curtime = time(NULL); | |
1179 | curdate = localtime(&curtime); | |
1180 | ||
1181 | if (curdate->tm_hour < 8) | |
1182 | job->hold_until = curtime; | |
1183 | else | |
1184 | job->hold_until = curtime + | |
1185 | ((23 - curdate->tm_hour) * 60 + 59 - | |
1186 | curdate->tm_min) * 60 + 60 - curdate->tm_sec; | |
1187 | } | |
1188 | else if (strcmp(when, "weekend") == 0) | |
1189 | { | |
1190 | /* | |
1191 | * Hold to weekend unless we are in the weekend. | |
1192 | */ | |
1193 | ||
1194 | curtime = time(NULL); | |
1195 | curdate = localtime(&curtime); | |
1196 | ||
1197 | if (curdate->tm_wday == 0 || curdate->tm_wday == 6) | |
1198 | job->hold_until = curtime; | |
1199 | else | |
1200 | job->hold_until = curtime + | |
1201 | (((5 - curdate->tm_wday) * 24 + | |
1202 | (17 - curdate->tm_hour)) * 60 + 59 - | |
1203 | curdate->tm_min) * 60 + 60 - curdate->tm_sec; | |
e532393d | 1204 | } |
e583bc2d | 1205 | else if (sscanf(when, "%d:%d:%d", &hour, &minute, &second) >= 2) |
1206 | { | |
1207 | /* | |
e6746ecb | 1208 | * Hold to specified GMT time (HH:MM or HH:MM:SS)... |
e583bc2d | 1209 | */ |
1210 | ||
1211 | curtime = time(NULL); | |
e6746ecb | 1212 | curdate = gmtime(&curtime); |
e583bc2d | 1213 | |
1214 | job->hold_until = curtime + | |
1215 | ((hour - curdate->tm_hour) * 60 + minute - | |
1216 | curdate->tm_min) * 60 + second - curdate->tm_sec; | |
1217 | ||
1218 | /* | |
1219 | * Hold until next day as needed... | |
1220 | */ | |
1221 | ||
1222 | if (job->hold_until < curtime) | |
1223 | job->hold_until += 24 * 60 * 60 * 60; | |
1224 | } | |
962e5a9f | 1225 | |
aa7e125a | 1226 | LogMessage(L_DEBUG, "SetJobHoldUntil: hold_until = %d", (int)job->hold_until); |
e583bc2d | 1227 | } |
1228 | ||
1229 | ||
9cbd98eb | 1230 | /* |
1231 | * 'SetJobPriority()' - Set the priority of a job, moving it up/down in the | |
1232 | * list as needed. | |
1233 | */ | |
1234 | ||
1235 | void | |
017c50f3 | 1236 | SetJobPriority(int id, /* I - Job ID */ |
1237 | int priority) /* I - New priority (0 to 100) */ | |
9cbd98eb | 1238 | { |
017c50f3 | 1239 | job_t *job, /* Job to change */ |
1240 | *current, /* Current job */ | |
1241 | *prev; /* Previous job */ | |
1242 | ipp_attribute_t *attr; /* Job attribute */ | |
9cbd98eb | 1243 | |
1244 | ||
1245 | /* | |
1246 | * Find the job... | |
1247 | */ | |
1248 | ||
1249 | for (current = Jobs, prev = NULL; | |
1250 | current != NULL; | |
1251 | prev = current, current = current->next) | |
1252 | if (current->id == id) | |
1253 | break; | |
1254 | ||
1255 | if (current == NULL) | |
1256 | return; | |
1257 | ||
1258 | /* | |
1259 | * Set the new priority... | |
1260 | */ | |
1261 | ||
1262 | job = current; | |
1263 | job->priority = priority; | |
1264 | ||
1265 | if ((attr = ippFindAttribute(job->attrs, "job-priority", IPP_TAG_INTEGER)) != NULL) | |
1266 | attr->values[0].integer = priority; | |
1267 | else | |
1268 | ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority", | |
1269 | priority); | |
1270 | ||
1271 | SaveJob(job->id); | |
1272 | ||
1273 | /* | |
1274 | * See if we need to do any sorting... | |
1275 | */ | |
1276 | ||
1277 | if ((prev == NULL || job->priority < prev->priority) && | |
1278 | (job->next == NULL || job->next->priority < job->priority)) | |
1279 | return; | |
1280 | ||
1281 | /* | |
1282 | * Remove the job from the list, and then insert it where it belongs... | |
1283 | */ | |
1284 | ||
1285 | if (prev == NULL) | |
1286 | Jobs = job->next; | |
1287 | else | |
1288 | prev->next = job->next; | |
1289 | ||
1290 | for (current = Jobs, prev = NULL; | |
1291 | current != NULL; | |
1292 | prev = current, current = current->next) | |
1293 | if (job->priority > current->priority) | |
1294 | break; | |
1295 | ||
1296 | job->next = current; | |
1297 | if (prev != NULL) | |
1298 | prev->next = job; | |
1299 | else | |
1300 | Jobs = job; | |
1301 | } | |
1302 | ||
1303 | ||
93894a43 | 1304 | /* |
1305 | * 'StartJob()' - Start a print job. | |
1306 | */ | |
1307 | ||
a9de544f | 1308 | void |
dd63ebe2 | 1309 | StartJob(int id, /* I - Job ID */ |
1310 | printer_t *printer) /* I - Printer to print job */ | |
a9de544f | 1311 | { |
dd63ebe2 | 1312 | job_t *current; /* Current job */ |
1313 | int i; /* Looping var */ | |
1314 | int slot; /* Pipe slot */ | |
1315 | int num_filters; /* Number of filters for job */ | |
1316 | mime_filter_t *filters; /* Filters for job */ | |
1317 | char method[255], /* Method for output */ | |
9a424b1e | 1318 | *optptr, /* Pointer to options */ |
1319 | *valptr; /* Pointer in value string */ | |
dd63ebe2 | 1320 | ipp_attribute_t *attr; /* Current attribute */ |
1321 | int pid; /* Process ID of new filter process */ | |
1322 | int banner_page; /* 1 if banner page, 0 otherwise */ | |
1323 | int statusfds[2], /* Pipes used between the filters and scheduler */ | |
1324 | filterfds[2][2]; /* Pipes used between the filters */ | |
1325 | int envc; /* Number of environment variables */ | |
1326 | char *argv[8], /* Filter command-line arguments */ | |
1327 | filename[1024], /* Job filename */ | |
1328 | command[1024], /* Full path to filter/backend command */ | |
1329 | jobid[255], /* Job ID string */ | |
1330 | title[IPP_MAX_NAME], /* Job title string */ | |
1331 | copies[255], /* # copies string */ | |
1332 | *envp[100], /* Environment variables */ | |
cc6d5b1e | 1333 | #ifdef __APPLE__ |
dd63ebe2 | 1334 | processPath[1050], /* CFProcessPath environment variable */ |
cc6d5b1e | 1335 | #endif /* __APPLE__ */ |
dd63ebe2 | 1336 | path[1024], /* PATH environment variable */ |
ff40b65e | 1337 | ipp_port[1024], /* IPP_PORT environment variable */ |
dd63ebe2 | 1338 | language[255], /* LANG environment variable */ |
1339 | charset[255], /* CHARSET environment variable */ | |
1340 | classification[1024], /* CLASSIFICATION environment variable */ | |
1341 | content_type[1024], /* CONTENT_TYPE environment variable */ | |
1342 | device_uri[1024], /* DEVICE_URI environment variable */ | |
2cb3f80d | 1343 | sani_uri[1024], /* Sanitized DEVICE_URI env var */ |
dd63ebe2 | 1344 | ppd[1024], /* PPD environment variable */ |
1345 | class_name[255], /* CLASS environment variable */ | |
1346 | printer_name[255], /* PRINTER environment variable */ | |
1347 | root[1024], /* CUPS_SERVERROOT environment variable */ | |
1348 | cache[255], /* RIP_MAX_CACHE environment variable */ | |
1349 | tmpdir[1024], /* TMPDIR environment variable */ | |
1350 | ld_library_path[1024], /* LD_LIBRARY_PATH environment variable */ | |
1351 | ld_preload[1024], /* LD_PRELOAD environment variable */ | |
1352 | dyld_library_path[1024],/* DYLD_LIBRARY_PATH environment variable */ | |
1353 | shlib_path[1024], /* SHLIB_PATH environment variable */ | |
1354 | nlspath[1024], /* NLSPATH environment variable */ | |
1355 | datadir[1024], /* CUPS_DATADIR environment variable */ | |
ff40b65e | 1356 | fontpath[1050], /* CUPS_FONTPATH environment variable */ |
1f4b7b03 | 1357 | vg_args[1024], /* VG_ARGS environment variable */ |
1358 | ld_assume_kernel[1024]; /* LD_ASSUME_KERNEL environment variable */ | |
dd63ebe2 | 1359 | static char *options = NULL; /* Full list of options */ |
1360 | static int optlength = 0; /* Length of option buffer */ | |
6abc7437 | 1361 | |
1362 | ||
aa7e125a | 1363 | LogMessage(L_DEBUG, "StartJob(%d, %p)", id, printer); |
a9de544f | 1364 | |
93894a43 | 1365 | for (current = Jobs; current != NULL; current = current->next) |
a9de544f | 1366 | if (current->id == id) |
e63d9801 | 1367 | break; |
6abc7437 | 1368 | |
e63d9801 | 1369 | if (current == NULL) |
1370 | return; | |
1371 | ||
b5cb0608 | 1372 | LogMessage(L_DEBUG, "StartJob() id = %d, file = %d/%d", id, |
1373 | current->current_file, current->num_files); | |
93336dbc | 1374 | |
b4257036 | 1375 | if (current->num_files == 0) |
1376 | { | |
93336dbc | 1377 | LogMessage(L_ERROR, "Job ID %d has no files! Cancelling it!", id); |
b4257036 | 1378 | CancelJob(id, 0); |
1379 | return; | |
1380 | } | |
1381 | ||
e63d9801 | 1382 | /* |
1383 | * Figure out what filters are required to convert from | |
1384 | * the source to the destination type... | |
1385 | */ | |
1386 | ||
8239f206 | 1387 | num_filters = 0; |
1388 | current->cost = 0; | |
e63d9801 | 1389 | |
a7a1daf4 | 1390 | if (printer->raw) |
e63d9801 | 1391 | { |
1392 | /* | |
a7a1daf4 | 1393 | * Remote jobs and raw queues go directly to the printer without |
d47f8ebe | 1394 | * filtering... |
e63d9801 | 1395 | */ |
6abc7437 | 1396 | |
8f9fe91c | 1397 | LogMessage(L_DEBUG, "StartJob: Sending job to queue tagged as raw..."); |
1398 | ||
e63d9801 | 1399 | filters = NULL; |
1400 | } | |
1401 | else | |
1402 | { | |
1403 | /* | |
1404 | * Local jobs get filtered... | |
1405 | */ | |
a9de544f | 1406 | |
e09246c8 | 1407 | filters = mimeFilter(MimeDatabase, current->filetypes[current->current_file], |
6ed689f8 | 1408 | printer->filetype, &num_filters, MAX_FILTERS - 1); |
6abc7437 | 1409 | |
e63d9801 | 1410 | if (num_filters == 0) |
1411 | { | |
93336dbc | 1412 | LogMessage(L_ERROR, "Unable to convert file %d to printable format for job %d!", |
1413 | current->current_file, current->id); | |
deb855a2 | 1414 | LogMessage(L_INFO, "Hint: Do you have ESP Ghostscript installed?"); |
1415 | ||
1416 | if (LogLevel < L_DEBUG) | |
1417 | LogMessage(L_INFO, "Hint: Try setting the LogLevel to \"debug\"."); | |
1418 | ||
93336dbc | 1419 | current->current_file ++; |
1420 | ||
1421 | if (current->current_file == current->num_files) | |
1422 | CancelJob(current->id, 0); | |
1423 | ||
e63d9801 | 1424 | return; |
1425 | } | |
8239f206 | 1426 | |
753453e4 | 1427 | /* |
1428 | * Remove NULL ("-") filters... | |
1429 | */ | |
1430 | ||
1431 | for (i = 0; i < num_filters;) | |
1432 | if (strcmp(filters[i].filter, "-") == 0) | |
1433 | { | |
1434 | num_filters --; | |
1435 | if (i < num_filters) | |
1436 | memcpy(filters + i, filters + i + 1, | |
1437 | (num_filters - i) * sizeof(mime_filter_t)); | |
1438 | } | |
1439 | else | |
1440 | i ++; | |
1441 | ||
1442 | if (num_filters == 0) | |
1443 | { | |
1444 | free(filters); | |
1445 | filters = NULL; | |
1446 | } | |
1447 | else | |
1448 | { | |
1449 | /* | |
1450 | * Compute filter cost... | |
1451 | */ | |
1452 | ||
1453 | for (i = 0; i < num_filters; i ++) | |
1454 | current->cost += filters[i].cost; | |
1455 | } | |
8239f206 | 1456 | } |
1457 | ||
1458 | /* | |
1459 | * See if the filter cost is too high... | |
1460 | */ | |
1461 | ||
fcc9e285 | 1462 | if ((FilterLevel + current->cost) > FilterLimit && FilterLevel > 0 && |
1463 | FilterLimit > 0) | |
8239f206 | 1464 | { |
1465 | /* | |
1466 | * Don't print this job quite yet... | |
1467 | */ | |
1468 | ||
1469 | if (filters != NULL) | |
1470 | free(filters); | |
1471 | ||
d87b2fe0 | 1472 | LogMessage(L_INFO, "Holding job %d because filter limit has been reached.", |
1473 | id); | |
1474 | LogMessage(L_DEBUG, "StartJob: id = %d, file = %d, " | |
93336dbc | 1475 | "cost = %d, level = %d, limit = %d", |
1476 | id, current->current_file, current->cost, FilterLevel, | |
1477 | FilterLimit); | |
8239f206 | 1478 | return; |
e63d9801 | 1479 | } |
c7fa9d06 | 1480 | |
8239f206 | 1481 | FilterLevel += current->cost; |
1482 | ||
d59a189c | 1483 | /* |
1484 | * Add decompression filters, if any... | |
1485 | */ | |
1486 | ||
1487 | if (current->compressions[current->current_file]) | |
1488 | { | |
1489 | /* | |
1490 | * Add gziptoany filter to the front of the list... | |
1491 | */ | |
1492 | ||
1493 | mime_filter_t *temp_filters; | |
1494 | ||
1495 | if (num_filters == 0) | |
1496 | temp_filters = malloc(sizeof(mime_filter_t)); | |
1497 | else | |
1498 | temp_filters = realloc(filters, | |
1499 | sizeof(mime_filter_t) * (num_filters + 1)); | |
1500 | ||
1501 | if (temp_filters == NULL) | |
1502 | { | |
1503 | LogMessage(L_ERROR, "Unable to add decompression filter - %s", | |
1504 | strerror(errno)); | |
1505 | ||
8650fcf2 | 1506 | if (filters != NULL) |
1507 | free(filters); | |
d59a189c | 1508 | |
1509 | current->current_file ++; | |
1510 | ||
1511 | if (current->current_file == current->num_files) | |
1512 | CancelJob(current->id, 0); | |
1513 | ||
1514 | return; | |
1515 | } | |
1516 | ||
db7c983e | 1517 | filters = temp_filters; |
1518 | memmove(filters + 1, filters, num_filters * sizeof(mime_filter_t)); | |
1519 | *filters = gziptoany_filter; | |
d59a189c | 1520 | num_filters ++; |
1521 | } | |
1522 | ||
8239f206 | 1523 | /* |
1524 | * Update the printer and job state to "processing"... | |
1525 | */ | |
1526 | ||
8239f206 | 1527 | current->state->values[0].integer = IPP_JOB_PROCESSING; |
1528 | current->status = 0; | |
1529 | current->printer = printer; | |
1530 | printer->job = current; | |
aa3b74e1 | 1531 | SetPrinterState(printer, IPP_PRINTER_PROCESSING, 0); |
8239f206 | 1532 | |
93336dbc | 1533 | if (current->current_file == 0) |
a2fc3d31 | 1534 | { |
93336dbc | 1535 | set_time(current, "time-at-processing"); |
8650fcf2 | 1536 | cupsdOpenPipe(current->back_pipes); |
a2fc3d31 | 1537 | } |
8239f206 | 1538 | |
b5cb0608 | 1539 | /* |
1540 | * Determine if we are printing a banner page or not... | |
1541 | */ | |
1542 | ||
1543 | if (current->job_sheets == NULL) | |
753453e4 | 1544 | { |
b5cb0608 | 1545 | LogMessage(L_DEBUG, "No job-sheets attribute."); |
753453e4 | 1546 | if ((current->job_sheets = |
1547 | ippFindAttribute(current->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL) | |
1548 | LogMessage(L_DEBUG, "... but someone added one without setting job_sheets!"); | |
1549 | } | |
b5cb0608 | 1550 | else if (current->job_sheets->num_values == 1) |
1551 | LogMessage(L_DEBUG, "job-sheets=%s", | |
1552 | current->job_sheets->values[0].string.text); | |
1553 | else | |
1554 | LogMessage(L_DEBUG, "job-sheets=%s,%s", | |
1555 | current->job_sheets->values[0].string.text, | |
1556 | current->job_sheets->values[1].string.text); | |
1557 | ||
934ef66d | 1558 | if (printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) |
b5cb0608 | 1559 | banner_page = 0; |
1560 | else if (current->job_sheets == NULL) | |
1561 | banner_page = 0; | |
1562 | else if (strcasecmp(current->job_sheets->values[0].string.text, "none") != 0 && | |
1563 | current->current_file == 0) | |
1564 | banner_page = 1; | |
1565 | else if (current->job_sheets->num_values > 1 && | |
1566 | strcasecmp(current->job_sheets->values[1].string.text, "none") != 0 && | |
1567 | current->current_file == (current->num_files - 1)) | |
1568 | banner_page = 1; | |
1569 | else | |
1570 | banner_page = 0; | |
1571 | ||
1572 | LogMessage(L_DEBUG, "banner_page = %d", banner_page); | |
1573 | ||
e63d9801 | 1574 | /* |
1575 | * Building the options string is harder than it needs to be, but | |
1576 | * for the moment we need to pass strings for command-line args and | |
1577 | * not IPP attribute pointers... :) | |
673d1710 | 1578 | * |
ad717326 | 1579 | * First allocate/reallocate the option buffer as needed... |
673d1710 | 1580 | */ |
1581 | ||
ad717326 | 1582 | i = ipp_length(current->attrs); |
673d1710 | 1583 | |
1584 | if (i > optlength) | |
1585 | { | |
1586 | if (optlength == 0) | |
1587 | optptr = malloc(i); | |
1588 | else | |
1589 | optptr = realloc(options, i); | |
1590 | ||
1591 | if (optptr == NULL) | |
1592 | { | |
1593 | LogMessage(L_CRIT, "StartJob: Unable to allocate %d bytes for option buffer for job %d!", | |
1594 | i, id); | |
1595 | ||
1596 | if (filters != NULL) | |
1597 | free(filters); | |
1598 | ||
1599 | FilterLevel -= current->cost; | |
1600 | ||
1601 | CancelJob(id, 0); | |
1602 | return; | |
1603 | } | |
1604 | ||
1605 | options = optptr; | |
1606 | optlength = i; | |
1607 | } | |
1608 | ||
1609 | /* | |
1610 | * Now loop through the attributes and convert them to the textual | |
1611 | * representation used by the filters... | |
e63d9801 | 1612 | */ |
6abc7437 | 1613 | |
e63d9801 | 1614 | optptr = options; |
1615 | *optptr = '\0'; | |
5b88701c | 1616 | |
a6988fb1 | 1617 | snprintf(title, sizeof(title), "%s-%d", printer->name, current->id); |
e63d9801 | 1618 | strcpy(copies, "1"); |
6abc7437 | 1619 | |
e63d9801 | 1620 | for (attr = current->attrs->attrs; attr != NULL; attr = attr->next) |
1621 | { | |
1622 | if (strcmp(attr->name, "copies") == 0 && | |
1623 | attr->value_tag == IPP_TAG_INTEGER) | |
a3e17a89 | 1624 | { |
1625 | /* | |
1626 | * Don't use the # copies attribute if we are printing the job sheets... | |
1627 | */ | |
1628 | ||
b5cb0608 | 1629 | if (!banner_page) |
a3e17a89 | 1630 | sprintf(copies, "%d", attr->values[0].integer); |
1631 | } | |
e63d9801 | 1632 | else if (strcmp(attr->name, "job-name") == 0 && |
1633 | (attr->value_tag == IPP_TAG_NAME || | |
1634 | attr->value_tag == IPP_TAG_NAMELANG)) | |
def978d5 | 1635 | strlcpy(title, attr->values[0].string.text, sizeof(title)); |
d588a92e | 1636 | else if (attr->group_tag == IPP_TAG_JOB) |
e63d9801 | 1637 | { |
c0521f33 | 1638 | /* |
1639 | * Filter out other unwanted attributes... | |
1640 | */ | |
1641 | ||
e63d9801 | 1642 | if (attr->value_tag == IPP_TAG_MIMETYPE || |
1643 | attr->value_tag == IPP_TAG_NAMELANG || | |
1644 | attr->value_tag == IPP_TAG_TEXTLANG || | |
1645 | attr->value_tag == IPP_TAG_URI || | |
ec6338d6 | 1646 | attr->value_tag == IPP_TAG_URISCHEME || |
1647 | attr->value_tag == IPP_TAG_BEGIN_COLLECTION) /* Not yet supported */ | |
e63d9801 | 1648 | continue; |
6abc7437 | 1649 | |
83f08393 | 1650 | if (strncmp(attr->name, "time-", 5) == 0) |
1651 | continue; | |
1652 | ||
1653 | if (strncmp(attr->name, "job-", 4) == 0 && | |
1654 | !(printer->type & CUPS_PRINTER_REMOTE)) | |
1655 | continue; | |
1656 | ||
1657 | if (strncmp(attr->name, "job-", 4) == 0 && | |
d11458ff | 1658 | strcmp(attr->name, "job-billing") != 0 && |
83f08393 | 1659 | strcmp(attr->name, "job-sheets") != 0 && |
1660 | strcmp(attr->name, "job-hold-until") != 0 && | |
1661 | strcmp(attr->name, "job-priority") != 0) | |
c0521f33 | 1662 | continue; |
1663 | ||
b91c8a76 | 1664 | if ((strcmp(attr->name, "page-label") == 0 || |
801766ac | 1665 | strcmp(attr->name, "page-border") == 0 || |
34089ee8 | 1666 | strncmp(attr->name, "number-up", 9) == 0 || |
1667 | strcmp(attr->name, "page-set") == 0) && | |
b5cb0608 | 1668 | banner_page) |
1669 | continue; | |
1670 | ||
c0521f33 | 1671 | /* |
1672 | * Otherwise add them to the list... | |
1673 | */ | |
1674 | ||
e63d9801 | 1675 | if (optptr > options) |
50f63f23 | 1676 | strlcat(optptr, " ", optlength - (optptr - options)); |
6abc7437 | 1677 | |
e63d9801 | 1678 | if (attr->value_tag != IPP_TAG_BOOLEAN) |
6abc7437 | 1679 | { |
50f63f23 | 1680 | strlcat(optptr, attr->name, optlength - (optptr - options)); |
1681 | strlcat(optptr, "=", optlength - (optptr - options)); | |
6abc7437 | 1682 | } |
1683 | ||
e63d9801 | 1684 | for (i = 0; i < attr->num_values; i ++) |
1685 | { | |
1686 | if (i) | |
50f63f23 | 1687 | strlcat(optptr, ",", optlength - (optptr - options)); |
6abc7437 | 1688 | |
e63d9801 | 1689 | optptr += strlen(optptr); |
6abc7437 | 1690 | |
e63d9801 | 1691 | switch (attr->value_tag) |
1692 | { | |
1693 | case IPP_TAG_INTEGER : | |
1694 | case IPP_TAG_ENUM : | |
50f63f23 | 1695 | snprintf(optptr, optlength - (optptr - options), |
d588a92e | 1696 | "%d", attr->values[i].integer); |
e63d9801 | 1697 | break; |
1698 | ||
1699 | case IPP_TAG_BOOLEAN : | |
1700 | if (!attr->values[i].boolean) | |
50f63f23 | 1701 | strlcat(optptr, "no", optlength - (optptr - options)); |
e63d9801 | 1702 | |
1703 | case IPP_TAG_NOVALUE : | |
def978d5 | 1704 | strlcat(optptr, attr->name, |
50f63f23 | 1705 | optlength - (optptr - options)); |
e63d9801 | 1706 | break; |
1707 | ||
1708 | case IPP_TAG_RANGE : | |
74cfdb8b | 1709 | if (attr->values[i].range.lower == attr->values[i].range.upper) |
50f63f23 | 1710 | snprintf(optptr, optlength - (optptr - options) - 1, |
74cfdb8b | 1711 | "%d", attr->values[i].range.lower); |
1712 | else | |
50f63f23 | 1713 | snprintf(optptr, optlength - (optptr - options) - 1, |
74cfdb8b | 1714 | "%d-%d", attr->values[i].range.lower, |
1715 | attr->values[i].range.upper); | |
e63d9801 | 1716 | break; |
1717 | ||
1718 | case IPP_TAG_RESOLUTION : | |
50f63f23 | 1719 | snprintf(optptr, optlength - (optptr - options) - 1, |
d588a92e | 1720 | "%dx%d%s", attr->values[i].resolution.xres, |
1721 | attr->values[i].resolution.yres, | |
1722 | attr->values[i].resolution.units == IPP_RES_PER_INCH ? | |
1723 | "dpi" : "dpc"); | |
e63d9801 | 1724 | break; |
1725 | ||
1726 | case IPP_TAG_STRING : | |
1727 | case IPP_TAG_TEXT : | |
1728 | case IPP_TAG_NAME : | |
1729 | case IPP_TAG_KEYWORD : | |
1730 | case IPP_TAG_CHARSET : | |
1731 | case IPP_TAG_LANGUAGE : | |
d81dac78 | 1732 | for (valptr = attr->values[i].string.text; *valptr;) |
e63d9801 | 1733 | { |
9a424b1e | 1734 | if (strchr(" \t\n\\\'\"", *valptr)) |
1735 | *optptr++ = '\\'; | |
1736 | *optptr++ = *valptr++; | |
e63d9801 | 1737 | } |
9a424b1e | 1738 | |
1739 | *optptr = '\0'; | |
e63d9801 | 1740 | break; |
d21a7597 | 1741 | |
1742 | default : | |
1743 | break; /* anti-compiler-warning-code */ | |
e63d9801 | 1744 | } |
6abc7437 | 1745 | } |
1746 | ||
e63d9801 | 1747 | optptr += strlen(optptr); |
1748 | } | |
1749 | } | |
6abc7437 | 1750 | |
e63d9801 | 1751 | /* |
1752 | * Build the command-line arguments for the filters. Each filter | |
1753 | * has 6 or 7 arguments: | |
1754 | * | |
1755 | * argv[0] = printer | |
1756 | * argv[1] = job ID | |
1757 | * argv[2] = username | |
1758 | * argv[3] = title | |
1759 | * argv[4] = # copies | |
1760 | * argv[5] = options | |
1761 | * argv[6] = filename (optional; normally stdin) | |
1762 | * | |
1763 | * This allows legacy printer drivers that use the old System V | |
1764 | * printing interface to be used by CUPS. | |
1765 | */ | |
1766 | ||
1767 | sprintf(jobid, "%d", current->id); | |
a6988fb1 | 1768 | snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, |
1769 | current->id, current->current_file + 1); | |
e63d9801 | 1770 | |
1771 | argv[0] = printer->name; | |
1772 | argv[1] = jobid; | |
1773 | argv[2] = current->username; | |
1774 | argv[3] = title; | |
1775 | argv[4] = copies; | |
1776 | argv[5] = options; | |
e09246c8 | 1777 | argv[6] = filename; |
e63d9801 | 1778 | argv[7] = NULL; |
1779 | ||
d87b2fe0 | 1780 | LogMessage(L_DEBUG, "StartJob: argv = \"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"", |
93336dbc | 1781 | argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); |
e63d9801 | 1782 | |
1783 | /* | |
1784 | * Create environment variable strings for the filters... | |
1785 | */ | |
1786 | ||
1787 | attr = ippFindAttribute(current->attrs, "attributes-natural-language", | |
1788 | IPP_TAG_LANGUAGE); | |
31e65f97 | 1789 | |
1790 | switch (strlen(attr->values[0].string.text)) | |
1791 | { | |
1792 | default : | |
1793 | /* | |
1794 | * This is an unknown or badly formatted language code; use | |
1795 | * the POSIX locale... | |
1796 | */ | |
1797 | ||
1798 | strcpy(language, "LANG=C"); | |
1799 | break; | |
1800 | ||
1801 | case 2 : | |
1802 | /* | |
1803 | * Just the language code (ll)... | |
1804 | */ | |
1805 | ||
1806 | snprintf(language, sizeof(language), "LANG=%s", | |
1807 | attr->values[0].string.text); | |
1808 | break; | |
1809 | ||
1810 | case 5 : | |
1811 | /* | |
1812 | * Language and country code (ll-cc)... | |
1813 | */ | |
1814 | ||
1815 | snprintf(language, sizeof(language), "LANG=%c%c_%c%c", | |
1816 | attr->values[0].string.text[0], | |
1817 | attr->values[0].string.text[1], | |
da275f55 | 1818 | toupper(attr->values[0].string.text[3] & 255), |
1819 | toupper(attr->values[0].string.text[4] & 255)); | |
31e65f97 | 1820 | break; |
1821 | } | |
e63d9801 | 1822 | |
1823 | attr = ippFindAttribute(current->attrs, "document-format", | |
1824 | IPP_TAG_MIMETYPE); | |
ad2b0c5f | 1825 | if (attr != NULL && |
1826 | (optptr = strstr(attr->values[0].string.text, "charset=")) != NULL) | |
a6988fb1 | 1827 | snprintf(charset, sizeof(charset), "CHARSET=%s", optptr + 8); |
e63d9801 | 1828 | else |
1829 | { | |
1830 | attr = ippFindAttribute(current->attrs, "attributes-charset", | |
1831 | IPP_TAG_CHARSET); | |
a6988fb1 | 1832 | snprintf(charset, sizeof(charset), "CHARSET=%s", |
1833 | attr->values[0].string.text); | |
e63d9801 | 1834 | } |
6abc7437 | 1835 | |
16566558 | 1836 | snprintf(path, sizeof(path), "PATH=%s/filter:/bin:/usr/bin", ServerBin); |
a6988fb1 | 1837 | snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s", |
1838 | current->filetypes[current->current_file]->super, | |
1839 | current->filetypes[current->current_file]->type); | |
04de52f8 | 1840 | snprintf(device_uri, sizeof(device_uri), "DEVICE_URI=%s", printer->device_uri); |
18157eca | 1841 | cupsdSanitizeURI(printer->device_uri, sani_uri, sizeof(sani_uri)); |
df3f73ff | 1842 | snprintf(ppd, sizeof(ppd), "PPD=%s/ppd/%s.ppd", ServerRoot, printer->name); |
a6988fb1 | 1843 | snprintf(printer_name, sizeof(printer_name), "PRINTER=%s", printer->name); |
04de52f8 | 1844 | snprintf(cache, sizeof(cache), "RIP_MAX_CACHE=%s", RIPCache); |
1845 | snprintf(root, sizeof(root), "CUPS_SERVERROOT=%s", ServerRoot); | |
1846 | snprintf(tmpdir, sizeof(tmpdir), "TMPDIR=%s", TempDir); | |
1847 | snprintf(datadir, sizeof(datadir), "CUPS_DATADIR=%s", DataDir); | |
1848 | snprintf(fontpath, sizeof(fontpath), "CUPS_FONTPATH=%s", FontPath); | |
ff40b65e | 1849 | sprintf(ipp_port, "IPP_PORT=%d", LocalPort); |
1cf29e95 | 1850 | |
dd63ebe2 | 1851 | envc = 0; |
1852 | ||
1853 | envp[envc ++] = path; | |
1854 | envp[envc ++] = "SOFTWARE=CUPS/1.1"; | |
1855 | envp[envc ++] = "USER=root"; | |
1856 | envp[envc ++] = charset; | |
1857 | envp[envc ++] = language; | |
ff40b65e | 1858 | if (TZ && TZ[0]) |
1859 | envp[envc ++] = TZ; | |
dd63ebe2 | 1860 | envp[envc ++] = ppd; |
1861 | envp[envc ++] = root; | |
1862 | envp[envc ++] = cache; | |
1863 | envp[envc ++] = tmpdir; | |
1864 | envp[envc ++] = content_type; | |
1865 | envp[envc ++] = device_uri; | |
1866 | envp[envc ++] = printer_name; | |
1867 | envp[envc ++] = datadir; | |
1868 | envp[envc ++] = fontpath; | |
ff40b65e | 1869 | envp[envc ++] = "CUPS_SERVER=localhost"; |
1870 | envp[envc ++] = ipp_port; | |
1871 | ||
1872 | if (getenv("VG_ARGS") != NULL) | |
1873 | { | |
1874 | snprintf(vg_args, sizeof(vg_args), "VG_ARGS=%s", getenv("VG_ARGS")); | |
1875 | envp[envc ++] = vg_args; | |
1876 | } | |
dd63ebe2 | 1877 | |
1f4b7b03 | 1878 | if (getenv("LD_ASSUME_KERNEL") != NULL) |
1879 | { | |
1880 | snprintf(ld_assume_kernel, sizeof(ld_assume_kernel), "LD_ASSUME_KERNEL=%s", | |
1881 | getenv("LD_ASSUME_KERNEL")); | |
1882 | envp[envc ++] = ld_assume_kernel; | |
1883 | } | |
1884 | ||
dd63ebe2 | 1885 | if (getenv("LD_LIBRARY_PATH") != NULL) |
1886 | { | |
1887 | snprintf(ld_library_path, sizeof(ld_library_path), "LD_LIBRARY_PATH=%s", | |
1888 | getenv("LD_LIBRARY_PATH")); | |
1889 | envp[envc ++] = ld_library_path; | |
1890 | } | |
1891 | ||
1892 | if (getenv("LD_PRELOAD") != NULL) | |
1893 | { | |
1894 | snprintf(ld_preload, sizeof(ld_preload), "LD_PRELOAD=%s", | |
1895 | getenv("LD_PRELOAD")); | |
1896 | envp[envc ++] = ld_preload; | |
1897 | } | |
1898 | ||
1899 | if (getenv("DYLD_LIBRARY_PATH") != NULL) | |
1900 | { | |
1901 | snprintf(dyld_library_path, sizeof(dyld_library_path), "DYLD_LIBRARY_PATH=%s", | |
1902 | getenv("DYLD_LIBRARY_PATH")); | |
1903 | envp[envc ++] = dyld_library_path; | |
1904 | } | |
1905 | ||
1906 | if (getenv("SHLIB_PATH") != NULL) | |
1907 | { | |
1908 | snprintf(shlib_path, sizeof(shlib_path), "SHLIB_PATH=%s", | |
1909 | getenv("SHLIB_PATH")); | |
1910 | envp[envc ++] = shlib_path; | |
1911 | } | |
1912 | ||
1913 | if (getenv("NLSPATH") != NULL) | |
1914 | { | |
1915 | snprintf(nlspath, sizeof(nlspath), "NLSPATH=%s", getenv("NLSPATH")); | |
1916 | envp[envc ++] = nlspath; | |
1917 | } | |
997cf8b0 | 1918 | |
36992080 | 1919 | if (Classification && !banner_page) |
753453e4 | 1920 | { |
1921 | if ((attr = ippFindAttribute(current->attrs, "job-sheets", | |
1922 | IPP_TAG_NAME)) == NULL) | |
1923 | snprintf(classification, sizeof(classification), "CLASSIFICATION=%s", | |
1924 | Classification); | |
1925 | else if (attr->num_values > 1 && | |
1926 | strcmp(attr->values[1].string.text, "none") != 0) | |
1927 | snprintf(classification, sizeof(classification), "CLASSIFICATION=%s", | |
1928 | attr->values[1].string.text); | |
1929 | else | |
1930 | snprintf(classification, sizeof(classification), "CLASSIFICATION=%s", | |
1931 | attr->values[0].string.text); | |
dd63ebe2 | 1932 | |
1933 | envp[envc ++] = classification; | |
753453e4 | 1934 | } |
1cf29e95 | 1935 | |
dd63ebe2 | 1936 | if (current->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) |
1937 | { | |
1938 | snprintf(class_name, sizeof(class_name), "CLASS=%s", current->dest); | |
1939 | envp[envc ++] = class_name; | |
1940 | } | |
e63d9801 | 1941 | |
cc6d5b1e | 1942 | #ifdef __APPLE__ |
5d2bd8d5 | 1943 | strlcpy(processPath, "<CFProcessPath>", sizeof(processPath)); |
dd63ebe2 | 1944 | envp[envc ++] = processPath; |
cc6d5b1e | 1945 | #endif /* __APPLE__ */ |
e63d9801 | 1946 | |
b696f4e3 | 1947 | envp[envc] = NULL; |
dd63ebe2 | 1948 | |
1949 | for (i = 0; i < envc; i ++) | |
2cb3f80d | 1950 | if (strncmp(envp[i], "DEVICE_URI=", 11)) |
1951 | LogMessage(L_DEBUG, "StartJob: envp[%d]=\"%s\"", i, envp[i]); | |
1952 | else | |
18157eca | 1953 | LogMessage(L_DEBUG, "StartJob: envp[%d]=\"DEVICE_URI=%s\"", i, sani_uri); |
e63d9801 | 1954 | |
1049abbe | 1955 | current->current_file ++; |
1956 | ||
e63d9801 | 1957 | /* |
1958 | * Now create processes for all of the filters... | |
1959 | */ | |
1960 | ||
8650fcf2 | 1961 | if (cupsdOpenPipe(statusfds)) |
e63d9801 | 1962 | { |
93336dbc | 1963 | LogMessage(L_ERROR, "Unable to create job status pipes - %s.", |
e63d9801 | 1964 | strerror(errno)); |
a6988fb1 | 1965 | snprintf(printer->state_message, sizeof(printer->state_message), |
1966 | "Unable to create status pipes - %s.", strerror(errno)); | |
c8a55d2c | 1967 | |
1968 | AddPrinterHistory(printer); | |
db3c5bfd | 1969 | |
1970 | if (filters != NULL) | |
1971 | free(filters); | |
1972 | ||
8650fcf2 | 1973 | CancelJob(current->id, 0); |
e63d9801 | 1974 | return; |
1975 | } | |
6abc7437 | 1976 | |
18fe941f | 1977 | LogMessage(L_DEBUG, "StartJob: statusfds = [ %d %d ]", |
93336dbc | 1978 | statusfds[0], statusfds[1]); |
bfa1abf0 | 1979 | |
e6df8a90 | 1980 | #ifdef FD_CLOEXEC |
1981 | fcntl(statusfds[0], F_SETFD, FD_CLOEXEC); | |
1982 | fcntl(statusfds[1], F_SETFD, FD_CLOEXEC); | |
1983 | #endif /* FD_CLOEXEC */ | |
1984 | ||
294f4cee | 1985 | current->status_buffer = cupsdStatBufNew(statusfds[0], "[Job %d]", |
1986 | current->id); | |
1987 | current->status = 0; | |
a2fc3d31 | 1988 | memset(current->filters, 0, sizeof(current->filters)); |
6abc7437 | 1989 | |
e63d9801 | 1990 | filterfds[1][0] = open("/dev/null", O_RDONLY); |
1991 | filterfds[1][1] = -1; | |
93336dbc | 1992 | |
db3c5bfd | 1993 | if (filterfds[1][0] < 0) |
1994 | { | |
1995 | LogMessage(L_ERROR, "Unable to open \"/dev/null\" - %s.", strerror(errno)); | |
1996 | snprintf(printer->state_message, sizeof(printer->state_message), | |
1997 | "Unable to open \"/dev/null\" - %s.", strerror(errno)); | |
1998 | ||
1999 | AddPrinterHistory(printer); | |
2000 | ||
2001 | if (filters != NULL) | |
2002 | free(filters); | |
2003 | ||
8650fcf2 | 2004 | cupsdClosePipe(statusfds); |
db3c5bfd | 2005 | CancelJob(current->id, 0); |
2006 | return; | |
2007 | } | |
2008 | ||
2009 | fcntl(filterfds[1][0], F_SETFD, fcntl(filterfds[1][0], F_GETFD) | FD_CLOEXEC); | |
2010 | ||
18fe941f | 2011 | LogMessage(L_DEBUG, "StartJob: filterfds[%d] = [ %d %d ]", 1, filterfds[1][0], |
93336dbc | 2012 | filterfds[1][1]); |
bfa1abf0 | 2013 | |
db911fcb | 2014 | for (i = 0, slot = 0; i < num_filters; i ++) |
e63d9801 | 2015 | { |
e63d9801 | 2016 | if (filters[i].filter[0] != '/') |
a6988fb1 | 2017 | snprintf(command, sizeof(command), "%s/filter/%s", ServerBin, |
2018 | filters[i].filter); | |
e63d9801 | 2019 | else |
def978d5 | 2020 | strlcpy(command, filters[i].filter, sizeof(command)); |
6abc7437 | 2021 | |
cc6d5b1e | 2022 | #ifdef __APPLE__ |
2023 | /* | |
2024 | * Setting CFProcessPath lets OS X's Core Foundation code find | |
2025 | * the bundle that may be associated with a filter or backend. | |
2026 | */ | |
2027 | ||
2028 | snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", command); | |
2029 | LogMessage(L_DEBUG, "StartJob: %s\n", processPath); | |
2030 | #endif /* __APPLE__ */ | |
2031 | ||
a2fc3d31 | 2032 | if (i < (num_filters - 1)) |
8650fcf2 | 2033 | { |
2034 | if (cupsdOpenPipe(filterfds[slot])) | |
2035 | { | |
2036 | LogMessage(L_ERROR, "Unable to create job filter pipes - %s.", | |
2037 | strerror(errno)); | |
2038 | snprintf(printer->state_message, sizeof(printer->state_message), | |
2039 | "Unable to create filter pipes - %s.", strerror(errno)); | |
2040 | AddPrinterHistory(printer); | |
2041 | ||
2042 | if (filters != NULL) | |
2043 | free(filters); | |
2044 | ||
2045 | cupsdClosePipe(statusfds); | |
2046 | cupsdClosePipe(filterfds[!slot]); | |
2047 | CancelJob(current->id, 0); | |
2048 | return; | |
2049 | } | |
2050 | } | |
e63d9801 | 2051 | else |
2052 | { | |
18fe941f | 2053 | if (current->current_file == 1) |
a2fc3d31 | 2054 | { |
2055 | if (strncmp(printer->device_uri, "file:", 5) != 0) | |
8650fcf2 | 2056 | { |
2057 | if (cupsdOpenPipe(current->print_pipes)) | |
2058 | { | |
2059 | LogMessage(L_ERROR, "Unable to create job filter pipes - %s.", | |
2060 | strerror(errno)); | |
2061 | snprintf(printer->state_message, sizeof(printer->state_message), | |
2062 | "Unable to create filter pipes - %s.", strerror(errno)); | |
2063 | AddPrinterHistory(printer); | |
2064 | ||
2065 | if (filters != NULL) | |
2066 | free(filters); | |
2067 | ||
2068 | cupsdClosePipe(statusfds); | |
2069 | cupsdClosePipe(filterfds[!slot]); | |
2070 | CancelJob(current->id, 0); | |
2071 | return; | |
2072 | } | |
2073 | } | |
a2fc3d31 | 2074 | else |
2075 | { | |
2076 | current->print_pipes[0] = -1; | |
e6df8a90 | 2077 | if (!strncmp(printer->device_uri, "file:/dev/", 10) && |
2078 | strcmp(printer->device_uri, "file:/dev/null")) | |
a2fc3d31 | 2079 | current->print_pipes[1] = open(printer->device_uri + 5, |
2080 | O_WRONLY | O_EXCL); | |
e6df8a90 | 2081 | else if (!strncmp(printer->device_uri, "file:///dev/", 12) && |
2082 | strcmp(printer->device_uri, "file:///dev/null")) | |
2083 | current->print_pipes[1] = open(printer->device_uri + 7, | |
2084 | O_WRONLY | O_EXCL); | |
a2fc3d31 | 2085 | else |
2086 | current->print_pipes[1] = open(printer->device_uri + 5, | |
2087 | O_WRONLY | O_CREAT | O_TRUNC, 0600); | |
18fe941f | 2088 | |
db3c5bfd | 2089 | if (current->print_pipes[1] < 0) |
2090 | { | |
2091 | LogMessage(L_ERROR, "Unable to open output file \"%s\" - %s.", | |
2092 | printer->device_uri, strerror(errno)); | |
2093 | snprintf(printer->state_message, sizeof(printer->state_message), | |
2094 | "Unable to open output file \"%s\" - %s.", | |
2095 | printer->device_uri, strerror(errno)); | |
2096 | ||
2097 | AddPrinterHistory(printer); | |
2098 | ||
2099 | if (filters != NULL) | |
2100 | free(filters); | |
2101 | ||
8650fcf2 | 2102 | cupsdClosePipe(statusfds); |
2103 | cupsdClosePipe(filterfds[!slot]); | |
db3c5bfd | 2104 | CancelJob(current->id, 0); |
2105 | return; | |
2106 | } | |
2107 | ||
2108 | fcntl(current->print_pipes[1], F_SETFD, | |
2109 | fcntl(current->print_pipes[1], F_GETFD) | FD_CLOEXEC); | |
2110 | } | |
e6df8a90 | 2111 | |
18fe941f | 2112 | LogMessage(L_DEBUG2, "StartJob: print_pipes = [ %d %d ]", |
2113 | current->print_pipes[0], current->print_pipes[1]); | |
a2fc3d31 | 2114 | } |
2115 | ||
2116 | filterfds[slot][0] = current->print_pipes[0]; | |
2117 | filterfds[slot][1] = current->print_pipes[1]; | |
e63d9801 | 2118 | } |
6abc7437 | 2119 | |
d87b2fe0 | 2120 | LogMessage(L_DEBUG, "StartJob: filter = \"%s\"", command); |
18fe941f | 2121 | LogMessage(L_DEBUG, "StartJob: filterfds[%d] = [ %d %d ]", |
db911fcb | 2122 | slot, filterfds[slot][0], filterfds[slot][1]); |
6abc7437 | 2123 | |
db911fcb | 2124 | pid = start_process(command, argv, envp, filterfds[!slot][0], |
a2fc3d31 | 2125 | filterfds[slot][1], statusfds[1], |
5c8eff27 | 2126 | current->back_pipes[0], 0, current->filters + i); |
6abc7437 | 2127 | |
18fe941f | 2128 | LogMessage(L_DEBUG2, "StartJob: Closing filter pipes for slot %d [ %d %d ]...", |
2129 | !slot, filterfds[!slot][0], filterfds[!slot][1]); | |
2130 | ||
8650fcf2 | 2131 | cupsdClosePipe(filterfds[!slot]); |
6abc7437 | 2132 | |
e63d9801 | 2133 | if (pid == 0) |
2134 | { | |
5ea8888e | 2135 | LogMessage(L_ERROR, "Unable to start filter \"%s\" - %s.", |
4621b86f | 2136 | filters[i].filter, strerror(errno)); |
a6988fb1 | 2137 | snprintf(printer->state_message, sizeof(printer->state_message), |
2138 | "Unable to start filter \"%s\" - %s.", | |
2139 | filters[i].filter, strerror(errno)); | |
a5ba1d82 | 2140 | |
c8a55d2c | 2141 | AddPrinterHistory(printer); |
2142 | ||
a5ba1d82 | 2143 | if (filters != NULL) |
2144 | free(filters); | |
2145 | ||
c8a55d2c | 2146 | AddPrinterHistory(printer); |
2147 | ||
a5ba1d82 | 2148 | CancelJob(current->id, 0); |
e63d9801 | 2149 | return; |
2150 | } | |
6abc7437 | 2151 | |
db911fcb | 2152 | LogMessage(L_INFO, "Started filter %s (PID %d) for job %d.", |
2153 | command, pid, current->id); | |
2154 | ||
2155 | argv[6] = NULL; | |
2156 | slot = !slot; | |
e63d9801 | 2157 | } |
6abc7437 | 2158 | |
e63d9801 | 2159 | if (filters != NULL) |
2160 | free(filters); | |
bfa1abf0 | 2161 | |
e63d9801 | 2162 | /* |
2163 | * Finally, pipe the final output into a backend process if needed... | |
2164 | */ | |
6abc7437 | 2165 | |
e63d9801 | 2166 | if (strncmp(printer->device_uri, "file:", 5) != 0) |
2167 | { | |
18fe941f | 2168 | if (current->current_file == 1) |
a2fc3d31 | 2169 | { |
2170 | sscanf(printer->device_uri, "%254[^:]", method); | |
2171 | snprintf(command, sizeof(command), "%s/backend/%s", ServerBin, method); | |
e31bfb6e | 2172 | |
cc6d5b1e | 2173 | #ifdef __APPLE__ |
2174 | /* | |
2175 | * Setting CFProcessPath lets OS X's Core Foundation code find | |
2176 | * the bundle that may be associated with a filter or backend. | |
2177 | */ | |
2178 | ||
2179 | snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", command); | |
2180 | LogMessage(L_DEBUG, "StartJob: %s\n", processPath); | |
2181 | #endif /* __APPLE__ */ | |
2182 | ||
18157eca | 2183 | argv[0] = sani_uri; |
e31bfb6e | 2184 | |
a2fc3d31 | 2185 | filterfds[slot][0] = -1; |
2186 | filterfds[slot][1] = open("/dev/null", O_WRONLY); | |
e31bfb6e | 2187 | |
db3c5bfd | 2188 | if (filterfds[slot][1] < 0) |
2189 | { | |
2190 | LogMessage(L_ERROR, "Unable to open \"/dev/null\" - %s.", strerror(errno)); | |
2191 | snprintf(printer->state_message, sizeof(printer->state_message), | |
2192 | "Unable to open \"/dev/null\" - %s.", strerror(errno)); | |
2193 | ||
2194 | AddPrinterHistory(printer); | |
2195 | ||
2196 | if (filters != NULL) | |
2197 | free(filters); | |
2198 | ||
8650fcf2 | 2199 | cupsdClosePipe(statusfds); |
db3c5bfd | 2200 | CancelJob(current->id, 0); |
2201 | return; | |
2202 | } | |
2203 | ||
2204 | fcntl(filterfds[slot][1], F_SETFD, | |
2205 | fcntl(filterfds[slot][1], F_GETFD) | FD_CLOEXEC); | |
2206 | ||
a2fc3d31 | 2207 | LogMessage(L_DEBUG, "StartJob: backend = \"%s\"", command); |
18fe941f | 2208 | LogMessage(L_DEBUG, "StartJob: filterfds[%d] = [ %d %d ]", |
a2fc3d31 | 2209 | slot, filterfds[slot][0], filterfds[slot][1]); |
e31bfb6e | 2210 | |
a2fc3d31 | 2211 | pid = start_process(command, argv, envp, filterfds[!slot][0], |
2212 | filterfds[slot][1], statusfds[1], | |
5c8eff27 | 2213 | current->back_pipes[1], 1, |
2214 | &(current->backend)); | |
e31bfb6e | 2215 | |
a2fc3d31 | 2216 | if (pid == 0) |
2217 | { | |
2218 | LogMessage(L_ERROR, "Unable to start backend \"%s\" - %s.", | |
2219 | method, strerror(errno)); | |
2220 | snprintf(printer->state_message, sizeof(printer->state_message), | |
2221 | "Unable to start backend \"%s\" - %s.", method, strerror(errno)); | |
e31bfb6e | 2222 | |
6cd03542 | 2223 | LogMessage(L_DEBUG2, "StartJob: Closing print pipes [ %d %d ]...", |
2224 | current->print_pipes[0], current->print_pipes[1]); | |
2225 | ||
8650fcf2 | 2226 | cupsdClosePipe(current->print_pipes); |
a2fc3d31 | 2227 | |
6cd03542 | 2228 | LogMessage(L_DEBUG2, "StartJob: Closing back pipes [ %d %d ]...", |
2229 | current->back_pipes[0], current->back_pipes[1]); | |
2230 | ||
8650fcf2 | 2231 | cupsdClosePipe(current->back_pipes); |
6cd03542 | 2232 | |
a5ba1d82 | 2233 | CancelJob(current->id, 0); |
a2fc3d31 | 2234 | return; |
2235 | } | |
2236 | else | |
2237 | { | |
5c8eff27 | 2238 | LogMessage(L_INFO, "Started backend %s (PID %d) for job %d.", |
2239 | command, pid, current->id); | |
a2fc3d31 | 2240 | } |
e63d9801 | 2241 | } |
a2fc3d31 | 2242 | |
6cd03542 | 2243 | if (current->current_file == current->num_files) |
e63d9801 | 2244 | { |
6cd03542 | 2245 | LogMessage(L_DEBUG2, "StartJob: Closing print pipes [ %d %d ]...", |
2246 | current->print_pipes[0], current->print_pipes[1]); | |
2247 | ||
8650fcf2 | 2248 | cupsdClosePipe(current->print_pipes); |
a2fc3d31 | 2249 | |
6cd03542 | 2250 | LogMessage(L_DEBUG2, "StartJob: Closing back pipes [ %d %d ]...", |
2251 | current->back_pipes[0], current->back_pipes[1]); | |
2252 | ||
8650fcf2 | 2253 | cupsdClosePipe(current->back_pipes); |
e63d9801 | 2254 | } |
2255 | } | |
2256 | else | |
2257 | { | |
db911fcb | 2258 | filterfds[slot][0] = -1; |
2259 | filterfds[slot][1] = -1; | |
bfa1abf0 | 2260 | |
6cd03542 | 2261 | if (current->current_file == current->num_files) |
a2fc3d31 | 2262 | { |
18fe941f | 2263 | LogMessage(L_DEBUG2, "StartJob: Closing print pipes [ %d %d ]...", |
2264 | current->print_pipes[0], current->print_pipes[1]); | |
2265 | ||
8650fcf2 | 2266 | cupsdClosePipe(current->print_pipes); |
a2fc3d31 | 2267 | } |
e63d9801 | 2268 | } |
bfa1abf0 | 2269 | |
18fe941f | 2270 | LogMessage(L_DEBUG2, "StartJob: Closing filter pipes for slot %d [ %d %d ]...", |
2271 | slot, filterfds[slot][0], filterfds[slot][1]); | |
2272 | ||
8650fcf2 | 2273 | cupsdClosePipe(filterfds[slot]); |
6abc7437 | 2274 | |
18fe941f | 2275 | LogMessage(L_DEBUG2, "StartJob: Closing status output pipe %d...", |
2276 | statusfds[1]); | |
2277 | ||
e63d9801 | 2278 | close(statusfds[1]); |
6abc7437 | 2279 | |
a2fc3d31 | 2280 | LogMessage(L_DEBUG2, "StartJob: Adding fd %d to InputSet...", |
294f4cee | 2281 | current->status_buffer->fd); |
99de6da0 | 2282 | |
294f4cee | 2283 | FD_SET(current->status_buffer->fd, InputSet); |
a9de544f | 2284 | } |
2285 | ||
2286 | ||
bd84e0d1 | 2287 | /* |
2288 | * 'StopAllJobs()' - Stop all print jobs. | |
2289 | */ | |
2290 | ||
2291 | void | |
2292 | StopAllJobs(void) | |
2293 | { | |
017c50f3 | 2294 | job_t *current; /* Current job */ |
1049abbe | 2295 | |
2296 | ||
c0521f33 | 2297 | DEBUG_puts("StopAllJobs()"); |
1049abbe | 2298 | |
2299 | for (current = Jobs; current != NULL; current = current->next) | |
2300 | if (current->state->values[0].integer == IPP_JOB_PROCESSING) | |
2301 | { | |
db911fcb | 2302 | StopJob(current->id, 1); |
1049abbe | 2303 | current->state->values[0].integer = IPP_JOB_PENDING; |
2304 | } | |
bd84e0d1 | 2305 | } |
2306 | ||
2307 | ||
93894a43 | 2308 | /* |
2309 | * 'StopJob()' - Stop a print job. | |
2310 | */ | |
2311 | ||
a9de544f | 2312 | void |
017c50f3 | 2313 | StopJob(int id, /* I - Job ID */ |
2314 | int force) /* I - 1 = Force all filters to stop */ | |
a9de544f | 2315 | { |
017c50f3 | 2316 | int i; /* Looping var */ |
2317 | job_t *current; /* Current job */ | |
a9de544f | 2318 | |
2319 | ||
db911fcb | 2320 | LogMessage(L_DEBUG, "StopJob: id = %d, force = %d", id, force); |
6abc7437 | 2321 | |
93894a43 | 2322 | for (current = Jobs; current != NULL; current = current->next) |
2323 | if (current->id == id) | |
a9de544f | 2324 | { |
6abc7437 | 2325 | DEBUG_puts("StopJob: found job in list."); |
2326 | ||
1049abbe | 2327 | if (current->state->values[0].integer == IPP_JOB_PROCESSING) |
a9de544f | 2328 | { |
6abc7437 | 2329 | DEBUG_puts("StopJob: job state is \'processing\'."); |
2330 | ||
8239f206 | 2331 | FilterLevel -= current->cost; |
2332 | ||
997cf8b0 | 2333 | if (current->status < 0 && |
f49663d5 | 2334 | !(current->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) && |
2335 | !(current->printer->type & CUPS_PRINTER_FAX)) | |
aa3b74e1 | 2336 | SetPrinterState(current->printer, IPP_PRINTER_STOPPED, 1); |
b5cb0608 | 2337 | else if (current->printer->state != IPP_PRINTER_STOPPED) |
aa3b74e1 | 2338 | SetPrinterState(current->printer, IPP_PRINTER_IDLE, 0); |
553ce970 | 2339 | |
d87b2fe0 | 2340 | LogMessage(L_DEBUG, "StopJob: printer state is %d", current->printer->state); |
e09246c8 | 2341 | |
1049abbe | 2342 | current->state->values[0].integer = IPP_JOB_STOPPED; |
ccd04319 | 2343 | current->printer->job = NULL; |
2344 | current->printer = NULL; | |
a9de544f | 2345 | |
1049abbe | 2346 | current->current_file --; |
2347 | ||
a2fc3d31 | 2348 | for (i = 0; current->filters[i]; i ++) |
2349 | if (current->filters[i] > 0) | |
ccd04319 | 2350 | { |
a2fc3d31 | 2351 | kill(current->filters[i], force ? SIGKILL : SIGTERM); |
2352 | current->filters[i] = 0; | |
ccd04319 | 2353 | } |
882031b3 | 2354 | |
a2fc3d31 | 2355 | if (current->backend > 0) |
2356 | { | |
2357 | kill(current->backend, force ? SIGKILL : SIGTERM); | |
2358 | current->backend = 0; | |
2359 | } | |
2360 | ||
6cd03542 | 2361 | LogMessage(L_DEBUG2, "StopJob: Closing print pipes [ %d %d ]...", |
2362 | current->print_pipes[0], current->print_pipes[1]); | |
2363 | ||
8650fcf2 | 2364 | cupsdClosePipe(current->print_pipes); |
a2fc3d31 | 2365 | |
6cd03542 | 2366 | LogMessage(L_DEBUG2, "StopJob: Closing back pipes [ %d %d ]...", |
2367 | current->back_pipes[0], current->back_pipes[1]); | |
2368 | ||
8650fcf2 | 2369 | cupsdClosePipe(current->back_pipes); |
a2fc3d31 | 2370 | |
294f4cee | 2371 | if (current->status_buffer) |
882031b3 | 2372 | { |
8d5e3b76 | 2373 | /* |
2374 | * Close the pipe and clear the input bit. | |
2375 | */ | |
2376 | ||
db911fcb | 2377 | LogMessage(L_DEBUG2, "StopJob: Removing fd %d from InputSet...", |
294f4cee | 2378 | current->status_buffer->fd); |
db911fcb | 2379 | |
294f4cee | 2380 | FD_CLR(current->status_buffer->fd, InputSet); |
db911fcb | 2381 | |
294f4cee | 2382 | LogMessage(L_DEBUG2, "StopJob: Closing status input pipe %d...", |
2383 | current->status_buffer->fd); | |
db911fcb | 2384 | |
294f4cee | 2385 | cupsdStatBufDelete(current->status_buffer); |
db911fcb | 2386 | |
294f4cee | 2387 | current->status_buffer = NULL; |
2388 | } | |
a9de544f | 2389 | } |
93894a43 | 2390 | return; |
a9de544f | 2391 | } |
a9de544f | 2392 | } |
2d7cba2b | 2393 | |
2394 | ||
2395 | /* | |
6abc7437 | 2396 | * 'UpdateJob()' - Read a status update from a job's filters. |
2397 | */ | |
2398 | ||
2399 | void | |
017c50f3 | 2400 | UpdateJob(job_t *job) /* I - Job to check */ |
6abc7437 | 2401 | { |
017c50f3 | 2402 | int i; /* Looping var */ |
017c50f3 | 2403 | int copies; /* Number of copies printed */ |
294f4cee | 2404 | char message[1024], /* Message text */ |
2405 | *ptr; /* Pointer update... */ | |
017c50f3 | 2406 | int loglevel; /* Log level for message */ |
96df88bb | 2407 | |
6abc7437 | 2408 | |
294f4cee | 2409 | while ((ptr = cupsdStatBufUpdate(job->status_buffer, &loglevel, |
2410 | message, sizeof(message))) != NULL) | |
ea315b09 | 2411 | { |
2412 | /* | |
294f4cee | 2413 | * Process page and printer state messages as needed... |
ea315b09 | 2414 | */ |
96df88bb | 2415 | |
ea315b09 | 2416 | if (loglevel == L_PAGE) |
2417 | { | |
c7fa9d06 | 2418 | /* |
aa0cb334 | 2419 | * Page message; send the message to the page_log file and update the |
2420 | * job sheet count... | |
c7fa9d06 | 2421 | */ |
2422 | ||
ad2b0c5f | 2423 | if (job->sheets != NULL) |
2424 | { | |
8f4595eb | 2425 | if (!strncasecmp(message, "total ", 6)) |
b521f3fc | 2426 | { |
8f4595eb | 2427 | /* |
2428 | * Got a total count of pages from a backend or filter... | |
2429 | */ | |
b521f3fc | 2430 | |
8f4595eb | 2431 | copies = atoi(message + 6); |
2432 | copies -= job->sheets->values[0].integer; /* Just track the delta */ | |
2433 | } | |
2434 | else if (!sscanf(message, "%*d%d", &copies)) | |
2435 | copies = 1; | |
2436 | ||
2437 | job->sheets->values[0].integer += copies; | |
b521f3fc | 2438 | |
8f4595eb | 2439 | if (job->printer->page_limit) |
2440 | UpdateQuota(job->printer, job->username, copies, 0); | |
ad2b0c5f | 2441 | } |
aa0cb334 | 2442 | |
ea315b09 | 2443 | LogPage(job, message); |
2444 | } | |
62bcac22 | 2445 | else if (loglevel == L_STATE) |
2446 | SetPrinterReasons(job->printer, message); | |
96df88bb | 2447 | |
294f4cee | 2448 | if (!strchr(job->status_buffer->buffer, '\n')) |
2449 | break; | |
96df88bb | 2450 | } |
ea315b09 | 2451 | |
294f4cee | 2452 | if (ptr == NULL) |
6abc7437 | 2453 | { |
d89de04a | 2454 | /* |
2455 | * See if all of the filters and the backend have returned their | |
2456 | * exit statuses. | |
2457 | */ | |
2458 | ||
017c50f3 | 2459 | for (i = 0; job->filters[i] < 0; i ++); |
2460 | ||
2461 | if (job->filters[i]) | |
2462 | return; | |
d89de04a | 2463 | |
2464 | if (job->current_file >= job->num_files && job->backend > 0) | |
2465 | return; | |
2466 | ||
2467 | /* | |
2468 | * Handle the end of job stuff... | |
2469 | */ | |
2470 | ||
017c50f3 | 2471 | FinishJob(job); |
6abc7437 | 2472 | } |
2473 | } | |
2474 | ||
2475 | ||
ad717326 | 2476 | /* |
2477 | * 'ipp_length()' - Compute the size of the buffer needed to hold | |
2478 | * the textual IPP attributes. | |
2479 | */ | |
2480 | ||
017c50f3 | 2481 | int /* O - Size of buffer to hold IPP attributes */ |
2482 | ipp_length(ipp_t *ipp) /* I - IPP request */ | |
ad717326 | 2483 | { |
017c50f3 | 2484 | int bytes; /* Number of bytes */ |
2485 | int i; /* Looping var */ | |
2486 | ipp_attribute_t *attr; /* Current attribute */ | |
ad717326 | 2487 | |
2488 | ||
2489 | /* | |
2490 | * Loop through all attributes... | |
2491 | */ | |
2492 | ||
2493 | bytes = 0; | |
2494 | ||
2495 | for (attr = ipp->attrs; attr != NULL; attr = attr->next) | |
2496 | { | |
2497 | /* | |
2498 | * Skip attributes that won't be sent to filters... | |
2499 | */ | |
2500 | ||
2501 | if (attr->value_tag == IPP_TAG_MIMETYPE || | |
2502 | attr->value_tag == IPP_TAG_NAMELANG || | |
2503 | attr->value_tag == IPP_TAG_TEXTLANG || | |
2504 | attr->value_tag == IPP_TAG_URI || | |
2505 | attr->value_tag == IPP_TAG_URISCHEME) | |
2506 | continue; | |
2507 | ||
2508 | if (strncmp(attr->name, "time-", 5) == 0) | |
2509 | continue; | |
2510 | ||
2511 | /* | |
2512 | * Add space for a leading space and commas between each value. | |
2513 | * For the first attribute, the leading space isn't used, so the | |
2514 | * extra byte can be used as the nul terminator... | |
2515 | */ | |
2516 | ||
2517 | bytes ++; /* " " separator */ | |
2518 | bytes += attr->num_values; /* "," separators */ | |
2519 | ||
2520 | /* | |
2521 | * Boolean attributes appear as "foo,nofoo,foo,nofoo", while | |
2522 | * other attributes appear as "foo=value1,value2,...,valueN". | |
2523 | */ | |
2524 | ||
2525 | if (attr->value_tag != IPP_TAG_BOOLEAN) | |
2526 | bytes += strlen(attr->name); | |
2527 | else | |
2528 | bytes += attr->num_values * strlen(attr->name); | |
2529 | ||
2530 | /* | |
2531 | * Now add the size required for each value in the attribute... | |
2532 | */ | |
2533 | ||
2534 | switch (attr->value_tag) | |
2535 | { | |
2536 | case IPP_TAG_INTEGER : | |
2537 | case IPP_TAG_ENUM : | |
2538 | /* | |
2539 | * Minimum value of a signed integer is -2147483647, or 11 digits. | |
2540 | */ | |
2541 | ||
2542 | bytes += attr->num_values * 11; | |
2543 | break; | |
2544 | ||
2545 | case IPP_TAG_BOOLEAN : | |
2546 | /* | |
2547 | * Add two bytes for each false ("no") value... | |
2548 | */ | |
2549 | ||
2550 | for (i = 0; i < attr->num_values; i ++) | |
2551 | if (!attr->values[i].boolean) | |
2552 | bytes += 2; | |
2553 | break; | |
2554 | ||
2555 | case IPP_TAG_RANGE : | |
2556 | /* | |
2557 | * A range is two signed integers separated by a hyphen, or | |
2558 | * 23 characters max. | |
2559 | */ | |
2560 | ||
2561 | bytes += attr->num_values * 23; | |
2562 | break; | |
2563 | ||
2564 | case IPP_TAG_RESOLUTION : | |
2565 | /* | |
2566 | * A resolution is two signed integers separated by an "x" and | |
2567 | * suffixed by the units, or 26 characters max. | |
2568 | */ | |
2569 | ||
2570 | bytes += attr->num_values * 26; | |
2571 | break; | |
2572 | ||
2573 | case IPP_TAG_STRING : | |
2574 | case IPP_TAG_TEXT : | |
2575 | case IPP_TAG_NAME : | |
2576 | case IPP_TAG_KEYWORD : | |
2577 | case IPP_TAG_CHARSET : | |
2578 | case IPP_TAG_LANGUAGE : | |
2579 | /* | |
2580 | * Strings can contain characters that need quoting. We need | |
2581 | * at least 2 * len + 2 characters to cover the quotes and | |
2582 | * any backslashes in the string. | |
2583 | */ | |
2584 | ||
2585 | for (i = 0; i < attr->num_values; i ++) | |
2586 | bytes += 2 * strlen(attr->values[i].string.text) + 2; | |
2587 | break; | |
2588 | ||
2589 | default : | |
2590 | break; /* anti-compiler-warning-code */ | |
2591 | } | |
2592 | } | |
2593 | ||
2594 | return (bytes); | |
2595 | } | |
2596 | ||
2597 | ||
7ebf3a09 | 2598 | /* |
0ccccc99 | 2599 | * 'set_time()' - Set one of the "time-at-xyz" attributes... |
7ebf3a09 | 2600 | */ |
2601 | ||
2602 | static void | |
2603 | set_time(job_t *job, /* I - Job to update */ | |
2604 | const char *name) /* I - Name of attribute */ | |
2605 | { | |
2606 | ipp_attribute_t *attr; /* Time attribute */ | |
2607 | ||
2608 | ||
0ccccc99 | 2609 | if ((attr = ippFindAttribute(job->attrs, name, IPP_TAG_ZERO)) != NULL) |
7ebf3a09 | 2610 | { |
0ccccc99 | 2611 | attr->value_tag = IPP_TAG_INTEGER; |
2612 | attr->values[0].integer = time(NULL); | |
7ebf3a09 | 2613 | } |
7ebf3a09 | 2614 | } |
2615 | ||
2616 | ||
6abc7437 | 2617 | /* |
bfa1abf0 | 2618 | * 'start_process()' - Start a background process. |
2619 | */ | |
2620 | ||
bd84e0d1 | 2621 | static int /* O - Process ID or 0 */ |
2622 | start_process(const char *command, /* I - Full path to command */ | |
e09246c8 | 2623 | char *argv[], /* I - Command-line arguments */ |
2624 | char *envp[], /* I - Environment */ | |
bd84e0d1 | 2625 | int infd, /* I - Standard input file descriptor */ |
2626 | int outfd, /* I - Standard output file descriptor */ | |
5d99df62 | 2627 | int errfd, /* I - Standard error file descriptor */ |
a2fc3d31 | 2628 | int backfd, /* I - Backchannel file descriptor */ |
5c8eff27 | 2629 | int root, /* I - Run as root? */ |
2630 | int *pid) /* O - Process ID */ | |
bfa1abf0 | 2631 | { |
879062a9 | 2632 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) |
c7a9d594 | 2633 | struct sigaction action; /* POSIX signal handler */ |
879062a9 | 2634 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ |
bfa1abf0 | 2635 | |
2636 | ||
aa7e125a | 2637 | LogMessage(L_DEBUG, "start_process(\"%s\", %p, %p, %d, %d, %d)", |
4f954c4e | 2638 | command, argv, envp, infd, outfd, errfd); |
bfa1abf0 | 2639 | |
879062a9 | 2640 | /* |
2641 | * Block signals before forking... | |
2642 | */ | |
2643 | ||
38743560 | 2644 | HoldSignals(); |
4d520ad4 | 2645 | |
5c8eff27 | 2646 | if ((*pid = fork()) == 0) |
bfa1abf0 | 2647 | { |
2648 | /* | |
2649 | * Child process goes here... | |
2650 | * | |
2651 | * Update stdin/stdout/stderr as needed... | |
2652 | */ | |
2653 | ||
2654 | close(0); | |
2655 | dup(infd); | |
2656 | close(1); | |
2657 | dup(outfd); | |
2658 | if (errfd > 2) | |
2659 | { | |
2660 | close(2); | |
2661 | dup(errfd); | |
2662 | } | |
a2fc3d31 | 2663 | if (backfd > 3) |
2664 | { | |
2665 | close(3); | |
2666 | dup(backfd); | |
2667 | fcntl(3, F_SETFL, O_NDELAY); | |
2668 | } | |
bfa1abf0 | 2669 | |
42ede8a2 | 2670 | /* |
2671 | * Change the priority of the process based on the FilterNice setting. | |
2672 | * (this is not done for backends...) | |
2673 | */ | |
2674 | ||
2675 | if (!root) | |
2676 | nice(FilterNice); | |
2677 | ||
bfa1abf0 | 2678 | /* |
2679 | * Change user to something "safe"... | |
2680 | */ | |
2681 | ||
48033118 | 2682 | if (!root && !RunUser) |
5d99df62 | 2683 | { |
5aeb433c | 2684 | /* |
2685 | * Running as root, so change to non-priviledged user... | |
2686 | */ | |
2687 | ||
2688 | if (setgid(Group)) | |
2689 | exit(errno); | |
2690 | ||
4342fddc | 2691 | if (setgroups(1, &Group)) |
daf8f5f0 | 2692 | exit(errno); |
2693 | ||
5aeb433c | 2694 | if (setuid(User)) |
2695 | exit(errno); | |
5d99df62 | 2696 | } |
8914cc4b | 2697 | else |
2698 | { | |
2699 | /* | |
2700 | * Reset group membership to just the main one we belong to. | |
2701 | */ | |
bfa1abf0 | 2702 | |
4342fddc | 2703 | setgroups(1, &Group); |
8914cc4b | 2704 | } |
5aeb433c | 2705 | |
082b40d2 | 2706 | /* |
2707 | * Change umask to restrict permissions on created files... | |
2708 | */ | |
2709 | ||
2710 | umask(077); | |
2711 | ||
5f152161 | 2712 | /* |
2713 | * Unblock signals before doing the exec... | |
2714 | */ | |
2715 | ||
2716 | #ifdef HAVE_SIGSET | |
c7a9d594 | 2717 | sigset(SIGTERM, SIG_DFL); |
2718 | sigset(SIGCHLD, SIG_DFL); | |
5f152161 | 2719 | #elif defined(HAVE_SIGACTION) |
c7a9d594 | 2720 | memset(&action, 0, sizeof(action)); |
2721 | ||
2722 | sigemptyset(&action.sa_mask); | |
2723 | action.sa_handler = SIG_DFL; | |
2724 | ||
2725 | sigaction(SIGTERM, &action, NULL); | |
38743560 | 2726 | sigaction(SIGCHLD, &action, NULL); |
c7a9d594 | 2727 | #else |
2728 | signal(SIGTERM, SIG_DFL); | |
38743560 | 2729 | signal(SIGCHLD, SIG_DFL); |
5f152161 | 2730 | #endif /* HAVE_SIGSET */ |
2731 | ||
38743560 | 2732 | ReleaseSignals(); |
2733 | ||
bfa1abf0 | 2734 | /* |
2735 | * Execute the command; if for some reason this doesn't work, | |
2736 | * return the error code... | |
2737 | */ | |
2738 | ||
2739 | execve(command, argv, envp); | |
2740 | ||
5d99df62 | 2741 | perror(command); |
bfa1abf0 | 2742 | |
2743 | exit(errno); | |
2744 | } | |
5c8eff27 | 2745 | else if (*pid < 0) |
bfa1abf0 | 2746 | { |
2747 | /* | |
2748 | * Error - couldn't fork a new process! | |
2749 | */ | |
2750 | ||
d87b2fe0 | 2751 | LogMessage(L_ERROR, "Unable to fork %s - %s.", command, strerror(errno)); |
bfa1abf0 | 2752 | |
5c8eff27 | 2753 | *pid = 0; |
bfa1abf0 | 2754 | } |
2755 | ||
38743560 | 2756 | ReleaseSignals(); |
4d520ad4 | 2757 | |
5c8eff27 | 2758 | return (*pid); |
bfa1abf0 | 2759 | } |
2760 | ||
2761 | ||
2762 | /* | |
225b3683 | 2763 | * 'set_hold_until()' - Set the hold time and update job-hold-until attribute... |
2764 | */ | |
2765 | ||
2766 | static void | |
2767 | set_hold_until(job_t *job, /* I - Job to update */ | |
2768 | time_t holdtime) /* I - Hold until time */ | |
2769 | { | |
2770 | ipp_attribute_t *attr; /* job-hold-until attribute */ | |
2771 | struct tm *holddate; /* Hold date */ | |
2772 | char holdstr[64]; /* Hold time */ | |
2773 | ||
2774 | ||
2775 | /* | |
2776 | * Set the hold_until value and hold the job... | |
2777 | */ | |
2778 | ||
2779 | LogMessage(L_DEBUG, "set_hold_until: hold_until = %d", (int)holdtime); | |
2780 | ||
2781 | job->state->values[0].integer = IPP_JOB_HELD; | |
2782 | job->hold_until = holdtime; | |
2783 | ||
2784 | /* | |
2785 | * Update the job-hold-until attribute with a string representing GMT | |
2786 | * time (HH:MM:SS)... | |
2787 | */ | |
2788 | ||
2789 | holddate = gmtime(&holdtime); | |
2790 | snprintf(holdstr, sizeof(holdstr), "%d:%d:%d", holddate->tm_hour, | |
2791 | holddate->tm_min, holddate->tm_sec); | |
2792 | ||
2793 | if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL) | |
2794 | attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME); | |
2795 | ||
2796 | /* | |
2797 | * Either add the attribute or update the value of the existing one | |
2798 | */ | |
2799 | ||
2800 | if (attr == NULL) | |
2801 | attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD, | |
2802 | "job-hold-until", NULL, holdstr); | |
2803 | else | |
2804 | SetString(&attr->values[0].string.text, holdstr); | |
2805 | ||
2806 | SaveJob(job->id); | |
2807 | } | |
2808 | ||
2809 | ||
2810 | /* | |
34089ee8 | 2811 | * End of "$Id: job.c,v 1.124.2.99 2004/12/16 20:03:22 mike Exp $". |
2d7cba2b | 2812 | */ |