1e9989320Seric # include "../hdr/defines.h"
2e9989320Seric # include "../hdr/had.h"
3e9989320Seric
4*a8a1d217Skarels static char Sccsid[] = "@(#)rmchg.c 4.5 08/23/90";
5e9989320Seric
6e9989320Seric /*
7e9989320Seric Program to remove a specified delta from an SCCS file,
8e9989320Seric when invoked as 'rmdel',
9e9989320Seric or to change the MRs and/or comments of a specified delta,
10e9989320Seric when invoked as 'chghist'.
11e9989320Seric (The program has two links to it, one called 'rmdel', the
12e9989320Seric other 'chghist'.)
13e9989320Seric
14e9989320Seric The delta to be removed (or whose MRs and/or comments
15e9989320Seric are to be changed) is specified via the
16e9989320Seric r argument, in the form of an SID.
17e9989320Seric
18e9989320Seric If the delta is to be removed, it must be the most recent one
19e9989320Seric in its branch in the delta tree (a so-called 'leaf' delta).
20e9989320Seric For either function, the delta being processed must not
21e9989320Seric have any 'delivered' MRs, and the user must have basically
22e9989320Seric the same permissions as are required to make deltas.
23e9989320Seric
24e9989320Seric If a directory is given as an argument, each SCCS file
25e9989320Seric within the directory will be processed as if it had been
26e9989320Seric specifically named. If a name of '-' is given, the standard
27e9989320Seric input will be read for a list of names of SCCS files to be
28e9989320Seric processed. Non SCCS files are ignored.
29e9989320Seric */
30e9989320Seric
31e9989320Seric # define COPY 0
32e9989320Seric # define NOCOPY 1
33e9989320Seric
34e9989320Seric struct sid sid;
35e9989320Seric int num_files;
36e9989320Seric char had[26];
37e9989320Seric char D_type;
38e9989320Seric int D_serial;
39e9989320Seric
main(argc,argv)40e9989320Seric main(argc,argv)
41e9989320Seric int argc;
42e9989320Seric char *argv[];
43e9989320Seric {
44e9989320Seric register int i;
45e9989320Seric register char *p;
46e9989320Seric char c;
47e9989320Seric extern rmchg();
48e9989320Seric extern int Fcnt;
49e9989320Seric
50e9989320Seric /*
51e9989320Seric Set flags for 'fatal' to issue message, call clean-up
52e9989320Seric routine, and terminate processing.
53e9989320Seric */
54e9989320Seric Fflags = FTLMSG | FTLCLN | FTLEXIT;
55e9989320Seric
56e9989320Seric for(i=1; i<argc; i++)
57e9989320Seric if(argv[i][0] == '-' && (c = argv[i][1])) {
58e9989320Seric p = &argv[i][2];
59e9989320Seric switch (c) {
60e9989320Seric
61e9989320Seric case 'r':
62e9989320Seric if (!(*p))
63e9989320Seric fatal("r has no sid (rc11)");
64e9989320Seric chksid(sid_ab(p,&sid),&sid);
65e9989320Seric break;
66e9989320Seric default:
67e9989320Seric fatal("unknown key letter (cm1)");
68e9989320Seric }
69e9989320Seric
70e9989320Seric if (had[c - 'a']++)
71e9989320Seric fatal("key letter twice (cm2)");
72e9989320Seric argv[i] = 0;
73e9989320Seric }
74e9989320Seric else
75e9989320Seric num_files++;
76e9989320Seric
77e9989320Seric if(num_files == 0)
78e9989320Seric fatal("missing file arg (cm3)");
79e9989320Seric
80e9989320Seric if (*(p = sname(argv[0])) == 'n')
81e9989320Seric p++;
82e9989320Seric if (equal(p,"rmdel"))
83e9989320Seric D_type = 'R'; /* invoked as 'rmdel' */
84e9989320Seric else if (equal(p,"chghist"))
85e9989320Seric D_type = 'D'; /* invoked as 'chghist' */
86e9989320Seric else
87e9989320Seric fatal("bad invocation (rc10)");
88e9989320Seric
89e9989320Seric setsig();
90e9989320Seric
91e9989320Seric /*
92e9989320Seric Change flags for 'fatal' so that it will return to this
93e9989320Seric routine (main) instead of terminating processing.
94e9989320Seric */
958be0c981Slepreau Fflags &= ~FTLEXIT;
968be0c981Slepreau Fflags |= FTLJMP;
97e9989320Seric
98e9989320Seric /*
99e9989320Seric Call 'rmchg' routine for each file argument.
100e9989320Seric */
101e9989320Seric for (i=1; i<argc; i++)
102e9989320Seric if (p = argv[i])
103e9989320Seric do_file(p,rmchg);
104e9989320Seric
105e9989320Seric exit(Fcnt ? 1 : 0);
106e9989320Seric }
107e9989320Seric
108e9989320Seric
109e9989320Seric /*
110e9989320Seric Routine that actually causes processing of the delta.
111e9989320Seric Processing on the file takes place on a
112e9989320Seric temporary copy of the SCCS file (the x-file).
113e9989320Seric The name of the x-file is the same as that of the
114e9989320Seric s-file (SCCS file) with the 's.' replaced by 'x.'.
115e9989320Seric At end of processing, the s-file is removed
116e9989320Seric and the x-file is renamed with the name of the old s-file.
117e9989320Seric
118e9989320Seric This routine makes use of the z-file to lock out simultaneous
119e9989320Seric updates to the SCCS file by more than one user.
120e9989320Seric */
121e9989320Seric
122e9989320Seric struct packet gpkt; /* see file s.h */
123e9989320Seric char line[BUFSIZ];
124e9989320Seric char *Mrs;
125e9989320Seric char *Comments;
126e9989320Seric int Domrs;
127e9989320Seric
128e9989320Seric USXALLOC(); /* defines alloc() and free() */
129e9989320Seric
rmchg(file)130e9989320Seric rmchg(file)
131e9989320Seric char *file;
132e9989320Seric {
1338be0c981Slepreau static int first_time = 1;
134e9989320Seric struct deltab dt; /* see file s.defines.h */
135e9989320Seric struct stats stats; /* see file s.defines.h */
136e9989320Seric extern char *Sflags[];
137e9989320Seric int n;
138e9989320Seric char *p, *cp;
139e9989320Seric int keep;
140e9989320Seric extern char Pgmr[8];
141e9989320Seric int fowner, downer, user;
142e9989320Seric
143e9989320Seric if (setjmp(Fjmp)) /* set up to return here from 'fatal' */
144e9989320Seric return; /* and return to caller of rmchg */
145e9989320Seric
146e9989320Seric if (!HADR)
147e9989320Seric fatal("missing r (rc1)");
148e9989320Seric
149e9989320Seric if (D_type == 'D' && first_time) {
150e9989320Seric first_time = 0;
151e9989320Seric dohist(file);
152e9989320Seric }
153e9989320Seric
154824dd99bSbostic if (!exists(file)) {
155824dd99bSbostic sprintf(Error,"file %s does not exist (rc2)",file);
156824dd99bSbostic fatal(Error);
157824dd99bSbostic }
158e9989320Seric
159e9989320Seric /*
160e9989320Seric Lock out any other user who may be trying to process
161e9989320Seric the same file.
162e9989320Seric */
163e9989320Seric if (lockit(auxf(file,'z'),2,getpid()))
164e9989320Seric fatal("cannot create lock file (cm4)");
165e9989320Seric
166e9989320Seric sinit(&gpkt,file,1); /* initialize packet and open s-file */
167e9989320Seric
168e9989320Seric /*
169e9989320Seric Flag for 'putline' routine to tell it to open x-file
170e9989320Seric and allow writing on it.
171e9989320Seric */
172e9989320Seric gpkt.p_upd = 1;
173e9989320Seric
174e9989320Seric /*
175e9989320Seric Save requested SID for later checking of
176e9989320Seric permissions (by 'permiss').
177e9989320Seric */
178f7460627Ssam bcopy(&sid,&gpkt.p_reqsid,sizeof(gpkt.p_reqsid));
179e9989320Seric
180e9989320Seric /*
181e9989320Seric Now read-in delta table. The 'dodelt' routine
182e9989320Seric will read the table and change the delta entry of the
183e9989320Seric requested SID to be of type 'R' if this is
184e9989320Seric being executed as 'rmdel'; otherwise, for 'chghist', only
185e9989320Seric the MR and comments sections will be changed
186e9989320Seric (by 'escdodelt', called by 'dodelt').
187e9989320Seric */
188e9989320Seric if (dodelt(&gpkt,&stats,&sid,D_type) == 0)
189e9989320Seric fmterr(&gpkt);
190e9989320Seric
191e9989320Seric /*
192e9989320Seric Get serial number of requested SID from
193e9989320Seric delta table just processed.
194e9989320Seric */
195e9989320Seric D_serial = sidtoser(&gpkt.p_reqsid,&gpkt);
196e9989320Seric
197e9989320Seric /*
198e9989320Seric If SID has not been zeroed (by 'dodelt'),
199e9989320Seric SID was not found in file.
200e9989320Seric */
201e9989320Seric if (sid.s_rel != 0)
202e9989320Seric fatal("nonexistent sid (rc3)");
203e9989320Seric /*
204e9989320Seric Replace 'sid' with original 'sid'
205e9989320Seric requested.
206e9989320Seric */
207f7460627Ssam bcopy(&gpkt.p_reqsid,&sid,sizeof(gpkt.p_reqsid));
208e9989320Seric
209e9989320Seric /*
210e9989320Seric Now check permissions.
211e9989320Seric */
212e9989320Seric finduser(&gpkt);
213e9989320Seric doflags(&gpkt);
214e9989320Seric permiss(&gpkt);
215e9989320Seric
216e9989320Seric /*
217e9989320Seric Check that user is either owner of file or
218e9989320Seric directory, or is one who made the delta.
219e9989320Seric */
220e9989320Seric fstat(fileno(gpkt.p_iop),&Statbuf);
221e9989320Seric fowner = Statbuf.st_uid & 0377;
222e9989320Seric copy(gpkt.p_file,line); /* temporary for dname() */
223e9989320Seric if (stat(dname(line),&Statbuf))
224e9989320Seric downer = -1;
225e9989320Seric else
226e9989320Seric downer = Statbuf.st_uid & 0377;
227e9989320Seric user = getuid() & 0377;
228e9989320Seric if (user != fowner || user != downer)
229824dd99bSbostic if (!equal(Pgmr,logname())) {
230824dd99bSbostic sprintf(Error, "you are neither owner nor '%s' (rc4)",Pgmr);
231824dd99bSbostic fatal(Error);
232824dd99bSbostic }
233e9989320Seric
234e9989320Seric /*
235e9989320Seric For 'rmdel', check that delta being removed is a
236e9989320Seric 'leaf' delta, and if ok,
237e9989320Seric process the body.
238e9989320Seric */
239e9989320Seric if (D_type == 'R') {
240e9989320Seric for (n = maxser(&gpkt); n > D_serial; n--) {
241e9989320Seric p = &gpkt.p_idel[n];
242*a8a1d217Skarels if (((struct idel *)p)->i_pred == D_serial)
243e9989320Seric fatal("not a 'leaf' delta (rc5)");
244e9989320Seric }
245e9989320Seric
246e9989320Seric /*
247e9989320Seric For 'rmdel' check that the sid requested is
248e9989320Seric not contained in p-file, should a p-file
249e9989320Seric exist.
250e9989320Seric */
251e9989320Seric
252e9989320Seric if (exists(auxf(gpkt.p_file,'p')))
253e9989320Seric rdpfile(&gpkt,&sid);
254e9989320Seric
255e9989320Seric flushto(&gpkt,EUSERTXT,COPY);
256e9989320Seric
257e9989320Seric keep = YES;
258e9989320Seric gpkt.p_chkeof = 1; /* set EOF is ok */
259e9989320Seric while ((p = getline(&gpkt)) != NULL) {
260e9989320Seric if (*p++ == CTLCHAR) {
261e9989320Seric cp = p++;
262e9989320Seric NONBLANK(p);
263e9989320Seric /*
264e9989320Seric Convert serial number to binary.
265e9989320Seric */
266e9989320Seric if (*(p = satoi(p,&n)) != '\n')
267e9989320Seric fmterr(&gpkt);
268e9989320Seric if (n == D_serial) {
269e9989320Seric gpkt.p_wrttn = 1;
270e9989320Seric if (*cp == INS)
271e9989320Seric keep = NO;
272e9989320Seric else
273e9989320Seric keep = YES;
274e9989320Seric }
275e9989320Seric }
276e9989320Seric else
277e9989320Seric if (keep == NO)
278e9989320Seric gpkt.p_wrttn = 1;
279e9989320Seric }
280e9989320Seric }
281e9989320Seric else {
282e9989320Seric /*
283e9989320Seric This is for invocation as 'chghist'.
284e9989320Seric Check MRs.
285e9989320Seric */
286e9989320Seric if (Mrs) {
287e9989320Seric if (!(p = Sflags[VALFLAG - 'a']))
288e9989320Seric fatal("MRs not allowed (rc6)");
289e9989320Seric if (*p && valmrs(&gpkt,p))
290e9989320Seric fatal("inavlid MRs (rc7)");
291e9989320Seric }
292e9989320Seric else
293e9989320Seric if (Sflags[VALFLAG - 'a'])
294e9989320Seric fatal("MRs required (rc8)");
295e9989320Seric
296e9989320Seric /*
297e9989320Seric Indicate that EOF at this point is ok, and
298e9989320Seric flush rest of s-file to x-file.
299e9989320Seric */
300e9989320Seric gpkt.p_chkeof = 1;
301e9989320Seric while (getline(&gpkt))
302e9989320Seric ;
303e9989320Seric }
304e9989320Seric
305e9989320Seric flushline(&gpkt,0);
306e9989320Seric
307e9989320Seric /*
308e9989320Seric Delete old s-file, change x-file name to s-file.
309e9989320Seric */
310e9989320Seric rename(auxf(&gpkt,'x'),&gpkt);
311e9989320Seric
312e9989320Seric clean_up();
313e9989320Seric }
314e9989320Seric
315e9989320Seric
316e9989320Seric escdodelt(pkt)
317e9989320Seric struct packet *pkt;
318e9989320Seric {
319e9989320Seric extern int First_esc;
320e9989320Seric char *p;
321e9989320Seric extern long Timenow;
322e9989320Seric
323e9989320Seric if (D_type == 'D' && First_esc) { /* chghist, first time */
324e9989320Seric First_esc = 0;
325e9989320Seric if (Mrs)
326e9989320Seric putmrs(pkt);
327e9989320Seric
328824dd99bSbostic sprintf(line,"%c%c ",CTLCHAR,COMMENTS);
329824dd99bSbostic putline(pkt,line);
330e9989320Seric putline(pkt,Comments);
331e9989320Seric putline(pkt,"\n");
332824dd99bSbostic sprintf(line,"%c%c ",CTLCHAR,COMMENTS);
333824dd99bSbostic putline(pkt,line);
334e9989320Seric putline(pkt,"*** CHANGED *** ");
335e9989320Seric date_ba(&Timenow,line); /* get date and time */
336e9989320Seric putline(pkt,line);
337824dd99bSbostic sprintf(line," %s\n",logname());
338824dd99bSbostic putline(pkt,line);
339e9989320Seric }
340e9989320Seric
341e9989320Seric if (pkt->p_line[1] == MRNUM) {
342e9989320Seric p = &pkt->p_line;
343e9989320Seric while (*p)
344e9989320Seric p++;
345e9989320Seric if (*(p - 2) == DELIVER)
346e9989320Seric fatal("delta specified has delivered MR (rc9)");
347e9989320Seric
348e9989320Seric if (D_type == 'D') /* turn MRs into comments */
349e9989320Seric pkt->p_line[1] = COMMENTS;
350e9989320Seric }
351e9989320Seric }
352e9989320Seric
353e9989320Seric
354e9989320Seric putmrs(pkt)
355e9989320Seric struct packet *pkt;
356e9989320Seric {
357e9989320Seric register char **argv;
358e9989320Seric char str[64];
359e9989320Seric extern char *Varg[];
360e9989320Seric
361824dd99bSbostic for (argv = &Varg[VSTART]; *argv; argv++) {
362824dd99bSbostic sprintf(str,"%c%c %s\n",CTLCHAR,MRNUM,*argv);
363824dd99bSbostic putline(pkt,str);
364824dd99bSbostic }
365e9989320Seric }
366e9989320Seric
367e9989320Seric
clean_up()368e9989320Seric clean_up()
369e9989320Seric {
370e9989320Seric xrm(&gpkt);
371e9989320Seric if (gpkt.p_file[0])
372e9989320Seric unlockit(auxf(gpkt.p_file,'z'),getpid());
373e9989320Seric if (exists(auxf(gpkt.p_file,'x')))
374e9989320Seric xunlink(auxf(gpkt.p_file,'x'));
375e9989320Seric xfreeall();
376e9989320Seric }
377e9989320Seric
378e9989320Seric
rdpfile(pkt,sp)379e9989320Seric rdpfile(pkt,sp)
380e9989320Seric register struct packet *pkt;
381e9989320Seric struct sid *sp;
382e9989320Seric {
383e9989320Seric struct pfile pf;
384e9989320Seric char line[BUFSIZ];
385e9989320Seric FILE *in;
386e9989320Seric
387e9989320Seric in = xfopen(auxf(pkt->p_file,'p'),0);
388e9989320Seric while (fgets(line,sizeof(line),in) != NULL) {
389e9989320Seric pf_ab(line,&pf,1);
390e9989320Seric if (sp->s_rel == pf.pf_gsid.s_rel &&
391e9989320Seric sp->s_lev == pf.pf_gsid.s_lev &&
392e9989320Seric sp->s_br == pf.pf_gsid.s_br &&
393e9989320Seric sp->s_seq == pf.pf_gsid.s_seq) {
394e9989320Seric fclose(in);
395e9989320Seric fatal("being edited -- sid is in p-file (rc12)");
396e9989320Seric }
397e9989320Seric }
398e9989320Seric fclose(in);
399e9989320Seric return;
400e9989320Seric }
401