[BACK]Return to util.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / cvs

Annotation of src/usr.bin/cvs/util.c, Revision 1.24

1.24    ! joris       1: /*     $OpenBSD: util.c,v 1.23 2005/04/18 21:02:50 jfb Exp $   */
1.1       jfb         2: /*
                      3:  * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
1.9       jfb         4:  * All rights reserved.
1.1       jfb         5:  *
1.9       jfb         6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
1.1       jfb         9:  *
1.9       jfb        10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
1.1       jfb        12:  * 2. The name of the author may not be used to endorse or promote products
1.9       jfb        13:  *    derived from this software without specific prior written permission.
1.1       jfb        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
1.9       jfb        24:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1       jfb        25:  */
                     26:
                     27: #include <sys/types.h>
                     28: #include <sys/stat.h>
1.12      krapht     29: #include <sys/wait.h>
1.1       jfb        30:
                     31: #include <md5.h>
                     32: #include <errno.h>
1.2       jfb        33: #include <fcntl.h>
1.1       jfb        34: #include <stdio.h>
                     35: #include <stdlib.h>
                     36: #include <unistd.h>
                     37: #include <string.h>
                     38:
                     39: #include "cvs.h"
                     40: #include "log.h"
1.5       jfb        41: #include "file.h"
1.1       jfb        42:
1.9       jfb        43: static const char *cvs_months[] = {
                     44:        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                     45:        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
                     46: };
                     47:
1.1       jfb        48:
                     49: /* letter -> mode type map */
                     50: static const int cvs_modetypes[26] = {
                     51:        -1, -1, -1, -1, -1, -1,  1, -1, -1, -1, -1, -1, -1,
                     52:        -1,  2, -1, -1, -1, -1, -1,  0, -1, -1, -1, -1, -1,
                     53: };
                     54:
                     55: /* letter -> mode map */
                     56: static const mode_t cvs_modes[3][26] = {
                     57:        {
                     58:                0,  0,       0,       0,       0,  0,  0,    /* a - g */
                     59:                0,  0,       0,       0,       0,  0,  0,    /* h - m */
                     60:                0,  0,       0,       S_IRUSR, 0,  0,  0,    /* n - u */
                     61:                0,  S_IWUSR, S_IXUSR, 0,       0             /* v - z */
                     62:        },
                     63:        {
                     64:                0,  0,       0,       0,       0,  0,  0,    /* a - g */
                     65:                0,  0,       0,       0,       0,  0,  0,    /* h - m */
                     66:                0,  0,       0,       S_IRGRP, 0,  0,  0,    /* n - u */
                     67:                0,  S_IWGRP, S_IXGRP, 0,       0             /* v - z */
                     68:        },
                     69:        {
                     70:                0,  0,       0,       0,       0,  0,  0,    /* a - g */
                     71:                0,  0,       0,       0,       0,  0,  0,    /* h - m */
                     72:                0,  0,       0,       S_IROTH, 0,  0,  0,    /* n - u */
                     73:                0,  S_IWOTH, S_IXOTH, 0,       0             /* v - z */
                     74:        }
                     75: };
                     76:
                     77:
                     78: /* octal -> string */
                     79: static const char *cvs_modestr[8] = {
                     80:        "", "x", "w", "wx", "r", "rx", "rw", "rwx"
                     81: };
                     82:
                     83:
1.11      krapht     84: pid_t cvs_exec_pid;
                     85:
1.1       jfb        86:
                     87: /*
                     88:  * cvs_readrepo()
                     89:  *
                     90:  * Read the path stored in the `Repository' CVS file for a given directory
                     91:  * <dir>, and store that path into the buffer pointed to by <dst>, whose size
                     92:  * is <len>.
                     93:  */
                     94: int
                     95: cvs_readrepo(const char *dir, char *dst, size_t len)
                     96: {
1.21      xsa        97:        int l;
1.1       jfb        98:        size_t dlen;
                     99:        FILE *fp;
                    100:        char repo_path[MAXPATHLEN];
                    101:
1.21      xsa       102:        l = snprintf(repo_path, sizeof(repo_path), "%s/CVS/Repository", dir);
                    103:        if (l == -1 || l >= (int)sizeof(repo_path)) {
                    104:                errno = ENAMETOOLONG;
                    105:                cvs_log(LP_ERRNO, "%s", repo_path);
                    106:                return (NULL);
                    107:         }
                    108:
1.1       jfb       109:        fp = fopen(repo_path, "r");
1.21      xsa       110:        if (fp == NULL)
1.1       jfb       111:                return (-1);
                    112:
                    113:        if (fgets(dst, (int)len, fp) == NULL) {
                    114:                if (ferror(fp)) {
                    115:                        cvs_log(LP_ERRNO, "failed to read from `%s'",
                    116:                            repo_path);
                    117:                }
                    118:                (void)fclose(fp);
                    119:                return (-1);
                    120:        }
                    121:        dlen = strlen(dst);
                    122:        if ((dlen > 0) && (dst[dlen - 1] == '\n'))
                    123:                dst[--dlen] = '\0';
                    124:
                    125:        (void)fclose(fp);
                    126:        return (0);
                    127: }
                    128:
                    129:
                    130: /*
1.9       jfb       131:  * cvs_datesec()
                    132:  *
1.10      jfb       133:  * Take a date string and transform it into the number of seconds since the
                    134:  * Epoch.  The <type> argument specifies whether the timestamp is in ctime(3)
                    135:  * format or RFC 822 format (as CVS uses in its protocol).  If the <adj>
                    136:  * parameter is not 0, the returned time will be adjusted according to the
                    137:  * machine's local timezone.
1.9       jfb       138:  */
                    139: time_t
