Annotation of src/usr.bin/cvs/root.c, Revision 1.1
1.1 ! jfb 1: /* $OpenBSD$ */
! 2: /*
! 3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: *
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. The name of the author may not be used to endorse or promote products
! 13: * derived from this software without specific prior written permission.
! 14: *
! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
! 16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
! 17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
! 18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
! 21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! 22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
! 23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! 24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 25: */
! 26:
! 27: #include <sys/types.h>
! 28:
! 29: #include <stdlib.h>
! 30: #include <stdio.h>
! 31: #include <unistd.h>
! 32: #include <err.h>
! 33: #include <errno.h>
! 34: #include <string.h>
! 35: #include <paths.h>
! 36:
! 37: #include "cvs.h"
! 38: #include "log.h"
! 39:
! 40:
! 41: extern char *cvs_rootstr;
! 42:
! 43:
! 44: /* keep these ordered with the defines */
! 45: const char *cvs_methods[] = {
! 46: "",
! 47: "local",
! 48: "ssh",
! 49: "pserver",
! 50: "kserver",
! 51: "gserver",
! 52: "ext",
! 53: "fork",
! 54: };
! 55:
! 56: #define CVS_NBMETHODS (sizeof(cvs_methods)/sizeof(cvs_methods[0]))
! 57:
! 58:
! 59:
! 60: /*
! 61: * cvsroot_parse()
! 62: *
! 63: * Parse a CVS root string (as found in CVS/Root files or the CVSROOT
! 64: * environment variable) and store the fields in a dynamically
! 65: * allocated cvs_root structure. The format of the string is as follows:
! 66: * :method:path
! 67: * Returns a pointer to the allocated information on success, or NULL
! 68: * on failure.
! 69: */
! 70:
! 71: struct cvsroot*
! 72: cvsroot_parse(const char *str)
! 73: {
! 74: u_int i;
! 75: char *cp, *sp, *pp;
! 76: struct cvsroot *root;
! 77:
! 78: root = (struct cvsroot *)malloc(sizeof(*root));
! 79: if (root == NULL) {
! 80: cvs_log(LP_ERRNO, "failed to allocate CVS root data");
! 81: return (NULL);
! 82: }
! 83:
! 84: root->cr_method = CVS_METHOD_NONE;
! 85:
! 86: root->cr_buf = strdup(str);
! 87: if (root->cr_buf == NULL) {
! 88: cvs_log(LP_ERRNO, "failed to copy CVS root");
! 89: free(root);
! 90: return (NULL);
! 91: }
! 92:
! 93: sp = root->cr_buf;
! 94: cp = root->cr_buf;
! 95:
! 96: if (*sp == ':') {
! 97: sp++;
! 98: cp = strchr(sp, ':');
! 99: if (cp == NULL) {
! 100: cvs_log(LP_ERR, "failed to parse CVSROOT: "
! 101: "unterminated method");
! 102: free(root->cr_buf);
! 103: free(root);
! 104: return (NULL);
! 105: }
! 106: *(cp++) = '\0';
! 107:
! 108: for (i = 0; i < CVS_NBMETHODS; i++) {
! 109: if (strcmp(sp, cvs_methods[i]) == 0) {
! 110: root->cr_method = i;
! 111: break;
! 112: }
! 113: }
! 114: }
! 115:
! 116: /* find the start of the actual path */
! 117: sp = strchr(cp, '/');
! 118: if (sp == NULL) {
! 119: cvs_log(LP_ERR, "no path specification in CVSROOT");
! 120: free(root->cr_buf);
! 121: free(root);
! 122: return (NULL);
! 123: }
! 124:
! 125: root->cr_dir = sp;
! 126: if (sp == cp) {
! 127: if (root->cr_method == CVS_METHOD_NONE)
! 128: root->cr_method = CVS_METHOD_LOCAL;
! 129: /* stop here, it's just a path */
! 130: return (root);
! 131: }
! 132:
! 133: if (*(sp - 1) != ':') {
! 134: cvs_log(LP_ERR, "missing host/path delimiter in CVS root");
! 135: free(root);
! 136: return (NULL);
! 137: }
! 138: *(sp - 1) = '\0';
! 139:
! 140: /*
! 141: * looks like we have more than just a directory path, so
! 142: * attempt to split it into user and host parts
! 143: */
! 144: sp = strchr(cp, '@');
! 145: if (sp != NULL) {
! 146: *(sp++) = '\0';
! 147:
! 148: /* password ? */
! 149: pp = strchr(cp, ':');
! 150: if (pp != NULL) {
! 151: *(pp++) = '\0';
! 152: root->cr_pass = pp;
! 153: }
! 154:
! 155: root->cr_user = cp;
! 156: }
! 157:
! 158: pp = strchr(sp, ':');
! 159: if (pp != NULL) {
! 160: *(pp++) = '\0';
! 161: root->cr_port = (u_int)strtol(pp, &cp, 10);
! 162: if (*cp != '\0' || root->cr_port > 65535) {
! 163: cvs_log(LP_ERR,
! 164: "invalid port specification in CVSROOT");
! 165: free(root);
! 166: return (NULL);
! 167: }
! 168:
! 169: }
! 170:
! 171: root->cr_host = sp;
! 172:
! 173: if (root->cr_method == CVS_METHOD_NONE) {
! 174: /* no method found from start of CVSROOT, guess */
! 175: if (root->cr_host != NULL)
! 176: root->cr_method = CVS_METHOD_SERVER;
! 177: else
! 178: root->cr_method = CVS_METHOD_LOCAL;
! 179: }
! 180:
! 181: return (root);
! 182: }
! 183:
! 184:
! 185: /*
! 186: * cvsroot_free()
! 187: *
! 188: * Free a CVSROOT structure previously allocated and returned by
! 189: * cvsroot_parse().
! 190: */
! 191:
! 192: void
! 193: cvsroot_free(struct cvsroot *root)
! 194: {
! 195: free(root->cr_buf);
! 196: free(root);
! 197: }
! 198:
! 199:
! 200: /*
! 201: * cvsroot_get()
! 202: *
! 203: * Get the CVSROOT information for a specific directory <dir>. The
! 204: * value is taken from one of 3 possible sources (in order of precedence):
! 205: *
! 206: * 1) the `-d' command-line option
! 207: * 2) the CVS/Root file found in checked-out trees
! 208: * 3) the CVSROOT environment variable
! 209: */
! 210:
! 211: struct cvsroot*
! 212: cvsroot_get(const char *dir)
! 213: {
! 214: size_t len;
! 215: char rootpath[MAXPATHLEN], *rootstr, *line;
! 216: FILE *fp;
! 217: struct cvsroot *rp;
! 218:
! 219: if (cvs_rootstr != NULL)
! 220: return cvsroot_parse(cvs_rootstr);
! 221:
! 222: snprintf(rootpath, sizeof(rootpath), "%s/" CVS_PATH_ROOTSPEC, dir);
! 223: fp = fopen(rootpath, "r");
! 224: if (fp == NULL) {
! 225: if (errno == ENOENT) {
! 226: /* try env as a last resort */
! 227: if ((rootstr = getenv("CVSROOT")) != NULL)
! 228: return cvsroot_parse(rootstr);
! 229: else
! 230: return (NULL);
! 231: }
! 232: else {
! 233: cvs_log(LP_ERRNO, "failed to open CVS/Root");
! 234: return (NULL);
! 235: }
! 236: }
! 237:
! 238: line = fgetln(fp, &len);
! 239: if (line == NULL) {
! 240: cvs_log(LP_ERR, "failed to read CVSROOT line from CVS/Root");
! 241: (void)fclose(fp);
! 242: }
! 243:
! 244: /* line is not NUL-terminated, but we don't need to allocate an
! 245: * extra byte because we don't want the trailing newline. It will
! 246: * get replaced by a \0.
! 247: */
! 248: rootstr = (char *)malloc(len);
! 249: if (rootstr == NULL) {
! 250: cvs_log(LP_ERRNO, "failed to allocate CVSROOT string");
! 251: (void)fclose(fp);
! 252: return (NULL);
! 253: }
! 254: strlcpy(rootstr, line, len);
! 255: rp = cvsroot_parse(rootstr);
! 256:
! 257: (void)fclose(fp);
! 258: free(rootstr);
! 259:
! 260: return (rp);
! 261: }