home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume19
/
rkive
/
part04
/
rkive.c
< prev
Wrap
C/C++ Source or Header
|
1989-06-29
|
17KB
|
611 lines
/*
**
** 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);
}