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

Annotation of src/usr.bin/cvs/admin.c, Revision 1.20

1.20    ! xsa         1: /*     $OpenBSD: admin.c,v 1.19 2005/07/11 08:32:36 xsa Exp $  */
1.1       joris       2: /*
                      3:  * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
                      4:  * Copyright (c) 2005 Joris Vink <joris@openbsd.org>
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  *
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. The name of the author may not be used to endorse or promote products
                     14:  *    derived from this software without specific prior written permission.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     17:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     18:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
                     19:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     20:  * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     21:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     22:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     23:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     24:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     25:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     26:  */
                     27:
                     28: #include <sys/types.h>
                     29: #include <sys/stat.h>
                     30:
                     31: #include <errno.h>
1.17      xsa        32: #include <fcntl.h>
1.1       joris      33: #include <stdio.h>
                     34: #include <stdlib.h>
1.17      xsa        35: #include <string.h>
1.1       joris      36: #include <unistd.h>
                     37:
                     38: #include "cvs.h"
                     39: #include "log.h"
                     40: #include "proto.h"
                     41:
                     42:
                     43: #define LOCK_SET       0x01
                     44: #define LOCK_REMOVE    0x02
                     45:
                     46: #define FLAG_BRANCH            0x01
                     47: #define FLAG_DELUSER           0x02
                     48: #define FLAG_INTERACTIVE       0x04
                     49: #define FLAG_QUIET             0x08
                     50:
1.15      jfb        51: static int cvs_admin_init     (struct cvs_cmd *, int, char **, int *);
                     52: static int cvs_admin_pre_exec (struct cvsroot *);
1.16      jfb        53: static int cvs_admin_remote   (CVSFILE *, void *);
                     54: static int cvs_admin_local    (CVSFILE *, void *);
1.15      jfb        55:
                     56: struct cvs_cmd cvs_cmd_admin = {
                     57:        CVS_OP_ADMIN, CVS_REQ_ADMIN, "admin",
                     58:        { "adm", "rcs" },
                     59:        "Administrative front-end for RCS",
                     60:        "",
                     61:        "a:A:b::c:e::Ik:l::Lm:n:N:o:qs:t:u::U",
                     62:        NULL,
                     63:        CF_SORT | CF_IGNORE | CF_RECURSE,
                     64:        cvs_admin_init,
                     65:        cvs_admin_pre_exec,
1.16      jfb        66:        cvs_admin_remote,
                     67:        cvs_admin_local,
1.15      jfb        68:        NULL,
                     69:        NULL,
1.7       joris      70:        CVS_CMD_ALLOWSPEC | CVS_CMD_SENDDIR | CVS_CMD_SENDARGS2
                     71: };
                     72:
                     73: static char *q, *Ntag, *ntag, *comment, *replace_msg;
                     74: static char *alist, *subst, *lockrev_arg, *unlockrev_arg;
                     75: static char *state, *userfile, *branch_arg, *elist, *range;
1.16      jfb        76: static int runflags, kflag, lockrev, lkmode;
                     77:
                     78: /* flag as invalid */
                     79: static int kflag = RCS_KWEXP_ERR;
                     80: static int lkmode = RCS_LOCK_INVAL;
1.7       joris      81:
1.15      jfb        82: static int
                     83: cvs_admin_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg)
