Annotation of src/usr.bin/rcs/rcsprog.c, Revision 1.28
1.28 ! joris 1: /* $OpenBSD: rcsprog.c,v 1.27 2005/10/12 17:43:18 xsa 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.6 joris 27: #include <sys/param.h>
1.1 deraadt 28: #include <sys/wait.h>
1.8 joris 29: #include <sys/stat.h>
1.1 deraadt 30:
1.3 joris 31: #include <ctype.h>
1.1 deraadt 32: #include <err.h>
1.3 joris 33: #include <errno.h>
1.1 deraadt 34: #include <pwd.h>
1.3 joris 35: #include <string.h>
1.1 deraadt 36: #include <stdio.h>
37: #include <stdlib.h>
38: #include <unistd.h>
39:
40: #include "log.h"
41: #include "rcs.h"
1.9 joris 42: #include "rcsprog.h"
1.1 deraadt 43: #include "strtab.h"
44:
45: const char rcs_version[] = "OpenCVS RCS version 3.6";
1.12 joris 46: int verbose = 1;
1.1 deraadt 47:
1.28 ! joris 48: int rcs_optind;
! 49: char *rcs_optarg;
! 50:
1.1 deraadt 51: struct rcs_prog {
1.26 deraadt 52: char *prog_name;
53: int (*prog_hdlr)(int, char **);
54: void (*prog_usage)(void);
1.1 deraadt 55: } programs[] = {
1.2 deraadt 56: { "rcs", rcs_main, rcs_usage },
1.17 joris 57: { "ci", checkin_main, checkin_usage },
1.11 joris 58: { "co", checkout_main, checkout_usage },
1.20 joris 59: { "rcsclean", rcsclean_main, rcsclean_usage },
1.18 joris 60: { "rcsdiff", rcsdiff_main, rcsdiff_usage },
1.21 joris 61: { "rlog", rlog_main, rlog_usage },
1.22 joris 62: { "ident", ident_main, ident_usage },
1.1 deraadt 63: };
64:
1.9 joris 65: int
1.28 ! joris 66: rcs_getopt(int argc, char **argv, const char *optstr)
! 67: {
! 68: char *a;
! 69: const char *c;
! 70: static int i = 1;
! 71: int opt, hasargument, ret;
! 72:
! 73: hasargument = 0;
! 74: rcs_optarg = NULL;
! 75:
! 76: if (i >= argc)
! 77: return (-1);
! 78:
! 79: a = argv[i++];
! 80: if (*a++ != '-')
! 81: return (-1);
! 82:
! 83: ret = 0;
! 84: opt = *a;
! 85: for (c = optstr; *c != '\0'; c++) {
! 86: if (*c == opt) {
! 87: a++;
! 88: ret = opt;
! 89:
! 90: if (*(c + 1) == ':') {
! 91: if (*(c + 2) == ':') {
! 92: if (*a != '\0')
! 93: hasargument = 1;
! 94: } else {
! 95: if (*a != '\0') {
! 96: hasargument = 1;
! 97: } else {
! 98: ret = 1;
! 99: break;
! 100: }
! 101: }
! 102: }
! 103:
! 104: if (hasargument == 1)
! 105: rcs_optarg = a;
! 106:
! 107: if (ret == opt)
! 108: rcs_optind++;
! 109: break;
! 110: }
! 111: }
! 112:
! 113: if (ret == 0)
! 114: cvs_log(LP_ERR, "unknown option -%c", opt);
! 115: else if (ret == 1)
! 116: cvs_log(LP_ERR, "missing argument for option -%c", opt);
! 117:
! 118: return (ret);
! 119: }
! 120:
! 121: int
1.9 joris 122: rcs_statfile(char *fname, char *out, size_t len)
123: {
124: int l;
125: char *s;
126: char filev[MAXPATHLEN], fpath[MAXPATHLEN];
127: struct stat st;
128:
129: l = snprintf(filev, sizeof(filev), "%s%s", fname, RCS_FILE_EXT);
130: if (l == -1 || l >= (int)sizeof(filev))
131: return (-1);
132:
1.16 joris 133: if ((stat(RCSDIR, &st) != -1) && (st.st_mode & S_IFDIR)) {
1.9 joris 134: l = snprintf(fpath, sizeof(fpath), "%s/%s", RCSDIR, filev);
135: if (l == -1 || l >= (int)sizeof(fpath))
136: return (-1);
137: } else {
138: strlcpy(fpath, filev, sizeof(fpath));
139: }
140:
141: if (stat(fpath, &st) == -1) {
1.20 joris 142: if (strcmp(__progname, "rcsclean"))
143: cvs_log(LP_ERRNO, "%s", fpath);
1.9 joris 144: return (-1);
145: }
146:
147: strlcpy(out, fpath, len);
1.27 xsa 148: if ((verbose == 1) && (strcmp(__progname, "rcsclean"))) {
1.12 joris 149: if (!strcmp(__progname, "co")) {
1.19 joris 150: printf("%s --> ", fpath);
1.12 joris 151: if ((s = strrchr(filev, ',')) != NULL) {
152: *s = '\0';
153: printf("%s\n", fname);
154: }
155: } else {
156: printf("RCS file: %s\n", fpath);
1.9 joris 157: }
158: }
159:
160: return (0);
161: }
1.1 deraadt 162:
163: int
164: main(int argc, char **argv)
165: {
166: u_int i;
167: int ret;
168:
169: ret = -1;
1.28 ! joris 170: rcs_optind = 1;
1.1 deraadt 171: cvs_strtab_init();
1.9 joris 172: cvs_log_init(LD_STD, 0);
1.1 deraadt 173:
174: for (i = 0; i < (sizeof(programs)/sizeof(programs[0])); i++)
1.2 deraadt 175: if (strcmp(__progname, programs[i].prog_name) == 0) {
176: usage = programs[i].prog_usage;
1.1 deraadt 177: ret = programs[i].prog_hdlr(argc, argv);
1.2 deraadt 178: break;
179: }
1.1 deraadt 180:
181: cvs_strtab_cleanup();
182:
1.23 niallo 183: exit(ret);
1.1 deraadt 184: }
185:
186:
187: void
188: rcs_usage(void)
189: {
190: fprintf(stderr,
1.26 deraadt 191: "usage: rcs [-hiLMUV] [-a users] [-b [rev]] [-c string] [-e users]\n"
192: " [-k opt] [-m rev:log] file ...\n");
1.1 deraadt 193: }
194:
195: /*
196: * rcs_main()
197: *
198: * Handler for the `rcs' program.
199: * Returns 0 on success, or >0 on error.
200: */
201: int
202: rcs_main(int argc, char **argv)
203: {
204: int i, ch, flags, kflag, lkmode;
1.10 joris 205: char fpath[MAXPATHLEN];
1.24 joris 206: char *logstr, *logmsg;
1.1 deraadt 207: char *oldfile, *alist, *comment, *elist, *unp, *sp;
208: mode_t fmode;
209: RCSFILE *file;
1.24 joris 210: RCSNUM *logrev;
1.1 deraadt 211:
212: kflag = lkmode = -1;
213: fmode = 0;
214: flags = RCS_RDWR;
1.24 joris 215: logstr = oldfile = alist = comment = elist = NULL;
1.1 deraadt 216:
1.28 ! joris 217: while ((ch = rcs_getopt(argc, argv, "A:a:b::c:e::hik:Lm:MqUV")) != -1) {
1.1 deraadt 218: switch (ch) {
219: case 'A':
1.28 ! joris 220: oldfile = rcs_optarg;
1.1 deraadt 221: break;
222: case 'a':
1.28 ! joris 223: alist = rcs_optarg;
1.1 deraadt 224: break;
225: case 'c':
1.28 ! joris 226: comment = rcs_optarg;
1.1 deraadt 227: break;
228: case 'e':
1.28 ! joris 229: elist = rcs_optarg;
1.1 deraadt 230: break;
231: case 'h':
1.2 deraadt 232: (usage)();
1.1 deraadt 233: exit(0);
234: case 'i':
235: flags |= RCS_CREATE;
236: break;
237: case 'k':
1.28 ! joris 238: kflag = rcs_kflag_get(rcs_optarg);
1.1 deraadt 239: if (RCS_KWEXP_INVAL(kflag)) {
240: cvs_log(LP_ERR,
241: "invalid keyword substitution mode `%s'",
1.28 ! joris 242: rcs_optarg);
1.1 deraadt 243: exit(1);
244: }
245: break;
246: case 'L':
247: if (lkmode == RCS_LOCK_LOOSE)
248: cvs_log(LP_WARN, "-U overriden by -L");
249: lkmode = RCS_LOCK_STRICT;
250: break;
1.24 joris 251: case 'm':
1.28 ! joris 252: if ((logstr = strdup(rcs_optarg)) == NULL) {
1.24 joris 253: cvs_log(LP_ERRNO, "failed to copy logstring");
254: exit(1);
255: }
256: break;
1.1 deraadt 257: case 'M':
258: /* ignore for the moment */
259: break;
1.12 joris 260: case 'q':
261: verbose = 0;
262: break;
1.1 deraadt 263: case 'U':
264: if (lkmode == RCS_LOCK_STRICT)
265: cvs_log(LP_WARN, "-L overriden by -U");
266: lkmode = RCS_LOCK_LOOSE;
267: break;
268: case 'V':
269: printf("%s\n", rcs_version);
270: exit(0);
271: default:
1.2 deraadt 272: (usage)();
1.1 deraadt 273: exit(1);
274: }
275: }
276:
1.28 ! joris 277: argc -= rcs_optind;
! 278: argv += rcs_optind;
1.1 deraadt 279: if (argc == 0) {
280: cvs_log(LP_ERR, "no input file");
1.5 joris 281: (usage)();
1.1 deraadt 282: exit(1);
283: }
284:
285: for (i = 0; i < argc; i++) {
1.9 joris 286: if (rcs_statfile(argv[i], fpath, sizeof(fpath)) < 0)
1.8 joris 287: continue;
1.6 joris 288:
289: file = rcs_open(fpath, flags, fmode);
290: if (file == NULL)
291: continue;
1.1 deraadt 292:
1.24 joris 293: if (logstr != NULL) {
294: if ((logmsg = strchr(logstr, ':')) == NULL) {
295: cvs_log(LP_ERR, "missing log message");
296: rcs_close(file);
297: continue;
298: }
299:
300: *logmsg++ = '\0';
301: if ((logrev = rcsnum_parse(logstr)) == NULL) {
302: cvs_log(LP_ERR, "'%s' bad revision number", logstr);
303: rcs_close(file);
304: continue;
305: }
306:
307: if (rcs_rev_setlog(file, logrev, logmsg) < 0) {
308: cvs_log(LP_ERR,
309: "failed to set logmsg for '%s' to '%s'",
310: logstr, logmsg);
311: rcs_close(file);
1.25 joris 312: rcsnum_free(logrev);
1.24 joris 313: continue;
314: }
315:
316: rcsnum_free(logrev);
317: }
318:
1.1 deraadt 319: /* entries to add to the access list */
320: if (alist != NULL) {
321: unp = alist;
322: do {
323: sp = strchr(unp, ',');
324: if (sp != NULL)
325: *(sp++) = '\0';
326:
327: rcs_access_add(file, unp);
328:
329: unp = sp;
330: } while (sp != NULL);
331: }
332:
333: if (comment != NULL)
334: rcs_comment_set(file, comment);
335:
336: if (kflag != -1)
337: rcs_kwexp_set(file, kflag);
338:
339: if (lkmode != -1)
340: rcs_lock_setmode(file, lkmode);
341:
342: rcs_close(file);
1.9 joris 343:
1.14 xsa 344: if (verbose == 1)
1.12 joris 345: printf("done\n");
1.1 deraadt 346: }
1.24 joris 347:
348: if (logstr != NULL)
349: free(logstr);
1.1 deraadt 350:
351: return (0);
352: }