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

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

1.45    ! okan        1: /*     $OpenBSD: history.c,v 1.44 2016/10/13 20:51:25 fcambus Exp $    */
1.1       jfb         2: /*
1.28      joris       3:  * Copyright (c) 2007 Joris Vink <joris@openbsd.org>
1.1       jfb         4:  *
1.28      joris       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.
1.1       jfb         8:  *
1.28      joris       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.28      joris      18: #include <sys/stat.h>
                     19:
                     20: #include <ctype.h>
                     21: #include <errno.h>
1.39      tobias     22: #include <fcntl.h>
1.28      joris      23: #include <pwd.h>
                     24: #include <stdlib.h>
                     25: #include <string.h>
1.45    ! okan       26: #include <time.h>
1.28      joris      27: #include <unistd.h>
1.1       jfb        28:
                     29: #include "cvs.h"
1.28      joris      30: #include "remote.h"
1.1       jfb        31:
1.28      joris      32: void   cvs_history_local(struct cvs_file *);
1.1       jfb        33:
1.38      tobias     34: static void    history_compress(char *, const char *);
                     35:
1.28      joris      36: struct cvs_cmd         cvs_cmd_history = {
1.35      tobias     37:        CVS_OP_HISTORY, CVS_USE_WDIR, "history",
1.29      xsa        38:        { "hi", "his" },                        /* omghi2you */
1.34      tobias     39:        "Display history of actions done in the base repository",
1.28      joris      40:        "[-ac]",
                     41:        "ac",
1.14      jfb        42:        NULL,
1.28      joris      43:        cvs_history
                     44: };
                     45:
                     46: /* keep in sync with the defines for history stuff in cvs.h */
                     47: const char historytab[] = {
                     48:        'T',
                     49:        'O',
                     50:        'E',
                     51:        'F',
                     52:        'W',
                     53:        'U',
                     54:        'G',
                     55:        'C',
                     56:        'M',
                     57:        'A',
                     58:        'R',
1.33      ray        59:        '\0'
1.9       joris      60: };
                     61:
1.28      joris      62: #define HISTORY_ALL_USERS              0x01
                     63: #define HISTORY_DISPLAY_ARCHIVED       0x02
1.1       jfb        64:
1.28      joris      65: void
                     66: cvs_history_add(int type, struct cvs_file *cf, const char *argument)