1.1       joris      84: {
1.7       joris      85:        int ch;
1.1       joris      86:        RCSNUM *rcs;
                     87:
1.16      jfb        88:        runflags = lockrev = 0;
1.5       joris      89:        Ntag = ntag = comment = replace_msg = NULL;
                     90:        state = alist = subst = elist = lockrev_arg = NULL;
                     91:        range = userfile = branch_arg = unlockrev_arg = NULL;
1.1       joris      92:
                     93:        /* option-o-rama ! */
1.15      jfb        94:        while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) {
1.1       joris      95:                switch (ch) {
                     96:                case 'a':
                     97:                        alist = optarg;
                     98:                        break;
                     99:                case 'A':
                    100:                        userfile = optarg;
                    101:                        break;
                    102:                case 'b':
                    103:                        runflags |= FLAG_BRANCH;
                    104:                        if (optarg)
                    105:                                branch_arg = optarg;
                    106:                        break;
                    107:                case 'c':
                    108:                        comment = optarg;
                    109:                        break;
                    110:                case 'e':
                    111:                        runflags |= FLAG_DELUSER;
                    112:                        if (optarg)
                    113:                                elist = optarg;
                    114:                        break;
                    115:                case 'I':
                    116:                        runflags |= FLAG_INTERACTIVE;
                    117:                        break;
                    118:                case 'k':
                    119:                        subst = optarg;
1.3       joris     120:                        kflag = rcs_kflag_get(subst);
                    121:                        if (RCS_KWEXP_INVAL(kflag)) {
                    122:                                cvs_log(LP_ERR,
                    123:                                    "invalid RCS keyword expansion mode");
                    124:                                rcs_kflag_usage();
1.11      joris     125:                                return (CVS_EX_USAGE);
1.3       joris     126:                        }
1.1       joris     127:                        break;
                    128:                case 'l':
                    129:                        lockrev |= LOCK_SET;
                    130:                        if (optarg)
                    131:                                lockrev_arg = optarg;
                    132:                        break;
                    133:                case 'L':
1.16      jfb       134:                        lkmode = RCS_LOCK_STRICT;
1.1       joris     135:                        break;
                    136:                case 'm':
                    137:                        replace_msg = optarg;
                    138:                        break;
                    139:                case 'n':
1.5       joris     140:                        ntag = optarg;
1.1       joris     141:                        break;
                    142:                case 'N':
1.5       joris     143:                        Ntag = optarg;
1.1       joris     144:                        break;
                    145:                case 'o':
1.5       joris     146:                        range = optarg;
1.1       joris     147:                        break;
                    148:                case 'q':
                    149:                        runflags |= FLAG_QUIET;
                    150:                        break;
                    151:                case 's':
1.5       joris     152:                        state = optarg;
1.1       joris     153:                        break;
                    154:                case 't':
                    155:                        break;
                    156:                case 'u':
                    157:                        lockrev |= LOCK_REMOVE;
                    158:                        if (optarg)
                    159:                                unlockrev_arg = optarg;
                    160:                        break;
                    161:                case 'U':
1.16      jfb       162:                        if (lkmode != RCS_LOCK_INVAL) {
                    163:                                cvs_log(LP_ERR, "-L and -U are incompatible");
                    164:                                return (CVS_EX_USAGE);
                    165:                        }
                    166:                        lkmode = RCS_LOCK_LOOSE;
1.1       joris     167:                        break;
                    168:                default:
1.11      joris     169:                        return (CVS_EX_USAGE);
1.1       joris     170:                }
                    171:        }
                    172:
                    173:        argc -= optind;
                    174:        argv += optind;
                    175:
                    176:        if (lockrev_arg != NULL) {
                    177:                if ((rcs = rcsnum_parse(lockrev_arg)) == NULL) {
                    178:                        cvs_log(LP_ERR, "%s is not a numeric branch",
                    179:                            lockrev_arg);
1.11      joris     180:                        return (CVS_EX_USAGE);
1.1       joris     181:                }
                    182:                rcsnum_free(rcs);
                    183:        }
                    184:
                    185:        if (unlockrev_arg != NULL) {
                    186:                if ((rcs = rcsnum_parse(unlockrev_arg)) == NULL) {
                    187:                        cvs_log(LP_ERR, "%s is not a numeric branch",
                    188:                            unlockrev_arg);
1.11      joris     189:                        return (CVS_EX_USAGE);
1.1       joris     190:                }
                    191:                rcsnum_free(rcs);
                    192:        }
                    193:
                    194:        if (replace_msg != NULL) {
                    195:                if ((q = strchr(replace_msg, ':')) == NULL) {
                    196:                        cvs_log(LP_ERR, "invalid option for -m");
1.11      joris     197:                        return (CVS_EX_USAGE);
1.1       joris     198:                }
                    199:                *q = '\0';
                    200:                if ((rcs = rcsnum_parse(replace_msg)) == NULL) {
                    201:                        cvs_log(LP_ERR, "%s is not a numeric revision",
                    202:                            replace_msg);
1.11      joris     203:                        return (CVS_EX_USAGE);
1.1       joris     204:                }
1.2       joris     205:                rcsnum_free(rcs);
1.1       joris     206:                *q = ':';
                    207:        }
                    208:
1.7       joris     209:        *arg = optind;
                    210:        return (0);
                    211: }
1.1       joris     212:
1.15      jfb       213: static int
                    214: cvs_admin_pre_exec(struct cvsroot *root)
