[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.47

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