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