1 /* $NetBSD: cmds.c,v 1.21 2009/01/18 09:57:26 lukem Exp $ */
3 * Copyright (c) 1983, 1993
4 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
35 The Regents of the University of California. All rights reserved.");
37 static char sccsid
[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95";
39 __RCSID("$NetBSD: cmds.c,v 1.21 2009/01/18 09:57:26 lukem Exp $");
44 * lpc -- line printer control program -- commands:
47 #include <sys/param.h>
65 #include "pathnames.h"
67 extern uid_t uid
, euid
;
69 static void abortpr(int);
70 static void cleanpr(void);
71 static void disablepr(void);
72 static int doarg(const char *);
73 static int doselect(const struct dirent
*);
74 static void enablepr(void);
75 static void prstat(void);
76 static void putmsg(int, char **);
77 static int sortq(const void *, const void *);
78 static void startpr(int);
79 static void stoppr(void);
80 static int touch(struct queue
*);
81 static void unlinkf(const char *);
82 static void upstat(const char *);
83 static int getcapdesc(void);
84 static void getcaps(void);
87 * kill an existing daemon and disable printing.
90 doabort(int argc
, char *argv
[])
97 printf("Usage: abort {all | printer ...}\n");
100 if (argc
== 2 && !strcmp(argv
[1], "all")) {
102 while (cgetnext(&bp
, printcapdb
) > 0) {
105 while ((c
= *cp2
++) && c
!= '|' && c
!= ':' &&
106 (size_t)(cp1
- prbuf
) < sizeof(prbuf
))
129 printf("%s:\n", printer
);
132 * Turn on the owner execute bit of the lock file to disable printing.
136 if (stat(line
, &stbuf
) >= 0) {
137 if (chmod(line
, (stbuf
.st_mode
& 0777) | 0100) < 0)
138 printf("\tcannot disable printing\n");
140 upstat("printing disabled\n");
141 printf("\tprinting disabled\n");
143 } else if (errno
== ENOENT
) {
144 if ((fd
= open(line
, O_WRONLY
|O_CREAT
, 0760)) < 0)
145 printf("\tcannot create lock file\n");
148 upstat("printing disabled\n");
149 printf("\tprinting disabled\n");
150 printf("\tno daemon to abort\n");
154 printf("\tcannot stat lock file\n");
159 * Kill the current daemon to stop printing now.
161 if ((fp
= fopen(line
, "r")) == NULL
) {
162 printf("\tcannot open lock file\n");
165 if (!get_line(fp
) || flock(fileno(fp
), LOCK_SH
|LOCK_NB
) == 0) {
166 (void)fclose(fp
); /* unlocks as well */
167 printf("\tno daemon to abort\n");
171 if (kill(pid
= atoi(line
), SIGTERM
) < 0) {
173 printf("\tno daemon to abort\n");
175 printf("\tWarning: daemon (pid %d) not killed\n", pid
);
177 printf("\tdaemon (pid %d) killed\n", pid
);
183 * Write a message into the status file.
186 upstat(const char *msg
)
189 char statfile
[MAXPATHLEN
];
192 (void)snprintf(statfile
, sizeof(statfile
), "%s/%s", SD
, ST
);
194 fd
= open(statfile
, O_WRONLY
|O_CREAT
, 0664);
195 if (fd
< 0 || flock(fd
, LOCK_EX
) < 0) {
196 printf("\tcannot create status file\n");
201 (void)ftruncate(fd
, 0);
202 if (msg
== (char *)NULL
)
203 (void)write(fd
, "\n", 1);
205 (void)write(fd
, msg
, strlen(msg
));
210 * Remove all spool files and temporaries from the spooling area.
213 clean(int argc
, char *argv
[])
220 printf("Usage: clean {all | printer ...}\n");
223 if (argc
== 2 && !strcmp(argv
[1], "all")) {
225 while (cgetnext(&bp
, printcapdb
) > 0) {
228 while ((c
= *cp2
++) && c
!= '|' && c
!= ':' &&
229 (size_t)(cp1
- prbuf
) < sizeof(prbuf
))
245 doselect(const struct dirent
*d
)
247 int c
= d
->d_name
[0];
249 if ((c
== 't' || c
== 'c' || c
== 'd') && d
->d_name
[1] == 'f')
255 * Comparison routine for scandir. Sort by job number and machine, then
256 * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z.
259 sortq(const void *a
, const void *b
)
261 const struct dirent
*const *d1
, *const *d2
;
264 d1
= (const struct dirent
*const *)a
;
265 d2
= (const struct dirent
*const *)b
;
266 if ((c1
= strcmp((*d1
)->d_name
+ 3, (*d2
)->d_name
+ 3)) != 0)
268 c1
= (*d1
)->d_name
[0];
269 c2
= (*d2
)->d_name
[0];
271 return((*d1
)->d_name
[2] - (*d2
)->d_name
[2]);
274 if (c1
== 'd' || c2
== 'c')
280 * Remove incomplete jobs from spooling area.
288 struct dirent
**queue
;
292 printf("%s:\n", printer
);
294 /* XXX depends on SD being non nul */
295 ep
= line
+ sizeof(line
);
296 for (lp
= line
, cp
= SD
; (size_t)(lp
- line
) < sizeof(line
) &&
297 (*lp
++ = *cp
++) != '\0'; )
302 nitems
= scandir(SD
, &queue
, doselect
, sortq
);
305 printf("\tcannot examine spool directory\n");
312 cp
= queue
[i
]->d_name
;
315 while (i
+ 1 < nitems
) {
316 cp1
= queue
[i
+ 1]->d_name
;
317 if (*cp1
!= 'd' || strcmp(cp
+ 3, cp1
+ 3))
323 strlcpy(lp
, cp
, ep
- lp
);
328 * Must be a df with no cf (otherwise, it would have
329 * been skipped above) or a tf file (which can always
332 strlcpy(lp
, cp
, ep
- lp
);
335 } while (++i
< nitems
);
339 unlinkf(const char *name
)
342 if (unlink(name
) < 0)
343 printf("\tcannot remove %s\n", name
);
345 printf("\tremoved %s\n", name
);
350 * Enable queuing to the printer (allow lpr's).
353 enable(int argc
, char *argv
[])
360 printf("Usage: enable {all | printer ...}\n");
363 if (argc
== 2 && !strcmp(argv
[1], "all")) {
365 while (cgetnext(&bp
, printcapdb
) > 0) {
368 while ((c
= *cp2
++) && c
!= '|' && c
!= ':' &&
369 (size_t)(cp1
- prbuf
) < sizeof(prbuf
))
388 if ((st
= cgetent(&bp
, printcapdb
, printer
)) == -2) {
389 printf("cannot open printer description file\n");
391 } else if (st
== -1) {
392 printf("unknown printer %s\n", printer
);
395 fatal("potential reference loop detected in printcap file");
405 printf("%s:\n", printer
);
408 * Turn off the group execute bit of the lock file to enable queuing.
411 if (stat(line
, &stbuf
) >= 0) {
412 if (chmod(line
, stbuf
.st_mode
& 0767) < 0)
413 printf("\tcannot enable queuing\n");
415 printf("\tqueuing enabled\n");
424 disable(int argc
, char *argv
[])
431 printf("Usage: disable {all | printer ...}\n");
434 if (argc
== 2 && !strcmp(argv
[1], "all")) {
436 while (cgetnext(&bp
, printcapdb
) > 0) {
439 while ((c
= *cp2
++) && c
!= '|' && c
!= ':' &&
440 (size_t)(cp1
- prbuf
) < sizeof(prbuf
))
462 printf("%s:\n", printer
);
464 * Turn on the group execute bit of the lock file to disable queuing.
467 if (stat(line
, &stbuf
) >= 0) {
468 if (chmod(line
, (stbuf
.st_mode
& 0777) | 010) < 0)
469 printf("\tcannot disable queuing\n");
471 printf("\tqueuing disabled\n");
472 } else if (errno
== ENOENT
) {
473 if ((fd
= open(line
, O_WRONLY
|O_CREAT
, 0670)) < 0)
474 printf("\tcannot create lock file\n");
477 printf("\tqueuing disabled\n");
480 printf("\tcannot stat lock file\n");
485 * Disable queuing and printing and put a message into the status file
486 * (reason for being down).
489 down(int argc
, char *argv
[])
496 printf("Usage: down {all | printer} [message ...]\n");
499 if (!strcmp(argv
[1], "all")) {
501 while (cgetnext(&bp
, printcapdb
) > 0) {
504 while ((c
= *cp2
++) && c
!= '|' && c
!= ':' &&
505 (size_t)(cp1
- prbuf
) < sizeof(prbuf
))
508 putmsg(argc
- 2, argv
+ 2);
515 putmsg(argc
- 2, argv
+ 2);
522 SD
= cgetstr(bp
, "sd", &cp
) == -1 ? _PATH_DEFSPOOL
: cp
;
523 LO
= cgetstr(bp
, "lo", &cp
) == -1 ? DEFLOCK
: cp
;
524 ST
= cgetstr(bp
, "st", &cp
) == -1 ? DEFSTAT
: cp
;
525 (void)snprintf(line
, sizeof(line
), "%s/%s", SD
, LO
);
529 putmsg(int argc
, char **argv
)
536 printf("%s:\n", printer
);
538 * Turn on the group execute bit of the lock file to disable queuing and
539 * turn on the owner execute bit of the lock file to disable printing.
542 if (stat(line
, &stbuf
) >= 0) {
543 if (chmod(line
, (stbuf
.st_mode
& 0777) | 0110) < 0)
544 printf("\tcannot disable queuing\n");
546 printf("\tprinter and queuing disabled\n");
547 } else if (errno
== ENOENT
) {
548 if ((fd
= open(line
, O_WRONLY
|O_CREAT
, 0770)) < 0)
549 printf("\tcannot create lock file\n");
552 printf("\tprinter and queuing disabled\n");
557 printf("\tcannot stat lock file\n");
559 * Write the message into the status file.
561 (void)snprintf(line
, sizeof(line
), "%s/%s", SD
, ST
);
562 fd
= open(line
, O_WRONLY
|O_CREAT
, 0664);
563 if (fd
< 0 || flock(fd
, LOCK_EX
) < 0) {
564 printf("\tcannot create status file\n");
569 (void)ftruncate(fd
, 0);
571 (void)write(fd
, "\n", 1);
576 while (--argc
>= 0) {
578 while ((size_t)(cp1
- buf
) < sizeof(buf
) && (*cp1
++ = *cp2
++))
584 (void)write(fd
, buf
, strlen(buf
));
592 quit(int argc
, char *argv
[])
598 * Kill and restart the daemon.
601 restart(int argc
, char *argv
[])
608 printf("Usage: restart {all | printer ...}\n");
611 if (argc
== 2 && !strcmp(argv
[1], "all")) {
613 while (cgetnext(&bp
, printcapdb
) > 0) {
616 while ((c
= *cp2
++) && c
!= '|' && c
!= ':' &&
617 (size_t)(cp1
- prbuf
) < sizeof(prbuf
))
635 * Enable printing on the specified printer and startup the daemon.
638 startcmd(int argc
, char *argv
[])
645 printf("Usage: start {all | printer ...}\n");
648 if (argc
== 2 && !strcmp(argv
[1], "all")) {
650 while (cgetnext(&bp
, printcapdb
) > 0) {
653 while ((c
= *cp2
++) && c
!= '|' && c
!= ':' &&
654 (size_t)(cp1
- prbuf
) < sizeof(prbuf
))
675 printf("%s:\n", printer
);
678 * Turn off the owner execute bit of the lock file to enable printing.
681 if (ena
&& stat(line
, &stbuf
) >= 0) {
682 if (chmod(line
, stbuf
.st_mode
& (ena
== 2 ? 0666 : 0677)) < 0)
683 printf("\tcannot enable printing\n");
685 printf("\tprinting enabled\n");
687 if (!startdaemon(printer
))
688 printf("\tcouldn't start daemon\n");
690 printf("\tdaemon started\n");
695 * Print the status of each queue listed or all the queues.
698 status(int argc
, char *argv
[])
704 if (argc
== 1 || (argc
== 2 && strcmp(argv
[1], "all") == 0)) {
706 while (cgetnext(&bp
, printcapdb
) > 0) {
709 while ((c
= *cp2
++) && c
!= '|' && c
!= ':' &&
710 (size_t)(cp1
- prbuf
) < sizeof(prbuf
))
726 * Print the status of the printer queue.
737 printf("%s:\n", printer
);
738 if (stat(line
, &stbuf
) >= 0) {
739 printf("\tqueuing is %s\n",
740 (stbuf
.st_mode
& 010) ? "disabled" : "enabled");
741 printf("\tprinting is %s\n",
742 (stbuf
.st_mode
& 0100) ? "disabled" : "enabled");
744 printf("\tqueuing is enabled\n");
745 printf("\tprinting is enabled\n");
747 if ((dirp
= opendir(SD
)) == NULL
) {
748 printf("\tcannot examine spool directory\n");
752 while ((dp
= readdir(dirp
)) != NULL
) {
753 if (*dp
->d_name
== 'c' && dp
->d_name
[1] == 'f')
758 printf("\tno entries\n");
760 printf("\t1 entry in spool area\n");
762 printf("\t%d entries in spool area\n", i
);
763 fd
= open(line
, O_RDONLY
);
764 if (fd
< 0 || flock(fd
, LOCK_SH
|LOCK_NB
) == 0) {
766 (void)close(fd
); /* unlocks as well */
767 printf("\tprinter idle\n");
771 (void)snprintf(line
, sizeof(line
), "%s/%s", SD
, ST
);
772 fd
= open(line
, O_RDONLY
);
774 (void)flock(fd
, LOCK_SH
);
775 (void)fstat(fd
, &stbuf
);
776 if (stbuf
.st_size
> 0) {
778 while ((i
= read(fd
, line
, sizeof(line
))) > 0)
779 (void)fwrite(line
, 1, i
, stdout
);
781 (void)close(fd
); /* unlocks as well */
786 * Stop the specified daemon after completing the current job and disable
790 stop(int argc
, char *argv
[])
797 printf("Usage: stop {all | printer ...}\n");
800 if (argc
== 2 && !strcmp(argv
[1], "all")) {
802 while (cgetnext(&bp
, printcapdb
) > 0) {
805 while ((c
= *cp2
++) && c
!= '|' && c
!= ':' &&
806 (size_t)(cp1
- prbuf
) < sizeof(prbuf
))
828 printf("%s:\n", printer
);
831 * Turn on the owner execute bit of the lock file to disable printing.
834 if (stat(line
, &stbuf
) >= 0) {
835 if (chmod(line
, (stbuf
.st_mode
& 0777) | 0100) < 0)
836 printf("\tcannot disable printing\n");
838 upstat("printing disabled\n");
839 printf("\tprinting disabled\n");
841 } else if (errno
== ENOENT
) {
842 if ((fd
= open(line
, O_WRONLY
|O_CREAT
, 0760)) < 0)
843 printf("\tcannot create lock file\n");
846 upstat("printing disabled\n");
847 printf("\tprinting disabled\n");
850 printf("\tcannot stat lock file\n");
854 struct queue
**queue
;
859 * Put the specified jobs at the top of printer queue.
862 topq(int argc
, char *argv
[])
869 printf("Usage: topq printer [jobnum ...] [user ...]\n");
879 printf("%s:\n", printer
);
883 printf("\tcannot chdir to %s\n", SD
);
887 nitems
= getq(&queue
);
891 mtime
= queue
[0]->q_time
;
892 for (i
= argc
; --i
; ) {
893 if (doarg(argv
[i
]) == 0) {
894 printf("\tjob %s is not in the queue\n", argv
[i
]);
899 for (i
= 0; i
< nitems
; i
++)
903 printf("\tqueue order unchanged\n");
907 * Turn on the public execute bit of the lock file to
908 * get lpd to rebuild the queue after the current job.
911 if (changed
&& stat(LO
, &stbuf
) >= 0)
912 (void)chmod(LO
, (stbuf
.st_mode
& 0777) | 01);
919 * Reposition the job by changing the modification time of
923 touch(struct queue
*q
)
925 struct timeval tvp
[2];
928 tvp
[0].tv_sec
= tvp
[1].tv_sec
= --mtime
;
929 tvp
[0].tv_usec
= tvp
[1].tv_usec
= 0;
931 ret
= utimes(q
->q_name
, tvp
);
937 * Checks if specified job name is in the printer's queue.
938 * Returns: negative (-1) if argument name is not in the queue.
941 doarg(const char *job
)
951 * Look for a job item consisting of system name, colon, number
952 * (example: ucbarpa:114)
954 if ((cp
= strchr(job
, ':')) != NULL
) {
962 * Check for job specified by number (example: 112 or 235ucbarpa).
964 if (isdigit((unsigned char)*job
)) {
967 jobnum
= jobnum
* 10 + (*job
++ - '0');
968 while (isdigit((unsigned char)*job
));
969 for (qq
= queue
+ nitems
; --qq
>= queue
; ) {
971 for (cp
= (*qq
)->q_name
+3; isdigit((unsigned char)*cp
); )
972 n
= n
* 10 + (*cp
++ - '0');
975 if (*job
&& strcmp(job
, cp
) != 0)
977 if (machine
!= NULL
&& strcmp(machine
, cp
) != 0)
979 if (touch(*qq
) == 0) {
980 printf("\tmoved %s\n", (*qq
)->q_name
);
987 * Process item consisting of owner's name (example: henry).
989 for (qq
= queue
+ nitems
; --qq
>= queue
; ) {
991 fp
= fopen((*qq
)->q_name
, "r");
995 while (get_line(fp
) > 0)
999 if (line
[0] != 'P' || strcmp(job
, line
+1) != 0)
1001 if (touch(*qq
) == 0) {
1002 printf("\tmoved %s\n", (*qq
)->q_name
);
1010 * Enable everything and start printer (undo `down').
1013 up(int argc
, char *argv
[])
1020 printf("Usage: up {all | printer ...}\n");
1023 if (argc
== 2 && !strcmp(argv
[1], "all")) {
1025 while (cgetnext(&bp
, printcapdb
) > 0) {
1028 while ((c
= *cp2
++) && c
!= '|' && c
!= ':' &&
1029 (size_t)(cp1
- prbuf
) < sizeof(prbuf
))