1.10      jfb       140: cvs_datesec(const char *date, int type, int adj)
1.9       jfb       141: {
                    142:        int i;
                    143:        long off;
                    144:        char sign, mon[8], gmt[8], hr[4], min[4], *ep;
                    145:        struct tm cvs_tm;
                    146:
                    147:        memset(&cvs_tm, 0, sizeof(cvs_tm));
                    148:        cvs_tm.tm_isdst = -1;
                    149:
1.10      jfb       150:        if (type == CVS_DATE_RFC822) {
                    151:                if (sscanf(date, "%d %3s %d %2d:%2d:%2d %5s", &cvs_tm.tm_mday,
                    152:                    mon, &cvs_tm.tm_year, &cvs_tm.tm_hour, &cvs_tm.tm_min,
                    153:                    &cvs_tm.tm_sec, gmt) < 7)
                    154:                        return (-1);
                    155:                cvs_tm.tm_year -= 1900;
1.9       jfb       156:
1.10      jfb       157:                if (*gmt == '-') {
                    158:                        sscanf(gmt, "%c%2s%2s", &sign, hr, min);
                    159:                        cvs_tm.tm_gmtoff = strtol(hr, &ep, 10);
1.9       jfb       160:                        if ((cvs_tm.tm_gmtoff == LONG_MIN) ||
                    161:                            (cvs_tm.tm_gmtoff == LONG_MAX) ||
                    162:                            (*ep != '\0')) {
                    163:                                cvs_log(LP_ERR,
1.10      jfb       164:                                    "parse error in GMT hours specification `%s'", hr);
                    165:                                cvs_tm.tm_gmtoff = 0;
1.15      deraadt   166:                        } else {
1.10      jfb       167:                                /* get seconds */
                    168:                                cvs_tm.tm_gmtoff *= 3600;
                    169:
                    170:                                /* add the minutes */
                    171:                                off = strtol(min, &ep, 10);
                    172:                                if ((cvs_tm.tm_gmtoff == LONG_MIN) ||
                    173:                                    (cvs_tm.tm_gmtoff == LONG_MAX) ||
                    174:                                    (*ep != '\0')) {
                    175:                                        cvs_log(LP_ERR,
                    176:                                            "parse error in GMT minutes "
                    177:                                            "specification `%s'", min);
1.15      deraadt   178:                                } else
1.10      jfb       179:                                        cvs_tm.tm_gmtoff += off * 60;
1.9       jfb       180:                        }
                    181:                }
1.10      jfb       182:                if (sign == '-')
                    183:                        cvs_tm.tm_gmtoff = -cvs_tm.tm_gmtoff;
1.15      deraadt   184:        } else if (type == CVS_DATE_CTIME) {
1.10      jfb       185:                /* gmt is used for the weekday */
                    186:                sscanf(date, "%3s %3s %d %2d:%2d:%2d %d", gmt, mon,
                    187:                    &cvs_tm.tm_mday, &cvs_tm.tm_hour, &cvs_tm.tm_min,
                    188:                    &cvs_tm.tm_sec, &cvs_tm.tm_year);
                    189:                cvs_tm.tm_year -= 1900;
1.18      tedu      190:                cvs_tm.tm_gmtoff = 0;
1.9       jfb       191:        }
                    192:
                    193:        for (i = 0; i < (int)(sizeof(cvs_months)/sizeof(cvs_months[0])); i++) {
                    194:                if (strcmp(cvs_months[i], mon) == 0) {
                    195:                        cvs_tm.tm_mon = i;
                    196:                        break;
                    197:                }
                    198:        }
                    199:
                    200:        return mktime(&cvs_tm);
                    201: }
                    202:
                    203:
                    204: /*
1.1       jfb       205:  * cvs_strtomode()
                    206:  *
                    207:  * Read the contents of the string <str> and generate a permission mode from
                    208:  * the contents of <str>, which is assumed to have the mode format of CVS.
                    209:  * The CVS protocol specification states that any modes or mode types that are
                    210:  * not recognized should be silently ignored.  This function does not return
                    211:  * an error in such cases, but will issue warnings.
                    212:  * Returns 0 on success, or -1 on failure.
                    213:  */
                    214: int
                    215: cvs_strtomode(const char *str, mode_t *mode)
                    216: {
1.2       jfb       217:        char type;
1.1       jfb       218:        mode_t m;
                    219:        char buf[32], ms[4], *sp, *ep;
                    220:
                    221:        m = 0;
                    222:        strlcpy(buf, str, sizeof(buf));
                    223:        sp = buf;
                    224:        ep = sp;
                    225:
                    226:        for (sp = buf; ep != NULL; sp = ep + 1) {
                    227:                ep = strchr(sp, ',');
                    228:                if (ep != NULL)
1.2       jfb       229:                        *ep = '\0';
1.1       jfb       230:
1.14      weingart  231:                memset(ms, 0, sizeof ms);
                    232:                if (sscanf(sp, "%c=%3s", &type, ms) != 2 &&
                    233:                        sscanf(sp, "%c=", &type) != 1) {
1.1       jfb       234:                        cvs_log(LP_WARN, "failed to scan mode string `%s'", sp);
                    235:                        continue;
                    236:                }
                    237:
                    238:                if ((type <= 'a') || (type >= 'z') ||
                    239:                    (cvs_modetypes[type - 'a'] == -1)) {
                    240:                        cvs_log(LP_WARN,
                    241:                            "invalid mode type `%c'"
                    242:                            " (`u', `g' or `o' expected), ignoring", type);
                    243:                        continue;
                    244:                }
                    245:
                    246:                /* make type contain the actual mode index */
                    247:                type = cvs_modetypes[type - 'a'];
                    248:
                    249:                for (sp = ms; *sp != '\0'; sp++) {
                    250:                        if ((*sp <= 'a') || (*sp >= 'z') ||
1.5       jfb       251:                            (cvs_modes[(int)type][*sp - 'a'] == 0)) {
1.1       jfb       252:                                cvs_log(LP_WARN,
                    253:                                    "invalid permission bit `%c'", *sp);
1.15      deraadt   254:                        } else
1.5       jfb       255:                                m |= cvs_modes[(int)type][*sp - 'a'];
1.1       jfb       256:                }
                    257:        }
                    258:
                    259:        *mode = m;
                    260:
                    261:        return (0);
                    262: }
                    263:
                    264:
                    265: /*
                    266:  * cvs_modetostr()
                    267:  *
                    268:  * Returns 0 on success, or -1 on failure.
                    269:  */
                    270: int
                    271: cvs_modetostr(mode_t mode, char *buf, size_t len)
                    272: {
                    273:        size_t l;
                    274:        char tmp[16], *bp;
                    275:        mode_t um, gm, om;
                    276:
                    277:        um = (mode & S_IRWXU) >> 6;
                    278:        gm = (mode & S_IRWXG) >> 3;
                    279:        om = mode & S_IRWXO;
                    280:
                    281:        bp = buf;
                    282:        *bp = '\0';
                    283:        l = 0;
                    284:
                    285:        if (um) {
                    286:                snprintf(tmp, sizeof(tmp), "u=%s", cvs_modestr[um]);
1.9       jfb       287:                l = strlcat(buf, tmp, len);
1.1       jfb       288:        }
                    289:        if (gm) {
                    290:                if (um)
                    291:                        strlcat(buf, ",", len);
                    292:                snprintf(tmp, sizeof(tmp), "g=%s", cvs_modestr[gm]);
1.9       jfb       293:                strlcat(buf, tmp, len);
1.1       jfb       294:        }
                    295:        if (om) {
                    296:                if (um || gm)
                    297:                        strlcat(buf, ",", len);
                    298:                snprintf(tmp, sizeof(tmp), "o=%s", cvs_modestr[gm]);
1.9       jfb       299:                strlcat(buf, tmp, len);
1.1       jfb       300:        }
                    301:
                    302:        return (0);
                    303: }
                    304:
                    305:
                    306: /*
                    307:  * cvs_cksum()
                    308:  *
                    309:  * Calculate the MD5 checksum of the file whose path is <file> and generate
                    310:  * a CVS-format 32 hex-digit string, which is stored in <dst>, whose size is
                    311:  * given in <len> and must be at least 33.
                    312:  * Returns 0 on success, or -1 on failure.
                    313:  */
                    314: int
                    315: cvs_cksum(const char *file, char *dst, size_t len)
                    316: {
                    317:        if (len < CVS_CKSUM_LEN) {
                    318:                cvs_log(LP_WARN, "buffer too small for checksum");
                    319:                return (-1);
                    320:        }
                    321:        if (MD5File(file, dst) == NULL) {
1.19      jfb       322:                cvs_log(LP_ERRNO, "failed to generate checksum for %s", file);
1.1       jfb       323:                return (-1);
                    324:        }
                    325:
                    326:        return (0);
                    327: }
                    328:
                    329:
                    330: /*
                    331:  * cvs_splitpath()
                    332:  *
1.7       jfb       333:  * Split a path <path> into the base portion and the filename portion.
                    334:  * The path is copied in <base> and the last delimiter is replaced by a NUL
                    335:  * byte.  The <file> pointer is set to point to the first character after
                    336:  * that delimiter.
1.1       jfb       337:  * Returns 0 on success, or -1 on failure.
                    338:  */
                    339: int
