home *** CD-ROM | disk | FTP | other *** search
- /* ta=4 */
- /****************************************************************************
- * a r c n e w s . c *
- * *
- * Archive news files. *
- * *
- * Tony Field (tony@ajfcal) *
- ****************************************************************************/
-
- /* Archive news articles (comp.sources.*). Construct a file name
- based on the "Newsgroups:", "Subject:" and "Archive-name:" headers.
-
- usage arcnews [ -v ] [ file file ...] archive.path
- -v = verbose
-
- input could be from stdin
-
- eg: arcnews /usr/spool/lbgm/[A-Z]* /u/archive
-
- MUST BE SETUID ROOT to work in news forward environment.
- (i.e. chmod 4711 arcnews)
-
- EXIT CODES: 0 = successful operation
- >0 = error of some form has been noted (usually 2)
-
- NOTE: Modify the list of "subject_line_groups[]" for those moderated
- groups that use an archive file name as the first word of the
- Subject: line.
-
- BUGS: maybe arcnews should quit when it finds the first error.
- */
-
- #include <stdio.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- #define NLINES 20 /* number of lines to search for
- Newsgroups:, Subject: Archive-name:
- */
-
- #define IS_FILE 0 /* file type from ftype() */
- #define IS_DIR 1
- #define IS_SPECIAL 2
- #define IS_ERROR -1
-
-
- /* construct the list of groups that use the first word of Subject:
- ~~~~~~~~~~~~~~~~~~~~~~
- */
- char *subject_line_groups[] =
- { "comp.doc",
- "comp.doc.techreports",
- (char *) NULL /* <--- end of list */
- } ;
-
- char *first_lines[NLINES];
- int nlines;
- int nfiles;
- char pgm_name[200];
-
- extern int errno;
- int rc = 0;
-
- main (argc, argv)
- int argc;
- char *argv[];
- { int i, j, c;
- FILE *fp;
- int verbose = 0;
- int nfiles = 0;
- char arc_dir[200];
- extern char *optarg;
- extern int optind;
- char amon[10], alt_fname[50], t[50];
- int day, year, pid;
- unsigned short guid, geuid, getuid(), geteuid(), getegid();
-
-
- strcpy (pgm_name, argv[0]);
- fname_only (pgm_name);
-
- if (argc == 1)
- usage ();
-
- /* we really want to say:
- setuid(geteuid());
- setgid(getegid());
- but Xenix get upset unless getuid() == root
- */
- guid = getuid();
- geuid = geteuid();
- if (guid != geuid)
- {
- setuid(geuid);
- setgid(getegid());
- if (geuid != getuid())
- { fprintf (stderr, "%s: must be setuid root\n", pgm_name);
- exit (1);
- }
- }
-
- while ((c = getopt(argc, argv, "v")) != -1)
- { switch (c)
- {
- case 'v':
- verbose = 1;
- break;
-
- default:
- usage ();
- }
- }
-
- strcpy (arc_dir, argv[--argc]);
-
- if (ftype (arc_dir) != IS_DIR)
- { fprintf (stderr, "%s: %s is not an valid directory\n", pgm_name, arc_dir);
- exit (2);
- }
- if (optind >= argc)
- { /* make a file name as YYMMMDD.PID. eg. 89Jan01.1234 */
- get_time (t);
- sscanf (t, "%*s%s%d%*s%d", amon, &day, &year);
- pid = getpid ();
- sprintf (alt_fname, "%d%s%02d.%d",year % 100, amon, day, pid);
- arc_file (arc_dir, alt_fname, verbose, "stdin");
- }
- else
- { for (i = optind; i < argc; i++)
- { arc_file (arc_dir, argv[i], verbose, NULL);
- }
- }
- exit (rc);
- }
-
-
- /****************************************************************************
- * arc_file() *
- * archive the given file name *
- ****************************************************************************/
-
- arc_file (arc_dir, fn, verbose, alt_fname)
- char *fn; /* name of file to archive */
- char *arc_dir; /* name of archive directory */
- char *alt_fname; /* NULL if file name specified or "stdin" */
- int verbose; /* 1 = display operation, 0 = quiet mode */
- { int i, j, c;
- FILE *fp;
- char line[1000], cline[1000];
- char *words[200];
- int nwords, trc;
- char arc_name[200], archive[200];
- char filename[200], dirname[200], subject[200], group[200];
- int nblanks;
- int have_group, have_subject, have_archive, sub_line;
-
-
- trc = 0;
-
- if (alt_fname == NULL && ftype (fn) != IS_FILE)
- return (-1);
-
- strcpy (archive, fn);
- fname_only (archive);
- if (strcmp (archive, "save.log") == 0) /* ignore save.log */
- return (-1);
-
- if (alt_fname)
- fp = stdin;
- else if ((fp = fopen (fn, "r")) == NULL)
- { rc |= 2;
- return (-1);
- }
-
- archive[0] = '\0';
- *subject = '\0';
- nlines = nblanks = 0;
- have_group = have_subject = have_archive = 0;
- while (nlines < NLINES && fgets (line, 999, fp)) /* get header lines */
- {
- first_lines[nlines] = (char *) malloc (strlen (line) + 1);
- strcpy (first_lines[nlines], line);
- nlines++;
-
- strcpy (cline, line);
- nwords = getwords (cline, words);
- if (nwords)
- { if (strcmp (words[0], "Newsgroups:") == 0)
- { have_group = 1;
- strcpy (archive, arc_dir);
- strcat (archive, "/");
- strcat (archive, words[1]);
- strcpy (group, words[1]);
- }
- else if (strcmp (words[0], "Subject:") == 0)
- { if (nwords >= 2)
- { strcpy (subject, words[1]);
- trim (subject); /* remove ":" */
- have_subject = 1;
- }
- else *subject = '\0';
- }
- else if (strcmp (words[0], "Archive-name:") == 0)
- { have_archive = 1;
- strcpy (arc_name, words[1]);
- }
- }
- else if (++nblanks == 2) /* quit if 2 blank lines */
- break;
- }
-
- if (have_group == 0) /* invalid news file */
- { if (fp != stdin)
- fclose (fp);
- return (-1);
- }
-
- if (have_archive)
- { /* have an Archive-name: header specified.
- sometimes R$alz uses /dev/null for notes.
- if so, use the Subject: line for the file name.
- */
- if (arc_name[0] == '/')
- { if (have_subject && *subject)
- strcpy (arc_name, subject); /* use subject as file name */
- else
- strcpy (arc_name, fn); /* no subject, use original file name */
- fname_only (arc_name);
- }
- }
- else
- { /* subject_line_groups[] get file name from Subject: */
-
- for (j = sub_line = 0; subject_line_groups[j] != NULL; j++)
- { if (sub_line = (strcmp (group, subject_line_groups[j]) == 0))
- break;
- }
- if (sub_line && have_subject && *subject)
- strcpy (arc_name, subject);
- else
- { /* all other groups use original file name */
- strcpy (arc_name, fn);
- fname_only (arc_name);
- }
- }
-
- /* now make the path to the file and actually do a copy */
-
- names (archive, arc_name, filename, dirname);
- if (makepath (dirname) == 0)
- {
- trc = copyfile (fp, filename);
- if (verbose || trc)
- {
- fprintf (stderr, "%s %s -> %s\n", pgm_name, fn, filename);
- if (trc)
- fprintf (stderr, "--------^^^-- copy failed\n");
- }
- rc |= trc;
- nfiles++;
- }
- else
- { fprintf (stderr, "%s: cannot create directory %s\n", pgm_name, dirname);
- rc |= 2;
- trc = 1;
- }
- if (trc)
- { fputs ("---> header of offending file:\n", stderr);
- for (j = 0; j < nlines; j++)
- if (first_lines[j][0] > ' ')
- fprintf (stderr, "\t%s", first_lines[j]);
- else
- break;
- }
- if (fp != stdin)
- fclose (fp);
- for (j = 0; j < nlines; j++)
- free (first_lines[j]);
- return (trc);
- }
-
-
- /****************************************************************************
- * name() *
- * given a archive name and program id, return the full file name and *
- * the path only. *
- ****************************************************************************/
-
- names (archive, arc_name, filename, dirname)
- char *archive; /* in: such as /u/archive/comp.sources.unix */
- char *arc_name; /* in: such as program/part01 */
- char *filename; /* ret: /u/archive/comp/sources/unix/program/part01*/
- char *dirname; /* ret: /u/archive/comp/sources/unix/program */
- { char *c, *strrchr();
-
- strcpy (filename, archive);
- dots (filename); /* change a.b.c to a/b/c */
- strcat (filename, "/");
- strcat (filename, arc_name); /* arc_name may be a path */
-
- strcpy (dirname, filename);
- c = strrchr (dirname, '/');
- *c = '\0';
- }
-
- /****************************************************************************
- * dots() *
- * translate . to / *
- ****************************************************************************/
-
- dots (c)
- char *c;
- {
- while (*c)
- { if (*c == '.')
- *c = '/';
- c++;
- }
- }
-
- /****************************************************************************
- * fname_only () *
- * replace the path with just the file name (right end of the path) *
- ****************************************************************************/
-
- fname_only (fname)
- char *fname;
- { char c[500], *strrchr(), *tc;
-
- if ((tc = strrchr (fname, '/')) != NULL)
- { strcpy (c, tc + 1);
- strcpy (fname, c);
- }
- }
-
- /****************************************************************************
- * getwords () *
- * given a string 's', return pointers in 'words' that point to the *
- * beginning of each word. 's' is modified with null word terminators. *
- * Function return is the number of words found *
- ****************************************************************************/
-
- getwords(s, words)
- char *s; /* string to scan */
- char *words[]; /* vector of words found. */
- { int nwords = 0;
-
- while (*s)
- { if (*s > ' ')
- { words[nwords++] = s;
- while (*s && *s > ' ' && *s != ',')
- s++;
- if (*s == '\0')
- return (nwords);
- *s++ = '\0';
- }
- else
- s++;
- }
- return (nwords);
- }
-
- /****************************************************************************
- * trim() *
- * remove trailing ':' marks. (eg subject:) *
- ****************************************************************************/
-
- trim (s)
- char *s;
- {
- int n;
-
- n = strlen (s);
- if (s[n-1] == ':')
- s[n-1] = '\0';
- }
-
- /****************************************************************************
- * makepath () *
- * for a given path specification, make all directores needed to ensure *
- * that the path is valid. *
- * If the path is valid, then return 0. If the path cannot be made, *
- * then return 2. *
- ****************************************************************************/
-
- makepath (path_name)
- char *path_name;
- { char path[500], p[500], *w[50], cmd[500];
- char *c, *strrchr();
- int i, j, n;
-
- strcpy (path, path_name);
- if ((c = strrchr (path, '/')) == NULL)
- return (-1);
-
- /* if path exists, the return now */
-
- if (access (path, 7) == 0)
- return (0);
-
- /* path does not exist. Start from left side of path and
- build towards the right as necessary
- */
- c = path;
- if (*c != '/') /* get each path directory */
- { n = 0;
- w[n++] = path;
- }
- else
- n = 0;
- while (*c)
- { if (*c == '/')
- { *c++ = '\0';
- w[n++] = c;
- }
- else
- c++;
- }
-
- for (i = 0; i < n; i++) /* try /a, /a/b, /a/b/c, etc. in order */
- { p[0] = '\0';
- if (*path_name == '/')
- strcat (p, "/");
- for (j = 0; j <= i; j++)
- { strcat (p, w[j]);
- if (j == i)
- break;
- strcat (p, "/");
- }
- switch (ftype (p))
- {
- case IS_ERROR:
- if (errno == ENOENT) /* no entry, build it */
- { sprintf (cmd, "mkdir %s", p);
- j = system (cmd);
- chmod (p, 0775);
- rc |= j;
- if (j)
- return (j);
- }
- else
- { rc |= 2;
- return (2);
- }
- break;
-
- case IS_DIR: /* directory already exists, continue*/
- break;
-
- default: /* file with same name. bad. */
- rc |= 2;
- return (2);
- break;
- }
- }
- return (0);
- }
-
- /****************************************************************************
- * copyfile() *
- * If a copy problem happens, return -1, otherwise return 0 *
- ****************************************************************************/
-
- copyfile (fp_in, out_file)
- FILE *fp_in;
- char *out_file;
- {
- FILE *fp_out;
- int r_many, w_many, rc, i;
- char buf[2000];
-
- if ((fp_out = fopen (out_file, "w")) == NULL)
- return (2);
-
- for (i = 0; i < nlines; i++)
- fputs (first_lines[i], fp_out);
-
- rc = 0;
- while (r_many = fread (buf, 1, 2000, fp_in))
- { w_many = fwrite (buf, 1, r_many, fp_out);
- if (w_many != r_many)
- { rc = 2;
- break;
- }
- if (r_many < 2000)
- break;
- }
- fclose (fp_out);
- chmod (out_file, 0664);
-
- #ifdef COMPRESSION
- /* compress the file just received. should use zoo and
- create an library file
- */
- if (rc == 0)
- { sprintf (buf, "/local/bin/compress %s", out_file);
- system (buf);
- }
- #endif
- return (rc);
- }
-
-
- /****************************************************************************
- * ftype (name) *
- * *
- * What is "name"? *
- * 0 = file, 1 = directory, 2 = special file, -1 = error *
- ****************************************************************************/
-
- ftype (name)
- char *name;
- {
- struct stat buf;
-
- if (stat (name, &buf) != 0)
- return (IS_ERROR);
- if ((buf.st_mode & S_IFMT) == S_IFDIR)
- return (IS_DIR);
- if ((buf.st_mode & S_IFMT) == S_IFREG)
- return (IS_FILE);
- return (IS_SPECIAL);
- }
-
-
- /****************************************************************************
- * time_name() *
- ****************************************************************************/
-
- get_time (t)
- char *t;
- {
- long n_time, time ();
- char *x_time, *cc, *strchr(), *ctime();
-
- n_time = time ((long *) 0L); /* get time */
- x_time = (char *) ctime (&n_time); /* convert ascii */
- if ((cc = strchr (x_time, '\n')) != NULL)
- *cc = '\0';
- strcpy (t, x_time);
- }
-
- /****************************************************************************
- * usage() *
- ****************************************************************************/
-
- usage ()
- { fprintf (stderr, "usage: %s [ -v ] [ file file ...] archive.path\n\n", pgm_name);
- fprintf (stderr, "e.g.: %s /usr/spool/lbgm/src/[A-Z]* /u/archive\n\n",pgm_name);
- exit (2);
- }
-