1 /* @(#)sccscvt.c 1.34 20/08/23 Copyright 2011-2020 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)sccscvt.c 1.34 20/08/23 Copyright 2011-2020 J. Schilling";
6 #endif
7 /*
8 * Convert a SCCS v4 history file to a SCCS v6 file and vice versa.
9 * When converting from v6 to v4, the extra meta data from the delta table
10 * is kept in special degenerated comment at the beginning of the comment
11 * block.
12 *
13 * Copyright (c) 2011-2020 J. Schilling
14 */
15 /*
16 * The contents of this file are subject to the terms of the
17 * Common Development and Distribution License, Version 1.0 only
18 * (the "License"). You may not use this file except in compliance
19 * with the License.
20 *
21 * See the file CDDL.Schily.txt in this distribution for details.
22 *
23 * When distributing Covered Code, include this CDDL HEADER in each
24 * file and include the License file CDDL.Schily.txt from this distribution.
25 */
26
27 #define SCCS_MAIN /* define global vars */
28 #include <defines.h>
29 #include <version.h>
30 #include <had.h> /* Do we need this? We don't use getopt() */
31 #include <i18n.h>
32 #include <schily/getargs.h>
33 #include <schily/utsname.h>
34
35 LOCAL void usage __PR((int exitcode));
36 EXPORT int main __PR((int ac, char *av[]));
37 LOCAL void dodir __PR((char *name));
38 LOCAL void convert __PR((char *file));
39 LOCAL void cvtdelt2v4 __PR((struct packet *pkt));
40 LOCAL void cvtdelt2v6 __PR((struct packet *pkt));
41 LOCAL void get_setup __PR((char *file));
42 LOCAL int get_hash __PR((int ser));
43 LOCAL void clean_up __PR((void));
44 LOCAL int getN __PR((const char *, void *));
45 LOCAL int getX __PR((const char *, void *));
46
47 LOCAL struct utsname un;
48 LOCAL char *uuname;
49 LOCAL struct packet gpkt;
50 LOCAL char Zhold[MAXPATHLEN]; /* temporary z-file name */
51 LOCAL Nparms N; /* Keep -N parameters */
52 LOCAL Xparms X; /* Keep -X parameters */
53
54 LOCAL BOOL dov6 = -1;
55 LOCAL BOOL keepold;
56 LOCAL BOOL discardv6;
57 LOCAL int olddate;
58
59 LOCAL void
usage(exitcode)60 usage(exitcode)
61 int exitcode;
62 {
63 fprintf(stderr, _("Usage: sccscvt [options] s.file1 .. s.filen\n"));
64 fprintf(stderr, _(" -help Print this help.\n"));
65 fprintf(stderr, _(" -version Print version number.\n"));
66 fprintf(stderr, _(" -V4 Convert history files to SCCS v4.\n"));
67 fprintf(stderr, _(" -V6 Convert history files to SCCS v6.\n"));
68 fprintf(stderr, _(" -d Discard SCCS v6 meta data.\n"));
69 fprintf(stderr, _(" -keep,-k Keep original history file as o.file.\n"));
70 fprintf(stderr, _(" -o Keep original time stamp.\n"));
71 fprintf(stderr, _(" -oo Use original time stamp + 1ns.\n"));
72 fprintf(stderr, _(" -ooo Use original time stamp + 1us.\n"));
73 fprintf(stderr, _(" -oooo Use original time stamp + 1s.\n"));
74 fprintf(stderr, _(" -Nbulk-spec Processes a bulk of SCCS history files.\n"));
75 fprintf(stderr, _(" -Xxopts Processes SCCS extended files.\n"));
76 exit(exitcode);
77 }
78
79 EXPORT int
main(ac,av)80 main(ac, av)
81 int ac;
82 char *av[];
83 {
84 int cac;
85 char * const *cav;
86 char *opts = "help,V,version,V4%0,V6,d,k,keep,o+,N&_,X&_";
87 BOOL help = FALSE;
88 BOOL pversion = FALSE;
89 int nargs = 0;
90
91 save_args(ac, av);
92
93 /*
94 * Set locale for all categories.
95 */
96 setlocale(LC_ALL, "");
97
98 sccs_setinsbase(INS_BASE);
99
100 /*
101 * Set directory to search for general l10n SCCS messages.
102 */
103 #ifdef PROTOTYPES
104 (void) bindtextdomain(NOGETTEXT("SUNW_SPRO_SCCS"),
105 NOGETTEXT(INS_BASE "/" SCCS_BIN_PRE "lib/locale/"));
106 #else
107 (void) bindtextdomain(NOGETTEXT("SUNW_SPRO_SCCS"),
108 NOGETTEXT("/usr/ccs/lib/locale/"));
109 #endif
110
111 (void) textdomain(NOGETTEXT("SUNW_SPRO_SCCS"));
112
113 tzset(); /* Set up timezome related vars */
114
115 set_clean_up(clean_up);
116 Fflags = FTLEXIT | FTLMSG | FTLCLN;
117 #ifdef SCCS_FATALHELP
118 Fflags |= FTLFUNC;
119 Ffunc = sccsfatalhelp;
120 #endif
121
122 cac = --ac;
123 cav = ++av;
124
125 if (getallargs(&cac, &cav, opts,
126 &help, &pversion, &pversion,
127 &dov6, &dov6,
128 &discardv6,
129 &keepold, &keepold,
130 &olddate,
131 getN, &N,
132 getX, &X) < 0) {
133 errmsgno(EX_BAD, _("Bad flag: %s.\n"), cav[0]);
134 usage(EX_BAD);
135 }
136 if (help)
137 usage(0);
138 if (pversion) {
139 printf(
140 _("sccscvt %s-SCCS version %s %s (%s-%s-%s) Copyright (C) 2011-2020 %s\n"),
141 PROVIDER,
142 VERSION,
143 VDATE,
144 HOST_CPU, HOST_VENDOR, HOST_OS,
145 _("J�rg Schilling"));
146 exit(0);
147 }
148 if (dov6 < 0) {
149 errmsgno(EX_BAD, _("Need to specify -V4 or -V6.\n"));
150 usage(EX_BAD);
151 }
152 if (N.n_parm) { /* Parse -N args */
153 parseN(&N);
154 }
155
156 xsethome(NULL);
157 if (N.n_parm && N.n_sdot && (sethomestat & SETHOME_OFFTREE))
158 fatal(gettext("-Ns. not supported in off-tree project mode"));
159
160 /*
161 * Get the name of our machine to be used for the lockfile.
162 */
163 uname(&un);
164 uuname = un.nodename;
165
166 /*
167 * Set up a project global lock on the changeset file.
168 * Since we set FTLJMP, we do not need to unlockchset() from clean_up().
169 */
170 if (SETHOME_CHSET())
171 lockchset(getppid(), getpid(), uuname);
172 timerchsetlock();
173
174 Fflags &= ~FTLEXIT;
175 Fflags |= FTLJMP;
176
177 cac = ac;
178 cav = av;
179
180 while (getfiles(&cac, &cav, opts) > 0) {
181 struct stat sb;
182
183 if (cav[0][0] == '-' && cav[0][1] == '\0')
184 do_file("-", convert, 0, N.n_sdot, &X);
185 else if (stat(cav[0], &sb) >= 0 && S_ISDIR(sb.st_mode))
186 dodir(cav[0]);
187 else
188 convert(cav[0]);
189 cac--;
190 cav++;
191 nargs++;
192 }
193
194 /*
195 * Only remove the global lock it it was created by us and not by
196 * our parent.
197 */
198 if (SETHOME_CHSET()) {
199 if (N.n_parm)
200 bulkchdir(&N);
201 unlockchset(getpid(), uuname);
202 }
203
204 if (nargs == 0) {
205 errmsgno(EX_BAD, _("Missing arg.\n"));
206 usage(EX_BAD);
207 }
208 return (0);
209 }
210
211 LOCAL void
dodir(name)212 dodir(name)
213 char *name;
214 {
215 DIR *dp;
216 struct dirent *d;
217 char *np;
218 char fname[MAXPATHNAME+1];
219 char *base;
220 int len;
221 BOOL newmode = FALSE;
222
223 if (SETHOME_CHSET() && N.n_parm && N.n_sdot == 0) {
224 newmode = TRUE;
225 N.n_pflags = NP_NOCHDIR|NP_DIR;
226 np = bulkprepare(&N, name);
227 if (np == NULL)
228 fatal(gettext(bulkerror(&N)));
229 N.n_pflags = 0;
230 dp = opendir(np);
231 } else {
232 dp = opendir(name);
233 }
234 if (dp == NULL) {
235 errmsg(_("Cannot open directory '%s'\n"), name);
236 return;
237 }
238
239 if ((len = resolvenpath(name, fname, sizeof (fname))) == -1) {
240 N.n_error = BULK_EPATHCONV;
241 closedir(dp);
242 efatal(gettext(bulkerror(&N)));
243 return;
244 } else if (len >= sizeof (fname)) {
245 N.n_error = BULK_ETOOLONG;
246 closedir(dp);
247 fatal(gettext(bulkerror(&N)));
248 return;
249 }
250 fname[len] = '\0';
251 if (fname[0] == '.' && len == 1) {
252 fname[--len] = '\0';
253 base = fname;
254 } else {
255 base = &fname[len-1];
256 if (*base != '/')
257 *++base = '/';
258 *++base = '\0';
259 }
260 len = sizeof (fname) - strlen(fname);
261 while ((d = readdir(dp)) != NULL) {
262 np = d->d_name;
263
264 if (np[0] != 's' || np[1] != '.' || np[2] == '\0')
265 continue;
266
267 if (newmode)
268 np += 2;
269 strlcpy(base, np, len);
270 convert(fname);
271 }
272 closedir(dp);
273 }
274
275 LOCAL void
convert(file)276 convert(file)
277 char *file;
278 {
279 struct stat sbuf;
280 struct timespec ts[2];
281 char hash[32];
282 char *xf;
283 char *dir_name = "";
284
285 /*
286 * Set up exception handling for fatal().
287 */
288 if (setjmp(Fjmp))
289 return;
290
291 /*
292 * In order to make the global lock with a potentially long duration
293 * not look as if it was expired, we refresh it for every file in our
294 * task list. This is needed since another SCCS instance on a different
295 * NFS machine cannot use kill() to check for a still active process.
296 */
297 if (SETHOME_CHSET()) {
298 if (N.n_parm)
299 bulkchdir(&N); /* Done by bulkprepare() anyway */
300 refreshchsetlock();
301 }
302
303 if (N.n_parm) {
304 #ifdef __needed__
305 char *ofile = file;
306 #endif
307
308 file = bulkprepare(&N, file);
309 if (file == NULL) {
310 #ifdef __needed__
311 if (N.n_ifile)
312 ofile = N.n_ifile;
313 #endif
314 /*
315 * The error is typically
316 * "directory specified as s-file (cm14)"
317 */
318 fatal(gettext(bulkerror(&N)));
319 }
320 dir_name = N.n_dir_name;
321 }
322
323 if (!sccsfile(file)) {
324 errmsgno(EX_BAD, _("%s: not an SCCS file (co1).\n"), file);
325 return;
326 }
327
328 /*
329 * Init and check for validity of file name but do not open the file.
330 * This prevents us from potentially damaging files with lockit().
331 */
332 sinit(&gpkt, file, SI_INIT);
333
334 /*
335 * Obtain a lock on the SCCS history file.
336 */
337 if (!islockchset(copy(auxf(gpkt.p_file, 'z'), Zhold)) &&
338 lockit(Zhold, SCCS_LOCK_ATTEMPTS, getpid(), uuname)) {
339 lockfatal(Zhold, getpid(), uuname);
340 } else {
341 timersetlockfile(Zhold);
342 }
343
344 /*
345 * Open s. file.
346 */
347 sinit(&gpkt, file, SI_OPEN);
348 if (dov6) {
349 if (gpkt.p_flags & PF_V6) {
350 errmsgno(EX_BAD, _("%s: already in SCCS v6 format.\n"),
351 file);
352 clean_up();
353 sclose(&gpkt);
354 sfree(&gpkt);
355 return;
356 }
357 gpkt.p_flags |= PF_V6;
358 } else {
359 if ((gpkt.p_flags & PF_V6) == 0) {
360 errmsgno(EX_BAD, _("%s: already in SCCS v4 format.\n"),
361 file);
362 clean_up();
363 sclose(&gpkt);
364 sfree(&gpkt);
365 return;
366 }
367 gpkt.p_flags &= ~PF_V6; /* Make sure initial chksum is V4 */
368 }
369
370 /*
371 * Write a magic in the expected new format.
372 */
373 gpkt.p_upd = 1;
374 putmagic(&gpkt, "00000");
375 gpkt.p_wrttn = 1;
376
377 get_setup(file); /* Read delta table for get_hash() */
378
379 /*
380 * The main conversion work happens here.
381 * Convert the delta table.
382 * The conversion stops at BUSERNAM (the beginning of the user names).
383 */
384 if (dov6)
385 cvtdelt2v6(&gpkt);
386 else
387 cvtdelt2v4(&gpkt);
388
389 /*
390 * The next sections in the history file are:
391 *
392 * - usernames mandatory BUSERNAM .. EUSERNAM
393 * - v4 flags optional
394 * - v6 flags optional
395 * - v6 meta data optional
396 * - future extens. optional
397 * - comments mandatory BUSERTXT .. EUSERTXT
398 *
399 * First copy user names...
400 */
401 flushto(&gpkt, EUSERNAM, FLUSH_COPY);
402
403 /*
404 * gpkt.p_line now points to EUSERNAM and this line has been written.
405 *
406 * Now copy SCCS v4 flags in case they are present.
407 * Using the flag parser is a bit slower, but warns about unknown flags.
408 */
409 doflags(&gpkt);
410
411 /*
412 * gpkt.p_line now points to the first line past the SCCS v4 flags and
413 * this line has not yet been written.
414 *
415 * Now copy SCCS v6 flags in case they are present.
416 * Using the flag parser is a bit slower, but warns about unknown flags.
417 */
418 donamedflags(&gpkt);
419
420 /*
421 * gpkt.p_line now points to the first line past the SCCS v6 flags and
422 * this line has not yet been written.
423 *
424 * Now copy SCCS v6 meta data extensions in case they are present.
425 * Using the meta data parser is needed since we need to know whether
426 * we already have SCCS v6 initial path and SCCS v6 unified random.
427 */
428 dometa(&gpkt);
429
430 /*
431 * gpkt.p_line now points to the first line past the SCCS v6 meta data
432 * and this line has not yet been written.
433 *
434 * Check whether we need to add SCCS v6 initial path and SCCS v6 urand.
435 */
436 if (dov6) {
437 unsigned mflags = 0;
438
439 if (gpkt.p_init_path == NULL && N.n_parm) {
440 set_init_path(&gpkt, N.n_ifile, dir_name);
441 mflags |= M_INIT_PATH;
442 }
443 if (!urand_valid(&gpkt.p_rand)) {
444 urandom(&gpkt.p_rand);
445 mflags |= M_URAND;
446 }
447 if (mflags) {
448 putmeta(&gpkt, mflags);
449 }
450 }
451
452 /*
453 * gpkt.p_line still points to the first line past the SCCS v6 meta data
454 * and this line has still not yet been written.
455 *
456 * Copy user names, extensions and descriptive user text.
457 * Before doing that, the unwritten line is flushed.
458 */
459 flushto(&gpkt, EUSERTXT, FLUSH_COPY);
460
461 /*
462 * Copy interleaved delta block.
463 */
464 gpkt.p_chkeof = 1; /* set EOF is ok */
465 while (getline(&gpkt))
466 ;
467 putline(&gpkt, (char *)0); /* flush final line */
468
469 /*
470 * Write checksum.
471 */
472 if (!dov6)
473 gpkt.p_flags &= ~PF_V6;
474 sprintf(hash, "%5.5d", gpkt.p_nhash&0xFFFF);
475 putmagic(&gpkt, hash);
476
477 /*
478 * Make sure the data is stable in the file on disk.
479 */
480 xf = auxf(gpkt.p_file, 'x');
481 if (fflush(gpkt.p_xiop) == EOF)
482 xmsg(xf, NOGETTEXT("convert"));
483
484 /*
485 * Lots of paranoia here, to try to catch
486 * delayed failure information from NFS.
487 */
488 #ifdef HAVE_FSYNC
489 if (fsync(fileno(gpkt.p_xiop)) < 0)
490 xmsg(xf, NOGETTEXT("convert"));
491 #endif
492 if (fclose(gpkt.p_xiop) == EOF)
493 xmsg(xf, NOGETTEXT("flushline"));
494 gpkt.p_xiop = NULL;
495
496 stat(gpkt.p_file, &sbuf);
497 if (keepold)
498 rename(gpkt.p_file, auxf(gpkt.p_file, 'o'));
499
500 rename(auxf(gpkt.p_file, 'x'), gpkt.p_file);
501 chmod(gpkt.p_file, (unsigned int)sbuf.st_mode);
502
503 chown(gpkt.p_file, (unsigned int)sbuf.st_uid,
504 (unsigned int)sbuf.st_gid);
505
506 if (olddate) {
507 ts[0].tv_sec = sbuf.st_atime;
508 ts[0].tv_nsec = stat_ansecs(&sbuf);
509 ts[1].tv_sec = sbuf.st_mtime;
510 ts[1].tv_nsec = stat_mnsecs(&sbuf);
511
512 if (olddate > 3)
513 ts[1].tv_sec += 1;
514 else if (olddate > 2)
515 ts[1].tv_nsec += 1000;
516 else if (olddate > 1)
517 ts[1].tv_nsec += 1;
518 if (ts[1].tv_nsec >= 1000000000) {
519 ts[1].tv_nsec -= 1000000000;
520 ts[1].tv_sec += 1;
521 }
522
523 utimensat(AT_FDCWD, gpkt.p_file, ts, 0);
524 }
525
526 clean_up();
527 }
528
529 LOCAL char xcomment[] = { CTLCHAR, COMMENTS, '_', '\0' }; /* "^Ac_" */
530
531 /*
532 * Convert the delta table from a SCCS v6 history file to SCCS v4
533 * The conversion stops at BUSERNAM (the beginning of the user names).
534 */
535 LOCAL void
cvtdelt2v4(pkt)536 cvtdelt2v4(pkt)
537 register struct packet *pkt;
538 {
539 char line[BUFSIZ];
540 struct deltab dt;
541
542 /*
543 * We need to permit to read and evaluate SCCS v6 time stamps.
544 */
545 pkt->p_flags |= PF_V6;
546
547 line[0] = '\0';
548 while (getline(pkt) != NULL) {
549 if (pkt->p_line[0] != CTLCHAR)
550 fmterr(pkt);
551 switch (pkt->p_line[1]) {
552
553 case BDELTAB:
554 /*
555 * Convert SCCS v6 to SCCS v4 delta line and save the
556 * old line as wrapped degenerated comment.
557 */
558 del_ab(pkt->p_line, &dt, pkt);
559 del_ba(&dt, line, pkt->p_flags & ~PF_V6);
560 putline(pkt, line);
561 line[0] = '\0';
562 pkt->p_wrttn = 1;
563 if (discardv6)
564 continue;
565 if (dt.d_dtime.dt_zone != DT_NO_ZONE) {
566 strcpy(line, xcomment);
567 strlcpy(&line[3], &pkt->p_line[1],
568 sizeof (line) - 3);
569 }
570 continue;
571
572 case STATS:
573 case INCLUDE:
574 case EXCLUDE:
575 case IGNORE:
576 case MRNUM:
577 continue;
578
579 case SIDEXTENS:
580 if (discardv6) {
581 pkt->p_wrttn = 1;
582 continue;
583 }
584 /*
585 * Keep SCCS v6 extensions as degenerated comment.
586 *
587 * If not yet flushed, flush delta line.
588 */
589 if (line[0] != '\0')
590 putline(pkt, line);
591 line[0] = '\0';
592 putline(pkt, xcomment);
593 putline(pkt, &pkt->p_line[1]);
594 pkt->p_wrttn = 1;
595 continue;
596
597 case COMMENTS:
598 /*
599 * If not yet flushed, flush delta line.
600 */
601 if (line[0] != '\0')
602 putline(pkt, line);
603 line[0] = '\0';
604 continue;
605
606 case EDELTAB:
607 continue;
608
609 case BUSERNAM:
610 return;
611
612 default:
613 fmterr(pkt);
614 }
615 }
616 }
617
618 /*
619 * Convert the delta table from a SCCS v4 history file to SCCS v6
620 * The conversion stops at BUSERNAM (the beginning of the user names).
621 */
622 LOCAL void
cvtdelt2v6(pkt)623 cvtdelt2v6(pkt)
624 register struct packet *pkt;
625 {
626 char line[BUFSIZ];
627 #define MAX_DELT_LINES 1024
628 char *lines[MAX_DELT_LINES];
629 int nlines = 0;
630 int i;
631 int commentstate = 0;
632 BOOL incomment = FALSE;
633 BOOL needthis = FALSE;
634 struct deltab dt;
635 struct deltab dt2;
636
637 while (getline(pkt) != NULL) {
638 if (pkt->p_line[0] != CTLCHAR)
639 fmterr(pkt);
640 switch (pkt->p_line[1]) {
641
642 case BDELTAB:
643 /*
644 * Converting a delta line from SCCS v4 to SCCS v6
645 * is harder as we need to save all following lines and
646 * look for old saved SCCS v6 content in degenerated
647 * comment first.
648 */
649 commentstate = 0;
650 incomment = FALSE;
651 del_ab(pkt->p_line, &dt, pkt);
652 if (dt.d_dtime.dt_zone != DT_NO_ZONE)
653 fmterr(pkt);
654
655 pkt->p_wrttn = 1;
656 while (getline(pkt) != NULL) {
657 if (pkt->p_line[0] != CTLCHAR)
658 fmterr(pkt);
659 /*
660 * Stop on first comment line or at the end
661 * of this delta table block.
662 */
663 if (pkt->p_line[1] == COMMENTS)
664 break;
665 if (pkt->p_line[1] == EDELTAB)
666 break;
667 if (nlines >= MAX_DELT_LINES)
668 fatal(_("OUT OF SPACE (ut9)"));
669 lines[nlines] = strdup(pkt->p_line);
670 if (lines[nlines++] == NULL)
671 fatal(_("OUT OF SPACE (ut9)"));
672 pkt->p_wrttn = 1;
673 }
674 /*
675 * If _we_ previously created a degenerated comment,
676 * then the first line is a saved v6 delta line.
677 * The first degenerated comment must be of type 'd'
678 * and the second degenerated comment must be of
679 * type 'S s'.
680 */
681 if ((pkt->p_line[1] == COMMENTS) &&
682 (pkt->p_line[2] == '_') &&
683 (pkt->p_line[3] == BDELTAB) &&
684 (pkt->p_line[4] == ' ')) {
685 pkt->p_line[2] = CTLCHAR;
686 del_ab(&pkt->p_line[2], &dt2, pkt);
687 if (dt2.d_dtime.dt_zone != DT_NO_ZONE) {
688 dt.d_dtime.dt_zone =
689 dt2.d_dtime.dt_zone;
690 dt.d_dtime.dt_nsec =
691 dt2.d_dtime.dt_nsec;
692 } else {
693 dt.d_dtime.dt_zone =
694 gmtoff(dt.d_dtime.dt_sec);
695 }
696 commentstate = 1;
697 needthis = FALSE;
698 } else {
699 dt.d_dtime.dt_zone =
700 gmtoff(dt.d_dtime.dt_sec);
701 needthis = TRUE;
702 }
703 /*
704 * Regenerate or generate a v6 delta line and write
705 * the remembered other lines.
706 */
707 del_ba(&dt, line, pkt->p_flags);
708 putline(pkt, line);
709 for (i = 0; i < nlines; i++) {
710 putline(pkt, lines[i]);
711 free(lines[i]);
712 }
713 nlines = 0;
714
715 if (commentstate == 1) {
716 pkt->p_wrttn = 1;
717 getline(pkt);
718 if ((pkt->p_line[1] == COMMENTS) &&
719 (pkt->p_line[2] == '_') &&
720 (pkt->p_line[3] == SIDEXTENS) &&
721 (pkt->p_line[4] == ' ') &&
722 (pkt->p_line[5] == 's')) {
723 commentstate = 2;
724 } else if ((pkt->p_line[1] == COMMENTS) &&
725 (pkt->p_line[2] == '_')) {
726 commentstate = 3;
727 } else {
728 needthis = TRUE;
729 }
730 }
731 if (commentstate != 2 && dt.d_type == 'D') {
732 pkt->p_ghash = get_hash(dt.d_serial);
733 sidext_ba(pkt, &dt);
734 }
735 if (commentstate >= 2)
736 goto dcomment;
737
738 /*
739 * If the first delta comment was not a degenerated
740 * comment from us, write it back unmodified.
741 */
742 if (needthis)
743 putline(pkt, (char *)0);
744 pkt->p_wrttn = 1;
745 continue;
746
747 case COMMENTS:
748 if (incomment)
749 continue;
750 /*
751 * Convert v6 extensions saved as degenerated comment
752 * back to v6 extensions.
753 */
754 dcomment:
755 if ((pkt->p_line[1] == COMMENTS) &&
756 (pkt->p_line[2] == '_') &&
757 (pkt->p_line[3] == SIDEXTENS)) {
758 putctl(pkt);
759 putline(pkt, &pkt->p_line[3]);
760 pkt->p_wrttn = 1;
761 continue;
762 }
763 incomment = TRUE;
764 continue;
765
766 case STATS:
767 case INCLUDE:
768 case EXCLUDE:
769 case IGNORE:
770 case MRNUM:
771 continue;
772
773 case SIDEXTENS:
774 fmterr(pkt);
775 continue;
776
777 case EDELTAB:
778 incomment = FALSE;
779 continue;
780
781 case BUSERNAM:
782 return;
783
784 default:
785 fmterr(pkt);
786 }
787 }
788 }
789
790 LOCAL struct packet pk2;
791 LOCAL off_t get_off;
792 LOCAL int slnno;
793
794 LOCAL void
get_setup(file)795 get_setup(file)
796 char *file;
797 {
798 struct stats stats;
799
800 sinit(&pk2, file, SI_OPEN);
801
802 pk2.p_stdout = stderr;
803 pk2.p_reopen = 1;
804 pk2.p_cutoff = MAX_TIME;
805
806 if ((pk2.p_flags & PF_V6) == 0)
807 pk2.p_flags |= PF_GMT;
808
809 if (dodelt(&pk2, &stats, (struct sid *) 0, 0) == 0)
810 fmterr(&pk2);
811 flushto(&pk2, EUSERTXT, FLUSH_NOCOPY);
812 get_off = stell(&pk2);
813 slnno = pk2.p_slnno;
814 }
815
816 LOCAL int
get_hash(ser)817 get_hash(ser)
818 int ser;
819 {
820 int max_ser = maxser(&pk2);
821
822 if (ser > max_ser)
823 return (-1);
824
825 sseek(&pk2, get_off, SEEK_SET);
826 pk2.p_slnno = slnno;
827
828 pk2.p_reopen = 1;
829 pk2.p_chkeof = 1;
830 pk2.p_gotsid = pk2.p_idel[ser].i_sid;
831 pk2.p_reqsid = pk2.p_gotsid;
832
833 zero((char *) pk2.p_apply, (max_ser+1)*sizeof(*pk2.p_apply));
834 setup(&pk2, ser);
835
836 pk2.p_ghash = 0;
837 while (readmod(&pk2))
838 ;
839 return (pk2.p_ghash & 0xFFFF);
840 }
841
842
843
844 LOCAL void
clean_up()845 clean_up()
846 {
847 uname(&un);
848 uuname = un.nodename;
849 if (mylock(auxf(gpkt.p_file, 'z'), getpid(), uuname)) {
850 sclose(&gpkt);
851 sfree(&gpkt);
852 if (gpkt.p_xiop) {
853 fclose(gpkt.p_xiop);
854 gpkt.p_xiop = NULL;
855 unlink(auxf(gpkt.p_file, 'x'));
856 }
857 sclose(&pk2);
858 sfree(&pk2);
859 xrm(&gpkt);
860 ffreeall();
861 timersetlockfile(NULL);
862 if (!islockchset(Zhold))
863 unlockit(Zhold, getpid(), uuname);
864 }
865 }
866
867 LOCAL int
getN(argp,valp)868 getN(argp, valp)
869 const char *argp;
870 void *valp;
871 {
872 initN(&N);
873 N.n_parm = (char *)argp;
874 return (TRUE);
875 }
876
877 LOCAL int
getX(argp,valp)878 getX(argp, valp)
879 const char *argp;
880 void *valp;
881 {
882 X.x_parm = (char *)argp;
883 X.x_flags = XO_NULLPATH;
884 if (!parseX(&X))
885 return (BADFLAG);
886 return (TRUE);
887 }
888