1.7       jfb       340: cvs_splitpath(const char *path, char *base, size_t blen, char **file)
1.1       jfb       341: {
                    342:        size_t rlen;
1.7       jfb       343:        char *sp;
1.1       jfb       344:
1.7       jfb       345:        if ((rlen = strlcpy(base, path, blen)) >= blen)
                    346:                return (-1);
1.6       jfb       347:
1.7       jfb       348:        while ((rlen > 0) && (base[rlen - 1] == '/'))
                    349:                base[--rlen] = '\0';
                    350:
                    351:        sp = strrchr(base, '/');
1.1       jfb       352:        if (sp == NULL) {
1.7       jfb       353:                strlcpy(base, "./", blen);
                    354:                strlcat(base, path, blen);
                    355:                sp = base + 1;
1.1       jfb       356:        }
                    357:
1.7       jfb       358:        *sp = '\0';
                    359:        if (file != NULL)
                    360:                *file = sp + 1;
1.1       jfb       361:
                    362:        return (0);
                    363: }
                    364:
                    365:
                    366: /*
                    367:  * cvs_getargv()
                    368:  *
                    369:  * Parse a line contained in <line> and generate an argument vector by
                    370:  * splitting the line on spaces and tabs.  The resulting vector is stored in
                    371:  * <argv>, which can accept up to <argvlen> entries.
1.20      david     372:  * Returns the number of arguments in the vector, or -1 if an error occurred.
1.1       jfb       373:  */
                    374: int
                    375: cvs_getargv(const char *line, char **argv, int argvlen)
                    376: {
                    377:        u_int i;
                    378:        int argc, err;
                    379:        char linebuf[256], qbuf[128], *lp, *cp, *arg;
                    380:
                    381:        strlcpy(linebuf, line, sizeof(linebuf));
                    382:        memset(argv, 0, sizeof(argv));
                    383:        argc = 0;
                    384:
                    385:        /* build the argument vector */
                    386:        err = 0;
                    387:        for (lp = linebuf; lp != NULL;) {
                    388:                if (*lp == '"') {
                    389:                        /* double-quoted string */
                    390:                        lp++;
                    391:                        i = 0;
                    392:                        memset(qbuf, 0, sizeof(qbuf));
                    393:                        while (*lp != '"') {
1.16      jfb       394:                                if (*lp == '\\')
                    395:                                        lp++;
1.1       jfb       396:                                if (*lp == '\0') {
                    397:                                        cvs_log(LP_ERR, "no terminating quote");
                    398:                                        err++;
                    399:                                        break;
1.16      jfb       400:                                }
1.1       jfb       401:
1.9       jfb       402:                                qbuf[i++] = *lp++;
1.1       jfb       403:                                if (i == sizeof(qbuf)) {
                    404:                                        err++;
                    405:                                        break;
                    406:                                }
                    407:                        }
                    408:
                    409:                        arg = qbuf;
1.15      deraadt   410:                } else {
1.1       jfb       411:                        cp = strsep(&lp, " \t");
                    412:                        if (cp == NULL)
                    413:                                break;
                    414:                        else if (*cp == '\0')
                    415:                                continue;
                    416:
                    417:                        arg = cp;
                    418:                }
                    419:
1.16      jfb       420:                if (argc == argvlen) {
                    421:                        err++;
                    422:                        break;
                    423:                }
                    424:
1.1       jfb       425:                argv[argc] = strdup(arg);
                    426:                if (argv[argc] == NULL) {
                    427:                        cvs_log(LP_ERRNO, "failed to copy argument");
                    428:                        err++;
                    429:                        break;
                    430:                }
                    431:                argc++;
                    432:        }
                    433:
                    434:        if (err) {
                    435:                /* ditch the argument vector */
                    436:                for (i = 0; i < (u_int)argc; i++)
                    437:                        free(argv[i]);
                    438:                argc = -1;
                    439:        }
                    440:
                    441:        return (argc);
1.17      jfb       442: }
                    443:
                    444:
                    445: /*
                    446:  * cvs_makeargv()
                    447:  *
1.20      david     448:  * Allocate an argument vector large enough to accommodate for all the
1.17      jfb       449:  * arguments found in <line> and return it.
                    450:  */
                    451:
                    452: char**
                    453: cvs_makeargv(const char *line, int *argc)
                    454: {
                    455:        int i, ret;
                    456:        char *argv[1024], **copy;
                    457:
                    458:        ret = cvs_getargv(line, argv, 1024);
                    459:        if (ret == -1)
                    460:                return (NULL);
                    461:
                    462:        copy = (char **)malloc((ret + 1) * sizeof(char *));
                    463:        if (copy == NULL) {
                    464:                cvs_log(LP_ERRNO, "failed to allocate argument vector");
                    465:                return (NULL);
                    466:        }
                    467:        memset(copy, 0, sizeof(copy));
                    468:
                    469:        for (i = 0; i < ret; i++)
                    470:                copy[i] = argv[i];
                    471:        copy[ret] = NULL;
                    472:
                    473:        *argc = ret;
                    474:        return (copy);
1.1       jfb       475: }
                    476:
                    477:
                    478: /*
                    479:  * cvs_freeargv()
                    480:  *
                    481:  * Free an argument vector previously generated by cvs_getargv().
                    482:  */
                    483: void
                    484: cvs_freeargv(char **argv, int argc)
                    485: {
                    486:        int i;
                    487:
                    488:        for (i = 0; i < argc; i++)
1.16      jfb       489:                if (argv[i] != NULL)
                    490:                        free(argv[i]);
1.2       jfb       491: }
                    492:
                    493:
                    494: /*
                    495:  * cvs_mkadmin()
                    496:  *
1.5       jfb       497:  * Create the CVS administrative files within the directory <cdir>.  If the
                    498:  * files already exist, they are kept as is.
1.2       jfb       499:  * Returns 0 on success, or -1 on failure.
                    500:  */
                    501: int
