]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/job.c
Sync changes and files from 1.1.x.
[thirdparty/cups.git] / scheduler / job.c
CommitLineData
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
70static 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 83static int ipp_length(ipp_t *ipp);
7ebf3a09 84static void set_time(job_t *job, const char *name);
e09246c8 85static 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 89static 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 96job_t * /* O - New job record */
97AddJob(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 138void
017c50f3 139CancelJob(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(&current->username);
223 ClearString(&current->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 239void
b07e0cc2 240CancelJobs(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
274void
275CheckJobs(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
370void
371CleanJobs(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
394void
395FinishJob(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
529void
530FreeAllJobs(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 565job_t * /* O - Job data */
566FindJob(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
584int /* O - Job count */
585GetPrinterJobCount(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
605int /* O - Job count */
606GetUserJobCount(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
625void
017c50f3 626HoldJob(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
653void
654LoadAllJobs(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 971void
017c50f3 972MoveJob(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(&current->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
1013void
017c50f3 1014ReleaseJob(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
1039void
017c50f3 1040RestartJob(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
1062void
017c50f3 1063SaveJob(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
1097void
1098SetJobHoldUntil(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
1235void
017c50f3 1236SetJobPriority(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 1308void
dd63ebe2 1309StartJob(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
2291void
2292StopAllJobs(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 2312void
017c50f3 2313StopJob(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
2399void
017c50f3 2400UpdateJob(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 2481int /* O - Size of buffer to hold IPP attributes */
2482ipp_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
2602static void
2603set_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 2621static int /* O - Process ID or 0 */
2622start_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
2766static void
2767set_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 */