Home | History | Annotate | Download | only in common
      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 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  *
     26  */
     27 
     28 /* $Id: lpd-job.c 157 2006-04-26 15:07:55Z ktou $ */
     29 
     30 
     31 #define	__EXTENSIONS__	/* for strtok_r() */
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <unistd.h>
     35 #include <errno.h>
     36 #include <limits.h>
     37 #include <sys/types.h>
     38 #include <sys/stat.h>
     39 #include <fcntl.h>
     40 #include <string.h>
     41 #include <pwd.h>
     42 #include <libintl.h>
     43 #include <papi_impl.h>
     44 
     45 enum { LPD_RFC, LPD_SVR4 };
     46 
     47 static char
     48 mime_type_to_rfc1179_type(char *mime)
     49 {
     50 	static struct { char *mime; char rfc; } cvt[] = {
     51 		{ "text/plain", 'f' },
     52 		{ "application/octet-stream", 'l' },
     53 		{ "application/postscript", 'f' }, /* rfc incorrectly has 'o' */
     54 		{ "application/x-pr", 'p' },
     55 		{ "application/x-cif", 'c' },
     56 		{ "application/x-dvi", 'd' },
     57 		{ "application/x-fortran", 'r' },
     58 		{ "application/x-plot", 'g' },
     59 		{ "application/x-ditroff", 'n' },
     60 		{ "application/x-troff", 't' },
     61 		{ "application/x-raster", 'v' },
     62 		{ NULL, 0}
     63 	};
     64 	char result = '\0';
     65 
     66 	if (mime != NULL) {
     67 		int i;
     68 
     69 		for (i = 0; cvt[i].mime != NULL; i++)
     70 			if (strcasecmp(cvt[i].mime, mime) == 0) {
     71 				result = cvt[i].rfc;
     72 				break;
     73 			}
     74 	}
     75 
     76 	return (result);
     77 }
     78 
     79 static papi_status_t
     80 add_lpd_control_line(char **metadata, char code, char *value)
     81 {
     82 	size_t size = 0;
     83 	char line[BUFSIZ];
     84 
     85 	if ((metadata == NULL) || (value == NULL))
     86 		return (PAPI_BAD_REQUEST);
     87 
     88 	if (*metadata != NULL)
     89 		size = strlen(*metadata);
     90 	size += strlen(value) + 3;
     91 
     92 	if (*metadata == NULL) {
     93 		*metadata = (char *)calloc(1, size);
     94 	} else {
     95 		void *tmp;
     96 		tmp = calloc(1, size);
     97 		if (tmp) {
     98 			strlcpy(tmp, *metadata, size);
     99 			free(*metadata);
    100 			*metadata = (char *)tmp;
    101 		} else
    102 			return (PAPI_TEMPORARY_ERROR);
    103 	}
    104 
    105 	snprintf(line, sizeof (line), "%c%s\n", code, value);
    106 	strlcat(*metadata, line, size);
    107 
    108 	return (PAPI_OK);
    109 }
    110 
    111 static papi_status_t
    112 add_svr4_control_line(char **metadata, char code, char *value)
    113 {
    114 
    115 	char line[BUFSIZ];
    116 
    117 	if ((metadata == NULL) || (value == NULL))
    118 		return (PAPI_BAD_REQUEST);
    119 
    120 	snprintf(line, sizeof (line), "%c%s", code, value);
    121 
    122 	return (add_lpd_control_line(metadata, '5', line));
    123 }
    124 
    125 static papi_status_t
    126 add_hpux_control_line(char **metadata, char *value)
    127 {
    128 
    129 	char line[BUFSIZ];
    130 
    131 	if ((metadata == NULL) || (value == NULL))
    132 		return (PAPI_BAD_REQUEST);
    133 
    134 	snprintf(line, sizeof (line), " O%s", value);
    135 
    136 	return (add_lpd_control_line(metadata, 'N', line));
    137 }
    138 
    139 static papi_status_t
    140 add_int_control_line(char **metadata, char code, int value, int flag)
    141 {
    142 	char buf[16];
    143 
    144 	snprintf(buf, sizeof (buf), "%d", value);
    145 
    146 	if (flag == LPD_SVR4)
    147 		return (add_svr4_control_line(metadata, code, buf));
    148 	else
    149 		return (add_lpd_control_line(metadata, code, buf));
    150 }
    151 
    152 static papi_status_t
    153 lpd_add_rfc1179_attributes(service_t *svc, papi_attribute_t **attributes,
    154 		char **metadata, papi_attribute_t ***used)
    155 {
    156 	papi_status_t status = PAPI_OK;
    157 	char *s;
    158 	int integer;
    159 	char bool;
    160 	char host[BUFSIZ];
    161 	char *user = "nobody";
    162 	uid_t uid = getuid();
    163 	struct passwd *pw;
    164 	char *h1;
    165 
    166 	if (svc == NULL)
    167 		return (PAPI_BAD_REQUEST);
    168 
    169 	/* There is nothing to do */
    170 	if (attributes == NULL)
    171 		return (PAPI_OK);
    172 
    173 	gethostname(host, sizeof (host));
    174 	if (papiAttributeListGetString(attributes, NULL,
    175 	    "job-originating-host-name", &h1) == PAPI_OK) {
    176 		papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND,
    177 		    "job-host", h1);
    178 	}
    179 	add_lpd_control_line(metadata, 'H', host);
    180 	papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    181 	    "job-originating-host-name", host);
    182 
    183 	if ((pw = getpwuid(uid)) != NULL)
    184 		user = pw->pw_name;
    185 	if (uid == 0)
    186 		papiAttributeListGetString(svc->attributes, NULL, "username",
    187 		    &user);
    188 	add_lpd_control_line(metadata, 'P', user);
    189 	papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    190 	    "job-originating-user-name", user);
    191 
    192 	/* Class for Banner Page */
    193 	s = NULL;
    194 	papiAttributeListGetString(attributes, NULL, "rfc-1179-class", &s);
    195 	if (s != NULL) {
    196 		add_lpd_control_line(metadata, 'C', s);
    197 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    198 		    "rfc-1179-class", s);
    199 	}
    200 
    201 	/* Print Banner Page */
    202 	s = NULL;
    203 	papiAttributeListGetString(attributes, NULL, "job-sheets", &s);
    204 	if ((s != NULL) && (strcmp(s, "standard") == 0)) {
    205 		add_lpd_control_line(metadata, 'L', user);
    206 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    207 		    "job-sheets", s);
    208 	}
    209 
    210 	/* Jobname */
    211 	s = NULL;
    212 	papiAttributeListGetString(attributes, NULL, "job-name", &s);
    213 	if (s != NULL) {
    214 		add_lpd_control_line(metadata, 'J', s);
    215 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    216 		    "job-name", s);
    217 	}
    218 
    219 	/* User to mail when job is done - lpr -m */
    220 	bool = PAPI_FALSE;
    221 	papiAttributeListGetBoolean(attributes, NULL, "rfc-1179-mail", &bool);
    222 	if (bool == PAPI_TRUE) {
    223 		add_lpd_control_line(metadata, 'M', user);
    224 		papiAttributeListAddBoolean(used, PAPI_ATTR_EXCL,
    225 		    "rfc-1179-mail", bool);
    226 	}
    227 
    228 	/* Title for pr */
    229 	s = NULL;
    230 	papiAttributeListGetString(attributes, NULL, "pr-title", &s);
    231 	if (s != NULL) {
    232 		add_lpd_control_line(metadata, 'T', s);
    233 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    234 		    "pr-title", s);
    235 	}
    236 
    237 	/* Indent - used with pr filter */
    238 	integer = 0;
    239 	papiAttributeListGetInteger(attributes, NULL, "pr-indent", &integer);
    240 	if (integer >= 1) {
    241 		add_int_control_line(metadata, 'I', integer, LPD_RFC);
    242 		papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
    243 		    "pr-indent", integer);
    244 	}
    245 
    246 	/* Width - used with pr filter */
    247 	integer = 0;
    248 	papiAttributeListGetInteger(attributes, NULL, "pr-width", &integer);
    249 	if (integer >= 1) {
    250 		add_int_control_line(metadata, 'W', integer, LPD_RFC);
    251 		papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
    252 		    "pr-width", integer);
    253 	}
    254 
    255 	/* file with Times Roman font lpr -1	*/
    256 	s = NULL;
    257 	papiAttributeListGetString(attributes, NULL, "rfc-1179-font-r", &s);
    258 	if (s != NULL) {
    259 		add_lpd_control_line(metadata, '1', s);
    260 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    261 		    "rfc-1179-font-r", s);
    262 	}
    263 
    264 	/* file with Times Roman font lpr -2	*/
    265 	s = NULL;
    266 	papiAttributeListGetString(attributes, NULL, "rfc-1179-font-i", &s);
    267 	if (s != NULL) {
    268 		add_lpd_control_line(metadata, '2', s);
    269 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    270 		    "rfc-1179-font-i", s);
    271 	}
    272 
    273 	/* file with Times Roman font lpr -3	*/
    274 	s = NULL;
    275 	papiAttributeListGetString(attributes, NULL, "rfc-1179-font-b", &s);
    276 	if (s != NULL) {
    277 		add_lpd_control_line(metadata, '3', s);
    278 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    279 		    "rfc-1179-font-b", s);
    280 	}
    281 
    282 	/* file with Times Roman font lpr -4	*/
    283 	s = NULL;
    284 	papiAttributeListGetString(attributes, NULL, "rfc-1179-font-s", &s);
    285 	if (s != NULL) {
    286 		add_lpd_control_line(metadata, '4', s);
    287 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    288 		    "rfc-1179-font-s", s);
    289 	}
    290 
    291 	/*
    292 	 * The document format needs to be added, but the control line
    293 	 * should be added when the filenames are figured out.
    294 	 */
    295 	s = NULL;
    296 	papiAttributeListGetString(attributes, NULL, "document-format", &s);
    297 	if (s != NULL) {
    298 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    299 		    "document-format", s);
    300 	}
    301 
    302 	return (status);
    303 }
    304 
    305 static char *
    306 unused_attributes(papi_attribute_t **list, papi_attribute_t **used)
    307 {
    308 	char *result = NULL;
    309 	char **names = NULL;
    310 	int i;
    311 
    312 	if ((list == NULL) || (used == NULL))
    313 		return (NULL);
    314 
    315 	for (i = 0; used[i] != NULL; i++)
    316 		list_append(&names, used[i]->name);
    317 
    318 	if (names != NULL) {
    319 		papi_attribute_t **unused = NULL;
    320 
    321 		/* add these to the list of things to ignore */
    322 		list_append(&names, "document-format");
    323 		list_append(&names, "copies");
    324 
    325 		split_and_copy_attributes(names, list, NULL, &unused);
    326 		if (unused != NULL) {
    327 			size_t size = 0;
    328 
    329 			do {
    330 				size += 1024;
    331 				if (result != NULL)
    332 					free(result);
    333 				result = calloc(1, size);
    334 			} while (papiAttributeListToString(unused, " ",
    335 			    result, size) != PAPI_OK);
    336 			papiAttributeListFree(unused);
    337 		}
    338 		free(names);
    339 	}
    340 
    341 	return (result);
    342 }
    343 
    344 /*
    345  * lpd_add_svr4_attributes
    346  *	Solaris 2.x LP - BSD protocol extensions
    347  */
    348 static papi_status_t
    349 lpd_add_svr4_attributes(service_t *svc, papi_attribute_t **attributes,
    350 		char **metadata, papi_attribute_t ***used)
    351 {
    352 	papi_attribute_t *tmp[2];
    353 	char *s;
    354 	int integer;
    355 
    356 	if (svc == NULL)
    357 		return (PAPI_BAD_REQUEST);
    358 
    359 	/* media */
    360 	s = NULL;
    361 	papiAttributeListGetString(attributes, NULL, "media", &s);
    362 	if (s != NULL) {
    363 		add_svr4_control_line(metadata, 'f', s);
    364 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    365 		    "media", s);
    366 	}
    367 
    368 	/* Handling */
    369 	s = NULL;
    370 	papiAttributeListGetString(attributes, NULL, "job-hold-until", &s);
    371 	if ((s != NULL) && (strcmp(s, "indefinite") == 0)) {
    372 		add_svr4_control_line(metadata, 'H', "hold");
    373 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    374 		    "job-hold-until", "indefinite");
    375 	} else if ((s != NULL) && (strcmp(s, "no-hold") == 0)) {
    376 		add_svr4_control_line(metadata, 'H', "immediate");
    377 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    378 		    "job-hold-until", "no-hold");
    379 	} else if (s != NULL) {
    380 		add_svr4_control_line(metadata, 'H', s);
    381 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    382 		    "job-hold-until", s);
    383 	}
    384 
    385 	/* Pages */
    386 	s = NULL;
    387 	memset(tmp, NULL, sizeof (tmp));
    388 	tmp[0] = papiAttributeListFind(attributes, "page-ranges");
    389 	if (tmp[0] != NULL) {
    390 		char buf[BUFSIZ];
    391 
    392 		papiAttributeListToString(tmp, " ", buf, sizeof (buf));
    393 		if ((s = strchr(buf, '=')) != NULL) {
    394 			add_svr4_control_line(metadata, 'P', ++s);
    395 			papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    396 			    "page-ranges", s);
    397 		}
    398 	}
    399 
    400 	/* Priority : lp -q */
    401 	integer = -1;
    402 	papiAttributeListGetInteger(attributes, NULL, "job-priority", &integer);
    403 	if (integer != -1) {
    404 		integer = 40 - (integer / 2.5);
    405 		add_int_control_line(metadata, 'q', integer, LPD_SVR4);
    406 		papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
    407 		    "job-priority", integer);
    408 	}
    409 
    410 	/* Charset : lp -S */
    411 	s = NULL;
    412 	papiAttributeListGetString(attributes, NULL, "lp-charset", &s);
    413 	if (s != NULL) {
    414 		add_svr4_control_line(metadata, 'S', s);
    415 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    416 		    "lp-charset", s);
    417 	}
    418 
    419 	/* Type : done when adding file  */
    420 
    421 	/* Mode : lp -y */
    422 	s = NULL;
    423 	papiAttributeListGetString(attributes, NULL, "lp-modes", &s);
    424 	if (s != NULL) {
    425 		add_svr4_control_line(metadata, 'y', s);
    426 		papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    427 		    "lp-modes", s);
    428 	}
    429 
    430 	/* Options lp -o are handled elsewhere */
    431 	if ((s = unused_attributes(attributes, *used)) != NULL) {
    432 		add_lpd_control_line(metadata, 'O', s);
    433 		free(s);
    434 	}
    435 
    436 	return (PAPI_OK);
    437 }
    438 
    439 papi_status_t
    440 lpd_add_hpux_attributes(service_t *svc, papi_attribute_t **attributes,
    441 		char **metadata, papi_attribute_t ***used)
    442 {
    443 	char *s = NULL;
    444 
    445 	/* Options lp -o */
    446 	if ((s = unused_attributes(attributes, *used)) != NULL) {
    447 		add_hpux_control_line(metadata, s);
    448 		free(s);
    449 	}
    450 
    451 	return (PAPI_OK);
    452 }
    453 
    454 papi_status_t
    455 lpd_job_add_attributes(service_t *svc, papi_attribute_t **attributes,
    456 		char **metadata, papi_attribute_t ***used)
    457 {
    458 	if ((svc == NULL) || (metadata == NULL))
    459 		return (PAPI_BAD_REQUEST);
    460 
    461 	lpd_add_rfc1179_attributes(svc, attributes, metadata, used);
    462 
    463 	/* add protocol extensions if applicable */
    464 	if (svc->uri->fragment != NULL) {
    465 		if ((strcasecmp(svc->uri->fragment, "solaris") == 0) ||
    466 		    (strcasecmp(svc->uri->fragment, "svr4") == 0))
    467 			lpd_add_svr4_attributes(svc, attributes, metadata,
    468 			    used);
    469 		else if (strcasecmp(svc->uri->fragment, "hpux") == 0)
    470 			lpd_add_hpux_attributes(svc, attributes, metadata,
    471 			    used);
    472 		/*
    473 		 * others could be added here:
    474 		 *	lprng, sco, aix, digital unix, xerox, ...
    475 		 */
    476 	}
    477 
    478 	return (PAPI_OK);
    479 }
    480 
    481 papi_status_t
    482 lpd_job_add_files(service_t *svc, papi_attribute_t **attributes,
    483 		char **files, char **metadata, papi_attribute_t ***used)
    484 {
    485 	char *format = "text/plain";
    486 	char rfc_fmt = 'l';
    487 	int copies = 1;
    488 	char host[BUFSIZ];
    489 	int i;
    490 
    491 	if ((svc == NULL) || (attributes == NULL) || (files == NULL) ||
    492 	    (metadata == NULL))
    493 		return (PAPI_BAD_ARGUMENT);
    494 
    495 	papiAttributeListGetString(attributes, NULL, "document-format",
    496 	    &format);
    497 	papiAttributeListAddString(used, PAPI_ATTR_EXCL,
    498 	    "document-format", format);
    499 	if ((rfc_fmt = mime_type_to_rfc1179_type(format)) == '\0') {
    500 		if ((svc->uri->fragment != NULL) &&
    501 		    ((strcasecmp(svc->uri->fragment, "solaris") == 0) ||
    502 		    (strcasecmp(svc->uri->fragment, "svr4") == 0)))
    503 			add_svr4_control_line(metadata, 'T', format);
    504 		rfc_fmt = 'l';
    505 	}
    506 
    507 	papiAttributeListGetInteger(attributes, NULL, "copies", &copies);
    508 	if (copies < 1)
    509 		copies = 1;
    510 	papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, "copies", copies);
    511 
    512 	gethostname(host, sizeof (host));
    513 
    514 	for (i = 0; files[i] != NULL; i++) {
    515 		char name[BUFSIZ];
    516 		struct stat statbuf;
    517 		char key;
    518 		int j;
    519 
    520 		if ((strcmp("standard input", files[i]) != 0) &&
    521 		    (access(files[i], R_OK) < 0)) {
    522 			detailed_error(svc, gettext("aborting request, %s: %s"),
    523 			    files[i], strerror(errno));
    524 			return (PAPI_NOT_AUTHORIZED);
    525 		}
    526 		if (strcmp("standard input", files[i]) != 0) {
    527 			if (stat(files[i], &statbuf) < 0) {
    528 				detailed_error(svc,
    529 				    gettext("Cannot access file: %s: %s"),
    530 				    files[i], strerror(errno));
    531 				return (PAPI_DOCUMENT_ACCESS_ERROR);
    532 			}
    533 			if (statbuf.st_size == 0) {
    534 				detailed_error(svc,
    535 				    gettext("Zero byte (empty) file: %s"),
    536 				    files[i]);
    537 				return (PAPI_BAD_ARGUMENT);
    538 			}
    539 		}
    540 
    541 		if (i < 26)
    542 			key = 'A' + i;
    543 		else if (i < 52)
    544 			key = 'a' + (i - 26);
    545 		else if (i < 62)
    546 			key = '0' + (i - 52);
    547 		else {
    548 			detailed_error(svc,
    549 			    gettext("too many files, truncated at 62"));
    550 			return (PAPI_OK_SUBST);
    551 		}
    552 
    553 		snprintf(name, sizeof (name), "df%cXXX%s", key, host);
    554 
    555 		for (j = 0; j < copies; j++)
    556 			add_lpd_control_line(metadata, rfc_fmt, name);
    557 		add_lpd_control_line(metadata, 'U', name);
    558 		add_lpd_control_line(metadata, 'N', (char *)files[i]);
    559 	}
    560 
    561 	return (PAPI_OK);
    562 }
    563 
    564 papi_status_t
    565 lpd_submit_job(service_t *svc, char *metadata, papi_attribute_t ***attributes,
    566 		int *ofd)
    567 {
    568 	papi_status_t status = PAPI_INTERNAL_ERROR;
    569 	int fd;
    570 	char path[32];
    571 	char *list[2];
    572 
    573 	if ((svc == NULL) || (metadata == NULL))
    574 		return (PAPI_BAD_ARGUMENT);
    575 
    576 	strcpy(path, "/tmp/lpd-job-XXXXXX");
    577 	fd = mkstemp(path);
    578 	write(fd, metadata, strlen(metadata));
    579 	close(fd);
    580 
    581 	list[0] = path;
    582 	list[1] = NULL;
    583 
    584 	if (((fd = lpd_open(svc, 's', list, 15)) < 0) && (errno != EBADMSG)) {
    585 		switch (errno) {
    586 		case ENOSPC:
    587 			status = PAPI_TEMPORARY_ERROR;
    588 			break;
    589 		case EIO:
    590 			status = PAPI_TEMPORARY_ERROR;
    591 			break;
    592 		case ECONNREFUSED:
    593 			status = PAPI_SERVICE_UNAVAILABLE;
    594 			break;
    595 		case ENOENT:
    596 			status = PAPI_NOT_ACCEPTING;
    597 			break;
    598 		case EBADMSG:
    599 		case EBADF:
    600 			status = PAPI_OK;
    601 			break;
    602 		default:
    603 			status = PAPI_TIMEOUT;
    604 			break;
    605 		}
    606 	} else
    607 		status = PAPI_OK;
    608 
    609 	if (ofd != NULL)
    610 		*ofd = fd;
    611 	else
    612 		close(fd);
    613 
    614 	/* read the ID and add it to to the job */
    615 	if ((fd = open(path, O_RDONLY)) >= 0) {
    616 		int job_id = 0;
    617 		read(fd, &job_id, sizeof (job_id));
    618 		papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
    619 		    "job-id", job_id);
    620 		close(fd);
    621 	}
    622 
    623 	unlink(path);
    624 
    625 	return (status);
    626 }
    627