1.13      jfb       502: cvs_mkadmin(CVSFILE *cdir, mode_t mode)
1.2       jfb       503: {
1.21      xsa       504:        int l;
1.13      jfb       505:        char dpath[MAXPATHLEN], path[MAXPATHLEN];
1.2       jfb       506:        FILE *fp;
                    507:        CVSENTRIES *ef;
1.5       jfb       508:        struct stat st;
1.2       jfb       509:        struct cvsroot *root;
                    510:
1.13      jfb       511:        cvs_file_getpath(cdir, dpath, sizeof(dpath));
                    512:
1.21      xsa       513:        l = snprintf(path, sizeof(path), "%s/" CVS_PATH_CVSDIR, dpath);
                    514:        if (l == -1 || l >= (int)sizeof(path)) {
                    515:                errno = ENAMETOOLONG;
                    516:                cvs_log(LP_ERRNO, "%s", path);
                    517:                return (-1);
                    518:        }
                    519:
1.5       jfb       520:        if ((mkdir(path, mode) == -1) && (errno != EEXIST)) {
1.2       jfb       521:                cvs_log(LP_ERRNO, "failed to create directory %s", path);
                    522:                return (-1);
                    523:        }
                    524:
1.5       jfb       525:        /* just create an empty Entries file */
1.13      jfb       526:        ef = cvs_ent_open(dpath, O_WRONLY);
1.2       jfb       527:        (void)cvs_ent_close(ef);
                    528:
1.23      jfb       529:        root = cdir->cf_root;
1.21      xsa       530:        l = snprintf(path, sizeof(path), "%s/" CVS_PATH_ROOTSPEC, dpath);
                    531:        if (l == -1 || l >= (int)sizeof(path)) {
                    532:                errno = ENAMETOOLONG;
                    533:                cvs_log(LP_ERRNO, "%s", path);
                    534:                return (-1);
                    535:        }
                    536:
1.8       jfb       537:        if ((root != NULL) && (stat(path, &st) != 0) && (errno == ENOENT)) {
1.5       jfb       538:                fp = fopen(path, "w");
                    539:                if (fp == NULL) {
                    540:                        cvs_log(LP_ERRNO, "failed to open %s", path);
                    541:                        return (-1);
                    542:                }
                    543:                if (root->cr_user != NULL) {
                    544:                        fprintf(fp, "%s", root->cr_user);
                    545:                        if (root->cr_pass != NULL)
                    546:                                fprintf(fp, ":%s", root->cr_pass);
                    547:                        if (root->cr_host != NULL)
                    548:                                putc('@', fp);
                    549:                }
                    550:
                    551:                if (root->cr_host != NULL) {
                    552:                        fprintf(fp, "%s", root->cr_host);
                    553:                        if (root->cr_dir != NULL)
                    554:                                putc(':', fp);
                    555:                }
                    556:                if (root->cr_dir)
                    557:                        fprintf(fp, "%s", root->cr_dir);
                    558:                putc('\n', fp);
                    559:                (void)fclose(fp);
1.2       jfb       560:        }
                    561:
1.22      xsa       562:        l = snprintf(path, sizeof(path), "%s/" CVS_PATH_REPOSITORY, dpath);
1.21      xsa       563:        if (l == -1 || l >= (int)sizeof(path)) {
                    564:                errno = ENAMETOOLONG;
                    565:                cvs_log(LP_ERRNO, "%s", path);
                    566:                return (-1);
                    567:        }
                    568:
1.5       jfb       569:        if ((stat(path, &st) != 0) && (errno == ENOENT) &&
1.23      jfb       570:            (cdir->cf_repo != NULL)) {
1.2       jfb       571:                fp = fopen(path, "w");
                    572:                if (fp == NULL) {
                    573:                        cvs_log(LP_ERRNO, "failed to open %s", path);
                    574:                        return (-1);
                    575:                }
1.23      jfb       576:                fprintf(fp, "%s\n", cdir->cf_repo);
1.2       jfb       577:                (void)fclose(fp);
                    578:        }
                    579:
                    580:        return (0);
1.11      krapht    581: }
                    582:
                    583:
                    584: /*
                    585:  * cvs_exec()
                    586:  */
                    587: int
                    588: cvs_exec(int argc, char **argv, int fds[3])
                    589: {
                    590:        int ret;
                    591:        pid_t pid;
                    592:
                    593:        if ((pid = fork()) == -1) {
                    594:                cvs_log(LP_ERRNO, "failed to fork");
                    595:                return (-1);
                    596:        } else if (pid == 0) {
                    597:                execvp(argv[0], argv);
1.13      jfb       598:                cvs_log(LP_ERRNO, "failed to exec %s", argv[0]);
                    599:                exit(1);
1.11      krapht    600:        }
                    601:
                    602:        if (waitpid(pid, &ret, 0) == -1)
1.13      jfb       603:                cvs_log(LP_ERRNO, "failed to waitpid");
1.11      krapht    604:
                    605:        return (ret);
1.1       jfb       606: }
1.24    ! joris     607:
        !           608: /*
        !           609:  * remove a directory tree from disk.
        !           610:  */
        !           611: int
        !           612: cvs_remove_dir(const char *path)
        !           613: {
        !           614:        int l, ret;
        !           615:        DIR *dirp;
        !           616:        struct dirent *ent;
        !           617:        char fpath[MAXPATHLEN];
        !           618:
        !           619:        if ((dirp = opendir(path)) == NULL) {
        !           620:                cvs_log(LP_ERRNO, "failed to open '%s'", path);
        !           621:                return (CVS_EX_FILE);
        !           622:        }
        !           623:
        !           624:        while ((ent = readdir(dirp)) != NULL) {
        !           625:                if (!strcmp(ent->d_name, ".") ||
        !           626:                    !strcmp(ent->d_name, ".."))
        !           627:                        continue;
        !           628:
        !           629:                l = snprintf(fpath, sizeof(fpath), "%s/%s", path, ent->d_name);
        !           630:                if (l == -1 || l >= (int)sizeof(fpath)) {
        !           631:                        errno = ENAMETOOLONG;
        !           632:                        cvs_log(LP_ERRNO, "%s", fpath);
        !           633:                        closedir(dirp);
        !           634:                        return (CVS_EX_FILE);
        !           635:                }
        !           636:
        !           637:                if (ent->d_type == DT_DIR) {
        !           638:                        if ((ret = cvs_remove_dir(fpath)) != CVS_EX_OK) {
        !           639:                                closedir(dirp);
        !           640:                                return (ret);
        !           641:                        }
        !           642:                } else {
        !           643:                        if ((unlink(fpath) == -1) && (errno != ENOENT))
        !           644:                                cvs_log(LP_ERRNO, "failed to remove '%s'",
        !           645:                                    fpath);
        !           646:                }
        !           647:        }
        !           648:
        !           649:        closedir(dirp);
        !           650:
        !           651:        if ((rmdir(path) == -1) && (errno != ENOENT))
        !           652:                cvs_log(LP_ERRNO, "failed to remove '%s'", path);
        !           653:
        !           654:        return (CVS_EX_OK);
        !           655: }
        !           656: