pcnfsd_print.c revision 1.2 1 1.2 gwr /* $NetBSD: pcnfsd_print.c,v 1.2 1995/07/25 22:20:48 gwr Exp $ */
2 1.2 gwr
3 1.1 jtc /* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_print.c 1.7 92/01/24 19:58:58 SMI */
4 1.1 jtc /*
5 1.1 jtc **=====================================================================
6 1.1 jtc ** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
7 1.1 jtc ** @(#)pcnfsd_print.c 1.7 1/24/92
8 1.1 jtc **=====================================================================
9 1.1 jtc */
10 1.1 jtc #include "common.h"
11 1.1 jtc /*
12 1.1 jtc **=====================================================================
13 1.1 jtc ** I N C L U D E F I L E S E C T I O N *
14 1.1 jtc ** *
15 1.1 jtc ** If your port requires different include files, add a suitable *
16 1.1 jtc ** #define in the customization section, and make the inclusion or *
17 1.1 jtc ** exclusion of the files conditional on this. *
18 1.1 jtc **=====================================================================
19 1.1 jtc */
20 1.1 jtc #include "pcnfsd.h"
21 1.1 jtc #include <malloc.h>
22 1.1 jtc #include <stdio.h>
23 1.1 jtc #include <pwd.h>
24 1.1 jtc #include <sys/file.h>
25 1.1 jtc #include <signal.h>
26 1.1 jtc #include <sys/stat.h>
27 1.1 jtc #include <sys/ioctl.h>
28 1.1 jtc #include <netdb.h>
29 1.1 jtc #include <errno.h>
30 1.1 jtc #include <string.h>
31 1.1 jtc
32 1.1 jtc #ifndef SYSV
33 1.1 jtc #include <sys/wait.h>
34 1.1 jtc #endif
35 1.1 jtc
36 1.1 jtc #ifdef ISC_2_0
37 1.1 jtc #include <sys/fcntl.h>
38 1.1 jtc #endif
39 1.1 jtc
40 1.1 jtc #ifdef SHADOW_SUPPORT
41 1.1 jtc #include <shadow.h>
42 1.1 jtc #endif
43 1.1 jtc
44 1.1 jtc /*
45 1.1 jtc **---------------------------------------------------------------------
46 1.1 jtc ** Other #define's
47 1.1 jtc **---------------------------------------------------------------------
48 1.1 jtc */
49 1.1 jtc #ifndef MAXPATHLEN
50 1.1 jtc #define MAXPATHLEN 1024
51 1.1 jtc #endif
52 1.1 jtc
53 1.1 jtc #ifndef SPOOLDIR
54 1.1 jtc #define SPOOLDIR "/export/pcnfs"
55 1.1 jtc #endif
56 1.1 jtc
57 1.1 jtc #ifndef LPRDIR
58 1.1 jtc #define LPRDIR "/usr/bin"
59 1.1 jtc #endif
60 1.1 jtc
61 1.1 jtc #ifndef LPCDIR
62 1.1 jtc #define LPCDIR "/usr/sbin"
63 1.1 jtc #endif
64 1.1 jtc
65 1.1 jtc /*
66 1.1 jtc ** The following defintions give the maximum time allowed for
67 1.1 jtc ** an external command to run (in seconds)
68 1.1 jtc */
69 1.1 jtc #define MAXTIME_FOR_PRINT 10
70 1.1 jtc #define MAXTIME_FOR_QUEUE 10
71 1.1 jtc #define MAXTIME_FOR_CANCEL 10
72 1.1 jtc #define MAXTIME_FOR_STATUS 10
73 1.1 jtc
74 1.1 jtc #define QMAX 50
75 1.1 jtc
76 1.1 jtc /*
77 1.1 jtc ** The following is derived from ucb/lpd/displayq.c
78 1.1 jtc */
79 1.1 jtc #define SIZECOL 62
80 1.1 jtc #define FILECOL 24
81 1.1 jtc
82 1.1 jtc extern void scramble();
83 1.1 jtc extern void run_ps630();
84 1.1 jtc extern char *crypt();
85 1.1 jtc extern FILE *su_popen();
86 1.1 jtc extern int su_pclose();
87 1.1 jtc int build_pr_list();
88 1.1 jtc char *map_printer_name();
89 1.1 jtc char *expand_alias();
90 1.1 jtc void *grab();
91 1.1 jtc void free_pr_list_item();
92 1.1 jtc void free_pr_queue_item();
93 1.1 jtc pr_list list_virtual_printers();
94 1.1 jtc
95 1.1 jtc /*
96 1.1 jtc **---------------------------------------------------------------------
97 1.1 jtc ** Misc. variable definitions
98 1.1 jtc **---------------------------------------------------------------------
99 1.1 jtc */
100 1.1 jtc
101 1.1 jtc extern int errno;
102 1.1 jtc extern int interrupted; /* in pcnfsd_misc.c */
103 1.1 jtc struct stat statbuf;
104 1.1 jtc char pathname[MAXPATHLEN];
105 1.1 jtc char new_pathname[MAXPATHLEN];
106 1.1 jtc char sp_name[MAXPATHLEN] = SPOOLDIR;
107 1.1 jtc char tempstr[256];
108 1.1 jtc char delims[] = " \t\r\n:()";
109 1.1 jtc
110 1.1 jtc pr_list printers = NULL;
111 1.1 jtc pr_queue queue = NULL;
112 1.1 jtc
113 1.1 jtc /*
114 1.1 jtc **=====================================================================
115 1.1 jtc ** C O D E S E C T I O N *
116 1.1 jtc **=====================================================================
117 1.1 jtc */
118 1.1 jtc
119 1.1 jtc /*
120 1.1 jtc * This is the latest word on the security check. The following
121 1.1 jtc * routine "suspicious()" returns non-zero if the character string
122 1.1 jtc * passed to it contains any shell metacharacters.
123 1.1 jtc * Callers will typically code
124 1.1 jtc *
125 1.1 jtc * if(suspicious(some_parameter)) reject();
126 1.1 jtc */
127 1.1 jtc
128 1.1 jtc int suspicious (s)
129 1.1 jtc char *s;
130 1.1 jtc {
131 1.1 jtc if(strpbrk(pathname, ";|&<>`'#!?*()[]^") != NULL)
132 1.1 jtc return 1;
133 1.1 jtc return 0;
134 1.1 jtc }
135 1.1 jtc
136 1.1 jtc
137 1.1 jtc int
138 1.1 jtc valid_pr(pr)
139 1.1 jtc char *pr;
140 1.1 jtc {
141 1.1 jtc char *p;
142 1.1 jtc pr_list curr;
143 1.1 jtc if(printers == NULL)
144 1.1 jtc build_pr_list();
145 1.1 jtc
146 1.1 jtc if(printers == NULL)
147 1.1 jtc return(1); /* can't tell - assume it's good */
148 1.1 jtc
149 1.1 jtc p = map_printer_name(pr);
150 1.1 jtc if (p == NULL)
151 1.1 jtc return(1); /* must be ok is maps to NULL! */
152 1.1 jtc curr = printers;
153 1.1 jtc while(curr) {
154 1.1 jtc if(!strcmp(p, curr->pn))
155 1.1 jtc return(1);
156 1.1 jtc curr = curr->pr_next;
157 1.1 jtc }
158 1.1 jtc
159 1.1 jtc return(0);
160 1.1 jtc }
161 1.1 jtc
162 1.1 jtc pirstat pr_init(sys, pr, sp)
163 1.1 jtc char *sys;
164 1.1 jtc char *pr;
165 1.1 jtc char**sp;
166 1.1 jtc {
167 1.1 jtc int dir_mode = 0777;
168 1.1 jtc int rc;
169 1.1 jtc
170 1.1 jtc *sp = &pathname[0];
171 1.1 jtc pathname[0] = '\0';
172 1.1 jtc
173 1.1 jtc if(suspicious(sys) || suspicious(pr))
174 1.1 jtc return(PI_RES_FAIL);
175 1.1 jtc
176 1.1 jtc /* get pathname of current directory and return to client */
177 1.1 jtc
178 1.1 jtc (void)sprintf(pathname,"%s/%s",sp_name, sys);
179 1.1 jtc (void)mkdir(sp_name, dir_mode); /* ignore the return code */
180 1.1 jtc (void)chmod(sp_name, dir_mode);
181 1.1 jtc rc = mkdir(pathname, dir_mode); /* DON'T ignore this return code */
182 1.1 jtc if((rc < 0 && errno != EEXIST) ||
183 1.1 jtc (chmod(pathname, dir_mode) != 0) ||
184 1.1 jtc (stat(pathname, &statbuf) != 0) ||
185 1.1 jtc !(statbuf.st_mode & S_IFDIR)) {
186 1.1 jtc (void)sprintf(tempstr,
187 1.1 jtc "rpc.pcnfsd: unable to set up spool directory %s\n",
188 1.1 jtc pathname);
189 1.1 jtc msg_out(tempstr);
190 1.1 jtc pathname[0] = '\0'; /* null to tell client bad vibes */
191 1.1 jtc return(PI_RES_FAIL);
192 1.1 jtc }
193 1.1 jtc if (!valid_pr(pr))
194 1.1 jtc {
195 1.1 jtc pathname[0] = '\0'; /* null to tell client bad vibes */
196 1.1 jtc return(PI_RES_NO_SUCH_PRINTER);
197 1.1 jtc }
198 1.1 jtc return(PI_RES_OK);
199 1.1 jtc
200 1.1 jtc }
201 1.1 jtc
202 1.1 jtc
204 1.1 jtc psrstat pr_start2(system, pr, user, fname, opts, id)
205 1.1 jtc char *system;
206 1.1 jtc char *pr;
207 1.1 jtc char *user;
208 1.1 jtc char *fname;
209 1.1 jtc char *opts;
210 1.1 jtc char **id;
211 1.1 jtc {
212 1.1 jtc char snum[20];
213 1.1 jtc static char req_id[256];
214 1.1 jtc char cmdbuf[256];
215 1.1 jtc char resbuf[256];
216 1.1 jtc FILE *fd;
217 1.1 jtc int i;
218 1.1 jtc char *xcmd;
219 1.1 jtc char *cp;
220 1.1 jtc int failed = 0;
221 1.1 jtc
222 1.1 jtc #ifdef HACK_FOR_ROTATED_TRANSCRIPT
223 1.1 jtc char scratch[512];
224 1.1 jtc #endif
225 1.1 jtc
226 1.1 jtc
227 1.1 jtc if(suspicious(system) ||
228 1.1 jtc suspicious(pr) ||
229 1.1 jtc suspicious(user) ||
230 1.1 jtc suspicious(fname))
231 1.1 jtc return(PS_RES_FAIL);
232 1.1 jtc
233 1.1 jtc (void)sprintf(pathname,"%s/%s/%s",sp_name,
234 1.1 jtc system,
235 1.1 jtc fname);
236 1.1 jtc
237 1.1 jtc *id = &req_id[0];
238 1.1 jtc req_id[0] = '\0';
239 1.1 jtc
240 1.1 jtc if (stat(pathname, &statbuf))
241 1.1 jtc {
242 1.1 jtc /*
243 1.1 jtc **-----------------------------------------------------------------
244 1.1 jtc ** We can't stat the file. Let's try appending '.spl' and
245 1.1 jtc ** see if it's already in progress.
246 1.1 jtc **-----------------------------------------------------------------
247 1.1 jtc */
248 1.1 jtc
249 1.1 jtc (void)strcat(pathname, ".spl");
250 1.1 jtc if (stat(pathname, &statbuf))
251 1.1 jtc {
252 1.1 jtc /*
253 1.1 jtc **----------------------------------------------------------------
254 1.1 jtc ** It really doesn't exist.
255 1.1 jtc **----------------------------------------------------------------
256 1.1 jtc */
257 1.1 jtc
258 1.1 jtc
259 1.1 jtc return(PS_RES_NO_FILE);
260 1.1 jtc }
261 1.1 jtc /*
262 1.1 jtc **-------------------------------------------------------------
263 1.1 jtc ** It is already on the way.
264 1.1 jtc **-------------------------------------------------------------
265 1.1 jtc */
266 1.1 jtc
267 1.1 jtc
268 1.1 jtc return(PS_RES_ALREADY);
269 1.1 jtc }
270 1.1 jtc
271 1.1 jtc if (statbuf.st_size == 0)
272 1.1 jtc {
273 1.1 jtc /*
274 1.1 jtc **-------------------------------------------------------------
275 1.1 jtc ** Null file - don't print it, just kill it.
276 1.1 jtc **-------------------------------------------------------------
277 1.1 jtc */
278 1.1 jtc (void)unlink(pathname);
279 1.1 jtc
280 1.1 jtc return(PS_RES_NULL);
281 1.1 jtc }
282 1.1 jtc /*
283 1.1 jtc **-------------------------------------------------------------
284 1.1 jtc ** The file is real, has some data, and is not already going out.
285 1.1 jtc ** We rename it by appending '.spl' and exec "lpr" to do the
286 1.1 jtc ** actual work.
287 1.1 jtc **-------------------------------------------------------------
288 1.1 jtc */
289 1.1 jtc (void)strcpy(new_pathname, pathname);
290 1.1 jtc (void)strcat(new_pathname, ".spl");
291 1.1 jtc
292 1.1 jtc /*
293 1.1 jtc **-------------------------------------------------------------
294 1.1 jtc ** See if the new filename exists so as not to overwrite it.
295 1.1 jtc **-------------------------------------------------------------
296 1.1 jtc */
297 1.1 jtc
298 1.1 jtc
299 1.1 jtc if (!stat(new_pathname, &statbuf))
300 1.1 jtc {
301 1.1 jtc (void)strcpy(new_pathname, pathname); /* rebuild a new name */
302 1.1 jtc (void)sprintf(snum, "%d", rand()); /* get some number */
303 1.1 jtc (void)strncat(new_pathname, snum, 3);
304 1.1 jtc (void)strcat(new_pathname, ".spl"); /* new spool file */
305 1.1 jtc }
306 1.1 jtc if (rename(pathname, new_pathname))
307 1.1 jtc {
308 1.1 jtc /*
309 1.1 jtc **---------------------------------------------------------------
310 1.1 jtc ** Should never happen.
311 1.1 jtc **---------------------------------------------------------------
312 1.1 jtc */
313 1.1 jtc (void)sprintf(tempstr, "rpc.pcnfsd: spool file rename (%s->%s) failed.\n",
314 1.1 jtc pathname, new_pathname);
315 1.1 jtc msg_out(tempstr);
316 1.1 jtc return(PS_RES_FAIL);
317 1.1 jtc }
318 1.1 jtc
319 1.1 jtc if (*opts == 'd')
320 1.1 jtc {
321 1.1 jtc /*
322 1.1 jtc **------------------------------------------------------
323 1.1 jtc ** This is a Diablo print stream. Apply the ps630
324 1.1 jtc ** filter with the appropriate arguments.
325 1.1 jtc **------------------------------------------------------
326 1.1 jtc */
327 1.1 jtc (void)run_ps630(new_pathname, opts);
328 1.1 jtc }
329 1.1 jtc /*
330 1.1 jtc ** Try to match to an aliased printer
331 1.1 jtc */
332 1.1 jtc xcmd = expand_alias(pr, new_pathname, user, system);
333 1.1 jtc /*
334 1.1 jtc **----------------------------------------------------------
335 1.1 jtc ** Use the copy option so we can remove the orignal spooled
336 1.1 jtc ** nfs file from the spool directory.
337 1.1 jtc **----------------------------------------------------------
338 1.1 jtc */
339 1.1 jtc if(!xcmd) {
340 1.1 jtc sprintf(cmdbuf, "%s/lpr -P%s %s",
341 1.1 jtc LPRDIR, pr, new_pathname);
342 1.1 jtc xcmd = cmdbuf;
343 1.1 jtc }
344 1.1 jtc if ((fd = su_popen(user, xcmd, MAXTIME_FOR_PRINT)) == NULL) {
345 1.1 jtc msg_out("rpc.pcnfsd: su_popen failed");
346 1.1 jtc return(PS_RES_FAIL);
347 1.1 jtc }
348 1.1 jtc req_id[0] = '\0'; /* asume failure */
349 1.1 jtc while(fgets(resbuf, 255, fd) != NULL) {
350 1.1 jtc i = strlen(resbuf);
351 1.1 jtc if(i)
352 1.1 jtc resbuf[i-1] = '\0'; /* trim NL */
353 1.1 jtc if(!strncmp(resbuf, "request id is ", 14))
354 1.1 jtc /* New - just the first word is needed */
355 1.1 jtc strcpy(req_id, strtok(&resbuf[14], delims));
356 1.1 jtc else if (strembedded("disabled", resbuf))
357 1.1 jtc failed = 1;
358 1.1 jtc }
359 1.1 jtc if(su_pclose(fd) == 255)
360 1.1 jtc msg_out("rpc.pcnfsd: su_pclose alert");
361 1.1 jtc (void)unlink(new_pathname);
362 1.1 jtc return((failed | interrupted)? PS_RES_FAIL : PS_RES_OK);
363 1.1 jtc }
364 1.1 jtc
365 1.1 jtc
367 1.1 jtc /*
368 1.1 jtc * determine which printers are valid...
369 1.1 jtc * on BSD use "lpc status"
370 1.1 jtc * on SVR4 use "lpstat -v"
371 1.1 jtc */
372 1.1 jtc int
373 1.1 jtc build_pr_list()
374 1.1 jtc {
375 1.1 jtc pr_list last = NULL;
376 1.1 jtc pr_list curr = NULL;
377 1.1 jtc char buff[256];
378 1.1 jtc FILE *p;
379 1.1 jtc char *cp;
380 1.1 jtc int saw_system;
381 1.1 jtc
382 1.1 jtc sprintf(buff, "%s/lpc status", LPCDIR);
383 1.1 jtc p = popen(buff, "r");
384 1.1 jtc if(p == NULL) {
385 1.1 jtc msg_out("rpc.pcnfsd: unable to popen lpc stat");
386 1.1 jtc return(0);
387 1.1 jtc }
388 1.1 jtc
389 1.1 jtc while(fgets(buff, 255, p) != NULL) {
390 1.1 jtc if (isspace(buff[0]))
391 1.1 jtc continue;
392 1.1 jtc
393 1.1 jtc if ((cp = strtok(buff, delims)) == NULL)
394 1.1 jtc continue;
395 1.1 jtc
396 1.1 jtc curr = (struct pr_list_item *)
397 1.1 jtc grab(sizeof (struct pr_list_item));
398 1.1 jtc
399 1.1 jtc /* XXX - Should distinguish remote printers. */
400 1.1 jtc curr->pn = strdup(cp);
401 1.1 jtc curr->device = strdup(cp);
402 1.1 jtc curr->remhost = strdup("");
403 1.1 jtc curr->cm = strdup("-");
404 1.1 jtc curr->pr_next = NULL;
405 1.1 jtc
406 1.1 jtc if(last == NULL)
407 1.1 jtc printers = curr;
408 1.1 jtc else
409 1.1 jtc last->pr_next = curr;
410 1.1 jtc last = curr;
411 1.1 jtc
412 1.1 jtc }
413 1.1 jtc (void) fclose(p);
414 1.1 jtc
415 1.1 jtc /*
416 1.1 jtc ** Now add on the virtual printers, if any
417 1.1 jtc */
418 1.1 jtc if(last == NULL)
419 1.1 jtc printers = list_virtual_printers();
420 1.1 jtc else
421 1.1 jtc last->pr_next = list_virtual_printers();
422 1.1 jtc
423 1.1 jtc return(1);
424 1.1 jtc }
425 1.1 jtc
426 1.1 jtc void *grab(n)
427 1.1 jtc int n;
428 1.1 jtc {
429 1.1 jtc void *p;
430 1.1 jtc
431 1.1 jtc p = (void *)malloc(n);
432 1.1 jtc if(p == NULL) {
433 1.1 jtc msg_out("rpc.pcnfsd: malloc failure");
434 1.1 jtc exit(1);
435 1.1 jtc }
436 1.1 jtc return(p);
437 1.1 jtc }
438 1.1 jtc
439 1.1 jtc void
440 1.1 jtc free_pr_list_item(curr)
441 1.1 jtc pr_list curr;
442 1.1 jtc {
443 1.1 jtc if(curr->pn)
444 1.1 jtc free(curr->pn);
445 1.1 jtc if(curr->device)
446 1.1 jtc free(curr->device);
447 1.1 jtc if(curr->remhost)
448 1.1 jtc free(curr->remhost);
449 1.1 jtc if(curr->cm)
450 1.1 jtc free(curr->cm);
451 1.1 jtc if(curr->pr_next)
452 1.1 jtc free_pr_list_item(curr->pr_next); /* recurse */
453 1.1 jtc free(curr);
454 1.1 jtc }
455 1.1 jtc /*
456 1.1 jtc ** Print queue handling.
457 1.1 jtc **
458 1.1 jtc ** Note that the first thing we do is to discard any
459 1.1 jtc ** existing queue.
460 1.1 jtc */
461 1.1 jtc
462 1.1 jtc pirstat
463 1.1 jtc build_pr_queue(pn, user, just_mine, p_qlen, p_qshown)
464 1.1 jtc printername pn;
465 1.1 jtc username user;
466 1.1 jtc int just_mine;
467 1.1 jtc int *p_qlen;
468 1.1 jtc int *p_qshown;
469 1.1 jtc {
470 1.1 jtc pr_queue last = NULL;
471 1.1 jtc pr_queue curr = NULL;
472 1.1 jtc char buff[256];
473 1.1 jtc FILE *p;
474 1.1 jtc char *cp;
475 1.1 jtc int i;
476 1.1 jtc char *rank;
477 1.1 jtc char *owner;
478 1.1 jtc char *job;
479 1.1 jtc char *files;
480 1.1 jtc char *totsize;
481 1.1 jtc
482 1.1 jtc if(queue) {
483 1.1 jtc free_pr_queue_item(queue);
484 1.1 jtc queue = NULL;
485 1.1 jtc }
486 1.1 jtc *p_qlen = 0;
487 1.1 jtc *p_qshown = 0;
488 1.1 jtc pn = map_printer_name(pn);
489 1.1 jtc if(pn == NULL || suspicious(pn))
490 1.1 jtc return(PI_RES_NO_SUCH_PRINTER);
491 1.1 jtc
492 1.1 jtc sprintf(buff, "%s/lpq -P%s", LPRDIR, pn);
493 1.1 jtc
494 1.1 jtc p = su_popen(user, buff, MAXTIME_FOR_QUEUE);
495 1.1 jtc if(p == NULL) {
496 1.1 jtc msg_out("rpc.pcnfsd: unable to popen() lpq");
497 1.1 jtc return(PI_RES_FAIL);
498 1.1 jtc }
499 1.1 jtc
500 1.1 jtc while(fgets(buff, 255, p) != NULL) {
501 1.1 jtc i = strlen(buff) - 1;
502 1.1 jtc buff[i] = '\0'; /* zap trailing NL */
503 1.1 jtc if(i < SIZECOL)
504 1.1 jtc continue;
505 1.1 jtc if(!mystrncasecmp(buff, "rank", 4))
506 1.1 jtc continue;
507 1.1 jtc
508 1.1 jtc totsize = &buff[SIZECOL-1];
509 1.1 jtc files = &buff[FILECOL-1];
510 1.1 jtc cp = totsize;
511 1.1 jtc cp--;
512 1.1 jtc while(cp > files && isspace(*cp))
513 1.1 jtc *cp-- = '\0';
514 1.1 jtc
515 1.1 jtc buff[FILECOL-2] = '\0';
516 1.1 jtc
517 1.1 jtc cp = strtok(buff, delims);
518 1.1 jtc if(!cp)
519 1.1 jtc continue;
520 1.1 jtc rank = cp;
521 1.1 jtc
522 1.1 jtc cp = strtok(NULL, delims);
523 1.1 jtc if(!cp)
524 1.1 jtc continue;
525 1.1 jtc owner = cp;
526 1.1 jtc
527 1.1 jtc cp = strtok(NULL, delims);
528 1.1 jtc if(!cp)
529 1.1 jtc continue;
530 1.1 jtc job = cp;
531 1.1 jtc
532 1.1 jtc *p_qlen += 1;
533 1.1 jtc
534 1.1 jtc if(*p_qshown > QMAX)
535 1.1 jtc continue;
536 1.1 jtc
537 1.1 jtc if(just_mine && mystrcasecmp(owner, user))
538 1.1 jtc continue;
539 1.1 jtc
540 1.1 jtc *p_qshown += 1;
541 1.1 jtc
542 1.1 jtc curr = (struct pr_queue_item *)
543 1.1 jtc grab(sizeof (struct pr_queue_item));
544 1.1 jtc
545 1.1 jtc curr->position = atoi(rank); /* active -> 0 */
546 1.1 jtc curr->id = strdup(job);
547 1.1 jtc curr->size = strdup(totsize);
548 1.1 jtc curr->status = strdup(rank);
549 1.1 jtc curr->system = strdup("");
550 1.1 jtc curr->user = strdup(owner);
551 1.1 jtc curr->file = strdup(files);
552 1.1 jtc curr->cm = strdup("-");
553 1.1 jtc curr->pr_next = NULL;
554 1.1 jtc
555 1.1 jtc if(last == NULL)
556 1.1 jtc queue = curr;
557 1.1 jtc else
558 1.1 jtc last->pr_next = curr;
559 1.1 jtc last = curr;
560 1.1 jtc
561 1.1 jtc }
562 1.1 jtc (void) su_pclose(p);
563 1.1 jtc return(PI_RES_OK);
564 1.1 jtc }
565 1.1 jtc
566 1.1 jtc void
567 1.1 jtc free_pr_queue_item(curr)
568 1.1 jtc pr_queue curr;
569 1.1 jtc {
570 1.1 jtc if(curr->id)
571 1.1 jtc free(curr->id);
572 1.1 jtc if(curr->size)
573 1.1 jtc free(curr->size);
574 1.1 jtc if(curr->status)
575 1.1 jtc free(curr->status);
576 1.1 jtc if(curr->system)
577 1.1 jtc free(curr->system);
578 1.1 jtc if(curr->user)
579 1.1 jtc free(curr->user);
580 1.1 jtc if(curr->file)
581 1.1 jtc free(curr->file);
582 1.1 jtc if(curr->cm)
583 1.1 jtc free(curr->cm);
584 1.1 jtc if(curr->pr_next)
585 1.1 jtc free_pr_queue_item(curr->pr_next); /* recurse */
586 1.1 jtc free(curr);
587 1.1 jtc }
588 1.1 jtc
589 1.1 jtc
590 1.1 jtc
591 1.1 jtc pirstat
592 1.1 jtc get_pr_status(pn, avail, printing, qlen, needs_operator, status)
593 1.1 jtc printername pn;
594 1.1 jtc bool_t *avail;
595 1.1 jtc bool_t *printing;
596 1.1 jtc int *qlen;
597 1.1 jtc bool_t *needs_operator;
598 1.1 jtc char *status;
599 1.1 jtc {
600 1.1 jtc char cmd[128];
601 1.1 jtc char buff[256];
602 1.1 jtc char buff2[256];
603 1.1 jtc char pname[64];
604 1.1 jtc FILE *p;
605 1.1 jtc char *cp;
606 1.1 jtc char *cp1;
607 1.1 jtc char *cp2;
608 1.1 jtc int n;
609 1.1 jtc pirstat stat = PI_RES_NO_SUCH_PRINTER;
610 1.1 jtc
611 1.1 jtc /* assume the worst */
612 1.1 jtc *avail = FALSE;
613 1.1 jtc *printing = FALSE;
614 1.1 jtc *needs_operator = FALSE;
615 1.1 jtc *qlen = 0;
616 1.1 jtc *status = '\0';
617 1.1 jtc
618 1.1 jtc pn = map_printer_name(pn);
619 1.1 jtc if(pn == NULL || suspicious(pn))
620 1.1 jtc return(PI_RES_NO_SUCH_PRINTER);
621 1.1 jtc
622 1.1 jtc sprintf(pname, "%s:", pn);
623 1.1 jtc n = strlen(pname);
624 1.1 jtc
625 1.1 jtc #if 0
626 1.1 jtc /*
627 1.1 jtc * We used to use lpstat -a, but it breaks because of
628 1.1 jtc * printer alias inconsistency
629 1.1 jtc */
630 1.1 jtc p = popen("/usr/bin/lpstat -a", "r");
631 1.1 jtc #else
632 1.1 jtc /*
633 1.1 jtc * So now we use: lpc status
634 1.1 jtc */
635 1.1 jtc sprintf(cmd, "%s/lpc status %s", LPCDIR, pn);
636 1.1 jtc p = popen(cmd, "r");
637 1.1 jtc #endif
638 1.1 jtc if(p == NULL) {
639 1.1 jtc msg_out("rpc.pcnfsd: unable to popen() lp status");
640 1.1 jtc return(PI_RES_FAIL);
641 1.1 jtc }
642 1.1 jtc
643 1.1 jtc while(fgets(buff, 255, p) != NULL) {
644 1.1 jtc if(strncmp(buff, pname, n))
645 1.1 jtc continue;
646 1.1 jtc /*
647 1.1 jtc ** We have a match. The only failure now is PI_RES_FAIL if
648 1.1 jtc ** lpstat output cannot be decoded
649 1.1 jtc */
650 1.1 jtc stat = PI_RES_FAIL;
651 1.1 jtc /*
652 1.1 jtc ** The next four lines are usually if the form
653 1.1 jtc **
654 1.1 jtc ** queuing is [enabled|disabled]
655 1.1 jtc ** printing is [enabled|disabled]
656 1.1 jtc ** [no entries | N entr[y|ies] in spool area]
657 1.1 jtc ** <status message, may include the word "attention">
658 1.1 jtc */
659 1.1 jtc while(fgets(buff, 255, p) != NULL && isspace(buff[0])) {
660 1.1 jtc cp = buff;
661 1.1 jtc while(isspace(*cp))
662 1.1 jtc cp++;
663 1.1 jtc if(*cp == '\0')
664 1.1 jtc break;
665 1.1 jtc cp1 = cp;
666 1.1 jtc cp2 = buff2;
667 1.1 jtc while(*cp1 && *cp1 != '\n') {
668 1.1 jtc *cp2++ = tolower(*cp1);
669 1.1 jtc cp1++;
670 1.1 jtc }
671 1.1 jtc *cp1 = '\0';
672 1.1 jtc *cp2 = '\0';
673 1.1 jtc /*
674 1.1 jtc ** Now buff2 has a lower-cased copy and cp points at the original;
675 1.1 jtc ** both are null terminated without any newline
676 1.1 jtc */
677 1.1 jtc if(!strncmp(buff2, "queuing", 7)) {
678 1.1 jtc *avail = (strstr(buff2, "enabled") != NULL);
679 1.1 jtc continue;
680 1.1 jtc }
681 1.1 jtc if(!strncmp(buff2, "printing", 8)) {
682 1.1 jtc *printing = (strstr(buff2, "enabled") != NULL);
683 1.1 jtc continue;
684 1.1 jtc }
685 1.1 jtc if(isdigit(buff2[0]) && (strstr(buff2, "entr") !=NULL)) {
686 1.1 jtc
687 1.1 jtc *qlen = atoi(buff2);
688 1.1 jtc continue;
689 1.1 jtc }
690 1.1 jtc if(strstr(buff2, "attention") != NULL ||
691 1.1 jtc strstr(buff2, "error") != NULL)
692 1.1 jtc *needs_operator = TRUE;
693 1.1 jtc if(*needs_operator || strstr(buff2, "waiting") != NULL)
694 1.1 jtc strcpy(status, cp);
695 1.1 jtc }
696 1.1 jtc stat = PI_RES_OK;
697 1.1 jtc break;
698 1.1 jtc }
699 1.1 jtc (void) pclose(p);
700 1.1 jtc return(stat);
701 1.1 jtc }
702 1.1 jtc
703 1.1 jtc
704 1.1 jtc pcrstat pr_cancel(pr, user, id)
705 1.1 jtc char *pr;
706 1.1 jtc char *user;
707 1.1 jtc char *id;
708 1.1 jtc {
709 1.1 jtc char cmdbuf[256];
710 1.1 jtc char resbuf[256];
711 1.1 jtc FILE *fd;
712 1.1 jtc int i;
713 1.1 jtc pcrstat stat = PC_RES_NO_SUCH_JOB;
714 1.1 jtc
715 1.1 jtc pr = map_printer_name(pr);
716 1.1 jtc if(pr == NULL || suspicious(pr))
717 1.1 jtc return(PC_RES_NO_SUCH_PRINTER);
718 1.1 jtc if(suspicious(id))
719 1.1 jtc return(PC_RES_NO_SUCH_JOB);
720 1.1 jtc
721 1.1 jtc sprintf(cmdbuf, "%s/lprm -P%s %s", LPRDIR, pr, id);
722 1.1 jtc if ((fd = su_popen(user, cmdbuf, MAXTIME_FOR_CANCEL)) == NULL) {
723 1.1 jtc msg_out("rpc.pcnfsd: su_popen failed");
724 1.1 jtc return(PC_RES_FAIL);
725 1.1 jtc }
726 1.1 jtc while(fgets(resbuf, 255, fd) != NULL) {
727 1.1 jtc i = strlen(resbuf);
728 1.1 jtc if(i)
729 1.1 jtc resbuf[i-1] = '\0'; /* trim NL */
730 1.1 jtc if(strstr(resbuf, "dequeued") != NULL)
731 1.1 jtc stat = PC_RES_OK;
732 1.1 jtc if(strstr(resbuf, "unknown printer") != NULL)
733 1.1 jtc stat = PC_RES_NO_SUCH_PRINTER;
734 1.1 jtc if(strstr(resbuf, "Permission denied") != NULL)
735 1.1 jtc stat = PC_RES_NOT_OWNER;
736 1.1 jtc }
737 1.1 jtc if(su_pclose(fd) == 255)
738 1.1 jtc msg_out("rpc.pcnfsd: su_pclose alert");
739 1.1 jtc return(stat);
740 1.1 jtc }
741 1.1 jtc
742 1.1 jtc
743 1.1 jtc /*
745 1.1 jtc ** New subsystem here. We allow the administrator to define
746 1.1 jtc ** up to NPRINTERDEFS aliases for printer names. This is done
747 1.1 jtc ** using the "/etc/pcnfsd.conf" file, which is read at startup.
748 1.1 jtc ** There are three entry points to this subsystem
749 1.1 jtc **
750 1.1 jtc ** void add_printer_alias(char *printer, char *alias_for, char *command)
751 1.1 jtc **
752 1.1 jtc ** This is invoked from "config_from_file()" for each
753 1.1 jtc ** "printer" line. "printer" is the name of a printer; note that
754 1.1 jtc ** it is possible to redefine an existing printer. "alias_for"
755 1.1 jtc ** is the name of the underlying printer, used for queue listing
756 1.1 jtc ** and other control functions. If it is "-", there is no
757 1.1 jtc ** underlying printer, or the administrative functions are
758 1.1 jtc ** not applicable to this printer. "command"
759 1.1 jtc ** is the command which should be run (via "su_popen()") if a
760 1.1 jtc ** job is printed on this printer. The following tokens may be
761 1.1 jtc ** embedded in the command, and are substituted as follows:
762 1.1 jtc **
763 1.1 jtc ** $FILE - path to the file containing the print data
764 1.1 jtc ** $USER - login of user
765 1.1 jtc ** $HOST - hostname from which job originated
766 1.1 jtc **
767 1.1 jtc ** Tokens may occur multiple times. If The command includes no
768 1.1 jtc ** $FILE token, the string " $FILE" is silently appended.
769 1.1 jtc **
770 1.1 jtc ** pr_list list_virtual_printers()
771 1.1 jtc **
772 1.1 jtc ** This is invoked from build_pr_list to generate a list of aliased
773 1.1 jtc ** printers, so that the client that asks for a list of valid printers
774 1.1 jtc ** will see these ones.
775 1.1 jtc **
776 1.1 jtc ** char *map_printer_name(char *printer)
777 1.1 jtc **
778 1.1 jtc ** If "printer" identifies an aliased printer, this function returns
779 1.1 jtc ** the "alias_for" name, or NULL if the "alias_for" was given as "-".
780 1.1 jtc ** Otherwise it returns its argument.
781 1.1 jtc **
782 1.1 jtc ** char *expand_alias(char *printer, char *file, char *user, char *host)
783 1.1 jtc **
784 1.1 jtc ** If "printer" is an aliased printer, this function returns a
785 1.1 jtc ** pointer to a static string in which the corresponding command
786 1.1 jtc ** has been expanded. Otherwise ot returns NULL.
787 1.1 jtc */
788 1.1 jtc #define NPRINTERDEFS 16
789 1.1 jtc int num_aliases = 0;
790 1.1 jtc struct {
791 1.1 jtc char *a_printer;
792 1.1 jtc char *a_alias_for;
793 1.1 jtc char *a_command;
794 1.1 jtc } alias [NPRINTERDEFS];
795 1.1 jtc
796 1.1 jtc
797 1.1 jtc
798 1.1 jtc void
799 1.1 jtc add_printer_alias(printer, alias_for, command)
800 1.1 jtc char *printer;
801 1.1 jtc char *alias_for;
802 1.1 jtc char *command;
803 1.1 jtc {
804 1.1 jtc if(num_aliases < NPRINTERDEFS) {
805 1.1 jtc alias[num_aliases].a_printer = strdup(printer);
806 1.1 jtc alias[num_aliases].a_alias_for =
807 1.1 jtc (strcmp(alias_for, "-") ? strdup(alias_for) : NULL);
808 1.1 jtc if(strstr(command, "$FILE"))
809 1.1 jtc alias[num_aliases].a_command = strdup(command);
810 1.1 jtc else {
811 1.1 jtc alias[num_aliases].a_command = (char *)grab(strlen(command) + 8);
812 1.1 jtc strcpy(alias[num_aliases].a_command, command);
813 1.1 jtc strcat(alias[num_aliases].a_command, " $FILE");
814 1.1 jtc }
815 1.1 jtc num_aliases++;
816 1.1 jtc }
817 1.1 jtc }
818 1.1 jtc
819 1.1 jtc pr_list list_virtual_printers()
820 1.1 jtc {
821 1.1 jtc pr_list first = NULL;
822 1.1 jtc pr_list last = NULL;
823 1.1 jtc pr_list curr = NULL;
824 1.1 jtc int i;
825 1.1 jtc
826 1.1 jtc
827 1.1 jtc if(num_aliases == 0)
828 1.1 jtc return(NULL);
829 1.1 jtc
830 1.1 jtc for (i = 0; i < num_aliases; i++) {
831 1.1 jtc curr = (struct pr_list_item *)
832 1.1 jtc grab(sizeof (struct pr_list_item));
833 1.1 jtc
834 1.1 jtc curr->pn = strdup(alias[i].a_printer);
835 1.1 jtc if(alias[i].a_alias_for == NULL)
836 1.1 jtc curr->device = strdup("");
837 1.1 jtc else
838 1.1 jtc curr->device = strdup(alias[i].a_alias_for);
839 1.1 jtc curr->remhost = strdup("");
840 1.1 jtc curr->cm = strdup("(alias)");
841 1.1 jtc curr->pr_next = NULL;
842 1.1 jtc if(last == NULL)
843 1.1 jtc first = curr;
844 1.1 jtc else
845 1.1 jtc last->pr_next = curr;
846 1.1 jtc last = curr;
847 1.1 jtc
848 1.1 jtc }
849 1.1 jtc return(first);
850 1.1 jtc }
851 1.1 jtc
852 1.1 jtc
853 1.1 jtc char *
854 1.1 jtc map_printer_name(printer)
855 1.1 jtc char *printer;
856 1.1 jtc {
857 1.1 jtc int i;
858 1.1 jtc for (i = 0; i < num_aliases; i++){
859 1.1 jtc if(!strcmp(printer, alias[i].a_printer))
860 1.1 jtc return(alias[i].a_alias_for);
861 1.1 jtc }
862 1.1 jtc return(printer);
863 1.1 jtc }
864 1.1 jtc
865 1.1 jtc static void
866 1.1 jtc substitute(string, token, data)
867 1.1 jtc char *string;
868 1.1 jtc char *token;
869 1.1 jtc char *data;
870 1.1 jtc {
871 1.1 jtc char temp[512];
872 1.1 jtc char *c;
873 1.1 jtc
874 1.1 jtc while(c = strstr(string, token)) {
875 1.1 jtc *c = '\0';
876 1.1 jtc strcpy(temp, string);
877 1.1 jtc strcat(temp, data);
878 1.1 jtc c += strlen(token);
879 1.1 jtc strcat(temp, c);
880 1.1 jtc strcpy(string, temp);
881 1.1 jtc }
882 1.1 jtc }
883 1.1 jtc
884 1.1 jtc char *
885 1.1 jtc expand_alias(printer, file, user, host)
886 1.1 jtc char *printer;
887 1.1 jtc char *file;
888 1.1 jtc char *user;
889 1.1 jtc char *host;
890 1.1 jtc {
891 1.1 jtc static char expansion[512];
892 1.1 jtc int i;
893 1.1 jtc for (i = 0; i < num_aliases; i++){
894 1.1 jtc if(!strcmp(printer, alias[i].a_printer)) {
895 1.1 jtc strcpy(expansion, alias[i].a_command);
896 1.1 jtc substitute(expansion, "$FILE", file);
897 1.1 jtc substitute(expansion, "$USER", user);
898 1.1 jtc substitute(expansion, "$HOST", host);
899 1.1 jtc return(expansion);
900 1.1 jtc }
901 1.1 jtc }
902 return(NULL);
903 }
904
905