Annotation of src/usr.bin/cvs/admin.c, Revision 1.31
1.31 ! ray 1: /* $OpenBSD: admin.c,v 1.30 2006/03/16 09:06:19 xsa Exp $ */
1.1 joris 2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
4: * Copyright (c) 2005 Joris Vink <joris@openbsd.org>
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: *
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. The name of the author may not be used to endorse or promote products
14: * derived from this software without specific prior written permission.
15: *
16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26: */
27:
1.26 xsa 28: #include "includes.h"
1.1 joris 29:
30: #include "cvs.h"
31: #include "log.h"
32: #include "proto.h"
33:
34:
35: #define LOCK_SET 0x01
36: #define LOCK_REMOVE 0x02
37:
38: #define FLAG_BRANCH 0x01
39: #define FLAG_DELUSER 0x02
40: #define FLAG_INTERACTIVE 0x04
41: #define FLAG_QUIET 0x08
42:
1.22 xsa 43: static int cvs_admin_init(struct cvs_cmd *, int, char **, int *);
44: static int cvs_admin_pre_exec(struct cvsroot *);
45: static int cvs_admin_remote(CVSFILE *, void *);
46: static int cvs_admin_local(CVSFILE *, void *);
1.15 jfb 47:
48: struct cvs_cmd cvs_cmd_admin = {
49: CVS_OP_ADMIN, CVS_REQ_ADMIN, "admin",
50: { "adm", "rcs" },
51: "Administrative front-end for RCS",
52: "",
53: "a:A:b::c:e::Ik:l::Lm:n:N:o:qs:t:u::U",
54: NULL,
55: CF_SORT | CF_IGNORE | CF_RECURSE,
56: cvs_admin_init,
57: cvs_admin_pre_exec,
1.16 jfb 58: cvs_admin_remote,
59: cvs_admin_local,
1.15 jfb 60: NULL,
61: NULL,
1.7 joris 62: CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR | CVS_CMD_SENDARGS2
63: };
64:
65: static char *q, *Ntag, *ntag, *comment, *replace_msg;
66: static char *alist, *subst, *lockrev_arg, *unlockrev_arg;
67: static char *state, *userfile, *branch_arg, *elist, *range;
1.16 jfb 68: static int runflags, kflag, lockrev, lkmode;
69:
70: /* flag as invalid */
71: static int kflag = RCS_KWEXP_ERR;
72: static int lkmode = RCS_LOCK_INVAL;
1.7 joris 73:
1.15 jfb 74: static int
75: cvs_admin_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
1.1 joris 76: {
1.7 joris 77: int ch;
1.1 joris 78: RCSNUM *rcs;
79:
1.16 jfb 80: runflags = lockrev = 0;
1.5 joris 81: Ntag = ntag = comment = replace_msg = NULL;
82: state = alist = subst = elist = lockrev_arg = NULL;
83: range = userfile = branch_arg = unlockrev_arg = NULL;
1.1 joris 84:
85: /* option-o-rama ! */
1.15 jfb 86: while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
1.1 joris 87: switch (ch) {
88: case 'a':
89: alist = optarg;
90: break;
91: case 'A':
92: userfile = optarg;
93: break;
94: case 'b':
95: runflags |= FLAG_BRANCH;
96: if (optarg)
97: branch_arg = optarg;
98: break;
99: case 'c':
100: comment = optarg;
101: break;
102: case 'e':
103: runflags |= FLAG_DELUSER;
104: if (optarg)
105: elist = optarg;
106: break;
107: case 'I':
108: runflags |= FLAG_INTERACTIVE;
109: break;
110: case 'k':
111: subst = optarg;
1.3 joris 112: kflag = rcs_kflag_get(subst);
113: if (RCS_KWEXP_INVAL(kflag)) {
114: cvs_log(LP_ERR,
115: "invalid RCS keyword expansion mode");
116: rcs_kflag_usage();
1.11 joris 117: return (CVS_EX_USAGE);
1.3 joris 118: }
1.1 joris 119: break;
120: case 'l':
121: lockrev |= LOCK_SET;
122: if (optarg)
123: lockrev_arg = optarg;
124: break;
125: case 'L':
1.16 jfb 126: lkmode = RCS_LOCK_STRICT;
1.1 joris 127: break;
128: case 'm':
129: replace_msg = optarg;
130: break;
131: case 'n':
1.5 joris 132: ntag = optarg;
1.1 joris 133: break;
134: case 'N':
1.5 joris 135: Ntag = optarg;
1.1 joris 136: break;
137: case 'o':
1.5 joris 138: range = optarg;
1.1 joris 139: break;
140: case 'q':
141: runflags |= FLAG_QUIET;
142: break;
143: case 's':
1.5 joris 144: state = optarg;
1.1 joris 145: break;
146: case 't':
147: break;
148: case 'u':
149: lockrev |= LOCK_REMOVE;
150: if (optarg)
151: unlockrev_arg = optarg;
152: break;
153: case 'U':
1.16 jfb 154: if (lkmode != RCS_LOCK_INVAL) {
155: cvs_log(LP_ERR, "-L and -U are incompatible");
156: return (CVS_EX_USAGE);
157: }
158: lkmode = RCS_LOCK_LOOSE;
1.1 joris 159: break;
160: default:
1.11 joris 161: return (CVS_EX_USAGE);
1.1 joris 162: }
163: }
164:
165: argc -= optind;
166: argv += optind;
167:
168: if (lockrev_arg != NULL) {
169: if ((rcs = rcsnum_parse(lockrev_arg)) == NULL) {
170: cvs_log(LP_ERR, "%s is not a numeric branch",
171: lockrev_arg);
1.11 joris 172: return (CVS_EX_USAGE);
1.1 joris 173: }
174: rcsnum_free(rcs);
175: }
176:
177: if (unlockrev_arg != NULL) {
178: if ((rcs = rcsnum_parse(unlockrev_arg)) == NULL) {
179: cvs_log(LP_ERR, "%s is not a numeric branch",
180: unlockrev_arg);
1.11 joris 181: return (CVS_EX_USAGE);
1.1 joris 182: }
183: rcsnum_free(rcs);
184: }
185:
186: if (replace_msg != NULL) {
187: if ((q = strchr(replace_msg, ':')) == NULL) {
188: cvs_log(LP_ERR, "invalid option for -m");
1.11 joris 189: return (CVS_EX_USAGE);
1.1 joris 190: }
191: *q = '\0';
192: if ((rcs = rcsnum_parse(replace_msg)) == NULL) {
193: cvs_log(LP_ERR, "%s is not a numeric revision",
194: replace_msg);
1.11 joris 195: return (CVS_EX_USAGE);
1.1 joris 196: }
1.2 joris 197: rcsnum_free(rcs);
1.1 joris 198: *q = ':';
199: }
200:
1.7 joris 201: *arg = optind;
202: return (0);
203: }
1.1 joris 204:
1.15 jfb 205: static int
206: cvs_admin_pre_exec(struct cvsroot *root)
1.7 joris 207: {
1.16 jfb 208: if (root->cr_method == CVS_METHOD_LOCAL)
209: return (0);
210:
1.25 joris 211: if (alist != NULL) {
212: cvs_sendarg(root, "-a", 0);
213: cvs_sendarg(root, alist, 0);
214: }
215:
216: if (userfile != NULL) {
217: cvs_sendarg(root, "-A", 0);
218: cvs_sendarg(root, userfile, 0);
219: }
1.1 joris 220:
1.7 joris 221: if (runflags & FLAG_BRANCH) {
1.25 joris 222: cvs_sendarg(root, "-b", 0);
223: if (branch_arg != NULL)
224: cvs_sendarg(root, branch_arg, 0);
1.7 joris 225: }
1.1 joris 226:
1.25 joris 227: if (comment != NULL) {
228: cvs_sendarg(root, "-c", 0);
229: cvs_sendarg(root, comment, 0);
230: }
1.1 joris 231:
1.7 joris 232: if (runflags & FLAG_DELUSER) {
1.25 joris 233: cvs_sendarg(root, "-e", 0);
234: if (elist != NULL)
235: cvs_sendarg(root, elist, 0);
236: }
237:
238: if (runflags & FLAG_INTERACTIVE)
239: cvs_sendarg(root, "-I", 0);
240:
241: if (subst != NULL) {
242: cvs_sendarg(root, "-k", 0);
243: cvs_sendarg(root, subst, 0);
1.7 joris 244: }
1.1 joris 245:
1.25 joris 246: if (lockrev & LOCK_SET) {
247: cvs_sendarg(root, "-l", 0);
248: if (lockrev_arg != NULL)
249: cvs_sendarg(root, lockrev_arg, 0);
1.7 joris 250: }
1.1 joris 251:
1.25 joris 252: if (lkmode == RCS_LOCK_STRICT)
253: cvs_sendarg(root, "-L", 0);
254: else if (lkmode == RCS_LOCK_LOOSE)
255: cvs_sendarg(root, "-U", 0);
256:
257: if (replace_msg != NULL) {
258: cvs_sendarg(root, "-m", 0);
259: cvs_sendarg(root, replace_msg, 0);
260: }
1.5 joris 261:
1.25 joris 262: if (ntag != NULL) {
263: cvs_sendarg(root, "-n", 0);
264: cvs_sendarg(root, ntag, 0);
265: }
266:
267: if (Ntag != NULL) {
268: cvs_sendarg(root, "-N", 0);
269: cvs_sendarg(root, Ntag, 0);
270: }
271:
272: if (range != NULL) {
273: cvs_sendarg(root, "-o", 0);
274: cvs_sendarg(root, range, 0);
275: }
276:
277: if (state != NULL) {
278: cvs_sendarg(root, "-s", 0);
279: cvs_sendarg(root, state, 0);
280: }
1.1 joris 281:
1.7 joris 282: if (lockrev & LOCK_REMOVE) {
1.25 joris 283: cvs_sendarg(root, "-u", 0);
284: if (unlockrev_arg != NULL)
285: cvs_sendarg(root, unlockrev_arg, 0);
1.1 joris 286: }
287:
288: return (0);
289: }
290:
291: /*
1.16 jfb 292: * cvs_admin_remote()
1.1 joris 293: *
294: * Perform admin commands on each file.
295: */
1.15 jfb 296: static int
1.16 jfb 297: cvs_admin_remote(CVSFILE *cf, void *arg)
1.1 joris 298: {
1.30 xsa 299: char fpath[MAXPATHLEN];
1.1 joris 300: struct cvsroot *root;
301:
1.16 jfb 302: root = CVS_DIR_ROOT(cf);
1.14 joris 303:
1.16 jfb 304: if (cf->cf_type == DT_DIR) {
305: if (cf->cf_cvstat == CVS_FST_UNKNOWN)
1.25 joris 306: cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
1.16 jfb 307: else
1.25 joris 308: cvs_senddir(root, cf);
309: return (0);
1.1 joris 310: }
311:
1.16 jfb 312: cvs_file_getpath(cf, fpath, sizeof(fpath));
1.25 joris 313: cvs_sendentry(root, cf);
1.16 jfb 314:
315: switch (cf->cf_cvstat) {
316: case CVS_FST_UNKNOWN:
1.25 joris 317: cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
1.16 jfb 318: break;
319: case CVS_FST_UPTODATE:
1.25 joris 320: cvs_sendreq(root, CVS_REQ_UNCHANGED, cf->cf_name);
1.16 jfb 321: break;
322: case CVS_FST_MODIFIED:
1.25 joris 323: cvs_sendreq(root, CVS_REQ_MODIFIED, cf->cf_name);
324: cvs_sendfile(root, fpath);
1.31 ! ray 325: break;
1.16 jfb 326: default:
327: break;
328: }
1.1 joris 329:
1.25 joris 330: return (0);
1.16 jfb 331: }
1.14 joris 332:
1.16 jfb 333: /*
334: * cvs_admin_local()
335: *
336: * Perform administrative operations on a local RCS file.
337: */
338: static int
339: cvs_admin_local(CVSFILE *cf, void *arg)
340: {
1.20 xsa 341: int ret;
342: char fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
1.16 jfb 343: RCSFILE *rf;
1.19 xsa 344:
345: if (cf->cf_type == DT_DIR) {
346: if (verbosity > 1)
1.23 xsa 347: cvs_log(LP_NOTICE, "Administrating %s", cf->cf_name);
1.19 xsa 348: return (0);
349: }
1.1 joris 350:
1.29 xsa 351: if (cf->cf_cvstat == CVS_FST_UNKNOWN)
352: return (0);
353: else if (cf->cf_cvstat == CVS_FST_ADDED) {
354: cvs_log(LP_WARN, "cannot admin newly added file `%s'",
355: cf->cf_name);
1.16 jfb 356: return (0);
357: }
1.1 joris 358:
1.16 jfb 359: cvs_file_getpath(cf, fpath, sizeof(fpath));
1.24 xsa 360: cvs_rcs_getpath(cf, rcspath, sizeof(rcspath));
1.1 joris 361:
1.27 xsa 362: if ((rf = rcs_open(rcspath, RCS_RDWR)) == NULL)
363: fatal("cvs_admin_local: rcs_open `%s': %s", rcspath,
1.28 xsa 364: rcs_errstr(rcs_errno));
1.16 jfb 365:
1.29 xsa 366: if (!(runflags & FLAG_QUIET))
367: cvs_printf("RCS file: %s\n", rcspath);
368:
1.16 jfb 369: if (!RCS_KWEXP_INVAL(kflag))
370: ret = rcs_kwexp_set(rf, kflag);
371: if (lkmode != RCS_LOCK_INVAL)
372: ret = rcs_lock_setmode(rf, lkmode);
373:
374: rcs_close(rf);
1.29 xsa 375:
376: if (!(runflags & FLAG_QUIET))
377: cvs_printf("done\n");
1.16 jfb 378:
379: return (0);
1.1 joris 380: }