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

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