1.7       joris     215: {
1.16      jfb       216:        if (root->cr_method == CVS_METHOD_LOCAL)
                    217:                return (0);
                    218:
1.18      joris     219:        if ((alist != NULL) && ((cvs_sendarg(root, "-a", 0) < 0) ||
1.7       joris     220:            (cvs_sendarg(root, alist, 0) < 0)))
1.11      joris     221:                return (CVS_EX_PROTO);
1.1       joris     222:
1.7       joris     223:        if ((userfile != NULL) && ((cvs_sendarg(root, "-A", 0) < 0) ||
                    224:            (cvs_sendarg(root, userfile, 0) < 0)))
1.11      joris     225:                return (CVS_EX_PROTO);
1.1       joris     226:
1.7       joris     227:        if (runflags & FLAG_BRANCH) {
                    228:                if (cvs_sendarg(root, "-b", 0) < 0)
1.11      joris     229:                        return (CVS_EX_PROTO);
1.7       joris     230:                if ((branch_arg != NULL) &&
                    231:                    (cvs_sendarg(root, branch_arg, 0) < 0))
1.11      joris     232:                        return (CVS_EX_PROTO);
1.7       joris     233:        }
1.1       joris     234:
1.7       joris     235:        if ((comment != NULL) && ((cvs_sendarg(root, "-c", 0) < 0) ||
                    236:            (cvs_sendarg(root, comment, 0) < 0)))
1.11      joris     237:                return (CVS_EX_PROTO);
1.1       joris     238:
1.7       joris     239:        if (runflags & FLAG_DELUSER)  {
                    240:                if (cvs_sendarg(root, "-e", 0) < 0)
1.11      joris     241:                        return (CVS_EX_PROTO);
1.7       joris     242:                if ((elist != NULL) &&
                    243:                    (cvs_sendarg(root, elist, 0) < 0))
1.11      joris     244:                        return (CVS_EX_PROTO);
1.7       joris     245:        }
1.1       joris     246:
1.7       joris     247:        if (runflags & FLAG_INTERACTIVE) {
                    248:                if (cvs_sendarg(root, "-I", 0) < 0)
1.11      joris     249:                        return (CVS_EX_PROTO);
1.7       joris     250:        }
1.1       joris     251:
1.7       joris     252:        if ((subst != NULL) && ((cvs_sendarg(root, "-k", 0) < 0) ||
                    253:            (cvs_sendarg(root, subst, 0) < 0)))
1.11      joris     254:                return (CVS_EX_PROTO);
1.5       joris     255:
1.7       joris     256:        if (lockrev & LOCK_SET) {
                    257:                if (cvs_sendarg(root, "-l", 0) < 0)
1.11      joris     258:                        return (CVS_EX_PROTO);
1.7       joris     259:                if ((lockrev_arg != NULL) &&
                    260:                    (cvs_sendarg(root, lockrev_arg, 0) < 0))
1.11      joris     261:                        return (CVS_EX_PROTO);
1.7       joris     262:        }
1.5       joris     263:
1.16      jfb       264:        if ((lkmode == RCS_LOCK_STRICT) && (cvs_sendarg(root, "-L", 0) < 0))
                    265:                return (CVS_EX_PROTO);
                    266:        else if ((lkmode == RCS_LOCK_LOOSE) && (cvs_sendarg(root, "-U", 0) < 0))
1.11      joris     267:                return (CVS_EX_PROTO);
1.5       joris     268:
1.7       joris     269:        if ((replace_msg != NULL) && ((cvs_sendarg(root, "-m", 0) < 0)
                    270:            || (cvs_sendarg(root, replace_msg, 0) < 0)))
1.11      joris     271:                return (CVS_EX_PROTO);
1.5       joris     272:
1.7       joris     273:        if ((ntag != NULL) && ((cvs_sendarg(root, "-n", 0) < 0) ||
                    274:            (cvs_sendarg(root, ntag, 0) < 0)))
1.11      joris     275:                return (CVS_EX_PROTO);
1.1       joris     276:
1.7       joris     277:        if ((Ntag != NULL) && ((cvs_sendarg(root, "-N", 0) < 0) ||
                    278:            (cvs_sendarg(root, Ntag, 0) < 0)))
1.11      joris     279:                return (CVS_EX_PROTO);
1.1       joris     280:
1.7       joris     281:        if ((range != NULL) && ((cvs_sendarg(root, "-o", 0) < 0) ||
                    282:            (cvs_sendarg(root, range, 0) < 0)))
1.11      joris     283:                return (CVS_EX_PROTO);
1.1       joris     284:
1.7       joris     285:        if ((state != NULL) && ((cvs_sendarg(root, "-s", 0) < 0) ||
                    286:            (cvs_sendarg(root, state, 0) < 0)))
1.11      joris     287:                return (CVS_EX_PROTO);
1.1       joris     288:
1.7       joris     289:        if (lockrev & LOCK_REMOVE) {
                    290:                if (cvs_sendarg(root, "-u", 0) < 0)
1.11      joris     291:                        return (CVS_EX_PROTO);
1.7       joris     292:                if ((unlockrev_arg != NULL) &&
                    293:                    (cvs_sendarg(root, unlockrev_arg, 0) < 0))
1.11      joris     294:                        return (CVS_EX_PROTO);
1.1       joris     295:        }
                    296:
                    297:        return (0);
                    298: }
                    299:
                    300: /*
1.16      jfb       301:  * cvs_admin_remote()
1.1       joris     302:  *
                    303:  * Perform admin commands on each file.
                    304:  */
