Annotation of src/usr.bin/cvs/tag.c, Revision 1.17
1.17 ! jfb 1: /* $OpenBSD: tag.c,v 1.16 2005/05/20 20:00:53 joris 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.3 jfb 154: cvs_log(LP_ERROR, "-r and -D options are mutually exclusive");
1.11 joris 155: return (CVS_EX_USAGE);
1.3 jfb 156: }
157:
1.7 joris 158: return (0);
159: }
160:
1.14 jfb 161: static int
1.17 ! jfb 162: cvs_tag_pre_exec(struct cvsroot *root)
1.7 joris 163: {
1.17 ! jfb 164: if (root->cr_method != CVS_METHOD_LOCAL) {
! 165: if (tag_branch && (cvs_sendarg(root, "-b", 0) < 0))
! 166: return (CVS_EX_PROTO);
! 167:
! 168: if (tag_delete && (cvs_sendarg(root, "-d", 0) < 0))
! 169: return (CVS_EX_PROTO);
1.7 joris 170:
1.17 ! jfb 171: if (tag_oldname) {
! 172: if ((cvs_sendarg(root, "-r", 0) < 0) ||
! 173: (cvs_sendarg(root, tag_oldname, 0) < 0))
! 174: return (CVS_EX_PROTO);
! 175: }
1.1 jfb 176:
1.17 ! jfb 177: if (tag_date) {
! 178: if ((cvs_sendarg(root, "-D", 0) < 0) ||
! 179: (cvs_sendarg(root, tag_date, 0) < 0))
! 180: return (CVS_EX_PROTO);
! 181: }
1.1 jfb 182:
1.17 ! jfb 183: if (cvs_sendarg(root, tag_name, 0) < 0)
1.11 joris 184: return (CVS_EX_PROTO);
1.1 jfb 185: }
1.7 joris 186:
1.1 jfb 187: return (0);
188: }
189:
190:
191: /*
1.14 jfb 192: * cvs_tag_remote()
1.1 jfb 193: *
194: * Get the status of a single file.
195: */
1.14 jfb 196: static int
197: cvs_tag_remote(CVSFILE *cfp, void *arg)
1.1 jfb 198: {
1.14 jfb 199: int ret;
200: char fpath[MAXPATHLEN];
1.1 jfb 201: struct cvsroot *root;
202:
203: ret = 0;
204: root = CVS_DIR_ROOT(cfp);
205:
1.14 jfb 206: if (cfp->cf_type == DT_DIR) {
1.16 joris 207: if (cvs_senddir(root, cfp) < 0)
208: ret = CVS_EX_PROTO;
1.14 jfb 209: return (ret);
210: }
211:
212: if (cvs_sendentry(root, cfp) < 0) {
213: return (CVS_EX_PROTO);
1.1 jfb 214: }
215:
216: cvs_file_getpath(cfp, fpath, sizeof(fpath));
217:
1.14 jfb 218: switch (cfp->cf_cvstat) {
219: case CVS_FST_UNKNOWN:
220: ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name);
221: break;
222: case CVS_FST_UPTODATE:
223: ret = cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name);
224: break;
225: case CVS_FST_MODIFIED:
226: ret = cvs_sendreq(root, CVS_REQ_ISMODIFIED, cfp->cf_name);
227: default:
228: break;
229: }
230:
1.16 joris 231: if (ret == -1)
232: ret = CVS_EX_PROTO;
233:
1.14 jfb 234: return (ret);
235: }
236:
237:
238: static int
239: cvs_tag_local(CVSFILE *cf, void *arg)
240: {
241: int len;
242: char *repo, fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
243: struct cvsroot *root;
244: RCSFILE *rf;
245: RCSNUM *tag_rev;
246:
247: cvs_file_getpath(cf, fpath, sizeof(fpath));
248:
1.17 ! jfb 249: if (cf->cf_type == DT_DIR) {
! 250: cvs_log(LP_INFO, "Tagging %s", fpath);
! 251: return (CVS_EX_OK);
! 252: }
! 253:
1.14 jfb 254: if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
255: cvs_log(LP_WARN, "I know nothing about %s", fpath);
256: return (0);
257: }
1.1 jfb 258:
1.14 jfb 259: repo = CVS_DIR_REPO(cf);
260: root = CVS_DIR_ROOT(cf);
1.17 ! jfb 261: tag_rev = cf->cf_lrev;
1.1 jfb 262:
1.14 jfb 263: len = snprintf(rcspath, sizeof(rcspath), "%s/%s/%s%s",
264: root->cr_dir, repo, cf->cf_name, RCS_FILE_EXT);
265: if (len == -1 || len >= (int)sizeof(rcspath)) {
266: errno = ENAMETOOLONG;
267: cvs_log(LP_ERRNO, "%s", rcspath);
1.16 joris 268: return (CVS_EX_DATA);
1.14 jfb 269: }
1.1 jfb 270:
1.14 jfb 271: rf = rcs_open(rcspath, RCS_READ|RCS_WRITE);
272: if (rf == NULL) {
273: cvs_log(LP_ERR, "failed to open %s: %s", rcspath,
274: rcs_errstr(rcs_errno));
1.16 joris 275: return (CVS_EX_DATA);
1.14 jfb 276: }
1.1 jfb 277:
1.14 jfb 278: if (rcs_sym_add(rf, tag_name, tag_rev) < 0) {
279: cvs_log(LP_ERR, "failed to tag %s: %s", rcspath,
280: rcs_errstr(rcs_errno));
1.1 jfb 281: }
1.17 ! jfb 282:
! 283: cvs_printf("T %s\n", fpath);
1.1 jfb 284:
1.14 jfb 285: rcs_close(rf);
286: return (0);
1.1 jfb 287: }