home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume17
/
rkive
/
part02
< prev
next >
Wrap
Internet Message Format
|
1991-02-24
|
56KB
From: kent@sparky.imd.sterling.com (Kent Landfield)
Newsgroups: comp.sources.misc
Subject: v17i018: rkive - Usenet sources archiver, Part02/06
Message-ID: <1991Feb24.222503.26973@sparky.IMD.Sterling.COM>
Date: 24 Feb 91 22:25:03 GMT
Approved: kent@sparky.imd.sterling.com
X-Checksum-Snefru: a0653cc2 6de1eff1 27e20a7f e94b5b43
Submitted-by: Kent Landfield <kent@sparky.imd.sterling.com>
Posting-number: Volume 17, Issue 18
Archive-name: rkive/part02
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
# "End of archive 2 (of 6)."
# Contents: rkive/rkive.c rkive/setup.c
# Wrapped by kent@sparky on Sun Feb 24 16:11:22 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'rkive/rkive.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'rkive/rkive.c'\"
else
echo shar: Extracting \"'rkive/rkive.c'\" \(27854 characters\)
sed "s/^X//" >'rkive/rkive.c' <<'END_OF_FILE'
X/*
X** Subsystem: USENET Sources Archiver
X** File Name: rkive.c
X**
X** usage: rkive [-?dgstuvV] [-f config_file] [-n newsgroup]
X** [-B batchfile] [-S newsgroup]
X**
X**
X** This software is Copyright (c) 1989, 1990, 1991 by Kent Landfield.
X**
X** Permission is hereby granted to copy, distribute or otherwise
X** use any part of this package as long as you do not try to make
X** money from it or pretend that you wrote it. This copyright
X** notice must be maintained in any copy made.
X**
X** Use of this software constitutes acceptance for use in an AS IS
X** condition. There are NO warranties with regard to this software.
X** In no event shall the author be liable for any damages whatsoever
X** arising out of or in connection with the use or performance of this
X** software. Any use of this software is at the user's own risk.
X**
X** If you make modifications to this software that you feel
X** increases it usefulness for the rest of the community, please
X** email the changes, enhancements, bug fixes as well as any and
X** all ideas to me. This software is going to be maintained and
X** enhanced as deemed necessary by the community.
X**
X** Kent Landfield
X** uunet!sparky!kent
X** kent@sparky.imd.sterling.com
X*/
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include "article.h"
X#include "cfg.h"
X
X#ifdef NNTP
Xchar sccsid[] = "@(#)rkive.c 2.2 2/23/91 - NNTP Version";
X#else
Xchar sccsid[] = "@(#)rkive.c 2.2 2/23/91";
X#endif /*!NNTP*/
X
X/*
X** This is necessary since the builtin makedir call uses
X** mknod which is a superuser only call for directories.
X*/
X#if (!HAVE_MKDIR && !USE_SYSMKDIR)
X#define ROOT_ONLY
X#endif
X
X/*
X** The following define is use for compilation
X** so that format_output can use the extended
X** fomating characters that are not available
X** in article.
X*/
X#define RKIVE
X
Xchar tmp_mailfile[] = "/tmp/rkive.mail";
Xchar global_mailfile[] = "/tmp/gbl.mail";
X
Xchar *batch_file = NULL;
Xchar article_name[MAXNAMLEN];
X
Xint retrieve = FROM_DISK; /* default archiving is done from local disk */
Xint overwrite;
Xint status_only;
X
Xstruct stat sbuf;
X
XFILE *inputfp;
X
Xint needs_to_be_archived();
Xchar *save_article();
Xchar *compress_file();
Xchar *do_compress();
Xchar *basename();
Xchar *suffix();
Xchar *format_output();
Xvoid archive();
Xvoid build_index();
Xvoid display_group_info();
Xvoid logit();
Xvoid log_activities();
Xvoid mail_file();
Xvoid notify_users();
Xvoid record_problem();
Xvoid set_ownership();
X
Xint fclose();
Xint stat();
Xint strcmp();
Xint strlen();
Xint system();
Xint unlink();
Xchar *strcpy();
Xchar *strcat();
Xchar *strchr();
XFILE *efopen();
Xvoid exit();
X
Xextern int yydebug;
Xextern char inputstring[];
Xextern parser_return_value;
X
Xextern int debug;
Xextern int verbose;
Xextern int test;
Xextern int inum;
Xextern int problem_article;
Xextern char *nntp_server;
X
Xvoid usage()
X{
X (void)fprintf(stderr,"usage: %s [-?dgstuvV] [-f config_file]\n", progname);
X (void)fprintf(stderr," [-n newsgroup] [-B batchfile] [-S newsgroup]\n");
X (void)fprintf(stderr,"options:\n");
X (void)fprintf(stderr," -? Display this message.\n");
X (void)fprintf(stderr," -d Debug, assumes verbose flag as well.\n");
X (void)fprintf(stderr," -g Fill in default values with group display.\n");
X (void)fprintf(stderr," Only effective with verbose mode flag.\n");
X (void)fprintf(stderr," -s Display status of article archiving.\n");
X (void)fprintf(stderr," -t Test mode, display what would be done but do no archiving.\n");
X (void)fprintf(stderr," -u Unconditionally overwrite dupliclate articles.\n");
X (void)fprintf(stderr," -v Verbose archiving information printed.\n");
X (void)fprintf(stderr," -V Display %s software version information.\n",
X progname);
X (void)fprintf(stderr," -f config_file\n");
X (void)fprintf(stderr," Specify alternate configuration file to be used.\n");
X (void)fprintf(stderr," -n newsgroup\n");
X (void)fprintf(stderr," Specify newsgroup to archive or display status for.\n");
X (void)fprintf(stderr," -B batchfile\n");
X (void)fprintf(stderr," Read names of articles to archive from batchfile.\n");
X (void)fprintf(stderr," Note: Use of the -B option requires a newsgroup\n");
X (void)fprintf(stderr," be specified using the -n option.\n");
X (void)fprintf(stderr," -S newsgroup\n");
X (void)fprintf(stderr," Take the name of articles to archive from stdin.\n");
X}
X
Xint main(argc, argv)
Xint argc;
Xchar **argv;
X{
X int getopt();
X void version();
X void setup_defaults();
X void init_article();
X
X int c;
X extern char *optarg;
X extern int opterr;
X char *nwsg = NULL;
X
X yydebug = FALSE;
X
X opterr = 0;
X progname = argv[0];
X inputfp = stdin;
X logfp = stdout;
X errfp = stderr;
X
X status_only = debug = verbose = 0;
X test = overwrite = fill_in_defaults = 0;
X
X /*
X ** Setup the default config file to be used
X ** unless the user specifies otherwise.
X */
X config_file = LOCATION;
X
X if (argc > 1) {
X while ((c = getopt(argc, argv, "?dgstuvVn:f:B:S:y")) != EOF) {
X switch (c) {
X case 'B': /* take filenames from batch file */
X retrieve = FROM_BATCHFILE;
X batch_file = optarg;
X break;
X case 'd': /* for extremely verbose output */
X debug++;
X verbose++;
X break;
X case 'f': /* alternate configuration file */
X config_file = optarg;
X break;
X case 'g': /* display defaults filled in */
X fill_in_defaults++;
X break;
X case 'n': /* specify an individual newsgroup */
X nwsg = optarg;
X break;
X case 's': /* display article archive status */
X status_only++;
X break;
X case 'S': /* single article archiving */
X retrieve = FROM_NAME;
X nwsg = optarg;
X break;
X case 't': /* test mode, show but do nothing */
X test++;
X verbose++;
X break;
X case 'u': /* overwrite existing duplicates */
X overwrite++;
X break;
X case 'v': /* display expanded output */
X verbose++;
X break;
X case 'V': /* display software version only */
X version();
X break;
X case 'y': /* turn on yydebug facilities */
X yydebug++;
X break;
X case '?': /* display usage information */
X default: /* display usage, invalid option */
X usage();
X return(1);
X }
X }
X }
X
X /*
X ** If the user has specified that input is be filenames
X ** retrieved from a batch file, the user must specify a
X ** a newsgroup in addition to the batch filename.
X */
X if (retrieve == FROM_BATCHFILE) {
X if (nwsg == NULL) {
X (void) fprintf(errfp,
X "%s: Must specify a newsgroup when using batchfile mode\n",
X progname);
X (void) fprintf(errfp,"Sample command line...\n");
X (void) fprintf(errfp,"\t%s -B %s -n newsgroup-here\n",
X progname, batch_file);
X return(1);
X }
X }
X
X setup_defaults();
X
X init_article();
X
X for (c = 0; c <= num; c++) {
X newsgrp = &group[c];
X /*
X ** Was a newsgroup specified on the command line ?
X */
X if (nwsg != NULL) {
X if (strcmp(nwsg, newsgrp->ng_name) != 0)
X continue;
X }
X archive();
X }
X
X if (!status_only) {
X /*
X ** Mail notification of the archived members to the
X ** list of users specified in the configuration file
X ** and remove the file containing the archived info.
X */
X mail_file(mail, global_mailfile, "Rkive results");
X (void) unlink(global_mailfile);
X }
X return(0);
X}
X
Xvoid archive()
X{
X char *get_archived_rec();
X int retrieve_article();
X void get_header();
X
X int cct;
X int first;
X int val;
X char *rp, *rec;
X char *new_member;
X char *archived_file;
X
X#ifdef ROOT_ONLY
X /*
X ** check to assure that the user is root if
X ** actual archiving is to take place. This is necessary
X ** if there is no mkdir system call.
X */
X
X if (!status_only && (getuid() != 0)) {
X (void) fprintf(errfp, "%s: Sorry, Must be root to rkive.\n",
X progname);
X exit(1);
X }
X#endif /* ROOT_ONLY */
X
X inum = 0; /* initialize chronological issue counter */
X
X /* Remove any existing temporary mail file */
X
X (void) unlink(tmp_mailfile);
X cct = 0; /* counter for newsgroup message in global mail */
X
X /*
X ** Assure that there something specified in the
X ** archive location variable...
X */
X if (!*newsgrp->location) {
X (void) fprintf(errfp, "SKIPPING %s: No archive location specified..\n",
X newsgrp->ng_name);
X return;
X }
X
X /*
X ** print out the appropriate
X ** header for the newsgroup.
X ** If the user wishes to see the newsgroup info as well as all the
X ** information about a file archived, the user must specify
X ** rkive -svv to see it all...
X */
X
X if (debug || (verbose == 2 && status_only)) {
X (void) fprintf(logfp,"\n\n");
X display_group_info(newsgrp);
X (void) fprintf(logfp,"\n");
X }
X else if (status_only || verbose == 2)
X (void) fprintf(logfp, "%s\n",newsgrp->ng_name);
X
X /*
X ** Create a path to the .archived file for the newsgroup's archive.
X ** This file is used to determine if an article has already been
X ** archived. If the user did not specify one ...
X */
X if (!*newsgrp->arc_done)
X (void) sprintf(newsgrp->arc_done,"%s/.archived",newsgrp->location);
X
X /*
X ** Create a path to the .patchlog file for the newsgroup's archive.
X ** This file is used to record patches to posted software so that
X ** it can easily be determined what the full set of software is.
X */
X if (!*newsgrp->patchlog)
X (void) sprintf(newsgrp->patchlog,"%s/.patchlog",newsgrp->location);
X
X /*
X ** first indicates that archiving has just begun for this group
X ** so that any necessary setup can be done in retrieve_article().
X */
X
X first = 1;
X
X#ifdef NNTP
X /*
X ** Determine if the newsgroup being archived is to be accessed via
X ** nntp or via local disk access.
X */
X if (*newsgrp->nntp) {
X nntp_server = newsgrp->nntp;
X retrieve = FROM_NNTP;
X }
X else if (*nntp) {
X nntp_server = nntp;
X retrieve = FROM_NNTP;
X }
X#endif /*NNTP*/
X
X while ((val = retrieve_article(article_name,first)) != DONE) {
X first = 0;
X if (val == ERROR_ENCOUNTERED)
X return;
X else if (val != RETRIEVED) {
X /*
X ** Invalid return value encountered, we're in truble now..
X */
X (void) fprintf(errfp,"Invalid return from retrieve_article..?? Skipping %s\n",
X newsgrp->ng_path);
X return;
X }
X
X /*
X ** Read the news article file to extract the
X ** header information and fill appropriate
X ** data structures.
X */
X get_header(article_name);
X
X /*
X ** If the user has specified that a quick status
X ** listing should be produced then hop to it....
X */
X
X if (status_only) {
X if ((rec = get_archived_rec(header.ident)) == NULL) {
X /*
X ** Assure that the article that we are going
X ** to give status on is one that would be archived
X ** if archiving was occuring. (e.g. does it match
X ** the user supplied criteria for archiving...)
X */
X if (*newsgrp->match) {
X parser_return_value = 0;
X (void) strcpy(inputstring, newsgrp->match);
X if (yyparse())
X (void) fprintf(logfp, "Parse failed and returned %d\n",
X parser_return_value);
X else {
X /* Did match string produce true as result? */
X
X if (debug)
X (void) fprintf(logfp, "Parser returned %d\n",
X parser_return_value);
X }
X if (!parser_return_value) {
X#ifdef NNTP
X /*
X ** Since they only want status, remove the
X ** nntp transfer tmpfile if newsgroup is
X ** being archived via nntp.
X */
X if (retrieve == FROM_NNTP)
X (void) unlink(article_name);
X#endif /*NNTP*/
X continue;
X }
X }
X#ifdef NNTP
X if (retrieve == FROM_NNTP)
X (void) fprintf(logfp,
X "\t[%s] Awaiting Archiving\n",header.ident);
X else
X (void) fprintf(logfp,
X "\t[%s] Awaiting Archiving\n",article_name);
X#else /*!NNTP*/
X (void) fprintf(logfp,"\t[%s] Awaiting Archiving\n",article_name);
X#endif /*NNTP*/
X }
X else if (verbose) {
X if ((rp = strchr(rec,' ')) == NULL) {
X#ifdef NNTP
X if (retrieve == FROM_NNTP)
X (void) fprintf(logfp,"\t[%s] Archived\n",header.ident);
X else
X (void) fprintf(logfp,"\t[%s] Archived\n",article_name);
X#else /*!NNTP*/
X (void) fprintf(logfp,"\t[%s] Archived\n",article_name);
X#endif /*NNTP*/
X }
X else {
X rp++;
X *(rp-1) = '\0';
X (void) fprintf(logfp,"\t%s Archived as %s\n",rec,rp);
X }
X }
X#ifdef NNTP
X /*
X ** Since they only want status, remove the
X ** nntp transfer tmpfile if newsgroup is
X ** being archived via nntp.
X */
X if (retrieve == FROM_NNTP)
X (void) unlink(article_name);
X#endif /*NNTP*/
X continue;
X } /* End of status only... */
X
X /*
X **
X ** We have located a file that may need to be archived.
X ** First read the header information from the found file.
X ** Next, determine if the file needs to be archived by
X ** doing a linear search of of the contents of the .archived file
X ** comparing the message-id of the new article with the message-ids
X ** recorded in the .archived file. If the new message-id is not
X ** specified in the .archived file, it has not been archived
X ** before and we can proceed with the archiving.
X ** Can we say slow... maybe dbm in the future ???
X */
X
X if (!needs_to_be_archived(header.ident)) {
X#ifdef NNTP
X /*
X ** Remove the nntp transfer tmpfile if the
X ** newsgroup is being archived via nntp.
X */
X if (retrieve == FROM_NNTP)
X (void) unlink(article_name);
X#endif /*NNTP*/
X continue;
X }
X
X if (*newsgrp->match) {
X (void) strcpy(inputstring, newsgrp->match);
X
X if (yyparse()) {
X (void) fprintf(logfp, "Parse failed and returned %d\n",
X parser_return_value);
X#ifdef NNTP
X /*
X ** Remove the nntp transfer tmpfile if the
X ** newsgroup is being archived via nntp.
X */
X if (retrieve == FROM_NNTP)
X (void) unlink(article_name);
X#endif /*NNTP*/
X continue;
X }
X
X /* Did match string produce true as result? */
X
X if (debug)
X (void) fprintf(logfp, "Parser returned %d\n", parser_return_value);
X
X if (!parser_return_value) {
X#ifdef NNTP
X /*
X ** Remove the nntp transfer tmpfile if the
X ** newsgroup is being archived via nntp.
X */
X if (retrieve == FROM_NNTP)
X (void) unlink(article_name);
X#endif /*NNTP*/
X continue;
X }
X }
X
X /*
X ** Archiving from here on out.
X */
X
X if ((new_member = save_article(article_name,newsgrp)) != NULL) {
X /*
X ** To not do any compression of setting of ownership
X ** for newsgroup articles that are archived by an
X ** external application.
X */
X if (newsgrp->type != EXTERNAL_COMMAND) {
X archived_file = compress_file(new_member,newsgrp);
X set_ownership(archived_file,new_member,newsgrp);
X }
X else
X archived_file = new_member;
X
X /*
X ** If a problem has been encountered,
X ** the function do_problem handles
X ** the logging, and notifying.
X */
X
X if (!problem_article) {
X log_activities(archived_file,newsgrp);
X build_index(new_member,newsgrp);
X notify_users(archived_file,newsgrp,cct++);
X }
X }
X else {
X if (newsgrp->type != ONLY_ARCHIVE_NAME) {
X (void) fprintf(logfp,"Unable to archive %s/%s!!!\n",
X newsgrp->ng_path, article_name);
X }
X }
X#ifdef NNTP
X /*
X ** Remove the nntp transfer tmpfile if the
X ** newsgroup is being archived via nntp.
X */
X if (retrieve == FROM_NNTP)
X (void) unlink(article_name);
X#endif /*NNTP*/
X }
X
X if (!status_only) {
X /* Mail notification of the archived members to the */
X /* list of users specified in the configuration file */
X /* and remove the file containing the archived info. */
X
X mail_file(newsgrp->mail_list, tmp_mailfile, newsgrp->ng_name);
X (void) unlink(tmp_mailfile);
X }
X return;
X}
X
X/*
X** Notify Users of Archiving.
X** If users have been specified to be informed, check to see
X** if they have requested a specific logging format. If so
X** use the specified format to notify the user. If not, use
X** "file archived at path" message.
X*/
Xvoid notify_users(filename,ng,num_msgs)
Xchar *filename;
Xstruct group_archive *ng;
Xint num_msgs;
X{
X /*
X ** Are there users specified in the
X ** newsgroup section ?
X */
X if ( *(ng->mail_list) ) {
X if ( *(ng->logformat) )
X logit(tmp_mailfile, ng->logformat, filename);
X else
X logit(tmp_mailfile, DEFAULT_LOG_FORMAT, filename);
X }
X
X /*
X ** Are there users specified in the
X ** global section ?
X */
X if ( *mail ) {
X if (num_msgs == 0) /* print the newsgroup name out */
X logit(global_mailfile, "\n\t\t:%G:\n",filename);
X if (*log_format)
X logit(global_mailfile, log_format,filename);
X else
X logit(global_mailfile, DEFAULT_LOG_FORMAT, filename);
X }
X}
X
X/*
X** Log_activities
X**
X** There are two possible logfiles that need to be written.
X** The group specific logfile (ng->logfile) and the global
X** log. If it has been configured to use a specific format
X** for the logging, do so. Else, just record the fact the
X** file was sucessfully archived and the date.
X*/
Xvoid log_activities(filename,ng)
Xchar *filename;
Xstruct group_archive *ng;
X{
X long clock;
X long time();
X char *ctime();
X
X char logbuf[BUFSIZ];
X char dms_date[30];
X
X if ( !*(ng->logformat) || !*log_format) {
X clock = time((long *)0);
X (void) strcpy(dms_date, ctime(&clock));
X *(dms_date+(strlen(dms_date)-1)) = '\0';
X (void) sprintf(logbuf,"%s archived %s",filename, dms_date);
X }
X
X if ( *(ng->logformat) )
X logit(ng->logfile, ng->logformat, filename);
X else
X logit(ng->logfile, logbuf, filename);
X
X if ( *log_format )
X logit(log, log_format, filename);
X else
X logit(log, logbuf, filename);
X}
X
X/*
X** logit
X**
X** This function is used to append a logfile record
X** if there is a logfile name specified.
X**
X*/
X
Xvoid logit(filename, format_of_log, arch_file)
Xchar *filename;
Xchar *format_of_log;
Xchar *arch_file;
X{
X FILE *fp, *fopen();
X char *qp;
X
X if (!test) {
X if ( *(filename) ) { /* Is a logfile specified ? */
X if ((fp = fopen(filename,"a")) != NULL) {
X qp = format_output(format_of_log, arch_file, ARCHIVE);
X (void) fprintf(fp,"%s\n",qp);
X (void) fclose(fp);
X }
X }
X }
X}
X
X/*
X** Set_ownership
X**
X** This functions is responsible for setting the owner, group
X** and modes of a file just put into the archive. Two file names
X** are passed to this function. "filename" contains the compression
X** suffix if the file is to be compressed. "flname" is the name of
X** the file without the compression suffix. If the ownership or
X** modes can not be set on the target "filename", this function
X** then tries to set the original file, "flname". In this manner,
X** the file permissions get set even if the compression routine fails.
X*/
X
Xvoid set_ownership(filename,flname,ng)
Xchar *filename; /* filename with compression suffix */
Xchar *flname; /* filename without compression suffix */
Xstruct group_archive *ng;
X{
X int chmod();
X int chown();
X
X if (verbose) /* Print out the actions about to be preformed */
X (void) fprintf(logfp,"chmod\t<%o> <%s>\n", ng->modes, filename);
X
X if (!test) { /* change the file modes to the specified modes */
X if (chmod(filename,ng->modes) != 0) {
X /* Assume the compress failed and try the original... */
X if (chmod(flname,ng->modes) != 0)
X record_problem("Can't change modes of %O", filename, ng);
X }
X }
X
X if (verbose) { /* Print out the actions about to be preformed */
X (void) fprintf(logfp,"chown\t<%d> <%s>\n", ng->owner, filename);
X (void) fprintf(logfp,"chgrp\t<%d> <%s>\n", ng->group, filename);
X }
X
X if (!test) { /* chown the owner/group to the desired values */
X if (chown(filename, ng->owner, ng->group) != 0) {
X /* Assume the compress failed and try the original... */
X if (chown(flname, ng->owner, ng->group) != 0) {
X /*
X ** Are we on a system that has a braindamaged chown
X ** and does not let a general user give files away ?
X ** Assume so. Quota be gone!!
X */
X if (getuid() == 0)
X record_problem("Can't change ownership of %O",filename,ng);
X }
X }
X }
X}
X
Xvoid mail_file(user_list, file_to_mail, nwsgrp)
Xchar *user_list;
Xchar *file_to_mail;
Xchar *nwsgrp;
X{
X char *list, *name;
X char cmdstr[80];
X
X /* Is there a list of users to mail to ? */
X if ( !*user_list || (strlen(user_list) == 0))
X return;
X
X /* Was there a notification file created ? */
X if (stat(file_to_mail, &sbuf) != 0)
X return;
X
X name = user_list;
X do {
X if ((list = strchr(name,',')) != NULL) {
X list++;
X *(list-1) = '\0';
X }
X
X#ifdef SUBJECT_LINE
X (void) sprintf(cmdstr, "%s -s '%s' %s < %s",
X MAIL, nwsgrp, name, file_to_mail);
X#else
X (void) sprintf(cmdstr, "%s %s < %s", MAIL, name, file_to_mail);
X#endif
X if (verbose)
X (void) fprintf(logfp,"Mailing %s to %s\n",
X nwsgrp, name);
X if (!test)
X (void) system(cmdstr);
X
X name = list;
X
X } while (name != NULL);
X return;
X}
X
Xvoid build_index(filename,ng)
Xchar *filename;
Xstruct group_archive *ng;
X{
X if (*(ng->index)) { /* Is there a newsgroup index file ? */
X if (*(ng->indformat)) /* Yes, Is there a index file format? */
X logit(ng->index, ng->indformat, filename);
X else if (*index_format) /* No, is there a global format ? */
X logit(ng->index, index_format, filename);
X else /* No, use the default index format */
X logit(ng->index, DEFAULT_INDEX_FORMAT, filename);
X }
X
X if (*mindex) { /* Is there a global index file ? */
X if (*index_format) /* Yes, Is there a global file format ? */
X logit(mindex, index_format, filename);
X else /* No, so use the default index format */
X logit(ng->index, DEFAULT_INDEX_FORMAT , filename);
X }
X}
X
X
Xchar *compress_file(filename,ng)
Xchar *filename;
Xstruct group_archive *ng;
X{
X static char compressed[MAXNAMLEN];
X
X (void) strcpy(compressed, filename); /* store the filename */
X
X /* Check to see if a group specific compress was specified. */
X /* If so, then execute the command with the filename passed in. */
X /* Else check to see if a global compress was specified. If so, */
X /* then execute the command with the filename passed in. */
X /* If both are NULL, no compression is done. */
X
X if (*(ng->compress) || (*compress)) {
X if (*(ng->compress))
X (void) strcat(compressed, do_compress(ng->compress, filename));
X else if (*compress)
X (void) strcat(compressed, do_compress(compress, filename));
X
X /* Check to see if the compression worked. If not, return the */
X /* original file name passed to this function. The check is */
X /* done by assuring the compressed file exists. If not then */
X /* it is assumed that it failed. */
X
X if (stat(compressed, &sbuf) == -1)
X (void) strcpy(compressed, filename); /* restore filename */
X }
X return(compressed);
X}
X
Xchar *do_compress(packit,filename)
Xchar *packit;
Xchar *filename;
X{
X char *comp_cmd;
X char *kp;
X char cmd[BUFSIZ];
X
X (void) sprintf(cmd,"%s %s", packit, filename);
X
X /*
X ** get the basename of the command to use.
X */
X comp_cmd = basename(packit);
X
X if (verbose)
X (void) fprintf(logfp,"%s %s\n", comp_cmd, filename);
X
X if (!test)
X (void) system(cmd);
X
X /*
X ** Need to remove any compression command
X ** options if they exist. (compress -f)
X */
X
X (void) sprintf(cmd,"%s", comp_cmd);
X
X if ((kp = strchr(cmd,' ')) != NULL) {
X *kp = '\0';
X }
X return(suffix(cmd));
X}
X
X
X/*
X** Record_problem()
X** This function is used to log problems encountered
X** to the designated parties.
X*/
X
Xvoid record_problem(msg_fmt,filename,ng)
Xchar *msg_fmt;
Xchar *filename;
Xstruct group_archive *ng;
X{
X /*
X ** This function is used in the event that a problem
X ** has occurred during archiving. It mails a message
X ** to the newsgroup speecified list and it mails a
X ** message to the globally specified users.
X **
X ** It then logs the fact into both the newsgroup
X ** and the global logfiles if they have been specified.
X */
X
X if ( *(ng->mail_list) )
X logit(tmp_mailfile, msg_fmt, filename);
X
X if ( *mail )
X logit(global_mailfile, msg_fmt,filename);
X
X logit(ng->logfile, msg_fmt, filename);
X logit(log, msg_fmt, filename);
X}
END_OF_FILE
if test 27854 -ne `wc -c <'rkive/rkive.c'`; then
echo shar: \"'rkive/rkive.c'\" unpacked with wrong size!
fi
# end of 'rkive/rkive.c'
fi
if test -f 'rkive/setup.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'rkive/setup.c'\"
else
echo shar: Extracting \"'rkive/setup.c'\" \(23815 characters\)
sed "s/^X//" >'rkive/setup.c' <<'END_OF_FILE'
X/*
X** This software is Copyright (c) 1989, 1990, 1991 by Kent Landfield.
X**
X** Permission is hereby granted to copy, distribute or otherwise
X** use any part of this package as long as you do not try to make
X** money from it or pretend that you wrote it. This copyright
X** notice must be maintained in any copy made.
X**
X*/
X
X#if !defined(lint) && !defined(SABER)
Xstatic char SID[] = "@(#)setup.c 2.2 2/23/91";
X#endif
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include <ctype.h>
X#include <pwd.h>
X#include <grp.h>
X#include "cfg.h"
X
X#define GAG(b) ((void) fprintf(errfp,"%s invalid variable, ignoring.\n",b))
X
Xchar spooldir[MAXNAMLEN] = { SPOOLDIR };
Xchar problems_dir[MAXNAMLEN] = { PROBLEMS_DIR };
X
Xint default_owner = OWNER;
Xint default_group = GROUP;
Xint default_modes = MODES;
Xint default_type = CHRONOLOGICAL;
Xint default_patch_type = HISTORICAL;
X
Xchar default_match[MAXMATCHLEN];
X
X/*
X** compress -
X** Used to determine whether or not articles should be compressed
X** to save space. The command to execute is stored in compress.
X*/
Xchar compress[MAXNAMLEN] = { '\0' };
X
X/*
X** arch_command -
X** Used to determine whether or not articles should be piped
X** to an external command for the actual archiving.
X*/
Xchar arch_command[MAXNAMLEN] = { '\0' };
X
X/*
X** mail -
X** If specified, all actions logged are mailed to the list of users
X** specified. The user names are a comma seperated list.
X*/
Xchar mail[MAXNAMLEN] = { '\0' };
X
X/*
X** checkhash -
X** If specified, command to feed article to for transit damage.
X*/
Xchar checkhash[MAXNAMLEN] = { '\0' };
X
X#ifdef NNTP
X/*
X** nntp -
X** If specified, nntp contains the system name of the nntp server.
X*/
Xchar nntp[MAXNAMLEN] = { '\0' };
X#endif /*NNTP*/
X
X/*
X** log -
X** The location of the master log in which all actions are logged.
X** If not specified, all logged events are printed on stdout.
X*/
Xchar log[MAXNAMLEN] = { '\0' };
X
X/*
X** log_format -
X** The format of each individual log file record. The format is
X** then filled with information contained in the headers.
X*/
Xchar log_format[BUFSIZ] = { '\0' };
X
X/*
X** mindex -
X** The location of the master index.
X*/
Xchar mindex[MAXNAMLEN] = { '\0' };
X
X/*
X** index_format -
X** The format of each individual master index record. The format
X** is then filled with information contained in the headers.
X*/
Xchar index_format[BUFSIZ] = { '\0' };
X
Xchar *config_file;
XFILE *config;
X
Xstruct stat stbuf;
Xstruct passwd *pwent;
X
Xint get_group();
Xint get_owner();
Xint correct_modes();
Xint get_patch_type();
Xint get_archive_type();
Xint fclose();
Xint sscanf();
Xint stat();
Xint strlen();
Xint strcmp();
Xint strncmp();
Xchar *strstrip();
Xchar *strchr();
Xchar *strcpy();
Xvoid error();
Xvoid get_spooldir();
Xvoid get_archive_basedir();
Xstruct passwd *getpwnam();
X
Xstruct restricted_dirs {
X char *dirstr; /* path of restricted directory */
X};
X
Xstatic struct restricted_dirs base_dirs[] = {
X{ "/" },
X{ "/bin" },
X{ "/dev" },
X{ "/dev/dsk" },
X{ "/dev/rdsk" },
X{ "/etc" },
X{ "/lib" },
X{ "/stand" },
X{ "/sbin" },
X{ "/sys" },
X{ "/usr/5bin" },
X{ "/usr/5include" },
X{ "/usr/5lib" },
X{ "/usr/adm" },
X{ "/usr/adm" },
X{ "/usr/boot" },
X{ "/usr/diag" },
X{ "/usr/etc" },
X{ "/usr/include" },
X{ "/usr/kvm" },
X{ "/usr/spool/uucp" },
X{ "/usr/man" },
X{ "/usr/sccs" },
X{ "/usr/sys" },
X{ "/usr/ucb" },
X{ "/usr/ucbinclude" },
X{ "/usr/ucblib" },
X{ "/usr/xpg2bin" },
X{ "/usr/xpg2include" },
X{ "/usr/xpg2lib" },
X{ NULL },
X};
X
Xint config_line_count = 0;
X
X/*
X** Reads lines from file, catting lines
X** ending with a backslash together.
X*/
X
Xchar *long_fgets(buffer, size, fp)
Xchar *buffer;
Xint size;
XFILE *fp;
X{
X static char buf[BUFSIZ];
X extern char *strcat();
X register char *p;
X
X *buffer = 0;
X
X for (;;) {
X if (fgets(buf, BUFSIZ, fp) == NULL) {
X if (*buffer) {
X if ((p = strchr(buf, '\n')) != NULL)
X *p = 0;
X return buffer;
X }
X else
X return NULL;
X }
X
X if ((p = strchr(buf, '\n')) != NULL)
X *p = 0;
X
X if (*buf) {
X if (*(buf + strlen(buf) - 1) != '\\') {
X /*
X ** If line would be too long,
X ** print warning and return empty
X */
X if (strlen(buffer) + strlen(buf) >= size) {
X (void) fprintf(errfp,"Config %d: Input line overflow, %d max\n",
X config_line_count, size);
X *buffer = 0;
X return buffer;
X }
X (void) strcat(buffer, buf);
X return buffer;
X }
X else {
X *(buf + strlen(buf) - 1) = 0; /* Remove backslash */
X
X /*
X ** If too long, print warning, read
X ** all continuation lines and ignore
X ** them, return empty line
X */
X
X if (strlen(buffer) + strlen(buf) >= size) {
X (void) fprintf(errfp,"Config %d: Input line overflow, %d max\n",
X config_line_count, size);
X while (*(buf + strlen(buf) - 1) == '\\' && fgets(buf, BUFSIZ, fp))
X ;
X *buffer = 0;
X return buffer;
X }
X
X /* Add new line and read next one */
X
X (void) strcat(buffer, buf);
X }
X }
X else
X return buffer;
X
X } /* End for(ever) */
X}
X
X
Xvoid setup_defaults()
X{
X char *sp;
X char *buf;
X char buffer[BUFSIZ];
X char mode_str[128];
X
X char *sav_format();
X char *get_cmd();
X char *get_users();
X#ifdef NNTP
X char *getnntp();
X#endif /*NNTP*/
X FILE *efopen();
X
X config = efopen(config_file,"r");
X
X num = -1; /* initialize group structure index */
X
X while (long_fgets(buffer, sizeof buffer, config) != NULL) {
X config_line_count++;
X /* ignore comments and blank lines */
X if (*buffer == '#' || !*buffer)
X continue;
X
X buf = buffer;
X
X /* strip leading spaces and tabs */
X while(*buf == ' ' || *buf == '\t')
X ++buf;
X
X /* if embedded comments, truncate at the comment */
X if ((sp = strchr(buf,'#')) != NULL)
X *sp = '\0';
X
X /* check to see if newsgroup entry */
X
X if (*buf == '$' && *(buf+1) == '$') {
X if (++num >= NUM_NEWSGROUPS)
X error("Maximum number of newsgroups exceeded!!\n",
X "Please increase the NUM_NEWSGROUPS define...");
X
X sp = buf+2;
X while (*sp && !isspace(*sp))
X ++sp;
X *sp = '\0';
X
X group[num].owner = default_owner;
X group[num].group = default_group;
X group[num].modes = default_modes;
X group[num].type = default_type;
X group[num].patch_type = default_patch_type;
X (void) strcpy (group[num].ng_name, strstrip(buf+2));
X group[num].location[0] = '\0';
X group[num].mail_list[0] = '\0';
X group[num].arc_done[0] = '\0';
X group[num].logfile[0] = '\0';
X group[num].index[0] = '\0';
X group[num].patchlog[0] = '\0';
X group[num].logformat[0] = '\0';
X group[num].indformat[0] = '\0';
X group[num].compress[0] = '\0';
X group[num].checkhash[0] = '\0';
X group[num].match[0] = '\0';
X group[num].arch_command[0] = '\0';
X
X#ifdef NNTP
X group[num].nntp[0] = '\0';
X#endif /*NNTP*/
X }
X
X else if ((sp = strchr(buf,'=')) != NULL) {
X sp++;
X /* Global assignment */
X while (*sp == ' ' || *sp == '\t')
X sp++;
X
X if (!*sp) /* is something still there ? */
X continue;
X
X switch(*buf) {
X case 'A': if (strncmp(buf, "ARCHIVE_CMD", 11) == 0)
X (void) strcpy(arch_command, get_cmd(sp));
X else
X GAG(buf);
X break;
X case 'C': if (strncmp(buf, "COMPRESS", 8) == 0)
X (void) strcpy(compress, get_cmd(sp));
X else if (strncmp(buf, "CHECKHASH", 9) == 0)
X (void) strcpy(checkhash, get_cmd(sp));
X else
X GAG(buf);
X break;
X case 'G': if (strncmp(buf,"GROUP",5) == 0)
X default_group = get_group(sp);
X else
X GAG(buf);
X break;
X case 'I': if (strncmp(buf, "INDEX_FORMAT", 12) == 0)
X (void) strcpy(index_format, sav_format(sp));
X else if (strncmp(buf, "INDEX", 3) == 0)
X (void) strcpy(mindex, strstrip(sp));
X else
X GAG(buf);
X break;
X case 'L': if (strncmp(buf, "LOG_FORMAT", 10) == 0)
X (void) strcpy(log_format, sav_format(sp));
X else if (strncmp(buf, "LOG", 3) == 0)
X (void) strcpy(log, strstrip(sp));
X else
X GAG(buf);
X break;
X case 'M': if (strncmp(buf, "MAIL",4) == 0)
X (void) strcpy(mail,get_users(sp));
X else if (strncmp(buf, "MODE",4) == 0)
X default_modes = correct_modes(sp, mode_str);
X else if (strncmp(buf, "MATCH", 5) == 0)
X (void) strcpy(default_match, sp);
X else
X GAG(buf);
X break;
X#ifdef NNTP
X case 'N': if (strncmp(buf, "NNTP",4) == 0)
X (void) strcpy(nntp, getnntp(sp));
X else
X GAG(buf);
X break;
X#endif /*NNTP*/
X case 'O': if (strncmp(buf,"OWNER",5) == 0)
X default_owner = get_owner(sp);
X else
X GAG(buf);
X break;
X case 'P': if (strncmp(buf, "PROBLEMS", 8) == 0)
X (void) strcpy(problems_dir, strstrip(sp));
X else if (strncmp(buf,"PATCHES",7) == 0)
X default_patch_type = get_patch_type("Global",sp);
X else
X GAG(buf);
X break;
X case 'S': if (strncmp(buf,"SPOOLDIR",8) == 0)
X get_spooldir(sp);
X else
X GAG(buf);
X break;
X case 'T': if (strncmp(buf,"TYPE",4) == 0)
X default_type = get_archive_type("Global", sp);
X else
X GAG(buf);
X break;
X default : (void) fprintf(errfp,
X "%s invalid global assignment, ignoring.\n",
X buf);
X }
X }
X else if ((sp = strchr(buf,':')) != NULL) {
X sp++;
X /* group variable assignment */
X while (*sp == ' ' || *sp == '\t')
X sp++;
X
X if (!*sp) /* is something still there ? */
X continue;
X
X switch(*buf) {
X case 'A': if (strncmp(buf, "ARCHIVE_CMD", 11) == 0)
X (void)strcpy(group[num].arch_command,get_cmd(sp));
X else if (strncmp(buf, "ARCHIVED_LOG", 11) == 0)
X (void) sprintf(group[num].arc_done, strstrip(sp));
X else
X GAG(buf);
X break;
X case 'B': if (strncmp(buf, "BASEDIR",7) == 0)
X get_archive_basedir(sp);
X break;
X case 'C': if (strncmp(buf, "COMPRESS", 8) == 0)
X (void) strcpy(group[num].compress,get_cmd(sp));
X else if (strncmp(buf, "CHECKHASH", 9) == 0)
X (void) strcpy(group[num].checkhash,get_cmd(sp));
X else
X GAG(buf);
X break;
X case 'G': if (strncmp(buf,"GROUP",5) == 0)
X group[num].group = get_group(sp);
X else
X GAG(buf);
X break;
X case 'I': if (strncmp(buf, "INDEX_FORMAT", 12) == 0)
X (void) strcpy(group[num].indformat,sav_format(sp));
X else if (strncmp(buf, "INDEX", 3) == 0)
X (void) strcpy(group[num].index, strstrip(sp));
X else
X GAG(buf);
X break;
X case 'L': if (strncmp(buf, "LOG_FORMAT", 10) == 0)
X (void) strcpy(group[num].logformat, sav_format(sp));
X else if (strncmp(buf, "LOG", 3) == 0)
X (void) strcpy(group[num].logfile, strstrip(sp));
X else
X GAG(buf);
X break;
X case 'M': if (strncmp(buf, "MAIL",4) == 0)
X (void) strcpy(group[num].mail_list, get_users(sp));
X else if (strncmp(buf, "MODE",4) == 0)
X group[num].modes = correct_modes(sp, mode_str);
X else if (strncmp(buf, "MATCH", 5) == 0)
X /* Copy as it is! */
X (void) strcpy(group[num].match, sp);
X else
X GAG(buf);
X break;
X#ifdef NNTP
X case 'N': if (strncmp(buf, "NNTP",4) == 0)
X (void) strcpy(group[num].nntp, getnntp(sp));
X else
X GAG(buf);
X break;
X#endif /*NNTP*/
X case 'O': if (strncmp(buf,"OWNER",5) == 0)
X group[num].owner = get_owner(sp);
X else
X GAG(buf);
X break;
X case 'P': if (strncmp(buf,"PATCHLOG",8) == 0)
X (void) sprintf(group[num].patchlog, strstrip(sp));
X else if (strncmp(buf,"PATCHES",7) == 0)
X group[num].patch_type = get_patch_type(group[num].ng_name,sp);
X else
X GAG(buf);
X break;
X case 'T': if (strncmp(buf,"TYPE",4) == 0)
X group[num].type = get_archive_type(group[num].ng_name,sp);
X else
X GAG(buf);
X break;
X default : (void) fprintf(errfp,
X "%s invalid group assignment, ignoring.\n",
X buf);
X }
X }
X else /* no idea what it is */
X error("unknown line type", buf);
X }
X (void) fclose(config);
X config_line_count = 0;
X}
X
Xvoid error(msg1,msg2)
X char *msg1;
X char *msg2;
X{
X if (config_line_count)
X (void) fprintf(errfp,"%s: config line %d: %s %s\n",
X progname, config_line_count, msg1, msg2);
X else
X (void) fprintf(errfp,"%s: %s %s\n",progname,msg1, msg2);
X
X exit(1);
X/*NOTREACHED*/
X}
X
X/*
X** valid_base_directory
X**
X** Assure the directory specified in the configuration file
X** as the base directory for a newsgroup archive is not found
X** in the table of restricted base directories.
X**
X** This kind of checking is almost insulting to me as an
X** administrator but, enough people asked me to put it in
X** so "this duds for you"..
X*/
X
Xint valid_base_directory(argstr)
X char *argstr;
X {
X register char *rp;
X register char *dp;
X char wpath[MAXNAMLEN];
X char lastchar;
X struct restricted_dirs *pt;
X
X /*
X ** First check to see if the base directory is any
X ** character other than a slash. We need to assure
X ** that "../../../etc" or ./etc is not allowed. We
X ** need a valid absolute path with which to do relative
X ** path addressing. (Have I confused myself yet ?)
X */
X
X if (*argstr != '/')
X return(FALSE);
X
X /*
X ** Strip the string of duplicate '/'s.
X ** Also check to assure that the path specified
X ** does not contain the '..' sequence.
X */
X
X dp = argstr;
X rp = wpath;
X lastchar = ' ';
X
X while (*dp) {
X if (*dp != '/' || lastchar != '/') {
X lastchar = *dp;
X *rp++ = *dp;
X }
X if (*dp == '.' && lastchar == '.') {
X if ((*(dp+1) == '/') || (*(dp+1) == '\0'))
X return(FALSE);
X }
X ++dp;
X }
X *rp = '\0';
X
X /*
X ** strip the string of trailing '/'s so
X ** I can use the simple checking below.
X */
X
X dp = wpath+(strlen(wpath)-1);
X while(*dp == '/' && dp > wpath)
X *dp = '\0';
X
X /*
X ** check if they match
X */
X
X pt = &base_dirs[0];
X while ((pt->dirstr) != NULL) {
X
X if (strcmp(wpath, pt->dirstr) == 0)
X return(FALSE);
X
X pt++;
X }
X return(TRUE);
X}
X
Xvoid get_archive_basedir(s)
Xchar *s;
X{
X (void) strcpy(group[num].location, strstrip(s));
X
X if (!valid_base_directory(group[num].location))
X error(group[num].ng_name," - Invalid archive base directory!");
X}
X
Xint correct_modes(s,mode_string)
Xchar *s;
Xchar *mode_string;
X{
X register int c;
X register int i;
X
X i = 0;
X (void) sscanf(s, "%s", mode_string);
X while ((c = *mode_string++) >= '0' && c <= '7')
X i = (i << 3) + (c - '0');
X mode_string--;
X return(i);
X}
X
X
Xchar *get_cmd(cmd)
Xchar *cmd;
X{
X static char *rp;
X char *kp;
X
X rp = strstrip(cmd);
X
X /*
X ** Here an external command needs to be verified.
X ** To do so, the options must be removed. I am being
X ** real lazy here but what the hey..
X ** If a space is found after the cmdline is striped
X ** put a null there and then replace it with a
X ** space after the check...
X */
X
X if ((kp = strchr(rp,' ')) != NULL)
X *kp = '\0';
X else if ((kp = strchr(rp,'\t')) != NULL)
X *kp = '\0';
X
X /* need to assure the user has specified */
X /* a valid executable path. */
X
X if (stat(rp, &stbuf) != 0)
X error("Can't find specified command -", rp);
X
X if (kp != NULL) /* replace the space.. */
X *kp = ' ';
X
X return(rp);
X}
X
X#ifdef NNTP
Xchar *getnntp(loc)
Xchar *loc;
X{
X static char *rp;
X
X rp = strstrip(loc);
X
X /*
X ** check to assure that the user does not wish to negate
X ** a global declaration for the nntp server.
X */
X
X if ((strncmp(rp,"LOCAL",5) == 0) || (strncmp(rp, "local",5) == 0))
X return("");
X
X return(rp);
X}
X#endif /*NNTP*/
X
X
X
Xint get_group(valstr)
Xchar *valstr;
X{
X char *wp;
X struct group *grent;
X struct group *getgrnam();
X
X /* group specified by names but */
X /* needs to be numbers */
X
X wp = strstrip(valstr);
X
X if ((grent = getgrnam(wp)) == NULL)
X error("Invalid system group:",wp);
X return(grent->gr_gid);
X}
X
X
Xint get_owner(valstr)
Xchar *valstr;
X{
X char *wp;
X
X /* owner specified by names but */
X /* needs to be numbers */
X
X wp = strstrip(valstr);
X
X if ((pwent = getpwnam(wp)) == NULL)
X error("Invalid user:",wp);
X return(pwent->pw_uid);
X}
X
Xint get_archive_type(ngname, s)
Xchar *ngname;
Xchar *s;
X{
X int return_type = default_type;
X
X if (strcmp(s, "Archive-Name") == 0)
X return_type = ARCHIVE_NAME;
X else if (strcmp(s, "Volume-Issue") == 0)
X return_type = VOLUME_ISSUE;
X else if (strcmp(s, "Chronological") == 0)
X return_type = CHRONOLOGICAL;
X else if (strcmp(s, "Article-Number") == 0)
X return_type = ARTICLE_NUMBER;
X else if (strcmp(s, "Comp-Archives") == 0)
X return_type = COMP_ARCHIVES;
X else if (strcmp(s, "External-Command") == 0)
X return_type = EXTERNAL_COMMAND;
X else if (strcmp(s, "Only-Archive-Name") == 0)
X return_type = ONLY_ARCHIVE_NAME;
X else {
X (void) fprintf(errfp,"%s: %s: %s %s\n", progname,
X ngname, "Invalid Archive Type:", s);
X (void) fprintf(errfp,"\tTYPE Must be %s, %s, %s, %s, %s, %s or %s\n",
X "Archive-Name", "Volume-Issue", "Comp-Archives",
X "External-Command", "Only-Archive-Name",
X "Chronological", "Article-Number");
X exit(1);
X }
X return(return_type);
X}
X
Xvoid get_spooldir(s)
Xchar *s;
X{
X static char *rp;
X
X rp = strstrip(s);
X
X /* need to assure the user has specified */
X /* a valid directory path for the base */
X /* directory for the news subsystem.. */
X
X if (stat(rp, &stbuf) != 0)
X error("Can't find SPOOLDIR -", rp);
X
X (void) strcpy(spooldir, rp);
X}
X
Xchar *get_users(s)
Xchar *s;
X{
X char *strcat();
X
X static char users[512];
X char tmp_users[512];
X char *list, *name;
X char *cp, *dp;
X register int i;
X
X /* prepare the string for saving by stripping any spaces */
X
X for (i = 0; i < sizeof users; i++)
X users[i] = '\0';
X
X cp = s;
X dp = users;
X while (*cp) {
X if (*cp != ' ' && *cp != '\t')
X *dp++ = *cp;
X ++cp;
X }
X
X /* Need to check the specified user list */
X /* to assure that all users are valid. */
X
X (void) strcpy(tmp_users, users);
X *users = '\0';
X
X name = tmp_users;
X
X while (name != NULL) {
X /* is there additional users specified ? */
X if ((list = strchr(name,',')) != NULL) {
X list++;
X *(list-1) = '\0';
X }
X
X#ifdef CHECK_LOGNAME
X /* check if user is found in passwd file */
X if ((pwent = getpwnam(name)) == NULL)
X error("Invalid user:",name);
X#endif /* CHECK_LOGNAME */
X
X if (*users != '\0') {
X (void) strcat(users, ",");
X (void) strcat(users, name);
X }
X else
X (void) strcpy(users, name);
X name = list;
X }
X return(users);
X}
X
X/*
X** get a specified format from the buffer
X** Must allow for spaces and tabs so they
X** need to be passed intact in the format.
X*/
Xchar *sav_format(s)
X char *s;
X{
X static char *cp;
X char *dp;
X
X if ((cp = strchr(s,'"')) != NULL &&
X (dp = strchr(++cp,'"')) != NULL) {
X *dp = '\0';
X }
X else
X cp = NULL;
X return(cp);
X}
X
Xint get_patch_type(ngname,s)
Xchar *ngname;
Xchar *s;
X{
X int return_type = default_type;
X
X if (strcmp(s, "Package") == 0)
X return_type = PACKAGE;
X else if (strcmp(s, "Historical") == 0)
X return_type = HISTORICAL;
X else {
X (void) fprintf(errfp,"%s: %s: %s %s\n", progname,
X ngname, "Invalid Patches Type:", s);
X (void) fprintf(errfp,"\tPATCHES Must be %s, or %s\n",
X "Historical", "Package");
X exit(1);
X }
X return(return_type);
X}
END_OF_FILE
if test 23815 -ne `wc -c <'rkive/setup.c'`; then
echo shar: \"'rkive/setup.c'\" unpacked with wrong size!
fi
# end of 'rkive/setup.c'
fi
echo shar: End of archive 2 \(of 6\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 6 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
exit 0 # Just in case...
--
Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD UUCP: uunet!sparky!kent
Phone: (402) 291-8300 FAX: (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.