1.15      jfb       305: static int
1.16      jfb       306: cvs_admin_remote(CVSFILE *cf, void *arg)
1.1       joris     307: {
1.16      jfb       308:        int ret;
                    309:        char *repo, fpath[MAXPATHLEN];
1.1       joris     310:        struct cvsroot *root;
                    311:
                    312:        ret = 0;
1.16      jfb       313:        root = CVS_DIR_ROOT(cf);
                    314:        repo = CVS_DIR_REPO(cf);
1.14      joris     315:
1.16      jfb       316:        if (cf->cf_type == DT_DIR) {
                    317:                if (cf->cf_cvstat == CVS_FST_UNKNOWN)
                    318:                        ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE,
                    319:                            cf->cf_name);
                    320:                else
                    321:                        ret = cvs_senddir(root, cf);
                    322:                if (ret == -1)
                    323:                        ret = CVS_EX_PROTO;
1.1       joris     324:
                    325:                return (ret);
                    326:        }
                    327:
1.16      jfb       328:        cvs_file_getpath(cf, fpath, sizeof(fpath));
1.1       joris     329:
1.16      jfb       330:        if (cvs_sendentry(root, cf) < 0)
                    331:                return (CVS_EX_PROTO);
                    332:
                    333:        switch (cf->cf_cvstat) {
                    334:        case CVS_FST_UNKNOWN:
                    335:                ret = cvs_sendreq(root, CVS_REQ_QUESTIONABLE, cf->cf_name);
                    336:                break;
                    337:        case CVS_FST_UPTODATE:
                    338:                ret = cvs_sendreq(root, CVS_REQ_UNCHANGED, cf->cf_name);
                    339:                break;
                    340:        case CVS_FST_MODIFIED:
                    341:                ret = cvs_sendreq(root, CVS_REQ_MODIFIED, cf->cf_name);
                    342:                if (ret == 0)
                    343:                        ret = cvs_sendfile(root, fpath);
                    344:        default:
                    345:                break;
                    346:        }
1.1       joris     347:
1.16      jfb       348:        return (ret);
                    349: }
1.14      joris     350:
1.16      jfb       351: /*
                    352:  * cvs_admin_local()
                    353:  *
                    354:  * Perform administrative operations on a local RCS file.
                    355:  */
                    356: static int
                    357: cvs_admin_local(CVSFILE *cf, void *arg)
                    358: {
1.20    ! xsa       359:        int ret;
        !           360:        char fpath[MAXPATHLEN], rcspath[MAXPATHLEN];
1.16      jfb       361:        RCSFILE *rf;
1.19      xsa       362:
                    363:        if (cf->cf_type == DT_DIR) {
                    364:                if (verbosity > 1)
                    365:                        cvs_log(LP_INFO, "Administrating %s", cf->cf_name);
                    366:                return (0);
                    367:        }
1.1       joris     368:
1.16      jfb       369:        if (cf->cf_cvstat == CVS_FST_UNKNOWN) {
                    370:                cvs_log(LP_WARN, "I know nothing about %s", fpath);
                    371:                return (0);
                    372:        }
1.1       joris     373:
1.16      jfb       374:        cvs_file_getpath(cf, fpath, sizeof(fpath));
1.1       joris     375:
1.20    ! xsa       376:        if (cvs_rcs_getpath(cf, rcspath, sizeof(rcspath)) == NULL)
        !           377:                return (CVS_EX_DATA);
1.1       joris     378:
1.16      jfb       379:        rf = rcs_open(rcspath, RCS_RDWR);
                    380:        if (rf == NULL)
                    381:                return (CVS_EX_DATA);
                    382:
                    383:        if (!RCS_KWEXP_INVAL(kflag))
                    384:                ret = rcs_kwexp_set(rf, kflag);
                    385:        if (lkmode != RCS_LOCK_INVAL)
                    386:                ret = rcs_lock_setmode(rf, lkmode);
                    387:
                    388:        rcs_close(rf);
                    389:
                    390:        return (0);
1.1       joris     391: }