sources-request@mirror.UUCP (07/15/86)
Submitted by: ihnp4!sun!cwruecmp!ncoast!allbery (Brandon S. Allbery) Mod.sources: Volume 6, Issue 55 Archive-name: S3uuque [ I edited Brandon's cover note into two manpages. I also threw together the quickie Makefile. The shar file below has two different styles, one for my stuff, one for his. I didn't repack it into one because I liked the renaming feature of his. Note that also included in here is a version of the directory-access routines. -r$ ] I got an overwhelming response to my announcement of this program. So, it comes full circle back to mod.sources. Uuque has been tested with System III uucp and should work with V7, System III and most System V uucp's. It has not been tested with Honey DanBer uucp, as I don't have access to a system with H/D/B uucp. If you find out that it works, or change it so it does, drop me a letter; our computer company may switch to H/D/B without warning and I'd like to be ready. It does not yet work under the 4.2BSD uucp. I am working on this; the program will dynamically determine whether the structure is ``flat'' or arranged in directories and act accordingly. I'll send the new version to mod.sources when it's done. It uses getopt, available from the mod.sources archive for non-AT&T UNIX systems. --Brandon --------------------------------- cut here ----------------------------------- #! /bin/sh # # Shell archive created Thu., Jun. 26, 1986 by tdi2!brandon. # Contents: # # -rw-r--r-- 1 brandon system 2625 Jun 9 13:49 dir.c # -rw-rw-rw- 1 brandon system 3164 Jun 9 13:49 dir.h # -rw-r--r-- 1 brandon system 2018 Jun 9 20:47 uukill.c # -rw-r--r-- 1 brandon system 6197 Jun 12 12:29 uuque.c # # You may unpack this archive with sh or ksh, but not csh. # if test -r "dir.c"; then echo "File dir.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="dir.c" esac else newname="dir.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:dir.c--' > "$newname" X/* X * X * N O T I C E X * X * This file is NOT a copyrighted part of the UNaXcess distribution. These X * are directory-reading routines which are compatible with the Berkeley Unix X * (4.2BSD, 4.3BSD) directory routines. They come from the Usenet news X * distribution and are in the public domain. X * X * To get the best use of them: install the file "dir.h" in /usr/include X * -- standard usage calls it "ndir.h", and make a random archive of dir.o and X * put it in /usr/lib/libndir.a . It is then available with "-lndir". X * X * Bell System {III, V} sites, just make an archive -- it is only one file X * anyway. Other sites will have to run ranlib on the archive to keep ld X * happy. X */ X X#include <sys/types.h> X#include "dir.h" X X#ifndef BSD X X/* X * close a directory. X */ Xclosedir(dirp) X register DIR *dirp; X{ X close(dirp->dd_fd); X dirp->dd_fd = -1; X dirp->dd_loc = 0; X free(dirp); X} X X X X/* X * open a directory. X */ XDIR * Xopendir(name) X char *name; X{ X register DIR *dirp; X register int fd; X X if ((fd = open(name, 0)) == -1) X return NULL; X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { X close (fd); X return NULL; X } X dirp->dd_fd = fd; X dirp->dd_loc = 0; X return dirp; X} X X X X/* X * read an old style directory entry and present it as a new one X */ X#define ODIRSIZ 14 X Xstruct olddirect { X ino_t od_ino; X char od_name[ODIRSIZ]; X}; X X/* X * get next entry in a directory. X */ Xstruct direct * Xreaddir(dirp) X register DIR *dirp; X{ X register struct olddirect *dp; X static struct direct dir; X X for (;;) { X if (dirp->dd_loc == 0) { X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, X DIRBLKSIZ); X if (dirp->dd_size <= 0) X return NULL; X } X if (dirp->dd_loc >= dirp->dd_size) { X dirp->dd_loc = 0; X continue; X } X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc); X dirp->dd_loc += sizeof(struct olddirect); X if (dp->od_ino == 0) X continue; X dir.d_ino = dp->od_ino; X strncpy(dir.d_name, dp->od_name, ODIRSIZ); X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */ X dir.d_namlen = strlen(dir.d_name); X dir.d_reclen = DIRBLKSIZ; X return (&dir); X } X} X X#endif BSD --EOF:dir.c-- fi if test -r "dir.h"; then echo "File dir.h exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="dir.h" esac else newname="dir.h" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:dir.h--' > "$newname" X/* X * X * N O T I C E X * X * This file is NOT a copyrighted part of the UNaXcess distribution. These X * are directory-reading routines which are compatible with the Berkeley Unix X * (4.2BSD, 4.3BSD) directory routines. They come from the Usenet news X * distribution and are in the public domain. X * X * To get the best use of them: install the file "dir.h" in /usr/include X * -- standard usage calls it "ndir.h", and make a random archive of dir.o and X * put it in /usr/lib/libndir.a . It is then available with "-lndir". X * X * Bell System {III, V} sites, just make an archive -- it is only one file X * anyway. Other sites will have to run ranlib on the archive to keep ld X * happy. X */ X X/* dir.h 4.4 82/07/25 */ X X#ifdef BSD X#include <sys/dir.h> X#else X X/* X * A directory consists of some number of blocks of DIRBLKSIZ X * bytes, where DIRBLKSIZ is chosen such that it can be transferred X * to disk in a single atomic operation (e.g. 512 bytes on most machines). X * X * Each DIRBLKSIZ byte block contains some number of directory entry X * structures, which are of variable length. Each directory entry has X * a struct direct at the front of it, containing its inode number, X * the length of the entry, and the length of the name contained in X * the entry. These are followed by the name padded to a 4 byte boundary X * with null bytes. All names are guaranteed null terminated. X * The maximum length of a name in a directory is MAXNAMLEN. X * X * The macro DIRSIZ(dp) gives the amount of space required to represent X * a directory entry. Free space in a directory is represented by X * entries which have dp->d_reclen >= DIRSIZ(dp). All DIRBLKSIZ bytes X * in a directory block are claimed by the directory entries. This X * usually results in the last entry in a directory having a large X * dp->d_reclen. When entries are deleted from a directory, the X * space is returned to the previous entry in the same directory X * block by increasing its dp->d_reclen. If the first entry of X * a directory block is free, then its dp->d_ino is set to 0. X * Entries other than the first in a directory do not normally have X * dp->d_ino set to 0. X */ X#define DIRBLKSIZ 512 X#define MAXNAMLEN 255 X Xstruct direct { X long d_ino; /* inode number of entry */ X short d_reclen; /* length of this record */ X short d_namlen; /* length of string in d_name */ X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ X}; X X/* X * The DIRSIZ macro gives the minimum record length which will hold X * the directory entry. This requires the amount of space in struct direct X * without the d_name field, plus enough space for the name with a terminating X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. X */ X#ifdef DIRSIZ X#undef DIRSIZ X#endif X#define DIRSIZ(dp) \ X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) X X#ifndef KERNEL X/* X * Definitions for library routines operating on directories. X */ Xtypedef struct _dirdesc { X int dd_fd; X long dd_loc; X long dd_size; X char dd_buf[DIRBLKSIZ]; X} DIR; X#ifndef NULL X#define NULL 0 X#endif Xextern DIR *opendir(); Xextern struct direct *readdir(); Xextern closedir(); X#endif KERNEL X X#endif BSD --EOF:dir.h-- fi if test -r "uukill.c"; then echo "File uukill.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="uukill.c" esac else newname="uukill.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:uukill.c--' > "$newname" X/* X * uukill X * uucp job killer X * s3 version (in C) by Brandon Allbery X */ X X#include <stdio.h> X#include "dir.h" X Xmain(argc, argv) Xchar **argv; { X int fndjob, jkstat; X X if (argc < 2) { X fprintf(stderr, "usage: uukill job ...\n"); X exit(1); X } X if (chdir("/usr/spool/uucp") < 0) { X perror("/usr/spool/uucp"); X exit(3); X } X fndjob = 0; X for (argc--, argv++; argc > 0; argc--, argv++) X switch (uukill(*argv)) { X case -1: X fndjob = 2; X break; X case 0: X fprintf(stderr, "uukill: no such job: %s\n", *argv); X if (fndjob < 2) X fndjob = 1; X continue; X } X exit(fndjob); X} X Xuukill(jobid) Xchar *jobid; { X DIR *spool; X struct direct *job; X char jid[8]; X int cnt; X X if ((spool = opendir(".")) == NULL) { X perror("uukill: cannot open spool directory"); X exit(3); X } X while ((job = readdir(spool)) != NULL) { X if (job->d_name[0] != 'C' || job->d_name[1] != '.') X continue; X strcpy(jid, &job->d_name[strlen(job->d_name) - 4]); X if (strcmp(jobid, jid) != 0) X continue; X return koutq(job, jid); X } X closedir(spool); X return 0; X} X Xkoutq(job, jid) Xchar *jid; Xstruct direct *job; { X FILE *jfile; X char cmd[2], xline[512], xtmp[128], otmp[128], utmp[18]; X X if ((jfile = fopen(job->d_name, "r")) < 0) { X fprintf(stderr, "uukill: cannot kill %s: ", jid); X perror(""); X return -1; X } X while (fgets(xline, sizeof xline, jfile) != NULL) { X sscanf(xline, "%s %s %s %s", cmd, xtmp, otmp, utmp); X switch (cmd[0]) { X case 'S': X if (!okkill(utmp)) { X fprintf(stderr, "uukill: job %s, permission denied\n", jid); X return 0; X } X if (xtmp[0] == 'D' && xtmp[1] == '.') X if (unlink(xtmp) < 0) X return 0; X break; X case 'R': X if (!okkill(utmp)) { X fprintf(stderr, "uukill: job %s, permission denied\n", jid); X return 0; X } X default: X fprintf(stderr, "uukill: invalid cmd %s: %s", job->d_name, xline); X return 0; X } X } X return unlink(job->d_name) == 0; X} X Xokkill(uid) Xchar *uid; { X if (getuid() == 0) X return 1; X return strcmp(uid, cuserid(NULL)) == 0; X} --EOF:uukill.c-- fi if test -r "uuque.c"; then echo "File uuque.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="uuque.c" esac else newname="uuque.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:uuque.c--' > "$newname" X/* X * uuque.c X * uucp queue lister X * s3 version (in C) by Brandon Allbery X */ X X#include <stdio.h> X#include <sys/utsname.h> X#include <sys/types.h> X#include <sys/stat.h> X#include "dir.h" X Xstruct utsname luuname; Xchar qsys[8], jobsys[8], jid[8]; Xint verbose, jobnames, jobs; X Xlong uuque(), outq(); X Xmain(argc, argv) Xchar **argv; { X extern int optind; X extern char *optarg; X char optch; X long total; X X verbose = 0; X jobnames = 0; X jobs = 0; X while ((optch = getopt(argc, argv, "vs:j")) != EOF) X switch (optch) { X case 'v': X verbose = !verbose; X break; X case 'j': X jobnames = !jobnames; X break; X case 's': X strncpy(qsys, optarg, 7); X qsys[7] = '\0'; X break; X case '?': X exit(1); X } X if (argv[optind] != NULL) { X fprintf(stderr, "Usage: uuque [-v] [-j] [-ssystem]\n"); X exit(1); X } X uname(&luuname); X if (chdir("/usr/spool/uucp") < 0) { X perror("/usr/spool/uucp"); X exit(2); X } X total = uuque('C'); /* print send queue */ X uuque('X'); /* print rcv queue */ X if (jobs == 0) X printf("No jobs queued.\n"); X else X printf("%s%7ld total for %d jobs\n", (jobnames? " ": ""), total, jobs); X exit(0); X} X Xlong uuque(sr) Xchar sr; { X DIR *spool; X struct direct *job; X int cnt; X long bytes; X X if ((spool = opendir(".")) == NULL) { X fprintf(stderr, "uuque: cannot open spool directory\n"); X exit(2); X } X bytes = 0; X while ((job = readdir(spool)) != NULL) { X if (job->d_name[0] != sr || job->d_name[1] != '.') X continue; X for (cnt = 2; cnt < strlen(job->d_name) - 5; cnt++) X jobsys[cnt - 2] = job->d_name[cnt]; X jobsys[cnt - 2] = '\0'; X strcpy(jid, &job->d_name[strlen(job->d_name) - 4]); X if (qsys[0] != '\0' && strcmp(jobsys, qsys) != 0) X continue; X if (jobs++ == 0) X printf("%s SIZE JOB\n", (jobnames? "ID ": "")); X if (sr == 'C') X bytes += outq(job); X else X inq(job); X } X closedir(spool); X return bytes; X} X Xlong outq(job) Xstruct direct *job; { X FILE *jfile, *cfile; X char cmd[2], xline[512], xfile[15], dfile[15], xtmp[128], dtmp[15], otmp[128], utmp[18], from[128], ftmp[150]; X struct stat statbuf; X int pj; X long tsize; X X if ((jfile = fopen(job->d_name, "r")) < 0) X return 0; X xfile[0] = '\0'; X dfile[0] = '\0'; X pj = 0; X tsize = 0; X while (fgets(xline, sizeof xline, jfile) != NULL) { X sscanf(xline, "%s %s %s %s", cmd, xtmp, otmp, utmp); X switch (cmd[0]) { X case 'S': X sprintf(dtmp, "D.%.7sX", luuname.nodename); X if (strncmp(xtmp, dtmp, strlen(dtmp)) == 0) X strcpy(xfile, xtmp); X else if (xtmp[0] == 'D' && xtmp[1] == '.') X strcpy(dfile, xtmp); X else { X stat(xtmp, &statbuf); X printf("%s%s%7ld uucp %s %s!%s (%s)\n", (jobnames? (pj? " ": jid): ""), (jobnames? " ": ""), statbuf.st_size, xtmp, jobsys, otmp, utmp); X tsize += statbuf.st_size; X pj++; X } X break; X case 'R': X printf("%s%s uucp %s!%s %s (%s)\n", (jobnames? (pj? " ": jid): ""), (jobnames? " ": ""), jobsys, xtmp, otmp, utmp); X pj++; X break; X default: X fprintf(stderr, "uuque: invalid cmd %s: %s", job->d_name, xline); X } X } X fclose(jfile); X if (xfile[0] == '\0') X return tsize; X if ((jfile = fopen(xfile, "r")) == NULL) X return tsize; X from[0] = '\0'; X while (fgets(xline, sizeof xline, jfile) != NULL) { X sscanf(xline, "%s %s %s %s", cmd, xtmp, otmp, utmp); X switch (cmd[0]) { X case 'U': X sprintf(from, "%s!%s", otmp, xtmp); X break; X case 'F': X case 'I': X case 'Z': X break; X case 'C': X stat(dfile, &statbuf); X if (strcmp(xtmp, "rmail") == 0) { X if ((cfile = fopen(dfile, "r")) != NULL) { X fgets(ftmp, sizeof ftmp, cfile); X fclose(cfile); X sscanf(ftmp, "From %s ", from); X } X } X printf("%s%s%7ld %s %s!%s (%s)\n", (jobnames? (pj? " ": jid): ""), (jobnames? " ": ""), statbuf.st_size, xtmp, jobsys, otmp, from); X if (verbose && (strcmp(xtmp, "rmail") == 0 || strcmp(xtmp, "rnews") == 0) && (cfile = fopen(dfile, "r")) != NULL) { X while (fgets(xline, sizeof xline, cfile) != NULL) { X if (strncmp(xline, "Subject: ", 9) == 0) X printf("%s %s", (jobnames? " ": ""), xline); X else if (strncmp(xline, "Newsgroups: ", 12) == 0) X printf("%s %s", (jobnames? "": " "), xline); X else if (xline[0] == '\n') X break; X } X fclose(cfile); X } X return statbuf.st_size; X default: X fprintf(stderr, "uuque: invalid command %s: %s", xfile, xline); X } X } X} X Xinq(job) Xstruct direct *job; { X FILE *jfile, *cfile; X char xline[512], cmd[2], utmp[50], stmp[50], from[128], dtmp[50], dfile[50], ftmp[150], xargs[100]; X int isxqt; X struct stat statbuf; X int pj; X X pj = 0; X isxqt = 0; X if ((jfile = fopen(job->d_name, "r")) == NULL) X return; X while (fgets(xline, sizeof xline, jfile) != NULL) { X xargs[0] = '\0'; X sscanf(xline, "%s %s %s %[^\n]", cmd, utmp, stmp, xargs); X switch (cmd[0]) { X case 'U': X sprintf(from, "%s!%s", stmp, utmp); X break; X case 'Z': X case 'I': X break; X case 'F': X if (stat(utmp, &statbuf) == 0) X strcpy(dfile, utmp); X else { X sprintf(dtmp, "/usr/lib/uucp/.XQTDIR/%s", stmp); X if (stat(dtmp, &statbuf) == 0) { X strcpy(dfile, dtmp); X isxqt = 1; X } X else X return; X } X break; X case 'C': X if (strcmp(utmp, "rmail") == 0) X if ((cfile = fopen(dfile, "r")) != NULL) { X fgets(ftmp, sizeof ftmp, cfile); X fclose(cfile); X sscanf(ftmp, "From %s ", from); X } X stat(dfile, &statbuf); X printf("%s%s%7ld%s %s%s%s%s\n", (jobnames? (pj? " ": jid): ""), (jobnames? " ": ""), statbuf.st_size, utmp, (xargs[0] == '\0'? "": " "), (xargs[0] == '\0'? "": xargs), (isxqt? " [Executing]": "")); X if (verbose && (strcmp(utmp, "rmail") == 0 || strcmp(utmp, "rnews") == 0) && (cfile = fopen(dfile, "r")) != NULL) { X while (fgets(xline, sizeof xline, cfile) != NULL) { X if (strncmp(xline, "Subject: ", 9) == 0) X printf("%s %s", (jobnames? " ": ""), xline); X else if (strncmp(xline, "Newsgroups: ", 12) == 0) X printf("%s %s", (jobnames? " ": ""), xline); X else if (xline[0] == '\n') X break; X } X fclose(cfile); X } X return; X default: X fprintf(stderr, "uuque: bad cmd in %s: %s", job->d_name, xline); X } X } X} --EOF:uuque.c-- fi echo x - Makefile sed 's/^XX//' > "Makefile" <<'@//E*O*F Makefile//' XXCFLAGS=-O XXall: uukill uuque XXdir.o uukill.o uuque.o: dir.h XXuukill: dir.o uukill.o XX cc $(CFLAGS) -o uukill uukill.o dir.o XXuuque: dir.o uuque.o XX cc $(CFLAGS) -o uuque uuque.o dir.o @//E*O*F Makefile// chmod u=rw,g=rw,o=rw Makefile echo x - uukill.1 sed 's/^XX//' > "uukill.1" <<'@//E*O*F uukill.1//' XX.TH UUKILL 1 LOCAL XX.SH NAME XXuukill \- remove job from UUCP queue XX.SH SYNOPSIS XX.B uukill XX.I jobid XX.SH DESCRIPTION XX.I Uukill XXtakes a job ID displayed by the XX.IR uuque (1L) XXprogram and removes the spool files for that job. XXYou must not only have read/write access in the UUCP spool directory, XXbut only the superuser or the owner of a job can kill the job. XXIt has been tested with SystemIII UUCP, and should work with V7, SystemIII XXand some System V UUCP's. XXIt has not been tested with Honey DanBer UUCP. XXIt does not yet work under the 4.2BSD UUCP, although this is being XXworked on; the program will dynamically determine whether the structure XXis ``flat'' or arranged in directories and act accordingly. XX.SH BUGS XXShould be more secure so that it can run setuid. @//E*O*F uukill.1// chmod u=rw,g=rw,o=rw uukill.1 echo x - uuque.1 sed 's/^XX//' > "uuque.1" <<'@//E*O*F uuque.1//' XX.TH UUQUE 1 LOCAL XX.SH NAME XXuuque \- Show uucp job queue XX.SH SYNOPSIS XX.B uuque XX[ XX.I \-j XX] [ XX.I \-v XX] [ XX.IR \-s site XX] XX.SH DESCRIPTION XX.I Uuque XXis a program to print out status information about the UUCP queues for XXthe indicated site. XXIt has been tested with SystemIII UUCP, and should work with V7, SystemIII XXand some System V UUCP's. XXIt has not been tested with Honey DanBer UUCP. XXIt does not yet work under the 4.2BSD UUCP, although this is being XXworked on; the program will dynamically determine whether the structure XXis ``flat'' or arranged in directories and act accordingly. XX.PP XXThe program displays the jobs spooled for the indicated site, their size, XXand a total size of all the jobs. XXTwo flags may be specified to get additional output: XX.TP \-j XXPrint the job ID's with each job. XX.TP \-v XXPrint the subjects and newsgroups of news and/or mail messages. XX.PP XXYou must have read permission in XX.I /usr/spool/uucp XXfor this program to work. XX.SH BUGS XXOnly one system can be displayed at a time. @//E*O*F uuque.1// chmod u=rw,g=rw,o=rw uuque.1 echo Inspecting for damage in transit... temp=/tmp/sharin$$; dtemp=/tmp/sharout$$ trap "rm -f $temp $dtemp; exit" 0 1 2 3 15 cat > $temp <<\!!! 12 26 183 Makefile 22 139 759 uukill.1 36 184 994 uuque.1 70 349 1936 total !!! wc Makefile uukill.1 uuque.1 | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp if test -s $dtemp then echo "Ouch [diff of wc output]:" ; cat $dtemp else echo "No problems found." fi exit 0