12150Seric # include "../hdr/defines.h"
22150Seric # include "../hdr/had.h"
32150Seric
4*33423Sbostic static char Sccsid[] = "@(#)rmchg.c 4.4 02/02/88";
52150Seric
62150Seric /*
72150Seric Program to remove a specified delta from an SCCS file,
82150Seric when invoked as 'rmdel',
92150Seric or to change the MRs and/or comments of a specified delta,
102150Seric when invoked as 'chghist'.
112150Seric (The program has two links to it, one called 'rmdel', the
122150Seric other 'chghist'.)
132150Seric
142150Seric The delta to be removed (or whose MRs and/or comments
152150Seric are to be changed) is specified via the
162150Seric r argument, in the form of an SID.
172150Seric
182150Seric If the delta is to be removed, it must be the most recent one
192150Seric in its branch in the delta tree (a so-called 'leaf' delta).
202150Seric For either function, the delta being processed must not
212150Seric have any 'delivered' MRs, and the user must have basically
222150Seric the same permissions as are required to make deltas.
232150Seric
242150Seric If a directory is given as an argument, each SCCS file
252150Seric within the directory will be processed as if it had been
262150Seric specifically named. If a name of '-' is given, the standard
272150Seric input will be read for a list of names of SCCS files to be
282150Seric processed. Non SCCS files are ignored.
292150Seric */
302150Seric
312150Seric # define COPY 0
322150Seric # define NOCOPY 1
332150Seric
342150Seric struct sid sid;
352150Seric int num_files;
362150Seric char had[26];
372150Seric char D_type;
382150Seric int D_serial;
392150Seric
main(argc,argv)402150Seric main(argc,argv)
412150Seric int argc;
422150Seric char *argv[];
432150Seric {
442150Seric register int i;
452150Seric register char *p;
462150Seric char c;
472150Seric extern rmchg();
482150Seric extern int Fcnt;
492150Seric
502150Seric /*
512150Seric Set flags for 'fatal' to issue message, call clean-up
522150Seric routine, and terminate processing.
532150Seric */
542150Seric Fflags = FTLMSG | FTLCLN | FTLEXIT;
552150Seric
562150Seric for(i=1; i<argc; i++)
572150Seric if(argv[i][0] == '-' && (c = argv[i][1])) {
582150Seric p = &argv[i][2];
592150Seric switch (c) {
602150Seric
612150Seric case 'r':
622150Seric if (!(*p))
632150Seric fatal("r has no sid (rc11)");
642150Seric chksid(sid_ab(p,&sid),&sid);
652150Seric break;
662150Seric default:
672150Seric fatal("unknown key letter (cm1)");
682150Seric }
692150Seric
702150Seric if (had[c - 'a']++)
712150Seric fatal("key letter twice (cm2)");
722150Seric argv[i] = 0;
732150Seric }
742150Seric else
752150Seric num_files++;
762150Seric
772150Seric if(num_files == 0)
782150Seric fatal("missing file arg (cm3)");
792150Seric
802150Seric if (*(p = sname(argv[0])) == 'n')
812150Seric p++;
822150Seric if (equal(p,"rmdel"))
832150Seric D_type = 'R'; /* invoked as 'rmdel' */
842150Seric else if (equal(p,"chghist"))
852150Seric D_type = 'D'; /* invoked as 'chghist' */
862150Seric else
872150Seric fatal("bad invocation (rc10)");
882150Seric
892150Seric setsig();
902150Seric
912150Seric /*
922150Seric Change flags for 'fatal' so that it will return to this
932150Seric routine (main) instead of terminating processing.
942150Seric */
9530499Slepreau Fflags &= ~FTLEXIT;
9630499Slepreau Fflags |= FTLJMP;
972150Seric
982150Seric /*
992150Seric Call 'rmchg' routine for each file argument.
1002150Seric */
1012150Seric for (i=1; i<argc; i++)
1022150Seric if (p = argv[i])
1032150Seric do_file(p,rmchg);
1042150Seric
1052150Seric exit(Fcnt ? 1 : 0);
1062150Seric }
1072150Seric
1082150Seric
1092150Seric /*
1102150Seric Routine that actually causes processing of the delta.
1112150Seric Processing on the file takes place on a
1122150Seric temporary copy of the SCCS file (the x-file).
1132150Seric The name of the x-file is the same as that of the
1142150Seric s-file (SCCS file) with the 's.' replaced by 'x.'.
1152150Seric At end of processing, the s-file is removed
1162150Seric and the x-file is renamed with the name of the old s-file.
1172150Seric
1182150Seric This routine makes use of the z-file to lock out simultaneous
1192150Seric updates to the SCCS file by more than one user.
1202150Seric */
1212150Seric
1222150Seric struct packet gpkt; /* see file s.h */
1232150Seric char line[BUFSIZ];
1242150Seric char *Mrs;
1252150Seric char *Comments;
1262150Seric int Domrs;
1272150Seric
1282150Seric USXALLOC(); /* defines alloc() and free() */
1292150Seric
rmchg(file)1302150Seric rmchg(file)
1312150Seric char *file;
1322150Seric {
13330499Slepreau static int first_time = 1;
1342150Seric struct deltab dt; /* see file s.defines.h */
1352150Seric struct stats stats; /* see file s.defines.h */
1362150Seric extern char *Sflags[];
1372150Seric int n;
1382150Seric char *p, *cp;
1392150Seric int keep;
1402150Seric extern char Pgmr[8];
1412150Seric int fowner, downer, user;
1422150Seric
1432150Seric if (setjmp(Fjmp)) /* set up to return here from 'fatal' */
1442150Seric return; /* and return to caller of rmchg */
1452150Seric
1462150Seric if (!HADR)
1472150Seric fatal("missing r (rc1)");
1482150Seric
1492150Seric if (D_type == 'D' && first_time) {
1502150Seric first_time = 0;
1512150Seric dohist(file);
1522150Seric }
1532150Seric
154*33423Sbostic if (!exists(file)) {
155*33423Sbostic sprintf(Error,"file %s does not exist (rc2)",file);
156*33423Sbostic fatal(Error);
157*33423Sbostic }
1582150Seric
1592150Seric /*
1602150Seric Lock out any other user who may be trying to process
1612150Seric the same file.
1622150Seric */
1632150Seric if (lockit(auxf(file,'z'),2,getpid()))
1642150Seric fatal("cannot create lock file (cm4)");
1652150Seric
1662150Seric sinit(&gpkt,file,1); /* initialize packet and open s-file */
1672150Seric
1682150Seric /*
1692150Seric Flag for 'putline' routine to tell it to open x-file
1702150Seric and allow writing on it.
1712150Seric */
1722150Seric gpkt.p_upd = 1;
1732150Seric
1742150Seric /*
1752150Seric Save requested SID for later checking of
1762150Seric permissions (by 'permiss').
1772150Seric */
17819943Ssam bcopy(&sid,&gpkt.p_reqsid,sizeof(gpkt.p_reqsid));
1792150Seric
1802150Seric /*
1812150Seric Now read-in delta table. The 'dodelt' routine
1822150Seric will read the table and change the delta entry of the
1832150Seric requested SID to be of type 'R' if this is
1842150Seric being executed as 'rmdel'; otherwise, for 'chghist', only
1852150Seric the MR and comments sections will be changed
1862150Seric (by 'escdodelt', called by 'dodelt').
1872150Seric */
1882150Seric if (dodelt(&gpkt,&stats,&sid,D_type) == 0)
1892150Seric fmterr(&gpkt);
1902150Seric
1912150Seric /*
1922150Seric Get serial number of requested SID from
1932150Seric delta table just processed.
1942150Seric */
1952150Seric D_serial = sidtoser(&gpkt.p_reqsid,&gpkt);
1962150Seric
1972150Seric /*
1982150Seric If SID has not been zeroed (by 'dodelt'),
1992150Seric SID was not found in file.
2002150Seric */
2012150Seric if (sid.s_rel != 0)
2022150Seric fatal("nonexistent sid (rc3)");
2032150Seric /*
2042150Seric Replace 'sid' with original 'sid'
2052150Seric requested.
2062150Seric */
20719943Ssam bcopy(&gpkt.p_reqsid,&sid,sizeof(gpkt.p_reqsid));
2082150Seric
2092150Seric /*
2102150Seric Now check permissions.
2112150Seric */
2122150Seric finduser(&gpkt);
2132150Seric doflags(&gpkt);
2142150Seric permiss(&gpkt);
2152150Seric
2162150Seric /*
2172150Seric Check that user is either owner of file or
2182150Seric directory, or is one who made the delta.
2192150Seric */
2202150Seric fstat(fileno(gpkt.p_iop),&Statbuf);
2212150Seric fowner = Statbuf.st_uid & 0377;
2222150Seric copy(gpkt.p_file,line); /* temporary for dname() */
2232150Seric if (stat(dname(line),&Statbuf))
2242150Seric downer = -1;
2252150Seric else
2262150Seric downer = Statbuf.st_uid & 0377;
2272150Seric user = getuid() & 0377;
2282150Seric if (user != fowner || user != downer)
229*33423Sbostic if (!equal(Pgmr,logname())) {
230*33423Sbostic sprintf(Error, "you are neither owner nor '%s' (rc4)",Pgmr);
231*33423Sbostic fatal(Error);
232*33423Sbostic }
2332150Seric
2342150Seric /*
2352150Seric For 'rmdel', check that delta being removed is a
2362150Seric 'leaf' delta, and if ok,
2372150Seric process the body.
2382150Seric */
2392150Seric if (D_type == 'R') {
2402150Seric for (n = maxser(&gpkt); n > D_serial; n--) {
2412150Seric p = &gpkt.p_idel[n];
2422150Seric if (p->i_pred == D_serial)
2432150Seric fatal("not a 'leaf' delta (rc5)");
2442150Seric }
2452150Seric
2462150Seric /*
2472150Seric For 'rmdel' check that the sid requested is
2482150Seric not contained in p-file, should a p-file
2492150Seric exist.
2502150Seric */
2512150Seric
2522150Seric if (exists(auxf(gpkt.p_file,'p')))
2532150Seric rdpfile(&gpkt,&sid);
2542150Seric
2552150Seric flushto(&gpkt,EUSERTXT,COPY);
2562150Seric
2572150Seric keep = YES;
2582150Seric gpkt.p_chkeof = 1; /* set EOF is ok */
2592150Seric while ((p = getline(&gpkt)) != NULL) {
2602150Seric if (*p++ == CTLCHAR) {
2612150Seric cp = p++;
2622150Seric NONBLANK(p);
2632150Seric /*
2642150Seric Convert serial number to binary.
2652150Seric */
2662150Seric if (*(p = satoi(p,&n)) != '\n')
2672150Seric fmterr(&gpkt);
2682150Seric if (n == D_serial) {
2692150Seric gpkt.p_wrttn = 1;
2702150Seric if (*cp == INS)
2712150Seric keep = NO;
2722150Seric else
2732150Seric keep = YES;
2742150Seric }
2752150Seric }
2762150Seric else
2772150Seric if (keep == NO)
2782150Seric gpkt.p_wrttn = 1;
2792150Seric }
2802150Seric }
2812150Seric else {
2822150Seric /*
2832150Seric This is for invocation as 'chghist'.
2842150Seric Check MRs.
2852150Seric */
2862150Seric if (Mrs) {
2872150Seric if (!(p = Sflags[VALFLAG - 'a']))
2882150Seric fatal("MRs not allowed (rc6)");
2892150Seric if (*p && valmrs(&gpkt,p))
2902150Seric fatal("inavlid MRs (rc7)");
2912150Seric }
2922150Seric else
2932150Seric if (Sflags[VALFLAG - 'a'])
2942150Seric fatal("MRs required (rc8)");
2952150Seric
2962150Seric /*
2972150Seric Indicate that EOF at this point is ok, and
2982150Seric flush rest of s-file to x-file.
2992150Seric */
3002150Seric gpkt.p_chkeof = 1;
3012150Seric while (getline(&gpkt))
3022150Seric ;
3032150Seric }
3042150Seric
3052150Seric flushline(&gpkt,0);
3062150Seric
3072150Seric /*
3082150Seric Delete old s-file, change x-file name to s-file.
3092150Seric */
3102150Seric rename(auxf(&gpkt,'x'),&gpkt);
3112150Seric
3122150Seric clean_up();
3132150Seric }
3142150Seric
3152150Seric
3162150Seric escdodelt(pkt)
3172150Seric struct packet *pkt;
3182150Seric {
3192150Seric extern int First_esc;
3202150Seric char *p;
3212150Seric extern long Timenow;
3222150Seric
3232150Seric if (D_type == 'D' && First_esc) { /* chghist, first time */
3242150Seric First_esc = 0;
3252150Seric if (Mrs)
3262150Seric putmrs(pkt);
3272150Seric
328*33423Sbostic sprintf(line,"%c%c ",CTLCHAR,COMMENTS);
329*33423Sbostic putline(pkt,line);
3302150Seric putline(pkt,Comments);
3312150Seric putline(pkt,"\n");
332*33423Sbostic sprintf(line,"%c%c ",CTLCHAR,COMMENTS);
333*33423Sbostic putline(pkt,line);
3342150Seric putline(pkt,"*** CHANGED *** ");
3352150Seric date_ba(&Timenow,line); /* get date and time */
3362150Seric putline(pkt,line);
337*33423Sbostic sprintf(line," %s\n",logname());
338*33423Sbostic putline(pkt,line);
3392150Seric }
3402150Seric
3412150Seric if (pkt->p_line[1] == MRNUM) {
3422150Seric p = &pkt->p_line;
3432150Seric while (*p)
3442150Seric p++;
3452150Seric if (*(p - 2) == DELIVER)
3462150Seric fatal("delta specified has delivered MR (rc9)");
3472150Seric
3482150Seric if (D_type == 'D') /* turn MRs into comments */
3492150Seric pkt->p_line[1] = COMMENTS;
3502150Seric }
3512150Seric }
3522150Seric
3532150Seric
3542150Seric putmrs(pkt)
3552150Seric struct packet *pkt;
3562150Seric {
3572150Seric register char **argv;
3582150Seric char str[64];
3592150Seric extern char *Varg[];
3602150Seric
361*33423Sbostic for (argv = &Varg[VSTART]; *argv; argv++) {
362*33423Sbostic sprintf(str,"%c%c %s\n",CTLCHAR,MRNUM,*argv);
363*33423Sbostic putline(pkt,str);
364*33423Sbostic }
3652150Seric }
3662150Seric
3672150Seric
clean_up()3682150Seric clean_up()
3692150Seric {
3702150Seric xrm(&gpkt);
3712150Seric if (gpkt.p_file[0])
3722150Seric unlockit(auxf(gpkt.p_file,'z'),getpid());
3732150Seric if (exists(auxf(gpkt.p_file,'x')))
3742150Seric xunlink(auxf(gpkt.p_file,'x'));
3752150Seric xfreeall();
3762150Seric }
3772150Seric
3782150Seric
rdpfile(pkt,sp)3792150Seric rdpfile(pkt,sp)
3802150Seric register struct packet *pkt;
3812150Seric struct sid *sp;
3822150Seric {
3832150Seric struct pfile pf;
3842150Seric char line[BUFSIZ];
3852150Seric FILE *in;
3862150Seric
3872150Seric in = xfopen(auxf(pkt->p_file,'p'),0);
3882150Seric while (fgets(line,sizeof(line),in) != NULL) {
3892150Seric pf_ab(line,&pf,1);
3902150Seric if (sp->s_rel == pf.pf_gsid.s_rel &&
3912150Seric sp->s_lev == pf.pf_gsid.s_lev &&
3922150Seric sp->s_br == pf.pf_gsid.s_br &&
3932150Seric sp->s_seq == pf.pf_gsid.s_seq) {
3942150Seric fclose(in);
3952150Seric fatal("being edited -- sid is in p-file (rc12)");
3962150Seric }
3972150Seric }
3982150Seric fclose(in);
3992150Seric return;
4002150Seric }
401