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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
34 
35 #include "stdio.h"
36 #include "string.h"
37 #include "errno.h"
38 #include "sys/types.h"
39 #include "stdlib.h"
40 
41 #include "lp.h"
42 #include "printers.h"
43 
44 extern struct {
45 	char			*v;
46 	short			len,
47 				okremote;
48 }			prtrheadings[];
49 
50 /**
51  ** getprinter() - EXTRACT PRINTER STRUCTURE FROM DISK FILE
52  **/
53 
54 PRINTER *
55 getprinter(char *name)
56 {
57 	static long		lastdir		= -1;
58 
59 	static PRINTER		prbuf;
60 
61 	char			buf[BUFSIZ];
62 
63 	short			daisy;
64 
65 	int			fld;
66 
67 	int fd;
68 
69 	FALERT			*pa;
70 
71 	register char *		p;
72 	register char **	pp;
73 	register char ***	ppp;
74 	register char *		path;
75 	int			isNameAll;
76 
77 
78 
79 	if (!name || !*name) {
80 		errno = EINVAL;
81 		return (0);
82 	}
83 
84 	/*
85 	 * Getting ``all''? If so, jump into the directory
86 	 * wherever we left off.
87 	 */
88 	isNameAll = STREQU(NAME_ALL, name);
89 	for (; ; ) {
90 		/* fix for bug 1117241
91 		 * occasionally when a printer is removed, a printer directory
92 		 * is left behind, but the CONFIGFILE is removed.  In this
93 		 * case this directory terminates the search for additional
94 		 * printers as we have been returning 0 in this case.
95 		 * Now, we loop back and try the next directory until
96 		 * we have no more directories or we find a directory with
97 		 * a CONFIGFILE
98 		 */
99 		if (isNameAll) {
100 			if (!(name = next_dir(Lp_A_Printers, &lastdir)))
101 				return (0);
102 		} else
103 			lastdir = -1;
104 
105 		/*
106 		 * Get the printer configuration information.
107 		 */
108 
109 		path = getprinterfile(name, CONFIGFILE);
110 		if (!path) {
111 			if (isNameAll)
112 				Free(name);
113 			return (0);
114 		}
115 
116 		if ((fd = open_locked(path, "r", 0)) < 0) {
117 			Free(path);	/*
118 					 * go around to loop again for
119 					 * NAME_ALL case
120 					 */
121 
122 			if (!isNameAll) /* fix for bug 1117241 */
123 				return(0);
124 			else
125 				Free(name);
126 		}
127 		else
128 			break;
129 	}
130 	Free (path);
131 
132 	/*
133 	 * Initialize the entire structure, to ensure no random
134 	 * values get in it. However, make sure some values won't
135 	 * be null or empty. Do the latter here as opposed to
136 	 * after reading the file, because sometimes the file
137 	 * contains an empty header to FORCE a null/empty value.
138 	 */
139 	(void)memset ((char *)&prbuf, 0, sizeof(prbuf));
140 	prbuf.name = Strdup(name);
141 	if (isNameAll)
142 		Free(name);
143 	prbuf.printer_types = getlist(NAME_UNKNOWN, LP_WS, LP_SEP);
144 	prbuf.input_types = getlist(NAME_SIMPLE, LP_WS, LP_SEP);
145 #if	defined(CAN_DO_MODULES)
146 	prbuf.modules = getlist(NAME_DEFAULT, LP_WS, LP_SEP);
147 #endif
148 
149 	/*
150 	 * Read the file.
151 	 */
152 	errno = 0;
153 	while (fdgets(buf, BUFSIZ, fd) != NULL) {
154 
155 		buf[strlen(buf) - 1] = 0;
156 
157 		for (fld = 0; fld < PR_MAX; fld++)
158 			if (
159 				prtrheadings[fld].v
160 			     && prtrheadings[fld].len
161 			     && STRNEQU(
162 					buf,
163 					prtrheadings[fld].v,
164 					prtrheadings[fld].len
165 				)
166 			) {
167 				p = buf + prtrheadings[fld].len;
168 				while (*p && *p == ' ')
169 					p++;
170 				break;
171 			}
172 
173 		/*
174 		 * To allow future extensions to not impact applications
175 		 * using old versions of this routine, ignore strange
176 		 * fields.
177 		 */
178 		if (fld >= PR_MAX)
179 			continue;
180 
181 		switch (fld) {
182 
183 		case PR_BAN:
184 			if ((pp = getlist(p, LP_WS, ":"))) {
185 				if (pp[0] != NULL) {
186 					if (strcmp(pp[0], NAME_OPTIONAL) == 0)
187 						prbuf.banner = BAN_OPTIONAL;
188 					else if (strcmp(pp[0], NAME_OFF) == 0)
189 						prbuf.banner = BAN_NEVER;
190 					else if (strcmp(pp[0], NAME_ON) == 0)
191 						prbuf.banner = BAN_ALWAYS;
192 					else /* default to the LP default */
193 						prbuf.banner = BAN_ALWAYS;
194 				}
195 				if (pp[1] && CS_STREQU(pp[1], NAME_ALWAYS))
196 					prbuf.banner |= BAN_ALWAYS;
197 				freelist (pp);
198 			}
199 			break;
200 
201 		case PR_LOGIN:
202 			prbuf.login = LOG_IN;
203 			break;
204 
205 		case PR_CPI:
206 			prbuf.cpi = getcpi(p);
207 			break;
208 
209 		case PR_LPI:
210 			prbuf.lpi = getsdn(p);
211 			break;
212 
213 		case PR_LEN:
214 			prbuf.plen = getsdn(p);
215 			break;
216 
217 		case PR_WIDTH:
218 			prbuf.pwid = getsdn(p);
219 			break;
220 
221 		case PR_CS:
222 			ppp = &(prbuf.char_sets);
223 			goto CharStarStar;
224 
225 		case PR_ITYPES:
226 			ppp = &(prbuf.input_types);
227 CharStarStar:		if (*ppp)
228 				freelist (*ppp);
229 			*ppp = getlist(p, LP_WS, LP_SEP);
230 			break;
231 
232 		case PR_DEV:
233 			pp = &(prbuf.device);
234 			goto CharStar;
235 
236 		case PR_DIAL:
237 			pp = &(prbuf.dial_info);
238 			goto CharStar;
239 
240 		case PR_RECOV:
241 			pp = &(prbuf.fault_rec);
242 			goto CharStar;
243 
244 		case PR_INTFC:
245 			pp = &(prbuf.interface);
246 			goto CharStar;
247 
248 		case PR_PTYPE:
249 			ppp = &(prbuf.printer_types);
250 			goto CharStarStar;
251 
252 		case PR_REMOTE:
253 			pp = &(prbuf.remote);
254 			goto CharStar;
255 
256 		case PR_SPEED:
257 			pp = &(prbuf.speed);
258 			goto CharStar;
259 
260 		case PR_STTY:
261 			pp = &(prbuf.stty);
262 CharStar:		if (*pp)
263 				Free (*pp);
264 			*pp = Strdup(p);
265 			break;
266 
267 #if	defined(CAN_DO_MODULES)
268 		case PR_MODULES:
269 			ppp = &(prbuf.modules);
270 			goto CharStarStar;
271 #endif
272 
273 		case PR_OPTIONS:
274 			ppp = &(prbuf.options);
275 			goto CharStarStar;
276 			break;
277 
278 		case PR_PPD:
279 		{
280 			pp = &(prbuf.ppd);
281 			goto CharStar;
282 		}
283 		}
284 
285 	}
286 	if (errno != 0) {
287 		int			save_errno = errno;
288 
289 		freeprinter (&prbuf);
290 		close(fd);
291 		errno = save_errno;
292 		return (0);
293 	}
294 	close(fd);
295 
296 	/*
297 	 * Get the printer description (if it exists).
298 	 */
299 	if (!(path = getprinterfile(prbuf.name, COMMENTFILE)))
300 		return (0);
301 	if (!(prbuf.description = loadstring(path)) && errno != ENOENT) {
302 		Free (path);
303 		freeprinter (&prbuf);
304 		return (0);
305 	}
306 	Free (path);
307 
308 	/*
309 	 * Get the information for the alert. Don't fail if we can't
310 	 * read it because of access permission UNLESS we're "root"
311 	 * or "lp"
312 	 */
313 	if (!(pa = getalert(Lp_A_Printers, prbuf.name))) {
314 		if (
315 			errno != ENOENT
316 		     && (
317 				errno != EACCES
318 			     || !getpid()		  /* we be root */
319 			     || STREQU(getname(), LPUSER) /* we be lp   */
320 			)
321 		) {
322 			freeprinter (&prbuf);
323 			return (0);
324 		}
325 	} else
326 		prbuf.fault_alert = *pa;
327 
328 	/*
329 	 * Now go through the structure and see if we have
330 	 * anything strange.
331 	 */
332 	if (!okprinter(prbuf.name, &prbuf, 0)) {
333 		freeprinter (&prbuf);
334 		errno = EBADF;
335 		return (0);
336 	}
337 
338 	/*
339 	 * Just in case somebody tried to pull a fast one
340 	 * by giving a printer type header by itself....
341 	 */
342 	if (!prbuf.printer_types)
343 		prbuf.printer_types = getlist(NAME_UNKNOWN, LP_WS, LP_SEP);
344 
345 	/*
346 	 * If there are more than one printer type, then we can't
347 	 * have any input types, except perhaps ``simple''.
348 	 */
349 	if (
350 		lenlist(prbuf.printer_types) > 1
351 	     && prbuf.input_types
352 	     && (
353 			lenlist(prbuf.input_types) > 1
354 		     || !STREQU(NAME_SIMPLE, *prbuf.input_types)
355 		)
356 	) {
357 		freeprinter (&prbuf);
358 		badprinter = BAD_ITYPES;
359 		errno = EBADF;
360 		return (0);
361 	}
362 
363 	/*
364 	 * If there are more than one printer types, none can
365 	 * be ``unknown''.
366 	 */
367 	if (
368 		lenlist(prbuf.printer_types) > 1
369 	     && searchlist(NAME_UNKNOWN, prbuf.printer_types)
370 	) {
371 		freeprinter (&prbuf);
372 		badprinter = BAD_PTYPES;
373 		errno = EBADF;
374 		return (0);
375 	}
376 
377 	/*
378 	 * All the printer types had better agree on whether the
379 	 * printer takes print wheels!
380 	 */
381 	prbuf.daisy = -1;
382 	for (pp = prbuf.printer_types; *pp; pp++) {
383 		tidbit (*pp, "daisy", &daisy);
384 		if (daisy == -1)
385 			daisy = 0;
386 		if (prbuf.daisy == -1)
387 			prbuf.daisy = daisy;
388 		else if (prbuf.daisy != daisy) {
389 			freeprinter (&prbuf);
390 			badprinter = BAD_DAISY;
391 			errno = EBADF;
392 			return (0);
393 		}
394 	}
395 
396 	/*
397 	 * Help out those who are still using the obsolete
398 	 * "printer_type" member.
399 	 */
400 	prbuf.printer_type = Strdup(*prbuf.printer_types);
401 
402 	return (&prbuf);
403 }
404