Annotation of src/usr.bin/cvs/tag.c, Revision 1.24
1.24 ! xsa 1: /* $OpenBSD: tag.c,v 1.23 2005/07/11 09:08:47 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.1 jfb 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:
30: #include <errno.h>
31: #include <stdio.h>
32: #include <stdlib.h>
33: #include <string.h>
34:
35: #include "cvs.h"
36: #include "log.h"
37: #include "proto.h"
38:
39:
1.17 jfb 40: static int cvs_tag_init (struct cvs_cmd *, int, char **, int *);
41: static int cvs_tag_local (CVSFILE *, void *);
42: static int cvs_tag_remote (CVSFILE *, void *);
43: static int cvs_tag_pre_exec (struct cvsroot *);
1.14 jfb 44:
45: static char *tag_name = NULL;
46: static char *tag_date = NULL;
47: static char *tag_oldname = NULL;
48: static int tag_branch = 0;
49: static int tag_delete = 0;
50: static int tag_forcehead = 0;
1.21 xsa 51: static int tag_forcemove = 0;
1.7 joris 52:
1.17 jfb 53: struct cvs_cmd cvs_cmd_tag = {
54: CVS_OP_TAG, CVS_REQ_TAG, "tag",
55: { "ta", "freeze" },
56: "Add a symbolic tag to checked out version of files",
57: "[-bcdFflR] [-D date | -r rev] tagname ...",
58: "bcD:dFflRr:",
59: NULL,
1.7 joris 60: CF_SORT | CF_IGNORE | CF_RECURSE,
1.17 jfb 61: cvs_tag_init,
62: cvs_tag_pre_exec,
63: cvs_tag_remote,
64: cvs_tag_local,
65: NULL,
66: NULL,
67: CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
68: };
69:
70:
71: struct cvs_cmd cvs_cmd_rtag = {
72: CVS_OP_RTAG, CVS_REQ_TAG, "rtag",
73: { },
74: "Add a symbolic tag to a module",
1.21 xsa 75: "[-abdFflnR] [-D date | -r rev] symbolic_tag modules ...",
76: "abD:fFflnRr:",
1.17 jfb 77: NULL,
78: CF_SORT | CF_IGNORE | CF_RECURSE,
79: cvs_tag_init,
80: cvs_tag_pre_exec,
81: cvs_tag_remote,
82: cvs_tag_local,
83: NULL,
84: NULL,
1.14 jfb 85: CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
1.7 joris 86: };
1.1 jfb 87:
1.14 jfb 88: static int
1.17 jfb 89: cvs_tag_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
1.1 jfb 90: {
1.7 joris 91: int ch;
1.1 jfb 92:
1.14 jfb 93: tag_date = tag_oldname = NULL;
1.1 jfb 94:
1.17 jfb 95: while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
1.1 jfb 96: switch (ch) {
97: case 'b':
1.14 jfb 98: tag_branch = 1;
1.1 jfb 99: break;
100: case 'd':
1.14 jfb 101: tag_delete = 1;
102: break;
1.21 xsa 103: case 'F':
104: tag_forcemove = 1;
105: break;
1.14 jfb 106: case 'f':
107: tag_forcehead = 1;
1.1 jfb 108: break;
1.3 jfb 109: case 'D':
1.14 jfb 110: tag_date = optarg;
1.3 jfb 111: break;
1.1 jfb 112: case 'l':
1.17 jfb 113: cmd->file_flags &= ~CF_RECURSE;
114: break;
115: case 'R':
116: cmd->file_flags |= CF_RECURSE;
1.1 jfb 117: break;
118: case 'r':
1.14 jfb 119: tag_oldname = optarg;
1.1 jfb 120: break;
121: default:
1.11 joris 122: return (CVS_EX_USAGE);
1.1 jfb 123: }
124: }
125:
1.7 joris 126: *arg = optind;
1.1 jfb 127: argc -= optind;
128: argv += optind;
129:
130: if (argc == 0) {
1.11 joris 131: return (CVS_EX_USAGE);
1.1 jfb 132: } else {
1.14 jfb 133: tag_name = argv[0];
1.1 jfb 134: argc--;
135: argv++;
1.7 joris 136: *arg += 1;
1.15 jfb 137: }
138:
139: if (!rcs_sym_check(tag_name)) {
140: cvs_log(LP_ABORT,
141: "tag `%s' must not contain the characters `%s'",
142: tag_name, RCS_SYM_INVALCHAR);
143: return (CVS_EX_BADTAG);
1.1 jfb 144: }
145:
1.14 jfb 146: if (tag_branch && tag_delete) {
1.1 jfb 147: cvs_log(LP_WARN, "ignoring -b with -d options");
1.14 jfb 148: tag_branch = 0;
1.1 jfb 149: }
150:
1.14 jfb 151: if (tag_delete && tag_oldname)
152: tag_oldname = NULL;
1.1 jfb 153:
1.14 jfb 154: if (tag_delete && tag_date)
155: tag_date = NULL;
1.3 jfb 156:
1.14 jfb 157: if (tag_oldname != NULL && tag_date != NULL) {
1.20 xsa 158: cvs_log(LP_ERR, "the -D and -r options are mutually exclusive");
1.11 joris 159: return (CVS_EX_USAGE);
1.3 jfb 160: }
161:
1.7 joris 162: return (0);
163: }
164:
1.14 jfb 165: static int
1.17 jfb 166: cvs_tag_pre_exec(struct cvsroot *root)
1.7 joris 167: {
1.17 jfb 168: if (root->cr_method != CVS_METHOD_LOCAL) {
169: if (tag_branch && (cvs_sendarg(root, "-b", 0) < 0))
170: return (CVS_EX_PROTO);
171:
172: if (tag_delete && (cvs_sendarg(root, "-d", 0) < 0))
173: return (CVS_EX_PROTO);
1.7 joris 174:
1.21 xsa 175: if (tag_forcemove && (cvs_sendarg(root, "-F", 0) < 0))
176: return (CVS_EX_PROTO);
177:
178: if (tag_forcehead && (cvs_sendarg(root, "-f", 0) < 0))
179: return (CVS_EX_PROTO);
180:
181: if ((tag_oldname) && ((cvs_sendarg(root, "-r", 0) < 0) ||
182: (cvs_sendarg(root, tag_oldname, 0) < 0)))
1.17 jfb 183: return (CVS_EX_PROTO);
1.1 jfb 184:
1.21 xsa 185: if ((tag_date) && ((cvs_sendarg(root, "-D", 0) < 0) ||
186: (cvs_sendarg(root, tag_date, 0) < 0)))
1.17 jfb 187: return (CVS_EX_PROTO);
1.1 jfb 188:
1.17 jfb 189: if (cvs_sendarg(root, tag_name, 0) < 0)
1.11 joris 190: return (CVS_EX_PROTO);
1.1 jfb 191: }
1.7 joris 192:
1.1 jfb 193: return (0);
194: }
195:
196:
197: /*
1.14 jfb 198: * cvs_tag_remote()
1.1 jfb 199: *
200: * Get the status of a single file.
201: */
1.14 jfb 202: static int
203: cvs_tag_remote(CVSFILE *cfp, void *arg)
1.1 jfb 204: {
1.14 jfb 205: int ret;
206: char fpath[MAXPATHLEN];
1.1 jfb 207: struct cvsroot *root;
208:
209: ret = 0;
210: root = CVS_DIR_ROOT(cfp);
211:
1.14 jfb 212: if (cfp->cf_type == DT_DIR) {
1.16 joris 213: if (cvs_senddir(root, cfp) < 0)
214: ret = CVS_EX_PROTO;
1.14 jfb 215: return (ret);
216: }
217:
218: if (cvs_sendentry(root, cfp) < 0) {
219: return (CVS_EX_PROTO);
1.1 jfb 220: }
221:
222: cvs_file_getpath(cfp, fpath, sizeof(fpath));
223:
1.14 jfb 224: switch (cfp->cf_cvstat) {
225: case CVS_FST_UNKNOWN:
226: ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name);
227: break;
228: case CVS_FST_UPTODATE:
229: ret = cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name);
230: break;
231: case CVS_FST_MODIFIED:
1.22 joris 232: ret = cvs_sendreq(root, CVS_REQ_ISMODIFIED, cfp->cf_name);
1.14 jfb 233: default:
234: break;
235: }
236:
1.16 joris 237: if (ret == -1)
238: ret = CVS_EX_PROTO;
239:
1.14 jfb 240: return (ret);
241: }
242:
243:
244: static int
245: cvs_tag_local(CVSFILE *cf, void *arg)
246: {
247: int len;
248: char *repo, fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
249: struct cvsroot *root;
250: RCSFILE *rf;
251: RCSNUM *tag_rev;
252:
253: cvs_file_getpath(cf, fpath, sizeof(fpath));
254:
1.17 jfb 255: if (cf->cf_type == DT_DIR) {
1.23 xsa 256: if (verbosity > 1)
257: cvs_log(LP_INFO, "%s %s",
258: tag_delete ? "Untagging" : "Tagging", fpath);
1.17 jfb 259: return (CVS_EX_OK);
260: }
261:
1.14 jfb 262: if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
263: cvs_log(LP_WARN, "I know nothing about %s", fpath);
264: return (0);
265: }
1.1 jfb 266:
1.14 jfb 267: repo = CVS_DIR_REPO(cf);
268: root = CVS_DIR_ROOT(cf);
1.17 jfb 269: tag_rev = cf->cf_lrev;
1.1 jfb 270:
1.14 jfb 271: len = snprintf(rcspath, sizeof(rcspath), "%s/%s/%s%s",
272: root->cr_dir, repo, cf->cf_name, RCS_FILE_EXT);
273: if (len == -1 || len >= (int)sizeof(rcspath)) {
274: errno = ENAMETOOLONG;
275: cvs_log(LP_ERRNO, "%s", rcspath);
1.16 joris 276: return (CVS_EX_DATA);
1.14 jfb 277: }
1.1 jfb 278:
1.14 jfb 279: rf = rcs_open(rcspath, RCS_READ|RCS_WRITE);
280: if (rf == NULL) {
281: cvs_log(LP_ERR, "failed to open %s: %s", rcspath,
282: rcs_errstr(rcs_errno));
1.16 joris 283: return (CVS_EX_DATA);
1.14 jfb 284: }
1.1 jfb 285:
1.18 xsa 286: if (!cvs_noexec) {
287: if (rcs_sym_add(rf, tag_name, tag_rev) < 0) {
288: cvs_log(LP_ERR, "failed to tag %s: %s", rcspath,
289: rcs_errstr(rcs_errno));
290: }
1.1 jfb 291: }
1.17 jfb 292:
1.24 ! xsa 293: if (verbosity > 0)
! 294: cvs_printf("T %s\n", fpath);
1.1 jfb 295:
1.14 jfb 296: rcs_close(rf);
297: return (0);
1.1 jfb 298: }