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

Annotation of src/usr.bin/cvs/cvs.c, Revision 1.18

1.18    ! tedu        1: /*     $OpenBSD: cvs.c,v 1.17 2004/12/07 06:33:10 jfb Exp $    */
1.1       jfb         2: /*
                      3:  * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
1.18    ! tedu        4:  * All rights reserved.
1.1       jfb         5:  *
1.18    ! tedu        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.18    ! tedu       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.18    ! tedu       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.18    ! tedu       24:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1       jfb        25:  */
                     26:
                     27: #include <sys/types.h>
                     28: #include <sys/wait.h>
                     29:
                     30: #include <err.h>
                     31: #include <pwd.h>
                     32: #include <errno.h>
                     33: #include <stdio.h>
                     34: #include <stdlib.h>
                     35: #include <unistd.h>
                     36: #include <signal.h>
                     37: #include <string.h>
                     38: #include <sysexits.h>
                     39:
                     40: #include "cvs.h"
                     41: #include "log.h"
1.8       jfb        42: #include "file.h"
1.1       jfb        43:
                     44:
                     45: extern char *__progname;
                     46:
                     47:
                     48: /* verbosity level: 0 = really quiet, 1 = quiet, 2 = verbose */
                     49: int verbosity = 2;
                     50:
                     51: /* compression level used with zlib, 0 meaning no compression taking place */
                     52: int   cvs_compress = 0;
1.17      jfb        53: int   cvs_readrc = 1;          /* read .cvsrc on startup */
1.1       jfb        54: int   cvs_trace = 0;
                     55: int   cvs_nolog = 0;
                     56: int   cvs_readonly = 0;
1.17      jfb        57: int   cvs_nocase = 0;   /* set to 1 to disable filename case sensitivity */
1.1       jfb        58:
1.17      jfb        59: char *cvs_defargs;             /* default global arguments from .cvsrc */
                     60: char *cvs_command;             /* name of the command we are running */
1.6       jfb        61: int   cvs_cmdop;
1.1       jfb        62: char *cvs_rootstr;
                     63: char *cvs_rsh = CVS_RSH_DEFAULT;
                     64: char *cvs_editor = CVS_EDITOR_DEFAULT;
                     65:
1.13      krapht     66: char *cvs_msg = NULL;
                     67:
1.10      jfb        68: /* hierarchy of all the files affected by the command */
                     69: CVSFILE *cvs_files;
                     70:
                     71:
