Annotation of src/usr.bin/cvs/tag.c, Revision 1.15
1.15 ! jfb 1: /* $OpenBSD: tag.c,v 1.14 2005/04/19 18:51:30 jfb 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.14 jfb 40: static int cvs_tag_local (CVSFILE *, void *);
41: static int cvs_tag_remote (CVSFILE *, void *);
42: static int cvs_tag_options (char *, int, char **, int *);
43: static int cvs_tag_sendflags (struct cvsroot *);
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:
52: struct cvs_cmd_info cvs_tag = {
53: cvs_tag_options,
54: cvs_tag_sendflags,
1.14 jfb 55: cvs_tag_remote,
1.7 joris 56: NULL, NULL,
57: CF_SORT | CF_IGNORE | CF_RECURSE,
58: CVS_REQ_TAG,
1.14 jfb 59: CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
1.7 joris 60: };
1.1 jfb 61:
1.14 jfb 62: static int
1.7 joris 63: cvs_tag_options(char *opt, int argc, char **argv, int *arg)
1.1 jfb 64: {
1.7 joris 65: int ch;
1.1 jfb 66:
1.14 jfb 67: tag_date = tag_oldname = NULL;
1.1 jfb 68:
1.7 joris 69: while ((ch = getopt(argc, argv, opt)) != -1) {
1.1 jfb 70: switch (ch) {
71: case 'b':
1.14 jfb 72: tag_branch = 1;
1.1 jfb 73: break;
74: case 'd':
1.14 jfb 75: tag_delete = 1;
76: break;
77: case 'f':
78: tag_forcehead = 1;
1.1 jfb 79: break;
1.3 jfb 80: case 'D':
1.14 jfb 81: tag_date = optarg;
1.3 jfb 82: break;
1.1 jfb 83: case 'l':
1.7 joris 84: cvs_tag.file_flags &= ~CF_RECURSE;
1.1 jfb 85: break;
86: case 'r':
1.14 jfb 87: tag_oldname = optarg;
1.1 jfb 88: break;
89: default:
1.11 joris 90: return (CVS_EX_USAGE);
1.1 jfb 91: }
92: }
93:
1.7 joris 94: *arg = optind;
1.1 jfb 95: argc -= optind;
96: argv += optind;
97:
98: if (argc == 0) {
1.11 joris 99: return (CVS_EX_USAGE);
1.1 jfb 100: } else {
1.14 jfb 101: tag_name = argv[0];
1.1 jfb 102: argc--;
103: argv++;
1.7 joris 104: *arg += 1;
1.15 ! jfb 105: }
! 106:
! 107: if (!rcs_sym_check(tag_name)) {
! 108: cvs_log(LP_ABORT,
! 109: "tag `%s' must not contain the characters `%s'",
! 110: tag_name, RCS_SYM_INVALCHAR);
! 111: return (CVS_EX_BADTAG);
1.1 jfb 112: }
113:
1.14 jfb 114: if (tag_branch && tag_delete) {
1.1 jfb 115: cvs_log(LP_WARN, "ignoring -b with -d options");
1.14 jfb 116: tag_branch = 0;
1.1 jfb 117: }
118:
1.14 jfb 119: if (tag_delete && tag_oldname)
120: tag_oldname = NULL;
1.1 jfb 121:
1.14 jfb 122: if (tag_delete && tag_date)
123: tag_date = NULL;
1.3 jfb 124:
1.14 jfb 125: if (tag_oldname != NULL && tag_date != NULL) {
1.3 jfb 126: cvs_log(LP_ERROR, "-r and -D options are mutually exclusive");
1.11 joris 127: return (CVS_EX_USAGE);
1.3 jfb 128: }
129:
1.7 joris 130: return (0);
131: }
132:
1.14 jfb 133: static int
1.7 joris 134: cvs_tag_sendflags(struct cvsroot *root)
135: {
1.14 jfb 136: if (tag_branch && (cvs_sendarg(root, "-b", 0) < 0))
1.11 joris 137: return (CVS_EX_PROTO);
1.7 joris 138:
1.14 jfb 139: if (tag_delete && (cvs_sendarg(root, "-d", 0) < 0))
1.11 joris 140: return (CVS_EX_PROTO);
1.1 jfb 141:
1.14 jfb 142: if (tag_oldname) {
1.7 joris 143: if ((cvs_sendarg(root, "-r", 0) < 0) ||
1.14 jfb 144: (cvs_sendarg(root, tag_oldname, 0) < 0))
1.11 joris 145: return (CVS_EX_PROTO);
1.1 jfb 146: }
147:
1.14 jfb 148: if (tag_date) {
1.7 joris 149: if ((cvs_sendarg(root, "-D", 0) < 0) ||
1.14 jfb 150: (cvs_sendarg(root, tag_date, 0) < 0))
1.11 joris 151: return (CVS_EX_PROTO);
1.1 jfb 152: }
1.7 joris 153:
1.14 jfb 154: if (cvs_sendarg(root, tag_name, 0) < 0)
1.11 joris 155: return (CVS_EX_PROTO);
1.1 jfb 156:
157: return (0);
158: }
159:
160:
161: /*
1.14 jfb 162: * cvs_tag_remote()
1.1 jfb 163: *
164: * Get the status of a single file.
165: */
1.14 jfb 166: static int
167: cvs_tag_remote(CVSFILE *cfp, void *arg)
1.1 jfb 168: {
1.14 jfb 169: int ret;
170: char fpath[MAXPATHLEN];
1.1 jfb 171: struct cvsroot *root;
172:
173: ret = 0;
174: root = CVS_DIR_ROOT(cfp);
175:
1.14 jfb 176: if (cfp->cf_type == DT_DIR) {
177: ret = cvs_senddir(root, cfp);
178: return (ret);
179: }
180:
181: if (cvs_sendentry(root, cfp) < 0) {
182: return (CVS_EX_PROTO);
1.1 jfb 183: }
184:
185: cvs_file_getpath(cfp, fpath, sizeof(fpath));
186:
1.14 jfb 187: switch (cfp->cf_cvstat) {
188: case CVS_FST_UNKNOWN:
189: ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cfp->cf_name);
190: break;
191: case CVS_FST_UPTODATE:
192: ret = cvs_sendreq(root, CVS_REQ_UNCHANGED, cfp->cf_name);
193: break;
194: case CVS_FST_MODIFIED:
195: ret = cvs_sendreq(root, CVS_REQ_ISMODIFIED, cfp->cf_name);
196: default:
197: break;
198: }
199:
200: return (ret);
201: }
202:
203:
204: static int
205: cvs_tag_local(CVSFILE *cf, void *arg)
206: {
207: int len;
208: char *repo, fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
209: struct cvsroot *root;
210: RCSFILE *rf;
211: RCSNUM *tag_rev;
212:
213: cvs_file_getpath(cf, fpath, sizeof(fpath));
214:
215: if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
216: cvs_log(LP_WARN, "I know nothing about %s", fpath);
217: return (0);
218: }
1.1 jfb 219:
1.14 jfb 220: repo = CVS_DIR_REPO(cf);
221: root = CVS_DIR_ROOT(cf);
1.1 jfb 222:
1.14 jfb 223: len = snprintf(rcspath, sizeof(rcspath), "%s/%s/%s%s",
224: root->cr_dir, repo, cf->cf_name, RCS_FILE_EXT);
225: if (len == -1 || len >= (int)sizeof(rcspath)) {
226: errno = ENAMETOOLONG;
227: cvs_log(LP_ERRNO, "%s", rcspath);
228: return (-1);
229: }
1.1 jfb 230:
1.14 jfb 231: rf = rcs_open(rcspath, RCS_READ|RCS_WRITE);
232: if (rf == NULL) {
233: cvs_log(LP_ERR, "failed to open %s: %s", rcspath,
234: rcs_errstr(rcs_errno));
235: return (-1);
236: }
1.1 jfb 237:
1.14 jfb 238: if (rcs_sym_add(rf, tag_name, tag_rev) < 0) {
239: cvs_log(LP_ERR, "failed to tag %s: %s", rcspath,
240: rcs_errstr(rcs_errno));
1.1 jfb 241: }
242:
1.14 jfb 243: rcs_close(rf);
244: return (0);
1.1 jfb 245: }