xref: /titanic_50/usr/src/cmd/print/bsd-sysv-commands/lpstat.c (revision bcd6185e1c81586e6929dc444ef32123263dd51c)
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: lpstat.c 173 2006-05-25 04:52:06Z njacobs $ */
29 
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <locale.h>
36 #include <libintl.h>
37 #include <ctype.h>
38 #include <pwd.h>
39 #include <papi.h>
40 #include <uri.h>
41 #include "common.h"
42 #include "lp.h"
43 
44 static void
45 usage(char *program)
46 {
47 	char *name;
48 
49 	if ((name = strrchr(program, '/')) == NULL)
50 		name = program;
51 	else
52 		name++;
53 
54 	fprintf(stdout, gettext("Usage: %s [-d] [-r] [-s] [-t] [-a [list]] "
55 	    "[-c [list]] [-o [list] [-l]] [-R [list] [-l]] "
56 	    "[-p [list] [-D] [-l]] [-v [list]] [-S [list] [-l]] "
57 	    "[-f [list] [-l]] [-u list]\n"),
58 	    name);
59 	exit(1);
60 }
61 
62 static char *
63 nctime(time_t *t)
64 {
65 	static char buf[64];
66 	struct tm *tm = localtime(t);
67 
68 	(void) strftime(buf, sizeof (buf), "%c", tm);
69 
70 	return (buf);
71 }
72 
73 static char *
74 printer_name(papi_printer_t printer)
75 {
76 	papi_attribute_t **attributes = papiPrinterGetAttributeList(printer);
77 	char *result = NULL;
78 
79 	if (attributes != NULL)
80 		papiAttributeListGetString(attributes, NULL,
81 		    "printer-name", &result);
82 
83 	return (result);
84 }
85 
86 static int
87 lpstat_default_printer(papi_encryption_t encryption)
88 {
89 	papi_status_t status;
90 	papi_service_t svc = NULL;
91 	papi_printer_t p = NULL;
92 	char *name = NULL;
93 
94 	status = papiServiceCreate(&svc, NULL, NULL, NULL, cli_auth_callback,
95 	    encryption, NULL);
96 	if (status == PAPI_OK) {
97 		char *req[] = { "printer-name", NULL };
98 
99 		status = papiPrinterQuery(svc, DEFAULT_DEST, req, NULL, &p);
100 		if (p != NULL)
101 			name = printer_name(p);
102 	}
103 	if (name != NULL)
104 		printf(gettext("system default printer: %s\n"), name);
105 	else
106 		printf(gettext("no system default destination\n"));
107 	papiPrinterFree(p);
108 	papiServiceDestroy(svc);
109 
110 	return (0);
111 }
112 
113 static int
114 lpstat_service_status(papi_encryption_t encryption)
115 {
116 	papi_status_t status;
117 	papi_service_t svc = NULL;
118 	char *name = NULL;
119 
120 	if (((name = getenv("PAPI_SERVICE_URI")) == NULL) &&
121 	    ((name = getenv("IPP_SERVER")) == NULL) &&
122 	    ((name = getenv("CUPS_SERVER")) == NULL))
123 		name = DEFAULT_SERVICE_URI;
124 
125 	status = papiServiceCreate(&svc, name, NULL, NULL, cli_auth_callback,
126 	    encryption, NULL);
127 	if (status != PAPI_OK) {
128 		printf(gettext("scheduler is not running\n"));
129 	} else
130 		printf(gettext("scheduler is running\n"));
131 	papiServiceDestroy(svc);
132 
133 	return (0);
134 }
135 
136 static char *
137 get_device_uri(papi_service_t svc, char *name)
138 {
139 	papi_status_t status;
140 	papi_printer_t p = NULL;
141 	char *keys[] = { "device-uri", NULL };
142 	char *result = NULL;
143 
144 	status = papiPrinterQuery(svc, name, keys, NULL, &p);
145 	if ((status == PAPI_OK) && (p != NULL)) {
146 		papi_attribute_t **attrs = papiPrinterGetAttributeList(p);
147 
148 		(void) papiAttributeListGetString(attrs, NULL,
149 		    "device-uri", &result);
150 		if (result != NULL)
151 			result = strdup(result);
152 
153 		papiPrinterFree(p);
154 	}
155 
156 	return (result);
157 }
158 
159 static void
160 print_description(papi_attribute_t **list, char *printer_name)
161 {
162 	char *str = "";
163 
164 	(void) papiAttributeListGetString(list, NULL,
165 	    "printer-info", &str);
166 
167 	/*
168 	 * If no printer-info is read then
169 	 * by default the printer-info is <printer-name>@<server>
170 	 */
171 	if (str[0] == '\0') {
172 		char *uri = NULL;
173 		uri_t *u = NULL;
174 
175 		(void) papiAttributeListGetString(list, NULL,
176 		    "printer-uri-supported", &uri);
177 
178 		if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
179 			char *nodename = localhostname();
180 
181 			if ((u->host == NULL) ||
182 			    (strcasecmp(u->host, "localhost") == 0) ||
183 			    (strcasecmp(u->host, nodename) == 0))
184 				printf(gettext("\tDescription:\n"));
185 			else
186 				printf(gettext("\tDescription: %s@%s\n"),
187 				    printer_name, u->host);
188 
189 			uri_free(u);
190 		} else
191 			printf(gettext("\tDescription:\n"));
192 	} else
193 		printf(gettext("\tDescription: %s\n"), str);
194 }
195 
196 static char *report_device_keys[] = { "printer-name", "printer-uri-supported",
197 					NULL };
198 /* ARGSUSED2 */
199 static int
200 report_device(papi_service_t svc, char *name, papi_printer_t printer,
201 		int verbose, int description)
202 {
203 	papi_status_t status;
204 	papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
205 	char *uri = NULL;
206 	char *device = NULL;
207 	uri_t *u = NULL;
208 
209 	if (name == NULL) {
210 		status = papiAttributeListGetString(attrs, NULL,
211 		    "printer-name", &name);
212 		if (status != PAPI_OK)
213 			status = papiAttributeListGetString(attrs, NULL,
214 			    "printer-uri-supported", &name);
215 	}
216 
217 	if (name == NULL)
218 		return (-1);
219 
220 	(void) papiAttributeListGetString(attrs, NULL,
221 	    "printer-uri-supported", &uri);
222 
223 	if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
224 		char *nodename = localhostname();
225 
226 		if ((u->host == NULL) ||
227 		    (strcasecmp(u->host, "localhost") == 0) ||
228 		    (strcasecmp(u->host, nodename) == 0))
229 			device = get_device_uri(svc, name);
230 
231 		if (device != NULL) {
232 			printf(gettext("device for %s: %s\n"), name, device);
233 			return (0);
234 		} else if (uri != NULL) {
235 			printf(gettext("system for %s: %s (as %s)\n"), name,
236 			    u->host?u->host:"localhost", uri);
237 			return (0);
238 		}
239 
240 		uri_free(u);
241 	}
242 
243 	return (0);
244 }
245 
246 static char *report_accepting_keys[] = { "printer-name",
247 			"printer-uri-supported", "printer-is-accepting-jobs",
248 			"printer-up-time", "printer-state-time",
249 			"lpsched-reject-date", "lpsched-reject-reason", NULL };
250 /* ARGSUSED2 */
251 static int
252 report_accepting(papi_service_t svc, char *name, papi_printer_t printer,
253 		int verbose, int description)
254 {
255 	papi_status_t status;
256 	papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
257 	time_t curr;
258 	char boolean = PAPI_FALSE;
259 
260 	if (name == NULL) {
261 		status = papiAttributeListGetString(attrs, NULL,
262 		    "printer-name", &name);
263 		if (status != PAPI_OK)
264 			status = papiAttributeListGetString(attrs, NULL,
265 			    "printer-uri-supported", &name);
266 	}
267 	if (name == NULL)
268 		return (-1);
269 
270 	(void) papiAttributeListGetBoolean(attrs, NULL,
271 	    "printer-is-accepting-jobs", &boolean);
272 	(void) time(&curr);
273 	(void) papiAttributeListGetDatetime(attrs, NULL,
274 	    "printer-up-time", &curr);
275 	(void) papiAttributeListGetDatetime(attrs, NULL,
276 	    "printer-state-time", &curr);
277 	(void) papiAttributeListGetDatetime(attrs, NULL,
278 	    "lpsched-reject-date", &curr);
279 
280 	if (boolean == PAPI_TRUE) {
281 		printf(gettext("%s accepting requests since %s\n"),
282 		    name, nctime(&curr));
283 	} else {
284 		char *reason = "unknown reason";
285 
286 		(void) papiAttributeListGetString(attrs, NULL,
287 		    "lpsched-reject-reason", &reason);
288 
289 		printf(gettext("%s not accepting requests since %s\n\t%s\n"),
290 		    name, nctime(&curr), reason);
291 	}
292 
293 	return (0);
294 }
295 
296 static char *report_class_keys[] = { "printer-name", "printer-uri-supported",
297 					"member-names", NULL };
298 /* ARGSUSED2 */
299 static int
300 report_class(papi_service_t svc, char *name, papi_printer_t printer,
301 		int verbose, int description)
302 {
303 	papi_status_t status;
304 	papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
305 	char *member = NULL;
306 	void *iter = NULL;
307 
308 	status = papiAttributeListGetString(attrs, &iter,
309 	    "member-names", &member);
310 	if (status == PAPI_NOT_FOUND)	/* it's not a class */
311 		return (0);
312 
313 	if (name == NULL) {
314 		status = papiAttributeListGetString(attrs, NULL,
315 		    "printer-name", &name);
316 		if (status != PAPI_OK)
317 			status = papiAttributeListGetString(attrs, NULL,
318 			    "printer-uri-supported", &name);
319 	}
320 	if (name == NULL)
321 		return (-1);
322 
323 	printf(gettext("members of class %s:\n\t%s\n"), name, member);
324 	while (papiAttributeListGetString(attrs, &iter, NULL, &member)
325 	    == PAPI_OK)
326 		printf("\t%s\n", member);
327 
328 	return (0);
329 }
330 
331 static int
332 get_remote_hostname(papi_attribute_t **attrs, char **host)
333 {
334 	char *uri = NULL;
335 	uri_t *u;
336 	char *nodename;
337 
338 	*host = NULL;
339 	(void) papiAttributeListGetString(attrs, NULL,
340 	    "job-originating-host-name", host);
341 	(void) papiAttributeListGetString(attrs, NULL,
342 	    "printer-uri-supported", &uri);
343 	if (*host == NULL) {
344 		if (uri != NULL) {
345 			if (uri_from_string(uri, &u) == 0) {
346 				if (u->host == NULL) {
347 					uri_free(u);
348 					return (0);
349 				}
350 				*host = strdup(u->host);
351 				uri_free(u);
352 			} else {
353 				return (0);
354 			}
355 		} else {
356 			return (0);
357 		}
358 	}
359 	nodename = localhostname();
360 	if ((strcasecmp(*host, "localhost") == 0) ||
361 	    (strcasecmp(*host, nodename) == 0)) {
362 		return (0);
363 	}
364 	return (1);
365 }
366 
367 static char *report_printer_keys[] = { "printer-name",
368 			"printer-uri-supported", "printer-state",
369 			"printer-up-time", "printer-state-time",
370 			"lpsched-disable-date", "printer-state-reasons",
371 			"lpsched-disable-reason", NULL };
372 /* ARGSUSED2 */
373 static int
374 report_printer(papi_service_t svc, char *name, papi_printer_t printer,
375 		int verbose, int description)
376 {
377 	papi_status_t status;
378 	papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
379 	time_t curr;
380 	int32_t pstat = 0;
381 	char *member = NULL;
382 	papi_job_t *j = NULL;
383 
384 	status = papiAttributeListGetString(attrs, NULL,
385 	    "member-names", &member);
386 	if (status == PAPI_OK)	/* it's a class */
387 		return (0);
388 
389 	if (name == NULL) {
390 		status = papiAttributeListGetString(attrs, NULL,
391 		    "printer-name", &name);
392 		if (status != PAPI_OK)
393 			status = papiAttributeListGetString(attrs, NULL,
394 			    "printer-uri-supported", &name);
395 	}
396 	if (name == NULL)
397 		return (-1);
398 
399 	printf(gettext("printer %s "), name);
400 
401 	status = papiAttributeListGetInteger(attrs, NULL,
402 	    "printer-state", &pstat);
403 
404 	switch (pstat) {
405 	case 0x03:	/* idle */
406 		printf(gettext("is idle. enabled"));
407 		break;
408 	case 0x04: /* processing */
409 	case 0x06: /* faulted printing */
410 		status = papiPrinterListJobs(svc, name, NULL,
411 		    0, 0, &j);
412 
413 		if (status == PAPI_OK) {
414 			if (j != NULL) {
415 				int i = 0;
416 				int32_t jobid = 0;
417 				int32_t jstate = 0;
418 
419 				for (i = 0; j[i] != NULL; ++i) {
420 					papi_attribute_t **attr =
421 					    papiJobGetAttributeList(j[i]);
422 
423 					papiAttributeListGetInteger(attr,
424 					    NULL, "job-state", &jstate);
425 					papiAttributeListGetInteger(attr,
426 					    NULL, "job-id", &jobid);
427 					/*
428 					 * For lpd protocol "job-id-requested"
429 					 * should be read.
430 					 */
431 					papiAttributeListGetInteger(attr,
432 					    NULL, "job-id-requested", &jobid);
433 
434 					/*
435 					 * When lpd protocol is used job-state
436 					 * cannot be retrieved, therefore
437 					 * job-state will be 0.
438 					 * When ipp protocol is used, the
439 					 * active/printing job-state will be
440 					 * RS_PRINTING (0x0008) post s10u5.
441 					 * For pre-s10u5 job-state will be
442 					 * RS_ACTIVE (0x05). So print only when
443 					 * the job-state is RS_PRINTING (0x0008)
444 					 * or RS_ACTIVE (0x05) or 0
445 					 */
446 					if ((jstate == 0x0008) ||
447 					    (jstate == 0x05) ||
448 					    (jstate == 0)) {
449 						if (pstat == 0x04)
450 							printf(gettext
451 							    ("now printing"\
452 							    " %s-%d. enabled"),
453 							    name, jobid);
454 						if (pstat == 0x06)
455 							printf(gettext
456 							    ("faulted printing"\
457 							    " %s-%d. enabled"),
458 							    name, jobid);
459 						break;
460 					}
461 				}
462 				papiJobListFree(j);
463 			}
464 		}
465 		break;
466 	case 0x05:	/* stopped */
467 		printf(gettext("disabled"));
468 		break;
469 	case 0x07:	/* faulted printer */
470 		printf(gettext("faulted. enabled"));
471 		break;
472 	case 0x08:	/* waiting for auto retry */
473 		printf(gettext("waiting for auto-retry."));
474 		break;
475 	default:
476 		printf(gettext("unknown state(0x%x)."), pstat);
477 		break;
478 	}
479 
480 	if (pstat == 0x08)
481 		printf(gettext(" available.\n"));
482 	else {
483 		(void) time(&curr);
484 		(void) papiAttributeListGetDatetime(attrs, NULL,
485 		    "printer-up-time", &curr);
486 		(void) papiAttributeListGetDatetime(attrs, NULL,
487 		    "printer-state-time", &curr);
488 		(void) papiAttributeListGetDatetime(attrs, NULL,
489 		    "lpsched-disable-date", &curr);
490 		printf(gettext(" since %s. available.\n"), nctime(&curr));
491 	}
492 
493 	if ((pstat == 0x05) ||
494 	    (pstat == 0x06) ||
495 	    (pstat == 0x07) ||
496 	    (pstat == 0x08)) {
497 		char *reason = "unknown reason";
498 
499 		(void) papiAttributeListGetString(attrs, NULL,
500 		    "printer-state-reasons", &reason);
501 		(void) papiAttributeListGetString(attrs, NULL,
502 		    "lpsched-disable-reason", &reason);
503 		printf(gettext("\t%s\n"), reason);
504 	}
505 
506 	if (verbose == 1) {
507 		void *iter;
508 		char *str;
509 		char *host = NULL;
510 
511 		if ((get_remote_hostname(attrs, &host)) != 0) {
512 			(void) printf(
513 			    gettext("\tRemote Name: %s\n\tRemote Server: "
514 			    "%s\n"), name, host);
515 			free(host);
516 			return (0);
517 		}
518 		str = "";
519 		(void) papiAttributeListGetString(attrs, NULL,
520 		    "form-ready", &str);
521 		printf(gettext("\tForm mounted: %s\n"), str);
522 
523 		str = "";
524 		iter = NULL;
525 		(void) papiAttributeListGetString(attrs, &iter,
526 		    "document-format-supported", &str);
527 		printf(gettext("\tContent types: %s"), str);
528 		while (papiAttributeListGetString(attrs, &iter, NULL, &str)
529 		    == PAPI_OK)
530 			printf(", %s", str);
531 		printf("\n");
532 
533 		/* Display the printer description */
534 		print_description(attrs, name);
535 
536 		str = "";
537 		iter = NULL;
538 		(void) papiAttributeListGetString(attrs, &iter,
539 		    "lpsched-printer-type", &str);
540 		printf(gettext("\tPrinter types: %s"), str);
541 		while (papiAttributeListGetString(attrs, &iter, NULL, &str)
542 		    == PAPI_OK)
543 			printf(", %s", str);
544 		printf("\n");
545 
546 		str = "";
547 		(void) papiAttributeListGetString(attrs, NULL,
548 		    "lpsched-dial-info", &str);
549 		printf(gettext("\tConnection: %s\n"),
550 		    ((str[0] == '\0') ? gettext("direct") : str));
551 
552 		str = "";
553 		(void) papiAttributeListGetString(attrs, NULL,
554 		    "lpsched-interface-script", &str);
555 		printf(gettext("\tInterface: %s\n"), str);
556 
557 		str = NULL;
558 		(void) papiAttributeListGetString(attrs, NULL,
559 		    "ppd-file-uri", &str);
560 		(void) papiAttributeListGetString(attrs, NULL,
561 		    "lpsched-ppd-source-path", &str);
562 		if (str != NULL)
563 			printf(gettext("\tPPD: %s\n"), str);
564 
565 		str = NULL;
566 		(void) papiAttributeListGetString(attrs, NULL,
567 		    "lpsched-fault-alert-command", &str);
568 		if (str != NULL)
569 			printf(gettext("\tOn fault: %s\n"), str);
570 
571 		str = "";
572 		(void) papiAttributeListGetString(attrs, NULL,
573 		    "lpsched-fault-recovery", &str);
574 		printf(gettext("\tAfter fault: %s\n"),
575 		    ((str[0] == '\0') ? gettext("continue") : str));
576 
577 		str = "(all)";
578 		iter = NULL;
579 		(void) papiAttributeListGetString(attrs, &iter,
580 		    "requesting-user-name-allowed", &str);
581 		printf(gettext("\tUsers allowed:\n\t\t%s\n"),
582 		    ((str[0] == '\0') ? gettext("(none)") : str));
583 		if ((str != NULL) && (str[0] != '\0'))
584 			while (papiAttributeListGetString(attrs, &iter, NULL,
585 			    &str) == PAPI_OK)
586 				printf("\t\t%s\n", str);
587 
588 		str = NULL;
589 		iter = NULL;
590 		(void) papiAttributeListGetString(attrs, &iter,
591 		    "requesting-user-name-denied", &str);
592 		if (str != NULL) {
593 			printf(gettext("\tUsers denied:\n\t\t%s\n"),
594 			    ((str[0] == '\0') ? gettext("(none)") : str));
595 			if ((str != NULL) && (str[0] != '\0'))
596 				while (papiAttributeListGetString(attrs, &iter,
597 				    NULL, &str) == PAPI_OK)
598 					printf("\t\t%s\n", str);
599 		}
600 
601 		str = "none";
602 		iter = NULL;
603 		(void) papiAttributeListGetString(attrs, &iter,
604 		    "form-supported", &str);
605 		printf(gettext("\tForms allowed:\n\t\t(%s)\n"),
606 		    ((str[0] == '\0') ? gettext("none") : str));
607 		if ((str != NULL) && (str[0] != '\0'))
608 			while (papiAttributeListGetString(attrs, &iter, NULL,
609 			    &str) == PAPI_OK)
610 				printf("\t\t(%s)\n", str);
611 
612 		str = "";
613 		iter = NULL;
614 		(void) papiAttributeListGetString(attrs, &iter,
615 		    "media-supported", &str);
616 		printf(gettext("\tMedia supported:\n\t\t%s\n"),
617 		    ((str[0] == '\0') ? gettext("(none)") : str));
618 		if ((str != NULL) && (str[0] != '\0'))
619 			while (papiAttributeListGetString(attrs, &iter, NULL,
620 			    &str) == PAPI_OK)
621 				printf("\t\t%s\n", str);
622 
623 		str = "";
624 		(void) papiAttributeListGetString(attrs, NULL,
625 		    "job-sheets-supported", &str);
626 		if ((strcasecmp(str, "none")) == 0)
627 			str = gettext("page never printed");
628 		else if (strcasecmp(str, "optional") == 0)
629 			str = gettext("not required");
630 		else
631 			str = gettext("required");
632 
633 		printf(gettext("\tBanner %s\n"), str);
634 
635 
636 		str = "";
637 		iter = NULL;
638 		(void) papiAttributeListGetString(attrs, &iter,
639 		    "lpsched-print-wheels", &str);
640 		printf(gettext("\tCharacter sets:\n\t\t%s\n"),
641 		    ((str[0] == '\0') ? gettext("(none)") : str));
642 		if ((str != NULL) && (str[0] != '\0'))
643 			while (papiAttributeListGetString(attrs, &iter, NULL,
644 			    &str) == PAPI_OK)
645 				printf("\t\t%s\n", str);
646 
647 		printf(gettext("\tDefault pitch:\n"));
648 		printf(gettext("\tDefault page size:\n"));
649 		printf(gettext("\tDefault port setting:\n"));
650 
651 		str = "";
652 		iter = NULL;
653 		(void) papiAttributeListGetString(attrs, &iter,
654 		    "lpsched-options", &str);
655 		if (str != NULL) {
656 			printf(gettext("\tOptions: %s"), str);
657 			while (papiAttributeListGetString(attrs, &iter, NULL,
658 			    &str) == PAPI_OK)
659 				printf(", %s", str);
660 			printf("\n");
661 		}
662 
663 	} else if (description == 1)
664 		/* Display printer description */
665 		print_description(attrs, name);
666 	else if (verbose > 1)
667 		papiAttributeListPrint(stdout, attrs, "\t");
668 
669 	if (verbose > 0)
670 		printf("\n");
671 
672 	return (0);
673 }
674 
675 static int
676 printer_query(char *name, int (*report)(papi_service_t, char *, papi_printer_t,
677 					int, int), papi_encryption_t encryption,
678 		int verbose, int description)
679 {
680 	int result = 0, i = 0;
681 	papi_status_t status;
682 	papi_service_t svc = NULL;
683 	char **list = getlist(name, LP_WS, LP_SEP);
684 
685 	if (list == NULL) {
686 		list = (char **)malloc(sizeof (char *));
687 		list[0] = name;
688 	}
689 
690 	/*
691 	 * The for loop executes once for every printer
692 	 * entry in list. If list is NULL that implies
693 	 * name is also NULL, the loop runs only one time.
694 	 */
695 
696 	for (i = 0; name == NULL || list[i] != NULL; i++) {
697 		name = list[i];
698 
699 		status = papiServiceCreate(&svc, name, NULL, NULL,
700 		    cli_auth_callback, encryption, NULL);
701 		if (status != PAPI_OK) {
702 			if (status == PAPI_NOT_FOUND)
703 				fprintf(stderr,
704 				    gettext("%s: unknown printer\n"),
705 				    name ? name : "(NULL)");
706 			else
707 				fprintf(stderr, gettext(
708 				    "Failed to contact service for %s: %s\n"),
709 				    name ? name : "(NULL)",
710 				    verbose_papi_message(svc, status));
711 			papiServiceDestroy(svc);
712 			result--;
713 			continue;
714 		}
715 
716 		if (name == NULL) { /* all */
717 			char **interest = interest_list(svc);
718 
719 			if (interest != NULL) {
720 				int i;
721 
722 				for (i = 0; interest[i] != NULL; i++)
723 					result += printer_query(interest[i],
724 					    report, encryption, verbose,
725 					    description);
726 			}
727 		} else {
728 			papi_printer_t printer = NULL;
729 			char **keys = NULL;
730 
731 			/*
732 			 * Limit the query to only required data
733 			 * to reduce the need to go remote for
734 			 * information.
735 			 */
736 			if (report == report_device)
737 				keys = report_device_keys;
738 			else if (report == report_class)
739 				keys = report_class_keys;
740 			else if (report == report_accepting)
741 				keys = report_accepting_keys;
742 			else if ((report == report_printer) && (verbose == 0))
743 				keys = report_printer_keys;
744 
745 			status = papiPrinterQuery(svc, name, keys,
746 			    NULL, &printer);
747 			if (status != PAPI_OK) {
748 				fprintf(stderr, gettext(
749 				    "Failed to get printer info for %s: %s\n"),
750 				    name, verbose_papi_message(svc, status));
751 				papiServiceDestroy(svc);
752 				result--;
753 				continue;
754 			}
755 
756 			if (printer != NULL)
757 				result += report(svc, name, printer, verbose,
758 				    description);
759 
760 			papiPrinterFree(printer);
761 		}
762 
763 		papiServiceDestroy(svc);
764 
765 		if (name == NULL)
766 			break;
767 	}
768 
769 	freelist(list);
770 
771 	return (result);
772 }
773 
774 static int
775 match_user(char *user, char **list)
776 {
777 	int i;
778 
779 	for (i = 0; list[i] != NULL; i++) {
780 		if (strcmp(user, list[i]) == 0)
781 			return (0);
782 	}
783 
784 	return (-1);
785 }
786 
787 static char **users = NULL;
788 
789 static int
790 report_job(char *printer, papi_job_t job, int show_rank, int verbose)
791 {
792 	papi_attribute_t **attrs = papiJobGetAttributeList(job);
793 	time_t clock = 0;
794 	char date[24];
795 	char request[26];
796 	char *user = "unknown";
797 	char *host = NULL;
798 	int32_t size = 0;
799 	int32_t jstate = 0;
800 	char User[50];
801 
802 	char *destination = "unknown";
803 	int32_t id = -1;
804 	static int check = 0;
805 	static char *uri = NULL;
806 	static char *puri = NULL;	/* printer-uri */
807 	static char *pname = NULL;	/* printer-name */
808 
809 	(void) papiAttributeListGetString(attrs, NULL,
810 	    "job-originating-user-name", &user);
811 
812 	if ((users != NULL) && (match_user(user, users) < 0))
813 		return (0);
814 
815 	(void) papiAttributeListGetString(attrs, NULL,
816 	    "job-originating-host-name", &host);
817 
818 	/*
819 	 * When lpstat is called for multiple printers
820 	 * internally the function 'report_job' gets
821 	 * called multiple times with different printer-names.
822 	 * The following block of code handles the case when lpstat is
823 	 * executed for multiple printers. In other words when 'report_job'
824 	 * is called multiple times for different printers for
825 	 * one lpstat command
826 	 * For e.g: lpstat printer1 printer2 printer3
827 	 */
828 	if (pname == NULL) {
829 		/*
830 		 * When lpstat is queried for the first time
831 		 * pname is NULL so this part of the code gets executed.
832 		 * Read the attribute "job-printer-uri"
833 		 * first time
834 		 */
835 		(void) papiAttributeListGetString(attrs, NULL,
836 		    "job-printer-uri", &uri);
837 
838 		if (printer != NULL) {
839 			/*
840 			 * Set pname to the printer that is being
841 			 * queried so that this can be used later
842 			 * if 'report_job' is called multiple times for
843 			 * different printers for one lpstat command
844 			 */
845 			pname = printer;
846 		}
847 
848 		if (uri != NULL) {
849 			/*
850 			 * Set puri so that "job-printer-uri" corresponding
851 			 * to a particular printer can be used later when
852 			 * lpstat is queried for the same printer as
853 			 * "job-printer-uri" for a printer is read just once.
854 			 */
855 			puri = strdup(uri);
856 		}
857 	} else {
858 		/*
859 		 * This part of the code will get executed when
860 		 * 'report_job' is called more than once for the same
861 		 * lpstat command
862 		 */
863 		if (printer != NULL) {
864 			if (strcasecmp(pname, printer) != 0) {
865 				/*
866 				 * Read the job-printer-uri as
867 				 * it will be different for
868 				 * different printers
869 				 */
870 				uri = NULL;
871 				(void) papiAttributeListGetString(attrs,
872 				    NULL, "job-printer-uri", &uri);
873 				pname = printer;
874 				if (uri != NULL)
875 					puri = strdup(uri);
876 				else
877 					puri = NULL;
878 			} else {
879 				/*
880 				 * Same printer queried twice
881 				 * uri should be the same as
882 				 * already read in the previous call
883 				 * to 'report_job'.
884 				 * For the same printer 'job-printer-uri'
885 				 * is read just once because only in the
886 				 * first call it contains the host information
887 				 */
888 				uri = puri;
889 			}
890 		}
891 	}
892 
893 	if (host) {
894 		/* Check if it is local printer or remote printer */
895 		uri_t *u = NULL;
896 
897 		if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
898 			char *nodename = localhostname();
899 
900 			if ((u->host == NULL) ||
901 			    (strcasecmp(u->host, "localhost") == 0) ||
902 			    (strcasecmp(u->host, nodename) == 0)) {
903 
904 				if (strcasecmp(host, nodename) == 0) {
905 					/*
906 					 * Request submitted locally
907 					 * for the local queue.
908 					 * Hostname will not be displayed
909 					 */
910 					snprintf(User, sizeof (User), "%s",
911 					    user);
912 				}
913 				else
914 					snprintf(User, sizeof (User), "%s@%s",
915 					    user, host);
916 			} else if (uri != NULL) {
917 				/*
918 				 * It's a remote printer.
919 				 * In case of remote printers hostname is
920 				 * always displayed.
921 				 */
922 				snprintf(User, sizeof (User), "%s@%s",
923 				    user, host);
924 			}
925 			uri_free(u);
926 		} else {
927 			/*
928 			 * If attribute "job-printer-uri"
929 			 * cannot be read
930 			 * by default append the hostname
931 			 */
932 			snprintf(User, sizeof (User), "%s@%s", user, host);
933 		}
934 	} else {
935 		/*
936 		 * When print server is s10u4 and ipp service is used
937 		 * "job-originating-hostname" attribute is not set
938 		 * So get the host information from the uri
939 		 */
940 		uri_t *u = NULL;
941 		if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
942 			if ((u != NULL) && (u->host != NULL))
943 				snprintf(User, sizeof (User), "%s@%s",
944 				    user, u->host);
945 			else
946 				snprintf(User, sizeof (User), "%s", user);
947 
948 			uri_free(u);
949 		} else
950 			snprintf(User, sizeof (User), "%s", user);
951 	}
952 	(void) papiAttributeListGetInteger(attrs, NULL, "job-k-octets", &size);
953 	size *= 1024;	/* for the approximate byte size */
954 	(void) papiAttributeListGetInteger(attrs, NULL, "job-octets", &size);
955 
956 	(void) time(&clock);
957 	(void) papiAttributeListGetInteger(attrs, NULL,
958 	    "time-at-creation", (int32_t *)&clock);
959 	(void) strftime(date, sizeof (date), "%b %d %R", localtime(&clock));
960 
961 	(void) papiAttributeListGetString(attrs, NULL,
962 	    "job-printer-uri", &destination);
963 	(void) papiAttributeListGetString(attrs, NULL,
964 	    "printer-name", &destination);
965 	(void) papiAttributeListGetInteger(attrs, NULL,
966 	    "job-id", &id);
967 	(void) papiAttributeListGetInteger(attrs, NULL,
968 	    "job-id-requested", &id);
969 
970 
971 	snprintf(request, sizeof (request), "%s-%d", printer, id);
972 
973 	if (show_rank != 0) {
974 		int32_t rank = -1;
975 
976 		(void) papiAttributeListGetInteger(attrs, NULL,
977 		    "number-of-intervening-jobs", &rank);
978 		rank++;
979 
980 		printf("%3d %-21s %-14s %7ld %s",
981 		    rank, request, User, size, date);
982 	} else
983 		printf("%-23s %-14s %7ld   %s", request, User, size, date);
984 
985 	(void) papiAttributeListGetInteger(attrs, NULL,
986 	    "job-state", &jstate);
987 
988 	if (jstate == 0x0001)
989 		printf(gettext(" being held"));
990 	else if (jstate == 0x0800)
991 		printf(gettext(" notifying user"));
992 	else if (jstate == 0x0040)
993 		printf(gettext(" cancelled"));
994 	else if (jstate == 0x0010)
995 		printf(gettext(" finished printing"));
996 	else if (jstate == 0x0008)
997 		printf(gettext(" on %s"), destination);
998 	else if (jstate == 0x2000)
999 		printf(gettext(" held by admin"));
1000 	else if (jstate == 0x0002)
1001 		printf(gettext(" being filtered"));
1002 	else if (jstate == 0x0004)
1003 		printf(gettext(" filtered"));
1004 	else if (jstate == 0x0020)
1005 		printf(gettext(" held for change"));
1006 
1007 	if (verbose == 1) {
1008 		char *form = NULL;
1009 
1010 		(void) papiAttributeListGetString(attrs, NULL,
1011 		    "output-device-assigned", &destination);
1012 		printf("\n\t assigned %s", destination);
1013 
1014 		(void) papiAttributeListGetString(attrs, NULL, "form", &form);
1015 		if (form != NULL)
1016 			printf(", form %s", form);
1017 	} else if (verbose > 1) {
1018 		printf("\n");
1019 		papiAttributeListPrint(stdout, attrs, "\t");
1020 	}
1021 
1022 	printf("\n");
1023 
1024 	return (0);
1025 }
1026 
1027 static int
1028 job_query(char *request, int (*report)(char *, papi_job_t, int, int),
1029 		papi_encryption_t encryption, int show_rank, int verbose)
1030 {
1031 	int result = 0;
1032 	papi_status_t status;
1033 	papi_service_t svc = NULL;
1034 	char *printer = request;
1035 	int32_t id = -1;
1036 	int flag1 = 0;
1037 	int flag = 1;
1038 	int print_flag = 0;
1039 
1040 	do {
1041 		status = papiServiceCreate(&svc, printer, NULL, NULL,
1042 		    cli_auth_callback, encryption, NULL);
1043 
1044 		if ((status == PAPI_OK) && (printer != NULL))
1045 			print_flag = 1;
1046 
1047 		/* <name>-# printer name does not exist */
1048 		if (status != PAPI_OK) {
1049 			/*
1050 			 * Check if <name>-# is a request-id
1051 			 * Once this check is done flag1 is set
1052 			 */
1053 			if (flag1 == 1)
1054 				break;
1055 
1056 			get_printer_id(printer, &printer, &id);
1057 
1058 			status = papiServiceCreate(&svc, printer, NULL, NULL,
1059 			    cli_auth_callback, encryption, NULL);
1060 
1061 			if (status != PAPI_OK) {
1062 				fprintf(stderr, gettext(
1063 				    "Failed to contact service for %s: %s\n"),
1064 				    (printer ? printer : "all"),
1065 				    verbose_papi_message(svc, status));
1066 				return (-1);
1067 			}
1068 		}
1069 
1070 		if (printer == NULL) { /* all */
1071 			char **interest = interest_list(svc);
1072 
1073 			if (interest != NULL) {
1074 				int i;
1075 
1076 				for (i = 0; interest[i] != NULL; i++)
1077 					result += job_query(interest[i], report,
1078 					    encryption, show_rank, verbose);
1079 			}
1080 		} else if (id == -1) { /* a printer */
1081 			papi_job_t *jobs = NULL;
1082 
1083 			status = papiPrinterListJobs(svc, printer, NULL,
1084 			    0, 0, &jobs);
1085 			if (status != PAPI_OK) {
1086 				fprintf(stderr, gettext(
1087 				    "Failed to get job list: %s\n"),
1088 				    verbose_papi_message(svc, status));
1089 				papiServiceDestroy(svc);
1090 				return (-1);
1091 			}
1092 
1093 			if (jobs != NULL) {
1094 				int i;
1095 
1096 				for (i = 0; jobs[i] != NULL; i++)
1097 					result += report(printer,
1098 					    jobs[i], show_rank,
1099 					    verbose);
1100 			}
1101 
1102 			papiJobListFree(jobs);
1103 		} else {	/* a job */
1104 			papi_job_t job = NULL;
1105 
1106 			/* Once a job has been found stop processing */
1107 			flag = 0;
1108 
1109 			/*
1110 			 * Job-id could be the job-id requested
1111 			 * Check if it is job-id or job-id-requested
1112 			 */
1113 			id = job_to_be_queried(svc, printer, id);
1114 
1115 			if (id >= 0)
1116 				status = papiJobQuery(svc, printer, id,
1117 				    NULL, &job);
1118 			else
1119 				/* id not found */
1120 				status = PAPI_NOT_FOUND;
1121 
1122 			if (status != PAPI_OK) {
1123 				if (!print_flag)
1124 					fprintf(stderr, gettext(
1125 					    "Failed to get job"\
1126 					    " info for %s: %s\n"),
1127 					    request,
1128 					    verbose_papi_message(svc, status));
1129 				papiServiceDestroy(svc);
1130 				return (-1);
1131 			}
1132 
1133 			if (job != NULL)
1134 				result = report(printer, job,
1135 				    show_rank, verbose);
1136 
1137 			papiJobFree(job);
1138 		}
1139 
1140 		if (flag) {
1141 			id = -1;
1142 			get_printer_id(printer, &printer, &id);
1143 			if (id == -1)
1144 				flag = 0;
1145 			else
1146 				flag1 = 1;
1147 		}
1148 	} while (flag);
1149 
1150 	papiServiceDestroy(svc);
1151 
1152 	return (result);
1153 }
1154 
1155 static int
1156 report_form(char *name, papi_attribute_t **attrs, int verbose)
1157 {
1158 	papi_status_t status;
1159 	char *form = NULL;
1160 	void *iter = NULL;
1161 
1162 	for (status = papiAttributeListGetString(attrs, &iter,
1163 	    "form-supported", &form);
1164 	    status == PAPI_OK;
1165 	    status = papiAttributeListGetString(attrs, &iter,
1166 	    NULL, &form)) {
1167 		if ((name == NULL) || (strcmp(name, form) == 0)) {
1168 			printf(gettext("form %s is available to you\n"), form);
1169 			if (verbose != 0) {
1170 				char *detail = NULL;
1171 				status = papiAttributeListGetString(attrs, NULL,
1172 				    "form-supported-detail", &detail);
1173 				if (status == PAPI_OK)
1174 					printf("%s\n", detail);
1175 			}
1176 		}
1177 	}
1178 
1179 	return (0);
1180 }
1181 
1182 static int
1183 report_print_wheels(char *name, papi_attribute_t **attrs, int verbose)
1184 {
1185 	papi_status_t status;
1186 	char *pw = NULL;
1187 	void *iter = NULL;
1188 
1189 	for (status = papiAttributeListGetString(attrs, &iter,
1190 	    "pw-supported", &pw);
1191 	    status == PAPI_OK;
1192 	    status = papiAttributeListGetString(attrs, &iter, NULL, &pw)) {
1193 		if ((name == NULL) || (strcmp(name, pw) == 0)) {
1194 			printf(gettext("charset %s is available\n"), pw);
1195 			if (verbose != 0) {
1196 				char *info = NULL;
1197 				status = papiAttributeListGetString(attrs, NULL,
1198 				    "pw-supported-extra", &info);
1199 				if (status == PAPI_OK)
1200 					printf("%s\n", info);
1201 			}
1202 		}
1203 	}
1204 
1205 	return (0);
1206 }
1207 
1208 static int
1209 service_query(char *name, int (*report)(char *, papi_attribute_t **, int),
1210 		papi_encryption_t encryption, int verbose)
1211 {
1212 	int result = 0;
1213 	papi_status_t status;
1214 	papi_service_t svc = NULL;
1215 	papi_attribute_t **attrs = NULL;
1216 
1217 	status = papiServiceCreate(&svc, name, NULL, NULL, cli_auth_callback,
1218 	    encryption, NULL);
1219 	if (status != PAPI_OK) {
1220 		papiServiceDestroy(svc);
1221 		return (-1);
1222 	}
1223 
1224 	attrs = papiServiceGetAttributeList(svc);
1225 	if (attrs != NULL) {
1226 		result = report(name, attrs, verbose);
1227 
1228 		if (verbose > 1) {
1229 			printf("\n");
1230 			papiAttributeListPrint(stdout, attrs, "\t");
1231 			printf("\n");
1232 		}
1233 	}
1234 
1235 	papiServiceDestroy(svc);
1236 
1237 	return (result);
1238 }
1239 
1240 int
1241 main(int ac, char *av[])
1242 {
1243 	int exit_code = 0;
1244 	papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
1245 	int rank = 0;
1246 	int verbose = 0;
1247 	int description = 0;
1248 	int c;
1249 	char **argv;
1250 
1251 	(void) setlocale(LC_ALL, "");
1252 	(void) textdomain("SUNW_OST_OSCMD");
1253 
1254 	argv = (char **)calloc((ac + 1), sizeof (char *));
1255 	for (c = 0; c < ac; c++) {
1256 		if ((av[c][0] == '-') && (av[c][1] == 'l') &&
1257 		    (isalpha(av[c][2]) != 0)) {
1258 			/* preserve old "-l[po...]" behavior */
1259 			argv[c] = &av[c][1];
1260 			argv[c][0] = '-';
1261 			verbose = 1;
1262 
1263 		} else
1264 			argv[c] = av[c];
1265 	}
1266 
1267 	argv[c++] = "--";
1268 	ac = c;
1269 
1270 	/* preprocess argument list looking for '-l' or '-R' so it can trail */
1271 	while ((c = getopt(ac, argv, "LEDf:S:stc:p:a:drs:v:l:o:R:u:")) != EOF) {
1272 		switch (c) {    /* these may or may not have an option */
1273 		case 'a':
1274 		case 'c':
1275 		case 'p':
1276 		case 'o':
1277 		case 'R':
1278 		case 'u':
1279 		case 'v':
1280 		case 'l':
1281 		case 'f':
1282 		case 'S':
1283 			if (optarg[0] == '-') {
1284 				/* this check stop a possible infinite loop */
1285 				if ((optind > 1) && (argv[optind-1][1] != c))
1286 					optind--;
1287 				optarg = NULL;
1288 			} else if (strcmp(optarg, "all") == 0)
1289 				optarg = NULL;
1290 		}
1291 
1292 		switch (c) {
1293 		case 'l':
1294 			if ((optarg == NULL) || (optarg[0] == '-'))
1295 				optarg = "1";
1296 			verbose = atoi(optarg);
1297 			break;
1298 		case 'D':
1299 			description = 1;
1300 			break;
1301 		case 'R':
1302 			rank = 1;
1303 			break;
1304 		case 'E':
1305 			encryption = PAPI_ENCRYPT_REQUIRED;
1306 			break;
1307 		default:
1308 			break;
1309 		}
1310 	}
1311 	optind = 1;
1312 
1313 	/* process command line arguments */
1314 	while ((c = getopt(ac, argv, "LEDf:S:stc:p:a:drs:v:l:o:R:u:")) != EOF) {
1315 		switch (c) {	/* these may or may not have an option */
1316 		case 'a':
1317 		case 'c':
1318 		case 'p':
1319 		case 'o':
1320 		case 'R':
1321 		case 'u':
1322 		case 'v':
1323 		case 'l':
1324 		case 'f':
1325 		case 'S':
1326 			if (optarg[0] == '-') {
1327 				/* this check stop a possible infinite loop */
1328 				if ((optind > 1) && (argv[optind-1][1] != c))
1329 					optind--;
1330 				optarg = NULL;
1331 			} else if (strcmp(optarg, "all") == 0)
1332 				optarg = NULL;
1333 		}
1334 
1335 		switch (c) {
1336 		case 'a':
1337 			exit_code += printer_query(optarg, report_accepting,
1338 			    encryption, verbose, 0);
1339 			break;
1340 		case 'c':
1341 			exit_code += printer_query(optarg, report_class,
1342 			    encryption, verbose, 0);
1343 			break;
1344 		case 'p':
1345 			exit_code += printer_query(optarg, report_printer,
1346 			    encryption, verbose, description);
1347 			break;
1348 		case 'd':
1349 			exit_code += lpstat_default_printer(encryption);
1350 			break;
1351 		case 'r':
1352 			exit_code += lpstat_service_status(encryption);
1353 			break;
1354 		case 'u':
1355 			if (optarg != NULL)
1356 				users = strsplit(optarg, ", \n");
1357 			exit_code += job_query(NULL, report_job,
1358 			    encryption, rank, verbose);
1359 			if (users != NULL) {
1360 				free(users);
1361 				users = NULL;
1362 			}
1363 			break;
1364 		case 'v':
1365 			exit_code += printer_query(optarg, report_device,
1366 			    encryption, verbose, 0);
1367 			break;
1368 		case 'R':	/* set "rank" flag in first pass */
1369 		case 'o':
1370 			exit_code += job_query(optarg, report_job,
1371 			    encryption, rank, verbose);
1372 			break;
1373 		case 'f':
1374 			exit_code += service_query(optarg, report_form,
1375 			    encryption, verbose);
1376 			break;
1377 		case 'S':
1378 			exit_code += service_query(optarg, report_print_wheels,
1379 			    encryption, verbose);
1380 			break;
1381 		case 's':
1382 			exit_code += lpstat_service_status(encryption);
1383 			exit_code += lpstat_default_printer(encryption);
1384 			exit_code += printer_query(NULL, report_class,
1385 			    encryption, verbose, 0);
1386 			exit_code += printer_query(NULL, report_device,
1387 			    encryption, verbose, 0);
1388 			exit_code += service_query(optarg, report_form,
1389 			    encryption, verbose);
1390 			exit_code += service_query(optarg, report_print_wheels,
1391 			    encryption, verbose);
1392 			break;
1393 		case 't':
1394 			exit_code += lpstat_service_status(encryption);
1395 			exit_code += lpstat_default_printer(encryption);
1396 			exit_code += printer_query(NULL, report_class,
1397 			    encryption, verbose, 0);
1398 			exit_code += printer_query(NULL, report_device,
1399 			    encryption, verbose, 0);
1400 			exit_code += printer_query(NULL, report_accepting,
1401 			    encryption, verbose, 0);
1402 			exit_code += printer_query(NULL, report_printer,
1403 			    encryption, verbose, 0);
1404 			exit_code += service_query(optarg, report_form,
1405 			    encryption, verbose);
1406 			exit_code += service_query(optarg, report_print_wheels,
1407 			    encryption, verbose);
1408 			exit_code += job_query(NULL, report_job,
1409 			    encryption, rank, verbose);
1410 			break;
1411 		case 'L':	/* local-only, ignored */
1412 		case 'l':	/* increased verbose level in first pass */
1413 		case 'D':	/* set "description" flag in first pass */
1414 		case 'E':	/* set encryption in the first pass */
1415 			break;
1416 		default:
1417 			usage(av[0]);
1418 		}
1419 	}
1420 	ac--;
1421 
1422 	if (ac == 1) {	/* report on my jobs */
1423 		struct passwd *pw = getpwuid(getuid());
1424 
1425 		if (pw != NULL)
1426 			users = strsplit(pw->pw_name, "");
1427 		exit_code += job_query(NULL, report_job, encryption,
1428 		    rank, verbose);
1429 		if (users != NULL) {
1430 			free(users);
1431 			users = NULL;
1432 		}
1433 	} else {
1434 		for (c = optind; c < ac; c++)
1435 			exit_code += job_query(argv[c], report_job, encryption,
1436 			    rank, verbose);
1437 	}
1438 
1439 
1440 	if (exit_code != 0)
1441 		exit_code = 1;
1442 
1443 	return (exit_code);
1444 }
1445