]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/job.c
2e89397b6ea6cc0061e7295c843585e4dcf6207e
2 * "$Id: job.c,v 1.124.2.14 2002/04/21 12:47:05 mike Exp $"
4 * Job management routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2002 by Easy Software Products, all rights reserved.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * AddJob() - Add a new job to the job queue...
27 * CancelJob() - Cancel the specified print job.
28 * CancelJobs() - Cancel all jobs on the given printer or class.
29 * CheckJobs() - Check the pending jobs and start any if the
30 * destination is available.
31 * CleanJobs() - Clean out old jobs.
32 * FindJob() - Find the specified job.
33 * GetPrinterJobCount() - Get the number of pending, processing,
34 * or held jobs in a printer or class.
35 * GetUserJobCount() - Get the number of pending, processing,
36 * or held jobs for a user.
37 * HoldJob() - Hold the specified job.
38 * LoadAllJobs() - Load all jobs from disk.
39 * LoadJob() - Load a job from disk.
40 * MoveJob() - Move the specified job to a different
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.
52 * start_process() - Start a background process.
56 * Include necessary headers...
67 static void set_time(job_t
*job
, const char *name
);
68 static int start_process(const char *command
, char *argv
[],
69 char *envp
[], int infd
, int outfd
,
70 int errfd
, int backfd
, int root
);
74 * 'AddJob()' - Add a new job to the job queue...
77 job_t
* /* O - New job record */
78 AddJob(int priority
, /* I - Job priority */
79 const char *dest
) /* I - Job destination */
81 job_t
*job
, /* New job record */
82 *current
, /* Current job in queue */
83 *prev
; /* Previous job in queue */
86 job
= calloc(sizeof(job_t
), 1);
88 job
->id
= NextJobId
++;
89 job
->priority
= priority
;
90 job
->back_pipes
[0] = -1;
91 job
->back_pipes
[1] = -1;
92 job
->print_pipes
[0] = -1;
93 job
->print_pipes
[1] = -1;
94 job
->status_pipe
= -1;
96 strncpy(job
->dest
, dest
, sizeof(job
->dest
) - 1);
100 for (current
= Jobs
, prev
= NULL
;
102 prev
= current
, current
= current
->next
)
103 if (job
->priority
> current
->priority
)
117 * 'CancelJob()' - Cancel the specified print job.
121 CancelJob(int id
, /* I - Job to cancel */
122 int purge
) /* I - Purge jobs? */
124 int i
; /* Looping var */
125 job_t
*current
, /* Current job */
126 *prev
; /* Previous job in list */
127 char filename
[1024]; /* Job filename */
130 LogMessage(L_DEBUG
, "CancelJob: id = %d", id
);
132 for (current
= Jobs
, prev
= NULL
; current
!= NULL
; prev
= current
, current
= current
->next
)
133 if (current
->id
== id
)
136 * Stop any processes that are working on the current...
139 DEBUG_puts("CancelJob: found job in list.");
141 if (current
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
142 StopJob(current
->id
, 0);
144 current
->state
->values
[0].integer
= IPP_JOB_CANCELLED
;
146 set_time(current
, "time-at-completed");
149 * Remove the print file for good if we aren't preserving jobs or
153 current
->current_file
= 0;
155 if (!JobHistory
|| !JobFiles
|| purge
||
156 (current
->dtype
& CUPS_PRINTER_REMOTE
))
157 for (i
= 1; i
<= current
->num_files
; i
++)
159 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
,
164 if (JobHistory
&& !purge
&& !(current
->dtype
& CUPS_PRINTER_REMOTE
))
167 * Save job state info...
170 SaveJob(current
->id
);
175 * Remove the job info file...
178 snprintf(filename
, sizeof(filename
), "%s/c%05d", RequestRoot
,
183 * Update pointers if we aren't preserving jobs...
187 Jobs
= current
->next
;
189 prev
->next
= current
->next
;
192 * Free all memory used...
195 if (current
->attrs
!= NULL
)
196 ippDelete(current
->attrs
);
198 free(current
->filetypes
);
211 * 'CancelJobs()' - Cancel all jobs on the given printer or class.
215 CancelJobs(const char *dest
) /* I - Destination to cancel */
217 job_t
*current
; /* Current job */
220 for (current
= Jobs
; current
!= NULL
;)
221 if (strcmp(current
->dest
, dest
) == 0)
224 * Cancel all jobs matching this destination...
227 CancelJob(current
->id
, 1);
232 current
= current
->next
;
239 * 'CheckJobs()' - Check the pending jobs and start any if the destination
246 job_t
*current
, /* Current job in queue */
247 *next
; /* Next job in queue */
248 printer_t
*printer
, /* Printer destination */
249 *pclass
; /* Printer class destination */
252 DEBUG_puts("CheckJobs()");
254 for (current
= Jobs
; current
!= NULL
; current
= next
)
257 * Save next pointer in case the job is cancelled en-route.
260 next
= current
->next
;
263 * Start held jobs if they are ready...
266 if (current
->state
->values
[0].integer
== IPP_JOB_HELD
&&
267 current
->hold_until
&&
268 current
->hold_until
< time(NULL
))
269 current
->state
->values
[0].integer
= IPP_JOB_PENDING
;
272 * Start pending jobs if the destination is available...
275 if (current
->state
->values
[0].integer
== IPP_JOB_PENDING
)
277 if ((pclass
= FindClass(current
->dest
)) != NULL
)
280 * If the class is remote, just pass it to the remote server...
283 if (pclass
->type
& CUPS_PRINTER_REMOTE
)
285 else if (pclass
->state
!= IPP_PRINTER_STOPPED
)
286 printer
= FindAvailablePrinter(current
->dest
);
291 printer
= FindPrinter(current
->dest
);
293 if (printer
!= NULL
&& (printer
->type
& CUPS_PRINTER_IMPLICIT
))
296 * Handle implicit classes...
301 if (pclass
->state
!= IPP_PRINTER_STOPPED
)
302 printer
= FindAvailablePrinter(current
->dest
);
307 if (printer
== NULL
&& pclass
== NULL
)
310 * Whoa, the printer and/or class for this destination went away;
314 LogMessage(L_WARN
, "Printer/class %s has gone away; cancelling job %d!",
315 current
->dest
, current
->id
);
316 CancelJob(current
->id
, 1);
318 else if (printer
!= NULL
)
321 * See if the printer is available or remote and not printing a job;
322 * if so, start the job...
325 if (printer
->state
== IPP_PRINTER_IDLE
|| /* Printer is idle */
326 ((printer
->type
& CUPS_PRINTER_REMOTE
) && /* Printer is remote */
327 !printer
->job
)) /* and not printing a job */
328 StartJob(current
->id
, printer
);
336 * 'CleanJobs()' - Clean out old jobs.
342 job_t
*job
, /* Current job */
343 *next
; /* Next job */
349 for (job
= Jobs
; job
&& NumJobs
>= MaxJobs
; job
= next
)
353 if (job
->state
->values
[0].integer
>= IPP_JOB_CANCELLED
)
354 CancelJob(job
->id
, 1);
360 * 'FindJob()' - Find the specified job.
363 job_t
* /* O - Job data */
364 FindJob(int id
) /* I - Job ID */
366 job_t
*current
; /* Current job */
369 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
370 if (current
->id
== id
)
378 * 'GetPrinterJobCount()' - Get the number of pending, processing,
379 * or held jobs in a printer or class.
382 int /* O - Job count */
383 GetPrinterJobCount(const char *dest
) /* I - Printer or class name */
385 int count
; /* Job count */
386 job_t
*job
; /* Current job */
389 for (job
= Jobs
, count
= 0; job
!= NULL
; job
= job
->next
)
390 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
&&
391 strcasecmp(job
->dest
, dest
) == 0)
399 * 'GetUserJobCount()' - Get the number of pending, processing,
400 * or held jobs for a user.
403 int /* O - Job count */
404 GetUserJobCount(const char *username
) /* I - Username */
406 int count
; /* Job count */
407 job_t
*job
; /* Current job */
410 for (job
= Jobs
, count
= 0; job
!= NULL
; job
= job
->next
)
411 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
&&
412 strcmp(job
->username
, username
) == 0)
420 * 'HoldJob()' - Hold the specified job.
424 HoldJob(int id
) /* I - Job ID */
426 job_t
*job
; /* Job data */
429 LogMessage(L_DEBUG
, "HoldJob: id = %d", id
);
431 if ((job
= FindJob(id
)) == NULL
)
434 if (job
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
437 DEBUG_puts("HoldJob: setting state to held...");
439 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
448 * 'LoadAllJobs()' - Load all jobs from disk.
454 DIR *dir
; /* Directory */
455 DIRENT
*dent
; /* Directory entry */
456 char filename
[1024]; /* Full filename of job file */
457 int fd
; /* File descriptor */
458 job_t
*job
, /* New job */
459 *current
, /* Current job */
460 *prev
; /* Previous job */
461 int jobid
, /* Current job ID */
462 fileid
; /* Current file ID */
463 ipp_attribute_t
*attr
; /* Job attribute */
464 char method
[HTTP_MAX_URI
],
465 /* Method portion of URI */
466 username
[HTTP_MAX_URI
],
467 /* Username portion of URI */
469 /* Host portion of URI */
470 resource
[HTTP_MAX_URI
];
471 /* Resource portion of URI */
472 int port
; /* Port portion of URI */
473 printer_t
*p
; /* Printer or class */
474 const char *dest
; /* Destination */
475 mime_type_t
**filetypes
; /* New filetypes array */
479 * First open the requests directory...
482 if ((dir
= opendir(RequestRoot
)) == NULL
)
486 * Read all the c##### files...
489 while ((dent
= readdir(dir
)) != NULL
)
490 if (NAMLEN(dent
) == 6 && dent
->d_name
[0] == 'c')
493 * Allocate memory for the job...
496 if ((job
= calloc(sizeof(job_t
), 1)) == NULL
)
498 LogMessage(L_ERROR
, "LoadAllJobs: Ran out of memory for jobs!");
503 if ((job
->attrs
= ippNew()) == NULL
)
506 LogMessage(L_ERROR
, "LoadAllJobs: Ran out of memory for job attributes!");
512 * Assign the job ID...
515 job
->id
= atoi(dent
->d_name
+ 1);
517 if (job
->id
>= NextJobId
)
518 NextJobId
= job
->id
+ 1;
521 * Load the job control file...
524 snprintf(filename
, sizeof(filename
), "%s/%s", RequestRoot
, dent
->d_name
);
525 if ((fd
= open(filename
, O_RDONLY
)) < 0)
527 LogMessage(L_ERROR
, "LoadAllJobs: Unable to open job control file \"%s\" - %s!",
528 filename
, strerror(errno
));
529 ippDelete(job
->attrs
);
536 if (ippReadFile(fd
, job
->attrs
) != IPP_DATA
)
538 LogMessage(L_ERROR
, "LoadAllJobs: Unable to read job control file \"%s\"!",
541 ippDelete(job
->attrs
);
550 if ((attr
= ippFindAttribute(job
->attrs
, "job-printer-uri", IPP_TAG_URI
)) == NULL
)
552 LogMessage(L_ERROR
, "LoadAllJobs: No job-printer-uri attribute in control file \"%s\"!",
554 ippDelete(job
->attrs
);
560 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
,
563 if ((dest
= ValidateDest(host
, resource
, &(job
->dtype
))) == NULL
)
566 * Job queued on remote printer or class, so add it...
569 if (strncmp(resource
, "/classes/", 9) == 0)
571 p
= AddClass(resource
+ 9);
572 strcpy(p
->make_model
, "Remote Class on unknown");
576 p
= AddPrinter(resource
+ 10);
577 strcpy(p
->make_model
, "Remote Printer on unknown");
580 p
->state
= IPP_PRINTER_STOPPED
;
581 p
->type
|= CUPS_PRINTER_REMOTE
;
582 p
->browse_time
= 2147483647;
584 strcpy(p
->location
, "Location Unknown");
585 strcpy(p
->info
, "No Information Available");
586 p
->hostname
[0] = '\0';
594 LogMessage(L_ERROR
, "LoadAllJobs: Unable to queue job for destination \"%s\"!",
595 attr
->values
[0].string
.text
);
596 ippDelete(job
->attrs
);
602 strncpy(job
->dest
, dest
, sizeof(job
->dest
) - 1);
604 job
->sheets
= ippFindAttribute(job
->attrs
, "job-media-sheets-completed",
606 job
->state
= ippFindAttribute(job
->attrs
, "job-state", IPP_TAG_ENUM
);
607 job
->job_sheets
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_NAME
);
609 attr
= ippFindAttribute(job
->attrs
, "job-priority", IPP_TAG_INTEGER
);
610 job
->priority
= attr
->values
[0].integer
;
612 attr
= ippFindAttribute(job
->attrs
, "job-name", IPP_TAG_NAME
);
613 strncpy(job
->title
, attr
->values
[0].string
.text
,
614 sizeof(job
->title
) - 1);
616 attr
= ippFindAttribute(job
->attrs
, "job-originating-user-name", IPP_TAG_NAME
);
617 strncpy(job
->username
, attr
->values
[0].string
.text
,
618 sizeof(job
->username
) - 1);
620 if (job
->state
->values
[0].integer
== IPP_JOB_HELD
)
622 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
623 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
626 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
628 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
630 else if (job
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
631 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
634 * Insert the job into the array, sorting by job priority and ID...
637 for (current
= Jobs
, prev
= NULL
;
639 prev
= current
, current
= current
->next
)
640 if (job
->priority
> current
->priority
)
642 else if (job
->priority
== current
->priority
&& job
->id
< current
->id
)
655 * Read all the d##### files...
660 while ((dent
= readdir(dir
)) != NULL
)
661 if (NAMLEN(dent
) > 7 && dent
->d_name
[0] == 'd')
667 jobid
= atoi(dent
->d_name
+ 1);
668 fileid
= atoi(dent
->d_name
+ 7);
670 snprintf(filename
, sizeof(filename
), "%s/%s", RequestRoot
, dent
->d_name
);
672 if ((job
= FindJob(jobid
)) == NULL
)
674 LogMessage(L_ERROR
, "LoadAllJobs: Orphaned print file \"%s\"!",
680 if (fileid
> job
->num_files
)
682 if (job
->num_files
== 0)
683 filetypes
= (mime_type_t
**)calloc(sizeof(mime_type_t
*), fileid
);
685 filetypes
= (mime_type_t
**)realloc(job
->filetypes
,
686 sizeof(mime_type_t
*) * fileid
);
688 if (filetypes
== NULL
)
690 LogMessage(L_ERROR
, "LoadAllJobs: Ran out of memory for job file types!");
694 job
->filetypes
= filetypes
;
695 job
->num_files
= fileid
;
698 job
->filetypes
[fileid
- 1] = mimeFileType(MimeDatabase
, filename
);
700 if (job
->filetypes
[fileid
- 1] == NULL
)
701 job
->filetypes
[fileid
- 1] = mimeType(MimeDatabase
, "application",
708 * Clean out old jobs as needed...
714 * Check to see if we need to start any jobs...
722 * 'MoveJob()' - Move the specified job to a different destination.
726 MoveJob(int id
, /* I - Job ID */
727 const char *dest
) /* I - Destination */
729 job_t
*current
;/* Current job */
730 ipp_attribute_t
*attr
; /* job-printer-uri attribute */
731 printer_t
*p
; /* Destination printer or class */
734 if ((p
= FindPrinter(dest
)) == NULL
)
740 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
741 if (current
->id
== id
)
743 if (current
->state
->values
[0].integer
>= IPP_JOB_PROCESSING
)
746 strncpy(current
->dest
, dest
, sizeof(current
->dest
) - 1);
747 current
->dtype
= p
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
749 if ((attr
= ippFindAttribute(current
->attrs
, "job-printer-uri", IPP_TAG_URI
)) != NULL
)
751 free(attr
->values
[0].string
.text
);
752 attr
->values
[0].string
.text
= strdup(p
->uri
);
755 SaveJob(current
->id
);
763 * 'ReleaseJob()' - Release the specified job.
767 ReleaseJob(int id
) /* I - Job ID */
769 job_t
*job
; /* Job data */
772 LogMessage(L_DEBUG
, "ReleaseJob: id = %d", id
);
774 if ((job
= FindJob(id
)) == NULL
)
777 if (job
->state
->values
[0].integer
== IPP_JOB_HELD
)
779 DEBUG_puts("ReleaseJob: setting state to pending...");
781 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
789 * 'RestartJob()' - Restart the specified job.
793 RestartJob(int id
) /* I - Job ID */
795 job_t
*job
; /* Job data */
798 if ((job
= FindJob(id
)) == NULL
)
801 if (job
->state
->values
[0].integer
== IPP_JOB_STOPPED
|| JobFiles
)
803 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
811 * 'SaveJob()' - Save a job to disk.
815 SaveJob(int id
) /* I - Job ID */
817 job_t
*job
; /* Pointer to job */
818 char filename
[1024]; /* Job control filename */
819 int fd
; /* File descriptor */
822 if ((job
= FindJob(id
)) == NULL
)
825 snprintf(filename
, sizeof(filename
), "%s/c%05d", RequestRoot
, id
);
827 if ((fd
= open(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600)) < 0)
829 LogMessage(L_ERROR
, "SaveJob: Unable to create job control file \"%s\" - %s.",
830 filename
, strerror(errno
));
835 fchown(fd
, User
, Group
);
837 ippWriteFile(fd
, job
->attrs
);
839 LogMessage(L_DEBUG2
, "SaveJob: Closing file %d...", fd
);
846 * 'SetJobHoldUntil()' - Set the hold time for a job...
850 SetJobHoldUntil(int id
, /* I - Job ID */
851 const char *when
) /* I - When to resume */
853 job_t
*job
; /* Pointer to job */
854 time_t curtime
; /* Current time */
855 struct tm
*curdate
; /* Current date */
856 int hour
; /* Hold hour */
857 int minute
; /* Hold minute */
858 int second
; /* Hold second */
861 LogMessage(L_DEBUG
, "SetJobHoldUntil(%d, \"%s\")", id
, when
);
863 if ((job
= FindJob(id
)) == NULL
)
868 if (strcmp(when
, "indefinite") == 0)
871 * Hold indefinitely...
876 else if (strcmp(when
, "day-time") == 0)
879 * Hold to 6am the next morning unless local time is < 6pm.
882 curtime
= time(NULL
);
883 curdate
= localtime(&curtime
);
885 if (curdate
->tm_hour
< 18)
886 job
->hold_until
= curtime
;
888 job
->hold_until
= curtime
+
889 ((29 - curdate
->tm_hour
) * 60 + 59 -
890 curdate
->tm_min
) * 60 + 60 - curdate
->tm_sec
;
892 else if (strcmp(when
, "evening") == 0 || strcmp(when
, "night") == 0)
895 * Hold to 6pm unless local time is > 6pm or < 6am.
898 curtime
= time(NULL
);
899 curdate
= localtime(&curtime
);
901 if (curdate
->tm_hour
< 6 || curdate
->tm_hour
>= 18)
902 job
->hold_until
= curtime
;
904 job
->hold_until
= curtime
+
905 ((17 - curdate
->tm_hour
) * 60 + 59 -
906 curdate
->tm_min
) * 60 + 60 - curdate
->tm_sec
;
908 else if (strcmp(when
, "second-shift") == 0)
911 * Hold to 4pm unless local time is > 4pm.
914 curtime
= time(NULL
);
915 curdate
= localtime(&curtime
);
917 if (curdate
->tm_hour
>= 16)
918 job
->hold_until
= curtime
;
920 job
->hold_until
= curtime
+
921 ((15 - curdate
->tm_hour
) * 60 + 59 -
922 curdate
->tm_min
) * 60 + 60 - curdate
->tm_sec
;
924 else if (strcmp(when
, "third-shift") == 0)
927 * Hold to 12am unless local time is < 8am.
930 curtime
= time(NULL
);
931 curdate
= localtime(&curtime
);
933 if (curdate
->tm_hour
< 8)
934 job
->hold_until
= curtime
;
936 job
->hold_until
= curtime
+
937 ((23 - curdate
->tm_hour
) * 60 + 59 -
938 curdate
->tm_min
) * 60 + 60 - curdate
->tm_sec
;
940 else if (strcmp(when
, "weekend") == 0)
943 * Hold to weekend unless we are in the weekend.
946 curtime
= time(NULL
);
947 curdate
= localtime(&curtime
);
949 if (curdate
->tm_wday
== 0 || curdate
->tm_wday
== 6)
950 job
->hold_until
= curtime
;
952 job
->hold_until
= curtime
+
953 (((5 - curdate
->tm_wday
) * 24 +
954 (17 - curdate
->tm_hour
)) * 60 + 59 -
955 curdate
->tm_min
) * 60 + 60 - curdate
->tm_sec
;
957 else if (sscanf(when
, "%d:%d:%d", &hour
, &minute
, &second
) >= 2)
960 * Hold to specified GMT time (HH:MM or HH:MM:SS)...
963 curtime
= time(NULL
);
964 curdate
= gmtime(&curtime
);
966 job
->hold_until
= curtime
+
967 ((hour
- curdate
->tm_hour
) * 60 + minute
-
968 curdate
->tm_min
) * 60 + second
- curdate
->tm_sec
;
971 * Hold until next day as needed...
974 if (job
->hold_until
< curtime
)
975 job
->hold_until
+= 24 * 60 * 60 * 60;
978 LogMessage(L_DEBUG
, "SetJobHoldUntil: hold_until = %d", job
->hold_until
);
983 * 'SetJobPriority()' - Set the priority of a job, moving it up/down in the
988 SetJobPriority(int id
, /* I - Job ID */
989 int priority
) /* I - New priority (0 to 100) */
991 job_t
*job
, /* Job to change */
992 *current
, /* Current job */
993 *prev
; /* Previous job */
994 ipp_attribute_t
*attr
; /* Job attribute */
1001 for (current
= Jobs
, prev
= NULL
;
1003 prev
= current
, current
= current
->next
)
1004 if (current
->id
== id
)
1007 if (current
== NULL
)
1011 * Set the new priority...
1015 job
->priority
= priority
;
1017 if ((attr
= ippFindAttribute(job
->attrs
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
1018 attr
->values
[0].integer
= priority
;
1020 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
1026 * See if we need to do any sorting...
1029 if ((prev
== NULL
|| job
->priority
< prev
->priority
) &&
1030 (job
->next
== NULL
|| job
->next
->priority
< job
->priority
))
1034 * Remove the job from the list, and then insert it where it belongs...
1040 prev
->next
= job
->next
;
1042 for (current
= Jobs
, prev
= NULL
;
1044 prev
= current
, current
= current
->next
)
1045 if (job
->priority
> current
->priority
)
1048 job
->next
= current
;
1057 * 'StartJob()' - Start a print job.
1061 StartJob(int id
, /* I - Job ID */
1062 printer_t
*printer
) /* I - Printer to print job */
1064 job_t
*current
; /* Current job */
1065 int i
; /* Looping var */
1066 int slot
; /* Pipe slot */
1067 int num_filters
; /* Number of filters for job */
1068 mime_filter_t
*filters
; /* Filters for job */
1069 char method
[255], /* Method for output */
1070 *optptr
; /* Pointer to options */
1071 ipp_attribute_t
*attr
; /* Current attribute */
1072 int pid
; /* Process ID of new filter process */
1073 int banner_page
; /* 1 if banner page, 0 otherwise */
1074 int statusfds
[2], /* Pipes used between the filters and scheduler */
1075 filterfds
[2][2];/* Pipes used between the filters */
1076 char *argv
[8], /* Filter command-line arguments */
1077 filename
[1024], /* Job filename */
1078 command
[1024], /* Full path to filter/backend command */
1079 jobid
[255], /* Job ID string */
1080 title
[IPP_MAX_NAME
],
1081 /* Job title string */
1082 copies
[255], /* # copies string */
1083 options
[16384], /* Full list of options */
1084 *envp
[20], /* Environment variables */
1085 path
[1024], /* PATH environment variable */
1086 language
[255], /* LANG environment variable */
1087 charset
[255], /* CHARSET environment variable */
1088 classification
[1024], /* CLASSIFICATION environment variable */
1089 content_type
[255],/* CONTENT_TYPE environment variable */
1090 device_uri
[1024],/* DEVICE_URI environment variable */
1091 ppd
[1024], /* PPD environment variable */
1092 printer_name
[255],/* PRINTER environment variable */
1093 root
[1024], /* CUPS_SERVERROOT environment variable */
1094 cache
[255], /* RIP_MAX_CACHE environment variable */
1095 tmpdir
[1024], /* TMPDIR environment variable */
1096 ldpath
[1024], /* LD_LIBRARY_PATH environment variable */
1097 datadir
[1024], /* CUPS_DATADIR environment variable */
1098 fontpath
[1050]; /* CUPS_FONTPATH environment variable */
1101 LogMessage(L_DEBUG
, "StartJob(%d, %08x)", id
, printer
);
1103 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
1104 if (current
->id
== id
)
1107 if (current
== NULL
)
1110 LogMessage(L_DEBUG
, "StartJob() id = %d, file = %d/%d", id
,
1111 current
->current_file
, current
->num_files
);
1113 if (current
->num_files
== 0)
1115 LogMessage(L_ERROR
, "Job ID %d has no files! Cancelling it!", id
);
1121 * Figure out what filters are required to convert from
1122 * the source to the destination type...
1128 if (printer
->type
& CUPS_PRINTER_REMOTE
)
1131 * Remote jobs go directly to the remote job...
1139 * Local jobs get filtered...
1142 filters
= mimeFilter(MimeDatabase
, current
->filetypes
[current
->current_file
],
1143 printer
->filetype
, &num_filters
);
1145 if (num_filters
== 0)
1147 LogMessage(L_ERROR
, "Unable to convert file %d to printable format for job %d!",
1148 current
->current_file
, current
->id
);
1149 current
->current_file
++;
1151 if (current
->current_file
== current
->num_files
)
1152 CancelJob(current
->id
, 0);
1158 * Remove NULL ("-") filters...
1161 for (i
= 0; i
< num_filters
;)
1162 if (strcmp(filters
[i
].filter
, "-") == 0)
1165 if (i
< num_filters
)
1166 memcpy(filters
+ i
, filters
+ i
+ 1,
1167 (num_filters
- i
) * sizeof(mime_filter_t
));
1172 if (num_filters
== 0)
1180 * Compute filter cost...
1183 for (i
= 0; i
< num_filters
; i
++)
1184 current
->cost
+= filters
[i
].cost
;
1189 * See if the filter cost is too high...
1192 if ((FilterLevel
+ current
->cost
) > FilterLimit
&& FilterLevel
> 0 &&
1196 * Don't print this job quite yet...
1199 if (filters
!= NULL
)
1202 LogMessage(L_INFO
, "Holding job %d because filter limit has been reached.",
1204 LogMessage(L_DEBUG
, "StartJob: id = %d, file = %d, "
1205 "cost = %d, level = %d, limit = %d",
1206 id
, current
->current_file
, current
->cost
, FilterLevel
,
1211 FilterLevel
+= current
->cost
;
1214 * Update the printer and job state to "processing"...
1217 current
->state
->values
[0].integer
= IPP_JOB_PROCESSING
;
1218 current
->status
= 0;
1219 current
->printer
= printer
;
1220 printer
->job
= current
;
1221 SetPrinterState(printer
, IPP_PRINTER_PROCESSING
);
1223 if (current
->current_file
== 0)
1225 set_time(current
, "time-at-processing");
1226 pipe(current
->back_pipes
);
1230 * Determine if we are printing a banner page or not...
1233 if (current
->job_sheets
== NULL
)
1235 LogMessage(L_DEBUG
, "No job-sheets attribute.");
1236 if ((current
->job_sheets
=
1237 ippFindAttribute(current
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
1238 LogMessage(L_DEBUG
, "... but someone added one without setting job_sheets!");
1240 else if (current
->job_sheets
->num_values
== 1)
1241 LogMessage(L_DEBUG
, "job-sheets=%s",
1242 current
->job_sheets
->values
[0].string
.text
);
1244 LogMessage(L_DEBUG
, "job-sheets=%s,%s",
1245 current
->job_sheets
->values
[0].string
.text
,
1246 current
->job_sheets
->values
[1].string
.text
);
1248 if (printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
))
1250 else if (current
->job_sheets
== NULL
)
1252 else if (strcasecmp(current
->job_sheets
->values
[0].string
.text
, "none") != 0 &&
1253 current
->current_file
== 0)
1255 else if (current
->job_sheets
->num_values
> 1 &&
1256 strcasecmp(current
->job_sheets
->values
[1].string
.text
, "none") != 0 &&
1257 current
->current_file
== (current
->num_files
- 1))
1262 LogMessage(L_DEBUG
, "banner_page = %d", banner_page
);
1265 * Building the options string is harder than it needs to be, but
1266 * for the moment we need to pass strings for command-line args and
1267 * not IPP attribute pointers... :)
1273 snprintf(title
, sizeof(title
), "%s-%d", printer
->name
, current
->id
);
1274 strcpy(copies
, "1");
1276 for (attr
= current
->attrs
->attrs
; attr
!= NULL
; attr
= attr
->next
)
1278 if (strcmp(attr
->name
, "copies") == 0 &&
1279 attr
->value_tag
== IPP_TAG_INTEGER
)
1282 * Don't use the # copies attribute if we are printing the job sheets...
1286 sprintf(copies
, "%d", attr
->values
[0].integer
);
1288 else if (strcmp(attr
->name
, "job-name") == 0 &&
1289 (attr
->value_tag
== IPP_TAG_NAME
||
1290 attr
->value_tag
== IPP_TAG_NAMELANG
))
1292 strncpy(title
, attr
->values
[0].string
.text
, sizeof(title
) - 1);
1293 title
[sizeof(title
) - 1] = '\0';
1295 else if (attr
->group_tag
== IPP_TAG_JOB
)
1298 * Filter out other unwanted attributes...
1301 if (attr
->value_tag
== IPP_TAG_MIMETYPE
||
1302 attr
->value_tag
== IPP_TAG_NAMELANG
||
1303 attr
->value_tag
== IPP_TAG_TEXTLANG
||
1304 attr
->value_tag
== IPP_TAG_URI
||
1305 attr
->value_tag
== IPP_TAG_URISCHEME
)
1308 if (strncmp(attr
->name
, "time-", 5) == 0)
1311 if (strncmp(attr
->name
, "job-", 4) == 0 &&
1312 !(printer
->type
& CUPS_PRINTER_REMOTE
))
1315 if (strncmp(attr
->name
, "job-", 4) == 0 &&
1316 strcmp(attr
->name
, "job-billing") != 0 &&
1317 strcmp(attr
->name
, "job-sheets") != 0 &&
1318 strcmp(attr
->name
, "job-hold-until") != 0 &&
1319 strcmp(attr
->name
, "job-priority") != 0)
1322 if (strcmp(attr
->name
, "page-label") == 0 &&
1327 * Otherwise add them to the list...
1330 if (optptr
> options
)
1331 strncat(optptr
, " ", sizeof(options
) - (optptr
- options
) - 1);
1333 if (attr
->value_tag
!= IPP_TAG_BOOLEAN
)
1335 strncat(optptr
, attr
->name
, sizeof(options
) - (optptr
- options
) - 1);
1336 strncat(optptr
, "=", sizeof(options
) - (optptr
- options
) - 1);
1339 for (i
= 0; i
< attr
->num_values
; i
++)
1342 strncat(optptr
, ",", sizeof(options
) - (optptr
- options
) - 1);
1344 optptr
+= strlen(optptr
);
1346 switch (attr
->value_tag
)
1348 case IPP_TAG_INTEGER
:
1350 snprintf(optptr
, sizeof(options
) - (optptr
- options
) - 1,
1351 "%d", attr
->values
[i
].integer
);
1354 case IPP_TAG_BOOLEAN
:
1355 if (!attr
->values
[i
].boolean
)
1356 strncat(optptr
, "no", sizeof(options
) - (optptr
- options
) - 1);
1358 case IPP_TAG_NOVALUE
:
1359 strncat(optptr
, attr
->name
,
1360 sizeof(options
) - (optptr
- options
) - 1);
1363 case IPP_TAG_RANGE
:
1364 if (attr
->values
[i
].range
.lower
== attr
->values
[i
].range
.upper
)
1365 snprintf(optptr
, sizeof(options
) - (optptr
- options
) - 1,
1366 "%d", attr
->values
[i
].range
.lower
);
1368 snprintf(optptr
, sizeof(options
) - (optptr
- options
) - 1,
1369 "%d-%d", attr
->values
[i
].range
.lower
,
1370 attr
->values
[i
].range
.upper
);
1373 case IPP_TAG_RESOLUTION
:
1374 snprintf(optptr
, sizeof(options
) - (optptr
- options
) - 1,
1375 "%dx%d%s", attr
->values
[i
].resolution
.xres
,
1376 attr
->values
[i
].resolution
.yres
,
1377 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
1381 case IPP_TAG_STRING
:
1384 case IPP_TAG_KEYWORD
:
1385 case IPP_TAG_CHARSET
:
1386 case IPP_TAG_LANGUAGE
:
1387 if (strchr(attr
->values
[i
].string
.text
, ' ') != NULL
||
1388 strchr(attr
->values
[i
].string
.text
, '\t') != NULL
||
1389 strchr(attr
->values
[i
].string
.text
, '\n') != NULL
)
1391 strncat(optptr
, "\'", sizeof(options
) - (optptr
- options
) - 1);
1392 strncat(optptr
, attr
->values
[i
].string
.text
,
1393 sizeof(options
) - (optptr
- options
) - 1);
1394 strncat(optptr
, "\'", sizeof(options
) - (optptr
- options
) - 1);
1397 strncat(optptr
, attr
->values
[i
].string
.text
,
1398 sizeof(options
) - (optptr
- options
) - 1);
1402 break; /* anti-compiler-warning-code */
1406 optptr
+= strlen(optptr
);
1411 * Build the command-line arguments for the filters. Each filter
1412 * has 6 or 7 arguments:
1416 * argv[2] = username
1418 * argv[4] = # copies
1420 * argv[6] = filename (optional; normally stdin)
1422 * This allows legacy printer drivers that use the old System V
1423 * printing interface to be used by CUPS.
1426 sprintf(jobid
, "%d", current
->id
);
1427 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
,
1428 current
->id
, current
->current_file
+ 1);
1430 argv
[0] = printer
->name
;
1432 argv
[2] = current
->username
;
1439 LogMessage(L_DEBUG
, "StartJob: argv = \"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
1440 argv
[0], argv
[1], argv
[2], argv
[3], argv
[4], argv
[5], argv
[6]);
1443 * Create environment variable strings for the filters...
1446 attr
= ippFindAttribute(current
->attrs
, "attributes-natural-language",
1449 switch (strlen(attr
->values
[0].string
.text
))
1453 * This is an unknown or badly formatted language code; use
1454 * the POSIX locale...
1457 strcpy(language
, "LANG=C");
1462 * Just the language code (ll)...
1465 snprintf(language
, sizeof(language
), "LANG=%s",
1466 attr
->values
[0].string
.text
);
1471 * Language and country code (ll-cc)...
1474 snprintf(language
, sizeof(language
), "LANG=%c%c_%c%c",
1475 attr
->values
[0].string
.text
[0],
1476 attr
->values
[0].string
.text
[1],
1477 toupper(attr
->values
[0].string
.text
[3]),
1478 toupper(attr
->values
[0].string
.text
[4]));
1482 attr
= ippFindAttribute(current
->attrs
, "document-format",
1485 (optptr
= strstr(attr
->values
[0].string
.text
, "charset=")) != NULL
)
1486 snprintf(charset
, sizeof(charset
), "CHARSET=%s", optptr
+ 8);
1489 attr
= ippFindAttribute(current
->attrs
, "attributes-charset",
1491 snprintf(charset
, sizeof(charset
), "CHARSET=%s",
1492 attr
->values
[0].string
.text
);
1495 snprintf(path
, sizeof(path
), "PATH=%s/filter:/bin:/usr/bin", ServerBin
);
1496 snprintf(content_type
, sizeof(content_type
), "CONTENT_TYPE=%s/%s",
1497 current
->filetypes
[current
->current_file
]->super
,
1498 current
->filetypes
[current
->current_file
]->type
);
1499 snprintf(device_uri
, sizeof(device_uri
), "DEVICE_URI=%s", printer
->device_uri
);
1500 snprintf(ppd
, sizeof(ppd
), "PPD=%s/ppd/%s.ppd", ServerRoot
, printer
->name
);
1501 snprintf(printer_name
, sizeof(printer_name
), "PRINTER=%s", printer
->name
);
1502 snprintf(cache
, sizeof(cache
), "RIP_MAX_CACHE=%s", RIPCache
);
1503 snprintf(root
, sizeof(root
), "CUPS_SERVERROOT=%s", ServerRoot
);
1504 snprintf(tmpdir
, sizeof(tmpdir
), "TMPDIR=%s", TempDir
);
1505 snprintf(datadir
, sizeof(datadir
), "CUPS_DATADIR=%s", DataDir
);
1506 snprintf(fontpath
, sizeof(fontpath
), "CUPS_FONTPATH=%s", FontPath
);
1507 if (Classification
[0] && !banner_page
)
1509 if ((attr
= ippFindAttribute(current
->attrs
, "job-sheets",
1510 IPP_TAG_NAME
)) == NULL
)
1511 snprintf(classification
, sizeof(classification
), "CLASSIFICATION=%s",
1513 else if (attr
->num_values
> 1 &&
1514 strcmp(attr
->values
[1].string
.text
, "none") != 0)
1515 snprintf(classification
, sizeof(classification
), "CLASSIFICATION=%s",
1516 attr
->values
[1].string
.text
);
1518 snprintf(classification
, sizeof(classification
), "CLASSIFICATION=%s",
1519 attr
->values
[0].string
.text
);
1522 classification
[0] = '\0';
1523 if (getenv("LD_LIBRARY_PATH") != NULL
)
1524 snprintf(ldpath
, sizeof(ldpath
), "LD_LIBRARY_PATH=%s", getenv("LD_LIBRARY_PATH"));
1525 else if (getenv("DYLD_LIBRARY_PATH") != NULL
)
1526 snprintf(ldpath
, sizeof(ldpath
), "DYLD_LIBRARY_PATH=%s", getenv("DYLD_LIBRARY_PATH"));
1531 envp
[1] = "SOFTWARE=CUPS/1.1";
1532 envp
[2] = "USER=root";
1540 envp
[10] = content_type
;
1541 envp
[11] = device_uri
;
1542 envp
[12] = printer_name
;
1544 envp
[14] = fontpath
;
1546 envp
[16] = classification
;
1549 LogMessage(L_DEBUG
, "StartJob: envp = \"%s\",\"%s\",\"%s\",\"%s\","
1550 "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\","
1551 "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
1552 envp
[0], envp
[1], envp
[2], envp
[3], envp
[4],
1553 envp
[5], envp
[6], envp
[7], envp
[8], envp
[9],
1554 envp
[10], envp
[11], envp
[12], envp
[13], envp
[14],
1555 envp
[15], envp
[16]);
1557 current
->current_file
++;
1560 * Make sure we have a buffer to read status info into...
1563 if (current
->buffer
== NULL
)
1565 LogMessage(L_DEBUG2
, "UpdateJob: Allocating status buffer...");
1567 if ((current
->buffer
= malloc(JOB_BUFFER_SIZE
)) == NULL
)
1569 LogMessage(L_EMERG
, "Unable to allocate memory for job status buffer - %s",
1571 CancelJob(current
->id
, 0);
1575 current
->bufused
= 0;
1579 * Now create processes for all of the filters...
1582 if (pipe(statusfds
))
1584 LogMessage(L_ERROR
, "Unable to create job status pipes - %s.",
1586 snprintf(printer
->state_message
, sizeof(printer
->state_message
),
1587 "Unable to create status pipes - %s.", strerror(errno
));
1591 LogMessage(L_DEBUG
, "StartJob: statusfds = [ %d %d ]",
1592 statusfds
[0], statusfds
[1]);
1594 current
->status_pipe
= statusfds
[0];
1595 current
->status
= 0;
1596 memset(current
->filters
, 0, sizeof(current
->filters
));
1598 filterfds
[1][0] = open("/dev/null", O_RDONLY
);
1599 filterfds
[1][1] = -1;
1601 LogMessage(L_DEBUG
, "StartJob: filterfds[%d] = [ %d %d ]", 1, filterfds
[1][0],
1604 for (i
= 0, slot
= 0; i
< num_filters
; i
++)
1606 if (filters
[i
].filter
[0] != '/')
1607 snprintf(command
, sizeof(command
), "%s/filter/%s", ServerBin
,
1611 strncpy(command
, filters
[i
].filter
, sizeof(command
) - 1);
1612 command
[sizeof(command
) - 1] = '\0';
1615 if (i
< (num_filters
- 1))
1616 pipe(filterfds
[slot
]);
1619 if (current
->current_file
== 1)
1621 if (strncmp(printer
->device_uri
, "file:", 5) != 0)
1622 pipe(current
->print_pipes
);
1625 current
->print_pipes
[0] = -1;
1626 if (strncmp(printer
->device_uri
, "file:/dev/", 10) == 0)
1627 current
->print_pipes
[1] = open(printer
->device_uri
+ 5,
1630 current
->print_pipes
[1] = open(printer
->device_uri
+ 5,
1631 O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
1634 LogMessage(L_DEBUG2
, "StartJob: print_pipes = [ %d %d ]",
1635 current
->print_pipes
[0], current
->print_pipes
[1]);
1638 filterfds
[slot
][0] = current
->print_pipes
[0];
1639 filterfds
[slot
][1] = current
->print_pipes
[1];
1642 LogMessage(L_DEBUG
, "StartJob: filter = \"%s\"", command
);
1643 LogMessage(L_DEBUG
, "StartJob: filterfds[%d] = [ %d %d ]",
1644 slot
, filterfds
[slot
][0], filterfds
[slot
][1]);
1646 pid
= start_process(command
, argv
, envp
, filterfds
[!slot
][0],
1647 filterfds
[slot
][1], statusfds
[1],
1648 current
->back_pipes
[0], 0);
1650 LogMessage(L_DEBUG2
, "StartJob: Closing filter pipes for slot %d [ %d %d ]...",
1651 !slot
, filterfds
[!slot
][0], filterfds
[!slot
][1]);
1653 close(filterfds
[!slot
][0]);
1654 close(filterfds
[!slot
][1]);
1658 LogMessage(L_ERROR
, "Unable to start filter \"%s\" - %s.",
1659 filters
[i
].filter
, strerror(errno
));
1660 snprintf(printer
->state_message
, sizeof(printer
->state_message
),
1661 "Unable to start filter \"%s\" - %s.",
1662 filters
[i
].filter
, strerror(errno
));
1666 current
->filters
[i
] = pid
;
1668 LogMessage(L_INFO
, "Started filter %s (PID %d) for job %d.",
1669 command
, pid
, current
->id
);
1675 if (filters
!= NULL
)
1679 * Finally, pipe the final output into a backend process if needed...
1682 if (strncmp(printer
->device_uri
, "file:", 5) != 0)
1684 if (current
->current_file
== 1)
1686 sscanf(printer
->device_uri
, "%254[^:]", method
);
1687 snprintf(command
, sizeof(command
), "%s/backend/%s", ServerBin
, method
);
1689 argv
[0] = printer
->device_uri
;
1691 filterfds
[slot
][0] = -1;
1692 filterfds
[slot
][1] = open("/dev/null", O_WRONLY
);
1694 LogMessage(L_DEBUG
, "StartJob: backend = \"%s\"", command
);
1695 LogMessage(L_DEBUG
, "StartJob: filterfds[%d] = [ %d %d ]",
1696 slot
, filterfds
[slot
][0], filterfds
[slot
][1]);
1698 pid
= start_process(command
, argv
, envp
, filterfds
[!slot
][0],
1699 filterfds
[slot
][1], statusfds
[1],
1700 current
->back_pipes
[1], 1);
1704 LogMessage(L_ERROR
, "Unable to start backend \"%s\" - %s.",
1705 method
, strerror(errno
));
1706 snprintf(printer
->state_message
, sizeof(printer
->state_message
),
1707 "Unable to start backend \"%s\" - %s.", method
, strerror(errno
));
1709 LogMessage(L_DEBUG2
, "StartJob: Closing print pipes [ %d %d ]...",
1710 current
->print_pipes
[0], current
->print_pipes
[1]);
1712 close(current
->print_pipes
[0]);
1713 close(current
->print_pipes
[1]);
1715 current
->print_pipes
[0] = -1;
1716 current
->print_pipes
[1] = -1;
1718 LogMessage(L_DEBUG2
, "StartJob: Closing back pipes [ %d %d ]...",
1719 current
->back_pipes
[0], current
->back_pipes
[1]);
1721 close(current
->back_pipes
[0]);
1722 close(current
->back_pipes
[1]);
1724 current
->back_pipes
[0] = -1;
1725 current
->back_pipes
[1] = -1;
1731 current
->backend
= pid
;
1733 LogMessage(L_INFO
, "Started backend %s (PID %d) for job %d.", command
, pid
,
1738 if (current
->current_file
== current
->num_files
)
1740 LogMessage(L_DEBUG2
, "StartJob: Closing print pipes [ %d %d ]...",
1741 current
->print_pipes
[0], current
->print_pipes
[1]);
1743 close(current
->print_pipes
[0]);
1744 close(current
->print_pipes
[1]);
1746 current
->print_pipes
[0] = -1;
1747 current
->print_pipes
[1] = -1;
1749 LogMessage(L_DEBUG2
, "StartJob: Closing back pipes [ %d %d ]...",
1750 current
->back_pipes
[0], current
->back_pipes
[1]);
1752 close(current
->back_pipes
[0]);
1753 close(current
->back_pipes
[1]);
1755 current
->back_pipes
[0] = -1;
1756 current
->back_pipes
[1] = -1;
1761 filterfds
[slot
][0] = -1;
1762 filterfds
[slot
][1] = -1;
1764 if (current
->current_file
== current
->num_files
)
1766 LogMessage(L_DEBUG2
, "StartJob: Closing print pipes [ %d %d ]...",
1767 current
->print_pipes
[0], current
->print_pipes
[1]);
1769 close(current
->print_pipes
[0]);
1770 close(current
->print_pipes
[1]);
1772 current
->print_pipes
[0] = -1;
1773 current
->print_pipes
[1] = -1;
1777 LogMessage(L_DEBUG2
, "StartJob: Closing filter pipes for slot %d [ %d %d ]...",
1778 slot
, filterfds
[slot
][0], filterfds
[slot
][1]);
1780 close(filterfds
[slot
][0]);
1781 close(filterfds
[slot
][1]);
1783 LogMessage(L_DEBUG2
, "StartJob: Closing status output pipe %d...",
1786 close(statusfds
[1]);
1788 LogMessage(L_DEBUG2
, "StartJob: Adding fd %d to InputSet...",
1789 current
->status_pipe
);
1791 FD_SET(current
->status_pipe
, &InputSet
);
1796 * 'StopAllJobs()' - Stop all print jobs.
1802 job_t
*current
; /* Current job */
1805 DEBUG_puts("StopAllJobs()");
1807 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
1808 if (current
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
1810 StopJob(current
->id
, 1);
1811 current
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1817 * 'StopJob()' - Stop a print job.
1821 StopJob(int id
, /* I - Job ID */
1822 int force
) /* I - 1 = Force all filters to stop */
1824 int i
; /* Looping var */
1825 job_t
*current
; /* Current job */
1828 LogMessage(L_DEBUG
, "StopJob: id = %d, force = %d", id
, force
);
1830 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
1831 if (current
->id
== id
)
1833 DEBUG_puts("StopJob: found job in list.");
1835 if (current
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
1837 DEBUG_puts("StopJob: job state is \'processing\'.");
1839 FilterLevel
-= current
->cost
;
1841 if (current
->status
< 0)
1842 SetPrinterState(current
->printer
, IPP_PRINTER_STOPPED
);
1843 else if (current
->printer
->state
!= IPP_PRINTER_STOPPED
)
1844 SetPrinterState(current
->printer
, IPP_PRINTER_IDLE
);
1846 LogMessage(L_DEBUG
, "StopJob: printer state is %d", current
->printer
->state
);
1848 current
->state
->values
[0].integer
= IPP_JOB_STOPPED
;
1849 current
->printer
->job
= NULL
;
1850 current
->printer
= NULL
;
1852 current
->current_file
--;
1854 for (i
= 0; current
->filters
[i
]; i
++)
1855 if (current
->filters
[i
] > 0)
1857 kill(current
->filters
[i
], force
? SIGKILL
: SIGTERM
);
1858 current
->filters
[i
] = 0;
1861 if (current
->backend
> 0)
1863 kill(current
->backend
, force
? SIGKILL
: SIGTERM
);
1864 current
->backend
= 0;
1867 LogMessage(L_DEBUG2
, "StopJob: Closing print pipes [ %d %d ]...",
1868 current
->print_pipes
[0], current
->print_pipes
[1]);
1870 close(current
->print_pipes
[0]);
1871 close(current
->print_pipes
[1]);
1873 current
->print_pipes
[0] = -1;
1874 current
->print_pipes
[1] = -1;
1876 LogMessage(L_DEBUG2
, "StopJob: Closing back pipes [ %d %d ]...",
1877 current
->back_pipes
[0], current
->back_pipes
[1]);
1879 close(current
->back_pipes
[0]);
1880 close(current
->back_pipes
[1]);
1882 current
->back_pipes
[0] = -1;
1883 current
->back_pipes
[1] = -1;
1885 if (current
->status_pipe
>= 0)
1888 * Close the pipe and clear the input bit.
1891 LogMessage(L_DEBUG2
, "StopJob: Closing status input pipe %d...",
1892 current
->status_pipe
);
1894 close(current
->status_pipe
);
1896 LogMessage(L_DEBUG2
, "StopJob: Removing fd %d from InputSet...",
1897 current
->status_pipe
);
1899 FD_CLR(current
->status_pipe
, &InputSet
);
1900 current
->status_pipe
= -1;
1903 if (current
->buffer
)
1906 * Free the status buffer...
1909 LogMessage(L_DEBUG2
, "StopJob: Freeing status buffer...");
1911 free(current
->buffer
);
1912 current
->buffer
= NULL
;
1913 current
->bufused
= 0;
1922 * 'UpdateJob()' - Read a status update from a job's filters.
1926 UpdateJob(job_t
*job
) /* I - Job to check */
1928 int bytes
; /* Number of bytes read */
1929 int copies
; /* Number of copies printed */
1930 char *lineptr
, /* Pointer to end of line in buffer */
1931 *message
; /* Pointer to message text */
1932 int loglevel
; /* Log level for message */
1935 if ((bytes
= read(job
->status_pipe
, job
->buffer
+ job
->bufused
,
1936 JOB_BUFFER_SIZE
- job
->bufused
- 1)) > 0)
1938 job
->bufused
+= bytes
;
1939 job
->buffer
[job
->bufused
] = '\0';
1940 lineptr
= strchr(job
->buffer
, '\n');
1942 else if (bytes
< 0 && errno
== EINTR
)
1946 lineptr
= job
->buffer
+ job
->bufused
;
1950 if (job
->bufused
== 0 && bytes
== 0)
1953 while (lineptr
!= NULL
)
1956 * Terminate each line and process it...
1962 * Figure out the logging level...
1965 if (strncmp(job
->buffer
, "EMERG:", 6) == 0)
1968 message
= job
->buffer
+ 6;
1970 else if (strncmp(job
->buffer
, "ALERT:", 6) == 0)
1973 message
= job
->buffer
+ 6;
1975 else if (strncmp(job
->buffer
, "CRIT:", 5) == 0)
1978 message
= job
->buffer
+ 5;
1980 else if (strncmp(job
->buffer
, "ERROR:", 6) == 0)
1983 message
= job
->buffer
+ 6;
1985 else if (strncmp(job
->buffer
, "WARNING:", 8) == 0)
1988 message
= job
->buffer
+ 8;
1990 else if (strncmp(job
->buffer
, "NOTICE:", 6) == 0)
1992 loglevel
= L_NOTICE
;
1993 message
= job
->buffer
+ 6;
1995 else if (strncmp(job
->buffer
, "INFO:", 5) == 0)
1998 message
= job
->buffer
+ 5;
2000 else if (strncmp(job
->buffer
, "DEBUG:", 6) == 0)
2003 message
= job
->buffer
+ 6;
2005 else if (strncmp(job
->buffer
, "DEBUG2:", 7) == 0)
2007 loglevel
= L_DEBUG2
;
2008 message
= job
->buffer
+ 7;
2010 else if (strncmp(job
->buffer
, "PAGE:", 5) == 0)
2013 message
= job
->buffer
+ 5;
2018 message
= job
->buffer
;
2022 * Skip leading whitespace in the message...
2025 while (isspace(*message
))
2029 * Send it to the log file and printer state message as needed...
2032 if (loglevel
== L_PAGE
)
2035 * Page message; send the message to the page_log file and update the
2036 * job sheet count...
2039 if (job
->sheets
!= NULL
)
2041 if (!sscanf(message
, "%*d%d", &copies
))
2043 job
->sheets
->values
[0].integer
++;
2045 if (job
->printer
->page_limit
)
2046 UpdateQuota(job
->printer
, job
->username
, 1, 0);
2050 job
->sheets
->values
[0].integer
+= copies
;
2052 if (job
->printer
->page_limit
)
2053 UpdateQuota(job
->printer
, job
->username
, copies
, 0);
2057 LogPage(job
, message
);
2062 * Other status message; send it to the error_log file...
2065 if (loglevel
!= L_INFO
)
2066 LogMessage(loglevel
, "%s", message
);
2068 if ((loglevel
== L_INFO
&& !job
->status
) ||
2070 strncpy(job
->printer
->state_message
, message
,
2071 sizeof(job
->printer
->state_message
) - 1);
2075 * Copy over the buffer data we've used up...
2078 strcpy(job
->buffer
, lineptr
);
2079 job
->bufused
-= lineptr
- job
->buffer
;
2081 if (job
->bufused
< 0)
2084 lineptr
= strchr(job
->buffer
, '\n');
2089 LogMessage(L_DEBUG
, "UpdateJob: job %d, file %d is complete.",
2090 job
->id
, job
->current_file
- 1);
2092 if (job
->status_pipe
>= 0)
2095 * Close the pipe and clear the input bit.
2098 LogMessage(L_DEBUG2
, "UpdateJob: Closing status input pipe %d...",
2101 close(job
->status_pipe
);
2103 LogMessage(L_DEBUG2
, "UpdateJob: Removing fd %d from InputSet...",
2106 FD_CLR(job
->status_pipe
, &InputSet
);
2107 job
->status_pipe
= -1;
2110 if (job
->status
< 0)
2113 * Backend had errors; stop it...
2116 StopJob(job
->id
, 0);
2117 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
2120 else if (job
->status
> 0)
2123 * Filter had errors; cancel it...
2126 if (job
->current_file
< job
->num_files
)
2127 StartJob(job
->id
, job
->printer
);
2130 CancelJob(job
->id
, 0);
2134 job
->state
->values
[0].integer
= IPP_JOB_ABORTED
;
2144 * Job printed successfully; cancel it...
2147 if (job
->current_file
< job
->num_files
)
2149 FilterLevel
-= job
->cost
;
2150 StartJob(job
->id
, job
->printer
);
2154 CancelJob(job
->id
, 0);
2158 job
->state
->values
[0].integer
= IPP_JOB_COMPLETED
;
2170 * 'set_time()' - Set one of the "time-at-xyz" attributes...
2174 set_time(job_t
*job
, /* I - Job to update */
2175 const char *name
) /* I - Name of attribute */
2177 ipp_attribute_t
*attr
; /* Time attribute */
2180 if ((attr
= ippFindAttribute(job
->attrs
, name
, IPP_TAG_ZERO
)) != NULL
)
2182 attr
->value_tag
= IPP_TAG_INTEGER
;
2183 attr
->values
[0].integer
= time(NULL
);
2189 * 'start_process()' - Start a background process.
2192 static int /* O - Process ID or 0 */
2193 start_process(const char *command
, /* I - Full path to command */
2194 char *argv
[], /* I - Command-line arguments */
2195 char *envp
[], /* I - Environment */
2196 int infd
, /* I - Standard input file descriptor */
2197 int outfd
, /* I - Standard output file descriptor */
2198 int errfd
, /* I - Standard error file descriptor */
2199 int backfd
, /* I - Backchannel file descriptor */
2200 int root
) /* I - Run as root? */
2202 int fd
; /* Looping var */
2203 int pid
; /* Process ID */
2206 LogMessage(L_DEBUG
, "start_process(\"%s\", %08x, %08x, %d, %d, %d)",
2207 command
, argv
, envp
, infd
, outfd
, errfd
);
2209 if ((pid
= fork()) == 0)
2212 * Child process goes here...
2214 * Update stdin/stdout/stderr as needed...
2230 fcntl(3, F_SETFL
, O_NDELAY
);
2234 * Close extra file descriptors...
2237 for (fd
= 4; fd
< MaxFDs
; fd
++)
2241 * Change user to something "safe"...
2244 if (!root
&& getuid() == 0)
2247 * Running as root, so change to non-priviledged user...
2258 * Reset group membership to just the main one we belong to.
2264 * Change umask to restrict permissions on created files...
2270 * Execute the command; if for some reason this doesn't work,
2271 * return the error code...
2274 execve(command
, argv
, envp
);
2283 * Error - couldn't fork a new process!
2286 LogMessage(L_ERROR
, "Unable to fork %s - %s.", command
, strerror(errno
));
2296 * End of "$Id: job.c,v 1.124.2.14 2002/04/21 12:47:05 mike Exp $".