xref: /illumos-gate/usr/src/cmd/lp/lib/papi/job.c (revision c1ecd8b9404ee0d96d93f02e82c441b9bb149a3d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*LINTLIBRARY*/
29 
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <libintl.h>
34 #include <pwd.h>
35 #include <sys/stat.h>
36 #include <papi_impl.h>
37 
38 
39 /*
40  * for an older application that may have been linked with a pre-v1.0
41  * PAPI implementation.
42  */
43 papi_status_t
44 papiAttributeListAdd(papi_attribute_t ***attrs, int flags, char *name,
45 		papi_attribute_value_type_t type, papi_attribute_value_t *value)
46 {
47 	return (papiAttributeListAddValue(attrs, flags, name, type, value));
48 }
49 
50 #ifdef LP_USE_PAPI_ATTR
51 static papi_status_t psm_modifyAttrsFile(papi_attribute_t **attrs, char *file);
52 static papi_status_t psm_modifyAttrsList(char *file, papi_attribute_t **attrs,
53 					papi_attribute_t ***newAttrs);
54 #endif
55 
56 
57 void
58 papiJobFree(papi_job_t job)
59 {
60 	job_t *tmp = (job_t *)job;
61 
62 	if (tmp != NULL) {
63 		papiAttributeListFree(tmp->attributes);
64 		free(tmp);
65 	}
66 }
67 
68 void
69 papiJobListFree(papi_job_t *jobs)
70 {
71 	if (jobs != NULL) {
72 		int i;
73 
74 		for (i = 0; jobs[i] != NULL; i++) {
75 			papiJobFree(jobs[i]);
76 		}
77 		free(jobs);
78 	}
79 }
80 
81 papi_attribute_t **
82 papiJobGetAttributeList(papi_job_t job)
83 {
84 	job_t *tmp = (job_t *)job;
85 
86 	if (tmp != NULL)
87 		return (tmp->attributes);
88 
89 	return (NULL);
90 }
91 
92 char *
93 papiJobGetPrinterName(papi_job_t job)
94 {
95 	job_t *tmp = (job_t *)job;
96 	char *result = NULL;
97 
98 	if (tmp != NULL)
99 		papiAttributeListGetString(tmp->attributes, NULL,
100 					"printer-name", &result);
101 
102 	return (result);
103 }
104 
105 int32_t
106 papiJobGetId(papi_job_t job)
107 {
108 	job_t *tmp = (job_t *)job;
109 	int result = -1;
110 
111 	if (tmp != NULL)
112 		papiAttributeListGetInteger(tmp->attributes, NULL, "job-id",
113 					&result);
114 
115 	return (result);
116 }
117 
118 static REQUEST *
119 create_request(papi_service_t svc, char *printer, papi_attribute_t **attributes)
120 {
121 	REQUEST *r;
122 
123 	if ((r = calloc(1, sizeof (*r))) != NULL) {
124 		r->priority = -1;
125 		r->destination = printer_name_from_uri_id(printer, -1);
126 		job_attributes_to_lpsched_request(svc, r, attributes);
127 	}
128 
129 	return (r);
130 }
131 
132 static papi_status_t
133 authorized(service_t *svc, int32_t id)
134 {
135 	papi_status_t result = PAPI_NOT_AUTHORIZED;	/* assume the worst */
136 	char file[32];
137 	REQUEST *r;
138 
139 	snprintf(file, sizeof (file), "%d-0", id);
140 	if ((r = getrequest(file)) != NULL) {
141 		uid_t uid = getuid();
142 		struct passwd *pw = NULL;
143 		char *user = "intruder";	/* assume an intruder */
144 
145 		if ((pw = getpwuid(uid)) != NULL)
146 			user = pw->pw_name;	/* use the process owner */
147 
148 		if ((uid == 0) || (uid == 71)) { /* root/lp can forge this */
149 			papi_status_t s;
150 			s = papiAttributeListGetString(svc->attributes, NULL,
151 					"user-name", &user);
152 			if (s != PAPI_OK)	/* true root/lp are almighty */
153 				result = PAPI_OK;
154 		}
155 
156 		if ((result != PAPI_OK) && (strcmp(user, r->user) == 0))
157 			result = PAPI_OK;
158 
159 		freerequest(r);
160 	} else
161 		result = PAPI_NOT_FOUND;
162 
163 	return (result);
164 }
165 
166 static papi_status_t
167 copy_file(char *from, char *to)
168 {
169 	int ifd, ofd;
170 	char buf[BUFSIZ];
171 	int rc;
172 
173 	if ((ifd = open(from, O_RDONLY)) < 0)
174 		return (PAPI_DOCUMENT_ACCESS_ERROR);
175 
176 	if ((ofd = open(to, O_WRONLY)) < 0) {
177 		close(ifd);
178 		return (PAPI_NOT_POSSIBLE);
179 	}
180 
181 	while ((rc = read(ifd, buf, sizeof (buf))) > 0)
182 		write(ofd, buf, rc);
183 
184 	close(ifd);
185 	close(ofd);
186 
187 	return (PAPI_OK);
188 }
189 
190 
191 #ifdef LP_USE_PAPI_ATTR
192 /*
193  * *****************************************************************************
194  *
195  * Description: Create a file containing all the attributes in the attribute
196  *              list passed to this function.
197  *              This file is then passed through lpsched and given to either
198  *              a slow-filter or to the printer's interface script to process
199  *              the attributes.
200  *
201  * Parameters:  attrs - list of attributes and their values
202  *              file  - file pathname to create and put the attributes into.
203  *
204  * *****************************************************************************
205  */
206 
207 static papi_status_t
208 psm_copy_attrsToFile(papi_attribute_t **attrs, char *file)
209 
210 {
211 	papi_status_t result = PAPI_OK;
212 
213 	if ((attrs != NULL) && (*attrs != NULL)) {
214 		FILE *out = NULL;
215 
216 		if ((out = fopen(file, "w")) != NULL) {
217 			papiAttributeListPrint(out, attrs, "");
218 			fclose(out);
219 		} else {
220 			result = PAPI_NOT_POSSIBLE;
221 		}
222 	}
223 
224 	return (result);
225 } /* psm_copy_attrsToFile */
226 
227 
228 /*
229  * *****************************************************************************
230  *
231  * Description: Modify the given attribute 'file' with the attributes from the
232  *              'attrs' list. Attributes already in the file will be replaced
233  *              with the new value. New attributes will be added into the file.
234  *
235  * Parameters:  attrs - list of attributes and their values
236  *              file  - file pathname to create and put the attributes into.
237  *
238  * *****************************************************************************
239  */
240 
241 static papi_status_t
242 psm_modifyAttrsFile(papi_attribute_t **attrs, char *file)
243 
244 {
245 	papi_status_t result = PAPI_OK;
246 	papi_attribute_t **newAttrs = NULL;
247 	struct stat   tmpBuf;
248 	FILE *fd = NULL;
249 
250 	if ((attrs != NULL) && (*attrs != NULL) && (file != NULL)) {
251 
252 		/*
253 		 * check file exist before try to modify it, if it doesn't
254 		 * exist assume there is an error
255 		 */
256 		if (stat(file, &tmpBuf) == 0) {
257 			/*
258 			 * if file is currently empty just write the given
259 			 * attributes to the file otherwise exact the attributes
260 			 * from the file and modify them accordingly before
261 			 * writing them back to the file
262 			 */
263 			if (tmpBuf.st_size == 0) {
264 				newAttrs = (papi_attribute_t **)attrs;
265 
266 				fd = fopen(file, "w");
267 				if (fd != NULL) {
268 					papiAttributeListPrint(fd,
269 							newAttrs, "");
270 					fclose(fd);
271 				} else {
272 					result = PAPI_NOT_POSSIBLE;
273 				}
274 			} else {
275 				result =
276 				    psm_modifyAttrsList(file, attrs, &newAttrs);
277 
278 				fd = fopen(file, "w");
279 				if (fd != NULL) {
280 					papiAttributeListPrint(fd,
281 								newAttrs, "");
282 					fclose(fd);
283 				} else {
284 					result = PAPI_NOT_POSSIBLE;
285 				}
286 
287 				papiAttributeListFree(newAttrs);
288 			}
289 		} else {
290 			result = PAPI_NOT_POSSIBLE;
291 		}
292 	}
293 
294 	return (result);
295 } /* psm_modifyAttrsFile */
296 
297 
298 /*
299  * *****************************************************************************
300  *
301  * Description: Extracts the attributes in the given attribute 'file' and
302  *              creates a new list 'newAttrs' containing the modified list of
303  *              attributes.
304  *
305  * Parameters:  file  - pathname of file containing attributes to be modified
306  *              attrs - list of attributes and their values to modify
307  *              newAttrs - returns the modified list of attributes
308  *
309  * *****************************************************************************
310  */
311 
312 static papi_status_t
313 psm_modifyAttrsList(char *file, papi_attribute_t **attrs,
314     papi_attribute_t ***newAttrs)
315 
316 {
317 	papi_status_t result = PAPI_OK;
318 	papi_attribute_t  *nextAttr = NULL;
319 	papi_attribute_value_t  **values = NULL;
320 	void *iter = NULL;
321 	FILE *fd = NULL;
322 	register int fD = 0;
323 	char aBuff[200];
324 	char *a = NULL;
325 	char *p = NULL;
326 	int count = 0;
327 	int n = 0;
328 
329 	fd = fopen(file, "r");
330 	if (fd != NULL) {
331 		fD = fileno(fd);
332 		a = &aBuff[0];
333 		p = &aBuff[0];
334 		count = read(fD, &aBuff[0], sizeof (aBuff) - 1);
335 		while ((result == PAPI_OK) && (count > 0)) {
336 			aBuff[count+n] = '\0';
337 			if (count == sizeof (aBuff) - n - 1) {
338 				p = strrchr(aBuff, '\n');
339 				if (p != NULL) {
340 					/* terminate at last complete line */
341 					*p = '\0';
342 				}
343 			}
344 			result = papiAttributeListFromString(
345 				newAttrs, PAPI_ATTR_EXCL, aBuff);
346 
347 			if (result == PAPI_OK) {
348 				/*
349 				 * handle any part lines and then read the next
350 				 * buffer from the file
351 				 */
352 				n = 0;
353 				if (p != a) {
354 					p++; /* skip NL */
355 					n = sizeof (aBuff) - 1 - (p - a);
356 					strncpy(aBuff, p, n);
357 				}
358 				count = read(fD, &aBuff[n],
359 					sizeof (aBuff) - n - 1);
360 				p = &aBuff[0];
361 			}
362 		}
363 		fclose(fd);
364 	}
365 
366 	/* now modify the attribute list with the new attributes in 'attrs' */
367 
368 	nextAttr = papiAttributeListGetNext((papi_attribute_t **)attrs, &iter);
369 	while ((result == PAPI_OK) && (nextAttr != NULL)) {
370 		values = nextAttr->values;
371 
372 		if ((values != NULL) && (*values != NULL)) {
373 			result = papiAttributeListAddValue(newAttrs,
374 						    PAPI_ATTR_REPLACE,
375 						    nextAttr->name,
376 						    nextAttr->type, *values);
377 			values++;
378 		}
379 
380 		while ((result == PAPI_OK) &&
381 			(values != NULL) && (*values != NULL)) {
382 			result = papiAttributeListAddValue(newAttrs,
383 						    PAPI_ATTR_APPEND,
384 						    nextAttr->name,
385 						    nextAttr->type, *values);
386 			values++;
387 		}
388 		nextAttr =
389 		    papiAttributeListGetNext((papi_attribute_t **)attrs, &iter);
390 	}
391 
392 	return (result);
393 } /* papi_modifyAttrsList() */
394 #endif
395 
396 
397 papi_status_t
398 papiJobSubmit(papi_service_t handle, char *printer,
399 		papi_attribute_t **job_attributes,
400 		papi_job_ticket_t *job_ticket,
401 		char **files, papi_job_t *job)
402 {
403 	papi_status_t status;
404 	service_t *svc = handle;
405 	job_t *j;
406 	int file_no;
407 	char *request_id = NULL;
408 	REQUEST *request;
409 	int i;
410 	char *c;
411 	char *tmp = NULL;
412 	char lpfile[BUFSIZ];
413 
414 	if ((svc == NULL) || (printer == NULL) || (files == NULL) ||
415 	    (job == NULL))
416 		return (PAPI_BAD_ARGUMENT);
417 
418 	if (job_ticket != NULL)
419 		return (PAPI_OPERATION_NOT_SUPPORTED);
420 
421 	if (files != NULL)
422 		for (file_no = 0; files[file_no] != NULL; file_no++)
423 			if (access(files[file_no], R_OK) < 0) {
424 				detailed_error(svc,
425 					gettext("Cannot access file: %s: %s"),
426 					files[file_no], strerror(errno));
427 				return (PAPI_BAD_ARGUMENT);
428 			}
429 
430 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
431 		return (PAPI_TEMPORARY_ERROR);
432 
433 	/* file_no + 1 for the control file (-0) */
434 	status = lpsched_alloc_files(svc, file_no + 1, &request_id);
435 	if (status != PAPI_OK)
436 		return (status);
437 
438 	request = create_request(svc, (char *)printer,
439 				(papi_attribute_t **)job_attributes);
440 
441 	for (i = 0; files[i] != NULL; i++) {
442 		papi_status_t status;
443 		snprintf(lpfile, sizeof (lpfile), "%s%s-%d",
444 			"/var/spool/lp/temp/", request_id, i+1);
445 		status = copy_file(files[i], lpfile);
446 		if (status != PAPI_OK) {
447 			detailed_error(svc,
448 				gettext("unable to copy: %s -> %s: %s"),
449 				files[i], lpfile, strerror(errno));
450 				freerequest(request);
451 			return (PAPI_DEVICE_ERROR);
452 		}
453 		addlist(&(request->file_list), lpfile);
454 	}
455 
456 #ifdef LP_USE_PAPI_ATTR
457 	/*
458 	 * store the job attributes in the PAPI job attribute file that was
459 	 * created by lpsched_alloc_files(), the attributes will then pass
460 	 * through lpsched and be given to the slow-filters and the printer's
461 	 * interface script to process them
462 	 */
463 	snprintf(lpfile, sizeof (lpfile), "%s%s-%s",
464 		"/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
465 	status = psm_copy_attrsToFile(job_attributes, lpfile);
466 	if (status != PAPI_OK) {
467 		detailed_error(svc, "unable to copy attributes to file: %s: %s",
468 				lpfile, strerror(errno));
469 		return (PAPI_DEVICE_ERROR);
470 	}
471 #endif
472 
473 	/* store the meta-data file */
474 	snprintf(lpfile, sizeof (lpfile), "%s-0", request_id);
475 	if (putrequest(lpfile, request) < 0) {
476 		detailed_error(svc, gettext("unable to save request: %s: %s"),
477 			lpfile, strerror(errno));
478 		freerequest(request);
479 		return (PAPI_DEVICE_ERROR);
480 	}
481 
482 	status = lpsched_commit_job(svc, lpfile, &tmp);
483 	if (status != PAPI_OK) {
484 		unlink(lpfile);
485 		freerequest(request);
486 		return (status);
487 	}
488 
489 	lpsched_request_to_job_attributes(request, j);
490 	freerequest(request);
491 
492 	if ((c = strrchr(tmp, '-')) != NULL)
493 		c++;
494 	papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
495 			"job-id", atoi(c));
496 	papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
497 			"job-uri", tmp);
498 
499 	return (PAPI_OK);
500 }
501 
502 papi_status_t
503 papiJobSubmitByReference(papi_service_t handle, char *printer,
504 		papi_attribute_t **job_attributes,
505 		papi_job_ticket_t *job_ticket,
506 		char **files, papi_job_t *job)
507 {
508 	service_t *svc = handle;
509 	job_t *j;
510 	int file_no;
511 	short status;
512 	char *request_id = NULL;
513 	REQUEST *request;
514 	char *c;
515 	char *tmp = NULL;
516 	char lpfile[BUFSIZ];
517 	char **file_list = NULL;
518 
519 	if ((svc == NULL) || (printer == NULL) || (files == NULL) ||
520 	    (job == NULL))
521 		return (PAPI_BAD_ARGUMENT);
522 
523 	if (job_ticket != NULL)
524 		return (PAPI_OPERATION_NOT_SUPPORTED);
525 
526 	if (files != NULL)
527 		for (file_no = 0; files[file_no] != NULL; file_no++) {
528 			if (access(files[file_no], R_OK) < 0) {
529 				detailed_error(svc,
530 					gettext("Cannot access file: %s: %s"),
531 					files[file_no], strerror(errno));
532 				return (PAPI_DOCUMENT_ACCESS_ERROR);
533 			}
534 			if (files[file_no][0] != '/') {
535 				char path[MAXPATHLEN];
536 
537 				if (getcwd(path, sizeof (path)) == NULL) {
538 					detailed_error(svc, gettext(
539 						"getcwd for file: %s: %s"),
540 						files[file_no],
541 						strerror(errno));
542 					return (PAPI_DOCUMENT_ACCESS_ERROR);
543 				}
544 				strlcat(path, "/", sizeof (path));
545 				if (strlcat(path, files[file_no], sizeof (path))
546 						>= sizeof (path)) {
547 					detailed_error(svc, gettext(
548 						"pathname too long: %s"),
549 						files[file_no]);
550 					return (PAPI_DOCUMENT_ACCESS_ERROR);
551 				}
552 				addlist(&file_list, path);
553 			} else
554 				addlist(&file_list, (char *)files[file_no]);
555 		}
556 
557 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
558 		return (PAPI_TEMPORARY_ERROR);
559 
560 	/* 1 for the control file (-0) */
561 	status = lpsched_alloc_files(svc, 1, &request_id);
562 	if (status != PAPI_OK)
563 		return (status);
564 
565 	request = create_request(svc, (char *)printer,
566 				(papi_attribute_t **)job_attributes);
567 	request->file_list = file_list;
568 
569 #ifdef LP_USE_PAPI_ATTR
570 	/*
571 	 * store the job attributes in the PAPI job attribute file that was
572 	 * created by lpsched_alloc_files(), the attributes will then pass
573 	 * through lpsched and be given to the slow-filters and the printer's
574 	 * interface script to process them
575 	 */
576 	snprintf(lpfile, sizeof (lpfile), "%s%s-%s",
577 		"/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
578 	status = psm_copy_attrsToFile(job_attributes, lpfile);
579 	if (status != PAPI_OK) {
580 		detailed_error(svc, "unable to copy attributes to file: %s: %s",
581 				lpfile, strerror(errno));
582 		return (PAPI_DEVICE_ERROR);
583 	}
584 #endif
585 
586 	/* store the meta-data file */
587 	snprintf(lpfile, sizeof (lpfile), "%s-0", request_id);
588 	if (putrequest(lpfile, request) < 0) {
589 		detailed_error(svc, gettext("unable to save request: %s: %s"),
590 			lpfile, strerror(errno));
591 		freerequest(request);
592 		return (PAPI_DEVICE_ERROR);
593 	}
594 
595 	status = lpsched_commit_job(svc, lpfile, &tmp);
596 	if (status != PAPI_OK) {
597 		unlink(lpfile);
598 		freerequest(request);
599 		return (status);
600 	}
601 
602 	lpsched_request_to_job_attributes(request, j);
603 
604 	freerequest(request);
605 
606 	if ((c = strrchr(tmp, '-')) != NULL)
607 		c++;
608 	papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
609 			"job-id", atoi(c));
610 	papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
611 			"job-uri", tmp);
612 
613 	return (PAPI_OK);
614 }
615 
616 papi_status_t
617 papiJobValidate(papi_service_t handle, char *printer,
618 		papi_attribute_t **job_attributes,
619 		papi_job_ticket_t *job_ticket,
620 		char **files, papi_job_t *job)
621 {
622 	papi_status_t status;
623 	papi_attribute_t **attributes = NULL;
624 	int i;
625 
626 	papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE,
627 			"job-hold-until", "indefinite");
628 	for (i = 0; job_attributes[i]; i++)
629 		list_append(&attributes, job_attributes[i]);
630 
631 	status = papiJobSubmitByReference(handle, printer,
632 				(papi_attribute_t **)attributes,
633 				job_ticket, files, job);
634 	if (status == PAPI_OK) {
635 		int id = papiJobGetId(*job);
636 
637 		if (id != -1)
638 			papiJobCancel(handle, printer, id);
639 	}
640 
641 	attributes[1] = NULL;	/* after attr[0], they are in another list */
642 	papiAttributeListFree(attributes);
643 
644 	return (status);
645 }
646 
647 papi_status_t
648 papiJobStreamOpen(papi_service_t handle, char *printer,
649 		papi_attribute_t **job_attributes,
650 		papi_job_ticket_t *job_ticket, papi_stream_t *stream)
651 {
652 	papi_status_t status;
653 	service_t *svc = handle;
654 	job_stream_t *s = NULL;
655 	char *request_id = NULL;
656 	char lpfile[BUFSIZ];
657 
658 	if ((svc == NULL) || (printer == NULL) || (stream == NULL))
659 		return (PAPI_BAD_ARGUMENT);
660 
661 	if (job_ticket != NULL)
662 		return (PAPI_OPERATION_NOT_SUPPORTED);
663 
664 	if ((*stream = s = calloc(1, sizeof (*s))) == NULL)
665 		return (PAPI_TEMPORARY_ERROR);
666 
667 	/* 1 for data, 1 for the meta-data (-0) */
668 	status = lpsched_alloc_files(svc, 2, &request_id);
669 	if (status != PAPI_OK)
670 		return (status);
671 
672 	s->request = create_request(svc, (char *)printer,
673 				(papi_attribute_t **)job_attributes);
674 	snprintf(lpfile, sizeof (lpfile), "/var/spool/lp/temp/%s-1",
675 							request_id);
676 	s->fd = open(lpfile, O_WRONLY);
677 	addlist(&(s->request->file_list), lpfile);
678 
679 #ifdef LP_USE_PAPI_ATTR
680 	/*
681 	 * store the job attributes in the PAPI job attribute file that was
682 	 * created by lpsched_alloc_files(), the attributes will then pass
683 	 * through lpsched and be given to the slow-filters and the printer's
684 	 * interface script to process them
685 	 */
686 	snprintf(lpfile, sizeof (lpfile), "%s%s-%s",
687 		"/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
688 	status = psm_copy_attrsToFile(job_attributes, lpfile);
689 	if (status != PAPI_OK) {
690 		detailed_error(svc, "unable to copy attributes to file: %s: %s",
691 				lpfile, strerror(errno));
692 		close(s->fd);
693 		free(s);
694 		return (PAPI_DEVICE_ERROR);
695 	}
696 #endif
697 
698 	/* store the meta-data file */
699 	snprintf(lpfile, sizeof (lpfile), "%s-0", request_id);
700 	s->meta_data_file = strdup(lpfile);
701 	if (putrequest(lpfile, s->request) < 0) {
702 		detailed_error(svc, gettext("unable to save request: %s: %s"),
703 			lpfile, strerror(errno));
704 		s->request = NULL;
705 		return (PAPI_DEVICE_ERROR);
706 	}
707 
708 	return (PAPI_OK);
709 }
710 
711 papi_status_t
712 papiJobStreamWrite(papi_service_t handle,
713 		papi_stream_t stream, void *buffer, size_t buflen)
714 {
715 	service_t *svc = handle;
716 	job_stream_t *s = stream;
717 
718 	if ((svc == NULL) || (stream == NULL) || (buffer == NULL))
719 		return (PAPI_BAD_ARGUMENT);
720 
721 	if (write(s->fd, buffer, buflen) != buflen)
722 		return (PAPI_DEVICE_ERROR);
723 
724 	return (PAPI_OK);
725 }
726 papi_status_t
727 papiJobStreamClose(papi_service_t handle,
728 		papi_stream_t stream, papi_job_t *job)
729 {
730 	papi_status_t status = PAPI_OK;
731 	service_t *svc = handle;
732 	job_stream_t *s = stream;
733 	job_t *j = NULL;
734 	char *tmp = NULL, *c;
735 
736 	if ((svc == NULL) || (stream == NULL) || (job == NULL))
737 		return (PAPI_BAD_ARGUMENT);
738 
739 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
740 		return (PAPI_TEMPORARY_ERROR);
741 
742 	close(s->fd);
743 
744 	lpsched_request_to_job_attributes(s->request, j);
745 
746 	if (s->meta_data_file != NULL) {
747 		status = lpsched_commit_job(svc, s->meta_data_file, &tmp);
748 		if (status != PAPI_OK) {
749 			unlink(s->meta_data_file);
750 			return (status);
751 		}
752 		if ((c = strrchr(tmp, '-')) != NULL)
753 			c++;
754 		papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
755 			"job-id", atoi(c));
756 		papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
757 			"job-uri", tmp);
758 		free(s->meta_data_file);
759 	}
760 	freerequest(s->request);
761 	free(s);
762 
763 	return (PAPI_OK);
764 }
765 
766 papi_status_t
767 papiJobQuery(papi_service_t handle, char *printer, int32_t job_id,
768 		char **requested_attrs,
769 		papi_job_t *job)
770 {
771 	service_t *svc = handle;
772 	job_t *j;
773 	char *dest;
774 	char req_id[32];
775 	short rc;
776 	char *form = NULL,
777 		*request_id = NULL,
778 		*charset = NULL,
779 		*user = NULL,
780 		*slabel = NULL,
781 		*file = NULL;
782 	time_t date = 0;
783 	size_t size = 0;
784 	short  rank = 0,
785 		state = 0;
786 
787 	if ((handle == NULL) || (printer == NULL) || (job_id < 0))
788 		return (PAPI_BAD_ARGUMENT);
789 
790 	dest = printer_name_from_uri_id(printer, job_id);
791 	snprintf(req_id, sizeof (req_id), "%s-%d", dest, job_id);
792 	free(dest);
793 
794 	rc = snd_msg(svc, S_INQUIRE_REQUEST_RANK, 0, "", "", req_id, "", "");
795 	if (rc < 0)
796 		return (PAPI_SERVICE_UNAVAILABLE);
797 
798 	if (rcv_msg(svc, R_INQUIRE_REQUEST_RANK, &rc, &request_id,
799 			&user, &slabel, &size, &date, &state, &dest, &form,
800 			&charset, &rank, &file) < 0) {
801 		detailed_error(svc,
802 			gettext("failed to read response from scheduler"));
803 		return (PAPI_DEVICE_ERROR);
804 	}
805 
806 	if ((request_id == NULL) || (request_id[0] == NULL))
807 		return (PAPI_NOT_FOUND);
808 
809 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
810 		return (PAPI_TEMPORARY_ERROR);
811 
812 	job_status_to_attributes(j, request_id, user, slabel, size, date, state,
813 				dest, form, charset, rank, file);
814 
815 	snprintf(req_id, sizeof (req_id), "%d-0", job_id);
816 	lpsched_read_job_configuration(svc, j, req_id);
817 
818 	return (PAPI_OK);
819 }
820 
821 papi_status_t
822 papiJobMove(papi_service_t handle, char *printer, int32_t job_id,
823 		char *destination)
824 {
825 	papi_status_t result = PAPI_OK;
826 	service_t *svc = handle;
827 	char req_id[64];
828 	char *queue;
829 	char *user = NULL;
830 
831 	if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
832 	    (destination == NULL))
833 		return (PAPI_BAD_ARGUMENT);
834 
835 	queue = printer_name_from_uri_id(printer, job_id);
836 	snprintf(req_id, sizeof (req_id), "%s-%d", queue, job_id);
837 	free(queue);
838 
839 	if (papiAttributeListGetString(svc->attributes, NULL, "user-name",
840 			&user) == PAPI_OK) {
841 		REQUEST *r = getrequest(req_id);
842 
843 		if ((r != NULL) && (r->user != NULL) &&
844 		    (strcmp(r->user, user) != 0))
845 			result = PAPI_NOT_AUTHORIZED;
846 		freerequest(r);
847 	}
848 
849 	if (result == PAPI_OK) {
850 		short status = MOK;
851 		char *dest = printer_name_from_uri_id(destination, -1);
852 
853 		if ((snd_msg(svc, S_MOVE_REQUEST, req_id, dest) < 0) ||
854 		    (rcv_msg(svc, R_MOVE_REQUEST, &status) < 0))
855 			status = MTRANSMITERR;
856 
857 		free(dest);
858 
859 		result = lpsched_status_to_papi_status(status);
860 	}
861 
862 	return (result);
863 }
864 
865 papi_status_t
866 papiJobCancel(papi_service_t handle, char *printer, int32_t job_id)
867 {
868 	papi_status_t result = PAPI_OK;
869 	service_t *svc = handle;
870 	char req_id[64];
871 	char *dest;
872 	char *user = NULL;
873 
874 	if ((svc == NULL) || (printer == NULL) || (job_id < 0))
875 		return (PAPI_BAD_ARGUMENT);
876 
877 	dest = printer_name_from_uri_id(printer, job_id);
878 	snprintf(req_id, sizeof (req_id), "%s-%d", dest, job_id);
879 	free(dest);
880 
881 	if (papiAttributeListGetString(svc->attributes, NULL, "user-name",
882 			&user) == PAPI_OK) {
883 		REQUEST *r = getrequest(req_id);
884 
885 		if ((r != NULL) && (r->user != NULL) &&
886 		    (strcmp(r->user, user) != 0))
887 			result = PAPI_NOT_AUTHORIZED;
888 		freerequest(r);
889 	}
890 
891 	if (result == PAPI_OK) {
892 		short status = MOK;
893 
894 		if ((snd_msg(svc, S_CANCEL_REQUEST, req_id) < 0) ||
895 		    (rcv_msg(svc, R_CANCEL_REQUEST, &status) < 0))
896 			status = MTRANSMITERR;
897 
898 		result = lpsched_status_to_papi_status(status);
899 	}
900 
901 	return (result);
902 }
903 
904 papi_status_t
905 hold_release_job(papi_service_t handle, char *printer,
906 		int32_t job_id, int flag)
907 {
908 	papi_status_t status;
909 	service_t *svc = handle;
910 	REQUEST *r = NULL;
911 	char *file;
912 	char *dest;
913 
914 	if ((svc == NULL) || (printer == NULL) || (job_id < 0))
915 		return (PAPI_BAD_ARGUMENT);
916 
917 	if ((status = authorized(svc, job_id)) != PAPI_OK)
918 		return (status);
919 
920 	dest = printer_name_from_uri_id(printer, job_id);
921 	status = lpsched_start_change(svc, dest, job_id, &file);
922 	if (status != PAPI_OK)
923 		return (status);
924 
925 	if ((r = getrequest(file)) != NULL) {
926 		r->actions &= ~ACT_RESUME;
927 		switch (flag) {
928 		case 0:
929 			r->actions |= ACT_HOLD;
930 			break;
931 		case 1:
932 			r->actions |= ACT_RESUME;
933 			break;
934 		case 2:
935 			r->actions |= ACT_IMMEDIATE;
936 			break;
937 		}
938 		if (putrequest(file, r) < 0) {
939 			detailed_error(svc,
940 				gettext("failed to write job: %s: %s"),
941 				file, strerror(errno));
942 			freerequest(r);
943 			return (PAPI_DEVICE_ERROR);
944 		}
945 		freerequest(r);
946 	} else {
947 		detailed_error(svc, gettext("failed to read job: %s: %s"),
948 				file, strerror(errno));
949 		return (PAPI_DEVICE_ERROR);
950 	}
951 
952 	status = lpsched_end_change(svc, dest, job_id);
953 
954 	return (status);
955 }
956 
957 papi_status_t
958 papiJobHold(papi_service_t handle, char *printer, int32_t job_id)
959 {
960 	return (hold_release_job(handle, printer, job_id, 0));
961 }
962 
963 papi_status_t
964 papiJobRelease(papi_service_t handle, char *printer, int32_t job_id)
965 {
966 	return (hold_release_job(handle, printer, job_id, 1));
967 }
968 
969 papi_status_t
970 papiJobPromote(papi_service_t handle, char *printer, int32_t job_id)
971 {
972 	return (hold_release_job(handle, printer, job_id, 2));
973 }
974 
975 papi_status_t
976 papiJobModify(papi_service_t handle, char *printer, int32_t job_id,
977 		papi_attribute_t **attributes, papi_job_t *job)
978 {
979 	papi_status_t status;
980 	job_t *j = NULL;
981 	service_t *svc = handle;
982 	char *file = NULL;
983 	char *dest;
984 	REQUEST *r = NULL;
985 	char lpfile[BUFSIZ];
986 
987 	if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
988 	    (attributes == NULL))
989 		return (PAPI_BAD_ARGUMENT);
990 
991 	if ((status = authorized(svc, job_id)) != PAPI_OK)
992 		return (status);
993 
994 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
995 		return (PAPI_TEMPORARY_ERROR);
996 
997 	dest = printer_name_from_uri_id(printer, job_id);
998 	status = lpsched_start_change(svc, dest, job_id, &file);
999 	if (status != PAPI_OK)
1000 		return (status);
1001 
1002 	if ((r = getrequest(file)) != NULL) {
1003 		job_attributes_to_lpsched_request(handle, r,
1004 				(papi_attribute_t **)attributes);
1005 #ifdef LP_USE_PAPI_ATTR
1006 		/*
1007 		 * store the job attributes in the PAPI job attribute file
1008 		 * that was created by the origonal job request. We need to
1009 		 * modify the attributes in the file as per the new attributes
1010 		 */
1011 		snprintf(lpfile, sizeof (lpfile), "%s%d-%s",
1012 			"/var/spool/lp/temp/", job_id, LP_PAPIATTRNAME);
1013 		status = psm_modifyAttrsFile(attributes, lpfile);
1014 		if (status != PAPI_OK) {
1015 			detailed_error(svc,
1016 				"unable to modify the attributes file: %s: %s",
1017 				lpfile, strerror(errno));
1018 			return (PAPI_DEVICE_ERROR);
1019 		}
1020 #endif
1021 
1022 		if (putrequest(file, r) < 0) {
1023 			detailed_error(svc,
1024 				gettext("failed to write job: %s: %s"),
1025 				file, strerror(errno));
1026 			freerequest(r);
1027 			return (PAPI_DEVICE_ERROR);
1028 		}
1029 	} else {
1030 		detailed_error(svc, gettext("failed to read job: %s: %s"),
1031 				file, strerror(errno));
1032 		return (PAPI_DEVICE_ERROR);
1033 	}
1034 
1035 	status = lpsched_end_change(svc, dest, job_id);
1036 	lpsched_request_to_job_attributes(r, j);
1037 
1038 	papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
1039 			"job-id", job_id);
1040 
1041 	freerequest(r);
1042 
1043 	return (status);
1044 }
1045 
1046 /*
1047  * Extension to PAPI, a variation of this is slated for post-1.0
1048  */
1049 #define	DUMMY_FILE	"/var/spool/lp/fifos/FIFO"
1050 
1051 papi_status_t
1052 papiJobCreate(papi_service_t handle, char *printer,
1053 		papi_attribute_t **job_attributes,
1054 		papi_job_ticket_t *job_ticket, papi_job_t *job)
1055 {
1056 	papi_status_t status;
1057 	service_t *svc = handle;
1058 	job_t *j = NULL;
1059 	REQUEST *request;
1060 	char *request_id = NULL;
1061 	char *c;
1062 	char *tmp = NULL;
1063 	char metadata_file[MAXPATHLEN];
1064 
1065 	if ((svc == NULL) || (printer == NULL) || (job == NULL))
1066 		return (PAPI_BAD_ARGUMENT);
1067 
1068 	if (job_ticket != NULL)
1069 		return (PAPI_JOB_TICKET_NOT_SUPPORTED);
1070 
1071 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
1072 		return (PAPI_TEMPORARY_ERROR);
1073 
1074 	/* 1 for the control file (-0) */
1075 	status = lpsched_alloc_files(svc, 1, &request_id);
1076 	if (status != PAPI_OK)
1077 		return (status);
1078 
1079 	/* convert the attributes to an lpsched REQUEST structure */
1080 	request = create_request(svc, (char *)printer,
1081 				(papi_attribute_t **)job_attributes);
1082 	if (request == NULL)
1083 		return (PAPI_TEMPORARY_ERROR);
1084 	addlist(&request->file_list, DUMMY_FILE);	/* add a dummy file */
1085 	request->actions |= ACT_HOLD;			/* hold the job */
1086 
1087 #ifdef LP_USE_PAPI_ATTR
1088 	/*
1089 	 * store the job attributes in the PAPI job attribute file that was
1090 	 * created by lpsched_alloc_files(), the attributes will then pass
1091 	 * through lpsched and be given to the slow-filters and the printer's
1092 	 * interface script to process them
1093 	 */
1094 	snprintf(metadata_file, sizeof (metadata_file), "%s%s-%s",
1095 		"/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
1096 	status = psm_copy_attrsToFile(job_attributes, metadata_file);
1097 	if (status != PAPI_OK) {
1098 		detailed_error(svc, "unable to copy attributes to file: %s: %s",
1099 				metadata_file, strerror(errno));
1100 		free(request_id);
1101 		return (PAPI_DEVICE_ERROR);
1102 	}
1103 #endif
1104 
1105 	/* store the REQUEST on disk */
1106 	snprintf(metadata_file, sizeof (metadata_file), "%s-0", request_id);
1107 	free(request_id);
1108 	if (putrequest(metadata_file, request) < 0) {
1109 		detailed_error(svc, gettext("unable to save request: %s: %s"),
1110 			metadata_file, strerror(errno));
1111 		return (PAPI_DEVICE_ERROR);
1112 	}
1113 
1114 	status = lpsched_commit_job(svc, metadata_file, &tmp);
1115 	if (status != PAPI_OK) {
1116 		unlink(metadata_file);
1117 		return (status);
1118 	}
1119 
1120 	lpsched_request_to_job_attributes(request, j);
1121 
1122 	if ((c = strrchr(tmp, '-')) != NULL)
1123 		c++;
1124 	papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
1125 			"job-id", atoi(c));
1126 	papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
1127 			"job-uri", tmp);
1128 
1129 	return (PAPI_OK);
1130 }
1131 
1132 papi_status_t
1133 papiJobCommit(papi_service_t handle, char *printer, int32_t id)
1134 {
1135 	papi_status_t status = PAPI_OK;
1136 	service_t *svc = handle;
1137 	REQUEST *r = NULL;
1138 	char *metadata_file;
1139 	char *dest;
1140 
1141 	if ((svc == NULL) || (printer == NULL))
1142 		return (PAPI_BAD_ARGUMENT);
1143 
1144 	dest = printer_name_from_uri_id(printer, id);
1145 	/* tell the scheduler that we want to change the job */
1146 	status = lpsched_start_change(svc, dest, id, &metadata_file);
1147 	if (status != PAPI_OK)
1148 		return (status);
1149 
1150 	if ((r = getrequest(metadata_file)) != NULL) {
1151 		r->actions &= ~ACT_RESUME;
1152 		r->actions |= ACT_RESUME;
1153 		dellist(&r->file_list, DUMMY_FILE);
1154 
1155 		if (putrequest(metadata_file, r) < 0) {
1156 			detailed_error(svc,
1157 				gettext("failed to write job: %s: %s"),
1158 				metadata_file, strerror(errno));
1159 			freerequest(r);
1160 			return (PAPI_DEVICE_ERROR);
1161 		}
1162 	} else {
1163 		detailed_error(svc, gettext("failed to read job: %s: %s"),
1164 				metadata_file, strerror(errno));
1165 		return (PAPI_DEVICE_ERROR);
1166 	}
1167 
1168 	status = lpsched_end_change(svc, dest, id);
1169 	freerequest(r);
1170 
1171 	return (status);
1172 }
1173 
1174 papi_status_t
1175 papiJobStreamAdd(papi_service_t handle, char *printer, int32_t id,
1176 		papi_stream_t *stream)
1177 {
1178 	papi_status_t status;
1179 	service_t *svc = handle;
1180 	job_stream_t *s = NULL;
1181 	char *metadata_file = NULL;
1182 	char *dest;
1183 	char path[MAXPATHLEN];
1184 
1185 	/* allocate space for the stream */
1186 	if ((*stream = s = calloc(1, sizeof (*s))) == NULL)
1187 		return (PAPI_TEMPORARY_ERROR);
1188 
1189 	dest = printer_name_from_uri_id(printer, id);
1190 	/* create/open data file (only root or lp can really do this */
1191 	snprintf(path, sizeof (path), "/var/spool/lp/temp/%d-XXXXXX", id);
1192 	if ((s->fd = mkstemp(path)) < 0) {
1193 		detailed_error(svc, gettext("unable to create sink (%s): %s"),
1194 			path, strerror(errno));
1195 		free(s);
1196 		return (PAPI_NOT_AUTHORIZED);
1197 	}
1198 
1199 	/* add data file to job */
1200 	status = lpsched_start_change(svc, dest, id, &metadata_file);
1201 	if (status != PAPI_OK) {
1202 		close(s->fd);
1203 		free(s);
1204 		unlink(path);
1205 		return (status);
1206 	}
1207 
1208 	if ((s->request = getrequest(metadata_file)) == NULL) {
1209 		detailed_error(svc, gettext("unable to load request: %s: %s"),
1210 			metadata_file, strerror(errno));
1211 		close(s->fd);
1212 		free(s);
1213 		unlink(path);
1214 		return (PAPI_NOT_POSSIBLE);
1215 	}
1216 
1217 	addlist(&(s->request->file_list), path);
1218 
1219 	if (putrequest(metadata_file, s->request) < 0) {
1220 		detailed_error(svc, gettext("unable to save request: %s: %s"),
1221 			metadata_file, strerror(errno));
1222 		close(s->fd);
1223 		free(s);
1224 		unlink(path);
1225 		return (PAPI_NOT_POSSIBLE);
1226 	}
1227 
1228 	status = lpsched_end_change(svc, dest, id);
1229 
1230 	if (status != PAPI_OK)
1231 		return (status);
1232 
1233 	return (PAPI_OK);
1234 }
1235