2 * "$Id: job.c,v 1.153 2002/05/15 01:52:18 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 * ipp_read_file() - Read an IPP request from a file.
53 * ipp_write_file() - Write an IPP request to a file.
54 * start_process() - Start a background process.
58 * Include necessary headers...
69 static ipp_state_t
ipp_read_file(const char *filename
, ipp_t
*ipp
);
70 static ipp_state_t
ipp_write_file(const char *filename
, ipp_t
*ipp
);
71 static void set_time(job_t
*job
, const char *name
);
72 static int start_process(const char *command
, char *argv
[],
73 char *envp
[], int in
, int out
, int err
,
78 * 'AddJob()' - Add a new job to the job queue...
81 job_t
* /* O - New job record */
82 AddJob(int priority
, /* I - Job priority */
83 const char *dest
) /* I - Job destination */
85 job_t
*job
, /* New job record */
86 *current
, /* Current job in queue */
87 *prev
; /* Previous job in queue */
90 job
= calloc(sizeof(job_t
), 1);
92 job
->id
= NextJobId
++;
93 job
->priority
= priority
;
94 strncpy(job
->dest
, dest
, sizeof(job
->dest
) - 1);
98 for (current
= Jobs
, prev
= NULL
;
100 prev
= current
, current
= current
->next
)
101 if (job
->priority
> current
->priority
)
115 * 'CancelJob()' - Cancel the specified print job.
119 CancelJob(int id
, /* I - Job to cancel */
120 int purge
) /* I - Purge jobs? */
122 int i
; /* Looping var */
123 job_t
*current
, /* Current job */
124 *prev
; /* Previous job in list */
125 char filename
[1024]; /* Job filename */
128 LogMessage(L_DEBUG
, "CancelJob: id = %d", id
);
130 for (current
= Jobs
, prev
= NULL
; current
!= NULL
; prev
= current
, current
= current
->next
)
131 if (current
->id
== id
)
134 * Stop any processes that are working on the current...
137 DEBUG_puts("CancelJob: found job in list.");
139 if (current
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
140 StopJob(current
->id
, 0);
142 current
->state
->values
[0].integer
= IPP_JOB_CANCELLED
;
144 set_time(current
, "time-at-completed");
147 * Remove the print file for good if we aren't preserving jobs or
151 current
->current_file
= 0;
153 if (!JobHistory
|| !JobFiles
|| purge
||
154 (current
->dtype
& CUPS_PRINTER_REMOTE
))
155 for (i
= 1; i
<= current
->num_files
; i
++)
157 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
,
162 if (JobHistory
&& !purge
&& !(current
->dtype
& CUPS_PRINTER_REMOTE
))
165 * Save job state info...
168 SaveJob(current
->id
);
173 * Remove the job info file...
176 snprintf(filename
, sizeof(filename
), "%s/c%05d", RequestRoot
,
181 * Update pointers if we aren't preserving jobs...
185 Jobs
= current
->next
;
187 prev
->next
= current
->next
;
190 * Free all memory used...
193 if (current
->attrs
!= NULL
)
194 ippDelete(current
->attrs
);
196 free(current
->filetypes
);
209 * 'CancelJobs()' - Cancel all jobs on the given printer or class.
213 CancelJobs(const char *dest
) /* I - Destination to cancel */
215 job_t
*current
; /* Current job */
218 for (current
= Jobs
; current
!= NULL
;)
219 if (strcmp(current
->dest
, dest
) == 0)
222 * Cancel all jobs matching this destination...
225 CancelJob(current
->id
, 1);
230 current
= current
->next
;
237 * 'CheckJobs()' - Check the pending jobs and start any if the destination
244 job_t
*current
, /* Current job in queue */
245 *next
; /* Next job in queue */
246 printer_t
*printer
, /* Printer destination */
247 *pclass
; /* Printer class destination */
250 DEBUG_puts("CheckJobs()");
252 for (current
= Jobs
; current
!= NULL
; current
= next
)
255 * Save next pointer in case the job is cancelled en-route.
258 next
= current
->next
;
261 * Start held jobs if they are ready...
264 if (current
->state
->values
[0].integer
== IPP_JOB_HELD
&&
265 current
->hold_until
&&
266 current
->hold_until
< time(NULL
))
267 current
->state
->values
[0].integer
= IPP_JOB_PENDING
;
270 * Start pending jobs if the destination is available...
273 if (current
->state
->values
[0].integer
== IPP_JOB_PENDING
)
275 if ((pclass
= FindClass(current
->dest
)) != NULL
)
278 * If the class is remote, just pass it to the remote server...
281 if (pclass
->type
& CUPS_PRINTER_REMOTE
)
283 else if (pclass
->state
!= IPP_PRINTER_STOPPED
)
284 printer
= FindAvailablePrinter(current
->dest
);
289 printer
= FindPrinter(current
->dest
);
291 if (printer
!= NULL
&& (printer
->type
& CUPS_PRINTER_IMPLICIT
))
294 * Handle implicit classes...
299 if (pclass
->state
!= IPP_PRINTER_STOPPED
)
300 printer
= FindAvailablePrinter(current
->dest
);
305 if (printer
== NULL
&& pclass
== NULL
)
308 * Whoa, the printer and/or class for this destination went away;
312 LogMessage(L_WARN
, "Printer/class %s has gone away; cancelling job %d!",
313 current
->dest
, current
->id
);
314 CancelJob(current
->id
, 1);
316 else if (printer
!= NULL
)
319 * See if the printer is available or remote and not printing a job;
320 * if so, start the job...
323 if (printer
->state
== IPP_PRINTER_IDLE
|| /* Printer is idle */
324 ((printer
->type
& CUPS_PRINTER_REMOTE
) && /* Printer is remote */
325 !printer
->job
)) /* and not printing a job */
326 StartJob(current
->id
, printer
);
334 * 'CleanJobs()' - Clean out old jobs.
340 job_t
*job
, /* Current job */
341 *next
; /* Next job */
347 for (job
= Jobs
; job
&& NumJobs
>= MaxJobs
; job
= next
)
351 if (job
->state
->values
[0].integer
>= IPP_JOB_CANCELLED
)
352 CancelJob(job
->id
, 1);
358 * 'FindJob()' - Find the specified job.
361 job_t
* /* O - Job data */
362 FindJob(int id
) /* I - Job ID */
364 job_t
*current
; /* Current job */
367 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
368 if (current
->id
== id
)
376 * 'GetPrinterJobCount()' - Get the number of pending, processing,
377 * or held jobs in a printer or class.
380 int /* O - Job count */
381 GetPrinterJobCount(const char *dest
) /* I - Printer or class name */
383 int count
; /* Job count */
384 job_t
*job
; /* Current job */
387 for (job
= Jobs
, count
= 0; job
!= NULL
; job
= job
->next
)
388 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
&&
389 strcasecmp(job
->dest
, dest
) == 0)
397 * 'GetUserJobCount()' - Get the number of pending, processing,
398 * or held jobs for a user.
401 int /* O - Job count */
402 GetUserJobCount(const char *username
) /* I - Username */
404 int count
; /* Job count */
405 job_t
*job
; /* Current job */
408 for (job
= Jobs
, count
= 0; job
!= NULL
; job
= job
->next
)
409 if (job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
&&
410 strcmp(job
->username
, username
) == 0)
418 * 'HoldJob()' - Hold the specified job.
422 HoldJob(int id
) /* I - Job ID */
424 job_t
*job
; /* Job data */
427 LogMessage(L_DEBUG
, "HoldJob: id = %d", id
);
429 if ((job
= FindJob(id
)) == NULL
)
432 if (job
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
435 DEBUG_puts("HoldJob: setting state to held...");
437 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
446 * 'LoadAllJobs()' - Load all jobs from disk.
452 DIR *dir
; /* Directory */
453 DIRENT
*dent
; /* Directory entry */
454 char filename
[1024]; /* Full filename of job file */
455 job_t
*job
, /* New job */
456 *current
, /* Current job */
457 *prev
; /* Previous job */
458 int jobid
, /* Current job ID */
459 fileid
; /* Current file ID */
460 ipp_attribute_t
*attr
; /* Job attribute */
461 char method
[HTTP_MAX_URI
],
462 /* Method portion of URI */
463 username
[HTTP_MAX_URI
],
464 /* Username portion of URI */
466 /* Host portion of URI */
467 resource
[HTTP_MAX_URI
];
468 /* Resource portion of URI */
469 int port
; /* Port portion of URI */
470 printer_t
*p
; /* Printer or class */
471 const char *dest
; /* Destination */
472 mime_type_t
**filetypes
; /* New filetypes array */
476 * First open the requests directory...
479 if ((dir
= opendir(RequestRoot
)) == NULL
)
483 * Read all the c##### files...
486 while ((dent
= readdir(dir
)) != NULL
)
487 if (NAMLEN(dent
) == 6 && dent
->d_name
[0] == 'c')
490 * Allocate memory for the job...
493 if ((job
= calloc(sizeof(job_t
), 1)) == NULL
)
495 LogMessage(L_ERROR
, "LoadAllJobs: Ran out of memory for jobs!");
500 if ((job
->attrs
= ippNew()) == NULL
)
503 LogMessage(L_ERROR
, "LoadAllJobs: Ran out of memory for job attributes!");
509 * Assign the job ID...
512 job
->id
= atoi(dent
->d_name
+ 1);
514 if (job
->id
>= NextJobId
)
515 NextJobId
= job
->id
+ 1;
518 * Load the job control file...
521 snprintf(filename
, sizeof(filename
), "%s/%s", RequestRoot
, dent
->d_name
);
522 if (ipp_read_file(filename
, job
->attrs
) != IPP_DATA
)
524 LogMessage(L_ERROR
, "LoadAllJobs: Unable to read job control file \"%s\"!",
526 ippDelete(job
->attrs
);
532 job
->state
= ippFindAttribute(job
->attrs
, "job-state", IPP_TAG_ENUM
);
534 if ((attr
= ippFindAttribute(job
->attrs
, "job-printer-uri", IPP_TAG_URI
)) == NULL
)
536 LogMessage(L_ERROR
, "LoadAllJobs: No job-printer-uri attribute in control file \"%s\"!",
538 ippDelete(job
->attrs
);
544 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
,
547 if ((dest
= ValidateDest(host
, resource
, &(job
->dtype
))) == NULL
&&
548 job
->state
!= NULL
&&
549 job
->state
->values
[0].integer
<= IPP_JOB_PROCESSING
)
552 * Job queued on remote printer or class, so add it...
555 if (strncmp(resource
, "/classes/", 9) == 0)
557 p
= AddClass(resource
+ 9);
558 strcpy(p
->make_model
, "Remote Class on unknown");
562 p
= AddPrinter(resource
+ 10);
563 strcpy(p
->make_model
, "Remote Printer on unknown");
566 p
->state
= IPP_PRINTER_STOPPED
;
567 p
->type
|= CUPS_PRINTER_REMOTE
;
568 p
->browse_time
= 2147483647;
570 strcpy(p
->location
, "Location Unknown");
571 strcpy(p
->info
, "No Information Available");
572 p
->hostname
[0] = '\0';
580 LogMessage(L_ERROR
, "LoadAllJobs: Unable to queue job for destination \"%s\"!",
581 attr
->values
[0].string
.text
);
582 ippDelete(job
->attrs
);
588 strncpy(job
->dest
, dest
, sizeof(job
->dest
) - 1);
590 job
->sheets
= ippFindAttribute(job
->attrs
, "job-media-sheets-completed",
592 job
->job_sheets
= ippFindAttribute(job
->attrs
, "job-sheets", IPP_TAG_NAME
);
594 attr
= ippFindAttribute(job
->attrs
, "job-priority", IPP_TAG_INTEGER
);
595 job
->priority
= attr
->values
[0].integer
;
597 attr
= ippFindAttribute(job
->attrs
, "job-name", IPP_TAG_NAME
);
598 strncpy(job
->title
, attr
->values
[0].string
.text
,
599 sizeof(job
->title
) - 1);
601 attr
= ippFindAttribute(job
->attrs
, "job-originating-user-name", IPP_TAG_NAME
);
602 strncpy(job
->username
, attr
->values
[0].string
.text
,
603 sizeof(job
->username
) - 1);
605 if (job
->state
->values
[0].integer
== IPP_JOB_HELD
)
607 if ((attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_KEYWORD
)) == NULL
)
608 attr
= ippFindAttribute(job
->attrs
, "job-hold-until", IPP_TAG_NAME
);
611 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
613 SetJobHoldUntil(job
->id
, attr
->values
[0].string
.text
);
615 else if (job
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
616 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
619 * Insert the job into the array, sorting by job priority and ID...
622 for (current
= Jobs
, prev
= NULL
;
624 prev
= current
, current
= current
->next
)
625 if (job
->priority
> current
->priority
)
627 else if (job
->priority
== current
->priority
&& job
->id
< current
->id
)
640 * Read all the d##### files...
645 while ((dent
= readdir(dir
)) != NULL
)
646 if (NAMLEN(dent
) > 7 && dent
->d_name
[0] == 'd')
652 jobid
= atoi(dent
->d_name
+ 1);
653 fileid
= atoi(dent
->d_name
+ 7);
655 snprintf(filename
, sizeof(filename
), "%s/%s", RequestRoot
, dent
->d_name
);
657 if ((job
= FindJob(jobid
)) == NULL
)
659 LogMessage(L_ERROR
, "LoadAllJobs: Orphaned print file \"%s\"!",
665 if (fileid
> job
->num_files
)
667 if (job
->num_files
== 0)
668 filetypes
= (mime_type_t
**)calloc(sizeof(mime_type_t
*), fileid
);
670 filetypes
= (mime_type_t
**)realloc(job
->filetypes
,
671 sizeof(mime_type_t
*) * fileid
);
673 if (filetypes
== NULL
)
675 LogMessage(L_ERROR
, "LoadAllJobs: Ran out of memory for job file types!");
679 job
->filetypes
= filetypes
;
680 job
->num_files
= fileid
;
683 job
->filetypes
[fileid
- 1] = mimeFileType(MimeDatabase
, filename
);
685 if (job
->filetypes
[fileid
- 1] == NULL
)
686 job
->filetypes
[fileid
- 1] = mimeType(MimeDatabase
, "application",
693 * Clean out old jobs as needed...
699 * Check to see if we need to start any jobs...
707 * 'MoveJob()' - Move the specified job to a different destination.
711 MoveJob(int id
, /* I - Job ID */
712 const char *dest
) /* I - Destination */
714 job_t
*current
;/* Current job */
715 ipp_attribute_t
*attr
; /* job-printer-uri attribute */
716 printer_t
*p
; /* Destination printer or class */
719 if ((p
= FindPrinter(dest
)) == NULL
)
725 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
726 if (current
->id
== id
)
728 if (current
->state
->values
[0].integer
>= IPP_JOB_PROCESSING
)
731 strncpy(current
->dest
, dest
, sizeof(current
->dest
) - 1);
732 current
->dtype
= p
->type
& (CUPS_PRINTER_CLASS
| CUPS_PRINTER_REMOTE
);
734 if ((attr
= ippFindAttribute(current
->attrs
, "job-printer-uri", IPP_TAG_URI
)) != NULL
)
736 free(attr
->values
[0].string
.text
);
737 attr
->values
[0].string
.text
= strdup(p
->uri
);
740 SaveJob(current
->id
);
748 * 'ReleaseJob()' - Release the specified job.
752 ReleaseJob(int id
) /* I - Job ID */
754 job_t
*job
; /* Job data */
757 LogMessage(L_DEBUG
, "ReleaseJob: id = %d", id
);
759 if ((job
= FindJob(id
)) == NULL
)
762 if (job
->state
->values
[0].integer
== IPP_JOB_HELD
)
764 DEBUG_puts("ReleaseJob: setting state to pending...");
766 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
774 * 'RestartJob()' - Restart the specified job.
778 RestartJob(int id
) /* I - Job ID */
780 job_t
*job
; /* Job data */
783 if ((job
= FindJob(id
)) == NULL
)
786 if (job
->state
->values
[0].integer
== IPP_JOB_STOPPED
|| JobFiles
)
788 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
796 * 'SaveJob()' - Save a job to disk.
800 SaveJob(int id
) /* I - Job ID */
802 job_t
*job
; /* Pointer to job */
803 char filename
[1024]; /* Job control filename */
806 if ((job
= FindJob(id
)) == NULL
)
809 snprintf(filename
, sizeof(filename
), "%s/c%05d", RequestRoot
, id
);
810 ipp_write_file(filename
, job
->attrs
);
815 * 'SetJobHoldUntil()' - Set the hold time for a job...
819 SetJobHoldUntil(int id
, /* I - Job ID */
820 const char *when
) /* I - When to resume */
822 job_t
*job
; /* Pointer to job */
823 time_t curtime
; /* Current time */
824 struct tm
*curdate
; /* Current date */
825 int hour
; /* Hold hour */
826 int minute
; /* Hold minute */
827 int second
; /* Hold second */
830 LogMessage(L_DEBUG
, "SetJobHoldUntil(%d, \"%s\")", id
, when
);
832 if ((job
= FindJob(id
)) == NULL
)
837 if (strcmp(when
, "indefinite") == 0)
840 * Hold indefinitely...
845 else if (strcmp(when
, "day-time") == 0)
848 * Hold to 6am the next morning unless local time is < 6pm.
851 curtime
= time(NULL
);
852 curdate
= localtime(&curtime
);
854 if (curdate
->tm_hour
< 18)
855 job
->hold_until
= curtime
;
857 job
->hold_until
= curtime
+
858 ((29 - curdate
->tm_hour
) * 60 + 59 -
859 curdate
->tm_min
) * 60 + 60 - curdate
->tm_sec
;
861 else if (strcmp(when
, "evening") == 0 || strcmp(when
, "night") == 0)
864 * Hold to 6pm unless local time is > 6pm or < 6am.
867 curtime
= time(NULL
);
868 curdate
= localtime(&curtime
);
870 if (curdate
->tm_hour
< 6 || curdate
->tm_hour
>= 18)
871 job
->hold_until
= curtime
;
873 job
->hold_until
= curtime
+
874 ((17 - curdate
->tm_hour
) * 60 + 59 -
875 curdate
->tm_min
) * 60 + 60 - curdate
->tm_sec
;
877 else if (strcmp(when
, "second-shift") == 0)
880 * Hold to 4pm unless local time is > 4pm.
883 curtime
= time(NULL
);
884 curdate
= localtime(&curtime
);
886 if (curdate
->tm_hour
>= 16)
887 job
->hold_until
= curtime
;
889 job
->hold_until
= curtime
+
890 ((15 - curdate
->tm_hour
) * 60 + 59 -
891 curdate
->tm_min
) * 60 + 60 - curdate
->tm_sec
;
893 else if (strcmp(when
, "third-shift") == 0)
896 * Hold to 12am unless local time is < 8am.
899 curtime
= time(NULL
);
900 curdate
= localtime(&curtime
);
902 if (curdate
->tm_hour
< 8)
903 job
->hold_until
= curtime
;
905 job
->hold_until
= curtime
+
906 ((23 - curdate
->tm_hour
) * 60 + 59 -
907 curdate
->tm_min
) * 60 + 60 - curdate
->tm_sec
;
909 else if (strcmp(when
, "weekend") == 0)
912 * Hold to weekend unless we are in the weekend.
915 curtime
= time(NULL
);
916 curdate
= localtime(&curtime
);
918 if (curdate
->tm_wday
== 0 || curdate
->tm_wday
== 6)
919 job
->hold_until
= curtime
;
921 job
->hold_until
= curtime
+
922 (((5 - curdate
->tm_wday
) * 24 +
923 (17 - curdate
->tm_hour
)) * 60 + 59 -
924 curdate
->tm_min
) * 60 + 60 - curdate
->tm_sec
;
926 else if (sscanf(when
, "%d:%d:%d", &hour
, &minute
, &second
) >= 2)
929 * Hold to specified GMT time (HH:MM or HH:MM:SS)...
932 curtime
= time(NULL
);
933 curdate
= gmtime(&curtime
);
935 job
->hold_until
= curtime
+
936 ((hour
- curdate
->tm_hour
) * 60 + minute
-
937 curdate
->tm_min
) * 60 + second
- curdate
->tm_sec
;
940 * Hold until next day as needed...
943 if (job
->hold_until
< curtime
)
944 job
->hold_until
+= 24 * 60 * 60 * 60;
947 LogMessage(L_DEBUG
, "SetJobHoldUntil: hold_until = %d", (int)job
->hold_until
);
952 * 'SetJobPriority()' - Set the priority of a job, moving it up/down in the
957 SetJobPriority(int id
, /* I - Job ID */
958 int priority
) /* I - New priority (0 to 100) */
960 job_t
*job
, /* Job to change */
961 *current
, /* Current job */
962 *prev
; /* Previous job */
963 ipp_attribute_t
*attr
; /* Job attribute */
970 for (current
= Jobs
, prev
= NULL
;
972 prev
= current
, current
= current
->next
)
973 if (current
->id
== id
)
980 * Set the new priority...
984 job
->priority
= priority
;
986 if ((attr
= ippFindAttribute(job
->attrs
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
987 attr
->values
[0].integer
= priority
;
989 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
995 * See if we need to do any sorting...
998 if ((prev
== NULL
|| job
->priority
< prev
->priority
) &&
999 (job
->next
== NULL
|| job
->next
->priority
< job
->priority
))
1003 * Remove the job from the list, and then insert it where it belongs...
1009 prev
->next
= job
->next
;
1011 for (current
= Jobs
, prev
= NULL
;
1013 prev
= current
, current
= current
->next
)
1014 if (job
->priority
> current
->priority
)
1017 job
->next
= current
;
1026 * 'StartJob()' - Start a print job.
1030 StartJob(int id
, /* I - Job ID */
1031 printer_t
*printer
) /* I - Printer to print job */
1033 job_t
*current
; /* Current job */
1034 int i
; /* Looping var */
1035 int slot
; /* Pipe slot */
1036 int num_filters
; /* Number of filters for job */
1037 mime_filter_t
*filters
; /* Filters for job */
1038 char method
[255], /* Method for output */
1039 *optptr
; /* Pointer to options */
1040 ipp_attribute_t
*attr
; /* Current attribute */
1041 int pid
; /* Process ID of new filter process */
1042 int banner_page
; /* 1 if banner page, 0 otherwise */
1043 int statusfds
[2], /* Pipes used between the filters and scheduler */
1044 filterfds
[2][2];/* Pipes used between the filters */
1045 char *argv
[8], /* Filter command-line arguments */
1046 filename
[1024], /* Job filename */
1047 command
[1024], /* Full path to filter/backend command */
1048 jobid
[255], /* Job ID string */
1049 title
[IPP_MAX_NAME
],
1050 /* Job title string */
1051 copies
[255], /* # copies string */
1052 options
[16384], /* Full list of options */
1053 *envp
[20], /* Environment variables */
1054 path
[1024], /* PATH environment variable */
1055 language
[255], /* LANG environment variable */
1056 charset
[255], /* CHARSET environment variable */
1057 classification
[1024],
1058 /* CLASSIFICATION environment variable */
1060 /* CONTENT_TYPE environment variable */
1062 /* DEVICE_URI environment variable */
1063 ppd
[1024], /* PPD environment variable */
1065 /* PRINTER environment variable */
1066 root
[1024], /* CUPS_SERVERROOT environment variable */
1067 cache
[255], /* RIP_MAX_CACHE environment variable */
1068 tmpdir
[1024], /* TMPDIR environment variable */
1069 ldpath
[1024], /* LD_LIBRARY_PATH environment variable */
1070 nlspath
[1024], /* NLSPATH environment variable */
1071 datadir
[1024], /* CUPS_DATADIR environment variable */
1072 fontpath
[1050]; /* CUPS_FONTPATH environment variable */
1075 LogMessage(L_DEBUG
, "StartJob(%d, %p)", id
, printer
);
1077 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
1078 if (current
->id
== id
)
1081 if (current
== NULL
)
1084 LogMessage(L_DEBUG
, "StartJob() id = %d, file = %d/%d", id
,
1085 current
->current_file
, current
->num_files
);
1087 if (current
->num_files
== 0)
1089 LogMessage(L_ERROR
, "Job ID %d has no files! Cancelling it!", id
);
1095 * Figure out what filters are required to convert from
1096 * the source to the destination type...
1102 if (printer
->type
& CUPS_PRINTER_REMOTE
)
1105 * Remote jobs go directly to the remote job...
1113 * Local jobs get filtered...
1116 filters
= mimeFilter(MimeDatabase
, current
->filetypes
[current
->current_file
],
1117 printer
->filetype
, &num_filters
);
1119 if (num_filters
== 0)
1121 LogMessage(L_ERROR
, "Unable to convert file %d to printable format for job %d!",
1122 current
->current_file
, current
->id
);
1123 current
->current_file
++;
1125 if (current
->current_file
== current
->num_files
)
1126 CancelJob(current
->id
, 0);
1132 * Remove NULL ("-") filters...
1135 for (i
= 0; i
< num_filters
;)
1136 if (strcmp(filters
[i
].filter
, "-") == 0)
1139 if (i
< num_filters
)
1140 memcpy(filters
+ i
, filters
+ i
+ 1,
1141 (num_filters
- i
) * sizeof(mime_filter_t
));
1146 if (num_filters
== 0)
1154 * Compute filter cost...
1157 for (i
= 0; i
< num_filters
; i
++)
1158 current
->cost
+= filters
[i
].cost
;
1163 * See if the filter cost is too high...
1166 if ((FilterLevel
+ current
->cost
) > FilterLimit
&& FilterLevel
> 0 &&
1170 * Don't print this job quite yet...
1173 if (filters
!= NULL
)
1176 LogMessage(L_INFO
, "Holding job %d because filter limit has been reached.",
1178 LogMessage(L_DEBUG
, "StartJob: id = %d, file = %d, "
1179 "cost = %d, level = %d, limit = %d",
1180 id
, current
->current_file
, current
->cost
, FilterLevel
,
1185 FilterLevel
+= current
->cost
;
1188 * Update the printer and job state to "processing"...
1191 current
->state
->values
[0].integer
= IPP_JOB_PROCESSING
;
1192 current
->status
= 0;
1193 current
->printer
= printer
;
1194 printer
->job
= current
;
1195 SetPrinterState(printer
, IPP_PRINTER_PROCESSING
);
1197 if (current
->current_file
== 0)
1198 set_time(current
, "time-at-processing");
1201 * Determine if we are printing a banner page or not...
1204 if (current
->job_sheets
== NULL
)
1206 LogMessage(L_DEBUG
, "No job-sheets attribute.");
1207 if ((current
->job_sheets
=
1208 ippFindAttribute(current
->attrs
, "job-sheets", IPP_TAG_ZERO
)) != NULL
)
1209 LogMessage(L_DEBUG
, "... but someone added one without setting job_sheets!");
1211 else if (current
->job_sheets
->num_values
== 1)
1212 LogMessage(L_DEBUG
, "job-sheets=%s",
1213 current
->job_sheets
->values
[0].string
.text
);
1215 LogMessage(L_DEBUG
, "job-sheets=%s,%s",
1216 current
->job_sheets
->values
[0].string
.text
,
1217 current
->job_sheets
->values
[1].string
.text
);
1219 if (printer
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
))
1221 else if (current
->job_sheets
== NULL
)
1223 else if (strcasecmp(current
->job_sheets
->values
[0].string
.text
, "none") != 0 &&
1224 current
->current_file
== 0)
1226 else if (current
->job_sheets
->num_values
> 1 &&
1227 strcasecmp(current
->job_sheets
->values
[1].string
.text
, "none") != 0 &&
1228 current
->current_file
== (current
->num_files
- 1))
1233 LogMessage(L_DEBUG
, "banner_page = %d", banner_page
);
1236 * Building the options string is harder than it needs to be, but
1237 * for the moment we need to pass strings for command-line args and
1238 * not IPP attribute pointers... :)
1244 snprintf(title
, sizeof(title
), "%s-%d", printer
->name
, current
->id
);
1245 strcpy(copies
, "1");
1247 for (attr
= current
->attrs
->attrs
; attr
!= NULL
; attr
= attr
->next
)
1249 if (strcmp(attr
->name
, "copies") == 0 &&
1250 attr
->value_tag
== IPP_TAG_INTEGER
)
1253 * Don't use the # copies attribute if we are printing the job sheets...
1257 sprintf(copies
, "%d", attr
->values
[0].integer
);
1259 else if (strcmp(attr
->name
, "job-name") == 0 &&
1260 (attr
->value_tag
== IPP_TAG_NAME
||
1261 attr
->value_tag
== IPP_TAG_NAMELANG
))
1263 strncpy(title
, attr
->values
[0].string
.text
, sizeof(title
) - 1);
1264 title
[sizeof(title
) - 1] = '\0';
1266 else if (attr
->group_tag
== IPP_TAG_JOB
)
1269 * Filter out other unwanted attributes...
1272 if (attr
->value_tag
== IPP_TAG_MIMETYPE
||
1273 attr
->value_tag
== IPP_TAG_NAMELANG
||
1274 attr
->value_tag
== IPP_TAG_TEXTLANG
||
1275 attr
->value_tag
== IPP_TAG_URI
||
1276 attr
->value_tag
== IPP_TAG_URISCHEME
)
1279 if (strncmp(attr
->name
, "time-", 5) == 0)
1282 if (strncmp(attr
->name
, "job-", 4) == 0 &&
1283 !(printer
->type
& CUPS_PRINTER_REMOTE
))
1286 if (strncmp(attr
->name
, "job-", 4) == 0 &&
1287 strcmp(attr
->name
, "job-billing") != 0 &&
1288 strcmp(attr
->name
, "job-sheets") != 0 &&
1289 strcmp(attr
->name
, "job-hold-until") != 0 &&
1290 strcmp(attr
->name
, "job-priority") != 0)
1293 if (strcmp(attr
->name
, "page-label") == 0 &&
1298 * Otherwise add them to the list...
1301 if (optptr
> options
)
1302 strncat(optptr
, " ", sizeof(options
) - (optptr
- options
) - 1);
1304 if (attr
->value_tag
!= IPP_TAG_BOOLEAN
)
1306 strncat(optptr
, attr
->name
, sizeof(options
) - (optptr
- options
) - 1);
1307 strncat(optptr
, "=", sizeof(options
) - (optptr
- options
) - 1);
1310 for (i
= 0; i
< attr
->num_values
; i
++)
1313 strncat(optptr
, ",", sizeof(options
) - (optptr
- options
) - 1);
1315 optptr
+= strlen(optptr
);
1317 switch (attr
->value_tag
)
1319 case IPP_TAG_INTEGER
:
1321 snprintf(optptr
, sizeof(options
) - (optptr
- options
) - 1,
1322 "%d", attr
->values
[i
].integer
);
1325 case IPP_TAG_BOOLEAN
:
1326 if (!attr
->values
[i
].boolean
)
1327 strncat(optptr
, "no", sizeof(options
) - (optptr
- options
) - 1);
1329 case IPP_TAG_NOVALUE
:
1330 strncat(optptr
, attr
->name
,
1331 sizeof(options
) - (optptr
- options
) - 1);
1334 case IPP_TAG_RANGE
:
1335 if (attr
->values
[i
].range
.lower
== attr
->values
[i
].range
.upper
)
1336 snprintf(optptr
, sizeof(options
) - (optptr
- options
) - 1,
1337 "%d", attr
->values
[i
].range
.lower
);
1339 snprintf(optptr
, sizeof(options
) - (optptr
- options
) - 1,
1340 "%d-%d", attr
->values
[i
].range
.lower
,
1341 attr
->values
[i
].range
.upper
);
1344 case IPP_TAG_RESOLUTION
:
1345 snprintf(optptr
, sizeof(options
) - (optptr
- options
) - 1,
1346 "%dx%d%s", attr
->values
[i
].resolution
.xres
,
1347 attr
->values
[i
].resolution
.yres
,
1348 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
1352 case IPP_TAG_STRING
:
1355 case IPP_TAG_KEYWORD
:
1356 case IPP_TAG_CHARSET
:
1357 case IPP_TAG_LANGUAGE
:
1358 if (strchr(attr
->values
[i
].string
.text
, ' ') != NULL
||
1359 strchr(attr
->values
[i
].string
.text
, '\t') != NULL
||
1360 strchr(attr
->values
[i
].string
.text
, '\n') != NULL
)
1362 strncat(optptr
, "\'", sizeof(options
) - (optptr
- options
) - 1);
1363 strncat(optptr
, attr
->values
[i
].string
.text
,
1364 sizeof(options
) - (optptr
- options
) - 1);
1365 strncat(optptr
, "\'", sizeof(options
) - (optptr
- options
) - 1);
1368 strncat(optptr
, attr
->values
[i
].string
.text
,
1369 sizeof(options
) - (optptr
- options
) - 1);
1373 break; /* anti-compiler-warning-code */
1377 optptr
+= strlen(optptr
);
1382 * Build the command-line arguments for the filters. Each filter
1383 * has 6 or 7 arguments:
1387 * argv[2] = username
1389 * argv[4] = # copies
1391 * argv[6] = filename (optional; normally stdin)
1393 * This allows legacy printer drivers that use the old System V
1394 * printing interface to be used by CUPS.
1397 sprintf(jobid
, "%d", current
->id
);
1398 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
,
1399 current
->id
, current
->current_file
+ 1);
1401 argv
[0] = printer
->name
;
1403 argv
[2] = current
->username
;
1410 LogMessage(L_DEBUG
, "StartJob: argv = \"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
1411 argv
[0], argv
[1], argv
[2], argv
[3], argv
[4], argv
[5], argv
[6]);
1414 * Create environment variable strings for the filters...
1417 attr
= ippFindAttribute(current
->attrs
, "attributes-natural-language",
1420 switch (strlen(attr
->values
[0].string
.text
))
1424 * This is an unknown or badly formatted language code; use
1425 * the POSIX locale...
1428 strcpy(language
, "LANG=C");
1433 * Just the language code (ll)...
1436 snprintf(language
, sizeof(language
), "LANG=%s",
1437 attr
->values
[0].string
.text
);
1442 * Language and country code (ll-cc)...
1445 snprintf(language
, sizeof(language
), "LANG=%c%c_%c%c",
1446 attr
->values
[0].string
.text
[0],
1447 attr
->values
[0].string
.text
[1],
1448 toupper(attr
->values
[0].string
.text
[3]),
1449 toupper(attr
->values
[0].string
.text
[4]));
1453 attr
= ippFindAttribute(current
->attrs
, "document-format",
1456 (optptr
= strstr(attr
->values
[0].string
.text
, "charset=")) != NULL
)
1457 snprintf(charset
, sizeof(charset
), "CHARSET=%s", optptr
+ 8);
1460 attr
= ippFindAttribute(current
->attrs
, "attributes-charset",
1462 snprintf(charset
, sizeof(charset
), "CHARSET=%s",
1463 attr
->values
[0].string
.text
);
1466 snprintf(path
, sizeof(path
), "PATH=%s/filter:/bin:/usr/bin", ServerBin
);
1467 snprintf(content_type
, sizeof(content_type
), "CONTENT_TYPE=%s/%s",
1468 current
->filetypes
[current
->current_file
]->super
,
1469 current
->filetypes
[current
->current_file
]->type
);
1470 snprintf(device_uri
, sizeof(device_uri
), "DEVICE_URI=%s", printer
->device_uri
);
1471 snprintf(ppd
, sizeof(ppd
), "PPD=%s/ppd/%s.ppd", ServerRoot
, printer
->name
);
1472 snprintf(printer_name
, sizeof(printer_name
), "PRINTER=%s", printer
->name
);
1473 snprintf(cache
, sizeof(cache
), "RIP_MAX_CACHE=%s", RIPCache
);
1474 snprintf(root
, sizeof(root
), "CUPS_SERVERROOT=%s", ServerRoot
);
1475 snprintf(tmpdir
, sizeof(tmpdir
), "TMPDIR=%s", TempDir
);
1476 snprintf(datadir
, sizeof(datadir
), "CUPS_DATADIR=%s", DataDir
);
1477 snprintf(fontpath
, sizeof(fontpath
), "CUPS_FONTPATH=%s", FontPath
);
1479 if (Classification
[0] && !banner_page
)
1481 if ((attr
= ippFindAttribute(current
->attrs
, "job-sheets",
1482 IPP_TAG_NAME
)) == NULL
)
1483 snprintf(classification
, sizeof(classification
), "CLASSIFICATION=%s",
1485 else if (attr
->num_values
> 1 &&
1486 strcmp(attr
->values
[1].string
.text
, "none") != 0)
1487 snprintf(classification
, sizeof(classification
), "CLASSIFICATION=%s",
1488 attr
->values
[1].string
.text
);
1490 snprintf(classification
, sizeof(classification
), "CLASSIFICATION=%s",
1491 attr
->values
[0].string
.text
);
1494 classification
[0] = '\0';
1496 if (getenv("LD_LIBRARY_PATH") != NULL
)
1497 snprintf(ldpath
, sizeof(ldpath
), "LD_LIBRARY_PATH=%s",
1498 getenv("LD_LIBRARY_PATH"));
1499 else if (getenv("DYLD_LIBRARY_PATH") != NULL
)
1500 snprintf(ldpath
, sizeof(ldpath
), "DYLD_LIBRARY_PATH=%s",
1501 getenv("DYLD_LIBRARY_PATH"));
1505 if (getenv("NLSPATH") != NULL
)
1506 snprintf(nlspath
, sizeof(nlspath
), "NLSPATH=%s", getenv("NLSPATH"));
1511 envp
[1] = "SOFTWARE=CUPS/1.1";
1512 envp
[2] = "USER=root";
1520 envp
[10] = content_type
;
1521 envp
[11] = device_uri
;
1522 envp
[12] = printer_name
;
1524 envp
[14] = fontpath
;
1527 envp
[17] = classification
;
1530 LogMessage(L_DEBUG
, "StartJob: envp = \"%s\",\"%s\",\"%s\",\"%s\","
1531 "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\","
1532 "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
1533 envp
[0], envp
[1], envp
[2], envp
[3], envp
[4],
1534 envp
[5], envp
[6], envp
[7], envp
[8], envp
[9],
1535 envp
[10], envp
[11], envp
[12], envp
[13], envp
[14],
1536 envp
[15], envp
[16], envp
[17]);
1538 current
->current_file
++;
1541 * Make sure we have a buffer to read status info into...
1544 if (current
->buffer
== NULL
)
1546 LogMessage(L_DEBUG2
, "UpdateJob: Allocating status buffer...");
1548 if ((current
->buffer
= malloc(JOB_BUFFER_SIZE
)) == NULL
)
1550 LogMessage(L_EMERG
, "Unable to allocate memory for job status buffer - %s",
1552 CancelJob(current
->id
, 0);
1556 current
->bufused
= 0;
1560 * Now create processes for all of the filters...
1563 if (pipe(statusfds
))
1565 LogMessage(L_ERROR
, "Unable to create job status pipes - %s.",
1567 snprintf(printer
->state_message
, sizeof(printer
->state_message
),
1568 "Unable to create status pipes - %s.", strerror(errno
));
1572 LogMessage(L_DEBUG
, "StartJob: statusfds = %d, %d",
1573 statusfds
[0], statusfds
[1]);
1575 current
->pipe
= statusfds
[0];
1576 current
->status
= 0;
1577 memset(current
->procs
, 0, sizeof(current
->procs
));
1579 filterfds
[1][0] = open("/dev/null", O_RDONLY
);
1580 filterfds
[1][1] = -1;
1582 LogMessage(L_DEBUG
, "StartJob: filterfds[%d] = %d, %d", 1, filterfds
[1][0],
1585 for (i
= 0, slot
= 0; i
< num_filters
; i
++)
1587 if (filters
[i
].filter
[0] != '/')
1588 snprintf(command
, sizeof(command
), "%s/filter/%s", ServerBin
,
1592 strncpy(command
, filters
[i
].filter
, sizeof(command
) - 1);
1593 command
[sizeof(command
) - 1] = '\0';
1596 if (i
< (num_filters
- 1) ||
1597 strncmp(printer
->device_uri
, "file:", 5) != 0)
1598 pipe(filterfds
[slot
]);
1601 filterfds
[slot
][0] = -1;
1602 if (strncmp(printer
->device_uri
, "file:/dev/", 10) == 0)
1603 filterfds
[slot
][1] = open(printer
->device_uri
+ 5,
1606 filterfds
[slot
][1] = open(printer
->device_uri
+ 5,
1607 O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
1610 LogMessage(L_DEBUG
, "StartJob: filter = \"%s\"", command
);
1611 LogMessage(L_DEBUG
, "StartJob: filterfds[%d] = %d, %d",
1612 slot
, filterfds
[slot
][0], filterfds
[slot
][1]);
1614 pid
= start_process(command
, argv
, envp
, filterfds
[!slot
][0],
1615 filterfds
[slot
][1], statusfds
[1], 0);
1617 close(filterfds
[!slot
][0]);
1618 close(filterfds
[!slot
][1]);
1622 LogMessage(L_ERROR
, "Unable to start filter \"%s\" - %s.",
1623 filters
[i
].filter
, strerror(errno
));
1624 snprintf(printer
->state_message
, sizeof(printer
->state_message
),
1625 "Unable to start filter \"%s\" - %s.",
1626 filters
[i
].filter
, strerror(errno
));
1630 current
->procs
[i
] = pid
;
1632 LogMessage(L_INFO
, "Started filter %s (PID %d) for job %d.",
1633 command
, pid
, current
->id
);
1639 if (filters
!= NULL
)
1643 * Finally, pipe the final output into a backend process if needed...
1646 if (strncmp(printer
->device_uri
, "file:", 5) != 0)
1648 sscanf(printer
->device_uri
, "%254[^:]", method
);
1649 snprintf(command
, sizeof(command
), "%s/backend/%s", ServerBin
, method
);
1651 argv
[0] = printer
->device_uri
;
1653 filterfds
[slot
][0] = -1;
1654 filterfds
[slot
][1] = open("/dev/null", O_WRONLY
);
1656 LogMessage(L_DEBUG
, "StartJob: backend = \"%s\"", command
);
1657 LogMessage(L_DEBUG
, "StartJob: filterfds[%d] = %d, %d",
1658 slot
, filterfds
[slot
][0], filterfds
[slot
][1]);
1660 pid
= start_process(command
, argv
, envp
, filterfds
[!slot
][0],
1661 filterfds
[slot
][1], statusfds
[1], 1);
1663 close(filterfds
[!slot
][0]);
1664 close(filterfds
[!slot
][1]);
1668 LogMessage(L_ERROR
, "Unable to start backend \"%s\" - %s.",
1669 method
, strerror(errno
));
1670 snprintf(printer
->state_message
, sizeof(printer
->state_message
),
1671 "Unable to start backend \"%s\" - %s.", method
, strerror(errno
));
1676 current
->procs
[i
] = pid
;
1678 LogMessage(L_INFO
, "Started backend %s (PID %d) for job %d.", command
, pid
,
1684 filterfds
[slot
][0] = -1;
1685 filterfds
[slot
][1] = -1;
1687 close(filterfds
[!slot
][0]);
1688 close(filterfds
[!slot
][1]);
1691 close(filterfds
[slot
][0]);
1692 close(filterfds
[slot
][1]);
1694 close(statusfds
[1]);
1696 LogMessage(L_DEBUG2
, "StartJob: Adding fd %d to InputSet...", current
->pipe
);
1698 FD_SET(current
->pipe
, &InputSet
);
1703 * 'StopAllJobs()' - Stop all print jobs.
1709 job_t
*current
; /* Current job */
1712 DEBUG_puts("StopAllJobs()");
1714 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
1715 if (current
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
1717 StopJob(current
->id
, 1);
1718 current
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1724 * 'StopJob()' - Stop a print job.
1728 StopJob(int id
, /* I - Job ID */
1729 int force
) /* I - 1 = Force all filters to stop */
1731 int i
; /* Looping var */
1732 job_t
*current
; /* Current job */
1735 LogMessage(L_DEBUG
, "StopJob: id = %d, force = %d", id
, force
);
1737 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
1738 if (current
->id
== id
)
1740 DEBUG_puts("StopJob: found job in list.");
1742 if (current
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
1744 DEBUG_puts("StopJob: job state is \'processing\'.");
1746 FilterLevel
-= current
->cost
;
1748 if (current
->status
< 0)
1749 SetPrinterState(current
->printer
, IPP_PRINTER_STOPPED
);
1750 else if (current
->printer
->state
!= IPP_PRINTER_STOPPED
)
1751 SetPrinterState(current
->printer
, IPP_PRINTER_IDLE
);
1753 LogMessage(L_DEBUG
, "StopJob: printer state is %d", current
->printer
->state
);
1755 current
->state
->values
[0].integer
= IPP_JOB_STOPPED
;
1756 current
->printer
->job
= NULL
;
1757 current
->printer
= NULL
;
1759 current
->current_file
--;
1761 for (i
= 0; current
->procs
[i
]; i
++)
1762 if (current
->procs
[i
] > 0)
1764 kill(current
->procs
[i
], force
? SIGKILL
: SIGTERM
);
1765 current
->procs
[i
] = 0;
1771 * Close the pipe and clear the input bit.
1774 LogMessage(L_DEBUG2
, "StopJob: Removing fd %d from InputSet...",
1777 close(current
->pipe
);
1778 FD_CLR(current
->pipe
, &InputSet
);
1782 if (current
->buffer
)
1785 * Free the status buffer...
1788 LogMessage(L_DEBUG2
, "StopJob: Freeing status buffer...");
1790 free(current
->buffer
);
1791 current
->buffer
= NULL
;
1792 current
->bufused
= 0;
1801 * 'UpdateJob()' - Read a status update from a job's filters.
1805 UpdateJob(job_t
*job
) /* I - Job to check */
1807 int bytes
; /* Number of bytes read */
1808 int copies
; /* Number of copies printed */
1809 char *lineptr
, /* Pointer to end of line in buffer */
1810 *message
; /* Pointer to message text */
1811 int loglevel
; /* Log level for message */
1814 if ((bytes
= read(job
->pipe
, job
->buffer
+ job
->bufused
,
1815 JOB_BUFFER_SIZE
- job
->bufused
- 1)) > 0)
1817 job
->bufused
+= bytes
;
1818 job
->buffer
[job
->bufused
] = '\0';
1819 lineptr
= strchr(job
->buffer
, '\n');
1821 else if (bytes
< 0 && errno
== EINTR
)
1825 lineptr
= job
->buffer
+ job
->bufused
;
1829 if (job
->bufused
== 0 && bytes
== 0)
1832 while (lineptr
!= NULL
)
1835 * Terminate each line and process it...
1841 * Figure out the logging level...
1844 if (strncmp(job
->buffer
, "EMERG:", 6) == 0)
1847 message
= job
->buffer
+ 6;
1849 else if (strncmp(job
->buffer
, "ALERT:", 6) == 0)
1852 message
= job
->buffer
+ 6;
1854 else if (strncmp(job
->buffer
, "CRIT:", 5) == 0)
1857 message
= job
->buffer
+ 5;
1859 else if (strncmp(job
->buffer
, "ERROR:", 6) == 0)
1862 message
= job
->buffer
+ 6;
1864 else if (strncmp(job
->buffer
, "WARNING:", 8) == 0)
1867 message
= job
->buffer
+ 8;
1869 else if (strncmp(job
->buffer
, "NOTICE:", 6) == 0)
1871 loglevel
= L_NOTICE
;
1872 message
= job
->buffer
+ 6;
1874 else if (strncmp(job
->buffer
, "INFO:", 5) == 0)
1877 message
= job
->buffer
+ 5;
1879 else if (strncmp(job
->buffer
, "DEBUG:", 6) == 0)
1882 message
= job
->buffer
+ 6;
1884 else if (strncmp(job
->buffer
, "DEBUG2:", 7) == 0)
1886 loglevel
= L_DEBUG2
;
1887 message
= job
->buffer
+ 7;
1889 else if (strncmp(job
->buffer
, "PAGE:", 5) == 0)
1892 message
= job
->buffer
+ 5;
1897 message
= job
->buffer
;
1901 * Skip leading whitespace in the message...
1904 while (isspace(*message
))
1908 * Send it to the log file and printer state message as needed...
1911 if (loglevel
== L_PAGE
)
1914 * Page message; send the message to the page_log file and update the
1915 * job sheet count...
1918 if (job
->sheets
!= NULL
)
1920 if (!sscanf(message
, "%*d%d", &copies
))
1922 job
->sheets
->values
[0].integer
++;
1924 if (job
->printer
->page_limit
)
1925 UpdateQuota(job
->printer
, job
->username
, 1, 0);
1929 job
->sheets
->values
[0].integer
+= copies
;
1931 if (job
->printer
->page_limit
)
1932 UpdateQuota(job
->printer
, job
->username
, copies
, 0);
1936 LogPage(job
, message
);
1941 * Other status message; send it to the error_log file...
1944 if (loglevel
!= L_INFO
)
1945 LogMessage(loglevel
, "%s", message
);
1947 if ((loglevel
== L_INFO
&& !job
->status
) ||
1949 strncpy(job
->printer
->state_message
, message
,
1950 sizeof(job
->printer
->state_message
) - 1);
1954 * Copy over the buffer data we've used up...
1957 strcpy(job
->buffer
, lineptr
);
1958 job
->bufused
-= lineptr
- job
->buffer
;
1960 if (job
->bufused
< 0)
1963 lineptr
= strchr(job
->buffer
, '\n');
1968 LogMessage(L_DEBUG
, "UpdateJob: job %d, file %d is complete.",
1969 job
->id
, job
->current_file
- 1);
1974 * Close the pipe and clear the input bit.
1977 LogMessage(L_DEBUG2
, "UpdateJob: Removing fd %d from InputSet...",
1981 FD_CLR(job
->pipe
, &InputSet
);
1985 if (job
->status
< 0)
1988 * Backend had errors; stop it...
1991 StopJob(job
->id
, 0);
1992 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1995 else if (job
->status
> 0)
1998 * Filter had errors; cancel it...
2001 if (job
->current_file
< job
->num_files
)
2002 StartJob(job
->id
, job
->printer
);
2005 CancelJob(job
->id
, 0);
2009 job
->state
->values
[0].integer
= IPP_JOB_ABORTED
;
2019 * Job printed successfully; cancel it...
2022 if (job
->current_file
< job
->num_files
)
2024 FilterLevel
-= job
->cost
;
2025 StartJob(job
->id
, job
->printer
);
2029 CancelJob(job
->id
, 0);
2033 job
->state
->values
[0].integer
= IPP_JOB_COMPLETED
;
2045 * 'ipp_read_file()' - Read an IPP request from a file.
2048 static ipp_state_t
/* O - State */
2049 ipp_read_file(const char *filename
, /* I - File to read from */
2050 ipp_t
*ipp
) /* I - Request to read into */
2052 int fd
; /* File descriptor for file */
2053 int n
; /* Length of data */
2054 unsigned char buffer
[8192], /* Data buffer */
2055 *bufptr
; /* Pointer into buffer */
2056 ipp_attribute_t
*attr
; /* Current attribute */
2057 ipp_tag_t tag
; /* Current tag */
2061 * Open the file if possible...
2064 if (filename
== NULL
|| ipp
== NULL
)
2067 if ((fd
= open(filename
, O_RDONLY
)) == -1)
2071 * Read the IPP request...
2074 ipp
->state
= IPP_IDLE
;
2079 break; /* anti-compiler-warning-code */
2082 ipp
->state
++; /* Avoid common problem... */
2086 * Get the request header...
2089 if ((n
= read(fd
, buffer
, 8)) < 8)
2091 DEBUG_printf(("ipp_read_file: Unable to read header (%d bytes read)!\n", n
));
2093 return (n
== 0 ? IPP_IDLE
: IPP_ERROR
);
2097 * Verify the major version number...
2102 DEBUG_printf(("ipp_read_file: version number (%d.%d) is bad.\n", buffer
[0],
2109 * Then copy the request header over...
2112 ipp
->request
.any
.version
[0] = buffer
[0];
2113 ipp
->request
.any
.version
[1] = buffer
[1];
2114 ipp
->request
.any
.op_status
= (buffer
[2] << 8) | buffer
[3];
2115 ipp
->request
.any
.request_id
= (((((buffer
[4] << 8) | buffer
[5]) << 8) |
2116 buffer
[6]) << 8) | buffer
[7];
2118 ipp
->state
= IPP_ATTRIBUTE
;
2119 ipp
->current
= NULL
;
2120 ipp
->curtag
= IPP_TAG_ZERO
;
2122 case IPP_ATTRIBUTE
:
2123 while (read(fd
, buffer
, 1) > 0)
2126 * Read this attribute...
2129 tag
= (ipp_tag_t
)buffer
[0];
2131 if (tag
== IPP_TAG_END
)
2134 * No more attributes left...
2137 DEBUG_puts("ipp_read_file: IPP_TAG_END!");
2139 ipp
->state
= IPP_DATA
;
2142 else if (tag
< IPP_TAG_UNSUPPORTED_VALUE
)
2145 * Group tag... Set the current group and continue...
2148 if (ipp
->curtag
== tag
)
2149 ippAddSeparator(ipp
);
2152 ipp
->current
= NULL
;
2153 DEBUG_printf(("ipp_read_file: group tag = %x\n", tag
));
2157 DEBUG_printf(("ipp_read_file: value tag = %x\n", tag
));
2163 if (read(fd
, buffer
, 2) < 2)
2165 DEBUG_puts("ipp_read_file: unable to read name length!");
2170 n
= (buffer
[0] << 8) | buffer
[1];
2172 if (n
> (sizeof(buffer
) - 1))
2174 DEBUG_printf(("ipp_read_file: bad name length %d!\n", n
));
2178 DEBUG_printf(("ipp_read_file: name length = %d\n", n
));
2183 * More values for current attribute...
2186 if (ipp
->current
== NULL
)
2192 attr
= ipp
->current
;
2195 * Finally, reallocate the attribute array as needed...
2198 if ((attr
->num_values
% IPP_MAX_VALUES
) == 0)
2200 ipp_attribute_t
*temp
, /* Pointer to new buffer */
2201 *ptr
; /* Pointer in attribute list */
2205 * Reallocate memory...
2208 if ((temp
= realloc(attr
, sizeof(ipp_attribute_t
) +
2209 (attr
->num_values
+ IPP_MAX_VALUES
- 1) *
2210 sizeof(ipp_value_t
))) == NULL
)
2217 * Reset pointers in the list...
2220 for (ptr
= ipp
->attrs
; ptr
&& ptr
->next
!= attr
; ptr
= ptr
->next
);
2227 attr
= ipp
->current
= ipp
->last
= temp
;
2233 * New attribute; read the name and add it...
2236 if (read(fd
, buffer
, n
) < n
)
2238 DEBUG_puts("ipp_read_file: unable to read name!");
2244 DEBUG_printf(("ipp_read_file: name = \'%s\'\n", buffer
));
2246 attr
= ipp
->current
= _ipp_add_attr(ipp
, IPP_MAX_VALUES
);
2248 attr
->group_tag
= ipp
->curtag
;
2249 attr
->value_tag
= tag
;
2250 attr
->name
= strdup((char *)buffer
);
2251 attr
->num_values
= 0;
2254 if (read(fd
, buffer
, 2) < 2)
2256 DEBUG_puts("ipp_read_file: unable to read value length!");
2261 n
= (buffer
[0] << 8) | buffer
[1];
2262 DEBUG_printf(("ipp_read_file: value length = %d\n", n
));
2266 case IPP_TAG_INTEGER
:
2268 if (read(fd
, buffer
, 4) < 4)
2274 n
= (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2277 attr
->values
[attr
->num_values
].integer
= n
;
2279 case IPP_TAG_BOOLEAN
:
2280 if (read(fd
, buffer
, 1) < 1)
2286 attr
->values
[attr
->num_values
].boolean
= buffer
[0];
2290 case IPP_TAG_KEYWORD
:
2291 case IPP_TAG_STRING
:
2293 case IPP_TAG_URISCHEME
:
2294 case IPP_TAG_CHARSET
:
2295 case IPP_TAG_LANGUAGE
:
2296 case IPP_TAG_MIMETYPE
:
2297 if (read(fd
, buffer
, n
) < n
)
2304 DEBUG_printf(("ipp_read_file: value = \'%s\'\n", buffer
));
2306 attr
->values
[attr
->num_values
].string
.text
= strdup((char *)buffer
);
2309 if (read(fd
, buffer
, 11) < 11)
2315 memcpy(attr
->values
[attr
->num_values
].date
, buffer
, 11);
2317 case IPP_TAG_RESOLUTION
:
2318 if (read(fd
, buffer
, 9) < 9)
2324 attr
->values
[attr
->num_values
].resolution
.xres
=
2325 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2327 attr
->values
[attr
->num_values
].resolution
.yres
=
2328 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
2330 attr
->values
[attr
->num_values
].resolution
.units
=
2331 (ipp_res_t
)buffer
[8];
2333 case IPP_TAG_RANGE
:
2334 if (read(fd
, buffer
, 8) < 8)
2340 attr
->values
[attr
->num_values
].range
.lower
=
2341 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2343 attr
->values
[attr
->num_values
].range
.upper
=
2344 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
2347 case IPP_TAG_TEXTLANG
:
2348 case IPP_TAG_NAMELANG
:
2349 if (n
> sizeof(buffer
))
2351 DEBUG_printf(("ipp_read_file: bad value length %d!\n", n
));
2355 if (read(fd
, buffer
, n
) < n
)
2361 * text-with-language and name-with-language are composite
2370 n
= (bufptr
[0] << 8) | bufptr
[1];
2372 attr
->values
[attr
->num_values
].string
.charset
= calloc(n
+ 1, 1);
2374 memcpy(attr
->values
[attr
->num_values
].string
.charset
,
2378 n
= (bufptr
[0] << 8) | bufptr
[1];
2380 attr
->values
[attr
->num_values
].string
.text
= calloc(n
+ 1, 1);
2382 memcpy(attr
->values
[attr
->num_values
].string
.text
,
2387 default : /* Other unsupported values */
2388 attr
->values
[attr
->num_values
].unknown
.length
= n
;
2391 attr
->values
[attr
->num_values
].unknown
.data
= malloc(n
);
2392 if (read(fd
, attr
->values
[attr
->num_values
].unknown
.data
, n
) < n
)
2396 attr
->values
[attr
->num_values
].unknown
.data
= NULL
;
2400 attr
->num_values
++;
2409 * Close the file and return...
2414 return (ipp
->state
);
2419 * 'ipp_write_file()' - Write an IPP request to a file.
2422 static ipp_state_t
/* O - State */
2423 ipp_write_file(const char *filename
, /* I - File to write to */
2424 ipp_t
*ipp
) /* I - Request to write */
2426 int fd
; /* File descriptor */
2427 int i
; /* Looping var */
2428 int n
; /* Length of data */
2429 unsigned char buffer
[8192], /* Data buffer */
2430 *bufptr
; /* Pointer into buffer */
2431 ipp_attribute_t
*attr
; /* Current attribute */
2435 * Open the file if possible...
2438 if (filename
== NULL
|| ipp
== NULL
)
2441 if ((fd
= open(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600)) == -1)
2445 fchown(fd
, User
, Group
);
2448 * Write the IPP request...
2451 ipp
->state
= IPP_IDLE
;
2456 break; /* anti-compiler-warning-code */
2459 ipp
->state
++; /* Avoid common problem... */
2463 * Send the request header...
2468 *bufptr
++ = ipp
->request
.any
.version
[0];
2469 *bufptr
++ = ipp
->request
.any
.version
[1];
2470 *bufptr
++ = ipp
->request
.any
.op_status
>> 8;
2471 *bufptr
++ = ipp
->request
.any
.op_status
;
2472 *bufptr
++ = ipp
->request
.any
.request_id
>> 24;
2473 *bufptr
++ = ipp
->request
.any
.request_id
>> 16;
2474 *bufptr
++ = ipp
->request
.any
.request_id
>> 8;
2475 *bufptr
++ = ipp
->request
.any
.request_id
;
2477 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2479 DEBUG_puts("ipp_write_file: Could not write IPP header...");
2484 ipp
->state
= IPP_ATTRIBUTE
;
2485 ipp
->current
= ipp
->attrs
;
2486 ipp
->curtag
= IPP_TAG_ZERO
;
2488 case IPP_ATTRIBUTE
:
2489 while (ipp
->current
!= NULL
)
2492 * Write this attribute...
2496 attr
= ipp
->current
;
2498 ipp
->current
= ipp
->current
->next
;
2500 if (ipp
->curtag
!= attr
->group_tag
)
2503 * Send a group operation tag...
2506 ipp
->curtag
= attr
->group_tag
;
2508 if (attr
->group_tag
== IPP_TAG_ZERO
)
2511 DEBUG_printf(("ipp_write_file: wrote group tag = %x\n", attr
->group_tag
));
2512 *bufptr
++ = attr
->group_tag
;
2515 if ((n
= strlen(attr
->name
)) > (sizeof(buffer
) - 3))
2518 DEBUG_printf(("ipp_write_file: writing value tag = %x\n", attr
->value_tag
));
2519 DEBUG_printf(("ipp_write_file: writing name = %d, \'%s\'\n", n
, attr
->name
));
2521 *bufptr
++ = attr
->value_tag
;
2524 memcpy(bufptr
, attr
->name
, n
);
2527 switch (attr
->value_tag
)
2529 case IPP_TAG_INTEGER
:
2531 for (i
= 0; i
< attr
->num_values
; i
++)
2533 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 9)
2535 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2537 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2547 * Arrays and sets are done by sending additional
2548 * values with a zero-length name...
2551 *bufptr
++ = attr
->value_tag
;
2558 *bufptr
++ = attr
->values
[i
].integer
>> 24;
2559 *bufptr
++ = attr
->values
[i
].integer
>> 16;
2560 *bufptr
++ = attr
->values
[i
].integer
>> 8;
2561 *bufptr
++ = attr
->values
[i
].integer
;
2565 case IPP_TAG_BOOLEAN
:
2566 for (i
= 0; i
< attr
->num_values
; i
++)
2568 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 6)
2570 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2572 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2582 * Arrays and sets are done by sending additional
2583 * values with a zero-length name...
2586 *bufptr
++ = attr
->value_tag
;
2593 *bufptr
++ = attr
->values
[i
].boolean
;
2599 case IPP_TAG_KEYWORD
:
2600 case IPP_TAG_STRING
:
2602 case IPP_TAG_URISCHEME
:
2603 case IPP_TAG_CHARSET
:
2604 case IPP_TAG_LANGUAGE
:
2605 case IPP_TAG_MIMETYPE
:
2606 for (i
= 0; i
< attr
->num_values
; i
++)
2611 * Arrays and sets are done by sending additional
2612 * values with a zero-length name...
2615 DEBUG_printf(("ipp_write_file: writing value tag = %x\n",
2617 DEBUG_printf(("ipp_write_file: writing name = 0, \'\'\n"));
2619 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 3)
2621 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2623 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2630 *bufptr
++ = attr
->value_tag
;
2635 n
= strlen(attr
->values
[i
].string
.text
);
2637 if (n
> sizeof(buffer
))
2640 DEBUG_printf(("ipp_write_file: writing string = %d, \'%s\'\n", n
,
2641 attr
->values
[i
].string
.text
));
2643 if ((sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
2645 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2647 DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
2657 memcpy(bufptr
, attr
->values
[i
].string
.text
, n
);
2663 for (i
= 0; i
< attr
->num_values
; i
++)
2665 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 16)
2667 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2669 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2679 * Arrays and sets are done by sending additional
2680 * values with a zero-length name...
2683 *bufptr
++ = attr
->value_tag
;
2690 memcpy(bufptr
, attr
->values
[i
].date
, 11);
2695 case IPP_TAG_RESOLUTION
:
2696 for (i
= 0; i
< attr
->num_values
; i
++)
2698 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 14)
2700 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2702 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2712 * Arrays and sets are done by sending additional
2713 * values with a zero-length name...
2716 *bufptr
++ = attr
->value_tag
;
2723 *bufptr
++ = attr
->values
[i
].resolution
.xres
>> 24;
2724 *bufptr
++ = attr
->values
[i
].resolution
.xres
>> 16;
2725 *bufptr
++ = attr
->values
[i
].resolution
.xres
>> 8;
2726 *bufptr
++ = attr
->values
[i
].resolution
.xres
;
2727 *bufptr
++ = attr
->values
[i
].resolution
.yres
>> 24;
2728 *bufptr
++ = attr
->values
[i
].resolution
.yres
>> 16;
2729 *bufptr
++ = attr
->values
[i
].resolution
.yres
>> 8;
2730 *bufptr
++ = attr
->values
[i
].resolution
.yres
;
2731 *bufptr
++ = attr
->values
[i
].resolution
.units
;
2735 case IPP_TAG_RANGE
:
2736 for (i
= 0; i
< attr
->num_values
; i
++)
2738 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 13)
2740 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2742 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2752 * Arrays and sets are done by sending additional
2753 * values with a zero-length name...
2756 *bufptr
++ = attr
->value_tag
;
2763 *bufptr
++ = attr
->values
[i
].range
.lower
>> 24;
2764 *bufptr
++ = attr
->values
[i
].range
.lower
>> 16;
2765 *bufptr
++ = attr
->values
[i
].range
.lower
>> 8;
2766 *bufptr
++ = attr
->values
[i
].range
.lower
;
2767 *bufptr
++ = attr
->values
[i
].range
.upper
>> 24;
2768 *bufptr
++ = attr
->values
[i
].range
.upper
>> 16;
2769 *bufptr
++ = attr
->values
[i
].range
.upper
>> 8;
2770 *bufptr
++ = attr
->values
[i
].range
.upper
;
2774 case IPP_TAG_TEXTLANG
:
2775 case IPP_TAG_NAMELANG
:
2776 for (i
= 0; i
< attr
->num_values
; i
++)
2781 * Arrays and sets are done by sending additional
2782 * values with a zero-length name...
2785 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 3)
2787 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2789 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2796 *bufptr
++ = attr
->value_tag
;
2801 n
= strlen(attr
->values
[i
].string
.charset
) +
2802 strlen(attr
->values
[i
].string
.text
) +
2805 if (n
> sizeof(buffer
))
2808 if ((sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
2810 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2812 DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
2819 /* Length of entire value */
2823 /* Length of charset */
2824 n
= strlen(attr
->values
[i
].string
.charset
);
2829 memcpy(bufptr
, attr
->values
[i
].string
.charset
, n
);
2832 /* Length of text */
2833 n
= strlen(attr
->values
[i
].string
.text
);
2838 memcpy(bufptr
, attr
->values
[i
].string
.text
, n
);
2844 for (i
= 0; i
< attr
->num_values
; i
++)
2849 * Arrays and sets are done by sending additional
2850 * values with a zero-length name...
2853 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 3)
2855 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2857 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2864 *bufptr
++ = attr
->value_tag
;
2869 n
= attr
->values
[i
].unknown
.length
;
2871 if (n
> sizeof(buffer
))
2874 if ((sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
2876 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2878 DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
2885 /* Length of unknown value */
2892 memcpy(bufptr
, attr
->values
[i
].unknown
.data
, n
);
2900 * Write the data out...
2903 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2905 DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
2910 DEBUG_printf(("ipp_write_file: wrote %d bytes\n", bufptr
- buffer
));
2913 if (ipp
->current
== NULL
)
2916 * Done with all of the attributes; add the end-of-attributes tag...
2919 buffer
[0] = IPP_TAG_END
;
2920 if (write(fd
, (char *)buffer
, 1) < 0)
2922 DEBUG_puts("ipp_write_file: Could not write IPP end-tag...");
2927 ipp
->state
= IPP_DATA
;
2936 * Close the file and return...
2941 return (ipp
->state
);
2946 * 'set_time()' - Set one of the "time-at-xyz" attributes...
2950 set_time(job_t
*job
, /* I - Job to update */
2951 const char *name
) /* I - Name of attribute */
2953 ipp_attribute_t
*attr
; /* Time attribute */
2956 if ((attr
= ippFindAttribute(job
->attrs
, name
, IPP_TAG_ZERO
)) != NULL
)
2958 attr
->value_tag
= IPP_TAG_INTEGER
;
2959 attr
->values
[0].integer
= time(NULL
);
2965 * 'start_process()' - Start a background process.
2968 static int /* O - Process ID or 0 */
2969 start_process(const char *command
, /* I - Full path to command */
2970 char *argv
[], /* I - Command-line arguments */
2971 char *envp
[], /* I - Environment */
2972 int infd
, /* I - Standard input file descriptor */
2973 int outfd
, /* I - Standard output file descriptor */
2974 int errfd
, /* I - Standard error file descriptor */
2975 int root
) /* I - Run as root? */
2977 int fd
; /* Looping var */
2978 int pid
; /* Process ID */
2981 LogMessage(L_DEBUG
, "start_process(\"%s\", %p, %p, %d, %d, %d)",
2982 command
, argv
, envp
, infd
, outfd
, errfd
);
2984 if ((pid
= fork()) == 0)
2987 * Child process goes here...
2989 * Update stdin/stdout/stderr as needed...
3003 * Close extra file descriptors...
3006 for (fd
= 3; fd
< MaxFDs
; fd
++)
3010 * Change user to something "safe"...
3013 if (!root
&& getuid() == 0)
3016 * Running as root, so change to non-priviledged user...
3027 * Reset group membership to just the main one we belong to.
3033 * Change umask to restrict permissions on created files...
3039 * Execute the command; if for some reason this doesn't work,
3040 * return the error code...
3043 execve(command
, argv
, envp
);
3052 * Error - couldn't fork a new process!
3055 LogMessage(L_ERROR
, "Unable to fork %s - %s.", command
, strerror(errno
));
3065 * End of "$Id: job.c,v 1.153 2002/05/15 01:52:18 mike Exp $".