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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 */ 27 28 /* $Id: common.c 162 2006-05-08 14:17:44Z njacobs $ */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <fcntl.h> 36 #include <alloca.h> 37 #include <string.h> 38 #include <libintl.h> 39 #include <ctype.h> 40 #include <pwd.h> 41 #include <papi.h> 42 #include "common.h" 43 44 #ifndef HAVE_GETPASSPHRASE /* some systems don't have getpassphrase() */ 45 #define getpassphrase getpass 46 #endif 47 48 /* give the most verbose error message to the caller */ 49 char * 50 verbose_papi_message(papi_service_t svc, papi_status_t status) 51 { 52 char *mesg; 53 54 mesg = papiServiceGetStatusMessage(svc); 55 56 if (mesg == NULL) 57 mesg = papiStatusString(status); 58 59 return (mesg); 60 } 61 62 static int 63 match_job(int id, char *user, int ac, char *av[]) 64 { 65 int i; 66 67 for (i = 0; i < ac; i++) 68 if (strcmp("-", av[i]) == 0) 69 return (0); /* "current" user match */ 70 else if ((isdigit(av[i][0]) != 0) && (id == atoi(av[i]))) 71 return (0); /* job-id match */ 72 else if (strcmp(user, av[i]) == 0) 73 return (0); /* user match */ 74 75 return (-1); 76 } 77 78 /* 79 * return 0 : argument passed is job-id && job-id matches 80 * or argument passed is user 81 */ 82 static int 83 match_job_rid(int id, int ac, char *av[]) 84 { 85 int i; 86 87 for (i = 0; i < ac; i++) 88 if (isdigit(av[i][0]) != 0) { 89 if (id == atoi(av[i])) 90 /* job-id match */ 91 return (0); 92 } else 93 /* argument passed is user */ 94 return (0); 95 return (-1); 96 } 97 98 static struct { 99 char *mime_type; 100 char *lp_type; 101 } type_map[] = { 102 { "text/plain", "simple" }, 103 { "application/octet-stream", "raw" }, 104 { "application/octet-stream", "any" }, 105 { "application/postscript", "postscript" }, 106 { "application/postscript", "ps" }, 107 { "application/x-cif", "cif" }, 108 { "application/x-dvi", "dvi" }, 109 { "application/x-plot", "plot" }, 110 { "application/x-ditroff", "troff" }, 111 { "application/x-troff", "otroff" }, 112 { "application/x-pr", "pr" }, 113 { "application/x-fortran", "fortran" }, 114 { "application/x-raster", "raster" }, 115 { NULL, NULL} 116 }; 117 118 char * 119 lp_type_to_mime_type(char *lp_type) 120 { 121 int i; 122 123 if (lp_type == NULL) 124 return ("application/octet-stream"); 125 126 for (i = 0; type_map[i].lp_type != NULL; i++) 127 if (strcasecmp(type_map[i].lp_type, lp_type) == 0) 128 return (type_map[i].mime_type); 129 130 return (lp_type); 131 } 132 133 /* 134 * to support job/printer status 135 */ 136 static char * 137 state_string(int state) 138 { 139 switch (state) { 140 case 3: 141 return (gettext("idle")); 142 case 4: 143 return (gettext("processing")); 144 case 5: 145 return (gettext("stopped")); 146 default: 147 return (gettext("unknown")); 148 } 149 } 150 151 static char *_rank_suffixes[] = { 152 "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 153 }; 154 155 static char * 156 rank_string(const int rank) 157 { 158 static char buf[12]; 159 160 if (rank < 0) 161 snprintf(buf, sizeof (buf), gettext("invalid")); 162 else if (rank == 0) 163 snprintf(buf, sizeof (buf), gettext("active")); 164 else if ((rank > 10) && (rank < 14)) 165 sprintf(buf, "%dth", rank); 166 else 167 sprintf(buf, "%d%s", rank, _rank_suffixes[rank % 10]); 168 169 return (buf); 170 } 171 172 static void 173 printer_state_line(FILE *fp, papi_printer_t p, int num_jobs, char *name) 174 { 175 papi_attribute_t **list = papiPrinterGetAttributeList(p); 176 int state = 0; 177 char *reason = ""; 178 179 (void) papiAttributeListGetInteger(list, NULL, 180 "printer-state", &state); 181 (void) papiAttributeListGetString(list, NULL, 182 "printer-state-reasons", &reason); 183 (void) papiAttributeListGetString(list, NULL, 184 "printer-name", &name); 185 186 if ((state != 0x03) || (num_jobs != 0)) { 187 fprintf(fp, "%s: %s", name, state_string(state)); 188 if ((state == 0x05) || 189 (state == 0x06) || 190 (state == 0x07) || 191 (state == 0x08)) /* stopped */ 192 fprintf(fp, ": %s\n", reason); 193 else 194 fprintf(fp, "\n"); 195 } else 196 fprintf(fp, "no entries\n"); 197 } 198 199 static void 200 print_header(FILE *fp) 201 { 202 fprintf(fp, gettext("Rank\tOwner\t Job\tFile(s)\t\t\t\tTotal Size\n")); 203 } 204 205 static void 206 print_job_line(FILE *fp, int count, papi_job_t job, int fmt, int ac, char *av[]) 207 { 208 papi_attribute_t **list = papiJobGetAttributeList(job); 209 int copies = 1, id = 0, rank = count, size = 0; 210 char *name = "print job"; 211 char *user = "nobody"; 212 char *host = "localhost"; 213 char *suffix = "k"; 214 215 (void) papiAttributeListGetInteger(list, NULL, 216 "job-id", &id); 217 (void) papiAttributeListGetInteger(list, NULL, 218 "job-id-requested", &id); 219 (void) papiAttributeListGetString(list, NULL, 220 "job-originating-user-name", &user); 221 (void) papiAttributeListGetString(list, NULL, 222 "job-originating-host-name", &host); 223 224 /* if we are looking and it doesn't match, return early */ 225 if ((ac > 0) && (match_job(id, user, ac, av) < 0)) 226 return; 227 228 (void) papiAttributeListGetInteger(list, NULL, 229 "copies", &copies); 230 (void) papiAttributeListGetInteger(list, NULL, 231 "number-of-intervening-jobs", &rank); 232 233 if (papiAttributeListGetInteger(list, NULL, "job-octets", &size) 234 == PAPI_OK) 235 suffix = "bytes"; 236 else 237 (void) papiAttributeListGetInteger(list, NULL, 238 "job-k-octets", &size); 239 (void) papiAttributeListGetString(list, NULL, 240 "job-name", &name); 241 242 size *= copies; 243 244 if (fmt == 3) { 245 fprintf(fp, gettext("%s\t%-8.8s %d\t%-32.32s%d %s\n"), 246 rank_string(++rank), user, id, name, size, suffix); 247 } else 248 fprintf(fp, gettext( 249 "\n%s: %s\t\t\t\t[job %d %s]\n\t%-32.32s\t%d %s\n"), 250 user, rank_string(++rank), id, host, name, size, 251 suffix); 252 } 253 254 /* 255 * to support job cancelation 256 */ 257 static void 258 cancel_job(papi_service_t svc, FILE *fp, char *printer, papi_job_t job, 259 int ac, char *av[]) 260 { 261 papi_status_t status; 262 papi_attribute_t **list = papiJobGetAttributeList(job); 263 int id = -1; 264 int rid = -1; 265 char *user = ""; 266 char *mesg = gettext("cancelled"); 267 int i = 0; 268 269 papiAttributeListGetInteger(list, NULL, 270 "job-id", &id); 271 papiAttributeListGetInteger(list, NULL, 272 "job-id-requested", &rid); 273 papiAttributeListGetString(list, NULL, 274 "job-originating-user-name", &user); 275 276 /* if we are looking and it doesn't match, return early */ 277 if ((ac > 0) && (match_job(id, user, ac, av) < 0) && 278 (match_job(rid, user, ac, av) < 0)) 279 return; 280 281 /* 282 * A remote lpd job should be cancelled only based on 283 * job-id-requested 284 */ 285 if (rid != -1) { 286 if (match_job_rid(rid, ac, av) == -1) 287 /* job-id mismatch */ 288 return; 289 } 290 291 status = papiJobCancel(svc, printer, id); 292 if (status != PAPI_OK) 293 mesg = papiStatusString(status); 294 295 if (rid != -1) 296 fprintf(fp, "%s-%d: %s\n", printer, rid, mesg); 297 else 298 fprintf(fp, "%s-%d: %s\n", printer, id, mesg); 299 } 300 301 int 302 berkeley_queue_report(papi_service_t svc, FILE *fp, char *dest, int fmt, 303 int ac, char *av[]) 304 { 305 papi_status_t status; 306 papi_printer_t p = NULL; 307 papi_job_t *jobs = NULL; 308 char *pattrs[] = { "printer-name", "printer-state", 309 "printer-state-reasons", NULL }; 310 char *jattrs[] = { "job-name", "job-octets", "job-k-octets", "job-id", 311 "job-originating-user-name", "job-id-requested", 312 "job-originating-host-name", 313 "number-of-intervening-jobs", NULL }; 314 int num_jobs = 0; 315 316 status = papiPrinterQuery(svc, dest, pattrs, NULL, &p); 317 if (status != PAPI_OK) { 318 fprintf(fp, gettext( 319 "Failed to query service for state of %s: %s\n"), 320 dest, verbose_papi_message(svc, status)); 321 return (-1); 322 } 323 324 status = papiPrinterListJobs(svc, dest, jattrs, PAPI_LIST_JOBS_ALL, 325 0, &jobs); 326 if (status != PAPI_OK) { 327 fprintf(fp, gettext( 328 "Failed to query service for jobs on %s: %s\n"), 329 dest, verbose_papi_message(svc, status)); 330 return (-1); 331 } 332 if (jobs != NULL) { 333 while (jobs[num_jobs] != NULL) 334 num_jobs++; 335 } 336 337 printer_state_line(fp, p, num_jobs, dest); 338 if (num_jobs > 0) { 339 int i; 340 341 if (fmt == 3) 342 print_header(fp); 343 for (i = 0; jobs[i] != NULL; i++) 344 print_job_line(fp, i, jobs[i], fmt, ac, av); 345 } 346 347 papiPrinterFree(p); 348 papiJobListFree(jobs); 349 350 return (num_jobs); 351 } 352 353 int 354 berkeley_cancel_request(papi_service_t svc, FILE *fp, char *dest, 355 int ac, char *av[]) 356 { 357 papi_status_t status; 358 papi_job_t *jobs = NULL; 359 char *jattrs[] = { "job-originating-user-name", "job-id", 360 "job-id-requested", NULL }; 361 362 status = papiPrinterListJobs(svc, dest, jattrs, PAPI_LIST_JOBS_ALL, 363 0, &jobs); 364 365 if (status != PAPI_OK) { 366 fprintf(fp, gettext("Failed to query service for %s: %s\n"), 367 dest, verbose_papi_message(svc, status)); 368 return (-1); 369 } 370 371 /* cancel the job(s) */ 372 if (jobs != NULL) { 373 int i; 374 375 for (i = 0; jobs[i] != NULL; i++) 376 cancel_job(svc, fp, dest, jobs[i], ac, av); 377 } 378 379 papiJobListFree(jobs); 380 381 return (0); 382 } 383 384 int 385 get_printer_id(char *name, char **printer, int *id) 386 { 387 int result = -1; 388 389 if (name != NULL) { 390 char *p = strrchr(name, '-'); 391 392 *printer = name; 393 if (p != NULL) { 394 char *s = NULL; 395 396 *id = strtol(p + 1, &s, 10); 397 if (s[0] != '\0') 398 *id = -1; 399 else 400 *p = '\0'; 401 result = 0; 402 } else 403 *id = -1; 404 } 405 406 return (result); 407 } 408 409 /* 410 * strsplit() splits a string into a NULL terminated array of substrings 411 * determined by a seperator. The original string is modified, and newly 412 * allocated space is only returned for the array itself. If more than 413 * 1024 substrings exist, they will be ignored. 414 */ 415 char ** 416 strsplit(char *string, const char *seperators) 417 { 418 char *list[BUFSIZ], 419 **result; 420 int length = 0; 421 422 if ((string == NULL) || (seperators == NULL)) 423 return (NULL); 424 425 (void) memset(list, 0, sizeof (list)); 426 for (list[length] = strtok(string, seperators); 427 (list[length] != NULL) && (length < (BUFSIZ - 2)); 428 list[length] = strtok(NULL, seperators)) 429 length++; 430 431 if ((result = (char **)calloc(length+1, sizeof (char *))) != NULL) 432 (void) memcpy(result, list, length * sizeof (char *)); 433 434 return (result); 435 } 436 437 papi_status_t 438 jobSubmitSTDIN(papi_service_t svc, char *printer, char *prefetch, int len, 439 papi_attribute_t **list, papi_job_t *job) 440 { 441 papi_status_t status; 442 papi_stream_t stream = NULL; 443 int rc; 444 char buf[BUFSIZ]; 445 446 status = papiJobStreamOpen(svc, printer, list, NULL, &stream); 447 448 if (len > 0) 449 status = papiJobStreamWrite(svc, stream, prefetch, len); 450 451 while ((status == PAPI_OK) && ((rc = read(0, buf, sizeof (buf))) > 0)) 452 status = papiJobStreamWrite(svc, stream, buf, rc); 453 454 if (status == PAPI_OK) 455 status = papiJobStreamClose(svc, stream, job); 456 457 return (status); 458 } 459 460 /* 461 * is_postscript() will detect if the file passed in contains postscript 462 * data. A one is returned if the file contains postscript, zero is returned 463 * if the file is not postscript, and -1 is returned if an error occurs 464 */ 465 #define PS_MAGIC "%!" 466 #define PC_PS_MAGIC "^D%!" 467 int 468 is_postscript_stream(int fd, char *buf, int *len) 469 { 470 if ((*len = read(fd, buf, *len)) < 0) { 471 close(fd); 472 return (-1); 473 } 474 475 if ((strncmp(buf, PS_MAGIC, sizeof (PS_MAGIC) - 1) == 0) || 476 (strncmp(buf, PC_PS_MAGIC, sizeof (PC_PS_MAGIC) - 1) == 0)) 477 return (1); 478 else 479 return (0); 480 } 481 482 int 483 is_postscript(const char *file) 484 { 485 int rc = -1; 486 int fd; 487 488 if ((fd = open(file, O_RDONLY)) >= 0) { 489 char buf[3]; 490 int len = sizeof (buf); 491 492 rc = is_postscript_stream(fd, buf, &len); 493 close(fd); 494 } 495 496 return (rc); 497 } 498 499 static char ** 500 all_list(papi_service_t svc) 501 { 502 papi_status_t status; 503 papi_printer_t printer = NULL; 504 char *list[] = { "member-names", NULL }; 505 char **result = NULL; 506 507 status = papiPrinterQuery(svc, "_all", list, NULL, &printer); 508 if ((status == PAPI_OK) && (printer != NULL)) { 509 papi_attribute_t **attributes = 510 papiPrinterGetAttributeList(printer); 511 if (attributes != NULL) { 512 void *iter = NULL; 513 char *value = NULL; 514 515 for (status = papiAttributeListGetString(attributes, 516 &iter, "member-names", &value); 517 status == PAPI_OK; 518 status = papiAttributeListGetString(attributes, 519 &iter, NULL, &value)) 520 list_append(&result, strdup(value)); 521 } 522 papiPrinterFree(printer); 523 } 524 525 return (result); 526 } 527 528 static char ** 529 printers_list(papi_service_t svc) 530 { 531 papi_status_t status; 532 papi_printer_t *printers = NULL; 533 char *keys[] = { "printer-name", NULL }; 534 char **result = NULL; 535 536 status = papiPrintersList(svc, keys, NULL, &printers); 537 if ((status == PAPI_OK) && (printers != NULL)) { 538 int i; 539 540 for (i = 0; printers[i] != NULL; i++) { 541 papi_attribute_t **attributes = 542 papiPrinterGetAttributeList(printers[i]); 543 char *name = NULL; 544 545 (void) papiAttributeListGetString(attributes, NULL, 546 "printer-name", &name); 547 if ((name != NULL) && (strcmp(name, "_default") != 0)) 548 list_append(&result, strdup(name)); 549 } 550 papiPrinterListFree(printers); 551 } 552 553 return (result); 554 } 555 556 char ** 557 interest_list(papi_service_t svc) 558 { 559 static char been_here; 560 static char **result; 561 562 if (been_here == 0) { /* only do this once */ 563 been_here = 1; 564 565 if ((result = all_list(svc)) == NULL) 566 result = printers_list(svc); 567 } 568 569 return (result); 570 } 571 572 char * 573 localhostname() 574 { 575 static char *result; 576 577 if (result == NULL) { 578 static char buf[256]; 579 580 if (gethostname(buf, sizeof (buf)) == 0) 581 result = buf; 582 } 583 584 return (result); 585 } 586 587 int 588 cli_auth_callback(papi_service_t svc, void *app_data) 589 { 590 char prompt[BUFSIZ]; 591 char *user, *svc_name, *passphrase; 592 593 /* get the name of the service we are contacting */ 594 if ((svc_name = papiServiceGetServiceName(svc)) == NULL) 595 return (-1); 596 597 /* find our who we are supposed to be */ 598 if ((user = papiServiceGetUserName(svc)) == NULL) { 599 struct passwd *pw; 600 601 if ((pw = getpwuid(getuid())) != NULL) 602 user = pw->pw_name; 603 else 604 user = "nobody"; 605 } 606 607 /* build the prompt string */ 608 snprintf(prompt, sizeof (prompt), 609 gettext("passphrase for %s to access %s: "), user, svc_name); 610 611 /* ask for the passphrase */ 612 if ((passphrase = getpassphrase(prompt)) != NULL) 613 papiServiceSetPassword(svc, passphrase); 614 615 return (0); 616 } 617 618 int32_t 619 job_to_be_queried(papi_service_t svc, char *printer, int32_t id) 620 { 621 papi_job_t *jobs = NULL; 622 papi_status_t status; 623 int ret = -1; 624 char *jattrs[] = { "job-id", 625 "job-id-requested", NULL }; 626 627 status = papiPrinterListJobs(svc, printer, jattrs, PAPI_LIST_JOBS_ALL, 628 0, &jobs); 629 630 if (status != PAPI_OK) { 631 fprintf(stderr, gettext("Failed to query service for %s: %s\n"), 632 printer, verbose_papi_message(svc, status)); 633 return (-1); 634 } 635 636 if (jobs != NULL) { 637 int i = 0; 638 639 for (i = 0; jobs[i] != NULL; i++) { 640 int32_t rid = -1; 641 int32_t jid = -1; 642 papi_attribute_t **list = 643 papiJobGetAttributeList(jobs[i]); 644 645 papiAttributeListGetInteger(list, NULL, 646 "job-id-requested", &rid); 647 papiAttributeListGetInteger(list, NULL, 648 "job-id", &jid); 649 650 /* 651 * check if id matches with either rid or jid 652 */ 653 if (rid == id) { 654 /* get the actual id and return it */ 655 papiAttributeListGetInteger(list, NULL, 656 "job-id", &id); 657 return (id); 658 } else if (id == jid) { 659 if (rid != -1) { 660 /* 661 * It is a remote lpd job 662 * can be cancelled only 663 * using rid 664 */ 665 ret = -1; 666 } else { 667 /* 668 * its local or 669 * remote ipp job 670 */ 671 return (id); 672 } 673 } 674 } 675 return (ret); 676 } 677 return (id); 678 } 679