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