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

Annotation of src/usr.bin/cvs/edit.c, Revision 1.45

1.45    ! deraadt     1: /*     $OpenBSD: edit.c,v 1.44 2008/02/06 12:42:46 tobias Exp $        */
1.1       jfb         2: /*
1.15      xsa         3:  * Copyright (c) 2006, 2007 Xavier Santolaria <xsa@openbsd.org>
1.1       jfb         4:  *
1.14      xsa         5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1       jfb        16:  */
                     17:
1.34      otto       18: #include <sys/stat.h>
                     19:
                     20: #include <errno.h>
                     21: #include <string.h>
                     22: #include <unistd.h>
1.1       jfb        23:
                     24: #include "cvs.h"
1.14      xsa        25: #include "remote.h"
1.1       jfb        26:
1.18      xsa        27: #define E_COMMIT       0x01
                     28: #define E_EDIT         0x02
                     29: #define E_UNEDIT       0x04
                     30: #define E_ALL          (E_EDIT|E_COMMIT|E_UNEDIT)
                     31:
1.23      xsa        32: #define BASE_ADD       0x01
                     33: #define BASE_GET       0x02
                     34: #define BASE_REMOVE    0x04
                     35:
1.18      xsa        36: static void    cvs_edit_local(struct cvs_file *);
1.14      xsa        37: static void    cvs_editors_local(struct cvs_file *);
1.15      xsa        38: static void    cvs_unedit_local(struct cvs_file *);
1.1       jfb        39:
1.23      xsa        40: static RCSNUM  *cvs_base_handle(struct cvs_file *, int);
                     41:
1.18      xsa        42: static int     edit_aflags = 0;
                     43:
                     44: struct cvs_cmd cvs_cmd_edit = {
1.42      tobias     45:        CVS_OP_EDIT, CVS_USE_WDIR, "edit",
1.18      xsa        46:        { },
                     47:        "Get ready to edit a watched file",
                     48:        "[-lR] [-a action] [file ...]",
                     49:        "a:lR",
                     50:        NULL,
                     51:        cvs_edit
                     52: };
                     53:
1.1       jfb        54: struct cvs_cmd cvs_cmd_editors = {
1.42      tobias     55:        CVS_OP_EDITORS, CVS_USE_WDIR, "editors",
1.1       jfb        56:        { },
1.14      xsa        57:        "See who is editing a watched file",
1.3       xsa        58:        "[-lR] [file ...]",
1.1       jfb        59:        "lR",
                     60:        NULL,
1.14      xsa        61:        cvs_editors
1.1       jfb        62: };
                     63:
1.15      xsa        64: struct cvs_cmd cvs_cmd_unedit = {
1.42      tobias     65:        CVS_OP_UNEDIT, CVS_USE_WDIR, "unedit",
1.15      xsa        66:        { },
                     67:        "Undo an edit command",
                     68:        "[-lR] [file ...]",
                     69:        "lR",
                     70:        NULL,
                     71:        cvs_unedit
                     72: };
                     73:
1.14      xsa        74: int
1.18      xsa        75: cvs_edit(int argc, char **argv)
                     76: {
                     77:        int ch;
                     78:        int flags;
                     79:        struct cvs_recursion cr;
                     80:
                     81:        flags = CR_RECURSE_DIRS;
                     82:
                     83:        while ((ch = getopt(argc, argv, cvs_cmd_edit.cmd_opts)) != -1) {
                     84:                switch (ch) {
                     85:                case 'a':
                     86:                        if (strcmp(optarg, "edit") == 0)
                     87:                                edit_aflags |= E_EDIT;
                     88:                        else if (strcmp(optarg, "unedit") == 0)
                     89:                                edit_aflags |= E_UNEDIT;
                     90:                        else if (strcmp(optarg, "commit") == 0)
                     91:                                edit_aflags |= E_COMMIT;
                     92:                        else if (strcmp(optarg, "all") == 0)
                     93:                                edit_aflags |= E_ALL;
                     94:                        else if (strcmp(optarg, "none") == 0)
                     95:                                edit_aflags &= ~E_ALL;
                     96:                        else
                     97:                                fatal("%s", cvs_cmd_edit.cmd_synopsis);
                     98:                        break;
                     99:                case 'l':
                    100:                        flags &= ~CR_RECURSE_DIRS;
                    101:                        break;
                    102:                case 'R':
1.41      tobias    103:                        flags |= CR_RECURSE_DIRS;
1.18      xsa       104:                        break;
                    105:                default:
                    106:                        fatal("%s", cvs_cmd_edit.cmd_synopsis);
                    107:                }
                    108:        }
                    109:
                    110:        argc -= optind;
                    111:        argv += optind;
                    112:
                    113:        if (argc == 0)
                    114:                fatal("%s", cvs_cmd_edit.cmd_synopsis);
                    115:
                    116:        if (edit_aflags == 0)
                    117:                edit_aflags |= E_ALL;
                    118:
                    119:        cr.enterdir = NULL;
                    120:        cr.leavedir = NULL;
                    121:
                    122:        if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
1.27      joris     123:                cvs_client_connect_to_server();
1.18      xsa       124:                cr.fileproc = cvs_client_sendfile;
                    125:
                    126:                if (!(flags & CR_RECURSE_DIRS))
                    127:                        cvs_client_send_request("Argument -l");
                    128:        } else {
                    129:                cr.fileproc = cvs_edit_local;
                    130:        }
                    131:
                    132:        cr.flags = flags;
                    133:
                    134:        cvs_file_run(argc, argv, &cr);
                    135:
                    136:        if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
                    137:                cvs_client_send_files(argv, argc);
                    138:                cvs_client_senddir(".");
                    139:                cvs_client_send_request("edit");
                    140:                cvs_client_get_responses();
                    141:        }
                    142:
                    143:        return (0);
                    144: }
                    145:
                    146: int