1.1       jfb        72: /*
                     73:  * Command dispatch table
                     74:  * ----------------------
                     75:  *
                     76:  * The synopsis field should only contain the list of arguments that the
                     77:  * command supports, without the actual command's name.
                     78:  *
                     79:  * Command handlers are expected to return 0 if no error occured, or one of
                     80:  * the values known in sysexits.h in case of an error.  In case the error
                     81:  * returned is EX_USAGE, the command's usage string is printed to standard
                     82:  * error before returning.
                     83:  */
                     84: static struct cvs_cmd {
1.6       jfb        85:        int     cmd_op;
1.1       jfb        86:        char    cmd_name[CVS_CMD_MAXNAMELEN];
                     87:        char    cmd_alias[CVS_CMD_MAXALIAS][CVS_CMD_MAXNAMELEN];
                     88:        int   (*cmd_hdlr)(int, char **);
                     89:        char   *cmd_synopsis;
1.13      krapht     90:        char   *cmd_opts;
1.1       jfb        91:        char    cmd_descr[CVS_CMD_MAXDESCRLEN];
1.17      jfb        92:        char   *cmd_defargs;
1.1       jfb        93: } cvs_cdt[] = {
                     94:        {
1.6       jfb        95:                CVS_OP_ADD, "add",      { "ad",  "new" }, cvs_add,
1.1       jfb        96:                "[-m msg] file ...",
1.13      krapht     97:                "",
1.1       jfb        98:                "Add a new file/directory to the repository",
1.17      jfb        99:                NULL,
1.1       jfb       100:        },
                    101:        {
1.6       jfb       102:                -1, "admin",    { "adm", "rcs" }, NULL,
1.1       jfb       103:                "",
1.13      krapht    104:                "",
1.1       jfb       105:                "Administration front end for rcs",
1.17      jfb       106:                NULL,
1.1       jfb       107:        },
                    108:        {
1.6       jfb       109:                CVS_OP_ANNOTATE, "annotate", { "ann"        }, NULL,
1.1       jfb       110:                "",
1.13      krapht    111:                "",
1.1       jfb       112:                "Show last revision where each line was modified",
1.17      jfb       113:                NULL,
1.1       jfb       114:        },
                    115:        {
1.6       jfb       116:                CVS_OP_CHECKOUT, "checkout", { "co",  "get" }, cvs_checkout,
1.1       jfb       117:                "",
1.13      krapht    118:                "",
1.1       jfb       119:                "Checkout sources for editing",
1.17      jfb       120:                NULL,
1.1       jfb       121:        },
                    122:        {
1.6       jfb       123:                CVS_OP_COMMIT, "commit",   { "ci",  "com" }, cvs_commit,
1.4       jfb       124:                "[-flR] [-F logfile | -m msg] [-r rev] ...",
1.13      krapht    125:                "F:flm:Rr:",
1.1       jfb       126:                "Check files into the repository",
1.17      jfb       127:                NULL,
1.1       jfb       128:        },
                    129:        {
1.6       jfb       130:                CVS_OP_DIFF, "diff",     { "di",  "dif" }, cvs_diff,
1.3       jfb       131:                "[-cilu] [-D date] [-r rev] ...",
1.13      krapht    132:                "cD:ilur:",
1.1       jfb       133:                "Show differences between revisions",
1.17      jfb       134:                NULL,
1.1       jfb       135:        },
                    136:        {
1.6       jfb       137:                -1, "edit",     {              }, NULL,
1.1       jfb       138:                "",
1.13      krapht    139:                "",
1.1       jfb       140:                "Get ready to edit a watched file",
1.17      jfb       141:                NULL,
1.1       jfb       142:        },
                    143:        {
1.6       jfb       144:                -1, "editors",  {              }, NULL,
1.1       jfb       145:                "",
1.13      krapht    146:                "",
1.1       jfb       147:                "See who is editing a watched file",
1.17      jfb       148:                NULL,
1.1       jfb       149:        },
                    150:        {
1.6       jfb       151:                -1, "export",   { "ex",  "exp" }, NULL,
1.1       jfb       152:                "",
1.13      krapht    153:                "",
1.1       jfb       154:                "Export sources from CVS, similar to checkout",
1.17      jfb       155:                NULL,
1.1       jfb       156:        },
                    157:        {
1.6       jfb       158:                CVS_OP_HISTORY, "history",  { "hi",  "his" }, cvs_history,
1.1       jfb       159:                "",
1.13      krapht    160:                "",
1.1       jfb       161:                "Show repository access history",
1.17      jfb       162:                NULL,
1.1       jfb       163:        },
                    164:        {
1.14      krapht    165:                CVS_OP_IMPORT, "import",   { "im",  "imp" }, NULL,
1.13      krapht    166:                "[-d] [-b branch] [-I ign] [-k subst] [-m msg] "
                    167:                "repository vendor-tag release-tags ...",
                    168:                "b:dI:k:m:",
1.1       jfb       169:                "Import sources into CVS, using vendor branches",
1.17      jfb       170:                NULL,
1.1       jfb       171:        },
                    172:        {
1.6       jfb       173:                CVS_OP_INIT, "init",     {              }, cvs_init,
1.1       jfb       174:                "",
1.13      krapht    175:                "",
1.1       jfb       176:                "Create a CVS repository if it doesn't exist",
1.17      jfb       177:                NULL,
1.1       jfb       178:        },
                    179: #if defined(HAVE_KERBEROS)
                    180:        {
                    181:                "kserver",  {}, NULL
                    182:                "",
1.13      krapht    183:                "",
1.1       jfb       184:                "Start a Kerberos authentication CVS server",
1.17      jfb       185:                NULL,
1.1       jfb       186:        },
                    187: #endif
                    188:        {
1.6       jfb       189:                CVS_OP_LOG, "log",      { "lo"         }, cvs_getlog,
1.1       jfb       190:                "",
1.13      krapht    191:                "",
1.1       jfb       192:                "Print out history information for files",
1.17      jfb       193:                NULL,
1.1       jfb       194:        },
                    195:        {
1.6       jfb       196:                -1, "login",    {}, NULL,
1.1       jfb       197:                "",
1.13      krapht    198:                "",
1.1       jfb       199:                "Prompt for password for authenticating server",
1.17      jfb       200:                NULL,
1.1       jfb       201:        },
                    202:        {
1.6       jfb       203:                -1, "logout",   {}, NULL,
1.1       jfb       204:                "",
1.13      krapht    205:                "",
1.1       jfb       206:                "Removes entry in .cvspass for remote repository",
1.17      jfb       207:                NULL,
1.1       jfb       208:        },
                    209:        {
1.6       jfb       210:                -1, "rdiff",    {}, NULL,
1.1       jfb       211:                "",
1.13      krapht    212:                "",
1.1       jfb       213:                "Create 'patch' format diffs between releases",
1.17      jfb       214:                NULL,
1.1       jfb       215:        },
                    216:        {
1.6       jfb       217:                -1, "release",  {}, NULL,
1.1       jfb       218:                "",
1.13      krapht    219:                "",
1.1       jfb       220:                "Indicate that a Module is no longer in use",
1.17      jfb       221:                NULL,
1.1       jfb       222:        },
                    223:        {
1.6       jfb       224:                CVS_OP_REMOVE, "remove",   {}, NULL,
1.1       jfb       225:                "",
1.13      krapht    226:                "",
1.1       jfb       227:                "Remove an entry from the repository",
1.17      jfb       228:                NULL,
1.1       jfb       229:        },
                    230:        {
1.6       jfb       231:                -1, "rlog",     {}, NULL,
1.1       jfb       232:                "",
1.13      krapht    233:                "",
1.1       jfb       234:                "Print out history information for a module",
1.17      jfb       235:                NULL,
1.1       jfb       236:        },
                    237:        {
1.6       jfb       238:                -1, "rtag",     {}, NULL,
1.1       jfb       239:                "",
1.13      krapht    240:                "",
1.1       jfb       241:                "Add a symbolic tag to a module",
1.17      jfb       242:                NULL,
1.1       jfb       243:        },
                    244:        {
1.6       jfb       245:                CVS_OP_SERVER, "server",   {}, cvs_server,
1.1       jfb       246:                "",
1.13      krapht    247:                "",
1.1       jfb       248:                "Server mode",
1.17      jfb       249:                NULL,
1.1       jfb       250:        },
                    251:        {
1.16      jfb       252:                CVS_OP_STATUS, "status",   { "st", "stat" }, cvs_status,
1.1       jfb       253:                "",
1.13      krapht    254:                "",
1.1       jfb       255:                "Display status information on checked out files",
1.17      jfb       256:                NULL,
1.1       jfb       257:        },
                    258:        {
1.16      jfb       259:                CVS_OP_TAG, "tag",      { "ta", "freeze" }, NULL,
1.1       jfb       260:                "",
1.13      krapht    261:                "",
1.1       jfb       262:                "Add a symbolic tag to checked out version of files",
1.17      jfb       263:                NULL,
1.1       jfb       264:        },
                    265:        {
1.6       jfb       266:                -1, "unedit",   {}, NULL,
1.1       jfb       267:                "",
1.13      krapht    268:                "",
1.1       jfb       269:                "Undo an edit command",
1.17      jfb       270:                NULL,
1.1       jfb       271:        },
                    272:        {
1.16      jfb       273:                CVS_OP_UPDATE, "update",   { "up", "upd" }, cvs_update,
1.1       jfb       274:                "",
1.13      krapht    275:                "",
1.1       jfb       276:                "Bring work tree in sync with repository",
1.17      jfb       277:                NULL,
1.1       jfb       278:        },
                    279:        {
1.16      jfb       280:                CVS_OP_VERSION, "version",  { "ve", "ver" }, cvs_version,
1.13      krapht    281:                "", "",
1.1       jfb       282:                "Show current CVS version(s)",
1.17      jfb       283:                NULL,
1.1       jfb       284:        },
                    285:        {
1.6       jfb       286:                -1, "watch",    {}, NULL,
1.1       jfb       287:                "",
1.13      krapht    288:                "",
1.1       jfb       289:                "Set watches",
1.17      jfb       290:                NULL,
1.1       jfb       291:        },
                    292:        {
1.6       jfb       293:                -1, "watchers", {}, NULL,
1.1       jfb       294:                "",
1.13      krapht    295:                "",
1.1       jfb       296:                "See who is watching a file",
1.17      jfb       297:                NULL,
1.1       jfb       298:        },
                    299: };
                    300:
                    301: #define CVS_NBCMD  (sizeof(cvs_cdt)/sizeof(cvs_cdt[0]))
                    302:
                    303:
                    304:
                    305: void             usage        (void);
                    306: void             sigchld_hdlr (int);
