1*4dcde513Sjoris /* $OpenBSD: root.c,v 1.49 2017/06/01 08:08:24 joris Exp $ */
26c121f58Sjfb /*
36c121f58Sjfb * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
46c121f58Sjfb * All rights reserved.
56c121f58Sjfb *
66c121f58Sjfb * Redistribution and use in source and binary forms, with or without
76c121f58Sjfb * modification, are permitted provided that the following conditions
86c121f58Sjfb * are met:
96c121f58Sjfb *
106c121f58Sjfb * 1. Redistributions of source code must retain the above copyright
116c121f58Sjfb * notice, this list of conditions and the following disclaimer.
126c121f58Sjfb * 2. The name of the author may not be used to endorse or promote products
136c121f58Sjfb * derived from this software without specific prior written permission.
146c121f58Sjfb *
156c121f58Sjfb * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
166c121f58Sjfb * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
176c121f58Sjfb * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
186c121f58Sjfb * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
196c121f58Sjfb * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
206c121f58Sjfb * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
216c121f58Sjfb * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
226c121f58Sjfb * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
236c121f58Sjfb * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
246c121f58Sjfb * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
256c121f58Sjfb */
266c121f58Sjfb
271f8531bdSotto #include <errno.h>
281f8531bdSotto #include <stdlib.h>
291f8531bdSotto #include <string.h>
306c121f58Sjfb
316c121f58Sjfb #include "cvs.h"
326c121f58Sjfb
336c121f58Sjfb extern char *cvs_rootstr;
346c121f58Sjfb
356c121f58Sjfb /* keep these ordered with the defines */
366c121f58Sjfb const char *cvs_methods[] = {
376c121f58Sjfb "",
386c121f58Sjfb "local",
396c121f58Sjfb "ssh",
406c121f58Sjfb "pserver",
416c121f58Sjfb "kserver",
426c121f58Sjfb "gserver",
436c121f58Sjfb "ext",
446c121f58Sjfb "fork",
456c121f58Sjfb };
466c121f58Sjfb
476c121f58Sjfb #define CVS_NBMETHODS (sizeof(cvs_methods)/sizeof(cvs_methods[0]))
486c121f58Sjfb
497f530f5cSjfb /*
506c121f58Sjfb * cvsroot_parse()
516c121f58Sjfb *
526c121f58Sjfb * Parse a CVS root string (as found in CVS/Root files or the CVSROOT
536c121f58Sjfb * environment variable) and store the fields in a dynamically
546c121f58Sjfb * allocated cvs_root structure. The format of the string is as follows:
55023558c8Sxsa * [:method:][[user[:pass]@]host[:port]:]path
566c121f58Sjfb * Returns a pointer to the allocated information on success, or NULL
576c121f58Sjfb * on failure.
586c121f58Sjfb */
59babed5a8Sjoris static struct cvsroot *
cvsroot_parse(const char * str)606c121f58Sjfb cvsroot_parse(const char *str)
616c121f58Sjfb {
626c121f58Sjfb u_int i;
636c121f58Sjfb char *cp, *sp, *pp;
64ec4a7e96Sxsa const char *errstr;
65babed5a8Sjoris static struct cvsroot *root = NULL;
666c121f58Sjfb
67babed5a8Sjoris if (root != NULL)
68dd10a000Sjoris return (root);
697f530f5cSjfb
703b4c5c25Sray root = xcalloc(1, sizeof(*root));
716c121f58Sjfb root->cr_method = CVS_METHOD_NONE;
720450b43bSjoris root->cr_str = xstrdup(str);
730450b43bSjoris root->cr_buf = xstrdup(str);
746c121f58Sjfb
756c121f58Sjfb sp = root->cr_buf;
766c121f58Sjfb cp = root->cr_buf;
776c121f58Sjfb if (*sp == ':') {
786c121f58Sjfb sp++;
79296ae42bSxsa if ((cp = strchr(sp, ':')) == NULL)
80296ae42bSxsa fatal("failed to parse CVSROOT: unterminated method");
81296ae42bSxsa
826c121f58Sjfb *(cp++) = '\0';
836c121f58Sjfb
846c121f58Sjfb for (i = 0; i < CVS_NBMETHODS; i++) {
856c121f58Sjfb if (strcmp(sp, cvs_methods[i]) == 0) {
866c121f58Sjfb root->cr_method = i;
876c121f58Sjfb break;
886c121f58Sjfb }
896c121f58Sjfb }
90296ae42bSxsa if (i == CVS_NBMETHODS)
91296ae42bSxsa fatal("cvsroot_parse: unknown method `%s'", sp);
926c121f58Sjfb }
936c121f58Sjfb
946c121f58Sjfb /* find the start of the actual path */
95296ae42bSxsa if ((sp = strchr(cp, '/')) == NULL)
96296ae42bSxsa fatal("no path specification in CVSROOT");
976c121f58Sjfb
986c121f58Sjfb root->cr_dir = sp;
993ad3fb45Sjoris STRIP_SLASH(root->cr_dir);
1006c121f58Sjfb if (sp == cp) {
1016c121f58Sjfb if (root->cr_method == CVS_METHOD_NONE)
1026c121f58Sjfb root->cr_method = CVS_METHOD_LOCAL;
1036c121f58Sjfb /* stop here, it's just a path */
1046c121f58Sjfb return (root);
1056c121f58Sjfb }
1066c121f58Sjfb
107296ae42bSxsa if (*(sp - 1) != ':')
108296ae42bSxsa fatal("missing host/path delimiter in CVSROOT");
109296ae42bSxsa
1106c121f58Sjfb *(sp - 1) = '\0';
1116c121f58Sjfb
1126c121f58Sjfb /*
1136c121f58Sjfb * looks like we have more than just a directory path, so
1146c121f58Sjfb * attempt to split it into user and host parts
1156c121f58Sjfb */
1166c121f58Sjfb sp = strchr(cp, '@');
1176c121f58Sjfb if (sp != NULL) {
1186c121f58Sjfb *(sp++) = '\0';
1196c121f58Sjfb
1206c121f58Sjfb /* password ? */
1216c121f58Sjfb pp = strchr(cp, ':');
1226c121f58Sjfb if (pp != NULL) {
1236c121f58Sjfb *(pp++) = '\0';
1246c121f58Sjfb root->cr_pass = pp;
1256c121f58Sjfb }
1266c121f58Sjfb
1276c121f58Sjfb root->cr_user = cp;
1283917c9bfSderaadt } else
1299c4cd84fSjfb sp = cp;
1306c121f58Sjfb
1316c121f58Sjfb pp = strchr(sp, ':');
1326c121f58Sjfb if (pp != NULL) {
1336c121f58Sjfb *(pp++) = '\0';
13447c33804Sjoris root->cr_port = strtonum(pp, 1, 65535, &errstr);
135ec4a7e96Sxsa if (errstr != NULL)
136ec4a7e96Sxsa fatal("port specification in CVSROOT is %s", errstr);
1376c121f58Sjfb
1386c121f58Sjfb }
1396c121f58Sjfb
1406c121f58Sjfb root->cr_host = sp;
1416c121f58Sjfb
1426c121f58Sjfb if (root->cr_method == CVS_METHOD_NONE) {
1436c121f58Sjfb /* no method found from start of CVSROOT, guess */
1446c121f58Sjfb if (root->cr_host != NULL)
1456c121f58Sjfb root->cr_method = CVS_METHOD_SERVER;
1466c121f58Sjfb else
1476c121f58Sjfb root->cr_method = CVS_METHOD_LOCAL;
1486c121f58Sjfb }
1496c121f58Sjfb
1506c121f58Sjfb return (root);
1516c121f58Sjfb }
1526c121f58Sjfb
153f367048cSjoris /*
1546c121f58Sjfb * cvsroot_get()
1556c121f58Sjfb *
1566c121f58Sjfb * Get the CVSROOT information for a specific directory <dir>. The
1576c121f58Sjfb * value is taken from one of 3 possible sources (in order of precedence):
1586c121f58Sjfb *
1596c121f58Sjfb * 1) the `-d' command-line option
1606c121f58Sjfb * 2) the CVS/Root file found in checked-out trees
1616c121f58Sjfb * 3) the CVSROOT environment variable
1626c121f58Sjfb */
1636c121f58Sjfb struct cvsroot *
cvsroot_get(const char * dir)1646c121f58Sjfb cvsroot_get(const char *dir)
1656c121f58Sjfb {
166b9fc9a72Sderaadt char rootpath[PATH_MAX], *rootstr, line[128];
1676c121f58Sjfb FILE *fp;
1686c121f58Sjfb
1696c121f58Sjfb if (cvs_rootstr != NULL)
1706c121f58Sjfb return cvsroot_parse(cvs_rootstr);
1716c121f58Sjfb
172b0d19690Stobias if (cvs_server_active == 1)
173b0d19690Stobias return cvsroot_parse(dir);
174b0d19690Stobias
1758fdeb7f5Snicm if (cvs_cmdop == CVS_OP_IMPORT) {
1768fdeb7f5Snicm if ((rootstr = getenv("CVSROOT")) != NULL)
1778fdeb7f5Snicm return (cvsroot_parse(rootstr));
1788fdeb7f5Snicm return (NULL);
1798fdeb7f5Snicm }
1802048ee2eStobias
181b9fc9a72Sderaadt (void)xsnprintf(rootpath, PATH_MAX, "%s/%s", dir, CVS_PATH_ROOTSPEC);
18227b85f85Sxsa
183296ae42bSxsa if ((fp = fopen(rootpath, "r")) == NULL) {
1846c121f58Sjfb if (errno == ENOENT) {
1856c121f58Sjfb /* try env as a last resort */
1866c121f58Sjfb if ((rootstr = getenv("CVSROOT")) != NULL)
1876c121f58Sjfb return cvsroot_parse(rootstr);
1886c121f58Sjfb else
1893ad3fb45Sjoris return (NULL);
1903917c9bfSderaadt } else {
191296ae42bSxsa fatal("cvsroot_get: fopen: `%s': %s",
192296ae42bSxsa CVS_PATH_ROOTSPEC, strerror(errno));
1936c121f58Sjfb }
1946c121f58Sjfb }
1956c121f58Sjfb
196296ae42bSxsa if (fgets(line, (int)sizeof(line), fp) == NULL)
197296ae42bSxsa fatal("cvsroot_get: fgets: `%s'", CVS_PATH_ROOTSPEC);
198296ae42bSxsa
1996c121f58Sjfb (void)fclose(fp);
2006c121f58Sjfb
201b625fa02Sgilles line[strcspn(line, "\n")] = '\0';
202b625fa02Sgilles if (line[0] == '\0')
2033ad3fb45Sjoris cvs_log(LP_ERR, "empty %s file", CVS_PATH_ROOTSPEC);
204a6f992bdSjfb
205a6f992bdSjfb return cvsroot_parse(line);
2066c121f58Sjfb }
207*4dcde513Sjoris
208*4dcde513Sjoris int
cvsroot_is_local(void)209*4dcde513Sjoris cvsroot_is_local(void)
210*4dcde513Sjoris {
211*4dcde513Sjoris if (current_cvsroot == NULL)
212*4dcde513Sjoris fatal("cvsroot_is_local: no CVSROOT");
213*4dcde513Sjoris
214*4dcde513Sjoris return (current_cvsroot->cr_method == CVS_METHOD_LOCAL);
215*4dcde513Sjoris }
216*4dcde513Sjoris
217*4dcde513Sjoris int
cvsroot_is_remote(void)218*4dcde513Sjoris cvsroot_is_remote(void)
219*4dcde513Sjoris {
220*4dcde513Sjoris if (current_cvsroot == NULL)
221*4dcde513Sjoris fatal("cvsroot_is_remote: no CVSROOT");
222*4dcde513Sjoris
223*4dcde513Sjoris return (current_cvsroot->cr_method != CVS_METHOD_LOCAL);
224*4dcde513Sjoris }
225