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