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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /*LINTLIBRARY*/ 30 31 #include <stdio.h> 32 #include <stdarg.h> 33 #include <libintl.h> 34 #include <string.h> 35 #include <stdlib.h> 36 #include <errno.h> 37 38 39 /* lpsched include files */ 40 #include "lp.h" 41 #include "msgs.h" 42 #include "printers.h" 43 #include "class.h" 44 45 #include <papi_impl.h> 46 47 48 /* 49 * Format and send message to lpsched (die if any errors occur) 50 */ 51 /*VARARGS1*/ 52 int 53 snd_msg(service_t *svc, int type, ...) 54 { 55 int rc = -1; 56 va_list ap; 57 58 if (svc == NULL) 59 return (-1); 60 61 /* fill the message buffer */ 62 va_start(ap, type); 63 rc = _putmessage(svc->msgbuf, type, ap); 64 va_end(ap); 65 if (rc < 0) { 66 detailed_error(svc, 67 gettext("unable to build message for scheduler: %s"), 68 strerror(errno)); 69 return (rc); 70 } 71 72 /* write the message */ 73 while (((rc = mwrite(svc->md, svc->msgbuf)) < 0) && (errno == EINTR)); 74 75 if (rc < 0) 76 detailed_error(svc, 77 gettext("unable to send message to scheduler: %s"), 78 strerror(errno)); 79 return (rc); 80 } 81 82 /* 83 * Receive message from lpsched (die if any errors occur) 84 */ 85 int 86 rcv_msg(service_t *svc, int type, ...) 87 { 88 int rc = -1; 89 90 if (svc == NULL) 91 return (-1); 92 93 /* read the message */ 94 while (((rc = mread(svc->md, svc->msgbuf, svc->msgbuf_size)) < 0) && 95 (errno == EINTR)); 96 97 if (rc < 0) 98 detailed_error(svc, 99 gettext("unable to read message from scheduler: %s"), 100 strerror(errno)); 101 else { 102 va_list ap; 103 104 va_start(ap, type); 105 rc = _getmessage(svc->msgbuf, type, ap); 106 va_end(ap); 107 108 if (rc < 0) 109 detailed_error(svc, 110 gettext("unable to parse message from scheduler: %s"), 111 strerror(errno)); 112 } 113 114 return (rc); 115 } 116 117 papi_status_t 118 lpsched_status_to_papi_status(int status) 119 { 120 switch (status) { 121 case MNOMEM: 122 return (PAPI_TEMPORARY_ERROR); 123 case MNOFILTER: 124 return (PAPI_DOCUMENT_FORMAT_ERROR); 125 case MNOOPEN: 126 return (PAPI_DOCUMENT_ACCESS_ERROR); 127 case MERRDEST: 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("queue disabled")); 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 freeclass(cls); 494 } 495 496 /* reset the default if it needs to be done */ 497 if (((dflt = getdefault()) != NULL) && 498 (strcmp(dflt, dest) == 0)) 499 putdefault(NAME_NONE); 500 } 501 502 return (result); 503 } 504 505 papi_status_t 506 lpsched_add_modify_class(papi_service_t handle, char *dest, 507 papi_attribute_t **attributes) 508 { 509 papi_status_t result; 510 void *iter = NULL; 511 char **members = NULL; 512 char *member; 513 514 /* 515 * The only attribute that we can modify for a class is the set of 516 * members. Anything else will be ignored. 517 */ 518 for (result = papiAttributeListGetString(attributes, &iter, 519 "member-names", &member); 520 result == PAPI_OK; 521 result = papiAttributeListGetString(attributes, &iter, 522 NULL, &member)) 523 addlist(&members, member); 524 525 if (members != NULL) { 526 /* modify the configuration file */ 527 CLASS class; 528 529 memset(&class, 0, sizeof (class)); 530 class.name = dest; 531 class.members = members; 532 533 if (putclass(dest, &class) == -1) { 534 if ((errno == EPERM) || (errno == EACCES)) 535 result = PAPI_NOT_AUTHORIZED; 536 else 537 result = PAPI_NOT_POSSIBLE; 538 } else 539 result = PAPI_OK; 540 541 freelist(members); 542 } else 543 result = PAPI_ATTRIBUTES; 544 545 /* tell the scheduler about the changes */ 546 if (result == PAPI_OK) 547 result = lpsched_load_unload_dest(handle, dest, S_LOAD_CLASS); 548 549 return (result); 550 } 551 552 papi_status_t 553 lpsched_add_printer(papi_service_t handle, char *dest, 554 papi_attribute_t **attributes) 555 { 556 PRINTER *p; 557 papi_status_t result = PAPI_TEMPORARY_ERROR; 558 559 if ((p = calloc(1, sizeof (*p))) != NULL) { 560 p->name = strdup(dest); 561 p->banner = BAN_ALWAYS; 562 p->interface = strdup("/usr/lib/lp/model/uri"); 563 p->fault_alert.shcmd = strdup("mail"); 564 565 attributes_to_printer(attributes, p); 566 567 if (putprinter(dest, p) == -1) { 568 if ((errno == EPERM) || (errno == EACCES)) 569 result = PAPI_NOT_AUTHORIZED; 570 else 571 result = PAPI_NOT_POSSIBLE; 572 } else 573 result = PAPI_OK; 574 575 freeprinter(p); 576 } 577 578 /* tell the scheduler about the changes */ 579 if (result == PAPI_OK) 580 result = lpsched_load_unload_dest(handle, dest, S_LOAD_PRINTER); 581 582 return (result); 583 } 584 585 papi_status_t 586 lpsched_add_modify_printer(papi_service_t handle, char *dest, 587 papi_attribute_t **attributes, int type) 588 { 589 PRINTER *p; 590 papi_status_t result; 591 592 if (type == 0) { 593 if ((p = calloc(1, sizeof (*p))) != NULL) { 594 p->name = strdup(dest); 595 p->banner = BAN_ALWAYS; 596 p->interface = strdup("/usr/lib/lp/model/uri"); 597 p->fault_alert.shcmd = strdup("mail"); 598 } 599 } else 600 p = getprinter(dest); 601 602 if (p != NULL) { 603 attributes_to_printer(attributes, p); 604 605 if (putprinter(dest, p) == -1) { 606 if ((errno == EPERM) || (errno == EACCES)) 607 result = PAPI_NOT_AUTHORIZED; 608 else 609 result = PAPI_NOT_POSSIBLE; 610 } else 611 result = PAPI_OK; 612 613 freeprinter(p); 614 } else 615 result = PAPI_NOT_POSSIBLE; 616 617 /* tell the scheduler about the changes */ 618 if (result == PAPI_OK) 619 result = lpsched_load_unload_dest(handle, dest, S_LOAD_PRINTER); 620 621 return (result); 622 } 623