Annotation of src/usr.bin/cvs/checkout.c, Revision 1.45
1.45 ! xsa 1: /* $OpenBSD: checkout.c,v 1.44 2006/01/02 08:11:56 xsa Exp $ */
1.1 jfb 2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
1.11 tedu 4: * All rights reserved.
1.1 jfb 5: *
1.11 tedu 6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
1.1 jfb 9: *
1.11 tedu 10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
1.1 jfb 12: * 2. The name of the author may not be used to endorse or promote products
1.11 tedu 13: * derived from this software without specific prior written permission.
1.1 jfb 14: *
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
1.11 tedu 24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1 jfb 25: */
26:
1.44 xsa 27: #include "includes.h"
1.1 jfb 28:
29: #include "cvs.h"
30: #include "log.h"
1.5 jfb 31: #include "proto.h"
1.1 jfb 32:
33:
1.39 xsa 34: #define CVS_LISTMOD 1
35: #define CVS_STATMOD 2
1.13 jfb 36:
1.39 xsa 37: static int cvs_checkout_init(struct cvs_cmd *, int, char **, int *);
38: static int cvs_checkout_pre_exec(struct cvsroot *);
1.41 joris 39: static int cvs_checkout_local(CVSFILE *cf, void *);
1.14 joris 40:
1.22 jfb 41: struct cvs_cmd cvs_cmd_checkout = {
42: CVS_OP_CHECKOUT, CVS_REQ_CO, "checkout",
43: { "co", "get" },
44: "Checkout sources for editing",
1.33 xsa 45: "[-AcflNnPpRs] [-D date | -r tag] [-d dir] [-j rev] [-k mode] "
1.22 jfb 46: "[-t id] module ...",
47: "AcD:d:fj:k:lNnPRr:st:",
48: NULL,
1.14 joris 49: 0,
1.22 jfb 50: cvs_checkout_init,
51: cvs_checkout_pre_exec,
52: NULL,
53: NULL,
54: NULL,
55: NULL,
1.23 joris 56: CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
1.14 joris 57: };
58:
1.33 xsa 59: struct cvs_cmd cvs_cmd_export = {
60: CVS_OP_EXPORT, CVS_REQ_EXPORT, "export",
61: { "ex", "exp" },
62: "Extract copy of a module without management directories",
63: "[-flNnR] [-d dir] [-k mode] -D date | -r tag module ...",
64: "D:d:fk:lNnRr:",
65: NULL,
66: 0,
67: cvs_checkout_init,
68: cvs_checkout_pre_exec,
69: NULL,
70: NULL,
71: NULL,
72: NULL,
73: CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR
74: };
75:
1.41 joris 76: static char *currepo = NULL;
77: static DIR *dirp = NULL;
78: static int cwdfd = -1;
1.33 xsa 79: static char *date, *tag, *koptstr, *tgtdir, *rcsid;
1.14 joris 80: static int statmod = 0;
1.37 joris 81: static int shorten = 0;
1.22 jfb 82: static int usehead = 0;
1.14 joris 83: static int kflag = RCS_KWEXP_DEFAULT;
1.1 jfb 84:
1.22 jfb 85: /* modules */
86: static char **co_mods;
87: static int co_nmod;
88:
1.41 joris 89: /* XXX checkout has issues in remote mode, -N gets seen as module */
90:
1.22 jfb 91: static int
92: cvs_checkout_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
1.1 jfb 93: {
1.14 joris 94: int ch;
1.33 xsa 95: RCSNUM *rcs;
1.14 joris 96:
1.33 xsa 97: date = tag = koptstr = tgtdir = rcsid = NULL;
1.13 jfb 98:
1.22 jfb 99: while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
1.1 jfb 100: switch (ch) {
1.13 jfb 101: case 'A':
102: break;
1.10 jfb 103: case 'c':
1.13 jfb 104: statmod = CVS_LISTMOD;
105: break;
106: case 'D':
107: date = optarg;
1.32 xsa 108: cmd->cmd_flags |= CVS_CMD_PRUNEDIRS;
1.13 jfb 109: break;
110: case 'd':
111: tgtdir = optarg;
1.37 joris 112: shorten = 1;
1.13 jfb 113: break;
114: case 'f':
1.21 xsa 115: usehead = 1;
1.13 jfb 116: break;
117: case 'j':
118: break;
119: case 'k':
120: koptstr = optarg;
121: kflag = rcs_kflag_get(koptstr);
122: if (RCS_KWEXP_INVAL(kflag)) {
123: cvs_log(LP_ERR,
124: "invalid RCS keyword expansion mode");
125: rcs_kflag_usage();
1.18 joris 126: return (CVS_EX_USAGE);
1.13 jfb 127: }
1.24 joris 128: break;
129: case 'P':
130: cmd->cmd_flags |= CVS_CMD_PRUNEDIRS;
1.20 xsa 131: break;
1.22 jfb 132: case 'N':
133: shorten = 0;
134: break;
1.20 xsa 135: case 'p':
136: cvs_noexec = 1; /* no locks will be created */
1.13 jfb 137: break;
138: case 'r':
1.33 xsa 139: tag = optarg;
1.25 xsa 140: cmd->cmd_flags |= CVS_CMD_PRUNEDIRS;
1.13 jfb 141: break;
142: case 's':
143: statmod = CVS_STATMOD;
144: break;
145: case 't':
146: rcsid = optarg;
1.10 jfb 147: break;
1.1 jfb 148: default:
1.18 joris 149: return (CVS_EX_USAGE);
1.1 jfb 150: }
151: }
152:
153: argc -= optind;
154: argv += optind;
155:
1.22 jfb 156: co_mods = argv;
157: co_nmod = argc;
158:
1.38 xsa 159: if ((statmod == 0) && (argc == 0)) {
1.31 xsa 160: cvs_log(LP_ABORT,
1.1 jfb 161: "must specify at least one module or directory");
1.26 xsa 162: return (-1);
1.1 jfb 163: }
164:
1.13 jfb 165: if (statmod && (argc > 0)) {
1.31 xsa 166: cvs_log(LP_ABORT, "-c and -s must not get any arguments");
1.26 xsa 167: return (-1);
1.13 jfb 168: }
169:
1.33 xsa 170: /* `export' command exceptions */
171: if (cvs_cmdop == CVS_OP_EXPORT) {
172: if (!tag && !date) {
173: cvs_log(LP_ABORT, "must specify a tag or date");
174: return (-1);
175: }
176:
177: /* we don't want numerical revisions here */
178: if (tag && (rcs = rcsnum_parse(tag)) != NULL) {
179: cvs_log(LP_ABORT, "tag `%s' must be a symbolic tag",
180: tag);
181: rcsnum_free(rcs);
182: return (-1);
183: }
184: }
185:
1.14 joris 186: *arg = optind;
187: return (0);
188: }
1.9 jfb 189:
1.22 jfb 190: static int
191: cvs_checkout_pre_exec(struct cvsroot *root)
1.14 joris 192: {
1.41 joris 193: int i, ret;
194: char *sp, repo[MAXPATHLEN];
195:
196: if ((dirp = opendir(".")) == NULL) {
197: cvs_log(LP_ERRNO, "failed to save cwd");
198: return (CVS_EX_DATA);
199: }
200:
201: cwdfd = dirfd(dirp);
1.1 jfb 202:
1.22 jfb 203: for (i = 0; i < co_nmod; i++) {
1.23 joris 204: if ((sp = strchr(co_mods[i], '/')) != NULL)
205: *sp = '\0';
206:
207: if ((mkdir(co_mods[i], 0755) == -1) && (errno != EEXIST)) {
208: cvs_log(LP_ERRNO, "can't create base directory '%s'",
209: co_mods[i]);
210: return (CVS_EX_DATA);
211: }
212:
1.40 xsa 213: if (cvs_mkadmin(co_mods[i], root->cr_str, co_mods[i],
214: NULL, NULL, 0) < 0) {
1.27 xsa 215: cvs_log(LP_ERR, "can't create base directory '%s'",
1.23 joris 216: co_mods[i]);
1.22 jfb 217: return (CVS_EX_DATA);
1.23 joris 218: }
219:
220: if (sp != NULL)
221: *sp = '/';
1.22 jfb 222: }
223:
1.41 joris 224: if (root->cr_method == CVS_METHOD_LOCAL) {
225: if ((dirp = opendir(".")) == NULL)
226: return (CVS_EX_DATA);
227: cwdfd = dirfd(dirp);
228:
229: for (i = 0; i < co_nmod; i++) {
1.45 ! xsa 230: if (strlcpy(repo, root->cr_dir, sizeof(repo)) >=
! 231: sizeof(repo) ||
! 232: strlcat(repo, "/", sizeof(repo)) >= sizeof(repo) ||
! 233: strlcat(repo, co_mods[i], sizeof(repo)) >=
! 234: sizeof(repo))
! 235: fatal("cvs_checkout_pre_exec: path truncation");
! 236:
1.41 joris 237: currepo = co_mods[i];
1.43 reyk 238: ret = cvs_file_get(repo, CF_RECURSE | CF_REPO |
239: CF_IGNORE, cvs_checkout_local, NULL, NULL);
1.41 joris 240: if (ret != CVS_EX_OK) {
241: closedir(dirp);
242: return (ret);
243: }
244: }
245:
246: closedir(dirp);
247: } else {
1.37 joris 248: /*
249: * These arguments are for the expand-modules
250: * command that we send to the server before requesting
251: * a checkout.
252: */
253: for (i = 0; i < co_nmod; i++)
1.42 joris 254: cvs_sendarg(root, co_mods[i], 0);
255:
256: cvs_sendreq(root, CVS_REQ_DIRECTORY, ".");
257: cvs_sendln(root, root->cr_dir);
258: cvs_sendreq(root, CVS_REQ_XPANDMOD, NULL);
259:
260: if (usehead == 1)
261: cvs_sendarg(root, "-f", 0);
262:
263: if (tgtdir != NULL) {
264: cvs_sendarg(root, "-d", 0);
265: cvs_sendarg(root, tgtdir, 0);
266: }
267:
268: if (shorten == 0)
269: cvs_sendarg(root, "-N", 0);
270:
271: if (cvs_cmd_checkout.cmd_flags & CVS_CMD_PRUNEDIRS);
272: cvs_sendarg(root, "-P", 0);
1.22 jfb 273:
274: for (i = 0; i < co_nmod; i++)
1.42 joris 275: cvs_sendarg(root, co_mods[i], 0);
1.22 jfb 276:
1.42 joris 277: if (statmod == CVS_LISTMOD)
278: cvs_sendarg(root, "-c", 0);
279: else if (statmod == CVS_STATMOD)
280: cvs_sendarg(root, "-s", 0);
281:
282: if (tag != NULL) {
283: cvs_sendarg(root, "-r", 0);
284: cvs_sendarg(root, tag, 0);
285: }
286:
287: if (date != NULL) {
288: cvs_sendarg(root, "-D", 0);
289: cvs_sendarg(root, date, 0);
290: }
1.22 jfb 291: }
1.42 joris 292:
1.1 jfb 293: return (0);
1.41 joris 294: }
295:
296: static int
297: cvs_checkout_local(CVSFILE *cf, void *arg)
298: {
299: char rcspath[MAXPATHLEN], fpath[MAXPATHLEN];
300: RCSFILE *rf;
301: struct cvsroot *root;
302: static int inattic = 0;
303:
304: /* we don't want these */
305: if ((cf->cf_type == DT_DIR) && !strcmp(cf->cf_name, "Attic")) {
306: inattic = 1;
307: return (CVS_EX_OK);
308: }
309:
310: root = CVS_DIR_ROOT(cf);
1.45 ! xsa 311:
1.41 joris 312: cvs_file_getpath(cf, fpath, sizeof(fpath));
1.45 ! xsa 313: cvs_rcs_getpath(cf, rcspath, sizeof(rcspath));
1.41 joris 314:
315: if (cf->cf_type == DT_DIR) {
316: inattic = 0;
317: if (verbosity > 1)
318: cvs_log(LP_INFO, "Updating %s", fpath);
319:
320: if (cvs_cmdop != CVS_OP_SERVER) {
321: /*
322: * We pass an empty repository name to
323: * cvs_create_dir(), because it will correctly
324: * create the repository directory for us.
325: */
326: if (cvs_create_dir(fpath, 1, root->cr_dir, NULL) < 0)
327: return (CVS_EX_FILE);
328: if (fchdir(cwdfd) < 0) {
329: cvs_log(LP_ERRNO, "fchdir failed");
330: return (CVS_EX_FILE);
331: }
332: } else {
333: /*
334: * TODO: send responses to client so it'll
335: * create it's directories.
336: */
337: }
338:
339: return (CVS_EX_OK);
340: }
341:
342: if (inattic == 1)
343: return (CVS_EX_OK);
344:
345: if ((rf = rcs_open(rcspath, RCS_READ)) == NULL) {
346: cvs_log(LP_ERR, "cvs_checkout_local: rcs_open failed");
347: return (CVS_EX_DATA);
348: }
349:
350: if (cvs_checkout_rev(rf, rf->rf_head, cf, fpath,
351: (cvs_cmdop != CVS_OP_SERVER) ? 1 : 0,
352: CHECKOUT_REV_CREATED) < 0) {
353: rcs_close(rf);
354: return (CVS_EX_DATA);
355: }
356:
357: rcs_close(rf);
358:
359: cvs_printf("U %s\n", fpath);
360: return (CVS_EX_OK);
1.1 jfb 361: }