version 1.22, 2006/02/10 10:15:48 |
version 1.23, 2006/06/12 13:56:00 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
/* |
/* |
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> |
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> |
|
* Copyright (c) 2006 Xavier Santolaria <xsa@openbsd.org> |
* All rights reserved. |
* All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
|
|
#include "includes.h" |
#include "includes.h" |
|
|
#include "cvs.h" |
#include "cvs.h" |
|
#include "init.h" |
#include "log.h" |
#include "log.h" |
#include "proto.h" |
#include "proto.h" |
|
|
|
int cvs_init(int, char **); |
|
void cvs_init_local(void); |
|
|
#define CFT_FILE 1 |
static void init_mkdir(const char *, mode_t); |
#define CFT_DIR 2 |
static void init_mkfile(char *, const char *const *); |
|
|
|
|
struct cvsroot_file { |
struct cvsroot_file { |
char *cf_path; /* path relative to CVS root directory */ |
char *cf_path; |
u_int cf_type; |
const char *const *cf_content; |
mode_t cf_mode; |
|
} cvsroot_files[] = { |
|
{ CVS_PATH_ROOT, CFT_DIR, (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) }, |
|
{ CVS_PATH_EMPTYDIR, CFT_DIR, (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) }, |
|
{ CVS_PATH_COMMITINFO, CFT_FILE, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) }, |
|
{ CVS_PATH_CONFIG, CFT_FILE, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) }, |
|
{ CVS_PATH_CVSIGNORE, CFT_FILE, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) }, |
|
{ CVS_PATH_CVSWRAPPERS, CFT_FILE, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) }, |
|
{ CVS_PATH_EDITINFO, CFT_FILE, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) }, |
|
{ CVS_PATH_HISTORY, CFT_FILE, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) }, |
|
{ CVS_PATH_LOGINFO, CFT_FILE, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) }, |
|
{ CVS_PATH_MODULES, CFT_FILE, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) }, |
|
{ CVS_PATH_NOTIFY_R, CFT_FILE, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) }, |
|
{ CVS_PATH_RCSINFO, CFT_FILE, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) }, |
|
{ CVS_PATH_TAGINFO, CFT_FILE, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) }, |
|
{ CVS_PATH_VERIFYMSG, CFT_FILE, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) }, |
|
}; |
}; |
|
|
static int cvs_init_pre_exec(struct cvsroot *); |
static const struct cvsroot_file cvsroot_files[] = { |
static void cvs_init_create_files(struct cvsroot *); |
{ CVS_PATH_CHECKOUTLIST, NULL }, |
|
{ CVS_PATH_COMMITINFO, NULL }, |
|
{ CVS_PATH_CONFIG, config_contents }, |
|
{ CVS_PATH_CVSWRAPPERS, NULL }, |
|
{ CVS_PATH_EDITINFO, NULL }, |
|
{ CVS_PATH_HISTORY, NULL }, |
|
{ CVS_PATH_LOGINFO, NULL }, |
|
{ CVS_PATH_MODULES, NULL }, |
|
{ CVS_PATH_NOTIFY_R, NULL }, |
|
{ CVS_PATH_RCSINFO, NULL }, |
|
{ CVS_PATH_TAGINFO, NULL }, |
|
{ CVS_PATH_VALTAGS, NULL }, |
|
{ CVS_PATH_VERIFYMSG, NULL } |
|
}; |
|
|
|
static const char *cvsroot_dirs[2] = { |
|
CVS_PATH_ROOT, CVS_PATH_EMPTYDIR |
|
}; |
|
|
|
#define INIT_NFILES (sizeof(cvsroot_files)/sizeof(cvsroot_files[0])) |
|
#define INIT_NDIRS (sizeof(cvsroot_dirs)/sizeof(cvsroot_dirs[0])) |
|
|
struct cvs_cmd cvs_cmd_init = { |
struct cvs_cmd cvs_cmd_init = { |
CVS_OP_INIT, CVS_REQ_INIT, "init", |
CVS_OP_INIT, CVS_REQ_INIT, "init", |
{ }, |
{ }, |
|
|
"", |
"", |
"", |
"", |
NULL, |
NULL, |
0, |
cvs_init |
NULL, |
|
cvs_init_pre_exec, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL, |
|
0 |
|
}; |
}; |
|
|
/* |
int |
* cvs_init_pre_exec() |
cvs_init(int argc, char **argv) |
* |
|
* Local/remote handler for the "cvs init" command. |
|
* Returns 0 on success, -1 on failure. |
|
*/ |
|
static int |
|
cvs_init_pre_exec(struct cvsroot *root) |
|
{ |
{ |
if (root->cr_method == CVS_METHOD_LOCAL) |
if (argc > 1) |
cvs_init_create_files(root); |
fatal("%s", cvs_cmd_init.cmd_synopsis); |
|
|
|
if (current_cvsroot->cr_method == CVS_METHOD_LOCAL) |
|
cvs_init_local(); |
|
|
return (0); |
return (0); |
} |
} |
|
|
/* |
void |
* cvs_init_create_files |
cvs_init_local(void) |
* |
|
* Create all required files for the "cvs init" command. |
|
* Used by the local handlers. |
|
* Returns 0 on success, -1 on failure. |
|
* |
|
*/ |
|
static void |
|
cvs_init_create_files(struct cvsroot *root) |
|
{ |
{ |
size_t len; |
|
int fd; |
|
u_int i; |
u_int i; |
char path[MAXPATHLEN]; |
char *path; |
RCSFILE *rfp; |
|
struct stat st; |
|
|
|
|
cvs_log(LP_TRACE, "cvs_init_local()"); |
|
|
/* Create repository root directory if it does not already exist */ |
/* Create repository root directory if it does not already exist */ |
if (mkdir(root->cr_dir, 0777) == -1) { |
init_mkdir(current_cvsroot->cr_dir, 0777); |
if (!(errno == EEXIST || (errno == EACCES && |
|
(stat(root->cr_dir, &st) == 0) && S_ISDIR(st.st_mode)))) { |
path = xmalloc(MAXPATHLEN); |
fatal("cvs_init_create_files: mkdir: %s: %s", |
|
root->cr_dir, strerror(errno)); |
for (i = 0; i < INIT_NDIRS; i++) { |
|
if (cvs_path_cat(current_cvsroot->cr_dir, |
|
cvsroot_dirs[i], path, MAXPATHLEN) >= MAXPATHLEN) |
|
fatal("cvs_init_local: truncation"); |
|
|
|
init_mkdir(path, 0777); |
|
} |
|
|
|
for (i = 0; i < INIT_NFILES; i++) { |
|
if (cvs_path_cat(current_cvsroot->cr_dir, |
|
cvsroot_files[i].cf_path, path, MAXPATHLEN) >= MAXPATHLEN) |
|
fatal("cvs_init_local: truncation"); |
|
|
|
init_mkfile(path, cvsroot_files[i].cf_content); |
|
} |
|
|
|
xfree(path); |
|
} |
|
|
|
static void |
|
init_mkdir(const char *path, mode_t mode) |
|
{ |
|
struct stat st; |
|
|
|
if (mkdir(path, mode) == -1) { |
|
if (!(errno == EEXIST || |
|
(errno == EACCES && (stat(path, &st) == 0) && |
|
S_ISDIR(st.st_mode)))) { |
|
fatal("init_mkdir: mkdir: `%s': %s", |
|
path, strerror(errno)); |
} |
} |
} |
} |
|
} |
|
|
/* Create the repository administrative files */ |
static void |
for (i = 0; i < sizeof(cvsroot_files)/sizeof(cvsroot_files[i]); i++) { |
init_mkfile(char *path, const char *const *content) |
len = cvs_path_cat(root->cr_dir, cvsroot_files[i].cf_path, |
{ |
path, sizeof(path)); |
BUF *b; |
if (len >= sizeof(path)) |
size_t len; |
fatal("cvs_init_create_files: path truncation"); |
int fd, openflags, rcsflags; |
|
char *d, *rpath; |
|
const char *const *p; |
|
RCSFILE *file; |
|
|
if (cvsroot_files[i].cf_type == CFT_DIR) { |
len = 0; |
if (mkdir(path, cvsroot_files[i].cf_mode) == -1) { |
fd = -1; |
if (!(errno == EEXIST || (errno == EACCES && |
d = NULL; |
(stat(path, &st) == 0) && |
openflags = O_WRONLY|O_CREAT|O_EXCL; |
S_ISDIR(st.st_mode)))) { |
rcsflags = RCS_RDWR|RCS_CREATE; |
fatal("cvs_init_create_files: mkdir: " |
|
"%s: %s", path, strerror(errno)); |
|
} |
|
} |
|
} else if (cvsroot_files[i].cf_type == CFT_FILE) { |
|
fd = open(path, O_WRONLY|O_CREAT|O_EXCL, |
|
cvsroot_files[i].cf_mode); |
|
if (fd == -1) |
|
fatal("cvs_init_create_file: open failed: %s", |
|
strerror(errno)); |
|
|
|
(void)close(fd); |
if ((fd = open(path, openflags, 0444)) == -1) |
|
fatal("init_mkfile: open: `%s': %s", path, strerror(errno)); |
|
|
strlcat(path, RCS_FILE_EXT, sizeof(path)); |
if (content != NULL) { |
rfp = rcs_open(path, RCS_WRITE|RCS_CREATE, 0640); |
for (p = content; *p != NULL; ++p) { |
if (rfp == NULL) |
len = strlen(*p); |
return; |
b = cvs_buf_alloc(len, BUF_AUTOEXT); |
|
|
rcs_close(rfp); |
if (cvs_buf_append(b, *p, strlen(*p)) < 0) |
|
fatal("init_mkfile: cvs_buf_append"); |
|
|
|
if (cvs_buf_write_fd(b, fd) < 0) |
|
fatal("init_mkfile: cvs_buf_write_fd"); |
|
|
|
cvs_buf_free(b); |
} |
} |
} |
} |
|
|
|
/* |
|
* Make sure history and val-tags files are world-writable. |
|
* Every user should be able to write to them. |
|
*/ |
|
if (strcmp(strrchr(CVS_PATH_HISTORY, '/'), strrchr(path, '/')) == 0 || |
|
strcmp(strrchr(CVS_PATH_VALTAGS, '/'), strrchr(path, '/')) == 0) { |
|
(void)fchmod(fd, 0666); |
|
goto out; |
|
} |
|
|
|
rpath = xstrdup(path); |
|
if (strlcat(rpath, RCS_FILE_EXT, MAXPATHLEN) >= MAXPATHLEN) |
|
fatal("init_mkfile: truncation"); |
|
|
|
if ((file = rcs_open(rpath, fd, rcsflags, 0444)) == NULL) |
|
fatal("failed to create RCS file for `%s'", path); |
|
|
|
if ((b = cvs_buf_load(path, BUF_AUTOEXT)) == NULL) |
|
fatal("init_mkfile: failed to load %s", path); |
|
|
|
cvs_buf_putc(b, '\0'); |
|
d = cvs_buf_release(b); |
|
|
|
if (rcs_rev_add(file, RCS_HEAD_REV, "initial checkin", -1, NULL) == -1) |
|
fatal("init_mkfile: failed to add new revision"); |
|
|
|
if (rcs_deltatext_set(file, file->rf_head, d) == -1) |
|
fatal("init_mkfile: failed to set delta"); |
|
|
|
file->rf_flags &= ~RCS_SYNCED; |
|
rcs_close(file); |
|
xfree(rpath); |
|
out: |
|
(void)close(fd); |
|
|
|
if (d != NULL) |
|
xfree(d); |
} |
} |