1.14      xsa       147: cvs_editors(int argc, char **argv)
1.1       jfb       148: {
1.12      xsa       149:        int ch;
1.14      xsa       150:        int flags;
                    151:        struct cvs_recursion cr;
                    152:
                    153:        flags = CR_RECURSE_DIRS;
1.1       jfb       154:
1.14      xsa       155:        while ((ch = getopt(argc, argv, cvs_cmd_editors.cmd_opts)) != -1) {
1.1       jfb       156:                switch (ch) {
                    157:                case 'l':
1.14      xsa       158:                        flags &= ~CR_RECURSE_DIRS;
1.1       jfb       159:                        break;
                    160:                case 'R':
1.41      tobias    161:                        flags |= CR_RECURSE_DIRS;
1.1       jfb       162:                        break;
                    163:                default:
1.14      xsa       164:                        fatal("%s", cvs_cmd_editors.cmd_synopsis);
1.1       jfb       165:                }
                    166:        }
                    167:
1.14      xsa       168:        argc -= optind;
                    169:        argv += optind;
1.1       jfb       170:
1.14      xsa       171:        if (argc == 0)
                    172:                fatal("%s", cvs_cmd_editors.cmd_synopsis);
1.1       jfb       173:
1.14      xsa       174:        cr.enterdir = NULL;
                    175:        cr.leavedir = NULL;
1.1       jfb       176:
1.14      xsa       177:        if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
1.27      joris     178:                cvs_client_connect_to_server();
1.14      xsa       179:                cr.fileproc = cvs_client_sendfile;
                    180:
                    181:                if (!(flags & CR_RECURSE_DIRS))
                    182:                        cvs_client_send_request("Argument -l");
                    183:        } else {
                    184:                cr.fileproc = cvs_editors_local;
                    185:        }
1.1       jfb       186:
1.14      xsa       187:        cr.flags = flags;
1.9       xsa       188:
1.14      xsa       189:        cvs_file_run(argc, argv, &cr);
1.9       xsa       190:
1.14      xsa       191:        if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
                    192:                cvs_client_send_files(argv, argc);
                    193:                cvs_client_senddir(".");
                    194:                cvs_client_send_request("editors");
                    195:                cvs_client_get_responses();
1.9       xsa       196:        }
                    197:
1.14      xsa       198:        return (0);
                    199: }
