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