modern syntax for asgops & inits cause Donn's latest ccom rejects the old.
[unix-history] / usr / src / local / sccscmds / sccscmds.ok / cmd / admin.c
CommitLineData
5a89b91c
EA
1# include "../hdr/defines.h"
2# include "../hdr/had.h"
3
38c01699 4static char Sccsid[] = "@(#)admin.c 4.2 %G%";
5a89b91c
EA
5
6/*
7 Program to create new SCCS files and change parameters
8 of existing ones. Arguments to the program may appear in
9 any order and consist of keyletters, which begin with '-',
10 and named files. Named files which do not exist are created
11 and their parameters are initialized according to the given
12 keyletter arguments, or are given default values if the
13 corresponding keyletters were not supplied. Named files which
14 do exist have those parameters corresponding to given key-letter
15 arguments changed and other parameters are left as is.
16
17 If a directory is given as an argument, each SCCS file within
18 the directory is processed as if it had been specifically named.
19 If a name of '-' is given, the standard input is read for a list
20 of names of SCCS files to be processed.
21 Non-SCCS files are ignored.
22
23 Files created are given mode 444.
24*/
25
26# define MINR 1 /* minimum release number */
27# define MAXR 9999 /* maximum release number */
28# define MAXNAMES 9
29# define COPY 0
30# define NOCOPY 1
31
32char *ifile, *tfile;
33char *z; /* for validation program name */
34char had[26], had_flag[26], rm_flag[26];
35char *Comments, *Mrs;
38c01699 36char Valpgm[] = "/usr/local/val";
5a89b91c 37int irel, fexists, num_files;
38c01699 38int VFLAG = 0;
5a89b91c
EA
39int Domrs;
40char *Sflags[];
41char *anames[MAXNAMES], *enames[MAXNAMES];
42char *flag_p[26];
43int asub, esub;
44int check_id;
45int Did_id;
46
47main(argc,argv)
48int argc;
49char *argv[];
50{
51 register int j;
52 register char *p;
53 char c, f;
54 int i, testklt;
55 extern admin();
56 extern int Fcnt;
57 struct sid sid;
58
59 /*
60 Set flags for 'fatal' to issue message, call clean-up
61 routine and terminate processing.
62 */
63 Fflags = FTLMSG | FTLCLN | FTLEXIT;
64
65 testklt = 1;
66
67 /*
68 The following loop processes keyletters and arguments.
69 Note that these are processed only once for each
70 invocation of 'main'.
71 */
72 for(j=1; j<argc; j++)
73 if(argv[j][0] == '-' && (c = argv[j][1])) {
74 p = &argv[j][2];
75 switch (c) {
76
77 case 'i': /* name of file of body */
78 ifile = p;
79 break;
80
81 case 't': /* name of file of descriptive text */
82 tfile = p;
83 break;
84 case 'm': /* mr flag */
85 Mrs = p;
86 break;
87 case 'y': /* comments flag for entry */
88 Comments = p;
89 break;
90
91 case 'd': /* flags to be deleted */
92 testklt = 0;
93 if (!(f = *p))
94 fatal("d has no argument (ad1)");
95 p = &argv[j][3];
96
97 switch (f) {
98
99 case IDFLAG: /* see 'f' keyletter */
100 case BRCHFLAG: /* for meanings of flags */
101 case VALFLAG:
102 case TYPEFLAG:
103 case MODFLAG:
104 case NULLFLAG:
105 case FLORFLAG:
106 case CEILFLAG:
107 case DEFTFLAG:
108 if (*p)
109 fatal(sprintf(Error,
110 "value after %c flag (ad12)",f));
111 break;
112
113 default:
114 fatal("unknown flag (ad3)");
115 }
116
117 if (rm_flag[f - 'a']++)
118 fatal("flag twice (ad4)");
119 break;
120
121 case 'f': /* flags to be added */
122 testklt = 0;
123 if (!(f = *p))
124 fatal("f has no argument (ad5)");
125 p = &argv[j][3];
126
127 switch (f) {
128
129 case IDFLAG: /* id-kwd message (err/warn) */
130 case BRCHFLAG: /* branch */
131 case NULLFLAG: /* null deltas */
132 if (*p)
133 fatal(sprintf(Error,
134 "value after %c flag (ad13)",f));
135 break;
136
137 case VALFLAG: /* mr validation */
138 VFLAG++;
139 if (*p)
140 z = p;
141 break;
142
143 case FLORFLAG: /* floor */
144 if ((i = patoi(p)) == -1)
145 fatal("floor not numeric (ad22)");
146 if ((size(p) > 5) || (i < MINR) ||
147 (i > MAXR))
148 fatal("floor out of range (ad23)");
149 break;
150
151 case CEILFLAG: /* ceiling */
152 if ((i = patoi(p)) == -1)
153 fatal("ceiling not numeric (ad24)");
154 if ((size(p) > 5) || (i < MINR) ||
155 (i > MAXR))
156 fatal("ceiling out of range (ad25)");
157 break;
158
159 case DEFTFLAG: /* default sid */
160 if (!(*p))
161 fatal("no default sid (ad14)");
162 chksid(sid_ab(p,&sid),&sid);
163 break;
164
165 case TYPEFLAG: /* type */
166 case MODFLAG: /* module name */
167 if (!(*p))
168 fatal(sprintf(Error,
169 "flag %c has no value (ad2)",f));
170 break;
171
172 default:
173 fatal("unknown flag (ad3)");
174 }
175
176 if (had_flag[f - 'a']++)
177 fatal("flag twice (ad4)");
178 flag_p[f - 'a'] = p;
179 break;
180
181 case 'r': /* initial release number supplied */
182 if ((irel = patoi(p)) == -1)
183 fatal("r arg not numeric (ad6)");
184 if ((size(p) > 5) || (irel < MINR) ||
185 (irel > MAXR))
186 fatal("r out of range (ad7)");
187 break;
188
189 case 'n': /* creating new SCCS file */
190 case 'h': /* only check hash of file */
191 case 'z': /* zero the input hash */
192 break;
193
194 case 'a': /* user-name allowed to make deltas */
195 testklt = 0;
196 if (!(*p))
197 fatal("bad a argument (ad8)");
198 if (asub > MAXNAMES)
199 fatal("too many 'a' keyletters (ad9)");
200 anames[asub++] = p;
201 break;
202
203 case 'e': /* user-name to be removed */
204 testklt = 0;
205 if (!(*p))
206 fatal("bad e argument (ad10)");
207 if (esub > MAXNAMES)
208 fatal("too many 'e' keyletters (ad11)");
209 enames[esub++] = p;
210 break;
211
212 default:
213 fatal("unknown key letter (cm1)");
214 }
215
216 if (had[c - 'a']++ && testklt++)
217 fatal("key letter twice (cm2)");
218 argv[j] = 0;
219 }
220 else
221 num_files++;
222
223 if (num_files == 0)
224 fatal("missing file arg (cm3)");
225
226 if (HADI && num_files > 1) /* only one file allowed with `i' */
227 fatal("more than one file (ad15)");
228
229 setsig();
230
231 /*
232 Change flags for 'fatal' so that it will return to this
233 routine (main) instead of terminating processing.
234 */
38c01699
JL
235 Fflags &= ~FTLEXIT;
236 Fflags |= FTLJMP;
5a89b91c
EA
237
238 /*
239 Call 'admin' routine for each file argument.
240 */
241 for (j=1; j<argc; j++)
242 if (p = argv[j])
243 do_file(p,admin);
244
245 exit(Fcnt ? 1 : 0);
246}
247
248
249/*
250 Routine that actually does admin's work on SCCS files.
251 Existing s-files are copied, with changes being made, to a
252 temporary file (x-file). The name of the x-file is the same as the
253 name of the s-file, with the 's.' replaced by 'x.'.
254 s-files which are to be created are processed in a similar
255 manner, except that a dummy s-file is first created with
256 mode 444.
257 At end of processing, the x-file is renamed with the name of s-file
258 and the old s-file is removed.
259*/
260
261struct packet gpkt; /* see file defines.h */
262char Zhold[BUFSIZ]; /* temporary z-file name */
263
264USXALLOC(); /* defines alloc() and free() */
265
266admin(afile)
267char *afile;
268{
269 struct deltab dt; /* see file defines.h */
270 struct stats stats; /* see file defines.h */
271 FILE *iptr;
272 register int k;
273 register char *cp, *q;
274 char command[80];
275 char line[512];
276 int i; /* used in forking procedure */
277 int status;
278 extern nfiles;
279 extern had_dir;
280
281 if (setjmp(Fjmp)) /* set up to return here from 'fatal' */
282 return; /* and return to caller of admin */
283
284 if (HADI && had_dir) /* directory not allowed with `i' keyletter */
285 fatal("directory named with `i' keyletter (ad26)");
286
287 fexists = exists(afile);
288
289 if (HADI)
290 HADN = 1;
291 if (HADI || HADN) {
292 if (HADM && !VFLAG)
293 fatal("MRs not allowed (de8)");
294
295 if (VFLAG && !HADM)
296 fatal("MRs required (de10)");
297
298 }
299
300 if (!HADI && HADR)
301 fatal("r only allowed with i (ad16)");
302
303 if (HADN && HADT && !(*tfile))
304 fatal("t has no argument (ad17)");
305
306 if (HADN && HADD)
307 fatal("d not allowed with n (ad18)");
308
309 if (HADN && fexists)
310 fatal(sprintf(Error,"file %s exists (ad19)",afile));
311
312 if (!HADN && !fexists)
313 fatal(sprintf(Error,"file %s does not exist (ad20)",afile));
314 /*
315 Check for '-h' flag. If set, create child process and
316 invoke 'get' to examine format of SCCS file.
317 */
318
319 if (HADH) {
320 /*
321 fork here so 'admin' can execute 'val' to
322 check for a corrupted file.
323 */
324 if ((i = fork()) < 0)
325 fatal("cannot fork, try again");
326 if (i == 0) { /* child */
327 /*
328 perform 'val' with appropriate keyletters
329 */
330 execl("/bin/sh","/bin/sh","-c",
331 sprintf(command,
332 "/usr/local/val -s %s",
333 afile),0);
334 fatal(sprintf(Error,"cannot execute '%s'",Valpgm));
335 }
336 else {
337 wait(&status); /* wait on status from 'execl' */
338 if (status)
339 fatal("corrupted file (co6)");
340 return; /* return to caller of 'admin' */
341 }
342 }
343
344 /*
345 Lock out any other user who may be trying to process
346 the same file.
347 */
348 if (!HADH && lockit(copy(auxf(afile,'z'),Zhold),2,getpid()))
349 fatal("cannot create lock file (cm4)");
350
351 if (fexists)
352 sinit(&gpkt,afile,1); /* init pkt & open s-file */
353 else {
354 xfcreat(afile,0444); /* create dummy s-file */
355 sinit(&gpkt,afile,0); /* and init pkt */
356 }
357
358 if (!HADH)
359 /*
360 set the flag for 'putline' routine to open
361 the 'x-file' and allow writing on it.
362 */
363 gpkt.p_upd = 1;
364
365 if (HADZ) {
366 gpkt.do_chksum = 0; /* ignore checksum processing */
367 gpkt.p_ihash = 0;
368 }
369
370 /*
371 Get statistics of latest delta in old file.
372 */
373 if (!HADN) {
374 stats_ab(&gpkt,&stats);
375 gpkt.p_wrttn++;
376 newstats(&gpkt,line,"0");
377 }
378
379 if (HADN) { /* N E W F I L E */
380
381 /*
382 Beginning of SCCS file.
383 */
384 putline(&gpkt,sprintf(line,"%c%c%s\n",CTLCHAR,HEAD,"00000"));
385
386 /*
387 Statistics.
388 */
389 newstats(&gpkt,line,"0");
390
391 dt.d_type = 'D'; /* type of delta */
392
393 /*
394 Set initial release, level, branch and
395 sequence values.
396 */
397 if (HADR)
398 dt.d_sid.s_rel = irel;
399 else
400 dt.d_sid.s_rel = 1;
401 dt.d_sid.s_lev = 1;
402 dt.d_sid.s_br = dt.d_sid.s_seq = 0;
403
404 time(&dt.d_datetime); /* get time and date */
405
406 copy(logname(),dt.d_pgmr); /* get user's name */
407
408 dt.d_serial = 1;
409 dt.d_pred = 0;
410
411 del_ba(&dt,line); /* form and write */
412 putline(&gpkt,line); /* delta-table entry */
413
414 /*
415 If -m flag, enter MR numbers
416 */
417
418 if (Mrs) {
419 mrfixup();
420 if (z && valmrs(&gpkt,z))
421 fatal("invalid MRs (de9)");
422 putmrs(&gpkt);
423 }
424
425 /*
426 Enter comment line for `chghist'
427 */
428
429 if (HADY) {
430 putline(&gpkt,sprintf(line,"%c%c ",CTLCHAR,COMMENTS));
431 putline(&gpkt,Comments);
432 putline(&gpkt,"\n");
433 }
434 else {
435 /*
436 insert date/time and pgmr into comment line
437 */
438 cmt_ba(&dt,line);
439 putline(&gpkt,line);
440 }
441 /*
442 End of delta-table.
443 */
444 putline(&gpkt,sprintf(line,CTLSTR,CTLCHAR,EDELTAB));
445
446 /*
447 Beginning of user-name section.
448 */
449 putline(&gpkt,sprintf(line,CTLSTR,CTLCHAR,BUSERNAM));
450 }
451 else
452 /*
453 For old file, copy to x-file until user-name section
454 is found.
455 */
456 flushto(&gpkt,BUSERNAM,COPY);
457
458 /*
459 Write user-names to be added to list of those
460 allowed to make deltas.
461 */
462 if (HADA)
463 for (k = 0; k < asub; k++)
464 putline(&gpkt,sprintf(line,"%s\n",anames[k]));
465
466 /*
467 Do not copy those user-names which are to be erased.
468 */
469 if (HADE && !HADN)
470 while ((cp = getline(&gpkt)) &&
471 !(*cp++ == CTLCHAR && *cp == EUSERNAM)) {
472 for (k = 0; k < esub; k++) {
473 cp = &gpkt.p_line;
474 while (*cp) /* find and */
475 cp++; /* zero newline */
476 *--cp = '\0'; /* character */
477
478 if (equal(enames[k],&gpkt.p_line)) {
479 /*
480 Tell getline not to output
481 previously read line.
482 */
483 gpkt.p_wrttn = 1;
484 break;
485 }
486 else
487 *cp = '\n'; /* restore newline */
488 }
489 }
490
491 if (HADN) { /* N E W F I L E */
492
493 /*
494 End of user-name section.
495 */
496 putline(&gpkt,sprintf(line,CTLSTR,CTLCHAR,EUSERNAM));
497 }
498 else
499 /*
500 For old file, copy to x-file until end of
501 user-names section is found.
502 */
503 if (!HADE)
504 flushto(&gpkt,EUSERNAM,COPY);
505
506 /*
507 For old file, read flags and their values (if any), and
508 store them. Check to see if the flag read is one that
509 should be deleted.
510 */
511 if (!HADN)
512 while ((cp = getline(&gpkt)) &&
513 (*cp++ == CTLCHAR && *cp == FLAG)) {
514
515 gpkt.p_wrttn = 1; /* don't write previous line */
516
38c01699 517 cp += 2; /* point to flag character */
5a89b91c
EA
518 k = *cp - 'a';
519
520 if (!had_flag[k] && !rm_flag[k]) {
521 had_flag[k] = 2; /* indicate flag is */
522 /* from file, not */
523 /* from arg list */
524
525 if (*++cp != '\n') { /* get flag value */
526 q = alloc(size(gpkt.p_line)-5);
527 copy(++cp,q);
528 flag_p[k] = q;
529 while (*q) /* find and */
530 q++; /* zero newline */
531 *--q = '\0'; /* character */
532 }
533 }
534 else
535 if (rm_flag[k])
536 had_flag[k] = 0;
537 }
538
539
540 /*
541 Write out flags.
542 */
543 for (k = 0; k < 26; k++)
544 if (had_flag[k]) {
545 if (flag_p[k])
546 sprintf(line,"%c%c %c %s\n",
547 CTLCHAR,FLAG,'a'+k,flag_p[k]);
548 else
549 sprintf(line,"%c%c %c\n",
550 CTLCHAR,FLAG,'a'+k);
551
552 putline(&gpkt,line);
553
554 if (had_flag[k] == 2) { /* flag was taken from file */
555 had_flag[k] = 0;
556 if (flag_p[k]) {
557 free(flag_p[k]);
558 flag_p[k] = 0;
559 }
560 }
561 }
562
563 if (HADN)
564 /*
565 Beginning of descriptive (user) text.
566 */
567 putline(&gpkt,sprintf(line,CTLSTR,CTLCHAR,BUSERTXT));
568 else
569 /*
570 Write out BUSERTXT record which was read in
571 above loop that processes flags.
572 */
573 gpkt.p_wrttn = 0;
574 putline(&gpkt,0);
575
576 /*
577 Get user description, copy to x-file.
578 */
579 if (HADT) {
580 if (*tfile) {
581 iptr = xfopen(tfile,0);
582 fgetchk(line,512,iptr,tfile,&gpkt);
583 fclose(iptr);
584 }
585
586 /*
587 If old file, ignore any previously supplied
588 commentary. (i.e., don't copy it to x-file.)
589 */
590 if (!HADN)
591 flushto(&gpkt,EUSERTXT,NOCOPY);
592 }
593
594 if (HADN) { /* N E W F I L E */
595
596 /*
597 End of user description.
598 */
599 putline(&gpkt,sprintf(line,CTLSTR,CTLCHAR,EUSERTXT));
600
601 /*
602 Beginning of body (text) of first delta.
603 */
604 putline(&gpkt,sprintf(line,"%c%c %u\n",CTLCHAR,INS,1));
605
606 if (HADI) { /* get body */
607
608 /*
609 Set indicator to check lines of body of file for
610 keyword definitions.
611 If no keywords are found, a warning
612 will be produced.
613 */
614 check_id = 1;
615 /*
616 Set indicator that tells whether there
617 were any keywords to 'no'.
618 */
619 Did_id = 0;
620 if (*ifile)
621 iptr = xfopen(ifile,0); /* from a file */
622 else
623 iptr = stdin; /* from standard input */
624
625 /*
626 Read and copy to x-file, while checking
627 first character of each line to see that it
628 is not the control character (octal 1).
629 Also, count lines read, and set statistics'
630 structure appropriately.
631 The 'fgetchk' routine will check for keywords.
632 */
633 stats.s_ins = fgetchk(line,512,iptr,ifile,&gpkt);
634 stats.s_del = stats.s_unc = 0;
635
636 /*
637 If no keywords were found, issue warning.
638 */
639 if (!Did_id) {
640 if (had_flag[IDFLAG - 'a'])
641 fatal("no id keywords (cm6)");
642 else
643 fprintf(stderr,"%s\n","No id keywords (cm7)");
644 }
645
646 check_id = 0;
647 Did_id = 0;
648 }
649
650 /*
651 End of body of first delta.
652 */
653 putline(&gpkt,sprintf(line,"%c%c %u\n",CTLCHAR,END,1));
654 }
655 else {
656 /*
657 Indicate that EOF at this point is ok, and
658 flush rest of (old) s-file to x-file.
659 */
660 gpkt.p_chkeof = 1;
661 while (getline(&gpkt)) ;
662 }
663
664 /*
665 Flush the buffer, take care of rewinding to insert
666 checksum and statistics in file, and close.
667 */
668 flushline(&gpkt,&stats);
669
670 /*
671 Change x-file name to s-file, and delete old file.
672 Unlock file before returning.
673 */
674 if (!HADH) {
675 rename(auxf(&gpkt,'x'),&gpkt);
676 xrm(&gpkt);
677 unlockit(auxf(afile,'z'),getpid());
678 }
679}
680
681
682fgetchk(strp,len,inptr,file,pkt)
683register char *strp;
684register int len;
685FILE *inptr;
686register char *file;
687register struct packet *pkt;
688{
689 register int k;
690
691 for (k = 1; fgets(strp,len,inptr); k++) {
692 if (*strp == CTLCHAR) fatal(
693 sprintf(Error,"%s illegal data on line %d (ad21)",
694 file,k));
695
696 if (check_id)
697 chkid(strp);
698
699 putline(pkt,strp);
700 }
701 return(k - 1);
702}
703
704
705clean_up()
706{
707 xrm(&gpkt);
708 if (!HADH)
709 unlockit(Zhold,getpid());
710 if (HADN)
711 unlink(&gpkt);
712}
713
714
715cmt_ba(dt,str)
716register struct deltab *dt;
717char *str;
718{
719 register char *p;
720
721 p = str;
722 *p++ = CTLCHAR;
723 *p++ = COMMENTS;
724 *p++ = ' ';
725 copy("date and time created",p);
726 while (*p++)
727 ;
728 --p;
729 *p++ = ' ';
730 date_ba(&dt->d_datetime,p);
731 while (*p++)
732 ;
733 --p;
734 *p++ = ' ';
735 copy("by",p);
736 while (*p++)
737 ;
738 --p;
739 *p++ = ' ';
740 copy(dt->d_pgmr,p);
741 while (*p++)
742 ;
743 --p;
744 *p++ = '\n';
745 *p = 0;
746 return(str);
747}
748
749
750putmrs(pkt)
751struct packet *pkt;
752{
753 register char **argv;
754 char str[64];
755 extern char *Varg[];
756
757 for (argv = &Varg[VSTART]; *argv; argv++)
758 putline(pkt,sprintf(str,"%c%c %s\n",CTLCHAR,MRNUM,*argv));
759}