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