xref: /netbsd/usr.sbin/rpc.pcnfsd/pcnfsd_print.c (revision 7cb2935c)
1*7cb2935cSjoerg /*	$NetBSD: pcnfsd_print.c,v 1.16 2020/04/22 23:46:02 joerg Exp $	*/
2457d5a17Sgwr 
382b75dfdSjtc /* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_print.c 1.7 92/01/24 19:58:58 SMI */
482b75dfdSjtc /*
582b75dfdSjtc **=====================================================================
682b75dfdSjtc ** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
782b75dfdSjtc **	@(#)pcnfsd_print.c	1.7	1/24/92
882b75dfdSjtc **=====================================================================
982b75dfdSjtc */
1082b75dfdSjtc /*
1182b75dfdSjtc **=====================================================================
1282b75dfdSjtc **             I N C L U D E   F I L E   S E C T I O N                *
1382b75dfdSjtc **                                                                    *
1482b75dfdSjtc ** If your port requires different include files, add a suitable      *
1582b75dfdSjtc ** #define in the customization section, and make the inclusion or    *
1682b75dfdSjtc ** exclusion of the files conditional on this.                        *
1782b75dfdSjtc **=====================================================================
1882b75dfdSjtc */
19736ba086Slukem 
2082b75dfdSjtc #include <sys/file.h>
2182b75dfdSjtc #include <sys/ioctl.h>
22736ba086Slukem #include <sys/stat.h>
23736ba086Slukem 
24736ba086Slukem #include <ctype.h>
2582b75dfdSjtc #include <errno.h>
26736ba086Slukem #include <netdb.h>
27736ba086Slukem #include <pwd.h>
28736ba086Slukem #include <signal.h>
29736ba086Slukem #include <stdio.h>
30736ba086Slukem #include <stdlib.h>
3182b75dfdSjtc #include <string.h>
32736ba086Slukem #include <unistd.h>
3382b75dfdSjtc 
3482b75dfdSjtc #ifndef SYSV
3582b75dfdSjtc #include <sys/wait.h>
3682b75dfdSjtc #endif
3782b75dfdSjtc 
3882b75dfdSjtc #ifdef ISC_2_0
3982b75dfdSjtc #include <sys/fcntl.h>
4082b75dfdSjtc #endif
4182b75dfdSjtc 
4282b75dfdSjtc #ifdef SHADOW_SUPPORT
4382b75dfdSjtc #include <shadow.h>
4482b75dfdSjtc #endif
4582b75dfdSjtc 
466f885de1Sgwr #include "paths.h"
476f885de1Sgwr 
48736ba086Slukem #include "common.h"
49736ba086Slukem #include "pcnfsd.h"
50736ba086Slukem #include "extern.h"
51736ba086Slukem 
5282b75dfdSjtc /*
5382b75dfdSjtc **---------------------------------------------------------------------
5482b75dfdSjtc ** Other #define's
5582b75dfdSjtc **---------------------------------------------------------------------
5682b75dfdSjtc */
5782b75dfdSjtc #ifndef MAXPATHLEN
5882b75dfdSjtc #define MAXPATHLEN 1024
5982b75dfdSjtc #endif
6082b75dfdSjtc 
6182b75dfdSjtc /*
62b1c7ac0eSwiz ** The following definitions give the maximum time allowed for
6382b75dfdSjtc ** an external command to run (in seconds)
6482b75dfdSjtc */
6582b75dfdSjtc #define MAXTIME_FOR_PRINT	10
6682b75dfdSjtc #define MAXTIME_FOR_QUEUE	10
6782b75dfdSjtc #define MAXTIME_FOR_CANCEL	10
6882b75dfdSjtc #define MAXTIME_FOR_STATUS	10
6982b75dfdSjtc 
7082b75dfdSjtc #define QMAX 50
7182b75dfdSjtc 
7282b75dfdSjtc /*
7382b75dfdSjtc ** The following is derived from ucb/lpd/displayq.c
7482b75dfdSjtc */
7582b75dfdSjtc #define SIZECOL 62
7682b75dfdSjtc #define FILECOL 24
7782b75dfdSjtc 
78d6aaec91Ssevan char   *expand_alias(char *, char *, char *, char *);
79d6aaec91Ssevan pr_list	list_virtual_printers(void);
80d6aaec91Ssevan char   *map_printer_name(char *);
81d6aaec91Ssevan void	substitute(char *, const char *, const char *);
82d6aaec91Ssevan int	suspicious(char *);
83d6aaec91Ssevan int	valid_pr(char *);
8482b75dfdSjtc 
8582b75dfdSjtc /*
8682b75dfdSjtc **---------------------------------------------------------------------
8782b75dfdSjtc **                       Misc. variable definitions
8882b75dfdSjtc **---------------------------------------------------------------------
8982b75dfdSjtc */
9082b75dfdSjtc 
9182b75dfdSjtc struct stat statbuf;
9282b75dfdSjtc char    pathname[MAXPATHLEN];
9382b75dfdSjtc char    new_pathname[MAXPATHLEN];
9482b75dfdSjtc char    sp_name[MAXPATHLEN] = SPOOLDIR;
95*7cb2935cSjoerg static char tempstr[256];
9682b75dfdSjtc char    delims[] = " \t\r\n:()";
9782b75dfdSjtc 
9882b75dfdSjtc pr_list printers = NULL;
9982b75dfdSjtc pr_queue queue = NULL;
10082b75dfdSjtc 
10182b75dfdSjtc /*
10282b75dfdSjtc **=====================================================================
10382b75dfdSjtc **                      C O D E   S E C T I O N                       *
10482b75dfdSjtc **=====================================================================
10582b75dfdSjtc */
10682b75dfdSjtc 
10782b75dfdSjtc /*
10882b75dfdSjtc  * This is the latest word on the security check. The following
10982b75dfdSjtc  * routine "suspicious()" returns non-zero if the character string
11082b75dfdSjtc  * passed to it contains any shell metacharacters.
11182b75dfdSjtc  * Callers will typically code
11282b75dfdSjtc  *
11382b75dfdSjtc  *	if(suspicious(some_parameter)) reject();
11482b75dfdSjtc  */
11582b75dfdSjtc 
116736ba086Slukem int
suspicious(char * s)117d6aaec91Ssevan suspicious(char *s)
11882b75dfdSjtc {
119d87f04d7Sgwr 	if (strpbrk(s, ";|&<>`'#!?*()[]^/${}\n\r\"\\:") != NULL)
12082b75dfdSjtc 		return 1;
12182b75dfdSjtc 	return 0;
12282b75dfdSjtc }
12382b75dfdSjtc 
12482b75dfdSjtc 
12582b75dfdSjtc int
valid_pr(char * pr)126d6aaec91Ssevan valid_pr(char *pr)
12782b75dfdSjtc {
12882b75dfdSjtc 	char   *p;
12982b75dfdSjtc 	pr_list curr;
13082b75dfdSjtc 	if (printers == NULL)
13182b75dfdSjtc 		build_pr_list();
13282b75dfdSjtc 
13382b75dfdSjtc 	if (printers == NULL)
13482b75dfdSjtc 		return (1);	/* can't tell - assume it's good */
13582b75dfdSjtc 
13682b75dfdSjtc 	p = map_printer_name(pr);
13782b75dfdSjtc 	if (p == NULL)
13882b75dfdSjtc 		return (1);	/* must be ok is maps to NULL! */
13982b75dfdSjtc 	curr = printers;
14082b75dfdSjtc 	while (curr) {
14182b75dfdSjtc 		if (!strcmp(p, curr->pn))
14282b75dfdSjtc 			return (1);
14382b75dfdSjtc 		curr = curr->pr_next;
14482b75dfdSjtc 	}
14582b75dfdSjtc 
14682b75dfdSjtc 	return (0);
14782b75dfdSjtc }
148d87f04d7Sgwr /*
149d87f04d7Sgwr  * get pathname of current directory and return to client
150d87f04d7Sgwr  *
151d87f04d7Sgwr  * Note: This runs as root on behalf of a client request.
152d87f04d7Sgwr  * As described in CERT advisory CA-96.08, be careful about
153d87f04d7Sgwr  * doing a chmod on something that could be a symlink...
154d87f04d7Sgwr  */
155d87f04d7Sgwr pirstat
pr_init(char * sys,char * pr,char ** sp)156d6aaec91Ssevan pr_init(char *sys, char *pr, char **sp)
15782b75dfdSjtc {
15882b75dfdSjtc 	int     dir_mode = 0777;
15982b75dfdSjtc 	int     rc;
160d87f04d7Sgwr 	mode_t  oldmask;
16182b75dfdSjtc 
16282b75dfdSjtc 	*sp = &pathname[0];
16382b75dfdSjtc 	pathname[0] = '\0';
16482b75dfdSjtc 
16582b75dfdSjtc 	if (suspicious(sys) || suspicious(pr))
16682b75dfdSjtc 		return (PI_RES_FAIL);
16782b75dfdSjtc 
168d87f04d7Sgwr 	/*
169d87f04d7Sgwr 	 * Make sure the server spool directory exists.
170d87f04d7Sgwr 	 * Never create it here - the sysadmin does that.
171d87f04d7Sgwr 	 */
172d87f04d7Sgwr 	if (stat(sp_name, &statbuf) || !S_ISDIR(statbuf.st_mode))
173d87f04d7Sgwr 		goto badspool;
17482b75dfdSjtc 
175d87f04d7Sgwr 	/*
176d87f04d7Sgwr 	 * Create the client spool directory if needed.
177d87f04d7Sgwr 	 * Just do the mkdir call and ignore EEXIST.
178d87f04d7Sgwr 	 * Mode of client directory should be 777.
179d87f04d7Sgwr 	 */
1805d573dd9Sitojun 	(void) snprintf(pathname, sizeof(pathname), "%s/%s", sp_name, sys);
181d87f04d7Sgwr 	oldmask = umask(0);
18282b75dfdSjtc 	rc = mkdir(pathname, dir_mode);	/* DON'T ignore this return code */
183d87f04d7Sgwr 	umask(oldmask);
184d87f04d7Sgwr 	if ((rc < 0) && (errno != EEXIST))
185d87f04d7Sgwr 		goto badspool;
186d87f04d7Sgwr 
187d87f04d7Sgwr 	/* By this point the client spool dir should exist. */
188d87f04d7Sgwr 	if (stat(pathname, &statbuf) || !S_ISDIR(statbuf.st_mode)) {
189d87f04d7Sgwr 		/* No spool directory... */
190d87f04d7Sgwr badspool:
1915d573dd9Sitojun 		(void) snprintf(tempstr, sizeof(tempstr),
19282b75dfdSjtc 		    "rpc.pcnfsd: unable to set up spool directory %s\n",
19382b75dfdSjtc 		    pathname);
19482b75dfdSjtc 		msg_out(tempstr);
19582b75dfdSjtc 		pathname[0] = '\0';	/* null to tell client bad vibes */
19682b75dfdSjtc 		return (PI_RES_FAIL);
19782b75dfdSjtc 	}
198d87f04d7Sgwr 	/* OK, we have a spool directory. */
199d87f04d7Sgwr 	if (!valid_pr(pr)) {
20082b75dfdSjtc 		pathname[0] = '\0';	/* null to tell client bad vibes */
20182b75dfdSjtc 		return (PI_RES_NO_SUCH_PRINTER);
20282b75dfdSjtc 	}
20382b75dfdSjtc 	return (PI_RES_OK);
20482b75dfdSjtc }
205736ba086Slukem psrstat
pr_start2(char * sys,char * pr,char * user,char * fname,char * opts,char ** id)206d6aaec91Ssevan pr_start2(char *sys, char *pr, char *user, char *fname, char *opts, char **id)
20782b75dfdSjtc {
20882b75dfdSjtc 	char    snum[20];
20982b75dfdSjtc 	static char req_id[256];
21082b75dfdSjtc 	char    cmdbuf[256];
21182b75dfdSjtc 	char    resbuf[256];
21282b75dfdSjtc 	FILE   *fd;
21382b75dfdSjtc 	int     i;
21482b75dfdSjtc 	char   *xcmd;
21582b75dfdSjtc 	int     failed = 0;
21682b75dfdSjtc 
21782b75dfdSjtc #ifdef HACK_FOR_ROTATED_TRANSCRIPT
21882b75dfdSjtc 	char    scratch[512];
21982b75dfdSjtc #endif
22082b75dfdSjtc 
22182b75dfdSjtc 
2220466bbb6Slukem 	if (suspicious(sys) ||
22382b75dfdSjtc 	    suspicious(pr) ||
22482b75dfdSjtc 	    suspicious(user) ||
22582b75dfdSjtc 	    suspicious(fname))
22682b75dfdSjtc 		return (PS_RES_FAIL);
22782b75dfdSjtc 
2285d573dd9Sitojun 	(void) snprintf(pathname, sizeof(pathname), "%s/%s/%s", sp_name,
2290466bbb6Slukem 	    sys,
23082b75dfdSjtc 	    fname);
23182b75dfdSjtc 
23282b75dfdSjtc 	*id = &req_id[0];
23382b75dfdSjtc 	req_id[0] = '\0';
23482b75dfdSjtc 
235736ba086Slukem 	if (stat(pathname, &statbuf)) {
23682b75dfdSjtc 		/*
23782b75dfdSjtc                 **-----------------------------------------------------------------
23882b75dfdSjtc 	        ** We can't stat the file. Let's try appending '.spl' and
23982b75dfdSjtc 	        ** see if it's already in progress.
24082b75dfdSjtc                 **-----------------------------------------------------------------
24182b75dfdSjtc 	        */
24282b75dfdSjtc 
2435d573dd9Sitojun 		(void) strlcat(pathname, ".spl", sizeof(pathname));
244736ba086Slukem 		if (stat(pathname, &statbuf)) {
24582b75dfdSjtc 			/*
24682b75dfdSjtc 	                **----------------------------------------------------------------
24782b75dfdSjtc 		        ** It really doesn't exist.
24882b75dfdSjtc 	                **----------------------------------------------------------------
24982b75dfdSjtc 		        */
25082b75dfdSjtc 
25182b75dfdSjtc 
25282b75dfdSjtc 			return (PS_RES_NO_FILE);
25382b75dfdSjtc 		}
25482b75dfdSjtc 		/*
25582b75dfdSjtc                 **-------------------------------------------------------------
25682b75dfdSjtc 	        ** It is already on the way.
25782b75dfdSjtc                 **-------------------------------------------------------------
25882b75dfdSjtc 	        */
25982b75dfdSjtc 
26082b75dfdSjtc 
26182b75dfdSjtc 		return (PS_RES_ALREADY);
26282b75dfdSjtc 	}
263736ba086Slukem 	if (statbuf.st_size == 0) {
26482b75dfdSjtc 		/*
26582b75dfdSjtc                 **-------------------------------------------------------------
26682b75dfdSjtc 	        ** Null file - don't print it, just kill it.
26782b75dfdSjtc                 **-------------------------------------------------------------
26882b75dfdSjtc 	        */
26982b75dfdSjtc 		(void) unlink(pathname);
27082b75dfdSjtc 
27182b75dfdSjtc 		return (PS_RES_NULL);
27282b75dfdSjtc 	}
27382b75dfdSjtc 	/*
27482b75dfdSjtc         **-------------------------------------------------------------
27582b75dfdSjtc         ** The file is real, has some data, and is not already going out.
27682b75dfdSjtc         ** We rename it by appending '.spl' and exec "lpr" to do the
27782b75dfdSjtc         ** actual work.
27882b75dfdSjtc         **-------------------------------------------------------------
27982b75dfdSjtc         */
2805d573dd9Sitojun 	(void) strlcpy(new_pathname, pathname, sizeof(new_pathname));
2815d573dd9Sitojun 	(void) strlcat(new_pathname, ".spl", sizeof(new_pathname));
28282b75dfdSjtc 
28382b75dfdSjtc 	/*
28482b75dfdSjtc         **-------------------------------------------------------------
28582b75dfdSjtc 	** See if the new filename exists so as not to overwrite it.
28682b75dfdSjtc         **-------------------------------------------------------------
28782b75dfdSjtc 	*/
28882b75dfdSjtc 
28982b75dfdSjtc 
290736ba086Slukem 	if (!stat(new_pathname, &statbuf)) {
2915d573dd9Sitojun 		(void) strlcpy(new_pathname, pathname, sizeof(new_pathname)); /* rebuild a new name */
2925d573dd9Sitojun 		(void) snprintf(snum, sizeof(snum), "%d", rand()); /* get some number */
2935d573dd9Sitojun 		(void) strlcat(new_pathname, snum, 4);
2945d573dd9Sitojun 		(void) strlcat(new_pathname, ".spl", sizeof(new_pathname)); /* new spool file */
29582b75dfdSjtc 	}
296736ba086Slukem 	if (rename(pathname, new_pathname)) {
29782b75dfdSjtc 		/*
29882b75dfdSjtc                 **---------------------------------------------------------------
29982b75dfdSjtc 	        ** Should never happen.
30082b75dfdSjtc                 **---------------------------------------------------------------
30182b75dfdSjtc                 */
3025d573dd9Sitojun 		(void) snprintf(tempstr, sizeof(tempstr),
3035d573dd9Sitojun 		    "rpc.pcnfsd: spool file rename (%s->%s) failed.\n",
30482b75dfdSjtc 		    pathname, new_pathname);
30582b75dfdSjtc 		msg_out(tempstr);
30682b75dfdSjtc 		return (PS_RES_FAIL);
30782b75dfdSjtc 	}
308d87f04d7Sgwr 	if (*opts == 'd') {
30982b75dfdSjtc 		/*
31082b75dfdSjtc 		 **------------------------------------------------------
31182b75dfdSjtc 		 ** This is a Diablo print stream. Apply the ps630
31282b75dfdSjtc 		 ** filter with the appropriate arguments.
31382b75dfdSjtc 		 **------------------------------------------------------
31482b75dfdSjtc 		 */
315736ba086Slukem #if 0				/* XXX: Temporary fix for CERT advisory
316736ba086Slukem 				 * CA-96.08 */
31782b75dfdSjtc 		(void) run_ps630(new_pathname, opts);
318d87f04d7Sgwr #else
3195d573dd9Sitojun 		(void) snprintf(tempstr, sizeof(tempstr),
320d87f04d7Sgwr 		    "rpc.pcnfsd: ps630 filter disabled for %s\n", pathname);
321d87f04d7Sgwr 		msg_out(tempstr);
322d87f04d7Sgwr 		return (PS_RES_FAIL);
323d87f04d7Sgwr #endif
32482b75dfdSjtc 	}
32582b75dfdSjtc 	/*
32682b75dfdSjtc 	** Try to match to an aliased printer
32782b75dfdSjtc 	*/
3280466bbb6Slukem 	xcmd = expand_alias(pr, new_pathname, user, sys);
32982b75dfdSjtc 	if (!xcmd) {
3306f885de1Sgwr #ifdef	SVR4
3316f885de1Sgwr 		/*
33229c185b0Smsaitoh 			 * Use the copy option so we can remove the original
3336f885de1Sgwr 			 * spooled nfs file from the spool directory.
3346f885de1Sgwr 			 */
3355d573dd9Sitojun 		snprintf(cmdbuf, sizeof(cmdbuf), "/usr/bin/lp -c -d%s %s",
3366f885de1Sgwr 		    pr, new_pathname);
3376f885de1Sgwr #else				/* SVR4 */
3386f885de1Sgwr 		/* BSD way: lpr */
3395d573dd9Sitojun 		snprintf(cmdbuf, sizeof(cmdbuf), "%s/lpr -P%s %s",
34082b75dfdSjtc 		    LPRDIR, pr, new_pathname);
3416f885de1Sgwr #endif				/* SVR4 */
34282b75dfdSjtc 		xcmd = cmdbuf;
34382b75dfdSjtc 	}
34482b75dfdSjtc 	if ((fd = su_popen(user, xcmd, MAXTIME_FOR_PRINT)) == NULL) {
34582b75dfdSjtc 		msg_out("rpc.pcnfsd: su_popen failed");
34682b75dfdSjtc 		return (PS_RES_FAIL);
34782b75dfdSjtc 	}
348a8f06ecbSmbalmer 	req_id[0] = '\0';	/* assume failure */
34982b75dfdSjtc 	while (fgets(resbuf, 255, fd) != NULL) {
35082b75dfdSjtc 		i = strlen(resbuf);
35182b75dfdSjtc 		if (i)
35282b75dfdSjtc 			resbuf[i - 1] = '\0';	/* trim NL */
35382b75dfdSjtc 		if (!strncmp(resbuf, "request id is ", 14))
35482b75dfdSjtc 			/* New - just the first word is needed */
3555d573dd9Sitojun 			strlcpy(req_id, strtok(&resbuf[14], delims),
3565d573dd9Sitojun 			    sizeof(req_id));
357736ba086Slukem 		else
358736ba086Slukem 			if (strembedded("disabled", resbuf))
35982b75dfdSjtc 				failed = 1;
36082b75dfdSjtc 	}
36182b75dfdSjtc 	if (su_pclose(fd) == 255)
36282b75dfdSjtc 		msg_out("rpc.pcnfsd: su_pclose alert");
36382b75dfdSjtc 	(void) unlink(new_pathname);
36482b75dfdSjtc 	return ((failed | interrupted) ? PS_RES_FAIL : PS_RES_OK);
36582b75dfdSjtc }
36682b75dfdSjtc /*
3676f885de1Sgwr  * build_pr_list: determine which printers are valid.
36882b75dfdSjtc  * on SVR4 use "lpstat -v"
3696f885de1Sgwr  * on BSD use "lpc status"
3706f885de1Sgwr  */
3716f885de1Sgwr 
3726f885de1Sgwr #ifdef	SVR4
3736f885de1Sgwr /*
3746f885de1Sgwr  * In SVR4 the command to determine which printers are
3756f885de1Sgwr  * valid is lpstat -v. The output is something like this:
3766f885de1Sgwr  *
3776f885de1Sgwr  * device for lp: /dev/lp0
3786f885de1Sgwr  * system for pcdslw: hinode
3796f885de1Sgwr  * system for bletch: hinode (as printer hisname)
3806f885de1Sgwr  *
3816f885de1Sgwr  * On SunOS using the SysV compatibility package, the output
3826f885de1Sgwr  * is more like:
3836f885de1Sgwr  *
3846f885de1Sgwr  * device for lp is /dev/lp0
3856f885de1Sgwr  * device for pcdslw is the remote printer pcdslw on hinode
3866f885de1Sgwr  * device for bletch is the remote printer hisname on hinode
3876f885de1Sgwr  *
3886f885de1Sgwr  * It is fairly simple to create logic that will handle either
3896f885de1Sgwr  * possibility:
3906f885de1Sgwr  */
3916f885de1Sgwr int
build_pr_list()3926f885de1Sgwr build_pr_list()
3936f885de1Sgwr {
3946f885de1Sgwr 	pr_list last = NULL;
3956f885de1Sgwr 	pr_list curr = NULL;
3966f885de1Sgwr 	char    buff[256];
3976f885de1Sgwr 	FILE   *p;
3986f885de1Sgwr 	char   *cp;
3996f885de1Sgwr 	int     saw_system;
4006f885de1Sgwr 
4016f885de1Sgwr 	p = popen("lpstat -v", "r");
4026f885de1Sgwr 	if (p == NULL) {
4036f885de1Sgwr 		msg_out("rpc.pcnfsd: unable to popen() lp status");
4046f885de1Sgwr 		return (0);
4056f885de1Sgwr 	}
4066f885de1Sgwr 	while (fgets(buff, 255, p) != NULL) {
4076f885de1Sgwr 		cp = strtok(buff, delims);
4086f885de1Sgwr 		if (!cp)
4096f885de1Sgwr 			continue;
4106f885de1Sgwr 		if (!strcmp(cp, "device"))
4116f885de1Sgwr 			saw_system = 0;
412736ba086Slukem 		else
413736ba086Slukem 			if (!strcmp(cp, "system"))
4146f885de1Sgwr 				saw_system = 1;
4156f885de1Sgwr 			else
4166f885de1Sgwr 				continue;
4176f885de1Sgwr 		cp = strtok(NULL, delims);
4186f885de1Sgwr 		if (!cp || strcmp(cp, "for"))
4196f885de1Sgwr 			continue;
4206f885de1Sgwr 		cp = strtok(NULL, delims);
4216f885de1Sgwr 		if (!cp)
4226f885de1Sgwr 			continue;
4236f885de1Sgwr 		curr = (struct pr_list_item *)
4246f885de1Sgwr 		    grab(sizeof(struct pr_list_item));
4256f885de1Sgwr 
4266f885de1Sgwr 		curr->pn = strdup(cp);
4276f885de1Sgwr 		curr->device = NULL;
4286f885de1Sgwr 		curr->remhost = NULL;
4296f885de1Sgwr 		curr->cm = strdup("-");
4306f885de1Sgwr 		curr->pr_next = NULL;
4316f885de1Sgwr 
4326f885de1Sgwr 		cp = strtok(NULL, delims);
4336f885de1Sgwr 
4346f885de1Sgwr 		if (cp && !strcmp(cp, "is"))
4356f885de1Sgwr 			cp = strtok(NULL, delims);
4366f885de1Sgwr 
4376f885de1Sgwr 		if (!cp) {
4386f885de1Sgwr 			free_pr_list_item(curr);
4396f885de1Sgwr 			continue;
4406f885de1Sgwr 		}
4416f885de1Sgwr 		if (saw_system) {
4426f885de1Sgwr 			/* "system" OR "system (as printer pname)" */
4436f885de1Sgwr 			curr->remhost = strdup(cp);
4446f885de1Sgwr 			cp = strtok(NULL, delims);
4456f885de1Sgwr 			if (!cp) {
4466f885de1Sgwr 				/* simple format */
4476f885de1Sgwr 				curr->device = strdup(curr->pn);
4486f885de1Sgwr 			} else {
4496f885de1Sgwr 				/* "sys (as printer pname)" */
4506f885de1Sgwr 				if (strcmp(cp, "as")) {
4516f885de1Sgwr 					free_pr_list_item(curr);
4526f885de1Sgwr 					continue;
4536f885de1Sgwr 				}
4546f885de1Sgwr 				cp = strtok(NULL, delims);
4556f885de1Sgwr 				if (!cp || strcmp(cp, "printer")) {
4566f885de1Sgwr 					free_pr_list_item(curr);
4576f885de1Sgwr 					continue;
4586f885de1Sgwr 				}
4596f885de1Sgwr 				cp = strtok(NULL, delims);
4606f885de1Sgwr 				if (!cp) {
4616f885de1Sgwr 					free_pr_list_item(curr);
4626f885de1Sgwr 					continue;
4636f885de1Sgwr 				}
4646f885de1Sgwr 				curr->device = strdup(cp);
4656f885de1Sgwr 			}
466736ba086Slukem 		} else
467736ba086Slukem 			if (!strcmp(cp, "the")) {
4686f885de1Sgwr 				/* start of "the remote printer foo on bar" */
4696f885de1Sgwr 				cp = strtok(NULL, delims);
4706f885de1Sgwr 				if (!cp || strcmp(cp, "remote")) {
4716f885de1Sgwr 					free_pr_list_item(curr);
4726f885de1Sgwr 					continue;
4736f885de1Sgwr 				}
4746f885de1Sgwr 				cp = strtok(NULL, delims);
4756f885de1Sgwr 				if (!cp || strcmp(cp, "printer")) {
4766f885de1Sgwr 					free_pr_list_item(curr);
4776f885de1Sgwr 					continue;
4786f885de1Sgwr 				}
4796f885de1Sgwr 				cp = strtok(NULL, delims);
4806f885de1Sgwr 				if (!cp) {
4816f885de1Sgwr 					free_pr_list_item(curr);
4826f885de1Sgwr 					continue;
4836f885de1Sgwr 				}
4846f885de1Sgwr 				curr->device = strdup(cp);
4856f885de1Sgwr 				cp = strtok(NULL, delims);
4866f885de1Sgwr 				if (!cp || strcmp(cp, "on")) {
4876f885de1Sgwr 					free_pr_list_item(curr);
4886f885de1Sgwr 					continue;
4896f885de1Sgwr 				}
4906f885de1Sgwr 				cp = strtok(NULL, delims);
4916f885de1Sgwr 				if (!cp) {
4926f885de1Sgwr 					free_pr_list_item(curr);
4936f885de1Sgwr 					continue;
4946f885de1Sgwr 				}
4956f885de1Sgwr 				curr->remhost = strdup(cp);
4966f885de1Sgwr 			} else {
4976f885de1Sgwr 				/* the local name */
4986f885de1Sgwr 				curr->device = strdup(cp);
4996f885de1Sgwr 				curr->remhost = strdup("");
5006f885de1Sgwr 			}
5016f885de1Sgwr 
5026f885de1Sgwr 		if (last == NULL)
5036f885de1Sgwr 			printers = curr;
5046f885de1Sgwr 		else
5056f885de1Sgwr 			last->pr_next = curr;
5066f885de1Sgwr 		last = curr;
5076f885de1Sgwr 
5086f885de1Sgwr 	}
5096f885de1Sgwr 	(void) pclose(p);
5106f885de1Sgwr 
5116f885de1Sgwr 	/*
5126f885de1Sgwr 	 ** Now add on the virtual printers, if any
5136f885de1Sgwr 	 */
5146f885de1Sgwr 	if (last == NULL)
5156f885de1Sgwr 		printers = list_virtual_printers();
5166f885de1Sgwr 	else
5176f885de1Sgwr 		last->pr_next = list_virtual_printers();
5186f885de1Sgwr 
5196f885de1Sgwr 	return (1);
5206f885de1Sgwr }
5216f885de1Sgwr #else				/* SVR4 */
5226f885de1Sgwr 
5236f885de1Sgwr /*
5246f885de1Sgwr  * BSD way: lpc stat
52582b75dfdSjtc  */
52682b75dfdSjtc int
build_pr_list()52782b75dfdSjtc build_pr_list()
52882b75dfdSjtc {
52982b75dfdSjtc 	pr_list last = NULL;
53082b75dfdSjtc 	pr_list curr = NULL;
53182b75dfdSjtc 	char    buff[256];
53282b75dfdSjtc 	FILE   *p;
53382b75dfdSjtc 	char   *cp;
53482b75dfdSjtc 
5355d573dd9Sitojun 	snprintf(buff, sizeof(buff), "%s/lpc status", LPCDIR);
53682b75dfdSjtc 	p = popen(buff, "r");
53782b75dfdSjtc 	if (p == NULL) {
53882b75dfdSjtc 		msg_out("rpc.pcnfsd: unable to popen lpc stat");
53982b75dfdSjtc 		return (0);
54082b75dfdSjtc 	}
54182b75dfdSjtc 	while (fgets(buff, 255, p) != NULL) {
542c4670c4eSdsl 		if (isspace((unsigned char)buff[0]))
54382b75dfdSjtc 			continue;
54482b75dfdSjtc 
54582b75dfdSjtc 		if ((cp = strtok(buff, delims)) == NULL)
54682b75dfdSjtc 			continue;
54782b75dfdSjtc 
54882b75dfdSjtc 		curr = (struct pr_list_item *)
54982b75dfdSjtc 		    grab(sizeof(struct pr_list_item));
55082b75dfdSjtc 
55182b75dfdSjtc 		/* XXX - Should distinguish remote printers. */
55282b75dfdSjtc 		curr->pn = strdup(cp);
55382b75dfdSjtc 		curr->device = strdup(cp);
55482b75dfdSjtc 		curr->remhost = strdup("");
55582b75dfdSjtc 		curr->cm = strdup("-");
55682b75dfdSjtc 		curr->pr_next = NULL;
55782b75dfdSjtc 
55882b75dfdSjtc 		if (last == NULL)
55982b75dfdSjtc 			printers = curr;
56082b75dfdSjtc 		else
56182b75dfdSjtc 			last->pr_next = curr;
56282b75dfdSjtc 		last = curr;
56382b75dfdSjtc 
56482b75dfdSjtc 	}
5658ad14b9aSwiz 	(void) pclose(p);
56682b75dfdSjtc 
56782b75dfdSjtc 	/*
56882b75dfdSjtc 	 ** Now add on the virtual printers, if any
56982b75dfdSjtc 	 */
57082b75dfdSjtc 	if (last == NULL)
57182b75dfdSjtc 		printers = list_virtual_printers();
57282b75dfdSjtc 	else
57382b75dfdSjtc 		last->pr_next = list_virtual_printers();
57482b75dfdSjtc 
57582b75dfdSjtc 	return (1);
57682b75dfdSjtc }
5776f885de1Sgwr #endif				/* SVR4 */
5786f885de1Sgwr 
579736ba086Slukem void   *
grab(int n)580d6aaec91Ssevan grab(int n)
58182b75dfdSjtc {
58282b75dfdSjtc 	void   *p;
58382b75dfdSjtc 
58482b75dfdSjtc 	p = (void *) malloc(n);
58582b75dfdSjtc 	if (p == NULL) {
58682b75dfdSjtc 		msg_out("rpc.pcnfsd: malloc failure");
58782b75dfdSjtc 		exit(1);
58882b75dfdSjtc 	}
58982b75dfdSjtc 	return (p);
59082b75dfdSjtc }
59182b75dfdSjtc 
59282b75dfdSjtc void
free_pr_list_item(pr_list curr)593d6aaec91Ssevan free_pr_list_item(pr_list curr)
59482b75dfdSjtc {
59582b75dfdSjtc 	if (curr->pn)
59682b75dfdSjtc 		free(curr->pn);
59782b75dfdSjtc 	if (curr->device)
59882b75dfdSjtc 		free(curr->device);
59982b75dfdSjtc 	if (curr->remhost)
60082b75dfdSjtc 		free(curr->remhost);
60182b75dfdSjtc 	if (curr->cm)
60282b75dfdSjtc 		free(curr->cm);
60382b75dfdSjtc 	if (curr->pr_next)
60482b75dfdSjtc 		free_pr_list_item(curr->pr_next);	/* recurse */
60582b75dfdSjtc 	free(curr);
60682b75dfdSjtc }
60782b75dfdSjtc /*
6086f885de1Sgwr  * build_pr_queue:  used to show the print queue.
6096f885de1Sgwr  *
6106f885de1Sgwr  * Note that the first thing we do is to discard any
6116f885de1Sgwr  * existing queue.
61282b75dfdSjtc  */
6136f885de1Sgwr #ifdef SVR4
6146f885de1Sgwr 
6156f885de1Sgwr /*
6166f885de1Sgwr ** In SVR4 the command to list the print jobs for printer
6176f885de1Sgwr ** lp is "lpstat lp" (or, equivalently, "lpstat -p lp").
6186f885de1Sgwr ** The output looks like this:
6196f885de1Sgwr **
6206f885de1Sgwr ** lp-2                    root               939   Jul 10 21:56
6216f885de1Sgwr ** lp-5                    geoff               15   Jul 12 23:23
6226f885de1Sgwr ** lp-6                    geoff               15   Jul 12 23:23
6236f885de1Sgwr **
6246f885de1Sgwr ** If the first job is actually printing the first line
6256f885de1Sgwr ** is modified, as follows:
6266f885de1Sgwr **
6276f885de1Sgwr ** lp-2                    root               939   Jul 10 21:56 on lp
6286f885de1Sgwr **
6296f885de1Sgwr ** I don't yet have any info on what it looks like if the printer
6306f885de1Sgwr ** is remote and we're spooling over the net. However for
6316f885de1Sgwr ** the purposes of rpc.pcnfsd we can simply say that field 1 is the
6326f885de1Sgwr ** job ID, field 2 is the submitter, and field 3 is the size.
6336f885de1Sgwr ** We can check for the presence of the string " on " in the
6346f885de1Sgwr ** first record to determine if we should count it as rank 0 or rank 1,
6356f885de1Sgwr ** but it won't hurt if we get it wrong.
6366f885de1Sgwr **/
6376f885de1Sgwr 
6386f885de1Sgwr pirstat
build_pr_queue(printername pn,username user,int just_mine,int p_qlen,int p_qshown)639d6aaec91Ssevan build_pr_queue(printername pn, username user, int just_mine, int p_qlen, int p_qshown)
6406f885de1Sgwr {
6416f885de1Sgwr 	pr_queue last = NULL;
6426f885de1Sgwr 	pr_queue curr = NULL;
6436f885de1Sgwr 	char    buff[256];
6446f885de1Sgwr 	FILE   *p;
6456f885de1Sgwr 	char   *owner;
6466f885de1Sgwr 	char   *job;
6476f885de1Sgwr 	char   *totsize;
6486f885de1Sgwr 
6496f885de1Sgwr 	if (queue) {
6506f885de1Sgwr 		free_pr_queue_item(queue);
6516f885de1Sgwr 		queue = NULL;
6526f885de1Sgwr 	}
6536f885de1Sgwr 	*p_qlen = 0;
6546f885de1Sgwr 	*p_qshown = 0;
6556f885de1Sgwr 
6566f885de1Sgwr 	pn = map_printer_name(pn);
6576f885de1Sgwr 	if (pn == NULL || !valid_pr(pn) || suspicious(pn))
6586f885de1Sgwr 		return (PI_RES_NO_SUCH_PRINTER);
6596f885de1Sgwr 
6605d573dd9Sitojun 	snprintf(buff, sizeof(buff), "/usr/bin/lpstat %s", pn);
6616f885de1Sgwr 	p = su_popen(user, buff, MAXTIME_FOR_QUEUE);
6626f885de1Sgwr 	if (p == NULL) {
6636f885de1Sgwr 		msg_out("rpc.pcnfsd: unable to popen() lpstat queue query");
6646f885de1Sgwr 		return (PI_RES_FAIL);
6656f885de1Sgwr 	}
6666f885de1Sgwr 	while (fgets(buff, 255, p) != NULL) {
6676f885de1Sgwr 		job = strtok(buff, delims);
6686f885de1Sgwr 		if (!job)
6696f885de1Sgwr 			continue;
6706f885de1Sgwr 
6716f885de1Sgwr 		owner = strtok(NULL, delims);
6726f885de1Sgwr 		if (!owner)
6736f885de1Sgwr 			continue;
6746f885de1Sgwr 
6756f885de1Sgwr 		totsize = strtok(NULL, delims);
6766f885de1Sgwr 		if (!totsize)
6776f885de1Sgwr 			continue;
6786f885de1Sgwr 
6796f885de1Sgwr 		*p_qlen += 1;
6806f885de1Sgwr 
6816f885de1Sgwr 		if (*p_qshown > QMAX)
6826f885de1Sgwr 			continue;
6836f885de1Sgwr 
684736ba086Slukem 		if (just_mine && strcasecmp(owner, user))
6856f885de1Sgwr 			continue;
6866f885de1Sgwr 
6876f885de1Sgwr 		*p_qshown += 1;
6886f885de1Sgwr 
6896f885de1Sgwr 		curr = (struct pr_queue_item *)
6906f885de1Sgwr 		    grab(sizeof(struct pr_queue_item));
6916f885de1Sgwr 
6926f885de1Sgwr 		curr->position = *p_qlen;
6936f885de1Sgwr 		curr->id = strdup(job);
6946f885de1Sgwr 		curr->size = strdup(totsize);
6956f885de1Sgwr 		curr->status = strdup("");
6966f885de1Sgwr 		curr->system = strdup("");
6976f885de1Sgwr 		curr->user = strdup(owner);
6986f885de1Sgwr 		curr->file = strdup("");
6996f885de1Sgwr 		curr->cm = strdup("-");
7006f885de1Sgwr 		curr->pr_next = NULL;
7016f885de1Sgwr 
7026f885de1Sgwr 		if (last == NULL)
7036f885de1Sgwr 			queue = curr;
7046f885de1Sgwr 		else
7056f885de1Sgwr 			last->pr_next = curr;
7066f885de1Sgwr 		last = curr;
7076f885de1Sgwr 
7086f885de1Sgwr 	}
7096f885de1Sgwr 	(void) su_pclose(p);
7106f885de1Sgwr 	return (PI_RES_OK);
7116f885de1Sgwr }
7126f885de1Sgwr #else				/* SVR4 */
71382b75dfdSjtc 
71482b75dfdSjtc pirstat
build_pr_queue(printername pn,username user,int just_mine,int * p_qlen,int * p_qshown)715d6aaec91Ssevan build_pr_queue(printername pn, username user, int just_mine, int *p_qlen, int *p_qshown)
71682b75dfdSjtc {
71782b75dfdSjtc 	pr_queue last = NULL;
71882b75dfdSjtc 	pr_queue curr = NULL;
71982b75dfdSjtc 	char    buff[256];
72082b75dfdSjtc 	FILE   *p;
72182b75dfdSjtc 	char   *cp;
72282b75dfdSjtc 	int     i;
72382b75dfdSjtc 	char   *rank;
72482b75dfdSjtc 	char   *owner;
72582b75dfdSjtc 	char   *job;
72682b75dfdSjtc 	char   *files;
72782b75dfdSjtc 	char   *totsize;
72882b75dfdSjtc 
72982b75dfdSjtc 	if (queue) {
73082b75dfdSjtc 		free_pr_queue_item(queue);
73182b75dfdSjtc 		queue = NULL;
73282b75dfdSjtc 	}
73382b75dfdSjtc 	*p_qlen = 0;
73482b75dfdSjtc 	*p_qshown = 0;
73582b75dfdSjtc 	pn = map_printer_name(pn);
73682b75dfdSjtc 	if (pn == NULL || suspicious(pn))
73782b75dfdSjtc 		return (PI_RES_NO_SUCH_PRINTER);
73882b75dfdSjtc 
7395d573dd9Sitojun 	snprintf(buff, sizeof(buff), "%s/lpq -P%s", LPRDIR, pn);
74082b75dfdSjtc 
74182b75dfdSjtc 	p = su_popen(user, buff, MAXTIME_FOR_QUEUE);
74282b75dfdSjtc 	if (p == NULL) {
74382b75dfdSjtc 		msg_out("rpc.pcnfsd: unable to popen() lpq");
74482b75dfdSjtc 		return (PI_RES_FAIL);
74582b75dfdSjtc 	}
74682b75dfdSjtc 	while (fgets(buff, 255, p) != NULL) {
74782b75dfdSjtc 		i = strlen(buff) - 1;
74882b75dfdSjtc 		buff[i] = '\0';	/* zap trailing NL */
74982b75dfdSjtc 		if (i < SIZECOL)
75082b75dfdSjtc 			continue;
751736ba086Slukem 		if (!strncasecmp(buff, "rank", 4))
75282b75dfdSjtc 			continue;
75382b75dfdSjtc 
75482b75dfdSjtc 		totsize = &buff[SIZECOL - 1];
75582b75dfdSjtc 		files = &buff[FILECOL - 1];
75682b75dfdSjtc 		cp = totsize;
75782b75dfdSjtc 		cp--;
758c4670c4eSdsl 		while (cp > files && isspace((unsigned char)*cp))
75982b75dfdSjtc 			*cp-- = '\0';
76082b75dfdSjtc 
76182b75dfdSjtc 		buff[FILECOL - 2] = '\0';
76282b75dfdSjtc 
76382b75dfdSjtc 		cp = strtok(buff, delims);
76482b75dfdSjtc 		if (!cp)
76582b75dfdSjtc 			continue;
76682b75dfdSjtc 		rank = cp;
76782b75dfdSjtc 
76882b75dfdSjtc 		cp = strtok(NULL, delims);
76982b75dfdSjtc 		if (!cp)
77082b75dfdSjtc 			continue;
77182b75dfdSjtc 		owner = cp;
77282b75dfdSjtc 
77382b75dfdSjtc 		cp = strtok(NULL, delims);
77482b75dfdSjtc 		if (!cp)
77582b75dfdSjtc 			continue;
77682b75dfdSjtc 		job = cp;
77782b75dfdSjtc 
77882b75dfdSjtc 		*p_qlen += 1;
77982b75dfdSjtc 
78082b75dfdSjtc 		if (*p_qshown > QMAX)
78182b75dfdSjtc 			continue;
78282b75dfdSjtc 
783736ba086Slukem 		if (just_mine && strcasecmp(owner, user))
78482b75dfdSjtc 			continue;
78582b75dfdSjtc 
78682b75dfdSjtc 		*p_qshown += 1;
78782b75dfdSjtc 
78882b75dfdSjtc 		curr = (struct pr_queue_item *)
78982b75dfdSjtc 		    grab(sizeof(struct pr_queue_item));
79082b75dfdSjtc 
79182b75dfdSjtc 		curr->position = atoi(rank);	/* active -> 0 */
79282b75dfdSjtc 		curr->id = strdup(job);
79382b75dfdSjtc 		curr->size = strdup(totsize);
79482b75dfdSjtc 		curr->status = strdup(rank);
79582b75dfdSjtc 		curr->system = strdup("");
79682b75dfdSjtc 		curr->user = strdup(owner);
79782b75dfdSjtc 		curr->file = strdup(files);
79882b75dfdSjtc 		curr->cm = strdup("-");
79982b75dfdSjtc 		curr->pr_next = NULL;
80082b75dfdSjtc 
80182b75dfdSjtc 		if (last == NULL)
80282b75dfdSjtc 			queue = curr;
80382b75dfdSjtc 		else
80482b75dfdSjtc 			last->pr_next = curr;
80582b75dfdSjtc 		last = curr;
80682b75dfdSjtc 
80782b75dfdSjtc 	}
80882b75dfdSjtc 	(void) su_pclose(p);
80982b75dfdSjtc 	return (PI_RES_OK);
81082b75dfdSjtc }
8116f885de1Sgwr #endif				/* SVR4 */
8126f885de1Sgwr 
81382b75dfdSjtc void
free_pr_queue_item(pr_queue curr)814d6aaec91Ssevan free_pr_queue_item(pr_queue curr)
81582b75dfdSjtc {
81682b75dfdSjtc 	if (curr->id)
81782b75dfdSjtc 		free(curr->id);
81882b75dfdSjtc 	if (curr->size)
81982b75dfdSjtc 		free(curr->size);
82082b75dfdSjtc 	if (curr->status)
82182b75dfdSjtc 		free(curr->status);
82282b75dfdSjtc 	if (curr->system)
82382b75dfdSjtc 		free(curr->system);
82482b75dfdSjtc 	if (curr->user)
82582b75dfdSjtc 		free(curr->user);
82682b75dfdSjtc 	if (curr->file)
82782b75dfdSjtc 		free(curr->file);
82882b75dfdSjtc 	if (curr->cm)
82982b75dfdSjtc 		free(curr->cm);
83082b75dfdSjtc 	if (curr->pr_next)
83182b75dfdSjtc 		free_pr_queue_item(curr->pr_next);	/* recurse */
83282b75dfdSjtc 	free(curr);
83382b75dfdSjtc }
8346f885de1Sgwr #ifdef SVR4
83582b75dfdSjtc 
8366f885de1Sgwr /*
8376f885de1Sgwr ** New - SVR4 printer status handling.
8386f885de1Sgwr **
8396f885de1Sgwr ** The command we'll use for checking the status of printer "lp"
8406f885de1Sgwr ** is "lpstat -a lp -p lp". Here are some sample outputs:
8416f885de1Sgwr **
8426f885de1Sgwr **
8436f885de1Sgwr ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
8446f885de1Sgwr ** printer lp disabled since Thu Feb 21 22:52:36 EST 1991. available.
8456f885de1Sgwr ** 	new printer
8466f885de1Sgwr ** ---
8476f885de1Sgwr ** pcdslw not accepting requests since Fri Jul 12 22:30:00 EDT 1991 -
8486f885de1Sgwr ** 	unknown reason
8496f885de1Sgwr ** printer pcdslw disabled since Fri Jul 12 22:15:37 EDT 1991. available.
8506f885de1Sgwr ** 	new printer
8516f885de1Sgwr ** ---
8526f885de1Sgwr ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
8536f885de1Sgwr ** printer lp now printing lp-2. enabled since Sat Jul 13 12:02:17 EDT 1991. available.
8546f885de1Sgwr ** ---
8556f885de1Sgwr ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
8566f885de1Sgwr ** printer lp now printing lp-2. enabled since Sat Jul 13 12:02:17 EDT 1991. available.
8576f885de1Sgwr ** ---
8586f885de1Sgwr ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
8596f885de1Sgwr ** printer lp disabled since Sat Jul 13 12:05:20 EDT 1991. available.
8606f885de1Sgwr ** 	unknown reason
8616f885de1Sgwr ** ---
8626f885de1Sgwr ** pcdslw not accepting requests since Fri Jul 12 22:30:00 EDT 1991 -
8636f885de1Sgwr ** 	unknown reason
8646f885de1Sgwr ** printer pcdslw is idle. enabled since Sat Jul 13 12:05:28 EDT 1991. available.
8656f885de1Sgwr **
8666f885de1Sgwr ** Note that these are actual outputs. The format (which is totally
8676f885de1Sgwr ** different from the lpstat in SunOS) seems to break down as
8686f885de1Sgwr ** follows:
8696f885de1Sgwr ** (1) The first line has the form "printername [not] accepting requests,,,"
8706f885de1Sgwr **    This is trivial to decode.
8716f885de1Sgwr ** (2) The second line has several forms, all beginning "printer printername":
8726f885de1Sgwr ** (2.1) "... disabled"
8736f885de1Sgwr ** (2.2) "... is idle"
8746f885de1Sgwr ** (2.3) "... now printing jobid"
8756f885de1Sgwr ** The "available" comment seems to be meaningless. The next line
8766f885de1Sgwr ** is the "reason" code which the operator can supply when issuing
8776f885de1Sgwr ** a "disable" or "reject" command.
8786f885de1Sgwr ** Note that there is no way to check the number of entries in the
8796f885de1Sgwr ** queue except to ask for the queue and count them.
8806f885de1Sgwr */
88182b75dfdSjtc 
88282b75dfdSjtc pirstat
get_pr_status(printername pn,bool_t * avail,bool_t * printing,int * qlen,bool_t * needs_operator,char * status,size_t statuslen)883d6aaec91Ssevan get_pr_status(printername pn, bool_t *avail, bool_t *printing, int *qlen, bool_t *needs_operator, char *status, size_t statuslen)
88482b75dfdSjtc {
8856f885de1Sgwr 	char    buff[256];
8866f885de1Sgwr 	char    cmd[64];
8876f885de1Sgwr 	FILE   *p;
8886f885de1Sgwr 	int     n;
8896f885de1Sgwr 	pirstat stat = PI_RES_NO_SUCH_PRINTER;
8906f885de1Sgwr 
8916f885de1Sgwr 	/* assume the worst */
8926f885de1Sgwr 	*avail = FALSE;
8936f885de1Sgwr 	*printing = FALSE;
8946f885de1Sgwr 	*needs_operator = FALSE;
8956f885de1Sgwr 	*qlen = 0;
8966f885de1Sgwr 	*status = '\0';
8976f885de1Sgwr 
8986f885de1Sgwr 	pn = map_printer_name(pn);
8996f885de1Sgwr 	if (pn == NULL || !valid_pr(pn) || suspicious(pn))
9006f885de1Sgwr 		return (PI_RES_NO_SUCH_PRINTER);
9016f885de1Sgwr 	n = strlen(pn);
9026f885de1Sgwr 
9035d573dd9Sitojun 	snprintf(cmd, sizeof(cmd), "/usr/bin/lpstat -a %s -p %s", pn, pn);
9046f885de1Sgwr 
9056f885de1Sgwr 	p = popen(cmd, "r");
9066f885de1Sgwr 	if (p == NULL) {
9076f885de1Sgwr 		msg_out("rpc.pcnfsd: unable to popen() lp status");
9086f885de1Sgwr 		return (PI_RES_FAIL);
9096f885de1Sgwr 	}
9106f885de1Sgwr 	stat = PI_RES_OK;
9116f885de1Sgwr 
9126f885de1Sgwr 	while (fgets(buff, 255, p) != NULL) {
9136f885de1Sgwr 		if (!strncmp(buff, pn, n)) {
9146f885de1Sgwr 			if (!strstr(buff, "not accepting"))
9156f885de1Sgwr 				*avail = TRUE;
9166f885de1Sgwr 			continue;
9176f885de1Sgwr 		}
9186f885de1Sgwr 		if (!strncmp(buff, "printer ", 8)) {
9196f885de1Sgwr 			if (!strstr(buff, "disabled"))
9206f885de1Sgwr 				*printing = TRUE;
9216f885de1Sgwr 			if (strstr(buff, "printing"))
922e6e73c33Sapb 				strlcpy(status, "printing", statuslen);
923736ba086Slukem 			else
924736ba086Slukem 				if (strstr(buff, "idle"))
925e6e73c33Sapb 					strlcpy(status, "idle", statuslen);
9266f885de1Sgwr 			continue;
9276f885de1Sgwr 		}
9286f885de1Sgwr 		if (!strncmp(buff, "UX:", 3)) {
9296f885de1Sgwr 			stat = PI_RES_NO_SUCH_PRINTER;
9306f885de1Sgwr 		}
9316f885de1Sgwr 	}
9326f885de1Sgwr 	(void) pclose(p);
9336f885de1Sgwr 	return (stat);
9346f885de1Sgwr }
9356f885de1Sgwr #else				/* SVR4 */
9366f885de1Sgwr 
9376f885de1Sgwr /*
9386f885de1Sgwr  * BSD way: lpc status
9396f885de1Sgwr  */
9406f885de1Sgwr pirstat
get_pr_status(printername pn,bool_t * avail,bool_t * printing,int * qlen,bool_t * needs_operator,char * status,size_t statuslen)941d6aaec91Ssevan get_pr_status(printername pn, bool_t *avail, bool_t *printing, int *qlen, bool_t *needs_operator, char *status, size_t statuslen)
9426f885de1Sgwr {
94382b75dfdSjtc 	char    cmd[128];
94482b75dfdSjtc 	char    buff[256];
94582b75dfdSjtc 	char    buff2[256];
94682b75dfdSjtc 	char    pname[64];
94782b75dfdSjtc 	FILE   *p;
94882b75dfdSjtc 	char   *cp;
94982b75dfdSjtc 	char   *cp1;
95082b75dfdSjtc 	char   *cp2;
95182b75dfdSjtc 	int     n;
9520466bbb6Slukem 	pirstat pstat = PI_RES_NO_SUCH_PRINTER;
95382b75dfdSjtc 
95482b75dfdSjtc 	/* assume the worst */
95582b75dfdSjtc 	*avail = FALSE;
95682b75dfdSjtc 	*printing = FALSE;
95782b75dfdSjtc 	*needs_operator = FALSE;
95882b75dfdSjtc 	*qlen = 0;
95982b75dfdSjtc 	*status = '\0';
96082b75dfdSjtc 
96182b75dfdSjtc 	pn = map_printer_name(pn);
96282b75dfdSjtc 	if (pn == NULL || suspicious(pn))
96382b75dfdSjtc 		return (PI_RES_NO_SUCH_PRINTER);
96482b75dfdSjtc 
9655d573dd9Sitojun 	snprintf(pname, sizeof(pname), "%s:", pn);
96682b75dfdSjtc 	n = strlen(pname);
96782b75dfdSjtc 
9685d573dd9Sitojun 	snprintf(cmd, sizeof(cmd), "%s/lpc status %s", LPCDIR, pn);
96982b75dfdSjtc 	p = popen(cmd, "r");
97082b75dfdSjtc 	if (p == NULL) {
97182b75dfdSjtc 		msg_out("rpc.pcnfsd: unable to popen() lp status");
97282b75dfdSjtc 		return (PI_RES_FAIL);
97382b75dfdSjtc 	}
97482b75dfdSjtc 	while (fgets(buff, 255, p) != NULL) {
97582b75dfdSjtc 		if (strncmp(buff, pname, n))
97682b75dfdSjtc 			continue;
97782b75dfdSjtc /*
97882b75dfdSjtc ** We have a match. The only failure now is PI_RES_FAIL if
97982b75dfdSjtc ** lpstat output cannot be decoded
98082b75dfdSjtc */
9810466bbb6Slukem 		pstat = PI_RES_FAIL;
98282b75dfdSjtc /*
98382b75dfdSjtc ** The next four lines are usually if the form
98482b75dfdSjtc **
98582b75dfdSjtc **     queuing is [enabled|disabled]
98682b75dfdSjtc **     printing is [enabled|disabled]
98782b75dfdSjtc **     [no entries | N entr[y|ies] in spool area]
98882b75dfdSjtc **     <status message, may include the word "attention">
98982b75dfdSjtc */
990c4670c4eSdsl 		while (fgets(buff, 255, p) != NULL && isspace((unsigned char)buff[0])) {
99182b75dfdSjtc 			cp = buff;
992c4670c4eSdsl 			while (isspace((unsigned char)*cp))
99382b75dfdSjtc 				cp++;
99482b75dfdSjtc 			if (*cp == '\0')
99582b75dfdSjtc 				break;
99682b75dfdSjtc 			cp1 = cp;
99782b75dfdSjtc 			cp2 = buff2;
99882b75dfdSjtc 			while (*cp1 && *cp1 != '\n') {
999c4670c4eSdsl 				*cp2++ = tolower((unsigned char)*cp1);
100082b75dfdSjtc 				cp1++;
100182b75dfdSjtc 			}
100282b75dfdSjtc 			*cp1 = '\0';
100382b75dfdSjtc 			*cp2 = '\0';
100482b75dfdSjtc /*
100582b75dfdSjtc ** Now buff2 has a lower-cased copy and cp points at the original;
100682b75dfdSjtc ** both are null terminated without any newline
100782b75dfdSjtc */
100882b75dfdSjtc 			if (!strncmp(buff2, "queuing", 7)) {
100982b75dfdSjtc 				*avail = (strstr(buff2, "enabled") != NULL);
101082b75dfdSjtc 				continue;
101182b75dfdSjtc 			}
101282b75dfdSjtc 			if (!strncmp(buff2, "printing", 8)) {
101382b75dfdSjtc 				*printing = (strstr(buff2, "enabled") != NULL);
101482b75dfdSjtc 				continue;
101582b75dfdSjtc 			}
1016c4670c4eSdsl 			if (isdigit((unsigned char)buff2[0]) && (strstr(buff2, "entr") != NULL)) {
101782b75dfdSjtc 
101882b75dfdSjtc 				*qlen = atoi(buff2);
101982b75dfdSjtc 				continue;
102082b75dfdSjtc 			}
102182b75dfdSjtc 			if (strstr(buff2, "attention") != NULL ||
102282b75dfdSjtc 			    strstr(buff2, "error") != NULL)
102382b75dfdSjtc 				*needs_operator = TRUE;
102482b75dfdSjtc 			if (*needs_operator || strstr(buff2, "waiting") != NULL)
1025e6e73c33Sapb 				strlcpy(status, cp, statuslen);
102682b75dfdSjtc 		}
10270466bbb6Slukem 		pstat = PI_RES_OK;
102882b75dfdSjtc 		break;
102982b75dfdSjtc 	}
103082b75dfdSjtc 	(void) pclose(p);
10310466bbb6Slukem 	return (pstat);
103282b75dfdSjtc }
10336f885de1Sgwr #endif				/* SVR4 */
103482b75dfdSjtc 
10356f885de1Sgwr /*
10366f885de1Sgwr  * pr_cancel: cancel a print job
10376f885de1Sgwr  */
10386f885de1Sgwr #ifdef SVR4
10396f885de1Sgwr 
10406f885de1Sgwr /*
10416f885de1Sgwr ** For SVR4 we have to be prepared for the following kinds of output:
10426f885de1Sgwr **
10436f885de1Sgwr ** # cancel lp-6
10446f885de1Sgwr ** request "lp-6" cancelled
10456f885de1Sgwr ** # cancel lp-33
10466f885de1Sgwr ** UX:cancel: WARNING: Request "lp-33" doesn't exist.
10476f885de1Sgwr ** # cancel foo-88
10486f885de1Sgwr ** UX:cancel: WARNING: Request "foo-88" doesn't exist.
10496f885de1Sgwr ** # cancel foo
10506f885de1Sgwr ** UX:cancel: WARNING: "foo" is not a request id or a printer.
10516f885de1Sgwr **             TO FIX: Cancel requests by id or by
10526f885de1Sgwr **                     name of printer where printing.
10536f885de1Sgwr ** # su geoff
10546f885de1Sgwr ** $ cancel lp-2
10556f885de1Sgwr ** UX:cancel: WARNING: Can't cancel request "lp-2".
10566f885de1Sgwr **             TO FIX: You are not allowed to cancel
10576f885de1Sgwr **                     another's request.
10586f885de1Sgwr **
10596f885de1Sgwr ** There are probably other variations for remote printers.
10606f885de1Sgwr ** Basically, if the reply begins with the string
10616f885de1Sgwr **          "UX:cancel: WARNING: "
10626f885de1Sgwr ** we can strip this off and look for one of the following
10636f885de1Sgwr ** (1) 'R' - should be part of "Request "xxxx" doesn't exist."
10646f885de1Sgwr ** (2) '"' - should be start of ""foo" is not a request id or..."
10656f885de1Sgwr ** (3) 'C' - should be start of "Can't cancel request..."
10666f885de1Sgwr **
10676f885de1Sgwr ** The fly in the ointment: all of this can change if these
10686f885de1Sgwr ** messages are localized..... :-(
10696f885de1Sgwr */
1070736ba086Slukem pcrstat
pr_cancel(char * pr,char * user,char * id)1071d6aaec91Ssevan pr_cancel(char *pr, char *user, char *id)
10726f885de1Sgwr {
10736f885de1Sgwr 	char    cmdbuf[256];
10746f885de1Sgwr 	char    resbuf[256];
10756f885de1Sgwr 	FILE   *fd;
10766f885de1Sgwr 	pcrstat stat = PC_RES_NO_SUCH_JOB;
10776f885de1Sgwr 
10786f885de1Sgwr 	pr = map_printer_name(pr);
10796f885de1Sgwr 	if (pr == NULL || suspicious(pr))
10806f885de1Sgwr 		return (PC_RES_NO_SUCH_PRINTER);
10816f885de1Sgwr 	if (suspicious(id))
10826f885de1Sgwr 		return (PC_RES_NO_SUCH_JOB);
10836f885de1Sgwr 
10845d573dd9Sitojun 	snprintf(cmdbuf, sizeof(cmdbuf), "/usr/bin/cancel %s", id);
10856f885de1Sgwr 	if ((fd = su_popen(user, cmdbuf, MAXTIME_FOR_CANCEL)) == NULL) {
10866f885de1Sgwr 		msg_out("rpc.pcnfsd: su_popen failed");
10876f885de1Sgwr 		return (PC_RES_FAIL);
10886f885de1Sgwr 	}
10896f885de1Sgwr 	if (fgets(resbuf, 255, fd) == NULL)
10906f885de1Sgwr 		stat = PC_RES_FAIL;
1091736ba086Slukem 	else
1092736ba086Slukem 		if (!strstr(resbuf, "UX:"))
10936f885de1Sgwr 			stat = PC_RES_OK;
1094736ba086Slukem 		else
1095736ba086Slukem 			if (strstr(resbuf, "doesn't exist"))
10966f885de1Sgwr 				stat = PC_RES_NO_SUCH_JOB;
1097736ba086Slukem 			else
1098736ba086Slukem 				if (strstr(resbuf, "not a request id"))
10996f885de1Sgwr 					stat = PC_RES_NO_SUCH_JOB;
1100736ba086Slukem 				else
1101736ba086Slukem 					if (strstr(resbuf, "Can't cancel request"))
11026f885de1Sgwr 						stat = PC_RES_NOT_OWNER;
1103736ba086Slukem 					else
1104736ba086Slukem 						stat = PC_RES_FAIL;
11056f885de1Sgwr 
11066f885de1Sgwr 	if (su_pclose(fd) == 255)
11076f885de1Sgwr 		msg_out("rpc.pcnfsd: su_pclose alert");
11086f885de1Sgwr 	return (stat);
11096f885de1Sgwr }
11106f885de1Sgwr #else				/* SVR4 */
11116f885de1Sgwr 
11126f885de1Sgwr /*
11136f885de1Sgwr  * BSD way: lprm
11146f885de1Sgwr  */
1115736ba086Slukem pcrstat
pr_cancel(char * pr,char * user,char * id)1116d6aaec91Ssevan pr_cancel(char *pr, char *user, char *id)
111782b75dfdSjtc {
111882b75dfdSjtc 	char    cmdbuf[256];
111982b75dfdSjtc 	char    resbuf[256];
112082b75dfdSjtc 	FILE   *fd;
112182b75dfdSjtc 	int     i;
11220466bbb6Slukem 	pcrstat pstat = PC_RES_NO_SUCH_JOB;
112382b75dfdSjtc 
112482b75dfdSjtc 	pr = map_printer_name(pr);
112582b75dfdSjtc 	if (pr == NULL || suspicious(pr))
112682b75dfdSjtc 		return (PC_RES_NO_SUCH_PRINTER);
112782b75dfdSjtc 	if (suspicious(id))
112882b75dfdSjtc 		return (PC_RES_NO_SUCH_JOB);
112982b75dfdSjtc 
11305d573dd9Sitojun 	snprintf(cmdbuf, sizeof(cmdbuf), "%s/lprm -P%s %s", LPRDIR, pr, id);
113182b75dfdSjtc 	if ((fd = su_popen(user, cmdbuf, MAXTIME_FOR_CANCEL)) == NULL) {
113282b75dfdSjtc 		msg_out("rpc.pcnfsd: su_popen failed");
113382b75dfdSjtc 		return (PC_RES_FAIL);
113482b75dfdSjtc 	}
113582b75dfdSjtc 	while (fgets(resbuf, 255, fd) != NULL) {
113682b75dfdSjtc 		i = strlen(resbuf);
113782b75dfdSjtc 		if (i)
113882b75dfdSjtc 			resbuf[i - 1] = '\0';	/* trim NL */
113982b75dfdSjtc 		if (strstr(resbuf, "dequeued") != NULL)
11400466bbb6Slukem 			pstat = PC_RES_OK;
114182b75dfdSjtc 		if (strstr(resbuf, "unknown printer") != NULL)
11420466bbb6Slukem 			pstat = PC_RES_NO_SUCH_PRINTER;
114382b75dfdSjtc 		if (strstr(resbuf, "Permission denied") != NULL)
11440466bbb6Slukem 			pstat = PC_RES_NOT_OWNER;
114582b75dfdSjtc 	}
114682b75dfdSjtc 	if (su_pclose(fd) == 255)
114782b75dfdSjtc 		msg_out("rpc.pcnfsd: su_pclose alert");
11480466bbb6Slukem 	return (pstat);
114982b75dfdSjtc }
11506f885de1Sgwr #endif				/* SVR4 */
1151736ba086Slukem 
115282b75dfdSjtc /*
115382b75dfdSjtc ** New subsystem here. We allow the administrator to define
115482b75dfdSjtc ** up to NPRINTERDEFS aliases for printer names. This is done
115582b75dfdSjtc ** using the "/etc/pcnfsd.conf" file, which is read at startup.
115682b75dfdSjtc ** There are three entry points to this subsystem
115782b75dfdSjtc **
115882b75dfdSjtc ** void add_printer_alias(char *printer, char *alias_for, char *command)
115982b75dfdSjtc **
116082b75dfdSjtc ** This is invoked from "config_from_file()" for each
116182b75dfdSjtc ** "printer" line. "printer" is the name of a printer; note that
116282b75dfdSjtc ** it is possible to redefine an existing printer. "alias_for"
116382b75dfdSjtc ** is the name of the underlying printer, used for queue listing
116482b75dfdSjtc ** and other control functions. If it is "-", there is no
116582b75dfdSjtc ** underlying printer, or the administrative functions are
116682b75dfdSjtc ** not applicable to this printer. "command"
116782b75dfdSjtc ** is the command which should be run (via "su_popen()") if a
116882b75dfdSjtc ** job is printed on this printer. The following tokens may be
116982b75dfdSjtc ** embedded in the command, and are substituted as follows:
117082b75dfdSjtc **
117182b75dfdSjtc ** $FILE	-	path to the file containing the print data
117282b75dfdSjtc ** $USER	-	login of user
117382b75dfdSjtc ** $HOST	-	hostname from which job originated
117482b75dfdSjtc **
117582b75dfdSjtc ** Tokens may occur multiple times. If The command includes no
117682b75dfdSjtc ** $FILE token, the string " $FILE" is silently appended.
117782b75dfdSjtc **
117882b75dfdSjtc ** pr_list list_virtual_printers()
117982b75dfdSjtc **
118082b75dfdSjtc ** This is invoked from build_pr_list to generate a list of aliased
118182b75dfdSjtc ** printers, so that the client that asks for a list of valid printers
118282b75dfdSjtc ** will see these ones.
118382b75dfdSjtc **
118482b75dfdSjtc ** char *map_printer_name(char *printer)
118582b75dfdSjtc **
118682b75dfdSjtc ** If "printer" identifies an aliased printer, this function returns
118782b75dfdSjtc ** the "alias_for" name, or NULL if the "alias_for" was given as "-".
118882b75dfdSjtc ** Otherwise it returns its argument.
118982b75dfdSjtc **
119082b75dfdSjtc ** char *expand_alias(char *printer, char *file, char *user, char *host)
119182b75dfdSjtc **
119282b75dfdSjtc ** If "printer" is an aliased printer, this function returns a
119382b75dfdSjtc ** pointer to a static string in which the corresponding command
119482b75dfdSjtc ** has been expanded. Otherwise ot returns NULL.
119582b75dfdSjtc */
119682b75dfdSjtc #define NPRINTERDEFS	16
119782b75dfdSjtc int     num_aliases = 0;
119882b75dfdSjtc struct {
119982b75dfdSjtc 	char   *a_printer;
120082b75dfdSjtc 	char   *a_alias_for;
120182b75dfdSjtc 	char   *a_command;
120282b75dfdSjtc }       alias[NPRINTERDEFS];
120382b75dfdSjtc 
120482b75dfdSjtc void
add_printer_alias(char * printer,char * alias_for,char * command)1205d6aaec91Ssevan add_printer_alias(char *printer, char *alias_for, char *command)
120682b75dfdSjtc {
12075d573dd9Sitojun 	size_t l;
12085d573dd9Sitojun 
120982b75dfdSjtc 	if (num_aliases < NPRINTERDEFS) {
121082b75dfdSjtc 		alias[num_aliases].a_printer = strdup(printer);
121182b75dfdSjtc 		alias[num_aliases].a_alias_for =
121282b75dfdSjtc 		    (strcmp(alias_for, "-") ? strdup(alias_for) : NULL);
121382b75dfdSjtc 		if (strstr(command, "$FILE"))
121482b75dfdSjtc 			alias[num_aliases].a_command = strdup(command);
121582b75dfdSjtc 		else {
12165d573dd9Sitojun 			l = strlen(command) + 8;
12175d573dd9Sitojun 			alias[num_aliases].a_command = (char *) grab(l);
12185d573dd9Sitojun 			strlcpy(alias[num_aliases].a_command, command, l);
12195d573dd9Sitojun 			strlcat(alias[num_aliases].a_command, " $FILE", l);
122082b75dfdSjtc 		}
122182b75dfdSjtc 		num_aliases++;
122282b75dfdSjtc 	}
122382b75dfdSjtc }
122482b75dfdSjtc 
1225736ba086Slukem pr_list
list_virtual_printers()1226736ba086Slukem list_virtual_printers()
122782b75dfdSjtc {
122882b75dfdSjtc 	pr_list first = NULL;
122982b75dfdSjtc 	pr_list last = NULL;
123082b75dfdSjtc 	pr_list curr = NULL;
123182b75dfdSjtc 	int     i;
123282b75dfdSjtc 
123382b75dfdSjtc 
123482b75dfdSjtc 	if (num_aliases == 0)
123582b75dfdSjtc 		return (NULL);
123682b75dfdSjtc 
123782b75dfdSjtc 	for (i = 0; i < num_aliases; i++) {
123882b75dfdSjtc 		curr = (struct pr_list_item *)
123982b75dfdSjtc 		    grab(sizeof(struct pr_list_item));
124082b75dfdSjtc 
124182b75dfdSjtc 		curr->pn = strdup(alias[i].a_printer);
124282b75dfdSjtc 		if (alias[i].a_alias_for == NULL)
124382b75dfdSjtc 			curr->device = strdup("");
124482b75dfdSjtc 		else
124582b75dfdSjtc 			curr->device = strdup(alias[i].a_alias_for);
124682b75dfdSjtc 		curr->remhost = strdup("");
124782b75dfdSjtc 		curr->cm = strdup("(alias)");
124882b75dfdSjtc 		curr->pr_next = NULL;
124982b75dfdSjtc 		if (last == NULL)
125082b75dfdSjtc 			first = curr;
125182b75dfdSjtc 		else
125282b75dfdSjtc 			last->pr_next = curr;
125382b75dfdSjtc 		last = curr;
125482b75dfdSjtc 
125582b75dfdSjtc 	}
125682b75dfdSjtc 	return (first);
125782b75dfdSjtc }
125882b75dfdSjtc 
125982b75dfdSjtc 
126082b75dfdSjtc char   *
map_printer_name(char * printer)1261d6aaec91Ssevan map_printer_name(char *printer)
126282b75dfdSjtc {
126382b75dfdSjtc 	int     i;
126482b75dfdSjtc 	for (i = 0; i < num_aliases; i++) {
126582b75dfdSjtc 		if (!strcmp(printer, alias[i].a_printer))
126682b75dfdSjtc 			return (alias[i].a_alias_for);
126782b75dfdSjtc 	}
126882b75dfdSjtc 	return (printer);
126982b75dfdSjtc }
127082b75dfdSjtc 
1271736ba086Slukem void
substitute(char * string,const char * token,const char * data)1272d6aaec91Ssevan substitute(char *string, const char *token, const char *data)
127382b75dfdSjtc {
127482b75dfdSjtc 	char    temp[512];
127582b75dfdSjtc 	char   *c;
127682b75dfdSjtc 
1277736ba086Slukem 	while ((c = strstr(string, token)) != NULL) {
127882b75dfdSjtc 		*c = '\0';
12795d573dd9Sitojun 		strlcpy(temp, string, sizeof(temp));
12805d573dd9Sitojun 		strlcat(temp, data, sizeof(temp));
128182b75dfdSjtc 		c += strlen(token);
12825d573dd9Sitojun 		strlcat(temp, c, sizeof(temp));
128382b75dfdSjtc 		strcpy(string, temp);
128482b75dfdSjtc 	}
128582b75dfdSjtc }
128682b75dfdSjtc 
128782b75dfdSjtc char   *
expand_alias(char * printer,char * file,char * user,char * host)1288d6aaec91Ssevan expand_alias(char *printer, char *file, char *user, char *host)
128982b75dfdSjtc {
129082b75dfdSjtc 	static char expansion[512];
129182b75dfdSjtc 	int     i;
129282b75dfdSjtc 	for (i = 0; i < num_aliases; i++) {
129382b75dfdSjtc 		if (!strcmp(printer, alias[i].a_printer)) {
12945d573dd9Sitojun 			strlcpy(expansion, alias[i].a_command,
12955d573dd9Sitojun 			    sizeof(expansion));
129682b75dfdSjtc 			substitute(expansion, "$FILE", file);
129782b75dfdSjtc 			substitute(expansion, "$USER", user);
129882b75dfdSjtc 			substitute(expansion, "$HOST", host);
129982b75dfdSjtc 			return (expansion);
130082b75dfdSjtc 		}
130182b75dfdSjtc 	}
130282b75dfdSjtc 	return (NULL);
130382b75dfdSjtc }
1304