Annotation of src/usr.bin/cvs/init.c, Revision 1.24
1.24 ! joris 1: /* $OpenBSD: init.c,v 1.23 2006/06/12 13:56:00 xsa Exp $ */
1.1 jfb 2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
1.23 xsa 4: * Copyright (c) 2006 Xavier Santolaria <xsa@openbsd.org>
1.8 tedu 5: * All rights reserved.
1.1 jfb 6: *
1.8 tedu 7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
1.1 jfb 10: *
1.8 tedu 11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
1.1 jfb 13: * 2. The name of the author may not be used to endorse or promote products
1.8 tedu 14: * derived from this software without specific prior written permission.
1.1 jfb 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
1.8 tedu 25: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1 jfb 26: */
27:
1.20 xsa 28: #include "includes.h"
1.1 jfb 29:
30: #include "cvs.h"
1.23 xsa 31: #include "init.h"
1.1 jfb 32: #include "log.h"
1.6 jfb 33: #include "proto.h"
1.1 jfb 34:
1.23 xsa 35: int cvs_init(int, char **);
36: void cvs_init_local(void);
1.1 jfb 37:
1.23 xsa 38: static void init_mkdir(const char *, mode_t);
39: static void init_mkfile(char *, const char *const *);
1.1 jfb 40:
1.23 xsa 41: struct cvsroot_file {
42: char *cf_path;
43: const char *const *cf_content;
44: };
45:
46: static const struct cvsroot_file cvsroot_files[] = {
47: { CVS_PATH_CHECKOUTLIST, NULL },
48: { CVS_PATH_COMMITINFO, NULL },
49: { CVS_PATH_CONFIG, config_contents },
50: { CVS_PATH_CVSWRAPPERS, NULL },
51: { CVS_PATH_EDITINFO, NULL },
52: { CVS_PATH_HISTORY, NULL },
53: { CVS_PATH_LOGINFO, NULL },
54: { CVS_PATH_MODULES, NULL },
55: { CVS_PATH_NOTIFY_R, NULL },
56: { CVS_PATH_RCSINFO, NULL },
57: { CVS_PATH_TAGINFO, NULL },
58: { CVS_PATH_VALTAGS, NULL },
59: { CVS_PATH_VERIFYMSG, NULL }
60: };
1.1 jfb 61:
1.23 xsa 62: static const char *cvsroot_dirs[2] = {
63: CVS_PATH_ROOT, CVS_PATH_EMPTYDIR
1.1 jfb 64: };
65:
1.23 xsa 66: #define INIT_NFILES (sizeof(cvsroot_files)/sizeof(cvsroot_files[0]))
67: #define INIT_NDIRS (sizeof(cvsroot_dirs)/sizeof(cvsroot_dirs[0]))
1.12 joris 68:
1.16 jfb 69: struct cvs_cmd cvs_cmd_init = {
70: CVS_OP_INIT, CVS_REQ_INIT, "init",
71: { },
72: "Create a CVS repository if it doesn't exist",
73: "",
74: "",
1.12 joris 75: NULL,
1.23 xsa 76: cvs_init
1.12 joris 77: };
1.1 jfb 78:
1.23 xsa 79: int
80: cvs_init(int argc, char **argv)
1.18 xsa 81: {
1.23 xsa 82: if (argc > 1)
1.24 ! joris 83: fatal("init does not take any extra arguments");
1.23 xsa 84:
85: if (current_cvsroot->cr_method == CVS_METHOD_LOCAL)
86: cvs_init_local();
1.18 xsa 87:
88: return (0);
89: }
90:
1.23 xsa 91: void
92: cvs_init_local(void)
93: {
94: u_int i;
95: char *path;
96:
97: cvs_log(LP_TRACE, "cvs_init_local()");
98:
99: /* Create repository root directory if it does not already exist */
100: init_mkdir(current_cvsroot->cr_dir, 0777);
101:
102: path = xmalloc(MAXPATHLEN);
103:
104: for (i = 0; i < INIT_NDIRS; i++) {
105: if (cvs_path_cat(current_cvsroot->cr_dir,
106: cvsroot_dirs[i], path, MAXPATHLEN) >= MAXPATHLEN)
107: fatal("cvs_init_local: truncation");
108:
109: init_mkdir(path, 0777);
110: }
111:
112: for (i = 0; i < INIT_NFILES; i++) {
113: if (cvs_path_cat(current_cvsroot->cr_dir,
114: cvsroot_files[i].cf_path, path, MAXPATHLEN) >= MAXPATHLEN)
115: fatal("cvs_init_local: truncation");
116:
117: init_mkfile(path, cvsroot_files[i].cf_content);
118: }
119:
120: xfree(path);
121: }
122:
1.21 xsa 123: static void
1.23 xsa 124: init_mkdir(const char *path, mode_t mode)
1.1 jfb 125: {
1.18 xsa 126: struct stat st;
1.4 jfb 127:
1.23 xsa 128: if (mkdir(path, mode) == -1) {
129: if (!(errno == EEXIST ||
130: (errno == EACCES && (stat(path, &st) == 0) &&
131: S_ISDIR(st.st_mode)))) {
132: fatal("init_mkdir: mkdir: `%s': %s",
133: path, strerror(errno));
1.18 xsa 134: }
135: }
1.23 xsa 136: }
137:
138: static void
139: init_mkfile(char *path, const char *const *content)
140: {
141: BUF *b;
142: size_t len;
143: int fd, openflags, rcsflags;
144: char *d, *rpath;
145: const char *const *p;
146: RCSFILE *file;
147:
148: len = 0;
149: fd = -1;
150: d = NULL;
151: openflags = O_WRONLY|O_CREAT|O_EXCL;
152: rcsflags = RCS_RDWR|RCS_CREATE;
153:
154: if ((fd = open(path, openflags, 0444)) == -1)
155: fatal("init_mkfile: open: `%s': %s", path, strerror(errno));
156:
157: if (content != NULL) {
158: for (p = content; *p != NULL; ++p) {
159: len = strlen(*p);
160: b = cvs_buf_alloc(len, BUF_AUTOEXT);
1.18 xsa 161:
1.23 xsa 162: if (cvs_buf_append(b, *p, strlen(*p)) < 0)
163: fatal("init_mkfile: cvs_buf_append");
1.1 jfb 164:
1.23 xsa 165: if (cvs_buf_write_fd(b, fd) < 0)
166: fatal("init_mkfile: cvs_buf_write_fd");
167:
168: cvs_buf_free(b);
1.1 jfb 169: }
170: }
1.23 xsa 171:
172: /*
173: * Make sure history and val-tags files are world-writable.
174: * Every user should be able to write to them.
175: */
176: if (strcmp(strrchr(CVS_PATH_HISTORY, '/'), strrchr(path, '/')) == 0 ||
177: strcmp(strrchr(CVS_PATH_VALTAGS, '/'), strrchr(path, '/')) == 0) {
178: (void)fchmod(fd, 0666);
179: goto out;
180: }
181:
182: rpath = xstrdup(path);
183: if (strlcat(rpath, RCS_FILE_EXT, MAXPATHLEN) >= MAXPATHLEN)
184: fatal("init_mkfile: truncation");
185:
186: if ((file = rcs_open(rpath, fd, rcsflags, 0444)) == NULL)
187: fatal("failed to create RCS file for `%s'", path);
188:
189: if ((b = cvs_buf_load(path, BUF_AUTOEXT)) == NULL)
190: fatal("init_mkfile: failed to load %s", path);
191:
192: cvs_buf_putc(b, '\0');
193: d = cvs_buf_release(b);
194:
195: if (rcs_rev_add(file, RCS_HEAD_REV, "initial checkin", -1, NULL) == -1)
196: fatal("init_mkfile: failed to add new revision");
197:
198: if (rcs_deltatext_set(file, file->rf_head, d) == -1)
199: fatal("init_mkfile: failed to set delta");
200:
201: file->rf_flags &= ~RCS_SYNCED;
202: rcs_close(file);
203: xfree(rpath);
204: out:
205: (void)close(fd);
206:
207: if (d != NULL)
208: xfree(d);
1.1 jfb 209: }