Home | History | Annotate | Download | only in cmd
      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, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     28 /*	  All Rights Reserved  	*/
     29 
     30 
     31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     32 
     33 #include <stdio.h>
     34 #include <errno.h>
     35 #include <string.h>
     36 #include <locale.h>
     37 
     38 #include "lp.h"
     39 #include "access.h"
     40 #include "filters.h"
     41 #include "msgs.h"
     42 
     43 #define	WHO_AM_I	I_AM_LPFILTER
     44 #include "oam.h"
     45 
     46 #define	OPT_LIST	"f:F:ixl"
     47 
     48 int			add_filter(),
     49 			reload_filter(),
     50 			delete_filter(),
     51 			list_filter();
     52 
     53 static void		alert_spooler(),
     54 			same_complaints();
     55 
     56 static char		*opt();
     57 
     58 /*
     59  * Unfortunately, the LP requirements show the listing of a filter
     60  * to be in a different order than the stored filter table. We can't
     61  * change the stored version because it's the same as UNISON uses.
     62  * So, we can't reuse the "FL_..." #defines found in "filters.h".
     63  * But the following have similar use.
     64  */
     65 #define FL_MAX_P	FL_MAX
     66 # define FL_IGN_P	8
     67 # define FL_PTYPS_P	2
     68 # define FL_PRTRS_P	3
     69 # define FL_ITYPS_P	0
     70 # define FL_NAME_P	7
     71 # define FL_OTYPS_P	1
     72 # define FL_TYPE_P	4
     73 # define FL_CMD_P	5
     74 # define FL_TMPS_P	6
     75 
     76 #define	TABLE		0
     77 #define	TABLE_I		1
     78 
     79 static struct headings {
     80 	char			*v;
     81 	short			len;
     82 }		headings[FL_MAX_P] = {
     83 
     84 #define	ENTRY(X)	X, sizeof(X)-1
     85 	ENTRY("Input types:"),
     86 	ENTRY("Output types:"),
     87 	ENTRY("Printer types:"),
     88 	ENTRY("Printers:"),
     89 	ENTRY("Filter type:"),
     90 	ENTRY("Command:"),
     91 	ENTRY("Options:"),
     92 	ENTRY(""),
     93 	ENTRY("")
     94 #undef	ENTRY
     95 
     96 };
     97 
     98 /**
     99  ** usage()
    100  **/
    101 
    102 void			usage ()
    103 {
    104 	(void) printf (gettext(
    105 "usage:\n"
    106 "\n"
    107 "  (add or change filter)\n"
    108 "    lpfilter -f filter-name {-F path-name | -}\n"
    109 "\n"
    110 "  (restore delivered filter)\n"
    111 "    lpfilter -f filter-name -i\n"
    112 "\n"
    113 "  (list a filter)\n"
    114 "    lpfilter -f filter-name -l\n"
    115 "\n"
    116 "  (list all filters)\n"
    117 "    lpfilter -f \"all\" -l\n"
    118 "\n"
    119 "  (delete filter)\n"
    120 "    lpfilter -f filter-name -x\n"));
    121 
    122 	return;
    123 }
    124 
    125 /**
    126  ** main()
    127  **/
    128 
    129 int			main (argc, argv)
    130 	int			argc;
    131 	char			*argv[];
    132 {
    133 	extern int		optind,
    134 				opterr,
    135 				optopt,
    136 				getopt();
    137 
    138 	extern char		*optarg;
    139 
    140 	int			c,
    141 				(*action)(),
    142 				(*newaction)();
    143 
    144 	FILE			*input;
    145 
    146 	char			*filter,
    147 				*p;
    148 
    149 
    150 	(void) setlocale (LC_ALL, "");
    151 #if !defined(TEXT_DOMAIN)
    152 #define TEXT_DOMAIN "SYS_TEST"
    153 #endif
    154 	(void) textdomain(TEXT_DOMAIN);
    155 
    156 	if (!is_user_admin()) {
    157 		LP_ERRMSG (ERROR, E_LP_NOTADM);
    158 		exit (1);
    159 	}
    160 
    161 	action = 0;
    162 	input = 0;
    163 	filter = 0;
    164 
    165 	opterr = 0;
    166 
    167 	while ((c = getopt(argc, argv, OPT_LIST)) != -1) switch (c) {
    168 
    169 	case 'f':
    170 		if (filter)
    171 			LP_ERRMSG1 (WARNING, E_LP_2MANY, 'f');
    172 		filter = optarg;
    173 		if (
    174 			STREQU(NAME_ANY, filter)
    175 		     || STREQU(NAME_NONE, filter)
    176 		) {
    177 			LP_ERRMSG (ERROR, E_LP_ANYNONE);
    178 			exit (1);
    179 		} else if (!syn_name(filter)) {
    180 			LP_ERRMSG1 (ERROR, E_LP_NOTNAME, filter);
    181 			exit (1);
    182 		} else if (!*filter)
    183 			filter = NAME_ALL;
    184 		break;
    185 
    186 	case 'F':
    187 		if (input)
    188 			LP_ERRMSG1 (WARNING, E_LP_2MANY, 'F');
    189 		if (!(input = fopen(optarg, "r"))) {
    190 			LP_ERRMSG1 (ERROR, E_FL_OPEN, optarg);
    191 			exit (1);
    192 		}
    193 		newaction = add_filter;
    194 		goto Check;
    195 
    196 	case 'i':
    197 		newaction = reload_filter;
    198 		goto Check;
    199 
    200 	case 'x':
    201 		newaction = delete_filter;
    202 		goto Check;
    203 
    204 	case 'l':
    205 		newaction = list_filter;
    206 Check:		if (action && newaction != action) {
    207 			LP_ERRMSG2 (
    208 				ERROR,
    209 				E_LP_AMBIG,
    210 				opt(action),
    211 				opt(newaction)
    212 			);
    213 			exit (1);
    214 		}
    215 		action = newaction;
    216 		break;
    217 
    218 	default:
    219 		if (optopt == '?') {
    220 			usage ();
    221 			exit (0);
    222 		}
    223 		(p = "-X")[1] = optopt;
    224 		if (strchr(OPT_LIST, optopt))
    225 			LP_ERRMSG1 (ERROR, E_LP_OPTARG, p);
    226 		else
    227 			LP_ERRMSG1 (ERROR, E_LP_OPTION, p);
    228 		exit (1);
    229 
    230 	}
    231 
    232 	if (optind < argc && STREQU(argv[optind], "-"))
    233 		if (action) {
    234 	 		LP_ERRMSG2 (ERROR, E_LP_AMBIG, opt(action), "-");
    235 			exit (1);
    236 		} else {
    237 			action = add_filter;
    238 			optind++;
    239 		}
    240 
    241 	if (!filter) {
    242 		LP_ERRMSG (ERROR, E_FL_NOFILT);
    243 		exit (1);
    244 	}
    245 
    246 	if (!action) {
    247 		LP_ERRMSG (ERROR, E_FL_NOACT);
    248 		exit (1);
    249 	}
    250 
    251 	if (optind < argc)
    252 		LP_ERRMSG1 (WARNING, E_FL_IGNORE, argv[optind]);
    253 
    254 	return ((*action)(filter, input));
    255 }
    256 
    257 /**
    258  ** add_filter()
    259  **/
    260 
    261 int			add_filter (filter, input)
    262 	char			*filter;
    263 	FILE			*input;
    264 {
    265 	register FILTER		*pf,
    266 				*store,
    267 				*ps;
    268 
    269 	register int		fld;
    270 
    271 	register char		*p;
    272 
    273 	char			buf[3 * BUFSIZ],
    274 				*file;
    275 
    276 	int			line,
    277 				bad_headings,
    278 				real_fields[FL_MAX],
    279 				at_least_one,
    280 				ret;
    281 
    282 	FILTER			flbuf;
    283 
    284 
    285 	/*
    286 	 * First we read in the input and parse it into a filter,
    287 	 * storing it in the filter buffer "flbuf". Keep track of
    288 	 * which fields have been given, to avoid overwriting unchanged
    289 	 * fields later.
    290 	 */
    291 
    292 	if (!input)
    293 		input = stdin;
    294 
    295 	for (fld = 0; fld < FL_MAX; fld++)
    296 		real_fields[fld] = 0;
    297 	flbuf.templates = 0;
    298 
    299 	line = bad_headings = 0;
    300 	while (fgets(buf, sizeof(buf), input) != NULL) {
    301 
    302 		buf[strlen(buf) - 1] = 0;
    303 
    304 		line++;
    305 
    306 		p = buf + strspn(buf, " \t");
    307 		if (!*p || *p == '#')
    308 			continue;
    309 
    310 		for (fld = 0; fld < FL_MAX; fld++)
    311 			if (
    312 				headings[fld].v
    313 			     && headings[fld].len
    314 			     && CS_STRNEQU(
    315 					p,
    316 					headings[fld].v,
    317 					headings[fld].len
    318 				)
    319 			) {
    320 				real_fields[fld] = 1;
    321 				p += headings[fld].len + 1;
    322 				break;
    323 			}
    324 
    325 		if (fld >= FL_MAX) {
    326 
    327 			if (bad_headings++ >= 5) {
    328 				LP_ERRMSG (ERROR, E_FL_GARBAGE);
    329 				return (1);
    330 			}
    331 			LP_ERRMSG1 (WARNING, E_FL_HEADING, line);
    332 
    333 		} else switch (fld) {
    334 
    335 			case FL_IGN_P:
    336 			case FL_NAME_P:
    337 				break;
    338 			case FL_CMD_P:
    339 				flbuf.command = strdup(strip(p));
    340 				break;
    341 			case FL_TYPE_P:
    342 				flbuf.type = s_to_filtertype(strip(p));
    343 				break;
    344 			case FL_PTYPS_P:
    345 				flbuf.printer_types = getlist(p, LP_WS, LP_SEP);
    346 				break;
    347 			case FL_ITYPS_P:
    348 				flbuf.input_types = getlist(p, LP_WS, LP_SEP);
    349 				break;
    350 			case FL_OTYPS_P:
    351 				flbuf.output_types = getlist(p, LP_WS, LP_SEP);
    352 				break;
    353 			case FL_PRTRS_P:
    354 				flbuf.printers = getlist(p, LP_WS, LP_SEP);
    355 				break;
    356 			case FL_TMPS_P:
    357 				if (flbuf.templates) {
    358 					char			**temp;
    359 
    360 					temp = getlist(p, "", LP_SEP);
    361 					mergelist (&(flbuf.templates), temp);
    362 					freelist (temp);
    363 				} else
    364 					flbuf.templates = getlist(p, "", LP_SEP);
    365 				break;
    366 
    367 		}
    368 
    369 	}
    370 	if (ferror(input)) {
    371 		LP_ERRMSG (ERROR, E_FL_READ);
    372 		return (1);
    373 	}
    374 
    375 	/*
    376 	 * We have the input stored, now get the current copy of the
    377 	 * filter(s). If no filter exists, we create it.
    378 	 */
    379 
    380 	if (STREQU(NAME_ALL, filter)) {
    381 
    382 		/*
    383 		 * Adding ``all'' means changing all filters to reflect
    384 		 * the information in the input. We'll preload the
    385 		 * filters so that we know how many there are.
    386 		 */
    387 		if (
    388 			!(file = getfilterfile(FILTERTABLE))
    389 		     || loadfilters(file) == -1
    390 		) {
    391 			switch (errno) {
    392 			case ENOENT:
    393 				LP_ERRMSG (ERROR, E_FL_NOTALL);
    394 				break;
    395 			default:
    396 				same_complaints (FILTERTABLE, TABLE);
    397 				break;
    398 			}
    399 			return (1);
    400 		}
    401 
    402 		store = (FILTER *)malloc((nfilters + 1) * sizeof(FILTER));
    403 		if (!store) {
    404 			LP_ERRMSG (ERROR, E_LP_MALLOC);
    405 			return (1);
    406 		}
    407 
    408 		for (ps = store; (pf = getfilter(filter)); )
    409 			*ps++ = *pf;
    410 		ps->name = 0;
    411 
    412 		switch (errno) {
    413 		case ENOENT:
    414 			if (ps - store != nfilters) {
    415 				LP_ERRMSG1 (
    416 					ERROR,
    417 					E_FL_STRANGE,
    418 					getfilterfile(FILTERTABLE)
    419 				);
    420 				return (1);
    421 			}
    422 			break;
    423 		default:
    424 			same_complaints (FILTERTABLE, TABLE);
    425 			return (1);
    426 		}
    427 
    428 	} else {
    429 
    430 		store = (FILTER *)malloc(2 * sizeof(FILTER));
    431 		if (!store) {
    432 			LP_ERRMSG (ERROR, E_LP_MALLOC);
    433 			return (1);
    434 		}
    435 
    436 		if ((pf = getfilter(filter))) {
    437 			store[0] = *pf;
    438 		} else
    439 			switch (errno) {
    440 			case ENOENT:
    441 				/*
    442 				 * We must be adding a new filter, so
    443 				 * set up default values. Check that
    444 				 * we'll have something reasonable to add.
    445 				 */
    446 				pf = store;
    447 				pf->name = strdup(filter);
    448 				pf->command = 0;
    449 				pf->type = fl_slow;
    450 				pf->printer_types = 0;
    451 				pf->printers = 0;
    452 				pf->input_types = 0;
    453 				pf->output_types = 0;
    454 				pf->templates = 0;
    455 				if (!flbuf.command) {
    456 					LP_ERRMSG (ERROR, E_FL_NOCMD);
    457 					return (1);
    458 				}
    459 				break;
    460 			default:
    461 				same_complaints (FILTERTABLE, TABLE);
    462 				return (1);
    463 			}
    464 
    465 		store[1].name = 0;
    466 
    467 	}
    468 
    469 	at_least_one = ret = 0;
    470 	for (ps = store; ps->name; ps++) {
    471 
    472 		for (fld = 0; fld < FL_MAX; fld++)
    473 			if (real_fields[fld]) switch(fld) {
    474 			case FL_IGN_P:
    475 			case FL_NAME_P:
    476 				break;
    477 			case FL_CMD_P:
    478 				ps->command = flbuf.command;
    479 				break;
    480 			case FL_TYPE_P:
    481 				ps->type = flbuf.type;
    482 				break;
    483 			case FL_PTYPS_P:
    484 				ps->printer_types = flbuf.printer_types;
    485 				break;
    486 			case FL_ITYPS_P:
    487 				ps->input_types = flbuf.input_types;
    488 				break;
    489 			case FL_OTYPS_P:
    490 				ps->output_types = flbuf.output_types;
    491 				break;
    492 			case FL_PRTRS_P:
    493 				ps->printers = flbuf.printers;
    494 				break;
    495 			case FL_TMPS_P:
    496 				ps->templates = flbuf.templates;
    497 				break;
    498 			}
    499 
    500 		if (putfilter(ps->name, ps) == -1) {
    501 			if (errno == EBADF)  switch (lp_errno) {
    502 			case LP_ETEMPLATE:
    503 				LP_ERRMSG (ERROR, E_FL_BADTEMPLATE);
    504 				break;
    505 			case LP_EKEYWORD:
    506 				LP_ERRMSG (ERROR, E_FL_BADKEY);
    507 				break;
    508 			case LP_EPATTERN:
    509 				LP_ERRMSG (ERROR, E_FL_BADPATT);
    510 				break;
    511 			case LP_EREGEX:
    512 			{
    513 				char *			why;
    514 
    515 				extern int		regerrno;
    516 
    517 
    518 				switch (regerrno) {
    519 				case 11:
    520 					why = "range endpoint too large";
    521 					break;
    522 				case 16:
    523 					why = "bad number";
    524 					break;
    525 				case 25:
    526 					why = "\"\\digit\" out of range";
    527 					break;
    528 				case 36:
    529 					why = "illegal or missing delimiter";
    530 					break;
    531 				case 41:
    532 					why = "no remembered search string";
    533 					break;
    534 				case 42:
    535 					why = "\\(...\\) imbalance";
    536 					break;
    537 				case 43:
    538 					why = "too many \\(";
    539 					break;
    540 				case 44:
    541 					why = "more than 2 numbers given in \\{...\\}";
    542 					break;
    543 				case 45:
    544 					why = "} expected after \\";
    545 					break;
    546 				case 46:
    547 					why = "first number exceeds second in \\{...\\}";
    548 					break;
    549 				case 49:
    550 					why = "[...] imbalance";
    551 					break;
    552 				case 50:
    553 					why = "regular expression overflow";
    554 					break;
    555 				}
    556 				LP_ERRMSG1 (ERROR, E_FL_BADREGEX, why);
    557 				break;
    558 			}
    559 			case LP_ERESULT:
    560 				LP_ERRMSG (ERROR, E_FL_BADRESULT);
    561 				break;
    562 			case LP_ENOMEM:
    563 				errno = ENOMEM;
    564 				same_complaints (FILTERTABLE, TABLE);
    565 				break;
    566 			} else
    567 				same_complaints (FILTERTABLE, TABLE);
    568 			ret = 1;
    569 			break;
    570 		} else
    571 			at_least_one = 1;
    572 
    573 	}
    574 
    575 	if (at_least_one)
    576 		(void)alert_spooler ();
    577 
    578 	return (ret);
    579 }
    580 
    581 /**
    582  ** reload_filter()
    583  **/
    584 
    585 int			reload_filter (filter)
    586 	char			*filter;
    587 {
    588 	register FILTER		*pf,
    589 				*store,
    590 				*ps;
    591 
    592 	char			*factory_file;
    593 
    594 	int			ret,
    595 				at_least_one;
    596 
    597 	/*
    598 	 * ``Manually'' load the archived filters, so that a call
    599 	 * to "getfilter()" will read from them instead of the regular
    600 	 * table.
    601 	 */
    602 	if (
    603 		!(factory_file = getfilterfile(FILTERTABLE_I))
    604 	     || loadfilters(factory_file) == -1
    605 	) {
    606 		switch (errno) {
    607 		case ENOENT:
    608 			LP_ERRMSG (ERROR, E_FL_NOFACTY);
    609 			break;
    610 		default:
    611 			same_complaints (FILTERTABLE_I, TABLE_I);
    612 			break;
    613 		}
    614 		return (1);
    615 	}
    616 
    617 	if (STREQU(NAME_ALL, filter)) {
    618 
    619 		store = (FILTER *)malloc((nfilters + 1) * sizeof(FILTER));
    620 		if (!store) {
    621 			LP_ERRMSG (ERROR, E_LP_MALLOC);
    622 			return (1);
    623 		}
    624 
    625 		for (ps = store; (pf = getfilter(filter)); )
    626 			*ps++ = *pf;
    627 		ps->name = 0;
    628 
    629 		switch (errno) {
    630 		case ENOENT:
    631 			if (ps - store != nfilters) {
    632 				LP_ERRMSG1 (
    633 					ERROR,
    634 					E_FL_STRANGE,
    635 					getfilterfile(FILTERTABLE_I)
    636 				);
    637 				return (1);
    638 			}
    639 			break;
    640 		default:
    641 			same_complaints (FILTERTABLE_I, TABLE_I);
    642 			return (1);
    643 		}
    644 
    645 	} else {
    646 
    647 		store = (FILTER *)malloc(2 * sizeof(FILTER));
    648 		if (!store) {
    649 			LP_ERRMSG (ERROR, E_LP_MALLOC);
    650 			return (1);
    651 		}
    652 
    653 		if (!(pf = getfilter(filter))) switch (errno) {
    654 		case ENOENT:
    655 			LP_ERRMSG (ERROR, E_FL_FACTYNM);
    656 			return (1);
    657 		default:
    658 			same_complaints (FILTERTABLE_I, TABLE_I);
    659 			return (1);
    660 		}
    661 
    662 		store[0] = *pf;
    663 		store[1].name = 0;
    664 
    665 	}
    666 
    667 	/*
    668 	 * Having stored the archived filter(s) in our own area, clear
    669 	 * the currently loaded table so that the subsequent calls to
    670 	 * "putfilter()" will read in the regular table.
    671 	 */
    672 	trash_filters ();
    673 
    674 	at_least_one = ret = 0;
    675 	for (ps = store; ps->name; ps++)
    676 		if (putfilter(ps->name, ps) == -1) {
    677 			same_complaints (FILTERTABLE, TABLE);
    678 			ret = 1;
    679 			break;
    680 		} else
    681 			at_least_one = 1;
    682 
    683 	if (at_least_one)
    684 		(void)alert_spooler ();
    685 
    686 	return (ret);
    687 }
    688 
    689 /**
    690  ** delete_filter()
    691  **/
    692 
    693 int			delete_filter (filter)
    694 	char			*filter;
    695 {
    696 	if (delfilter(filter) == -1) switch (errno) {
    697 	case ENOENT:
    698 		LP_ERRMSG1 (ERROR, E_FL_UNKFILT, filter);
    699 		return (1);
    700 	default:
    701 		same_complaints (FILTERTABLE, TABLE);
    702 		return (1);
    703 	}
    704 
    705 	(void)alert_spooler ();
    706 
    707 	return (0);
    708 }
    709 
    710 /**
    711  ** list_filter()
    712  **/
    713 
    714 static void		_list_filter();
    715 
    716 int			list_filter (filter)
    717 	char			*filter;
    718 {
    719 	register FILTER		*pf;
    720 
    721 	char			*nl;
    722 
    723 	if (STREQU(NAME_ALL, filter)) {
    724 
    725 		nl = "";
    726 		while ((pf = getfilter(filter))) {
    727 			printf (gettext("%s(Filter \"%s\")\n"), nl, pf->name);
    728 			_list_filter (pf);
    729 			nl = "\n";
    730 		}
    731 
    732 		switch (errno) {
    733 		case ENOENT:
    734 			return (0);
    735 		default:
    736 			same_complaints (FILTERTABLE, TABLE);
    737 			return (1);
    738 		}
    739 
    740 	} else {
    741 
    742 		if ((pf = getfilter(filter))) {
    743 			_list_filter (pf);
    744 			return (0);
    745 		}
    746 
    747 		switch (errno) {
    748 		case ENOENT:
    749 			LP_ERRMSG1 (ERROR, E_FL_UNKFILT, filter);
    750 			return (1);
    751 		default:
    752 			same_complaints (FILTERTABLE, TABLE);
    753 			return (1);
    754 		}
    755 
    756 	}
    757 }
    758 
    759 static void		_list_filter (pf)
    760 	register FILTER		*pf;
    761 {
    762 	register char		**pp,
    763 				*sep;
    764 
    765 	register int		fld;
    766 
    767 	char *			head;
    768 
    769 
    770 	for (fld = 0; fld < FL_MAX_P; fld++) switch (fld) {
    771 	case FL_IGN_P:
    772 	case FL_NAME_P:
    773 		break;
    774 	case FL_CMD_P:
    775 		printf (
    776 			"%s %s\n",
    777 			headings[fld].v,
    778 			(pf->command? pf->command : "")
    779 		);
    780 		break;
    781 	case FL_TYPE_P:
    782 		printf (
    783 			"%s %s\n",
    784 			headings[fld].v,
    785 			(pf->type == fl_fast? FL_FAST : FL_SLOW)
    786 		);
    787 		break;
    788 	case FL_PTYPS_P:
    789 		pp = pf->printer_types;
    790 		goto Lists;
    791 	case FL_ITYPS_P:
    792 		pp = pf->input_types;
    793 		goto Lists;
    794 	case FL_OTYPS_P:
    795 		pp = pf->output_types;
    796 		goto Lists;
    797 	case FL_PRTRS_P:
    798 		pp = pf->printers;
    799 Lists:		printlist_qsep = 1;
    800 		printlist_setup ("", "", LP_SEP, "");
    801 		printf ("%s ", headings[fld].v);
    802 		printlist (stdout, pp);
    803 		printf ("\n");
    804 		break;
    805 	case FL_TMPS_P:
    806 		head = makestr(headings[fld].v, " ", (char *)0);
    807 		printlist_qsep = 1;
    808 		printlist_setup (head, "", "\n", "\n");
    809 		printlist (stdout, pf->templates);
    810 		break;
    811 	}
    812 
    813 	return;
    814 }
    815 
    816 /**
    817  ** opt() - GENERATE OPTION FROM FUNCTION NAME
    818  **/
    819 
    820 static char		*opt (fnc)
    821 	int			(*fnc)();
    822 {
    823 	if (fnc == add_filter)
    824 		return ("-F");
    825 	else if (fnc == reload_filter)
    826 		return ("-i");
    827 	else if (fnc == list_filter)
    828 		return ("-l");
    829 	else if (fnc == delete_filter)
    830 		return ("-x");
    831 	else
    832 		return ("-?");
    833 }
    834 
    835 /**
    836  ** alert_spooler() - TELL SPOOLER TO LOAD FILTER TABLE
    837  **/
    838 
    839 static void		alert_spooler ()
    840 {
    841 	char			msgbuf[MSGMAX];
    842 
    843 	int			mtype;
    844 
    845 	short			status;
    846 
    847 	/*
    848 	 * If the attempt to open a message queue to the
    849 	 * Spooler fails, assume it isn't running and just
    850 	 * return--don't say anything, `cause the user may
    851 	 * know. Any other failure deserves an error message.
    852 	 */
    853 
    854 	if (mopen() == -1)
    855 		return;
    856 
    857 	(void)putmessage (msgbuf, S_LOAD_FILTER_TABLE);
    858 
    859 	if (msend(msgbuf) == -1)
    860 		goto Error;
    861 	if (mrecv(msgbuf, MSGMAX) == -1)
    862 		goto Error;
    863 
    864 	mtype = getmessage(msgbuf, R_LOAD_FILTER_TABLE, &status);
    865 	if (mtype != R_LOAD_FILTER_TABLE) {
    866 		LP_ERRMSG1 (ERROR, E_LP_BADREPLY, mtype);
    867 		(void)mclose ();
    868 		exit (1);
    869 	}
    870 
    871 	if (status == MOK)
    872 		goto NoError;
    873 
    874 Error:	LP_ERRMSG (ERROR, E_FL_NOSPLOAD);
    875 
    876 NoError:(void)mclose ();
    877 	return;
    878 
    879 }
    880 
    881 /**
    882  ** same_complaints() - PRINT COMMON ERROR MESSAGES
    883  **/
    884 
    885 static void		same_complaints (table, type)
    886 	char			*table;
    887 	int			type;
    888 {
    889 	switch (errno) {
    890 	case EACCES:
    891 		if (type == TABLE)
    892 			LP_ERRMSG1 (
    893 				ERROR,
    894 				E_FL_ACCESS,
    895 				getfilterfile(table)
    896 			);
    897 		else
    898 			LP_ERRMSG1 (
    899 				ERROR,
    900 				E_FL_ACCESSI,
    901 				getfilterfile(table)
    902 			);
    903 		break;
    904 	case EAGAIN:
    905 	case EDEADLK:
    906 		LP_ERRMSG1 (ERROR, E_LP_AGAIN, getfilterfile(table));
    907 		break;
    908 	default:
    909 		LP_ERRMSG2 (
    910 			ERROR,
    911 			E_FL_UNKNOWN,
    912 			getfilterfile(table),
    913 			strerror(errno)
    914 		);
    915 		break;
    916 	}
    917 	return;
    918 }
    919