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