Annotation of src/usr.bin/cvs/init.c, Revision 1.39
1.39 ! deraadt 1: /* $OpenBSD: init.c,v 1.38 2010/10/31 15:37:34 nicm 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.32 otto 28: #include <sys/stat.h>
29:
30: #include <errno.h>
31: #include <fcntl.h>
32: #include <string.h>
33: #include <unistd.h>
1.1 jfb 34:
1.34 tobias 35: #include "atomicio.h"
1.1 jfb 36: #include "cvs.h"
1.23 xsa 37: #include "init.h"
1.26 xsa 38: #include "remote.h"
1.1 jfb 39:
1.23 xsa 40: void cvs_init_local(void);
1.1 jfb 41:
1.23 xsa 42: static void init_mkdir(const char *, mode_t);
1.34 tobias 43: static void init_mkfile(char *, const char **);
1.1 jfb 44:
1.23 xsa 45: struct cvsroot_file {
46: char *cf_path;
1.34 tobias 47: const char **cf_content;
1.23 xsa 48: };
49:
50: static const struct cvsroot_file cvsroot_files[] = {
51: { CVS_PATH_CHECKOUTLIST, NULL },
52: { CVS_PATH_COMMITINFO, NULL },
53: { CVS_PATH_CONFIG, config_contents },
54: { CVS_PATH_CVSWRAPPERS, NULL },
55: { CVS_PATH_EDITINFO, NULL },
56: { CVS_PATH_HISTORY, NULL },
57: { CVS_PATH_LOGINFO, NULL },
58: { CVS_PATH_MODULES, NULL },
59: { CVS_PATH_NOTIFY_R, NULL },
60: { CVS_PATH_RCSINFO, NULL },
61: { CVS_PATH_TAGINFO, NULL },
62: { CVS_PATH_VALTAGS, NULL },
63: { CVS_PATH_VERIFYMSG, NULL }
64: };
1.1 jfb 65:
1.23 xsa 66: static const char *cvsroot_dirs[2] = {
67: CVS_PATH_ROOT, CVS_PATH_EMPTYDIR
1.1 jfb 68: };
69:
1.23 xsa 70: #define INIT_NFILES (sizeof(cvsroot_files)/sizeof(cvsroot_files[0]))
71: #define INIT_NDIRS (sizeof(cvsroot_dirs)/sizeof(cvsroot_dirs[0]))
1.12 joris 72:
1.16 jfb 73: struct cvs_cmd cvs_cmd_init = {
1.25 joris 74: CVS_OP_INIT, 0, "init",
1.35 ragge 75: { { 0 }, { 0 } },
1.16 jfb 76: "Create a CVS repository if it doesn't exist",
77: "",
78: "",
1.12 joris 79: NULL,
1.23 xsa 80: cvs_init
1.12 joris 81: };
1.1 jfb 82:
1.23 xsa 83: int
84: cvs_init(int argc, char **argv)
1.18 xsa 85: {
1.23 xsa 86: if (argc > 1)
1.24 joris 87: fatal("init does not take any extra arguments");
1.23 xsa 88:
1.26 xsa 89: if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
1.27 joris 90: cvs_client_connect_to_server();
1.26 xsa 91: cvs_client_send_request("init %s", current_cvsroot->cr_dir);
92: cvs_client_get_responses();
93: } else
1.23 xsa 94: cvs_init_local();
1.18 xsa 95:
96: return (0);
97: }
98:
1.23 xsa 99: void
100: cvs_init_local(void)
101: {
102: u_int i;
1.39 ! deraadt 103: char path[PATH_MAX];
1.23 xsa 104:
105: cvs_log(LP_TRACE, "cvs_init_local()");
106:
107: /* Create repository root directory if it does not already exist */
108: init_mkdir(current_cvsroot->cr_dir, 0777);
109:
110: for (i = 0; i < INIT_NDIRS; i++) {
1.39 ! deraadt 111: (void)xsnprintf(path, PATH_MAX, "%s/%s",
1.31 xsa 112: current_cvsroot->cr_dir, cvsroot_dirs[i]);
1.23 xsa 113:
114: init_mkdir(path, 0777);
115: }
116:
117: for (i = 0; i < INIT_NFILES; i++) {
1.39 ! deraadt 118: (void)xsnprintf(path, PATH_MAX, "%s/%s",
1.31 xsa 119: current_cvsroot->cr_dir, cvsroot_files[i].cf_path);
1.23 xsa 120:
121: init_mkfile(path, cvsroot_files[i].cf_content);
122: }
123: }
124:
1.21 xsa 125: static void
1.23 xsa 126: init_mkdir(const char *path, mode_t mode)
1.1 jfb 127: {
1.18 xsa 128: struct stat st;
1.4 jfb 129:
1.23 xsa 130: if (mkdir(path, mode) == -1) {
131: if (!(errno == EEXIST ||
132: (errno == EACCES && (stat(path, &st) == 0) &&
133: S_ISDIR(st.st_mode)))) {
134: fatal("init_mkdir: mkdir: `%s': %s",
135: path, strerror(errno));
1.18 xsa 136: }
137: }
1.23 xsa 138: }
139:
140: static void
1.34 tobias 141: init_mkfile(char *path, const char **content)
1.23 xsa 142: {
143: BUF *b;
144: size_t len;
145: int fd, openflags, rcsflags;
1.39 ! deraadt 146: char rpath[PATH_MAX];
1.34 tobias 147: const char **p;
1.23 xsa 148: RCSFILE *file;
149:
1.36 joris 150: openflags = O_WRONLY | O_CREAT | O_EXCL;
151: rcsflags = RCS_WRITE | RCS_CREATE;
1.23 xsa 152:
153: if ((fd = open(path, openflags, 0444)) == -1)
154: fatal("init_mkfile: open: `%s': %s", path, strerror(errno));
155:
156: if (content != NULL) {
157: for (p = content; *p != NULL; ++p) {
158: len = strlen(*p);
1.34 tobias 159: if (atomicio(vwrite, fd, *p, len) != len)
160: fatal("init_mkfile: atomicio failed");
1.1 jfb 161: }
162: }
1.23 xsa 163:
164: /*
165: * Make sure history and val-tags files are world-writable.
166: * Every user should be able to write to them.
167: */
168: if (strcmp(strrchr(CVS_PATH_HISTORY, '/'), strrchr(path, '/')) == 0 ||
169: strcmp(strrchr(CVS_PATH_VALTAGS, '/'), strrchr(path, '/')) == 0) {
170: (void)fchmod(fd, 0666);
1.34 tobias 171: (void)close(fd);
172: return;
1.23 xsa 173: }
174:
1.39 ! deraadt 175: (void)xsnprintf(rpath, PATH_MAX, "%s%s", path, RCS_FILE_EXT);
1.23 xsa 176:
1.38 nicm 177: if ((file = rcs_open(rpath, -1, rcsflags, 0444)) == NULL)
1.23 xsa 178: fatal("failed to create RCS file for `%s'", path);
179:
1.37 ray 180: b = buf_load(path);
1.23 xsa 181:
182: if (rcs_rev_add(file, RCS_HEAD_REV, "initial checkin", -1, NULL) == -1)
183: fatal("init_mkfile: failed to add new revision");
184:
1.28 joris 185: /* b buffer is free'd in rcs_deltatext_set */
186: if (rcs_deltatext_set(file, file->rf_head, b) == -1)
1.23 xsa 187: fatal("init_mkfile: failed to set delta");
188:
189: file->rf_flags &= ~RCS_SYNCED;
190: rcs_close(file);
191: (void)close(fd);
1.1 jfb 192: }