xref: /openbsd-src/usr.bin/cvs/init.c (revision 2100a5ff504ed00b8deedb415d4733763a3845d8)
1*2100a5ffSderaadt /*	$OpenBSD: init.c,v 1.42 2021/10/25 10:07:12 deraadt Exp $	*/
26c121f58Sjfb /*
36c121f58Sjfb  * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
4db68708cSxsa  * Copyright (c) 2006 Xavier Santolaria <xsa@openbsd.org>
56c121f58Sjfb  * All rights reserved.
66c121f58Sjfb  *
76c121f58Sjfb  * Redistribution and use in source and binary forms, with or without
86c121f58Sjfb  * modification, are permitted provided that the following conditions
96c121f58Sjfb  * are met:
106c121f58Sjfb  *
116c121f58Sjfb  * 1. Redistributions of source code must retain the above copyright
126c121f58Sjfb  *    notice, this list of conditions and the following disclaimer.
136c121f58Sjfb  * 2. The name of the author may not be used to endorse or promote products
146c121f58Sjfb  *    derived from this software without specific prior written permission.
156c121f58Sjfb  *
166c121f58Sjfb  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
176c121f58Sjfb  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
186c121f58Sjfb  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
196c121f58Sjfb  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
206c121f58Sjfb  * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
216c121f58Sjfb  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
226c121f58Sjfb  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
236c121f58Sjfb  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
246c121f58Sjfb  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
256c121f58Sjfb  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
266c121f58Sjfb  */
276c121f58Sjfb 
281f8531bdSotto #include <sys/stat.h>
291f8531bdSotto 
301f8531bdSotto #include <errno.h>
311f8531bdSotto #include <fcntl.h>
321f8531bdSotto #include <string.h>
331f8531bdSotto #include <unistd.h>
346c121f58Sjfb 
35710495d3Stobias #include "atomicio.h"
366c121f58Sjfb #include "cvs.h"
37db68708cSxsa #include "init.h"
38fd590a3cSxsa #include "remote.h"
396c121f58Sjfb 
40db68708cSxsa void	cvs_init_local(void);
416c121f58Sjfb 
42db68708cSxsa static void init_mkdir(const char *, mode_t);
430fcddf58Sotto static void init_mkfile(char *, char **);
446c121f58Sjfb 
456c121f58Sjfb struct cvsroot_file {
46db68708cSxsa 	char			*cf_path;
470fcddf58Sotto 	char			**cf_content;
486c121f58Sjfb };
496c121f58Sjfb 
50db68708cSxsa static const struct cvsroot_file cvsroot_files[] = {
51db68708cSxsa 	{ CVS_PATH_CHECKOUTLIST,	NULL			},
52db68708cSxsa 	{ CVS_PATH_COMMITINFO,		NULL			},
53db68708cSxsa 	{ CVS_PATH_CONFIG,		config_contents		},
54db68708cSxsa 	{ CVS_PATH_CVSWRAPPERS,		NULL			},
55db68708cSxsa 	{ CVS_PATH_EDITINFO,		NULL			},
56db68708cSxsa 	{ CVS_PATH_HISTORY,		NULL			},
57db68708cSxsa 	{ CVS_PATH_LOGINFO,		NULL			},
58db68708cSxsa 	{ CVS_PATH_MODULES,		NULL			},
59db68708cSxsa 	{ CVS_PATH_NOTIFY_R,		NULL			},
60db68708cSxsa 	{ CVS_PATH_RCSINFO,		NULL			},
61db68708cSxsa 	{ CVS_PATH_TAGINFO,		NULL			},
62db68708cSxsa 	{ CVS_PATH_VALTAGS,		NULL			},
63db68708cSxsa 	{ CVS_PATH_VERIFYMSG,		NULL			}
64db68708cSxsa };
65db68708cSxsa 
66db68708cSxsa static const char *cvsroot_dirs[2] = {
67db68708cSxsa 	CVS_PATH_ROOT, CVS_PATH_EMPTYDIR
68db68708cSxsa };
69db68708cSxsa 
70db68708cSxsa #define INIT_NFILES	(sizeof(cvsroot_files)/sizeof(cvsroot_files[0]))
71db68708cSxsa #define INIT_NDIRS	(sizeof(cvsroot_dirs)/sizeof(cvsroot_dirs[0]))
7216cfc147Sjoris 
73e4276007Sjfb struct cvs_cmd cvs_cmd_init = {
7462dc927bSjoris 	CVS_OP_INIT, 0, "init",
757eeb4908Sragge 	{ { 0 }, { 0 } },
76e4276007Sjfb 	"Create a CVS repository if it doesn't exist",
77e4276007Sjfb 	"",
78e4276007Sjfb 	"",
7916cfc147Sjoris 	NULL,
80db68708cSxsa 	cvs_init
8116cfc147Sjoris };
826c121f58Sjfb 
83db68708cSxsa int
cvs_init(int argc,char ** argv)84db68708cSxsa cvs_init(int argc, char **argv)
856c121f58Sjfb {
86db68708cSxsa 	if (argc > 1)
878e7fbdbaSjoris 		fatal("init does not take any extra arguments");
88db68708cSxsa 
894dcde513Sjoris 	if (cvsroot_is_remote()) {
9080f6ca9bSjoris 		cvs_client_connect_to_server();
91fd590a3cSxsa 		cvs_client_send_request("init %s", current_cvsroot->cr_dir);
92fd590a3cSxsa 		cvs_client_get_responses();
934dcde513Sjoris 	} else {
94db68708cSxsa 		cvs_init_local();
954dcde513Sjoris 	}
9640f842cdSxsa 
9740f842cdSxsa 	return (0);
9840f842cdSxsa }
9940f842cdSxsa 
100db68708cSxsa void
cvs_init_local(void)101db68708cSxsa cvs_init_local(void)
10240f842cdSxsa {
1036c121f58Sjfb 	u_int i;
104b9fc9a72Sderaadt 	char path[PATH_MAX];
105db68708cSxsa 
106db68708cSxsa 	cvs_log(LP_TRACE, "cvs_init_local()");
1079afeef4eSjfb 
10840f842cdSxsa 	/* Create repository root directory if it does not already exist */
109db68708cSxsa 	init_mkdir(current_cvsroot->cr_dir, 0777);
110db68708cSxsa 
111db68708cSxsa 	for (i = 0; i < INIT_NDIRS; i++) {
112b9fc9a72Sderaadt 		(void)xsnprintf(path, PATH_MAX, "%s/%s",
113e40de241Sxsa 		    current_cvsroot->cr_dir, cvsroot_dirs[i]);
114db68708cSxsa 
115db68708cSxsa 		init_mkdir(path, 0777);
11640f842cdSxsa 	}
11740f842cdSxsa 
118db68708cSxsa 	for (i = 0; i < INIT_NFILES; i++) {
119b9fc9a72Sderaadt 		(void)xsnprintf(path, PATH_MAX, "%s/%s",
120e40de241Sxsa 		    current_cvsroot->cr_dir, cvsroot_files[i].cf_path);
1216c121f58Sjfb 
122db68708cSxsa 		init_mkfile(path, cvsroot_files[i].cf_content);
123db68708cSxsa 	}
124db68708cSxsa }
125db68708cSxsa 
126db68708cSxsa static void
init_mkdir(const char * path,mode_t mode)127db68708cSxsa init_mkdir(const char *path, mode_t mode)
128db68708cSxsa {
129db68708cSxsa 	struct stat st;
130db68708cSxsa 
131db68708cSxsa 	if (mkdir(path, mode) == -1) {
132db68708cSxsa 		if (!(errno == EEXIST ||
133db68708cSxsa 		    (errno == EACCES && (stat(path, &st) == 0) &&
13440f842cdSxsa 		    S_ISDIR(st.st_mode)))) {
135db68708cSxsa 			fatal("init_mkdir: mkdir: `%s': %s",
136db68708cSxsa 			    path, strerror(errno));
1376c121f58Sjfb 		}
13840f842cdSxsa 	}
139db68708cSxsa }
1406c121f58Sjfb 
141db68708cSxsa static void
init_mkfile(char * path,char ** content)1420fcddf58Sotto init_mkfile(char *path, char **content)
143db68708cSxsa {
144db68708cSxsa 	BUF *b;
145db68708cSxsa 	size_t len;
146*2100a5ffSderaadt 	int fd, rcsflags;
147b9fc9a72Sderaadt 	char rpath[PATH_MAX];
1480fcddf58Sotto 	char **p;
149db68708cSxsa 	RCSFILE *file;
150db68708cSxsa 
151e0b06badSjoris 	rcsflags = RCS_WRITE | RCS_CREATE;
152db68708cSxsa 
153*2100a5ffSderaadt 	if ((fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0444)) == -1)
154db68708cSxsa 		fatal("init_mkfile: open: `%s': %s", path, strerror(errno));
155db68708cSxsa 
156db68708cSxsa 	if (content != NULL) {
157db68708cSxsa 		for (p = content; *p != NULL; ++p) {
158db68708cSxsa 			len = strlen(*p);
159710495d3Stobias 			if (atomicio(vwrite, fd, *p, len) != len)
160710495d3Stobias 				fatal("init_mkfile: atomicio failed");
161db68708cSxsa 		}
162db68708cSxsa 	}
163db68708cSxsa 
164db68708cSxsa 	/*
165db68708cSxsa 	 * Make sure history and val-tags files are world-writable.
166db68708cSxsa 	 * Every user should be able to write to them.
167db68708cSxsa 	 */
168db68708cSxsa 	if (strcmp(strrchr(CVS_PATH_HISTORY, '/'), strrchr(path, '/')) == 0 ||
169db68708cSxsa 	    strcmp(strrchr(CVS_PATH_VALTAGS, '/'), strrchr(path, '/')) == 0) {
170db68708cSxsa 		(void)fchmod(fd, 0666);
171710495d3Stobias 		(void)close(fd);
172710495d3Stobias 		return;
173db68708cSxsa 	}
174db68708cSxsa 
175b9fc9a72Sderaadt 	(void)xsnprintf(rpath, PATH_MAX, "%s%s", path, RCS_FILE_EXT);
176db68708cSxsa 
177cc89a134Snicm 	if ((file = rcs_open(rpath, -1, rcsflags, 0444)) == NULL)
178db68708cSxsa 		fatal("failed to create RCS file for `%s'", path);
179db68708cSxsa 
1807bb3ddb0Sray 	b = buf_load(path);
181db68708cSxsa 
182db68708cSxsa 	if (rcs_rev_add(file, RCS_HEAD_REV, "initial checkin", -1, NULL) == -1)
183db68708cSxsa 		fatal("init_mkfile: failed to add new revision");
184db68708cSxsa 
185784f2510Sjoris 	/* b buffer is free'd in rcs_deltatext_set */
186784f2510Sjoris 	if (rcs_deltatext_set(file, file->rf_head, b) == -1)
187db68708cSxsa 		fatal("init_mkfile: failed to set delta");
188db68708cSxsa 
189db68708cSxsa 	file->rf_flags &= ~RCS_SYNCED;
190db68708cSxsa 	rcs_close(file);
1916c121f58Sjfb 	(void)close(fd);
1926c121f58Sjfb }
193