v06i055: uuque for System III/V in C (S3uuque)
sources-request at mirror.UUCP
sources-request at mirror.UUCP
Tue Jul 15 21:54:52 AEST 1986
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
More information about the Mod.sources
mailing list