Annotation of src/usr.bin/cvs/tag.c, Revision 1.43
1.43 ! deraadt 1: /* $OpenBSD: tag.c,v 1.42 2006/04/12 14:09:11 xsa Exp $ */
1.1 jfb 2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
1.5 joris 4: * Copyright (c) 2004 Joris Vink <joris@openbsd.org>
1.40 xsa 5: * Copyright (c) 2005, 2006 Xavier Santolaria <xsa@openbsd.org>
1.1 jfb 6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: *
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. The name of the author may not be used to endorse or promote products
15: * derived from this software without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27: */
28:
1.36 xsa 29: #include "includes.h"
1.1 jfb 30:
31: #include "cvs.h"
32: #include "log.h"
33: #include "proto.h"
34:
1.40 xsa 35: #define TAG_BRANCH (1<<0)
36: #define TAG_DELETE (1<<1)
37: #define TAG_FORCE_HEAD (1<<2)
38: #define TAG_FORCE_RM (1<<3)
39: #define UPTODATE (1<<4)
1.1 jfb 40:
1.28 xsa 41: static int cvs_tag_init(struct cvs_cmd *, int, char **, int *);
42: static int cvs_tag_local(CVSFILE *, void *);
43: static int cvs_tag_remote(CVSFILE *, void *);
44: static int cvs_tag_pre_exec(struct cvsroot *);
1.14 jfb 45:
1.40 xsa 46: static int runflags = 0;
1.14 jfb 47: static char *tag_name = NULL;
48: static char *tag_date = NULL;
49: static char *tag_oldname = NULL;
1.7 joris 50:
1.17 jfb 51: struct cvs_cmd cvs_cmd_tag = {
52: CVS_OP_TAG, CVS_REQ_TAG, "tag",
53: { "ta", "freeze" },
54: "Add a symbolic tag to checked out version of files",
1.40 xsa 55: "[-bcdFflR] [-D date | -r rev] tag [file ...]",
1.17 jfb 56: "bcD:dFflRr:",
57: NULL,
1.7 joris 58: CF_SORT | CF_IGNORE | CF_RECURSE,
1.17 jfb 59: cvs_tag_init,
60: cvs_tag_pre_exec,
61: cvs_tag_remote,
62: cvs_tag_local,
63: NULL,
64: NULL,
65: CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
66: };
67:
68:
69: struct cvs_cmd cvs_cmd_rtag = {
70: CVS_OP_RTAG, CVS_REQ_TAG, "rtag",
1.30 xsa 71: { "rt", "rfreeze" },
1.17 jfb 72: "Add a symbolic tag to a module",
1.40 xsa 73: "[-abdFflnR] [-D date | -r rev] tag modules ...",
1.21 xsa 74: "abD:fFflnRr:",
1.17 jfb 75: NULL,
76: CF_SORT | CF_IGNORE | CF_RECURSE,
77: cvs_tag_init,
78: cvs_tag_pre_exec,
79: cvs_tag_remote,
80: cvs_tag_local,
81: NULL,
82: NULL,
1.14 jfb 83: CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
1.7 joris 84: };
1.1 jfb 85:
1.14 jfb 86: static int
1.17 jfb 87: cvs_tag_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
1.1 jfb 88: {
1.7 joris 89: int ch;
1.1 jfb 90:
1.14 jfb 91: tag_date = tag_oldname = NULL;
1.1 jfb 92:
1.17 jfb 93: while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
1.1 jfb 94: switch (ch) {
95: case 'b':
1.40 xsa 96: runflags |= TAG_BRANCH;
97: break;
98: case 'c':
99: runflags |= UPTODATE;
1.1 jfb 100: break;
101: case 'd':
1.40 xsa 102: runflags |= TAG_DELETE;
1.14 jfb 103: break;
1.21 xsa 104: case 'F':
1.40 xsa 105: runflags |= TAG_FORCE_RM;
1.21 xsa 106: break;
1.14 jfb 107: case 'f':
1.40 xsa 108: runflags |= TAG_FORCE_HEAD;
1.1 jfb 109: break;
1.3 jfb 110: case 'D':
1.14 jfb 111: tag_date = optarg;
1.3 jfb 112: break;
1.1 jfb 113: case 'l':
1.17 jfb 114: cmd->file_flags &= ~CF_RECURSE;
115: break;
116: case 'R':
117: cmd->file_flags |= CF_RECURSE;
1.1 jfb 118: break;
119: case 'r':
1.14 jfb 120: tag_oldname = optarg;
1.1 jfb 121: break;
122: default:
1.11 joris 123: return (CVS_EX_USAGE);
1.1 jfb 124: }
125: }
126:
1.7 joris 127: *arg = optind;
1.1 jfb 128: argc -= optind;
129: argv += optind;
130:
1.40 xsa 131: if (argc == 0)
1.11 joris 132: return (CVS_EX_USAGE);
1.40 xsa 133: else {
1.14 jfb 134: tag_name = argv[0];
1.1 jfb 135: argc--;
136: argv++;
1.7 joris 137: *arg += 1;
1.15 jfb 138: }
139:
1.38 xsa 140: if (!rcs_sym_check(tag_name))
141: fatal("tag `%s' must not contain the characters `%s'",
1.15 jfb 142: tag_name, RCS_SYM_INVALCHAR);
1.1 jfb 143:
1.40 xsa 144: if ((runflags & TAG_BRANCH) && (runflags & TAG_DELETE)) {
1.1 jfb 145: cvs_log(LP_WARN, "ignoring -b with -d options");
1.41 deraadt 146: runflags &= ~TAG_BRANCH;
1.1 jfb 147: }
148:
1.43 ! deraadt 149: if ((runflags & TAG_DELETE) && tag_oldname != NULL)
1.14 jfb 150: tag_oldname = NULL;
1.1 jfb 151:
1.43 ! deraadt 152: if ((runflags & TAG_DELETE) && tag_date != NULL)
1.14 jfb 153: tag_date = NULL;
1.3 jfb 154:
1.43 ! deraadt 155: if ((tag_oldname != NULL) && tag_date != NULL) {
1.20 xsa 156: cvs_log(LP_ERR, "the -D and -r options are mutually exclusive");
1.11 joris 157: return (CVS_EX_USAGE);
1.3 jfb 158: }
159:
1.7 joris 160: return (0);
161: }
162:
1.14 jfb 163: static int
1.17 jfb 164: cvs_tag_pre_exec(struct cvsroot *root)
1.7 joris 165: {
1.17 jfb 166: if (root->cr_method != CVS_METHOD_LOCAL) {
1.40 xsa 167: if (runflags & TAG_BRANCH)
1.35 joris 168: cvs_sendarg(root, "-b", 0);
1.17 jfb 169:
1.40 xsa 170: if (runflags & UPTODATE)
171: cvs_sendarg(root, "-c", 0);
172:
173: if (runflags & TAG_DELETE)
1.35 joris 174: cvs_sendarg(root, "-d", 0);
1.7 joris 175:
1.40 xsa 176: if (runflags & TAG_FORCE_RM)
1.35 joris 177: cvs_sendarg(root, "-F", 0);
1.21 xsa 178:
1.40 xsa 179: if (runflags & TAG_FORCE_HEAD)
1.35 joris 180: cvs_sendarg(root, "-f", 0);
1.21 xsa 181:
1.35 joris 182: if (tag_oldname != NULL) {
183: cvs_sendarg(root, "-r", 0);
184: cvs_sendarg(root, tag_oldname, 0);
185: }
1.1 jfb 186:
1.35 joris 187: if (tag_date != NULL) {
188: cvs_sendarg(root, "-D", 0);
189: cvs_sendarg(root, tag_date, 0);
190: }
1.1 jfb 191:
1.35 joris 192: cvs_sendarg(root, tag_name, 0);
1.1 jfb 193: }
194: return (0);
195: }
196:
197:
198: /*
1.14 jfb 199: * cvs_tag_remote()
1.1 jfb 200: *
201: * Get the status of a single file.
202: */
1.14 jfb 203: static int
204: cvs_tag_remote(CVSFILE *cfp, void *arg)
1.1 jfb 205: {
1.14 jfb 206: char fpath[MAXPATHLEN];
1.1 jfb 207: struct cvsroot *root;
208:
209: root = CVS_DIR_ROOT(cfp);
210:
1.14 jfb 211: if (cfp->cf_type == DT_DIR) {
1.35 joris 212: cvs_senddir(root, cfp);
213: return (0);
1.1 jfb 214: }
215:
1.35 joris 216: cvs_sendentry(root, cfp);
1.1 jfb 217: cvs_file_getpath(cfp, fpath, sizeof(fpath));
218:
1.14 jfb 219: switch (cfp->cf_cvstat) {
220: case CVS_FST_UNKNOWN:
1.35 joris 221: cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name);
1.14 jfb 222: break;
223: case CVS_FST_UPTODATE:
1.35 joris 224: cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name);
1.14 jfb 225: break;
226: case CVS_FST_MODIFIED:
1.35 joris 227: cvs_sendreq(root, CVS_REQ_ISMODIFIED, cfp->cf_name);
1.42 xsa 228: break;
1.14 jfb 229: default:
230: break;
231: }
232:
1.35 joris 233: return (0);
1.14 jfb 234: }
235:
236:
237: static int
238: cvs_tag_local(CVSFILE *cf, void *arg)
239: {
1.39 xsa 240: char fpath[MAXPATHLEN], numbuf[64], rcspath[MAXPATHLEN];
1.14 jfb 241: RCSFILE *rf;
242: RCSNUM *tag_rev;
243:
244: cvs_file_getpath(cf, fpath, sizeof(fpath));
245:
1.17 jfb 246: if (cf->cf_type == DT_DIR) {
1.23 xsa 247: if (verbosity > 1)
1.29 xsa 248: cvs_log(LP_NOTICE, "%s %s",
1.40 xsa 249: (runflags & TAG_DELETE) ? "Untagging" : "Tagging",
250: fpath);
1.17 jfb 251: return (CVS_EX_OK);
252: }
253:
1.14 jfb 254: if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
1.26 xsa 255: if (verbosity > 1)
256: cvs_log(LP_WARN, "nothing known about %s", fpath);
1.33 xsa 257: return (0);
258: } else if (cf->cf_cvstat == CVS_FST_ADDED) {
259: if (verbosity > 1)
260: cvs_log(LP_WARN,
261: "couldn't tag added but un-commited file `%s'",
262: fpath);
263: return (0);
264: } else if (cf->cf_cvstat == CVS_FST_REMOVED) {
265: if (verbosity > 1)
266: cvs_log(LP_WARN,
267: "skipping removed but un-commited file `%s'",
268: fpath);
1.14 jfb 269: return (0);
270: }
1.1 jfb 271:
1.17 jfb 272: tag_rev = cf->cf_lrev;
1.1 jfb 273:
1.34 xsa 274: cvs_rcs_getpath(cf, rcspath, sizeof(rcspath));
1.1 jfb 275:
1.37 xsa 276: if ((rf = rcs_open(rcspath, RCS_READ|RCS_WRITE)) == NULL)
277: fatal("cvs_tag_local: rcs_open: %s: %s", rcspath,
1.14 jfb 278: rcs_errstr(rcs_errno));
1.32 xsa 279:
1.40 xsa 280: if (runflags & TAG_DELETE) {
1.39 xsa 281: if (cvs_noexec == 0) {
282: if (rcs_sym_remove(rf, tag_name) < 0)
283: fatal("failed to remove tag %s from %s",
284: tag_name, rcspath);
285: }
286:
1.32 xsa 287: if (verbosity > 0)
288: cvs_printf("D %s\n", fpath);
289:
1.39 xsa 290: rcs_close(rf);
1.32 xsa 291: return (0);
1.14 jfb 292: }
1.1 jfb 293:
1.27 xsa 294: if (cvs_noexec == 0) {
1.39 xsa 295: if (rcs_sym_add(rf, tag_name, tag_rev) < 0) {
296: rcsnum_tostr(tag_rev, numbuf, sizeof(numbuf));
297: fatal("failed to set tag %s to revision %s in %s",
298: tag_name, numbuf, rcspath);
299: }
1.1 jfb 300: }
1.17 jfb 301:
1.24 xsa 302: if (verbosity > 0)
303: cvs_printf("T %s\n", fpath);
1.1 jfb 304:
1.14 jfb 305: rcs_close(rf);
306: return (0);
1.1 jfb 307: }