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

Annotation of src/usr.bin/cvs/trigger.c, Revision 1.1

1.1     ! joris       1: /*     $OpenBSD$       */
        !             2: /*
        !             3:  * Copyright (c) 2008 Tobias Stoeckmann <tobias@openbsd.org>
        !             4:  * Copyright (c) 2008 Jonathan Armani <dbd@asystant.net>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: #include <sys/queue.h>
        !            20: #include <sys/types.h>
        !            21:
        !            22: #include <ctype.h>
        !            23: #include <errno.h>
        !            24: #include <regex.h>
        !            25: #include <stdio.h>
        !            26: #include <stdlib.h>
        !            27: #include <string.h>
        !            28: #include <unistd.h>
        !            29:
        !            30: #include "config.h"
        !            31: #include "cvs.h"
        !            32:
        !            33: static int      expand_args(BUF *, struct file_info_list *, const char *,
        !            34:     const char *, char *);
        !            35: static char    *parse_cmd(int, char *, const char *, struct file_info_list *);
        !            36:
        !            37: static int
        !            38: expand_args(BUF *buf, struct file_info_list *file_info, const char *repo,
        !            39:     const char *allowed_args, char *format)
        !            40: {
        !            41:        int oldstyle, quote;
        !            42:        struct file_info *fi = NULL;
        !            43:        char *p, valbuf[2] = { '\0', '\0' };
        !            44:        const char *val;
        !            45:
        !            46:        if (file_info != NULL && !TAILQ_EMPTY(file_info))
        !            47:                fi = TAILQ_FIRST(file_info);
        !            48:
        !            49:        quote = oldstyle = 0;
        !            50:
        !            51:        /* Why does GNU cvs print something if it encounters %{}? */
        !            52:        if (*format == '\0')
        !            53:                oldstyle = 1;
        !            54:
        !            55:        for (p = format; *p != '\0'; p++) {
        !            56:                if (*p != '%' && strchr(allowed_args, *p) == NULL)
        !            57:                        return 1;
        !            58:
        !            59:                switch (*p) {
        !            60:                case 's':
        !            61:                case 'V':
        !            62:                case 'v':
        !            63:                        quote = 1;
        !            64:                        oldstyle = 1;
        !            65:                        break;
        !            66:                default:
        !            67:                        break;
        !            68:                }
        !            69:        }
        !            70:        if (quote)
        !            71:                cvs_buf_putc(buf, '"');
        !            72:        if (oldstyle) {
        !            73:                cvs_buf_append(buf, repo, strlen(repo));
        !            74:                cvs_buf_putc(buf, ' ');
        !            75:        }
        !            76:
        !            77:        if (*format == '\0')
        !            78:                return 0;
        !            79:
        !            80:        for (;;) {
        !            81:                for (p = format; *p != '\0';) {
        !            82:                        val = NULL;
        !            83:
        !            84:                        switch (*p) {
        !            85:                        case '%':
        !            86:                                val = "%";
        !            87:                                break;
        !            88:                        case 'b':
        !            89:                                if (fi != NULL) {
        !            90:                                        valbuf[0] = fi->tag_type;
        !            91:                                        val = valbuf;
        !            92:                                }
        !            93:                                break;
        !            94:                        case 'o':
        !            95:                                if (fi != NULL)
        !            96:                                        val = fi->tag_op;
        !            97:                                break;
        !            98:                        case 'p':
        !            99:                                val = current_cvsroot->cr_dir;
        !           100:                                break;
        !           101:                        case 'r':
        !           102:                                val = repo;
        !           103:                                break;
        !           104:                        case 'l':
        !           105:                        case 'S':
        !           106:                        case 's':
        !           107:                                if (fi != NULL)
        !           108:                                        val = fi->file_path;
        !           109:                                break;
        !           110:                        case 't':
        !           111:                                if (fi != NULL)
        !           112:                                        val = fi->tag_new;
        !           113:                                break;
        !           114:                        case 'V':
        !           115:                                if (fi != NULL)
        !           116:                                        val = fi->crevstr;
        !           117:                                break;
        !           118:                        case 'v':
        !           119:                                if (fi != NULL)
        !           120:                                        val = fi->nrevstr;
        !           121:                                break;
        !           122:                        default:
        !           123:                                return 1;
        !           124:                        }
        !           125:
        !           126:                        if (val != NULL)
        !           127:                                cvs_buf_append(buf, val, strlen(val));
        !           128:
        !           129:                        if (*(++p) != '\0')
        !           130:                                cvs_buf_putc(buf, ',');
        !           131:                }
        !           132:
        !           133:                if (fi != NULL)
        !           134:                        fi = TAILQ_NEXT(fi, flist);
        !           135:                if (fi == NULL)
        !           136:                        break;
        !           137:
        !           138:                if (strlen(format) == 1 && (*format == '%' || *format == 'o' ||
        !           139:                    *format == 'p' || *format == 'r' || *format == 't'))
        !           140:                        break;
        !           141:
        !           142:                cvs_buf_putc(buf, ' ');
        !           143:        }
        !           144:
        !           145:        if (quote)
        !           146:                cvs_buf_putc(buf, '"');
        !           147:
        !           148:        return 0;
        !           149: }
        !           150:
        !           151: static char *
        !           152: parse_cmd(int type, char *cmd, const char *repo,
        !           153:     struct file_info_list *file_info)
        !           154: {
        !           155:        int expanded = 0;
        !           156:        char argbuf[2] = { '\0', '\0' };
        !           157:        char *allowed_args, *default_args, *args, *p, *q = NULL;
        !           158:        size_t pos;
        !           159:        BUF *buf;
        !           160:
        !           161:        switch (type) {
        !           162:        case CVS_TRIGGER_COMMITINFO:
        !           163:                allowed_args = "prsS{}";
        !           164:                default_args = " %p/%r %S";
        !           165:                break;
        !           166:        case CVS_TRIGGER_LOGINFO:
        !           167:                allowed_args = "prsSvV{}";
        !           168:                default_args = NULL;
        !           169:                break;
        !           170:        case CVS_TRIGGER_VERIFYMSG:
        !           171:                allowed_args = "l";
        !           172:                default_args = " %l";
        !           173:                break;
        !           174:        case CVS_TRIGGER_TAGINFO:
        !           175:                allowed_args = "btoprsSvV{}";
        !           176:                default_args = " %t %o %p/%r %{sv}";
        !           177:                break;
        !           178:        default:
        !           179:                return (NULL);
        !           180:        }
        !           181:
        !           182:        /* XXX move this out of this function */
        !           183:        /* before doing any stuff, check if the command starts with % */
        !           184:        for (p = cmd; *p != '%' && !isspace(*p) && *p != '\0'; p++)
        !           185:                ;
        !           186:        if (*p == '%')
        !           187:                return (NULL);
        !           188:
        !           189:        buf = cvs_buf_alloc(1024);
        !           190:
        !           191:        p = cmd;
        !           192: again:
        !           193:        for (; *p != '\0'; p++) {
        !           194:                if ((pos = strcspn(p, "%")) != 0) {
        !           195:                        cvs_buf_append(buf, p, pos);
        !           196:                        p += pos;
        !           197:                }
        !           198:
        !           199:                if (*p++ == '\0')
        !           200:                        break;
        !           201:
        !           202:                q = NULL;
        !           203:                switch (*p) {
        !           204:                case '\0':
        !           205:                        goto bad;
        !           206:                case '{':
        !           207:                        /* XXX do we realy have to check for { in there? */
        !           208:                        if (strchr(allowed_args, '{') == NULL)
        !           209:                                goto bad;
        !           210:                        pos = strcspn(++p, "}");
        !           211:                        if (p[pos] == '\0')
        !           212:                                goto bad;
        !           213:                        q = xmalloc(pos + 1);
        !           214:                        memcpy(q, p, pos);
        !           215:                        q[pos] = '\0';
        !           216:                        args = q;
        !           217:                        p += pos;
        !           218:                        break;
        !           219:                default:
        !           220:                        argbuf[0] = *p;
        !           221:                        args = argbuf;
        !           222:                        break;
        !           223:                }
        !           224:
        !           225:                if (expand_args(buf, file_info, repo, allowed_args, args))
        !           226:                        goto bad;
        !           227:                expanded = 1;
        !           228:
        !           229:                if (q != NULL)
        !           230:                        xfree(q);
        !           231:        }
        !           232:
        !           233:        if (!expanded && default_args != NULL) {
        !           234:                p = default_args;
        !           235:                expanded = 1;
        !           236:                goto again;
        !           237:        }
        !           238:
        !           239:        cvs_buf_putc(buf, '\0');
        !           240:        return (cvs_buf_release(buf));
        !           241:
        !           242: bad:
        !           243:        if (q != NULL)
        !           244:                xfree(q);
        !           245:        cvs_log(LP_NOTICE, "CVSROOT: malformed line %s", cmd);
        !           246:        cvs_buf_free(buf);
        !           247:        return (NULL);
        !           248: }
        !           249:
        !           250: int
        !           251: cvs_trigger_handle(int type, char *repo, char *in, struct trigger_list *list,
        !           252:     struct file_info_list *files)
        !           253: {
        !           254:        int r;
        !           255:        char *cmd;
        !           256:        struct trigger_line *line;
        !           257:
        !           258:        TAILQ_FOREACH(line, list, flist) {
        !           259:                cmd = parse_cmd(type, line->line, repo, files);
        !           260:                if (cmd != NULL) {
        !           261:                        switch(type) {
        !           262:                        case CVS_TRIGGER_COMMITINFO:
        !           263:                        case CVS_TRIGGER_TAGINFO:
        !           264:                        case CVS_TRIGGER_VERIFYMSG:
        !           265:                                if ((r = cvs_exec(cmd, NULL, 1)) != 0) {
        !           266:                                        xfree(cmd);
        !           267:                                        return r;
        !           268:                                }
        !           269:                                break;
        !           270:                        default:
        !           271:                                (void)cvs_exec(cmd, in, 1);
        !           272:                                break;
        !           273:                        }
        !           274:                        xfree(cmd);
        !           275:                }
        !           276:        }
        !           277:
        !           278:        return 0;
        !           279: }
        !           280:
        !           281: struct trigger_list *
        !           282: cvs_trigger_getlines(char * file, char * repo)
        !           283: {
        !           284:        FILE *fp;
        !           285:        int allow_all, lineno, match = 0;
        !           286:        size_t len;
        !           287:        regex_t preg;
        !           288:        struct trigger_list *list;
        !           289:        struct trigger_line *tline;
        !           290:        char fpath[MAXPATHLEN];
        !           291:        char *currentline, *defaultline = NULL, *nline, *p, *q, *regex;
        !           292:
        !           293:        list = xmalloc(sizeof(*list));
        !           294:        TAILQ_INIT(list);
        !           295:
        !           296:        if (strcmp(file, CVS_PATH_EDITINFO) == 0 ||
        !           297:            strcmp(file, CVS_PATH_VERIFYMSG) == 0)
        !           298:                allow_all = 0;
        !           299:        else
        !           300:                allow_all = 1;
        !           301:
        !           302:        (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", current_cvsroot->cr_dir,
        !           303:            file);
        !           304:
        !           305:        if ((fp = fopen(fpath, "r")) == NULL) {
        !           306:                if (errno != ENOENT)
        !           307:                        cvs_log(LP_ERRNO, "cvs_trigger_getlines: %s", file);
        !           308:                return (NULL);
        !           309:        }
        !           310:
        !           311:        lineno = 0;
        !           312:        nline = NULL;
        !           313:        while ((currentline = fgetln(fp, &len)) != NULL)
        !           314:        {
        !           315:                if (currentline[len - 1] == '\n') {
        !           316:                        currentline[len - 1] = '\0';
        !           317:                } else {
        !           318:                        nline = xmalloc(len + 1);
        !           319:                        memcpy(nline, currentline, len);
        !           320:                        nline[len] = '\0';
        !           321:                        currentline = nline;
        !           322:                }
        !           323:
        !           324:                lineno++;
        !           325:
        !           326:                for (p = currentline; isspace(*p); p++)
        !           327:                        ;
        !           328:
        !           329:                if (*p == '\0' || *p == '#')
        !           330:                        continue;
        !           331:
        !           332:                for (q = p; !isspace(*q) && *q != '\0'; q++)
        !           333:                        ;
        !           334:
        !           335:                if (*q == '\0')
        !           336:                        goto bad;
        !           337:
        !           338:                /* XXX why do you check *p (regex)? */
        !           339:                if (*p == '%')
        !           340:                        goto bad;
        !           341:
        !           342:                *q++ = '\0';
        !           343:                regex = p;
        !           344:
        !           345:                for (; isspace(*q); q++)
        !           346:                        ;
        !           347:
        !           348:                if (*q == '\0')
        !           349:                        goto bad;
        !           350:
        !           351:                if (strcmp(regex, "ALL") == 0 && allow_all) {
        !           352:                        tline = xmalloc(sizeof(*tline));
        !           353:                        tline->line = xstrdup(q);
        !           354:                        TAILQ_INSERT_TAIL(list, tline, flist);
        !           355:                } else if (defaultline == NULL && !match &&
        !           356:                    strcmp(regex, "DEFAULT") == 0) {
        !           357:                        defaultline = xstrdup(q);
        !           358:                } else if (!match) {
        !           359:                        if (regcomp(&preg, regex, REG_NOSUB|REG_EXTENDED))
        !           360:                                goto bad;
        !           361:
        !           362:                        if (regexec(&preg, repo, 0, NULL, 0) != REG_NOMATCH) {
        !           363:                                match = 1;
        !           364:
        !           365:                                tline = xmalloc(sizeof(*tline));
        !           366:                                tline->line = xstrdup(q);
        !           367:                                TAILQ_INSERT_HEAD(list, tline, flist);
        !           368:                        }
        !           369:                        regfree(&preg);
        !           370:                }
        !           371:        }
        !           372:        if (nline != NULL)
        !           373:                xfree(nline);
        !           374:
        !           375:        if (defaultline != NULL) {
        !           376:                if (!match) {
        !           377:                        tline = xmalloc(sizeof(*tline));
        !           378:                        tline->line = defaultline;
        !           379:                        TAILQ_INSERT_HEAD(list, tline, flist);
        !           380:                } else
        !           381:                        xfree(defaultline);
        !           382:        }
        !           383:
        !           384:        if (TAILQ_EMPTY(list)) {
        !           385:                xfree(list);
        !           386:                list = NULL;
        !           387:        }
        !           388:
        !           389:        return (list);
        !           390:
        !           391: bad:
        !           392:        cvs_log(LP_NOTICE, "%s: malformed line %d", file, lineno);
        !           393:
        !           394:        if (defaultline != NULL)
        !           395:                xfree(defaultline);
        !           396:        cvs_trigger_freelist(list);
        !           397:
        !           398:        return (NULL);
        !           399: }
        !           400:
        !           401: void
        !           402: cvs_trigger_freelist(struct trigger_list * list)
        !           403: {
        !           404:        struct trigger_line *line;
        !           405:
        !           406:        while ((line = TAILQ_FIRST(list)) != NULL) {
        !           407:                TAILQ_REMOVE(list, line, flist);
        !           408:                xfree(line->line);
        !           409:                xfree(line);
        !           410:        }
        !           411:
        !           412:        xfree(list);
        !           413: }
        !           414:
        !           415: void
        !           416: cvs_trigger_freeinfo(struct file_info_list * list)
        !           417: {
        !           418:        struct file_info * fi;
        !           419:
        !           420:        while ((fi = TAILQ_FIRST(list)) != NULL) {
        !           421:                TAILQ_REMOVE(list, fi, flist);
        !           422:
        !           423:                if (fi->file_path != NULL)
        !           424:                        xfree(fi->file_path);
        !           425:                if (fi->file_wd != NULL)
        !           426:                        xfree(fi->file_wd);
        !           427:                if (fi->crevstr != NULL)
        !           428:                        xfree(fi->crevstr);
        !           429:                if (fi->nrevstr != NULL)
        !           430:                        xfree(fi->nrevstr);
        !           431:                if (fi->tag_new != NULL)
        !           432:                        xfree(fi->tag_new);
        !           433:                if (fi->tag_old != NULL)
        !           434:                        xfree(fi->tag_old);
        !           435:
        !           436:                xfree(fi);
        !           437:        }
        !           438: }
        !           439:
        !           440: void
        !           441: cvs_trigger_loginfo_header(BUF *buf, char *repo)
        !           442: {
        !           443:        char *dir, pwd[MAXPATHLEN];
        !           444:        char hostname[MAXHOSTNAMELEN];
        !           445:
        !           446:        if (gethostname(hostname, sizeof(hostname)) == -1) {
        !           447:                fatal("cvs_trigger_loginfo_header: gethostname failed %s",
        !           448:                    strerror(errno));
        !           449:        }
        !           450:
        !           451:        if (getcwd(pwd, sizeof(pwd)) == NULL)
        !           452:                fatal("cvs_trigger_loginfo_header: Cannot get working "
        !           453:                    "directory");
        !           454:
        !           455:        if ((dir = dirname(pwd)) == NULL) {
        !           456:                fatal("cvs_trigger_loginfo_header: dirname failed %s",
        !           457:                    strerror(errno));
        !           458:        }
        !           459:
        !           460:        cvs_buf_puts(buf, "Update of ");
        !           461:        cvs_buf_puts(buf, current_cvsroot->cr_dir);
        !           462:        cvs_buf_putc(buf, '/');
        !           463:        cvs_buf_puts(buf, repo);
        !           464:        cvs_buf_putc(buf, '\n');
        !           465:
        !           466:        cvs_buf_puts(buf, "In directory ");
        !           467:        cvs_buf_puts(buf, hostname);
        !           468:        cvs_buf_puts(buf, ":");
        !           469:        cvs_buf_puts(buf, dirname(pwd));
        !           470:        cvs_buf_putc(buf, '/');
        !           471:        cvs_buf_puts(buf, repo);
        !           472:        cvs_buf_putc(buf, '\n');
        !           473:        cvs_buf_putc(buf, '\n');
        !           474: }
        !           475: