Annotation of src/usr.bin/cvs/admin.c, Revision 1.10
1.10 ! joris 1: /* $OpenBSD: admin.c,v 1.9 2005/04/11 17:56:27 joris 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:
28: #include <sys/types.h>
29: #include <sys/stat.h>
30:
31: #include <errno.h>
32: #include <stdio.h>
33: #include <fcntl.h>
34: #include <stdlib.h>
35: #include <unistd.h>
36: #include <string.h>
37:
38: #include "cvs.h"
39: #include "log.h"
40: #include "proto.h"
41:
42:
43: #define LOCK_SET 0x01
44: #define LOCK_REMOVE 0x02
45:
46: #define FLAG_BRANCH 0x01
47: #define FLAG_DELUSER 0x02
48: #define FLAG_INTERACTIVE 0x04
49: #define FLAG_QUIET 0x08
50:
1.7 joris 51: int cvs_admin_options(char *, int, char **, int *);
52: int cvs_admin_sendflags(struct cvsroot *);
53: int cvs_admin_file(CVSFILE *, void *);
54:
55: struct cvs_cmd_info cvs_admin = {
56: cvs_admin_options,
57: cvs_admin_sendflags,
58: cvs_admin_file,
59: NULL, NULL,
60: CF_SORT | CF_IGNORE | CF_RECURSE,
61: CVS_REQ_ADMIN,
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;
68: static int runflags, kflag, lockrev, strictlock;
69:
1.1 joris 70: int
1.7 joris 71: cvs_admin_options(char *opt, int argc, char **argv, int *arg)
1.1 joris 72: {
1.7 joris 73: int ch;
1.1 joris 74: RCSNUM *rcs;
75:
76: runflags = strictlock = lockrev = 0;
1.5 joris 77: Ntag = ntag = comment = replace_msg = NULL;
78: state = alist = subst = elist = lockrev_arg = NULL;
79: range = userfile = branch_arg = unlockrev_arg = NULL;
1.1 joris 80:
81: /* option-o-rama ! */
1.7 joris 82: while ((ch = getopt(argc, argv, opt)) != -1) {
1.1 joris 83: switch (ch) {
84: case 'a':
85: alist = optarg;
86: break;
87: case 'A':
88: userfile = optarg;
89: break;
90: case 'b':
91: runflags |= FLAG_BRANCH;
92: if (optarg)
93: branch_arg = optarg;
94: break;
95: case 'c':
96: comment = optarg;
97: break;
98: case 'e':
99: runflags |= FLAG_DELUSER;
100: if (optarg)
101: elist = optarg;
102: break;
103: case 'I':
104: runflags |= FLAG_INTERACTIVE;
105: break;
106: case 'k':
107: subst = optarg;
1.3 joris 108: kflag = rcs_kflag_get(subst);
109: if (RCS_KWEXP_INVAL(kflag)) {
110: cvs_log(LP_ERR,
111: "invalid RCS keyword expansion mode");
112: rcs_kflag_usage();
1.9 joris 113: return (1);
1.3 joris 114: }
1.1 joris 115: break;
116: case 'l':
117: lockrev |= LOCK_SET;
118: if (optarg)
119: lockrev_arg = optarg;
120: break;
121: case 'L':
122: strictlock |= LOCK_SET;
123: break;
124: case 'm':
125: replace_msg = optarg;
126: break;
127: case 'n':
1.5 joris 128: ntag = optarg;
1.1 joris 129: break;
130: case 'N':
1.5 joris 131: Ntag = optarg;
1.1 joris 132: break;
133: case 'o':
1.5 joris 134: range = optarg;
1.1 joris 135: break;
136: case 'q':
137: runflags |= FLAG_QUIET;
138: break;
139: case 's':
1.5 joris 140: state = optarg;
1.1 joris 141: break;
142: case 't':
143: break;
144: case 'u':
145: lockrev |= LOCK_REMOVE;
146: if (optarg)
147: unlockrev_arg = optarg;
148: break;
149: case 'U':
150: strictlock |= LOCK_REMOVE;
151: break;
152: default:
1.9 joris 153: return (1);
1.1 joris 154: }
155: }
156:
157: argc -= optind;
158: argv += optind;
159:
160: /* do some sanity checking on the arguments */
161: if ((strictlock & LOCK_SET) && (strictlock & LOCK_REMOVE)) {
162: cvs_log(LP_ERR, "-L and -U are incompatible");
1.8 xsa 163: return (-1);
1.1 joris 164: }
165:
166: if (lockrev_arg != NULL) {
167: if ((rcs = rcsnum_parse(lockrev_arg)) == NULL) {
168: cvs_log(LP_ERR, "%s is not a numeric branch",
169: lockrev_arg);
1.9 joris 170: return (1);
1.1 joris 171: }
172: rcsnum_free(rcs);
173: }
174:
175: if (unlockrev_arg != NULL) {
176: if ((rcs = rcsnum_parse(unlockrev_arg)) == NULL) {
177: cvs_log(LP_ERR, "%s is not a numeric branch",
178: unlockrev_arg);
1.8 xsa 179: return (-1);
1.1 joris 180: }
181: rcsnum_free(rcs);
182: }
183:
184: if (replace_msg != NULL) {
185: if ((q = strchr(replace_msg, ':')) == NULL) {
186: cvs_log(LP_ERR, "invalid option for -m");
1.9 joris 187: return (1);
1.1 joris 188: }
189: *q = '\0';
190: if ((rcs = rcsnum_parse(replace_msg)) == NULL) {
191: cvs_log(LP_ERR, "%s is not a numeric revision",
192: replace_msg);
1.8 xsa 193: return (-1);
1.1 joris 194: }
1.2 joris 195: rcsnum_free(rcs);
1.1 joris 196: *q = ':';
197: }
198:
1.7 joris 199: *arg = optind;
200: return (0);
201: }
1.1 joris 202:
1.7 joris 203: int
204: cvs_admin_sendflags(struct cvsroot *root)
205: {
206: if ((alist != NULL) && ((cvs_sendarg(root, "-a", 0) < 0) ||
207: (cvs_sendarg(root, alist, 0) < 0)))
1.8 xsa 208: return (-1);
1.1 joris 209:
1.7 joris 210: if ((userfile != NULL) && ((cvs_sendarg(root, "-A", 0) < 0) ||
211: (cvs_sendarg(root, userfile, 0) < 0)))
1.8 xsa 212: return (-1);
1.1 joris 213:
1.7 joris 214: if (runflags & FLAG_BRANCH) {
215: if (cvs_sendarg(root, "-b", 0) < 0)
1.8 xsa 216: return (-1);
1.7 joris 217: if ((branch_arg != NULL) &&
218: (cvs_sendarg(root, branch_arg, 0) < 0))
1.8 xsa 219: return (-1);
1.7 joris 220: }
1.1 joris 221:
1.7 joris 222: if ((comment != NULL) && ((cvs_sendarg(root, "-c", 0) < 0) ||
223: (cvs_sendarg(root, comment, 0) < 0)))
1.8 xsa 224: return (-1);
1.1 joris 225:
1.7 joris 226: if (runflags & FLAG_DELUSER) {
227: if (cvs_sendarg(root, "-e", 0) < 0)
1.8 xsa 228: return (-1);
1.7 joris 229: if ((elist != NULL) &&
230: (cvs_sendarg(root, elist, 0) < 0))
1.8 xsa 231: return (-1);
1.7 joris 232: }
1.1 joris 233:
1.7 joris 234: if (runflags & FLAG_INTERACTIVE) {
235: if (cvs_sendarg(root, "-I", 0) < 0)
1.8 xsa 236: return (-1);
1.7 joris 237: }
1.1 joris 238:
1.7 joris 239: if ((subst != NULL) && ((cvs_sendarg(root, "-k", 0) < 0) ||
240: (cvs_sendarg(root, subst, 0) < 0)))
1.8 xsa 241: return (-1);
1.5 joris 242:
1.7 joris 243: if (lockrev & LOCK_SET) {
244: if (cvs_sendarg(root, "-l", 0) < 0)
1.8 xsa 245: return (-1);
1.7 joris 246: if ((lockrev_arg != NULL) &&
247: (cvs_sendarg(root, lockrev_arg, 0) < 0))
1.8 xsa 248: return (-1);
1.7 joris 249: }
1.5 joris 250:
1.7 joris 251: if ((strictlock & LOCK_SET) &&
252: (cvs_sendarg(root, "-L", 0) < 0))
1.8 xsa 253: return (-1);
1.5 joris 254:
1.7 joris 255: if ((replace_msg != NULL) && ((cvs_sendarg(root, "-m", 0) < 0)
256: || (cvs_sendarg(root, replace_msg, 0) < 0)))
1.8 xsa 257: return (-1);
1.5 joris 258:
1.7 joris 259: if ((ntag != NULL) && ((cvs_sendarg(root, "-n", 0) < 0) ||
260: (cvs_sendarg(root, ntag, 0) < 0)))
1.8 xsa 261: return (-1);
1.1 joris 262:
1.7 joris 263: if ((Ntag != NULL) && ((cvs_sendarg(root, "-N", 0) < 0) ||
264: (cvs_sendarg(root, Ntag, 0) < 0)))
1.8 xsa 265: return (-1);
1.1 joris 266:
1.7 joris 267: if ((range != NULL) && ((cvs_sendarg(root, "-o", 0) < 0) ||
268: (cvs_sendarg(root, range, 0) < 0)))
1.8 xsa 269: return (-1);
1.1 joris 270:
1.7 joris 271: if ((state != NULL) && ((cvs_sendarg(root, "-s", 0) < 0) ||
272: (cvs_sendarg(root, state, 0) < 0)))
1.8 xsa 273: return (-1);
1.1 joris 274:
1.7 joris 275: if (lockrev & LOCK_REMOVE) {
276: if (cvs_sendarg(root, "-u", 0) < 0)
1.8 xsa 277: return (-1);
1.7 joris 278: if ((unlockrev_arg != NULL) &&
279: (cvs_sendarg(root, unlockrev_arg, 0) < 0))
1.8 xsa 280: return (-1);
1.1 joris 281: }
282:
1.7 joris 283: if ((strictlock & LOCK_REMOVE) &&
284: (cvs_sendarg(root, "-U", 0) < 0))
1.8 xsa 285: return (-1);
1.7 joris 286:
1.1 joris 287: return (0);
288: }
289:
290: /*
291: * cvs_admin_file()
292: *
293: * Perform admin commands on each file.
294: */
295: int
296: cvs_admin_file(CVSFILE *cfp, void *arg)
297: {
298: int ret;
299: char *repo, fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
300: RCSFILE *rf;
301: struct cvs_ent *entp;
302: struct cvsroot *root;
303:
304: ret = 0;
305: rf = NULL;
306: root = CVS_DIR_ROOT(cfp);
307: repo = CVS_DIR_REPO(cfp);
308:
309: if (cfp->cf_type == DT_DIR) {
310: if (root->cr_method != CVS_METHOD_LOCAL) {
311: if (cfp->cf_cvstat == CVS_FST_UNKNOWN)
312: ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE,
313: CVS_FILE_NAME(cfp));
314: else
315: ret = cvs_senddir(root, cfp);
316: }
317:
318: return (ret);
319: }
320:
321: cvs_file_getpath(cfp, fpath, sizeof(fpath));
322: entp = cvs_ent_getent(fpath);
323:
324: if (root->cr_method != CVS_METHOD_LOCAL) {
325: if ((entp != NULL) && (cvs_sendentry(root, entp) < 0)) {
326: cvs_ent_free(entp);
327: return (-1);
328: }
329:
330: switch (cfp->cf_cvstat) {
331: case CVS_FST_UNKNOWN:
332: ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE,
333: CVS_FILE_NAME(cfp));
334: break;
335: case CVS_FST_UPTODATE:
336: ret = cvs_sendreq(root, CVS_REQ_UNCHANGED,
337: CVS_FILE_NAME(cfp));
338: break;
339: case CVS_FST_MODIFIED:
340: ret = cvs_sendreq(root, CVS_REQ_MODIFIED,
341: CVS_FILE_NAME(cfp));
342: if (ret == 0)
343: ret = cvs_sendfile(root, fpath);
344: default:
345: break;
346: }
347: } else {
348: if (cfp->cf_cvstat == CVS_FST_UNKNOWN) {
349: cvs_log(LP_WARN, "I know nothing about %s", fpath);
350: return (0);
351: }
352:
353: snprintf(rcspath, sizeof(rcspath), "%s/%s/%s%s",
354: root->cr_dir, repo, CVS_FILE_NAME(cfp), RCS_FILE_EXT);
355:
356: rf = rcs_open(rcspath, RCS_READ);
357: if (rf == NULL) {
1.6 tedu 358: if (entp != NULL)
359: cvs_ent_free(entp);
1.1 joris 360: return (-1);
361: }
362:
363: rcs_close(rf);
364: }
365:
366: if (entp != NULL)
367: cvs_ent_free(entp);
368: return (ret);
369: }