1.9       xsa       200:
1.15      xsa       201: int
                    202: cvs_unedit(int argc, char **argv)
                    203: {
                    204:        int ch;
                    205:        int flags;
                    206:        struct cvs_recursion cr;
                    207:
                    208:        flags = CR_RECURSE_DIRS;
                    209:
                    210:        while ((ch = getopt(argc, argv, cvs_cmd_unedit.cmd_opts)) != -1) {
                    211:                switch (ch) {
                    212:                case 'l':
                    213:                        flags &= ~CR_RECURSE_DIRS;
                    214:                        break;
                    215:                case 'R':
1.41      tobias    216:                        flags |= CR_RECURSE_DIRS;
1.15      xsa       217:                        break;
                    218:                default:
                    219:                        fatal("%s", cvs_cmd_unedit.cmd_synopsis);
                    220:                }
                    221:        }
                    222:
                    223:        argc -= optind;
                    224:        argv += optind;
                    225:
                    226:        if (argc == 0)
                    227:                fatal("%s", cvs_cmd_unedit.cmd_synopsis);
                    228:
                    229:        cr.enterdir = NULL;
                    230:        cr.leavedir = NULL;
                    231:
                    232:        if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
1.28      xsa       233:                cvs_client_connect_to_server();
1.15      xsa       234:                cr.fileproc = cvs_client_sendfile;
                    235:
                    236:                if (!(flags & CR_RECURSE_DIRS))
                    237:                        cvs_client_send_request("Argument -l");
                    238:        } else {
                    239:                cr.fileproc = cvs_unedit_local;
                    240:        }
                    241:
                    242:        cr.flags = flags;
                    243:
                    244:        cvs_file_run(argc, argv, &cr);
                    245:
                    246:        if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
                    247:                cvs_client_send_files(argv, argc);
                    248:                cvs_client_senddir(".");
                    249:                cvs_client_send_request("unedit");
                    250:                cvs_client_get_responses();
                    251:        }
                    252:
                    253:        return (0);
1.18      xsa       254: }
                    255:
                    256: static void
                    257: cvs_edit_local(struct cvs_file *cf)
                    258: {
                    259:        FILE *fp;
                    260:        struct tm *t;
                    261:        time_t now;
1.36      xsa       262:        char timebuf[CVS_TIME_BUFSZ], thishost[MAXHOSTNAMELEN];
                    263:        char bfpath[MAXPATHLEN], wdir[MAXPATHLEN];
1.18      xsa       264:
                    265:        if (cvs_noexec == 1)
                    266:                return;
                    267:
1.24      xsa       268:        cvs_log(LP_TRACE, "cvs_edit_local(%s)", cf->file_path);
                    269:
1.37      joris     270:        cvs_file_classify(cf, cvs_directory_tag);
1.23      xsa       271:
1.18      xsa       272:        if ((fp = fopen(CVS_PATH_NOTIFY, "a")) == NULL)
                    273:                fatal("cvs_edit_local: fopen: `%s': %s",
                    274:                    CVS_PATH_NOTIFY, strerror(errno));
                    275:
                    276:        (void)time(&now);
                    277:        if ((t = gmtime(&now)) == NULL)
                    278:                fatal("gmtime failed");
                    279:
1.20      xsa       280:        asctime_r(t, timebuf);
1.40      tobias    281:        timebuf[strcspn(timebuf, "\n")] = '\0';
1.18      xsa       282:
1.19      xsa       283:        if (gethostname(thishost, sizeof(thishost)) == -1)
                    284:                fatal("gethostname failed");
                    285:
1.21      xsa       286:        if (getcwd(wdir, sizeof(wdir)) == NULL)
                    287:                fatal("getcwd failed");
                    288:
1.25      xsa       289:        (void)fprintf(fp, "E%s\t%s GMT\t%s\t%s\t",
1.21      xsa       290:            cf->file_name, timebuf, thishost, wdir);
1.18      xsa       291:
                    292:        if (edit_aflags & E_EDIT)
                    293:                (void)fprintf(fp, "E");
                    294:        if (edit_aflags & E_UNEDIT)
                    295:                (void)fprintf(fp, "U");
                    296:        if (edit_aflags & E_COMMIT)
                    297:                (void)fprintf(fp, "C");
                    298:
                    299:        (void)fprintf(fp, "\n");
                    300:
                    301:        (void)fclose(fp);
                    302:
                    303:        if (fchmod(cf->fd, 0644) == -1)
                    304:                fatal("cvs_edit_local: fchmod %s", strerror(errno));
                    305:
1.33      xsa       306:        (void)xsnprintf(bfpath, MAXPATHLEN, "%s/%s",
                    307:            CVS_PATH_BASEDIR, cf->file_name);
1.22      xsa       308:
                    309:        if (mkdir(CVS_PATH_BASEDIR, 0755) == -1 && errno != EEXIST)
                    310:                fatal("cvs_edit_local: `%s': %s", CVS_PATH_BASEDIR,
                    311:                    strerror(errno));
1.18      xsa       312:
1.26      xsa       313:        if (cvs_file_copy(cf->file_path, bfpath) == -1)
                    314:                fatal("cvs_edit_local: cvs_file_copy failed");
1.18      xsa       315:
1.23      xsa       316:        (void)cvs_base_handle(cf, BASE_ADD);
1.15      xsa       317: }
                    318:
