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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /*LINTLIBRARY*/ 29 30 #include <stdio.h> 31 #include <stdarg.h> 32 #include <libintl.h> 33 #include <string.h> 34 #include <stdlib.h> 35 #include <errno.h> 36 37 38 /* lpsched include files */ 39 #include "lp.h" 40 #include "msgs.h" 41 #include "printers.h" 42 #include "class.h" 43 44 #include <papi_impl.h> 45 46 47 /* 48 * Format and send message to lpsched (die if any errors occur) 49 */ 50 /*VARARGS1*/ 51 int 52 snd_msg(service_t *svc, int type, ...) 53 { 54 int rc = -1; 55 va_list ap; 56 57 if (svc == NULL) 58 return (-1); 59 60 /* fill the message buffer */ 61 va_start(ap, type); 62 rc = _putmessage(svc->msgbuf, type, ap); 63 va_end(ap); 64 if (rc < 0) { 65 detailed_error(svc, 66 gettext("unable to build message for scheduler: %s"), 67 strerror(errno)); 68 return (rc); 69 } 70 71 /* write the message */ 72 while (((rc = mwrite(svc->md, svc->msgbuf)) < 0) && (errno == EINTR)); 73 74 if (rc < 0) 75 detailed_error(svc, 76 gettext("unable to send message to scheduler: %s"), 77 strerror(errno)); 78 return (rc); 79 } 80 81 /* 82 * Receive message from lpsched (die if any errors occur) 83 */ 84 int 85 rcv_msg(service_t *svc, int type, ...) 86 { 87 int rc = -1; 88 89 if (svc == NULL) 90 return (-1); 91 92 /* read the message */ 93 while (((rc = mread(svc->md, svc->msgbuf, svc->msgbuf_size)) < 0) && 94 (errno == EINTR)); 95 96 if (rc < 0) 97 detailed_error(svc, 98 gettext("unable to read message from scheduler: %s"), 99 strerror(errno)); 100 else { 101 va_list ap; 102 103 va_start(ap, type); 104 rc = _getmessage(svc->msgbuf, type, ap); 105 va_end(ap); 106 107 if (rc < 0) 108 detailed_error(svc, 109 gettext("unable to parse message from scheduler: %s"), 110 strerror(errno)); 111 } 112 113 return (rc); 114 } 115 116 papi_status_t 117 lpsched_status_to_papi_status(int status) 118 { 119 switch (status) { 120 case MNOMEM: 121 return (PAPI_TEMPORARY_ERROR); 122 case MNOFILTER: 123 return (PAPI_DOCUMENT_FORMAT_ERROR); 124 case MNOOPEN: 125 return (PAPI_DOCUMENT_ACCESS_ERROR); 126 case MERRDEST: 127 return (PAPI_DEVICE_ERROR); 128 case MDENYDEST: 129 return (PAPI_NOT_ACCEPTING); 130 case MNOMEDIA: 131 return (PAPI_PRINT_SUPPORT_FILE_NOT_FOUND); 132 case MDENYMEDIA: 133 case MNOPERM: 134 return (PAPI_NOT_AUTHORIZED); 135 case MUNKNOWN: 136 case MNODEST: 137 case MNOINFO: 138 return (PAPI_NOT_FOUND); 139 case MTRANSMITERR: 140 return (PAPI_SERVICE_UNAVAILABLE); 141 case M2LATE: 142 return (PAPI_GONE); 143 case MBUSY: 144 return (PAPI_PRINTER_BUSY); 145 case MOK: 146 case MOKMORE: 147 return (PAPI_OK); 148 } 149 150 return (PAPI_INTERNAL_ERROR); 151 } 152 153 char * 154 lpsched_status_string(short status) 155 { 156 switch (status) { 157 case MNOMEM: 158 return (gettext("lpsched: out of memory")); 159 case MNOFILTER: 160 return (gettext("No filter available to convert job")); 161 case MNOOPEN: 162 return (gettext("lpsched: could not open request")); 163 case MERRDEST: 164 return (gettext("An error occured in submission")); 165 case MDENYDEST: 166 return (gettext("destination denied request")); 167 case MNOMEDIA: 168 return (gettext("unknown form specified in job")); 169 case MDENYMEDIA: 170 return (gettext("access denied to form specified in job")); 171 case MUNKNOWN: 172 return (gettext("no such resource")); 173 case MNODEST: 174 return (gettext("unknown destination")); 175 case MNOPERM: 176 return (gettext("permission denied")); 177 case MNOINFO: 178 return (gettext("no information available")); 179 case MTRANSMITERR: 180 return (gettext("failure to communicate with lpsched")); 181 default: { 182 static char result[16]; 183 184 snprintf(result, sizeof (result), gettext("status: %d"), 185 status); 186 return (result); 187 } 188 } 189 } 190 191 papi_status_t 192 lpsched_alloc_files(papi_service_t svc, int number, char **prefix) 193 { 194 papi_status_t result = PAPI_OK; 195 short status = MOK; 196 197 if ((svc == NULL) || (prefix == NULL)) 198 return (PAPI_BAD_ARGUMENT); 199 200 if ((snd_msg(svc, S_ALLOC_FILES, number) < 0) || 201 (rcv_msg(svc, R_ALLOC_FILES, &status, prefix) < 0)) 202 status = MTRANSMITERR; 203 204 if (status != MOK) { 205 detailed_error(svc, 206 gettext("failed to allocate %d file(s) for request: %s"), 207 number, lpsched_status_string(status)); 208 result = lpsched_status_to_papi_status(status); 209 } 210 211 return (result); 212 } 213 214 papi_status_t 215 lpsched_commit_job(papi_service_t svc, char *job, char **tmp) 216 /* job is host/req-id */ 217 { 218 papi_status_t result = PAPI_OK; 219 short status = MOK; 220 long bits; 221 222 if ((svc == NULL) || (job == NULL) || (tmp == NULL)) 223 return (PAPI_BAD_ARGUMENT); 224 225 if ((snd_msg(svc, S_PRINT_REQUEST, job) < 0) || 226 (rcv_msg(svc, R_PRINT_REQUEST, &status, tmp, &bits) < 0)) 227 status = MTRANSMITERR; 228 229 if (status != MOK) { 230 detailed_error(svc, gettext("failed to commit job (%s): %s"), 231 job, lpsched_status_string(status)); 232 result = lpsched_status_to_papi_status(status); 233 } 234 235 return (result); 236 } 237 238 papi_status_t 239 lpsched_start_change(papi_service_t svc, char *printer, int32_t job_id, 240 char **tmp) 241 { 242 papi_status_t result = PAPI_OK; 243 short status = MOK; 244 char req[BUFSIZ]; 245 char *dest; 246 247 if ((svc == NULL) || (printer == NULL) || (job_id < 0)) 248 return (PAPI_BAD_ARGUMENT); 249 250 dest = printer_name_from_uri_id(printer, job_id); 251 snprintf(req, sizeof (req), "%s-%d", dest, job_id); 252 free(dest); 253 254 if ((snd_msg(svc, S_START_CHANGE_REQUEST, req) < 0) || 255 (rcv_msg(svc, R_START_CHANGE_REQUEST, &status, tmp) < 0)) 256 status = MTRANSMITERR; 257 258 if (status != MOK) { 259 detailed_error(svc, 260 gettext("failed to initiate change for job (%s-%d): %s"), 261 printer, 262 job_id, lpsched_status_string(status)); 263 result = lpsched_status_to_papi_status(status); 264 } 265 266 return (result); 267 } 268 269 papi_status_t 270 lpsched_end_change(papi_service_t svc, char *printer, int32_t job_id) 271 { 272 papi_status_t result = PAPI_OK; 273 short status = MOK; 274 long bits; 275 char req[BUFSIZ]; 276 char *dest; 277 278 if ((svc == NULL) || (printer == NULL) || (job_id < 0)) 279 return (PAPI_BAD_ARGUMENT); 280 281 dest = printer_name_from_uri_id(printer, job_id); 282 snprintf(req, sizeof (req), "%s-%d", dest, job_id); 283 free(dest); 284 285 if ((snd_msg(svc, S_END_CHANGE_REQUEST, req) < 0) || 286 (rcv_msg(svc, R_END_CHANGE_REQUEST, &status, &bits) < 0)) 287 status = MTRANSMITERR; 288 289 if (status != MOK) { 290 detailed_error(svc, 291 gettext("failed to commit change for job (%s-%d): %s"), printer, 292 job_id, lpsched_status_string(status)); 293 result = lpsched_status_to_papi_status(status); 294 } 295 296 return (result); 297 } 298 299 papi_status_t 300 lpsched_accept_printer(papi_service_t svc, char *printer) 301 { 302 papi_status_t result = PAPI_OK; 303 short status; 304 char *req_id; 305 char *dest; 306 307 if ((svc == NULL) || (printer == NULL)) 308 return (PAPI_BAD_ARGUMENT); 309 310 dest = printer_name_from_uri_id(printer, -1); 311 if ((snd_msg(svc, S_ACCEPT_DEST, dest) < 0) || 312 (rcv_msg(svc, R_ACCEPT_DEST, &status, &req_id) < 0)) 313 status = MTRANSMITERR; 314 free(dest); 315 316 if ((status != MOK) && (status != MERRDEST)) { 317 detailed_error(svc, "%s: %s", printer, 318 lpsched_status_string(status)); 319 result = lpsched_status_to_papi_status(status); 320 } 321 322 return (result); 323 } 324 325 papi_status_t 326 lpsched_reject_printer(papi_service_t svc, char *printer, char *message) 327 { 328 papi_status_t result = PAPI_OK; 329 short status; 330 char *req_id; 331 char *dest; 332 333 if ((svc == NULL) || (printer == NULL)) 334 return (PAPI_BAD_ARGUMENT); 335 336 if (message == NULL) 337 message = "stopped by user"; 338 339 dest = printer_name_from_uri_id(printer, -1); 340 if ((snd_msg(svc, S_REJECT_DEST, dest, message, 0) < 0) || 341 (rcv_msg(svc, R_REJECT_DEST, &status, &req_id) < 0)) 342 status = MTRANSMITERR; 343 free(dest); 344 345 if ((status != MOK) && (status != MERRDEST)) { 346 detailed_error(svc, "%s: %s", printer, 347 lpsched_status_string(status)); 348 result = lpsched_status_to_papi_status(status); 349 } 350 351 return (result); 352 } 353 354 papi_status_t 355 lpsched_enable_printer(papi_service_t svc, char *printer) 356 { 357 papi_status_t result = PAPI_OK; 358 short status; 359 char *req_id; 360 char *dest; 361 362 if ((svc == NULL) || (printer == NULL)) 363 return (PAPI_BAD_ARGUMENT); 364 365 dest = printer_name_from_uri_id(printer, -1); 366 if ((snd_msg(svc, S_ENABLE_DEST, dest) < 0) || 367 (rcv_msg(svc, R_ENABLE_DEST, &status, &req_id) < 0)) 368 status = MTRANSMITERR; 369 free(dest); 370 371 if ((status != MOK) && (status != MERRDEST)) { 372 detailed_error(svc, "%s: %s", printer, 373 lpsched_status_string(status)); 374 result = lpsched_status_to_papi_status(status); 375 } 376 377 return (result); 378 } 379 380 papi_status_t 381 lpsched_disable_printer(papi_service_t svc, char *printer, char *message) 382 { 383 papi_status_t result = PAPI_OK; 384 short status; 385 char *req_id; 386 char *dest; 387 388 if ((svc == NULL) || (printer == NULL)) 389 return (PAPI_BAD_ARGUMENT); 390 391 if (message == NULL) 392 message = "stopped by user"; 393 394 dest = printer_name_from_uri_id(printer, -1); 395 if ((snd_msg(svc, S_DISABLE_DEST, dest, message, 0) < 0) || 396 (rcv_msg(svc, R_DISABLE_DEST, &status, &req_id) < 0)) 397 status = MTRANSMITERR; 398 free(dest); 399 400 if ((status != MOK) && (status != MERRDEST)) { 401 detailed_error(svc, "%s: %s", printer, 402 lpsched_status_string(status)); 403 result = lpsched_status_to_papi_status(status); 404 } 405 406 return (result); 407 } 408 409 papi_status_t 410 lpsched_load_unload_dest(papi_service_t handle, char *dest, int type) 411 { 412 service_t *svc = handle; 413 papi_status_t result; 414 short status = MOK; 415 416 /* tell the scheduler it's going */ 417 if (snd_msg(svc, type, dest, "", "") < 0) 418 return (PAPI_SERVICE_UNAVAILABLE); 419 420 switch (type) { 421 case S_LOAD_PRINTER: 422 type = R_LOAD_PRINTER; 423 break; 424 case S_UNLOAD_PRINTER: 425 type = R_UNLOAD_PRINTER; 426 break; 427 case S_LOAD_CLASS: 428 type = R_LOAD_CLASS; 429 break; 430 case S_UNLOAD_CLASS: 431 type = R_UNLOAD_CLASS; 432 } 433 434 if (rcv_msg(svc, type, &status) < 0) 435 return (PAPI_SERVICE_UNAVAILABLE); 436 437 result = lpsched_status_to_papi_status(status); 438 439 return (result); 440 } 441 442 papi_status_t 443 lpsched_remove_class(papi_service_t handle, char *dest) 444 { 445 papi_status_t result; 446 447 /* tell the scheduler it's going */ 448 result = lpsched_load_unload_dest(handle, dest, S_UNLOAD_CLASS); 449 450 if (result == PAPI_OK) { 451 /* remove the scheduler config files */ 452 if (delclass(dest) == -1) 453 result = PAPI_SERVICE_UNAVAILABLE; 454 } 455 456 return (result); 457 } 458 459 static void 460 remove_from_class(papi_service_t handle, char *dest, CLASS *cls) 461 { 462 if (dellist(&cls->members, dest) == 0) { 463 if (cls->members != NULL) { 464 if (putclass(cls->name, cls) == 0) 465 (void) lpsched_load_unload_dest(handle, 466 cls->name, S_LOAD_CLASS); 467 } else 468 (void) lpsched_remove_class(handle, cls->name); 469 } 470 } 471 472 papi_status_t 473 lpsched_remove_printer(papi_service_t handle, char *dest) 474 { 475 476 papi_status_t result; 477 478 /* tell the scheduler it's going */ 479 result = lpsched_load_unload_dest(handle, dest, S_UNLOAD_PRINTER); 480 481 if (result == PAPI_OK) { 482 CLASS *cls; 483 char *dflt; 484 485 /* remove the scheduler config files */ 486 if (delprinter(dest) == -1) 487 return (PAPI_SERVICE_UNAVAILABLE); 488 489 /* remove from any classes */ 490 while ((cls = getclass(NAME_ALL)) != NULL) 491 if (searchlist(dest, cls->members) != 0) 492 remove_from_class(handle, dest, cls); 493 494 /* reset the default if it needs to be done */ 495 if (((dflt = getdefault()) != NULL) && 496 (strcmp(dflt, dest) == 0)) 497 putdefault(NAME_NONE); 498 } 499 500 return (result); 501 } 502 503 papi_status_t 504 lpsched_add_modify_class(papi_service_t handle, char *dest, 505 papi_attribute_t **attributes) 506 { 507 papi_status_t result; 508 void *iter = NULL; 509 char **members = NULL; 510 char *member; 511 512 /* 513 * The only attribute that we can modify for a class is the set of 514 * members. Anything else will be ignored. 515 */ 516 for (result = papiAttributeListGetString(attributes, &iter, 517 "member-names", &member); 518 result == PAPI_OK; 519 result = papiAttributeListGetString(attributes, &iter, 520 NULL, &member)) 521 addlist(&members, member); 522 523 if (members != NULL) { 524 /* modify the configuration file */ 525 CLASS class; 526 527 memset(&class, 0, sizeof (class)); 528 class.name = dest; 529 class.members = members; 530 531 if (putclass(dest, &class) == -1) { 532 if ((errno == EPERM) || (errno == EACCES)) 533 result = PAPI_NOT_AUTHORIZED; 534 else 535 result = PAPI_NOT_POSSIBLE; 536 } else 537 result = PAPI_OK; 538 539 freelist(members); 540 } else 541 result = PAPI_ATTRIBUTES; 542 543 /* tell the scheduler about the changes */ 544 if (result == PAPI_OK) 545 result = lpsched_load_unload_dest(handle, dest, S_LOAD_CLASS); 546 547 return (result); 548 } 549 550 papi_status_t 551 lpsched_add_printer(papi_service_t handle, char *dest, 552 papi_attribute_t **attributes) 553 { 554 PRINTER *p; 555 papi_status_t result = PAPI_TEMPORARY_ERROR; 556 557 if ((p = calloc(1, sizeof (*p))) != NULL) { 558 p->name = strdup(dest); 559 p->banner = BAN_ALWAYS; 560 p->interface = strdup("/usr/lib/lp/model/uri"); 561 p->fault_alert.shcmd = strdup("mail"); 562 563 attributes_to_printer(attributes, p); 564 565 if (putprinter(dest, p) == -1) { 566 if ((errno == EPERM) || (errno == EACCES)) 567 result = PAPI_NOT_AUTHORIZED; 568 else 569 result = PAPI_NOT_POSSIBLE; 570 } else 571 result = PAPI_OK; 572 573 freeprinter(p); 574 } 575 576 /* tell the scheduler about the changes */ 577 if (result == PAPI_OK) 578 result = lpsched_load_unload_dest(handle, dest, S_LOAD_PRINTER); 579 580 return (result); 581 } 582 583 papi_status_t 584 lpsched_add_modify_printer(papi_service_t handle, char *dest, 585 papi_attribute_t **attributes, int type) 586 { 587 PRINTER *p; 588 papi_status_t result; 589 590 if (type == 0) { 591 if ((p = calloc(1, sizeof (*p))) != NULL) { 592 p->name = strdup(dest); 593 p->banner = BAN_ALWAYS; 594 p->interface = strdup("/usr/lib/lp/model/uri"); 595 p->fault_alert.shcmd = strdup("mail"); 596 } 597 } else 598 p = getprinter(dest); 599 600 if (p != NULL) { 601 attributes_to_printer(attributes, p); 602 603 if (putprinter(dest, p) == -1) { 604 if ((errno == EPERM) || (errno == EACCES)) 605 result = PAPI_NOT_AUTHORIZED; 606 else 607 result = PAPI_NOT_POSSIBLE; 608 } else 609 result = PAPI_OK; 610 611 freeprinter(p); 612 } else 613 result = PAPI_NOT_POSSIBLE; 614 615 /* tell the scheduler about the changes */ 616 if (result == PAPI_OK) 617 result = lpsched_load_unload_dest(handle, dest, S_LOAD_PRINTER); 618 619 return (result); 620 } 621