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