1.17      jfb       307: void             cvs_read_rcfile   (void);
1.1       jfb       308: struct cvs_cmd*  cvs_findcmd  (const char *);
1.17      jfb       309: int              cvs_getopt   (int, char **);
1.1       jfb       310:
                    311:
                    312: /*
                    313:  * usage()
                    314:  *
                    315:  * Display usage information.
                    316:  */
                    317: void
                    318: usage(void)
                    319: {
                    320:        fprintf(stderr,
1.11      jfb       321:            "Usage: %s [-lQqtvx] [-b bindir] [-d root] [-e editor] [-z level] "
1.1       jfb       322:            "command [options] ...\n",
                    323:            __progname);
                    324: }
                    325:
                    326:
                    327: int
                    328: main(int argc, char **argv)
                    329: {
1.17      jfb       330:        char *envstr, *cmd_argv[CVS_CMD_MAXARG], **targv;
                    331:        int i, ret, cmd_argc;
1.1       jfb       332:        struct cvs_cmd *cmdp;
                    333:
                    334:        if (cvs_log_init(LD_STD, 0) < 0)
                    335:                err(1, "failed to initialize logging");
                    336:
                    337:        /* by default, be very verbose */
                    338:        (void)cvs_log_filter(LP_FILTER_UNSET, LP_INFO);
                    339:
                    340: #ifdef DEBUG
                    341:        (void)cvs_log_filter(LP_FILTER_UNSET, LP_DEBUG);
                    342: #endif
                    343:
                    344:        /* check environment so command-line options override it */
                    345:        if ((envstr = getenv("CVS_RSH")) != NULL)
                    346:                cvs_rsh = envstr;
                    347:
                    348:        if (((envstr = getenv("CVSEDITOR")) != NULL) ||
                    349:            ((envstr = getenv("VISUAL")) != NULL) ||
                    350:            ((envstr = getenv("EDITOR")) != NULL))
                    351:                cvs_editor = envstr;
                    352:
1.17      jfb       353:        ret = cvs_getopt(argc, argv);
                    354:
                    355:        argc -= ret;
                    356:        argv += ret;
                    357:        if (argc == 0) {
                    358:                usage();
                    359:                exit(EX_USAGE);
                    360:        }
                    361:        cvs_command = argv[0];
                    362:
                    363:        if (cvs_readrc) {
                    364:                cvs_read_rcfile();
                    365:
                    366:                if (cvs_defargs != NULL) {
                    367:                        targv = cvs_makeargv(cvs_defargs, &i);
                    368:                        if (targv == NULL) {
                    369:                                cvs_log(LP_ERR,
                    370:                                    "failed to load default arguments to %s",
                    371:                                    __progname);
                    372:                                exit(EX_OSERR);
                    373:                        }
                    374:
                    375:                        cvs_getopt(i, targv);
                    376:                        cvs_freeargv(targv, i);
                    377:                        free(targv);
                    378:                }
                    379:        }
                    380:
                    381:        /* setup signal handlers */
                    382:        signal(SIGPIPE, SIG_IGN);
                    383:
                    384:        cvs_file_init();
                    385:
                    386:        ret = -1;
                    387:
                    388:        cmdp = cvs_findcmd(cvs_command);
                    389:        if (cmdp == NULL) {
                    390:                fprintf(stderr, "Unknown command: `%s'\n\n", cvs_command);
                    391:                fprintf(stderr, "CVS commands are:\n");
                    392:                for (i = 0; i < (int)CVS_NBCMD; i++)
                    393:                        fprintf(stderr, "\t%-16s%s\n",
                    394:                            cvs_cdt[i].cmd_name, cvs_cdt[i].cmd_descr);
                    395:                exit(EX_USAGE);
                    396:        }
                    397:
                    398:        if (cmdp->cmd_hdlr == NULL) {
                    399:                cvs_log(LP_ERR, "command `%s' not implemented", cvs_command);
                    400:                exit(1);
                    401:        }
                    402:
                    403:        cvs_cmdop = cmdp->cmd_op;
                    404:
                    405:        cmd_argc = 0;
                    406:        memset(cmd_argv, 0, sizeof(cmd_argv));
                    407:
                    408:        cmd_argv[cmd_argc++] = argv[0];
                    409:        if (cmdp->cmd_defargs != NULL) {
                    410:                /* transform into a new argument vector */
                    411:                ret = cvs_getargv(cmdp->cmd_defargs, cmd_argv + 1,
                    412:                    CVS_CMD_MAXARG - 1);
                    413:                if (ret < 0) {
                    414:                        cvs_log(LP_ERRNO, "failed to generate argument vector "
                    415:                            "from default arguments");
                    416:                        exit(EX_DATAERR);
                    417:                }
                    418:                cmd_argc += ret;
                    419:        }
                    420:        for (ret = 1; ret < argc; ret++)
                    421:                cmd_argv[cmd_argc++] = argv[ret];
                    422:
                    423:        ret = (*cmdp->cmd_hdlr)(cmd_argc, cmd_argv);
                    424:        if (ret == EX_USAGE) {
                    425:                fprintf(stderr, "Usage: %s %s %s\n", __progname, cvs_command,
                    426:                    cmdp->cmd_synopsis);
                    427:        }
                    428:
                    429:        if (cvs_files != NULL)
                    430:                cvs_file_free(cvs_files);
                    431:
                    432:        return (ret);
                    433: }
                    434:
                    435:
                    436: int
                    437: cvs_getopt(int argc, char **argv)
                    438: {
                    439:        int ret;
                    440:        char *ep;
                    441:
1.11      jfb       442:        while ((ret = getopt(argc, argv, "b:d:e:fHlnQqrtvz:")) != -1) {
1.1       jfb       443:                switch (ret) {
1.11      jfb       444:                case 'b':
                    445:                        /*
                    446:                         * We do not care about the bin directory for RCS files
                    447:                         * as this program has no dependencies on RCS programs,
                    448:                         * so it is only here for backwards compatibility.
                    449:                         */
                    450:                        cvs_log(LP_NOTICE, "the -b argument is obsolete");
                    451:                        break;
1.1       jfb       452:                case 'd':
                    453:                        cvs_rootstr = optarg;
                    454:                        break;
                    455:                case 'e':
                    456:                        cvs_editor = optarg;
                    457:                        break;
                    458:                case 'f':
1.17      jfb       459:                        cvs_readrc = 0;
1.1       jfb       460:                        break;
                    461:                case 'l':
                    462:                        cvs_nolog = 1;
                    463:                        break;
                    464:                case 'n':
                    465:                        break;
                    466:                case 'Q':
                    467:                        verbosity = 0;
                    468:                        break;
                    469:                case 'q':
                    470:                        /* don't override -Q */
                    471:                        if (verbosity > 1)
                    472:                                verbosity = 1;
                    473:                        break;
                    474:                case 'r':
                    475:                        cvs_readonly = 1;
                    476:                        break;
                    477:                case 't':
                    478:                        cvs_trace = 1;
                    479:                        break;
                    480:                case 'v':
                    481:                        printf("%s\n", CVS_VERSION);
                    482:                        exit(0);
                    483:                        /* NOTREACHED */
1.11      jfb       484:                        break;
                    485:                case 'x':
                    486:                        /*
                    487:                         * Kerberos encryption support, kept for compatibility
                    488:                         */
1.1       jfb       489:                        break;
                    490:                case 'z':
1.18    ! tedu      491:                        cvs_compress = (int)strtol(optarg, &ep, 10);
1.1       jfb       492:                        if (*ep != '\0')
                    493:                                errx(1, "error parsing compression level");
                    494:                        if (cvs_compress < 0 || cvs_compress > 9)
                    495:                                errx(1, "gzip compression level must be "
                    496:                                    "between 0 and 9");
                    497:                        break;
                    498:                default:
                    499:                        usage();
                    500:                        exit(EX_USAGE);
                    501:                }
                    502:        }
                    503:
1.17      jfb       504:        ret = optind;
1.1       jfb       505:        optind = 1;
1.17      jfb       506:        optreset = 1;   /* for next call */
1.12      jfb       507:
1.1       jfb       508:        return (ret);
                    509: }
                    510:
                    511:
                    512: /*
                    513:  * cvs_findcmd()
                    514:  *
                    515:  * Find the entry in the command dispatch table whose name or one of its
                    516:  * aliases matches <cmd>.
                    517:  * Returns a pointer to the command entry on success, NULL on failure.
                    518:  */
                    519: struct cvs_cmd*
                    520: cvs_findcmd(const char *cmd)
                    521: {
                    522:        u_int i, j;
                    523:        struct cvs_cmd *cmdp;
                    524:
                    525:        cmdp = NULL;
                    526:
                    527:        for (i = 0; (i < CVS_NBCMD) && (cmdp == NULL); i++) {
                    528:                if (strcmp(cmd, cvs_cdt[i].cmd_name) == 0)
                    529:                        cmdp = &cvs_cdt[i];
                    530:                else {
                    531:                        for (j = 0; j < CVS_CMD_MAXALIAS; j++) {
                    532:                                if (strcmp(cmd, cvs_cdt[i].cmd_alias[j]) == 0) {
                    533:                                        cmdp = &cvs_cdt[i];
                    534:                                        break;
                    535:                                }
                    536:                        }
                    537:                }
                    538:        }
                    539:
                    540:        return (cmdp);
                    541: }
                    542:
                    543:
                    544: /*
1.17      jfb       545:  * cvs_read_rcfile()
1.1       jfb       546:  *
                    547:  * Read the CVS `.cvsrc' file in the user's home directory.  If the file
                    548:  * exists, it should contain a list of arguments that should always be given
                    549:  * implicitly to the specified commands.
                    550:  */
                    551: void