1.14      xsa       319: static void
                    320: cvs_editors_local(struct cvs_file *cf)
                    321: {
1.15      xsa       322: }
                    323:
                    324: static void
                    325: cvs_unedit_local(struct cvs_file *cf)
                    326: {
                    327:        FILE *fp;
                    328:        struct stat st;
                    329:        struct tm *t;
                    330:        time_t now;
1.31      otto      331:        char bfpath[MAXPATHLEN], timebuf[64], thishost[MAXHOSTNAMELEN];
1.44      tobias    332:        char wdir[MAXPATHLEN], sticky[CVS_ENT_MAXLINELEN];
1.24      xsa       333:        RCSNUM *ba_rev;
1.15      xsa       334:
                    335:        if (cvs_noexec == 1)
                    336:                return;
                    337:
1.24      xsa       338:        cvs_log(LP_TRACE, "cvs_unedit_local(%s)", cf->file_path);
                    339:
1.38      joris     340:        cvs_file_classify(cf, cvs_directory_tag);
1.23      xsa       341:
1.33      xsa       342:        (void)xsnprintf(bfpath, MAXPATHLEN, "%s/%s",
                    343:            CVS_PATH_BASEDIR, cf->file_name);
1.15      xsa       344:
1.31      otto      345:        if (stat(bfpath, &st) == -1)
1.15      xsa       346:                return;
                    347:
1.17      xsa       348:        if (cvs_file_cmp(cf->file_path, bfpath) != 0) {
                    349:                cvs_printf("%s has been modified; revert changes? ",
                    350:                    cf->file_name);
                    351:
1.31      otto      352:                if (cvs_yesno() == -1)
1.17      xsa       353:                        return;
                    354:        }
1.15      xsa       355:
                    356:        cvs_rename(bfpath, cf->file_path);
                    357:
                    358:        if ((fp = fopen(CVS_PATH_NOTIFY, "a")) == NULL)
                    359:                fatal("cvs_unedit_local: fopen: `%s': %s",
                    360:                    CVS_PATH_NOTIFY, strerror(errno));
                    361:
                    362:        (void)time(&now);
                    363:        if ((t = gmtime(&now)) == NULL)
                    364:                fatal("gmtime failed");
                    365:
1.20      xsa       366:        asctime_r(t, timebuf);
1.40      tobias    367:        timebuf[strcspn(timebuf, "\n")] = '\0';
1.15      xsa       368:
1.19      xsa       369:        if (gethostname(thishost, sizeof(thishost)) == -1)
                    370:                fatal("gethostname failed");
                    371:
1.21      xsa       372:        if (getcwd(wdir, sizeof(wdir)) == NULL)
1.23      xsa       373:                fatal("getcwd failed");
1.21      xsa       374:
1.15      xsa       375:        (void)fprintf(fp, "U%s\t%s GMT\t%s\t%s\t\n",
1.21      xsa       376:            cf->file_name, timebuf, thishost, wdir);
1.15      xsa       377:
                    378:        (void)fclose(fp);
                    379:
1.29      xsa       380:        if ((ba_rev = cvs_base_handle(cf, BASE_GET)) == NULL) {
                    381:                cvs_log(LP_ERR, "%s not mentioned in %s",
                    382:                    cf->file_name, CVS_PATH_BASEREV);
                    383:                return;
                    384:        }
                    385:
1.24      xsa       386:        if (cf->file_ent != NULL) {
1.29      xsa       387:                CVSENTRIES *entlist;
                    388:                struct cvs_ent *ent;
1.35      xsa       389:                char *entry, rbuf[CVS_REV_BUFSZ];
1.29      xsa       390:
                    391:                entlist = cvs_ent_open(cf->file_wd);
                    392:
                    393:                if ((ent = cvs_ent_get(entlist, cf->file_name)) == NULL)
1.30      xsa       394:                        fatal("cvs_unedit_local: cvs_ent_get failed");
1.29      xsa       395:
                    396:                (void)rcsnum_tostr(ba_rev, rbuf, sizeof(rbuf));
                    397:
                    398:                memset(timebuf, 0, sizeof(timebuf));
                    399:                ctime_r(&cf->file_ent->ce_mtime, timebuf);
1.40      tobias    400:                timebuf[strcspn(timebuf, "\n")] = '\0';
1.29      xsa       401:
1.44      tobias    402:                sticky[0] = '\0';
                    403:                if (cf->file_ent->ce_tag != NULL)
                    404:                        (void)xsnprintf(sticky, sizeof(sticky), "T%s",
                    405:                            cf->file_ent->ce_tag);
                    406:
1.29      xsa       407:                (void)xasprintf(&entry, "/%s/%s/%s/%s/%s",
1.43      tobias    408:                    cf->file_name, rbuf, timebuf, cf->file_ent->ce_opts ? : "",
1.44      tobias    409:                    sticky);
1.29      xsa       410:
                    411:                cvs_ent_add(entlist, entry);
                    412:
                    413:                cvs_ent_free(ent);
                    414:                cvs_ent_close(entlist, ENT_SYNC);
                    415:
                    416:                xfree(entry);
1.24      xsa       417:        }
1.29      xsa       418:
                    419:        rcsnum_free(ba_rev);
1.24      xsa       420:
                    421:        (void)cvs_base_handle(cf, BASE_REMOVE);
1.16      xsa       422:
                    423:        if (fchmod(cf->fd, 0644) == -1)
                    424:                fatal("cvs_unedit_local: fchmod %s", strerror(errno));
1.23      xsa       425: }
                    426:
                    427: static RCSNUM *
                    428: cvs_base_handle(struct cvs_file *cf, int flags)
                    429: {
                    430:        FILE *fp, *tfp;
                    431:        RCSNUM *ba_rev;
1.24      xsa       432:        int i;
                    433:        char *dp, *sp;
1.35      xsa       434:        char buf[MAXPATHLEN], *fields[2], rbuf[CVS_REV_BUFSZ];
1.23      xsa       435:
                    436:        cvs_log(LP_TRACE, "cvs_base_handle(%s)", cf->file_path);
                    437:
                    438:        tfp = NULL;
                    439:        ba_rev = NULL;
                    440:
1.24      xsa       441:        if (((fp = fopen(CVS_PATH_BASEREV, "r")) == NULL) && errno != ENOENT) {
1.23      xsa       442:                cvs_log(LP_ERRNO, "%s", CVS_PATH_BASEREV);
                    443:                goto out;
                    444:        }
                    445:
                    446:        if (flags & (BASE_ADD|BASE_REMOVE)) {
                    447:                if ((tfp = fopen(CVS_PATH_BASEREVTMP, "w")) == NULL) {
                    448:                        cvs_log(LP_ERRNO, "%s", CVS_PATH_BASEREVTMP);
                    449:                        goto out;
                    450:                }
                    451:        }
                    452:
1.24      xsa       453:        if (fp != NULL) {
1.45    ! deraadt   454:                while (fgets(buf, sizeof(buf), fp)) {
1.39      gilles    455:                        buf[strcspn(buf, "\n")] = '\0';
1.24      xsa       456:
                    457:                        if (buf[0] != 'B')
                    458:                                continue;
                    459:
                    460:                        sp = buf + 1;
                    461:                        i = 0;
                    462:                        do {
                    463:                                if ((dp = strchr(sp, '/')) != NULL)
                    464:                                        *(dp++) = '\0';
                    465:                                fields[i++] = sp;
                    466:                                sp = dp;
                    467:                        } while (dp != NULL && i < 2);
                    468:
                    469:                        if (cvs_file_cmpname(fields[0], cf->file_path) == 0) {
                    470:                                if (flags & BASE_GET) {
                    471:                                        ba_rev = rcsnum_parse(fields[1]);
                    472:                                        if (ba_rev == NULL)
                    473:                                                fatal("cvs_base_handle: "
                    474:                                                    "rcsnum_parse");
                    475:                                        goto got_rev;
                    476:                                }
                    477:                        } else {
                    478:                                if (flags & (BASE_ADD|BASE_REMOVE))
                    479:                                        (void)fprintf(tfp, "%s\n", buf);
1.23      xsa       480:                        }
                    481:                }
                    482:        }
                    483:
                    484: got_rev:
                    485:        if (flags & (BASE_ADD)) {
                    486:                (void)rcsnum_tostr(cf->file_ent->ce_rev, rbuf, sizeof(rbuf));
                    487:                (void)fprintf(tfp, "B%s/%s/\n", cf->file_path, rbuf);
                    488:        }
                    489:
                    490: out:
                    491:        if (fp != NULL)
                    492:                (void)fclose(fp);
                    493:
                    494:        if (tfp != NULL) {
                    495:                (void)fclose(tfp);
                    496:                (void)cvs_rename(CVS_PATH_BASEREVTMP, CVS_PATH_BASEREV);
                    497:        }
                    498:
                    499:        return (ba_rev);
1.1       jfb       500: }