home *** CD-ROM | disk | FTP | other *** search
- /*
- **
- ** Subsystem: USENET Sources Archiver
- ** File Name: rkive.c
- **
- ** usage: rkive [ -dgstuvV ] [ -f config_file ] [-n newsgroup ]
- **
- **
- ** This software is Copyright (c) 1989 by Kent Landfield.
- **
- ** Permission is hereby granted to copy, distribute or otherwise
- ** use any part of this package as long as you do not try to make
- ** money from it or pretend that you wrote it. This copyright
- ** notice must be maintained in any copy made.
- **
- ** Use of this software constitutes acceptance for use in an AS IS
- ** condition. There are NO warranties with regard to this software.
- ** In no event shall the author be liable for any damages whatsoever
- ** arising out of or in connection with the use or performance of this
- ** software. Any use of this software is at the user's own risk.
- **
- ** If you make modifications to this software that you feel
- ** increases it usefulness for the rest of the community, please
- ** email the changes, enhancements, bug fixes as well as any and
- ** all ideas to me. This software is going to be maintained and
- ** enhanced as deemed necessary by the community.
- **
- ** Kent Landfield
- ** uunet!ssbell!kent
- **
- ** History:
- ** Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
- **
- */
- char sccsid[] = "@(#)rkive.c 1.1 6/1/89";
-
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <dirent.h>
- #include <stdio.h>
- #include "article.h"
- #include "cfg.h"
-
- /*
- ** This is necessary since the builtin makedir call uses
- ** mknod which is a superuser only call for directories.
- */
- #if (!HAVE_MKDIR && !USE_SYSMKDIR)
- #define ROOT_ONLY
- #endif
-
- #define UFMT "usage: %s [ -dgstuvV ] [ -f config_file ] [ -n newsgroup ]\n"
-
- int overwrite;
- int status_only;
- struct stat sbuf;
- struct group_archive *newsgrp;
-
- char tmp_mailfile[] = "/tmp/rkive.mail";
- char global_mailfile[] = "/tmp/gbl.mail";
-
- char *save_article();
- char *compress_file();
- char *do_compress();
- char *basename();
- char *suffix();
- void archive();
-
- char *strcpy();
- char *strcat();
- char *strchr();
- FILE *efopen();
- void exit();
-
- extern int debug;
- extern int verbose;
- extern int test;
- extern int problem_article;
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- int c;
- extern char *optarg;
- char *nwsg = NULL;
-
- progname = argv[0];
- errfp = stderr;
- logfp = stdout;
-
- status_only = debug = verbose = 0;
- test = overwrite = fill_in_defaults = 0;
-
- /*
- ** Setup the default config file to be used
- ** unless the user specifies otherwise.
- */
- config_file = LOCATION;
-
- if (argc > 1) {
- while ((c = getopt(argc, argv, "dgstuvVn:f:")) != EOF) {
- switch (c) {
- case 'f':
- config_file = optarg;
- break;
- case 'd':
- debug++;
- verbose++;
- break;
- case 'g':
- fill_in_defaults++;
- break;
- case 'n':
- nwsg = optarg;
- break;
- case 's':
- status_only++;
- break;
- case 't':
- test++;
- verbose++;
- break;
- case 'u':
- overwrite++;
- break;
- case 'v':
- verbose++;
- break;
- case 'V':
- version();
- default:
- (void) fprintf(errfp, UFMT, progname);
- return(1);
- }
- }
- }
-
- setup_defaults();
-
- init_article();
-
- for (c = 0; c <= num; c++) {
- newsgrp = &group[c];
- /*
- ** Was a newsgroup specified on the command line ?
- */
- if (nwsg != NULL) {
- if (strcmp(nwsg, newsgrp->ng_name) != 0)
- continue;
- }
- archive();
- }
-
- if (!status_only) {
- /*
- ** Mail notification of the archived members to the
- ** list of users specified in the configuration file
- ** and remove the file containing the archived info.
- */
- mail_file(mail, global_mailfile, "Complete Archive Results ");
- (void) unlink(global_mailfile);
- }
- return(0);
- }
-
- void archive()
- {
- struct dirent *dp;
- int cct;
- DIR *dfd;
- char *rp, *rec;
- char *dir = ".";
- char *new_member;
- char *archived_file;
- char *get_archived_rec();
- char newsgroup_directory[MAXNAMLEN];
-
- #ifdef ROOT_ONLY
- /*
- ** check to assure that the user is root if
- ** actual archiving is to take place. This is necessary
- ** if there is no mkdir system call.
- */
-
- if (!status_only && (getuid() != 0)) {
- (void) fprintf(errfp, "%s: Sorry, Must be root to rkive.\n",
- progname);
- exit(1);
- }
- #endif
-
- /* Remove any existing temporary mail file */
-
- (void) unlink(tmp_mailfile);
- cct = 0; /* counter for newsgroup message in global mail */
-
- /*
- ** Assure that there something specified in the
- ** archive location variable...
- */
- if (!*newsgrp->location) {
- (void) fprintf(errfp, "SKIPPING %s: No archive location specified..\n",
- newsgrp->ng_name);
- return;
- }
-
- /*
- ** print out the appropriate
- ** header for the newsgroup.
- */
-
- if (debug || (verbose && status_only)) {
- (void) fprintf(logfp,"\n\n");
- display_group_info(newsgrp);
- (void) fprintf(logfp,"\n");
- }
- else if (status_only)
- (void) fprintf(logfp, "%s\n",newsgrp->ng_name);
-
- /* convert newsgroup name into a disk path */
-
- rp = newsgrp->ng_name;
-
- /*
- ** convert all '.' to '/' to generate a path to the
- ** newsgroup directory relative from the specified SPOOLDIR.
- */
-
- while (*rp) { /* convert all */
- if (*rp == '.') /* '.'s to '/' */
- *rp = '/'; /* to create */
- rp++; /* the disk */
- } /* location */
-
- (void) sprintf(newsgroup_directory,"%s/%s", spooldir,newsgrp->ng_name);
-
- if (chdir(newsgroup_directory) != 0) {
- (void) fprintf(errfp,"Can't change directory to %s, %s not archived\n",
- newsgroup_directory, newsgrp->ng_name);
- return;
- }
-
- /*
- ** Create a path to the .archived file for the newsgroup's archive.
- ** This file is used to determine if an article has already been
- ** archived.
- */
- (void) sprintf(newsgrp->arc_done,"%s/.archived",newsgrp->location);
-
- /*
- ** Create a path to the .patchlog file for the newsgroup's archive.
- ** This file is used to record patches to posted software so that
- ** it can easily be determined what the full set of software is.
- */
- (void) sprintf(newsgrp->patchlog,"%s/.patchlog",newsgrp->location);
-
- /*
- ** locate a file that needs to be archived. This is done by
- ** a linear search of the directory with a linear search of
- ** of the contents of the .archived file. If the file is not
- ** specified in the .archived file, it has not been archived
- ** before and we can proceed with the archiving.
- */
- if ((dfd = opendir(dir)) == NULL) {
- (void) fprintf(errfp, "can't open %s\n", newsgroup_directory);
- return;
- }
- while ((dp = readdir(dfd)) != NULL) {
- if (strcmp(dp->d_name,".") == 0
- || strcmp(dp->d_name,"..") == 0)
- continue;
-
- if (stat(dp->d_name, &sbuf) != 0) {
- (void) fprintf(errfp, "can't stat %s/%s\n",
- newsgroup_directory, dp->d_name);
- continue;
- }
-
- /*
- ** If its not a regular file, we cannot archive it.
- */
-
- else if ((sbuf.st_mode & S_IFMT) != S_IFREG)
- continue;
-
- /*
- ** If the user has specified that a quick status
- ** listing should be produced then hop to it....
- */
-
- if (status_only) {
- if ((rec = get_archived_rec(dp->d_name)) == NULL)
- (void) fprintf(logfp,"\t<%s> Awaiting Archiving\n",dp->d_name);
- else if ((rp = strchr(rec,' ')) == NULL)
- (void) fprintf(logfp,"\t<%s> Archived\n",dp->d_name);
- else {
- rp++;
- *(rp-1) = '\0';
- (void) fprintf(logfp,"\t<%s> Archived as <%s>\n",rec,rp);
- }
- continue;
- }
-
- /*
- ** Archiving from here on out.
- */
-
- if (!needs_to_be_archived(dp->d_name))
- continue;
-
- if ((new_member = save_article(dp->d_name,newsgrp)) != NULL) {
- archived_file = compress_file(new_member,newsgrp);
- set_ownership(archived_file,newsgrp);
-
- /*
- ** If a problem has been encountered,
- ** the function do_problem handles
- ** the logging, and notifying.
- */
-
- if (!problem_article) {
- log_activities(archived_file,newsgrp);
- build_index(new_member,newsgrp);
- notify_users(archived_file,newsgrp,cct++);
- }
- }
- else
- (void) fprintf(logfp,"Unable to archive %s/%s!!!\n",
- newsgrp->ng_name, dp->d_name);
- }
- (void) closedir(dfd);
-
- if (!status_only) {
- /* Remove the expired entries from the .archived file */
- /* stored in the newsgroup's BASEDIR directory. */
-
- remove_expired();
-
- /* Mail notification of the archived members to the */
- /* list of users specified in the configuration file */
- /* and remove the file containing the archived info. */
-
- mail_file(newsgrp->mail_list, tmp_mailfile, newsgrp->ng_name);
- (void) unlink(tmp_mailfile);
- }
- return;
- }
-
- /*
- ** Notify Users of Archiving.
- ** If users have been specified to be informed, check to see
- ** if they have requested a specific logging format. If so
- ** use the specified format to notify the user. If not, use
- ** "file archived at path" message.
- */
- notify_users(filename,ng,num_msgs)
- char *filename;
- struct group_archive *ng;
- int num_msgs;
- {
- /*
- ** Are there users specified in the
- ** newsgroup section ?
- */
- if ( *(ng->mail_list) ) {
- if ( *(ng->logformat) )
- logit(tmp_mailfile, ng->logformat, filename);
- else
- logit(tmp_mailfile, DEFAULT_LOG_FORMAT, filename);
- }
-
- /*
- ** Are there users specified in the
- ** global section ?
- */
- if ( *mail ) {
- if (num_msgs == 0) /* print the newsgroup name out */
- logit(global_mailfile, "\n\t\t:%G:\n",filename);
- if (*log_format)
- logit(global_mailfile, log_format,filename);
- else
- logit(global_mailfile, DEFAULT_LOG_FORMAT, filename);
- }
- }
-
- /*
- ** Log_activities
- **
- ** There are two possible logfiles that need to be written.
- ** The group specific logfile (ng->logfile) and the global
- ** log. If it has been configured to use a specific format
- ** for the logging, do so. Else, just record the fact the
- ** file was sucessfully archived and the date.
- */
- log_activities(filename,ng)
- char *filename;
- struct group_archive *ng;
- {
- long clock;
- long time();
- char *ctime();
-
- char logbuf[BUFSIZ];
- char dms_date[30];
-
- if ( !*(ng->logformat) || !*log_format) {
- clock = time((long *)0);
- (void) strcpy(dms_date, ctime(&clock));
- *(dms_date+(strlen(dms_date)-1)) = '\0';
- (void) sprintf(logbuf,"%s archived %s",filename, dms_date);
- }
-
- if ( *(ng->logformat) )
- logit(ng->logfile, ng->logformat, filename);
- else
- logit(ng->logfile, logbuf, filename);
-
- if ( *log_format )
- logit(log, log_format, filename);
- else
- logit(log, logbuf, filename);
- }
-
- /*
- ** logit
- **
- ** This function is used to append a logfile record
- ** if there is a logfile name specified.
- **
- */
-
- logit(filename, format_of_log, arch_file)
- char *filename;
- char *format_of_log;
- char *arch_file;
- {
- FILE *fp, *fopen();
-
- if ( *(filename) ) { /* Is a logfile specified ? */
- if ((fp = fopen(filename,"a")) != NULL) {
- format_output(fp, format_of_log, arch_file, ARCHIVE);
- (void) fclose(fp);
- }
- }
- }
-
-
- set_ownership(filename,ng)
- char *filename;
- struct group_archive *ng;
- {
- if (verbose) { /* Print out the actions about to be preformed */
- (void) fprintf(logfp,"chown\t<%d> <%s>\n", ng->owner, filename);
- (void) fprintf(logfp,"chgrp\t<%d> <%s>\n", ng->group, filename);
- }
-
- if (!test) { /* chown the owner/group to the desired values */
- if (chown(filename,ng->owner, ng->group) != 0)
- error("Can't change ownership of", filename);
- }
-
- if (verbose) { /* Print out the actions about to be preformed */
- (void) fprintf(logfp,"chmod\t<%o> <%s>\n", ng->modes, filename);
- }
-
- if (!test) { /* change the file modes to the specified modes */
- if (chmod(filename,ng->modes) != 0)
- error("Can't change modes of", filename);
- }
- }
-
- mail_file(user_list, file_to_mail, nwsgrp)
- char *user_list;
- char *file_to_mail;
- char *nwsgrp;
- {
- char *list, *name;
- char cmdstr[80];
-
- /* Is there a list of users to mail to ? */
- if ( !*user_list || (strlen(user_list) == 0))
- return;
-
- /* Was there a notification file created ? */
- if (stat(file_to_mail, &sbuf) != 0)
- return;
-
- name = user_list;
- do {
- if ((list = strchr(name,',')) != NULL) {
- list++;
- *(list-1) = '\0';
- }
-
- #ifdef SUBJECT_LINE
- (void) sprintf(cmdstr, "%s -s '%s' %s < %s",
- MAIL, nwsgrp, name, file_to_mail);
- #else
- (void) sprintf(cmdstr, "%s %s < %s", MAIL, name, file_to_mail);
- #endif
- if (verbose)
- (void) fprintf(logfp,"Mailing %s Archived results to %s\n",
- nwsgrp, name);
- if (!test)
- (void) system(cmdstr);
-
- name = list;
-
- } while (name != NULL);
- return;
- }
-
- build_index(filename,ng)
- char *filename;
- struct group_archive *ng;
- {
- if (*(ng->index)) { /* Is there a newsgroup index file ? */
- if (*(ng->indformat)) /* Yes, Is there a index file format? */
- logit(ng->index, ng->indformat, filename);
- else if (*index_format) /* No, is there a global format ? */
- logit(ng->index, index_format, filename);
- else /* No, use the default index format */
- logit(ng->index, DEFAULT_INDEX_FORMAT, filename);
- }
-
- if (*index) { /* Is there a global index file ? */
- if (*index_format) /* Yes, Is there a global file format ? */
- logit(index, index_format, filename);
- else /* No, so use the default index format */
- logit(ng->index, DEFAULT_INDEX_FORMAT , filename);
- }
- }
-
-
- char *compress_file(filename,ng)
- char *filename;
- struct group_archive *ng;
- {
- static char compressed[MAXNAMLEN];
-
- (void) strcpy(compressed, filename); /* store the filename */
-
- /* Check to see if a group specific compress was specified. */
- /* If so, then execute the command with the filename passed in. */
- /* Else check to see if a global compress was specified. If so, */
- /* then execute the command with the filename passed in. */
- /* If both are NULL, no compression is done. */
-
- if (*(ng->compress))
- (void) strcat(compressed, do_compress(ng->compress, filename));
- else if (*compress)
- (void) strcat(compressed, do_compress(compress, filename));
-
- return(compressed);
- }
-
- char *do_compress(packit,filename)
- char *packit;
- char *filename;
- {
- char *comp_cmd;
- char cmd[BUFSIZ];
-
- (void) sprintf(cmd,"%s %s", packit, filename);
-
- /*
- ** get the basename of the command to use.
- */
- comp_cmd = basename(packit);
-
- if (verbose)
- (void) fprintf(logfp,"%s %s\n", comp_cmd, filename);
-
- if (!test)
- (void) system(cmd);
-
- return(suffix(comp_cmd));
- }
-
-
- /*
- ** Record_problem()
- ** This function is used to log problems encountered
- ** to the designated parties.
- */
- record_problem(msg_fmt,filename,ng)
- char *msg_fmt;
- char *filename;
- struct group_archive *ng;
- {
- /*
- ** This function is used in the event that a problem
- ** has occurred during archiving. It mails a message
- ** to the newsgroup speecified list and it mails a
- ** message to the globally specified users.
- **
- ** It then logs the fact into both the newsgroup
- ** and the global logfiles if they have been specified.
- */
-
- if ( *(ng->mail_list) )
- logit(tmp_mailfile, msg_fmt, filename);
-
- if ( *mail )
- logit(global_mailfile, msg_fmt,filename);
-
- logit(ng->logfile, msg_fmt, filename);
- logit(log, msg_fmt, filename);
- }
-