Annotation of src/usr.bin/cvs/import.c, Revision 1.18
1.18 ! jfb 1: /* $OpenBSD: import.c,v 1.17 2005/05/25 09:25:48 jfb Exp $ */
1.1 krapht 2: /*
1.5 joris 3: * Copyright (c) 2004 Joris Vink <joris@openbsd.org>
1.1 krapht 4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. The name of the author may not be used to endorse or promote products
13: * derived from this software without specific prior written permission.
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
24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: #include <sys/types.h>
1.15 jfb 28: #include <sys/stat.h>
1.1 krapht 29:
30: #include <errno.h>
31: #include <stdio.h>
32: #include <stdlib.h>
33: #include <unistd.h>
34: #include <string.h>
35:
36: #include "log.h"
37: #include "file.h"
1.3 jfb 38: #include "cvs.h"
1.1 krapht 39: #include "proto.h"
40:
1.3 jfb 41:
42: #define CVS_IMPORT_DEFBRANCH "1.1.1"
43:
1.15 jfb 44: static int cvs_import_init (struct cvs_cmd *, int, char **, int *);
45: static int cvs_import_pre_exec (struct cvsroot *);
46: static int cvs_import_remote (CVSFILE *, void *);
47: static int cvs_import_local (CVSFILE *, void *);
1.3 jfb 48:
1.18 ! jfb 49: static int dflag = 0;
1.7 joris 50: static RCSNUM *bnum;
51: static char *branch, *module, *vendor, *release;
1.3 jfb 52:
1.15 jfb 53: struct cvs_cmd cvs_cmd_import = {
54: CVS_OP_IMPORT, CVS_REQ_IMPORT, "import",
55: { "im", "imp" },
56: "Import sources into CVS, using vendor branches",
57: "[-d] [-b branch] [-I ign] [-k subst] [-m msg] repository "
58: "vendor-tag release-tags ...",
59: "b:dI:k:m:",
60: NULL,
1.7 joris 61: CF_RECURSE | CF_IGNORE | CF_NOSYMS,
1.15 jfb 62: cvs_import_init,
63: cvs_import_pre_exec,
64: cvs_import_remote,
65: cvs_import_local,
66: NULL,
67: NULL,
1.7 joris 68: CVS_CMD_SENDDIR
69: };
1.1 krapht 70:
1.15 jfb 71: static int
72: cvs_import_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
1.1 krapht 73: {
1.7 joris 74: int ch;
1.1 krapht 75:
1.13 jfb 76: branch = CVS_IMPORT_DEFBRANCH;
77:
1.15 jfb 78: while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
1.1 krapht 79: switch (ch) {
80: case 'b':
1.3 jfb 81: branch = optarg;
1.6 joris 82: if ((bnum = rcsnum_parse(branch)) == NULL) {
1.3 jfb 83: cvs_log(LP_ERR, "%s is not a numeric branch",
84: branch);
1.11 joris 85: return (CVS_EX_USAGE);
1.3 jfb 86: }
1.6 joris 87: rcsnum_free(bnum);
1.3 jfb 88: break;
1.1 krapht 89: case 'd':
1.18 ! jfb 90: dflag = 1;
1.1 krapht 91: break;
92: case 'I':
93: if (cvs_file_ignore(optarg) < 0) {
94: cvs_log(LP_ERR, "failed to add `%s' to list "
95: "of ignore patterns", optarg);
1.11 joris 96: return (CVS_EX_USAGE);
1.1 krapht 97: }
98: break;
99: case 'k':
100: break;
101: case 'm':
1.4 jfb 102: cvs_msg = strdup(optarg);
103: if (cvs_msg == NULL) {
104: cvs_log(LP_ERRNO, "failed to copy message");
1.11 joris 105: return (CVS_EX_DATA);
1.4 jfb 106: }
1.1 krapht 107: break;
108: default:
1.11 joris 109: return (CVS_EX_USAGE);
1.1 krapht 110: }
111: }
112:
113: argc -= optind;
114: argv += optind;
1.7 joris 115:
1.15 jfb 116: if (argc != 3)
1.11 joris 117: return (CVS_EX_USAGE);
1.1 krapht 118:
1.7 joris 119: module = argv[0];
120: vendor = argv[1];
121: release = argv[2];
1.1 krapht 122:
1.15 jfb 123: *arg = optind + 3;
124:
1.3 jfb 125: if ((cvs_msg == NULL) &&
126: (cvs_msg = cvs_logmsg_get(NULL, NULL, NULL, NULL)) == NULL)
1.11 joris 127: return (CVS_EX_DATA);
1.1 krapht 128:
1.7 joris 129: return (0);
130: }
1.1 krapht 131:
1.15 jfb 132: static int
133: cvs_import_pre_exec(struct cvsroot *root)
1.7 joris 134: {
1.15 jfb 135: char repodir[MAXPATHLEN];
136:
137: if (root->cr_method == CVS_METHOD_LOCAL) {
138: snprintf(repodir, sizeof(repodir), "%s/%s", root->cr_dir,
139: module);
1.18 ! jfb 140: if (mkdir(repodir, 0700) == -1) {
! 141: cvs_log(LP_ERRNO, "failed to create %s", repodir);
! 142: return (CVS_EX_DATA);
! 143: }
1.15 jfb 144: } else {
145: if ((cvs_sendarg(root, "-b", 0) < 0) ||
146: (cvs_sendarg(root, branch, 0) < 0) ||
147: (cvs_logmsg_send(root, cvs_msg) < 0) ||
148: (cvs_sendarg(root, module, 0) < 0) ||
149: (cvs_sendarg(root, vendor, 0) < 0) ||
150: (cvs_sendarg(root, release, 0) < 0))
151: return (CVS_EX_PROTO);
152: }
1.1 krapht 153:
154: return (0);
155: }
156:
1.3 jfb 157: /*
1.15 jfb 158: * cvs_import_remote()
1.3 jfb 159: *
160: * Perform the import of a single file or directory.
161: */
1.15 jfb 162: static int
163: cvs_import_remote(CVSFILE *cf, void *arg)
1.1 krapht 164: {
1.15 jfb 165: int len;
1.3 jfb 166: struct cvsroot *root;
167: char fpath[MAXPATHLEN], repodir[MAXPATHLEN];
1.7 joris 168: char repo[MAXPATHLEN];
1.1 krapht 169:
1.15 jfb 170: root = CVS_DIR_ROOT(cf);
171: len = snprintf(repo, sizeof(repo), "%s/%s", root->cr_dir, module);
172: if (len == -1 || len >= (int)sizeof(repo)) {
1.12 xsa 173: errno = ENAMETOOLONG;
174: cvs_log(LP_ERRNO, "%s", repo);
1.14 joris 175: return (CVS_EX_DATA);
1.12 xsa 176: }
1.1 krapht 177:
1.15 jfb 178: cvs_file_getpath(cf, fpath, sizeof(fpath));
1.1 krapht 179:
1.15 jfb 180: if (cf->cf_type == DT_DIR) {
181: if (!strcmp(cf->cf_name, "."))
1.3 jfb 182: strlcpy(repodir, repo, sizeof(repodir));
1.12 xsa 183: else {
1.15 jfb 184: len = snprintf(repodir, sizeof(repodir), "%s/%s",
1.12 xsa 185: repo, fpath);
1.15 jfb 186: if (len == -1 || len >= (int)sizeof(repodir)) {
1.12 xsa 187: errno = ENAMETOOLONG;
188: cvs_log(LP_ERRNO, "%s", repodir);
1.14 joris 189: return (CVS_EX_DATA);
1.12 xsa 190: }
191: }
1.15 jfb 192:
193: if (cvs_sendreq(root, CVS_REQ_DIRECTORY, fpath) < 0)
194: return (CVS_EX_PROTO);
195: if (cvs_sendln(root, repodir) < 0)
196: return (CVS_EX_PROTO);
197: return (0);
198: }
199:
200: if (cvs_sendreq(root, CVS_REQ_MODIFIED, cf->cf_name) < 0)
201: return (CVS_EX_PROTO);
202: if (cvs_sendfile(root, fpath) < 0)
203: return (CVS_EX_PROTO);
204:
205: return (0);
206: }
207:
208: static int
209: cvs_import_local(CVSFILE *cf, void *arg)
210: {
211: int len;
1.18 ! jfb 212: time_t stamp;
1.15 jfb 213: char fpath[MAXPATHLEN], rpath[MAXPATHLEN], repo[MAXPATHLEN];
1.17 jfb 214: const char *comment;
1.18 ! jfb 215: struct stat fst;
! 216: struct timeval ts[2];
! 217: struct cvsroot *root;
1.15 jfb 218: RCSFILE *rf;
1.17 jfb 219: RCSNUM *rev;
1.15 jfb 220:
221: root = CVS_DIR_ROOT(cf);
222: len = snprintf(repo, sizeof(repo), "%s/%s", root->cr_dir, module);
223: if (len == -1 || len >= (int)sizeof(repo)) {
224: errno = ENAMETOOLONG;
225: cvs_log(LP_ERRNO, "%s", repo);
226: return (CVS_EX_DATA);
227: }
228:
229: cvs_file_getpath(cf, fpath, sizeof(fpath));
230:
231: if (cf->cf_type == DT_DIR) {
232: if (!strcmp(cf->cf_name, "."))
233: strlcpy(rpath, repo, sizeof(rpath));
234: else {
235: len = snprintf(rpath, sizeof(rpath), "%s/%s",
236: repo, fpath);
237: if (len == -1 || len >= (int)sizeof(rpath)) {
238: errno = ENAMETOOLONG;
239: cvs_log(LP_ERRNO, "%s", rpath);
240: return (CVS_EX_DATA);
241: }
242:
243: cvs_printf("Importing %s\n", rpath);
244: if (mkdir(rpath, 0700) == -1) {
245: cvs_log(LP_ERRNO, "failed to create %s",
246: rpath);
247: }
1.3 jfb 248: }
1.1 krapht 249:
1.3 jfb 250: return (0);
1.1 krapht 251: }
252:
1.18 ! jfb 253: /*
! 254: * If -d was given, use the file's last modification time as the
! 255: * timestamps for the initial revisions.
! 256: */
! 257: if (dflag) {
! 258: if (stat(fpath, &fst) == -1) {
! 259: cvs_log(LP_ERRNO, "failed to stat %s", fpath);
! 260: return (CVS_EX_DATA);
! 261: }
! 262: stamp = (time_t)fst.st_mtime;
! 263:
! 264: ts[0].tv_sec = stamp;
! 265: ts[0].tv_usec = 0;
! 266: ts[1].tv_sec = stamp;
! 267: ts[1].tv_usec = 0;
! 268: } else
! 269: stamp = -1;
! 270:
1.15 jfb 271: snprintf(rpath, sizeof(rpath), "%s/%s%s",
272: repo, fpath, RCS_FILE_EXT);
273:
274: cvs_printf("N %s\n", fpath);
275:
276: rf = rcs_open(rpath, RCS_RDWR|RCS_CREATE);
277: if (rf == NULL) {
1.17 jfb 278: cvs_log(LP_ERR, "failed to create RCS file: %s",
279: strerror(rcs_errno));
280: return (CVS_EX_DATA);
281: }
282:
283: comment = rcs_comment_lookup(cf->cf_name);
284: if ((comment != NULL) && (rcs_comment_set(rf, comment) < 0)) {
1.18 ! jfb 285: cvs_log(LP_WARN, "failed to set RCS comment leader: %s",
1.17 jfb 286: rcs_errstr(rcs_errno));
1.18 ! jfb 287: /* don't error out, no big deal */
1.17 jfb 288: }
289:
290: /* first add the magic 1.1.1.1 revision */
291: rev = rcsnum_parse("1.1.1.1");
1.18 ! jfb 292: if (rcs_rev_add(rf, rev, cvs_msg, stamp) < 0) {
1.17 jfb 293: cvs_log(LP_ERR, "failed to add revision: %s",
294: rcs_errstr(rcs_errno));
295: rcs_close(rf);
296: (void)unlink(rpath);
297: return (CVS_EX_DATA);
298: }
1.18 ! jfb 299:
! 300: if (rcs_sym_add(rf, release, rev) < 0) {
! 301: cvs_log(LP_ERR, "failed to set RCS symbol: %s",
! 302: strerror(rcs_errno));
! 303: rcs_close(rf);
! 304: (void)unlink(rpath);
! 305: return (CVS_EX_DATA);
! 306: }
! 307:
1.17 jfb 308: rcsnum_free(rev);
309:
310: rev = rcsnum_parse(RCS_HEAD_INIT);
1.18 ! jfb 311: if (rcs_rev_add(rf, rev, cvs_msg, stamp) < 0) {
1.17 jfb 312: cvs_log(LP_ERR, "failed to add revision: %s",
313: rcs_errstr(rcs_errno));
314: rcs_close(rf);
315: (void)unlink(rpath);
316: return (CVS_EX_DATA);
317: }
318:
319: if (rcs_head_set(rf, rev) < 0) {
320: cvs_log(LP_ERR, "failed to set RCS head: %s",
321: rcs_errstr(rcs_errno));
322: rcs_close(rf);
323: (void)unlink(rpath);
324: return (CVS_EX_DATA);
1.1 krapht 325: }
326:
1.18 ! jfb 327: #if 0
! 328: if (rcs_branch_set(rf, rev) < 0) {
! 329: cvs_log(LP_ERR, "failed to set RCS default branch: %s",
! 330: strerror(rcs_errno));
! 331: return (CVS_EX_DATA);
! 332: }
! 333: #endif
! 334:
! 335: /* add the vendor tag and release tag as symbols */
1.15 jfb 336: rcs_close(rf);
1.18 ! jfb 337:
! 338: if (dflag && (utimes(rpath, ts) == -1))
! 339: cvs_log(LP_ERRNO, "failed to timestamp RCS file");
1.15 jfb 340:
341: return (CVS_EX_OK);
1.1 krapht 342: }