Annotation of src/usr.bin/rcs/rcsprog.c, Revision 1.163
1.163 ! mortimer 1: /* $OpenBSD: rcsprog.c,v 1.162 2020/06/09 20:05:40 joris Exp $ */
1.1 deraadt 2: /*
3: * Copyright (c) 2005 Jean-Francois Brousseau <jfb@openbsd.org>
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. The name of the author may not be used to endorse or promote products
13: * derived from this software without specific prior written permission.
14: *
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
1.137 xsa 27: #include <sys/stat.h>
28:
29: #include <err.h>
1.150 chl 30: #include <signal.h>
1.137 xsa 31: #include <stdio.h>
32: #include <stdlib.h>
33: #include <string.h>
34: #include <unistd.h>
1.1 deraadt 35:
1.9 joris 36: #include "rcsprog.h"
1.1 deraadt 37:
1.161 millert 38: #define RCSPROG_OPTSTRING "A:a:b::c:e::Iik:Ll::m:Mn:N:o:qt::TUu::Vx::z::"
1.56 joris 39:
1.147 joris 40: const char rcs_version[] = "OpenRCS 4.5";
1.1 deraadt 41:
1.91 ray 42: int rcsflags;
1.36 xsa 43: int rcs_optind;
1.28 joris 44: char *rcs_optarg;
1.149 tobias 45: char *rcs_suffixes = RCS_DEFAULT_SUFFIX;
1.36 xsa 46: char *rcs_tmpdir = RCS_TMPDIR_DEFAULT;
1.28 joris 47:
1.1 deraadt 48: struct rcs_prog {
1.26 deraadt 49: char *prog_name;
50: int (*prog_hdlr)(int, char **);
51: void (*prog_usage)(void);
1.1 deraadt 52: } programs[] = {
1.2 deraadt 53: { "rcs", rcs_main, rcs_usage },
1.17 joris 54: { "ci", checkin_main, checkin_usage },
1.11 joris 55: { "co", checkout_main, checkout_usage },
1.20 joris 56: { "rcsclean", rcsclean_main, rcsclean_usage },
1.18 joris 57: { "rcsdiff", rcsdiff_main, rcsdiff_usage },
1.33 xsa 58: { "rcsmerge", rcsmerge_main, rcsmerge_usage },
1.21 joris 59: { "rlog", rlog_main, rlog_usage },
1.22 joris 60: { "ident", ident_main, ident_usage },
1.126 xsa 61: { "merge", merge_main, merge_usage },
1.1 deraadt 62: };
1.163 ! mortimer 63: void (*usage)(void);
1.31 joris 64:
1.148 ray 65: struct wklhead temp_files;
1.68 joris 66:
67: void sighdlr(int);
1.101 joris 68: static void rcs_attach_symbol(RCSFILE *, const char *);
1.56 joris 69:
1.78 ray 70: /* ARGSUSED */
1.31 joris 71: void
1.68 joris 72: sighdlr(int sig)
73: {
1.148 ray 74: worklist_clean(&temp_files, worklist_unlink);
1.68 joris 75: _exit(1);
76: }
77:
1.9 joris 78: int
1.144 tobias 79: build_cmd(char ***cmd_argv, char **argv, int argc)
1.29 joris 80: {
1.144 tobias 81: int cmd_argc, i, cur;
82: char *cp, *rcsinit, *linebuf, *lp;
1.29 joris 83:
1.144 tobias 84: if ((rcsinit = getenv("RCSINIT")) == NULL) {
85: *cmd_argv = argv;
86: return argc;
87: }
88:
89: cur = argc + 2;
90: cmd_argc = 0;
91: *cmd_argv = xcalloc(cur, sizeof(char *));
92: (*cmd_argv)[cmd_argc++] = argv[0];
1.29 joris 93:
1.144 tobias 94: linebuf = xstrdup(rcsinit);
1.29 joris 95: for (lp = linebuf; lp != NULL;) {
1.61 xsa 96: cp = strsep(&lp, " \t\b\f\n\r\t\v");
1.29 joris 97: if (cp == NULL)
98: break;
1.144 tobias 99: if (*cp == '\0')
1.29 joris 100: continue;
101:
1.144 tobias 102: if (cmd_argc == cur) {
103: cur += 8;
1.154 deraadt 104: *cmd_argv = xreallocarray(*cmd_argv, cur,
1.144 tobias 105: sizeof(char *));
1.29 joris 106: }
107:
1.144 tobias 108: (*cmd_argv)[cmd_argc++] = cp;
1.29 joris 109: }
110:
1.144 tobias 111: if (cmd_argc + argc > cur) {
112: cur = cmd_argc + argc + 1;
1.154 deraadt 113: *cmd_argv = xreallocarray(*cmd_argv, cur,
1.144 tobias 114: sizeof(char *));
1.29 joris 115: }
116:
1.144 tobias 117: for (i = 1; i < argc; i++)
118: (*cmd_argv)[cmd_argc++] = argv[i];
119:
120: (*cmd_argv)[cmd_argc] = NULL;
121:
122: return cmd_argc;
1.29 joris 123: }
124:
125: int
1.1 deraadt 126: main(int argc, char **argv)
127: {
128: u_int i;
1.144 tobias 129: char **cmd_argv;
1.29 joris 130: int ret, cmd_argc;
1.157 deraadt 131:
1.159 millert 132: if (pledge("stdio rpath wpath cpath fattr flock getpw", NULL) == -1)
1.160 gsoares 133: err(2, "pledge");
1.1 deraadt 134:
135: ret = -1;
1.28 joris 136: rcs_optind = 1;
1.148 ray 137: SLIST_INIT(&temp_files);
1.1 deraadt 138:
1.144 tobias 139: cmd_argc = build_cmd(&cmd_argv, argv, argc);
1.36 xsa 140:
141: if ((rcs_tmpdir = getenv("TMPDIR")) == NULL)
142: rcs_tmpdir = RCS_TMPDIR_DEFAULT;
1.68 joris 143:
144: signal(SIGHUP, sighdlr);
145: signal(SIGINT, sighdlr);
146: signal(SIGQUIT, sighdlr);
147: signal(SIGABRT, sighdlr);
148: signal(SIGALRM, sighdlr);
149: signal(SIGTERM, sighdlr);
1.29 joris 150:
1.1 deraadt 151: for (i = 0; i < (sizeof(programs)/sizeof(programs[0])); i++)
1.2 deraadt 152: if (strcmp(__progname, programs[i].prog_name) == 0) {
153: usage = programs[i].prog_usage;
1.29 joris 154: ret = programs[i].prog_hdlr(cmd_argc, cmd_argv);
1.2 deraadt 155: break;
156: }
1.100 joris 157:
158: /* clean up temporary files */
1.148 ray 159: worklist_run(&temp_files, worklist_unlink);
1.1 deraadt 160:
1.23 niallo 161: exit(ret);
1.1 deraadt 162: }
163:
164:
1.152 otto 165: __dead void
1.1 deraadt 166: rcs_usage(void)
167: {
168: fprintf(stderr,
1.135 niallo 169: "usage: rcs [-IiLqTUV] [-Aoldfile] [-ausers] [-b[rev]]\n"
1.92 ray 170: " [-cstring] [-e[users]] [-kmode] [-l[rev]] [-mrev:msg]\n"
1.151 sobrado 171: " [-orev] [-t[str]] [-u[rev]] [-xsuffixes] file ...\n");
1.152 otto 172:
173: exit(1);
1.1 deraadt 174: }
175:
176: /*
177: * rcs_main()
178: *
179: * Handler for the `rcs' program.
180: * Returns 0 on success, or >0 on error.
181: */
182: int
183: rcs_main(int argc, char **argv)
184: {
1.129 ray 185: int fd;
1.112 xsa 186: int i, j, ch, flags, kflag, lkmode;
1.130 ray 187: const char *nflag, *oldfilename, *orange;
1.155 deraadt 188: char fpath[PATH_MAX];
1.130 ray 189: char *logstr, *logmsg, *descfile;
190: char *alist, *comment, *elist, *lrev, *urev;
1.1 deraadt 191: mode_t fmode;
1.129 ray 192: RCSFILE *file;
1.24 joris 193: RCSNUM *logrev;
1.39 xsa 194: struct rcs_access *acp;
1.48 xsa 195: time_t rcs_mtime = -1;
1.1 deraadt 196:
1.95 xsa 197: kflag = RCS_KWEXP_ERR;
1.134 xsa 198: lkmode = RCS_LOCK_INVAL;
1.89 niallo 199: fmode = S_IRUSR|S_IRGRP|S_IROTH;
1.58 niallo 200: flags = RCS_RDWR|RCS_PARSE_FULLY;
1.130 ray 201: lrev = urev = descfile = NULL;
202: logstr = alist = comment = elist = NULL;
203: nflag = oldfilename = orange = NULL;
1.111 xsa 204:
205: /* match GNU */
206: if (1 < argc && argv[1][0] != '-')
207: warnx("warning: No options were given; "
208: "this usage is obsolescent.");
1.1 deraadt 209:
1.51 xsa 210: while ((ch = rcs_getopt(argc, argv, RCSPROG_OPTSTRING)) != -1) {
1.1 deraadt 211: switch (ch) {
212: case 'A':
1.129 ray 213: oldfilename = rcs_optarg;
1.56 joris 214: rcsflags |= CO_ACLAPPEND;
1.1 deraadt 215: break;
216: case 'a':
1.28 joris 217: alist = rcs_optarg;
1.1 deraadt 218: break;
219: case 'c':
1.28 joris 220: comment = rcs_optarg;
1.1 deraadt 221: break;
222: case 'e':
1.28 joris 223: elist = rcs_optarg;
1.87 ray 224: rcsflags |= RCSPROG_EFLAG;
1.1 deraadt 225: break;
1.161 millert 226: case 'I':
227: rcsflags |= INTERACTIVE;
228: break;
1.1 deraadt 229: case 'i':
230: flags |= RCS_CREATE;
231: break;
232: case 'k':
1.28 joris 233: kflag = rcs_kflag_get(rcs_optarg);
1.1 deraadt 234: if (RCS_KWEXP_INVAL(kflag)) {
1.114 xsa 235: warnx("invalid RCS keyword substitution mode");
236: (usage)();
1.1 deraadt 237: }
238: break;
239: case 'L':
240: if (lkmode == RCS_LOCK_LOOSE)
1.146 tobias 241: warnx("-U overridden by -L");
1.1 deraadt 242: lkmode = RCS_LOCK_STRICT;
243: break;
1.92 ray 244: case 'l':
1.153 otto 245: if (rcsflags & RCSPROG_UFLAG)
246: warnx("-u overridden by -l");
1.92 ray 247: lrev = rcs_optarg;
1.153 otto 248: rcsflags &= ~RCSPROG_UFLAG;
1.92 ray 249: rcsflags |= RCSPROG_LFLAG;
250: break;
1.24 joris 251: case 'm':
1.156 nicm 252: free(logstr);
1.53 joris 253: logstr = xstrdup(rcs_optarg);
1.24 joris 254: break;
1.1 deraadt 255: case 'M':
256: /* ignore for the moment */
257: break;
1.56 joris 258: case 'n':
1.130 ray 259: nflag = rcs_optarg;
1.56 joris 260: break;
261: case 'N':
1.130 ray 262: nflag = rcs_optarg;
1.87 ray 263: rcsflags |= RCSPROG_NFLAG;
1.56 joris 264: break;
1.101 joris 265: case 'o':
1.130 ray 266: orange = rcs_optarg;
1.101 joris 267: break;
1.12 joris 268: case 'q':
1.108 xsa 269: rcsflags |= QUIET;
1.46 xsa 270: break;
1.56 joris 271: case 't':
272: descfile = rcs_optarg;
1.113 ray 273: rcsflags |= DESCRIPTION;
1.56 joris 274: break;
1.46 xsa 275: case 'T':
1.56 joris 276: rcsflags |= PRESERVETIME;
1.12 joris 277: break;
1.1 deraadt 278: case 'U':
279: if (lkmode == RCS_LOCK_STRICT)
1.146 tobias 280: warnx("-L overridden by -U");
1.1 deraadt 281: lkmode = RCS_LOCK_LOOSE;
282: break;
1.92 ray 283: case 'u':
1.153 otto 284: if (rcsflags & RCSPROG_LFLAG)
285: warnx("-l overridden by -u");
1.92 ray 286: urev = rcs_optarg;
1.153 otto 287: rcsflags &= ~RCSPROG_LFLAG;
1.92 ray 288: rcsflags |= RCSPROG_UFLAG;
289: break;
1.1 deraadt 290: case 'V':
291: printf("%s\n", rcs_version);
292: exit(0);
1.45 xsa 293: case 'x':
1.85 ray 294: /* Use blank extension if none given. */
295: rcs_suffixes = rcs_optarg ? rcs_optarg : "";
1.51 xsa 296: break;
297: case 'z':
298: /*
299: * kept for compatibility
300: */
1.45 xsa 301: break;
1.1 deraadt 302: default:
1.2 deraadt 303: (usage)();
1.1 deraadt 304: }
305: }
306:
1.28 joris 307: argc -= rcs_optind;
308: argv += rcs_optind;
1.30 joris 309:
1.1 deraadt 310: if (argc == 0) {
1.110 xsa 311: warnx("no input file");
1.5 joris 312: (usage)();
1.1 deraadt 313: }
314:
315: for (i = 0; i < argc; i++) {
1.128 ray 316: fd = rcs_choosefile(argv[i], fpath, sizeof(fpath));
317: if (fd < 0 && !(flags & RCS_CREATE)) {
1.133 niallo 318: warn("%s", fpath);
1.8 joris 319: continue;
1.128 ray 320: }
1.6 joris 321:
1.108 xsa 322: if (!(rcsflags & QUIET))
1.125 xsa 323: (void)fprintf(stderr, "RCS file: %s\n", fpath);
1.48 xsa 324:
1.132 ray 325: if ((file = rcs_open(fpath, fd, flags, fmode)) == NULL) {
326: close(fd);
1.6 joris 327: continue;
1.132 ray 328: }
1.1 deraadt 329:
1.132 ray 330: if (rcsflags & DESCRIPTION) {
1.161 millert 331: if (rcs_set_description(file, descfile, rcsflags) == -1) {
1.132 ray 332: warn("%s", descfile);
333: rcs_close(file);
334: continue;
335: }
336: }
337: else if (flags & RCS_CREATE) {
1.161 millert 338: if (rcs_set_description(file, NULL, rcsflags) == -1) {
1.132 ray 339: warn("stdin");
340: rcs_close(file);
341: continue;
342: }
343: }
1.56 joris 344:
345: if (rcsflags & PRESERVETIME)
1.118 joris 346: rcs_mtime = rcs_get_mtime(file);
1.48 xsa 347:
1.56 joris 348: if (nflag != NULL)
349: rcs_attach_symbol(file, nflag);
350:
1.24 joris 351: if (logstr != NULL) {
352: if ((logmsg = strchr(logstr, ':')) == NULL) {
1.110 xsa 353: warnx("missing log message");
1.24 joris 354: rcs_close(file);
355: continue;
356: }
357:
358: *logmsg++ = '\0';
359: if ((logrev = rcsnum_parse(logstr)) == NULL) {
1.116 xsa 360: warnx("`%s' bad revision number", logstr);
1.24 joris 361: rcs_close(file);
362: continue;
363: }
364:
365: if (rcs_rev_setlog(file, logrev, logmsg) < 0) {
1.116 xsa 366: warnx("failed to set logmsg for `%s' to `%s'",
1.24 joris 367: logstr, logmsg);
368: rcs_close(file);
1.25 joris 369: rcsnum_free(logrev);
1.24 joris 370: continue;
371: }
372:
373: rcsnum_free(logrev);
1.39 xsa 374: }
375:
376: /* entries to add from <oldfile> */
1.56 joris 377: if (rcsflags & CO_ACLAPPEND) {
1.129 ray 378: RCSFILE *oldfile;
379: int ofd;
1.155 deraadt 380: char ofpath[PATH_MAX];
1.129 ray 381:
382: ofd = rcs_choosefile(oldfilename, ofpath, sizeof(ofpath));
383: if (ofd < 0) {
384: if (!(flags & RCS_CREATE))
1.133 niallo 385: warn("%s", ofpath);
1.129 ray 386: exit(1);
387: }
1.118 joris 388: if ((oldfile = rcs_open(ofpath, ofd, RCS_READ)) == NULL)
1.39 xsa 389: exit(1);
390:
391: TAILQ_FOREACH(acp, &(oldfile->rf_access), ra_list)
392: rcs_access_add(file, acp->ra_name);
393:
394: rcs_close(oldfile);
1.129 ray 395: (void)close(ofd);
1.24 joris 396: }
397:
1.1 deraadt 398: /* entries to add to the access list */
399: if (alist != NULL) {
1.117 joris 400: struct rcs_argvector *aargv;
1.1 deraadt 401:
1.117 joris 402: aargv = rcs_strsplit(alist, ",");
1.86 pat 403: for (j = 0; aargv->argv[j] != NULL; j++)
404: rcs_access_add(file, aargv->argv[j]);
1.1 deraadt 405:
1.117 joris 406: rcs_argv_destroy(aargv);
1.1 deraadt 407: }
408:
409: if (comment != NULL)
410: rcs_comment_set(file, comment);
1.82 xsa 411:
412: if (elist != NULL) {
1.117 joris 413: struct rcs_argvector *eargv;
1.82 xsa 414:
1.117 joris 415: eargv = rcs_strsplit(elist, ",");
1.86 pat 416: for (j = 0; eargv->argv[j] != NULL; j++)
417: rcs_access_remove(file, eargv->argv[j]);
1.82 xsa 418:
1.117 joris 419: rcs_argv_destroy(eargv);
1.87 ray 420: } else if (rcsflags & RCSPROG_EFLAG) {
1.82 xsa 421: struct rcs_access *rap;
422:
423: /* XXX rcs_access_remove(file, NULL); ?? */
424: while (!TAILQ_EMPTY(&(file->rf_access))) {
425: rap = TAILQ_FIRST(&(file->rf_access));
426: TAILQ_REMOVE(&(file->rf_access), rap, ra_list);
1.156 nicm 427: free(rap->ra_name);
428: free(rap);
1.82 xsa 429: }
430: /* not synced anymore */
431: file->rf_flags &= ~RCS_SYNCED;
432: }
1.1 deraadt 433:
1.95 xsa 434: rcs_kwexp_set(file, kflag);
1.1 deraadt 435:
1.134 xsa 436: if (lkmode != RCS_LOCK_INVAL)
1.84 xsa 437: (void)rcs_lock_setmode(file, lkmode);
1.92 ray 438:
439: if (rcsflags & RCSPROG_LFLAG) {
440: RCSNUM *rev;
441: const char *username;
1.139 xsa 442: char rev_str[RCS_REV_BUFSZ];
1.92 ray 443:
1.141 joris 444: if (file->rf_head == NULL) {
445: warnx("%s contains no revisions", fpath);
446: rcs_close(file);
447: continue;
448: }
449:
1.92 ray 450: if ((username = getlogin()) == NULL)
1.115 xsa 451: err(1, "getlogin");
1.92 ray 452: if (lrev == NULL) {
453: rev = rcsnum_alloc();
454: rcsnum_cpy(file->rf_head, rev, 0);
455: } else if ((rev = rcsnum_parse(lrev)) == NULL) {
1.110 xsa 456: warnx("unable to unlock file");
1.92 ray 457: rcs_close(file);
458: continue;
459: }
1.98 ray 460: rcsnum_tostr(rev, rev_str, sizeof(rev_str));
1.92 ray 461: /* Make sure revision exists. */
462: if (rcs_findrev(file, rev) == NULL)
1.115 xsa 463: errx(1, "%s: cannot lock nonexisting "
464: "revision %s", fpath, rev_str);
1.98 ray 465: if (rcs_lock_add(file, username, rev) != -1 &&
1.108 xsa 466: !(rcsflags & QUIET))
1.127 xsa 467: (void)fprintf(stderr, "%s locked\n", rev_str);
1.92 ray 468: rcsnum_free(rev);
469: }
470:
471: if (rcsflags & RCSPROG_UFLAG) {
472: RCSNUM *rev;
473: const char *username;
1.139 xsa 474: char rev_str[RCS_REV_BUFSZ];
1.141 joris 475:
476: if (file->rf_head == NULL) {
477: warnx("%s contains no revisions", fpath);
478: rcs_close(file);
479: continue;
480: }
1.92 ray 481:
482: if ((username = getlogin()) == NULL)
1.115 xsa 483: err(1, "getlogin");
1.92 ray 484: if (urev == NULL) {
485: rev = rcsnum_alloc();
486: rcsnum_cpy(file->rf_head, rev, 0);
487: } else if ((rev = rcsnum_parse(urev)) == NULL) {
1.110 xsa 488: warnx("unable to unlock file");
1.92 ray 489: rcs_close(file);
490: continue;
491: }
1.98 ray 492: rcsnum_tostr(rev, rev_str, sizeof(rev_str));
1.92 ray 493: /* Make sure revision exists. */
494: if (rcs_findrev(file, rev) == NULL)
1.115 xsa 495: errx(1, "%s: cannot unlock nonexisting "
496: "revision %s", fpath, rev_str);
1.98 ray 497: if (rcs_lock_remove(file, username, rev) == -1 &&
1.108 xsa 498: !(rcsflags & QUIET))
1.110 xsa 499: warnx("%s: warning: No locks are set.", fpath);
1.127 xsa 500: else {
501: if (!(rcsflags & QUIET))
502: (void)fprintf(stderr,
503: "%s unlocked\n", rev_str);
504: }
1.92 ray 505: rcsnum_free(rev);
506: }
1.1 deraadt 507:
1.101 joris 508: if (orange != NULL) {
1.123 joris 509: struct rcs_delta *rdp, *nrdp;
1.139 xsa 510: char b[RCS_REV_BUFSZ];
1.101 joris 511:
512: rcs_rev_select(file, orange);
1.123 joris 513: for (rdp = TAILQ_FIRST(&(file->rf_delta));
514: rdp != NULL; rdp = nrdp) {
515: nrdp = TAILQ_NEXT(rdp, rd_list);
516:
1.101 joris 517: /*
518: * Delete selected revisions.
519: */
520: if (rdp->rd_flags & RCS_RD_SELECT) {
521: rcsnum_tostr(rdp->rd_num, b, sizeof(b));
1.162 joris 522:
523: if (rdp->rd_locker != NULL) {
524: errx(1, "%s: can't remove "
525: "locked revision %s",
526: fpath, b);
527: continue;
528: }
529:
1.125 xsa 530: if (!(rcsflags & QUIET)) {
531: (void)fprintf(stderr, "deleting"
532: " revision %s\n", b);
533: }
1.101 joris 534: (void)rcs_rev_remove(file, rdp->rd_num);
535: }
536: }
537: }
538:
1.118 joris 539: rcs_write(file);
1.48 xsa 540:
1.56 joris 541: if (rcsflags & PRESERVETIME)
1.118 joris 542: rcs_set_mtime(file, rcs_mtime);
543:
544: rcs_close(file);
1.9 joris 545:
1.108 xsa 546: if (!(rcsflags & QUIET))
1.125 xsa 547: (void)fprintf(stderr, "done\n");
1.1 deraadt 548: }
1.56 joris 549:
1.1 deraadt 550: return (0);
1.56 joris 551: }
552:
553: static void
554: rcs_attach_symbol(RCSFILE *file, const char *symname)
555: {
556: char *rnum;
557: RCSNUM *rev;
1.139 xsa 558: char rbuf[RCS_REV_BUFSZ];
1.56 joris 559: int rm;
560:
561: rm = 0;
562: rev = NULL;
563: if ((rnum = strrchr(symname, ':')) != NULL) {
564: if (rnum[1] == '\0')
565: rev = file->rf_head;
566: *(rnum++) = '\0';
567: } else {
568: rm = 1;
569: }
570:
571: if (rev == NULL && rm != 1) {
572: if ((rev = rcsnum_parse(rnum)) == NULL)
1.115 xsa 573: errx(1, "bad revision %s", rnum);
1.56 joris 574: }
575:
1.87 ray 576: if (rcsflags & RCSPROG_NFLAG)
1.56 joris 577: rm = 1;
578:
579: if (rm == 1) {
580: if (rcs_sym_remove(file, symname) < 0) {
1.102 deraadt 581: if (rcs_errno == RCS_ERR_NOENT &&
1.87 ray 582: !(rcsflags & RCSPROG_NFLAG))
1.115 xsa 583: warnx("cannot delete nonexisting symbol %s",
1.110 xsa 584: symname);
1.56 joris 585: } else {
1.87 ray 586: if (rcsflags & RCSPROG_NFLAG)
1.56 joris 587: rm = 0;
588: }
589: }
590:
591: if (rm == 0) {
1.102 deraadt 592: if (rcs_sym_add(file, symname, rev) < 0 &&
593: rcs_errno == RCS_ERR_DUPENT) {
1.56 joris 594: rcsnum_tostr(rcs_sym_getrev(file, symname),
595: rbuf, sizeof(rbuf));
1.115 xsa 596: errx(1, "symbolic name %s already bound to %s",
1.56 joris 597: symname, rbuf);
598: }
599: }
1.1 deraadt 600: }