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 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
add_svr4_control_line(char ** metadata,char code,char * value)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
add_hpux_control_line(char ** metadata,char * value)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
add_int_control_line(char ** metadata,char code,int value,int flag)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
lpd_add_rfc1179_attributes(service_t * svc,papi_attribute_t ** attributes,char ** metadata,papi_attribute_t *** used)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 *
unused_attributes(papi_attribute_t ** list,papi_attribute_t ** used)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
lpd_add_svr4_attributes(service_t * svc,papi_attribute_t ** attributes,char ** metadata,papi_attribute_t *** used)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
lpd_add_hpux_attributes(service_t * svc,papi_attribute_t ** attributes,char ** metadata,papi_attribute_t *** used)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
lpd_job_add_attributes(service_t * svc,papi_attribute_t ** attributes,char ** metadata,papi_attribute_t *** used)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
lpd_job_add_files(service_t * svc,papi_attribute_t ** attributes,char ** files,char ** metadata,papi_attribute_t *** used)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
lpd_submit_job(service_t * svc,char * metadata,papi_attribute_t *** attributes,int * ofd)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