* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char copyright
[] =
"@(#) Copyright (c) 1983, 1993\n\
The Regents of the University of California. All rights reserved.\n";
static char sccsid
[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95";
* lpc -- line printer control program -- commands:
static void abortpr
__P((int));
static void cleanpr
__P((void));
static void disablepr
__P((void));
static int doarg
__P((char *));
static int doselect
__P((struct dirent
*));
static void enablepr
__P((void));
static void prstat
__P((void));
static void putmsg
__P((int, char **));
static int sortq
__P((const void *, const void *));
static void startpr
__P((int));
static void stoppr
__P((void));
static int touch
__P((struct queue
*));
static void unlinkf
__P((char *));
static void upstat
__P((char *));
* kill an existing daemon and disable printing.
register char *cp1
, *cp2
;
printf("Usage: abort {all | printer ...}\n");
if (argc
== 2 && !strcmp(argv
[1], "all")) {
while (cgetnext(&bp
, printcapdb
) > 0) {
while ((c
= *cp2
++) && c
!= '|' && c
!= ':')
if ((status
= cgetent(&bp
, printcapdb
, printer
)) == -2) {
printf("cannot open printer description file\n");
} else if (status
== -1) {
printf("unknown printer %s\n", printer
);
fatal("potential reference loop detected in printcap file");
if (cgetstr(bp
, "sd", &SD
) == -1)
if (cgetstr(bp
, "lo", &LO
) == -1)
(void) sprintf(line
, "%s/%s", SD
, LO
);
printf("%s:\n", printer
);
* Turn on the owner execute bit of the lock file to disable printing.
if (stat(line
, &stbuf
) >= 0) {
if (chmod(line
, (stbuf
.st_mode
& 0777) | 0100) < 0)
printf("\tcannot disable printing\n");
upstat("printing disabled\n");
printf("\tprinting disabled\n");
} else if (errno
== ENOENT
) {
if ((fd
= open(line
, O_WRONLY
|O_CREAT
, 0760)) < 0)
printf("\tcannot create lock file\n");
upstat("printing disabled\n");
printf("\tprinting disabled\n");
printf("\tno daemon to abort\n");
printf("\tcannot stat lock file\n");
* Kill the current daemon to stop printing now.
if ((fp
= fopen(line
, "r")) == NULL
) {
printf("\tcannot open lock file\n");
if (!getline(fp
) || flock(fileno(fp
), LOCK_SH
|LOCK_NB
) == 0) {
(void) fclose(fp
); /* unlocks as well */
printf("\tno daemon to abort\n");
if (kill(pid
= atoi(line
), SIGTERM
) < 0)
printf("\tWarning: daemon (pid %d) not killed\n", pid
);
printf("\tdaemon (pid %d) killed\n", pid
);
* Write a message into the status file.
if (cgetstr(bp
, "st", &ST
) == -1)
(void) sprintf(statfile
, "%s/%s", SD
, ST
);
fd
= open(statfile
, O_WRONLY
|O_CREAT
, 0664);
if (fd
< 0 || flock(fd
, LOCK_EX
) < 0) {
printf("\tcannot create status file\n");
(void) write(fd
, "\n", 1);
(void) write(fd
, msg
, strlen(msg
));
* Remove all spool files and temporaries from the spooling area.
register char *cp1
, *cp2
;
printf("Usage: clean {all | printer ...}\n");
if (argc
== 2 && !strcmp(argv
[1], "all")) {
while (cgetnext(&bp
, printcapdb
) > 0) {
while ((c
= *cp2
++) && c
!= '|' && c
!= ':')
if ((status
= cgetent(&bp
, printcapdb
, printer
)) == -2) {
printf("cannot open printer description file\n");
} else if (status
== -1) {
printf("unknown printer %s\n", printer
);
fatal("potential reference loop detected in printcap file");
if ((c
== 't' || c
== 'c' || c
== 'd') && d
->d_name
[1] == 'f')
* Comparison routine for scandir. Sort by job number and machine, then
* by `cf', `tf', or `df', then by the sequence letter A-Z, a-z.
struct dirent
**d1
, **d2
;
d1
= (struct dirent
**)a
;
d2
= (struct dirent
**)b
;
if (c1
= strcmp((*d1
)->d_name
+ 3, (*d2
)->d_name
+ 3))
return((*d1
)->d_name
[2] - (*d2
)->d_name
[2]);
if (c1
== 'd' || c2
== 'c')
* Remove incomplete jobs from spooling area.
register char *cp
, *cp1
, *lp
;
if (cgetstr(bp
, "sd", &SD
) == -1)
printf("%s:\n", printer
);
for (lp
= line
, cp
= SD
; *lp
++ = *cp
++; )
nitems
= scandir(SD
, &queue
, doselect
, sortq
);
printf("\tcannot examine spool directory\n");
cp1
= queue
[i
+ 1]->d_name
;
if (*cp1
!= 'd' || strcmp(cp
+ 3, cp1
+ 3))
* Must be a df with no cf (otherwise, it would have
* been skipped above) or a tf file (which can always
printf("\tcannot remove %s\n", name
);
printf("\tremoved %s\n", name
);
* Enable queuing to the printer (allow lpr's).
register char *cp1
, *cp2
;
printf("Usage: enable {all | printer ...}\n");
if (argc
== 2 && !strcmp(argv
[1], "all")) {
while (cgetnext(&bp
, printcapdb
) > 0) {
while ((c
= *cp2
++) && c
!= '|' && c
!= ':')
if ((status
= cgetent(&bp
, printcapdb
, printer
)) == -2) {
printf("cannot open printer description file\n");
} else if (status
== -1) {
printf("unknown printer %s\n", printer
);
fatal("potential reference loop detected in printcap file");
if (cgetstr(bp
, "sd", &SD
) == -1)
if (cgetstr(bp
, "lo", &LO
) == -1)
(void) sprintf(line
, "%s/%s", SD
, LO
);
printf("%s:\n", printer
);
* Turn off the group execute bit of the lock file to enable queuing.
if (stat(line
, &stbuf
) >= 0) {
if (chmod(line
, stbuf
.st_mode
& 0767) < 0)
printf("\tcannot enable queuing\n");
printf("\tqueuing enabled\n");
register char *cp1
, *cp2
;
printf("Usage: disable {all | printer ...}\n");
if (argc
== 2 && !strcmp(argv
[1], "all")) {
while (cgetnext(&bp
, printcapdb
) > 0) {
while ((c
= *cp2
++) && c
!= '|' && c
!= ':')
if ((status
= cgetent(&bp
, printcapdb
, printer
)) == -2) {
printf("cannot open printer description file\n");
} else if (status
== -1) {
printf("unknown printer %s\n", printer
);
fatal("potential reference loop detected in printcap file");
if (cgetstr(bp
, "sd", &SD
) == -1)
if (cgetstr(bp
, "lo", &LO
) == -1)
(void) sprintf(line
, "%s/%s", SD
, LO
);
printf("%s:\n", printer
);
* Turn on the group execute bit of the lock file to disable queuing.
if (stat(line
, &stbuf
) >= 0) {
if (chmod(line
, (stbuf
.st_mode
& 0777) | 010) < 0)
printf("\tcannot disable queuing\n");
printf("\tqueuing disabled\n");
} else if (errno
== ENOENT
) {
if ((fd
= open(line
, O_WRONLY
|O_CREAT
, 0670)) < 0)
printf("\tcannot create lock file\n");
printf("\tqueuing disabled\n");
printf("\tcannot stat lock file\n");
* Disable queuing and printing and put a message into the status file
* (reason for being down).
register char *cp1
, *cp2
;
printf("Usage: down {all | printer} [message ...]\n");
if (!strcmp(argv
[1], "all")) {
while (cgetnext(&bp
, printcapdb
) > 0) {
while ((c
= *cp2
++) && c
!= '|' && c
!= ':')
putmsg(argc
- 2, argv
+ 2);
if ((status
= cgetent(&bp
, printcapdb
, printer
)) == -2) {
printf("cannot open printer description file\n");
} else if (status
== -1) {
printf("unknown printer %s\n", printer
);
fatal("potential reference loop detected in printcap file");
putmsg(argc
- 2, argv
+ 2);
register char *cp1
, *cp2
;
if (cgetstr(bp
, "sd", &SD
) == -1)
if (cgetstr(bp
, "lo", &LO
) == -1)
if (cgetstr(bp
, "st", &ST
) == -1)
printf("%s:\n", printer
);
* Turn on the group execute bit of the lock file to disable queuing and
* turn on the owner execute bit of the lock file to disable printing.
(void) sprintf(line
, "%s/%s", SD
, LO
);
if (stat(line
, &stbuf
) >= 0) {
if (chmod(line
, (stbuf
.st_mode
& 0777) | 0110) < 0)
printf("\tcannot disable queuing\n");
printf("\tprinter and queuing disabled\n");
} else if (errno
== ENOENT
) {
if ((fd
= open(line
, O_WRONLY
|O_CREAT
, 0770)) < 0)
printf("\tcannot create lock file\n");
printf("\tprinter and queuing disabled\n");
printf("\tcannot stat lock file\n");
* Write the message into the status file.
(void) sprintf(line
, "%s/%s", SD
, ST
);
fd
= open(line
, O_WRONLY
|O_CREAT
, 0664);
if (fd
< 0 || flock(fd
, LOCK_EX
) < 0) {
printf("\tcannot create status file\n");
(void) write(fd
, "\n", 1);
(void) write(fd
, buf
, strlen(buf
));
* Kill and restart the daemon.
register char *cp1
, *cp2
;
printf("Usage: restart {all | printer ...}\n");
if (argc
== 2 && !strcmp(argv
[1], "all")) {
while (cgetnext(&bp
, printcapdb
) > 0) {
while ((c
= *cp2
++) && c
!= '|' && c
!= ':')
if ((status
= cgetent(&bp
, printcapdb
, printer
)) == -2) {
printf("cannot open printer description file\n");
} else if (status
== -1) {
printf("unknown printer %s\n", printer
);
fatal("potential reference loop detected in printcap file");
* Enable printing on the specified printer and startup the daemon.
register char *cp1
, *cp2
;
printf("Usage: start {all | printer ...}\n");
if (argc
== 2 && !strcmp(argv
[1], "all")) {
while (cgetnext(&bp
, printcapdb
) > 0) {
while ((c
= *cp2
++) && c
!= '|' && c
!= ':')
if ((status
= cgetent(&bp
, printcapdb
, printer
)) == -2) {
printf("cannot open printer description file\n");
} else if (status
== -1) {
printf("unknown printer %s\n", printer
);
fatal("potential reference loop detected in printcap file");
if (cgetstr(bp
, "sd", &SD
) == -1)
if (cgetstr(bp
, "lo", &LO
) == -1)
(void) sprintf(line
, "%s/%s", SD
, LO
);
printf("%s:\n", printer
);
* Turn off the owner execute bit of the lock file to enable printing.
if (enable
&& stat(line
, &stbuf
) >= 0) {
if (chmod(line
, stbuf
.st_mode
& (enable
==2 ? 0666 : 0677)) < 0)
printf("\tcannot enable printing\n");
printf("\tprinting enabled\n");
if (!startdaemon(printer
))
printf("\tcouldn't start daemon\n");
printf("\tdaemon started\n");
* Print the status of each queue listed or all the queues.
register char *cp1
, *cp2
;
while (cgetnext(&bp
, printcapdb
) > 0) {
while ((c
= *cp2
++) && c
!= '|' && c
!= ':')
if ((status
= cgetent(&bp
, printcapdb
, printer
)) == -2) {
printf("cannot open printer description file\n");
} else if (status
== -1) {
printf("unknown printer %s\n", printer
);
fatal("potential reference loop detected in printcap file");
* Print the status of the printer queue.
register struct dirent
*dp
;
if (cgetstr(bp
, "sd", &SD
) == -1)
if (cgetstr(bp
, "lo", &LO
) == -1)
if (cgetstr(bp
, "st", &ST
) == -1)
printf("%s:\n", printer
);
(void) sprintf(line
, "%s/%s", SD
, LO
);
if (stat(line
, &stbuf
) >= 0) {
printf("\tqueuing is %s\n",
(stbuf
.st_mode
& 010) ? "disabled" : "enabled");
printf("\tprinting is %s\n",
(stbuf
.st_mode
& 0100) ? "disabled" : "enabled");
printf("\tqueuing is enabled\n");
printf("\tprinting is enabled\n");
if ((dirp
= opendir(SD
)) == NULL
) {
printf("\tcannot examine spool directory\n");
while ((dp
= readdir(dirp
)) != NULL
) {
if (*dp
->d_name
== 'c' && dp
->d_name
[1] == 'f')
printf("\tno entries\n");
printf("\t1 entry in spool area\n");
printf("\t%d entries in spool area\n", i
);
fd
= open(line
, O_RDONLY
);
if (fd
< 0 || flock(fd
, LOCK_SH
|LOCK_NB
) == 0) {
(void) close(fd
); /* unlocks as well */
printf("\tno daemon present\n");
(void) sprintf(line
, "%s/%s", SD
, ST
);
fd
= open(line
, O_RDONLY
);
(void) flock(fd
, LOCK_SH
);
while ((i
= read(fd
, line
, sizeof(line
))) > 0)
(void) fwrite(line
, 1, i
, stdout
);
(void) close(fd
); /* unlocks as well */
* Stop the specified daemon after completing the current job and disable
register char *cp1
, *cp2
;
printf("Usage: stop {all | printer ...}\n");
if (argc
== 2 && !strcmp(argv
[1], "all")) {
while (cgetnext(&bp
, printcapdb
) > 0) {
while ((c
= *cp2
++) && c
!= '|' && c
!= ':')
if ((status
= cgetent(&bp
, printcapdb
, printer
)) == -2) {
printf("cannot open printer description file\n");
} else if (status
== -1) {
printf("unknown printer %s\n", printer
);
fatal("potential reference loop detected in printcap file");
if (cgetstr(bp
, "sd", &SD
) == -1)
if (cgetstr(bp
, "lo", &LO
) == -1)
(void) sprintf(line
, "%s/%s", SD
, LO
);
printf("%s:\n", printer
);
* Turn on the owner execute bit of the lock file to disable printing.
if (stat(line
, &stbuf
) >= 0) {
if (chmod(line
, (stbuf
.st_mode
& 0777) | 0100) < 0)
printf("\tcannot disable printing\n");
upstat("printing disabled\n");
printf("\tprinting disabled\n");
} else if (errno
== ENOENT
) {
if ((fd
= open(line
, O_WRONLY
|O_CREAT
, 0760)) < 0)
printf("\tcannot create lock file\n");
upstat("printing disabled\n");
printf("\tprinting disabled\n");
printf("\tcannot stat lock file\n");
* Put the specified jobs at the top of printer queue.
printf("Usage: topq printer [jobnum ...] [user ...]\n");
status
= cgetent(&bp
, printcapdb
, printer
);
printf("cannot open printer description file\n");
} else if (status
== -1) {
printf("%s: unknown printer\n", printer
);
fatal("potential reference loop detected in printcap file");
if (cgetstr(bp
, "sd", &SD
) == -1)
if (cgetstr(bp
, "lo", &LO
) == -1)
printf("%s:\n", printer
);
printf("\tcannot chdir to %s\n", SD
);
mtime
= queue
[0]->q_time
;
if (doarg(argv
[i
]) == 0) {
printf("\tjob %s is not in the queue\n", argv
[i
]);
for (i
= 0; i
< nitems
; i
++)
printf("\tqueue order unchanged\n");
* Turn on the public execute bit of the lock file to
* get lpd to rebuild the queue after the current job.
if (changed
&& stat(LO
, &stbuf
) >= 0)
(void) chmod(LO
, (stbuf
.st_mode
& 0777) | 01);
* Reposition the job by changing the modification time of
tvp
[0].tv_sec
= tvp
[1].tv_sec
= --mtime
;
tvp
[0].tv_usec
= tvp
[1].tv_usec
= 0;
return(utimes(q
->q_name
, tvp
));
* Checks if specified job name is in the printer's queue.
* Returns: negative (-1) if argument name is not in the queue.
register struct queue
**qq
;
register char *cp
, *machine
;
* Look for a job item consisting of system name, colon, number
if ((cp
= index(job
, ':')) != NULL
) {
* Check for job specified by number (example: 112 or 235ucbarpa).
jobnum
= jobnum
* 10 + (*job
++ - '0');
for (qq
= queue
+ nitems
; --qq
>= queue
; ) {
for (cp
= (*qq
)->q_name
+3; isdigit(*cp
); )
n
= n
* 10 + (*cp
++ - '0');
if (*job
&& strcmp(job
, cp
) != 0)
if (machine
!= NULL
&& strcmp(machine
, cp
) != 0)
printf("\tmoved %s\n", (*qq
)->q_name
);
* Process item consisting of owner's name (example: henry).
for (qq
= queue
+ nitems
; --qq
>= queue
; ) {
if ((fp
= fopen((*qq
)->q_name
, "r")) == NULL
)
if (line
[0] != 'P' || strcmp(job
, line
+1) != 0)
printf("\tmoved %s\n", (*qq
)->q_name
);
* Enable everything and start printer (undo `down').
register char *cp1
, *cp2
;
printf("Usage: up {all | printer ...}\n");
if (argc
== 2 && !strcmp(argv
[1], "all")) {
while (cgetnext(&bp
, printcapdb
) > 0) {
while ((c
= *cp2
++) && c
!= '|' && c
!= ':')
if ((status
= cgetent(&bp
, printcapdb
, printer
)) == -2) {
printf("cannot open printer description file\n");
} else if (status
== -1) {
printf("unknown printer %s\n", printer
);
fatal("potential reference loop detected in printcap file");