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