1.17      jfb       552: cvs_read_rcfile(void)
1.1       jfb       553: {
                    554:        char rcpath[MAXPATHLEN], linebuf[128], *lp;
1.17      jfb       555:        size_t len;
1.1       jfb       556:        struct cvs_cmd *cmdp;
                    557:        struct passwd *pw;
                    558:        FILE *fp;
                    559:
                    560:        pw = getpwuid(getuid());
                    561:        if (pw == NULL) {
                    562:                cvs_log(LP_NOTICE, "failed to get user's password entry");
                    563:                return;
                    564:        }
                    565:
                    566:        snprintf(rcpath, sizeof(rcpath), "%s/%s", pw->pw_dir, CVS_PATH_RC);
                    567:
                    568:        fp = fopen(rcpath, "r");
                    569:        if (fp == NULL) {
                    570:                if (errno != ENOENT)
                    571:                        cvs_log(LP_NOTICE, "failed to open `%s': %s", rcpath,
                    572:                            strerror(errno));
                    573:                return;
                    574:        }
                    575:
                    576:        while (fgets(linebuf, sizeof(linebuf), fp) != NULL) {
1.17      jfb       577:                if ((len = strlen(linebuf)) == 0)
                    578:                        continue;
                    579:                if (linebuf[len - 1] != '\n') {
                    580:                        cvs_log(LP_WARN, ".cvsrc line too long");
                    581:                        break;
                    582:                }
                    583:                linebuf[--len] = '\0';
                    584:
1.1       jfb       585:                lp = strchr(linebuf, ' ');
                    586:                if (lp == NULL)
1.17      jfb       587:                        continue;       /* ignore lines with no arguments */
                    588:                *lp = '\0';
1.1       jfb       589:                if (strcmp(linebuf, "cvs") == 0) {
1.17      jfb       590:                        /*
                    591:                         * Global default options.  In the case of cvs only,
                    592:                         * we keep the 'cvs' string as first argument because
                    593:                         * getopt() does not like starting at index 0 for
                    594:                         * argument processing.
                    595:                         */
                    596:                        *lp = ' ';
                    597:                        cvs_defargs = strdup(linebuf);
                    598:                        if (cvs_defargs == NULL)
                    599:                                cvs_log(LP_ERRNO,
                    600:                                    "failed to copy global arguments");
1.15      deraadt   601:                } else {
1.17      jfb       602:                        lp++;
1.1       jfb       603:                        cmdp = cvs_findcmd(linebuf);
                    604:                        if (cmdp == NULL) {
                    605:                                cvs_log(LP_NOTICE,
                    606:                                    "unknown command `%s' in cvsrc",
                    607:                                    linebuf);
                    608:                                continue;
                    609:                        }
1.17      jfb       610:
                    611:                        cmdp->cmd_defargs = strdup(lp);
                    612:                        if (cmdp->cmd_defargs == NULL)
                    613:                                cvs_log(LP_ERRNO,
                    614:                                    "failed to copy default arguments for %s",
                    615:                                    cmdp->cmd_name);
1.1       jfb       616:                }
                    617:        }
                    618:        if (ferror(fp)) {
                    619:                cvs_log(LP_NOTICE, "failed to read line from cvsrc");
                    620:        }
                    621:
                    622:        (void)fclose(fp);
                    623: }