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