1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)common.c	5.1 (Berkeley) 06/06/85";
9 #endif not lint
10 
11 /*
12  * Routines and data common to all the line printer functions.
13  */
14 
15 #include "lp.h"
16 
17 int	DU;		/* daeomon user-id */
18 int	MX;		/* maximum number of blocks to copy */
19 int	MC;		/* maximum number of copies allowed */
20 char	*LP;		/* line printer device name */
21 char	*RM;		/* remote machine name */
22 char	*RP;		/* remote printer name */
23 char	*LO;		/* lock file name */
24 char	*ST;		/* status file name */
25 char	*SD;		/* spool directory */
26 char	*AF;		/* accounting file */
27 char	*LF;		/* log file for error messages */
28 char	*OF;		/* name of output filter (created once) */
29 char	*IF;		/* name of input filter (created per job) */
30 char	*RF;		/* name of fortran text filter (per job) */
31 char	*TF;		/* name of troff filter (per job) */
32 char	*NF;		/* name of ditroff filter (per job) */
33 char	*DF;		/* name of tex filter (per job) */
34 char	*GF;		/* name of graph(1G) filter (per job) */
35 char	*VF;		/* name of vplot filter (per job) */
36 char	*CF;		/* name of cifplot filter (per job) */
37 char	*PF;		/* name of vrast filter (per job) */
38 char	*FF;		/* form feed string */
39 char	*TR;		/* trailer string to be output when Q empties */
40 short	SC;		/* suppress multiple copies */
41 short	SF;		/* suppress FF on each print job */
42 short	SH;		/* suppress header page */
43 short	SB;		/* short banner instead of normal header */
44 short	HL;		/* print header last */
45 short	RW;		/* open LP for reading and writing */
46 short	PW;		/* page width */
47 short	PL;		/* page length */
48 short	PX;		/* page width in pixels */
49 short	PY;		/* page length in pixels */
50 short	BR;		/* baud rate if lp is a tty */
51 int	FC;		/* flags to clear if lp is a tty */
52 int	FS;		/* flags to set if lp is a tty */
53 int	XC;		/* flags to clear for local mode */
54 int	XS;		/* flags to set for local mode */
55 short	RS;		/* restricted to those with local accounts */
56 
57 char	line[BUFSIZ];
58 char	pbuf[BUFSIZ/2];	/* buffer for printcap strings */
59 char	*bp = pbuf;	/* pointer into pbuf for pgetent() */
60 char	*name;		/* program name */
61 char	*printer;	/* printer name */
62 char	host[32];	/* host machine name */
63 char	*from = host;	/* client's machine name */
64 
65 /*
66  * Create a connection to the remote printer server.
67  * Most of this code comes from rcmd.c.
68  */
69 getport(rhost)
70 	char *rhost;
71 {
72 	struct hostent *hp;
73 	struct servent *sp;
74 	struct sockaddr_in sin;
75 	int s, timo = 1, lport = IPPORT_RESERVED - 1;
76 	int err;
77 
78 	/*
79 	 * Get the host address and port number to connect to.
80 	 */
81 	if (rhost == NULL)
82 		fatal("no remote host to connect to");
83 	hp = gethostbyname(rhost);
84 	if (hp == NULL)
85 		fatal("unknown host %s", rhost);
86 	sp = getservbyname("printer", "tcp");
87 	if (sp == NULL)
88 		fatal("printer/tcp: unknown service");
89 	bzero((char *)&sin, sizeof(sin));
90 	bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
91 	sin.sin_family = hp->h_addrtype;
92 	sin.sin_port = sp->s_port;
93 
94 	/*
95 	 * Try connecting to the server.
96 	 */
97 retry:
98 	s = rresvport(&lport);
99 	if (s < 0)
100 		return(-1);
101 	if (connect(s, (caddr_t)&sin, sizeof(sin), 0) < 0) {
102 		err = errno;
103 		(void) close(s);
104 		errno = err;
105 		if (errno == EADDRINUSE) {
106 			lport--;
107 			goto retry;
108 		}
109 		if (errno == ECONNREFUSED && timo <= 16) {
110 			sleep(timo);
111 			timo *= 2;
112 			goto retry;
113 		}
114 		return(-1);
115 	}
116 	return(s);
117 }
118 
119 rresvport(alport)
120 	int *alport;
121 {
122 	struct sockaddr_in sin;
123 	int s;
124 
125 	sin.sin_family = AF_INET;
126 	sin.sin_addr.s_addr = 0;
127 	s = socket(AF_INET, SOCK_STREAM, 0);
128 	if (s < 0)
129 		return(-1);
130 	for (; *alport > IPPORT_RESERVED/2; (*alport)--) {
131 		sin.sin_port = htons((u_short) *alport);
132 		if (bind(s, (caddr_t)&sin, sizeof(sin), 0) >= 0)
133 			return(s);
134 		if (errno != EADDRINUSE && errno != EADDRNOTAVAIL)
135 			break;
136 	}
137 	(void) close(s);
138 	return(-1);
139 }
140 
141 /*
142  * Getline reads a line from the control file cfp, removes tabs, converts
143  *  new-line to null and leaves it in line.
144  * Returns 0 at EOF or the number of characters read.
145  */
146 getline(cfp)
147 	FILE *cfp;
148 {
149 	register int linel = 0;
150 	register char *lp = line;
151 	register c;
152 
153 	while ((c = getc(cfp)) != '\n') {
154 		if (c == EOF)
155 			return(0);
156 		if (c == '\t') {
157 			do {
158 				*lp++ = ' ';
159 				linel++;
160 			} while ((linel & 07) != 0);
161 			continue;
162 		}
163 		*lp++ = c;
164 		linel++;
165 	}
166 	*lp++ = '\0';
167 	return(linel);
168 }
169 
170 /*
171  * Scan the current directory and make a list of daemon files sorted by
172  * creation time.
173  * Return the number of entries and a pointer to the list.
174  */
175 getq(namelist)
176 	struct queue *(*namelist[]);
177 {
178 	register struct direct *d;
179 	register struct queue *q, **queue;
180 	register int nitems;
181 	struct stat stbuf;
182 	int arraysz, compar();
183 	DIR *dirp;
184 
185 	if ((dirp = opendir(SD)) == NULL)
186 		return(-1);
187 	if (fstat(dirp->dd_fd, &stbuf) < 0)
188 		goto errdone;
189 
190 	/*
191 	 * Estimate the array size by taking the size of the directory file
192 	 * and dividing it by a multiple of the minimum size entry.
193 	 */
194 	arraysz = (stbuf.st_size / 24);
195 	queue = (struct queue **)malloc(arraysz * sizeof(struct queue *));
196 	if (queue == NULL)
197 		goto errdone;
198 
199 	nitems = 0;
200 	while ((d = readdir(dirp)) != NULL) {
201 		if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
202 			continue;	/* daemon control files only */
203 		if (stat(d->d_name, &stbuf) < 0)
204 			continue;	/* Doesn't exist */
205 		q = (struct queue *)malloc(sizeof(time_t)+strlen(d->d_name)+1);
206 		if (q == NULL)
207 			goto errdone;
208 		q->q_time = stbuf.st_mtime;
209 		strcpy(q->q_name, d->d_name);
210 		/*
211 		 * Check to make sure the array has space left and
212 		 * realloc the maximum size.
213 		 */
214 		if (++nitems > arraysz) {
215 			queue = (struct queue **)realloc((char *)queue,
216 				(stbuf.st_size/12) * sizeof(struct queue *));
217 			if (queue == NULL)
218 				goto errdone;
219 		}
220 		queue[nitems-1] = q;
221 	}
222 	closedir(dirp);
223 	if (nitems)
224 		qsort(queue, nitems, sizeof(struct queue *), compar);
225 	*namelist = queue;
226 	return(nitems);
227 
228 errdone:
229 	closedir(dirp);
230 	return(-1);
231 }
232 
233 /*
234  * Compare modification times.
235  */
236 static
237 compar(p1, p2)
238 	register struct queue **p1, **p2;
239 {
240 	if ((*p1)->q_time < (*p2)->q_time)
241 		return(-1);
242 	if ((*p1)->q_time > (*p2)->q_time)
243 		return(1);
244 	return(0);
245 }
246 
247 /*VARARGS1*/
248 fatal(msg, a1, a2, a3)
249 	char *msg;
250 {
251 	if (from != host)
252 		printf("%s: ", host);
253 	printf("%s: ", name);
254 	if (printer)
255 		printf("%s: ", printer);
256 	printf(msg, a1, a2, a3);
257 	putchar('\n');
258 	exit(1);
259 }
260