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