1.1       jfb        67: {
1.37      tobias     68:        BUF *buf;
1.28      joris      69:        FILE *fp;
1.38      tobias     70:        RCSNUM *hrev;
                     71:        size_t len;
1.39      tobias     72:        int fd;
1.38      tobias     73:        char *cwd, *p, *rev;
1.42      deraadt    74:        char revbuf[CVS_REV_BUFSZ], repo[PATH_MAX], fpath[PATH_MAX];
1.37      tobias     75:        char timebuf[CVS_TIME_BUFSZ];
                     76:        struct tm datetm;
1.1       jfb        77:
1.28      joris      78:        if (cvs_nolog == 1)
                     79:                return;
1.19      xsa        80:
1.28      joris      81:        if (cvs_cmdop == CVS_OP_CHECKOUT || cvs_cmdop == CVS_OP_EXPORT) {
                     82:                if (type != CVS_HISTORY_CHECKOUT &&
                     83:                    type != CVS_HISTORY_EXPORT)
                     84:                        return;
1.1       jfb        85:        }
                     86:
1.28      joris      87:        cvs_log(LP_TRACE, "cvs_history_add(`%c', `%s', `%s')",
                     88:            historytab[type], (cf != NULL) ? cf->file_name : "", argument);
1.1       jfb        89:
1.38      tobias     90:        /* construct repository field */
                     91:        if (cvs_cmdop != CVS_OP_CHECKOUT && cvs_cmdop != CVS_OP_EXPORT) {
                     92:                cvs_get_repository_name((cf != NULL) ? cf->file_wd : ".",
                     93:                    repo, sizeof(repo));
                     94:        } else {
                     95:                cvs_get_repository_name(argument, repo, sizeof(repo));
                     96:        }
                     97:
1.30      joris      98:        if (cvs_server_active == 1) {
                     99:                cwd = "<remote>";
                    100:        } else {
1.38      tobias    101:                if (getcwd(fpath, sizeof(fpath)) == NULL)
1.30      joris     102:                        fatal("cvs_history_add: getcwd: %s", strerror(errno));
1.38      tobias    103:                p = fpath;
                    104:                if (cvs_cmdop == CVS_OP_CHECKOUT ||
                    105:                    cvs_cmdop == CVS_OP_EXPORT) {
                    106:                        if (strlcat(fpath, "/", sizeof(fpath)) >=
                    107:                            sizeof(fpath) || strlcat(fpath, argument,
                    108:                            sizeof(fpath)) >= sizeof(fpath))
                    109:                                fatal("cvs_history_add: string truncation");
                    110:                }
                    111:                if (cvs_homedir != NULL && cvs_homedir[0] != '\0') {
                    112:                        len = strlen(cvs_homedir);
                    113:                        if (strncmp(cvs_homedir, fpath, len) == 0 &&
                    114:                            fpath[len] == '/') {
                    115:                                p += len - 1;
                    116:                                *p = '~';
                    117:                        }
                    118:                }
1.1       jfb       119:
1.38      tobias    120:                history_compress(p, repo);
                    121:                cwd = xstrdup(p);
1.28      joris     122:        }
1.24      joris     123:
1.28      joris     124:        /* construct revision field */
                    125:        revbuf[0] = '\0';
1.37      tobias    126:        rev = revbuf;
                    127:        switch (type) {
                    128:        case CVS_HISTORY_TAG:
                    129:                strlcpy(revbuf, argument, sizeof(revbuf));
                    130:                break;
                    131:        case CVS_HISTORY_CHECKOUT:
                    132:        case CVS_HISTORY_EXPORT:
                    133:                /*
1.40      ray       134:                 * buf_alloc uses xcalloc(), so we are safe even
1.37      tobias    135:                 * if neither cvs_specified_tag nor cvs_specified_date
                    136:                 * have been supplied.
                    137:                 */
1.40      ray       138:                buf = buf_alloc(128);
1.37      tobias    139:                if (cvs_specified_tag != NULL) {
1.40      ray       140:                        buf_puts(buf, cvs_specified_tag);
1.37      tobias    141:                        if (cvs_specified_date != -1)
1.40      ray       142:                                buf_putc(buf, ':');
1.37      tobias    143:                }
                    144:                if (cvs_specified_date != -1) {
                    145:                        gmtime_r(&cvs_specified_date, &datetm);
                    146:                        strftime(timebuf, sizeof(timebuf),
                    147:                            "%Y.%m.%d.%H.%M.%S", &datetm);
1.40      ray       148:                        buf_puts(buf, timebuf);
1.15      xsa       149:                }
1.40      ray       150:                rev = buf_release(buf);
1.37      tobias    151:                break;
                    152:        case CVS_HISTORY_UPDATE_MERGED:
                    153:        case CVS_HISTORY_UPDATE_MERGED_ERR:
                    154:        case CVS_HISTORY_COMMIT_MODIFIED:
                    155:        case CVS_HISTORY_COMMIT_ADDED:
                    156:        case CVS_HISTORY_COMMIT_REMOVED:
                    157:        case CVS_HISTORY_UPDATE_CO:
1.38      tobias    158:                if ((hrev = rcs_head_get(cf->file_rcs)) == NULL)
                    159:                        fatal("cvs_history_add: rcs_head_get failed");
                    160:                rcsnum_tostr(hrev, revbuf, sizeof(revbuf));
1.44      fcambus   161:                free(hrev);
1.37      tobias    162:                break;
1.28      joris     163:        }
1.20      joris     164:
1.28      joris     165:        (void)xsnprintf(fpath, sizeof(fpath), "%s/%s",
                    166:            current_cvsroot->cr_dir, CVS_PATH_HISTORY);
1.20      joris     167:
1.39      tobias    168:        if ((fd = open(fpath, O_WRONLY|O_APPEND)) == -1) {
                    169:                if (errno != ENOENT)
                    170:                        cvs_log(LP_ERR, "failed to open history file");
1.28      joris     171:        } else {
1.39      tobias    172:                if ((fp = fdopen(fd, "a")) != NULL) {
1.41      zhuk      173:                        fprintf(fp, "%c%08llx|%s|%s|%s|%s|%s\n",
                    174:                            historytab[type], (long long)time(NULL),
                    175:                            getlogin(), cwd, repo, rev,
                    176:                            (cf != NULL) ? cf->file_name : argument);
1.39      tobias    177:                        (void)fclose(fp);
                    178:                } else {
                    179:                        cvs_log(LP_ERR, "failed to add entry to history file");
                    180:                        (void)close(fd);
                    181:                }
1.15      xsa       182:        }
1.1       jfb       183:
1.37      tobias    184:        if (rev != revbuf)
1.43      nicm      185:                free(rev);
1.30      joris     186:        if (cvs_server_active != 1)
1.43      nicm      187:                free(cwd);
1.38      tobias    188: }
                    189:
                    190: static void
                    191: history_compress(char *wdir, const char *repo)
                    192: {
                    193:        char *p;
                    194:        const char *q;
                    195:        size_t repo_len, wdir_len;
                    196:
                    197:        repo_len = strlen(repo);
                    198:        wdir_len = strlen(wdir);
                    199:
                    200:        p = wdir + wdir_len;
                    201:        q = repo + repo_len;
                    202:
                    203:        while (p >= wdir && q >= repo) {
                    204:                if (*p != *q)
                    205:                        break;
                    206:                p--;
                    207:                q--;
                    208:        }
                    209:        p++;
                    210:        q++;
                    211:
                    212:        /* if it's not worth the effort, skip compression */
                    213:        if (repo + repo_len - q < 3)
                    214:                return;
                    215:
                    216:        (void)xsnprintf(p, strlen(p) + 1, "*%zx", q - repo);
1.1       jfb       217: }
                    218:
1.28      joris     219: int
                    220: cvs_history(int argc, char **argv)
                    221: {
                    222:        int ch, flags;
1.1       jfb       223:
1.28      joris     224:        flags = 0;
1.1       jfb       225:
1.28      joris     226:        while ((ch = getopt(argc, argv, cvs_cmd_history.cmd_opts)) != -1) {
                    227:                switch (ch) {
                    228:                case 'a':
                    229:                        flags |= HISTORY_ALL_USERS;
                    230:                        break;
                    231:                case 'c':
                    232:                        flags |= HISTORY_DISPLAY_ARCHIVED;
                    233:                        break;
                    234:                default:
                    235:                        fatal("%s", cvs_cmd_history.cmd_synopsis);
                    236:                }
1.1       jfb       237:        }
                    238:
1.28      joris     239:        argc -= optind;
                    240:        argv += optind;
                    241:
                    242:        return (0);
1.1       jfb       243: }