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

Annotation of src/usr.bin/cvs/server.c, Revision 1.42

1.42    ! xsa         1: /*     $OpenBSD: server.c,v 1.41 2006/12/04 09:51:21 xsa Exp $ */
1.1       jfb         2: /*
1.29      joris       3:  * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
1.1       jfb         4:  *
1.29      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.29      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.27      xsa        18: #include "includes.h"
1.1       jfb        19:
                     20: #include "cvs.h"
                     21: #include "log.h"
1.29      joris      22: #include "diff.h"
                     23: #include "remote.h"
                     24:
                     25: struct cvs_resp cvs_responses[] = {
                     26:        /* this is what our server uses, the client should support it */
                     27:        { "Valid-requests",     1,      cvs_client_validreq, RESP_NEEDED },
                     28:        { "ok",                 0,      cvs_client_ok, RESP_NEEDED},
                     29:        { "error",              0,      cvs_client_error, RESP_NEEDED },
                     30:        { "E",                  0,      cvs_client_e, RESP_NEEDED },
                     31:        { "M",                  0,      cvs_client_m, RESP_NEEDED },
                     32:        { "Checked-in",         0,      cvs_client_checkedin, RESP_NEEDED },
                     33:        { "Updated",            0,      cvs_client_updated, RESP_NEEDED },
                     34:        { "Merged",             0,      cvs_client_merged, RESP_NEEDED },
                     35:        { "Removed",            0,      cvs_client_removed, RESP_NEEDED },
                     36:        { "Remove-entry",       0,      cvs_client_remove_entry, RESP_NEEDED },
                     37:
                     38:        /* unsupported responses until told otherwise */
                     39:        { "New-entry",                  0,      NULL, 0 },
                     40:        { "Created",                    0,      NULL, 0 },
                     41:        { "Update-existing",            0,      NULL, 0 },
                     42:        { "Rcs-diff",                   0,      NULL, 0 },
                     43:        { "Patched",                    0,      NULL, 0 },
                     44:        { "Mode",                       0,      NULL, 0 },
                     45:        { "Mod-time",                   0,      NULL, 0 },
                     46:        { "Checksum",                   0,      NULL, 0 },
                     47:        { "Copy-file",                  0,      NULL, 0 },
                     48:        { "Set-static-directory",       0,      NULL, 0 },
                     49:        { "Clear-static-directory",     0,      NULL, 0 },
                     50:        { "Set-sticky",                 0,      NULL, 0 },
                     51:        { "Clear-sticky",               0,      NULL, 0 },
                     52:        { "Template",                   0,      NULL, 0 },
                     53:        { "Set-checkin-prog",           0,      NULL, 0 },
                     54:        { "Set-update-prog",            0,      NULL, 0 },
                     55:        { "Notified",                   0,      NULL, 0 },
                     56:        { "Module-expansion",           0,      NULL, 0 },
                     57:        { "Wrapper-rcsOption",          0,      NULL, 0 },
                     58:        { "Mbinary",                    0,      NULL, 0 },
                     59:        { "F",                          0,      NULL, 0 },
                     60:        { "MT",                         0,      NULL, 0 },
                     61:        { "",                           -1,     NULL, 0 }
                     62: };
1.1       jfb        63:
1.29      joris      64: int    cvs_server(int, char **);
                     65: char   *cvs_server_path = NULL;
1.1       jfb        66:
1.29      joris      67: static char *server_currentdir = NULL;
                     68: static char *server_argv[CVS_CMD_MAXARG];
                     69: static int server_argc = 1;
1.8       joris      70:
1.17      jfb        71: struct cvs_cmd cvs_cmd_server = {
1.29      joris      72:        CVS_OP_SERVER, 0, "server", { "", "" },
                     73:        "server mode",
1.17      jfb        74:        NULL,
1.29      joris      75:        NULL,
                     76:        NULL,
                     77:        cvs_server
1.17      jfb        78: };
1.1       jfb        79:
1.14      joris      80:
1.1       jfb        81: int
                     82: cvs_server(int argc, char **argv)
                     83: {
1.29      joris      84:        int l;
                     85:        char *cmd, *data;
                     86:        struct cvs_req *req;
                     87:
                     88:        server_argv[0] = xstrdup("server");
                     89:
                     90:        cvs_server_path = xmalloc(MAXPATHLEN);
                     91:        l = snprintf(cvs_server_path, MAXPATHLEN, "%s/cvs-serv%d",
                     92:            cvs_tmpdir, getpid());
                     93:        if (l == -1 || l >= MAXPATHLEN)
                     94:                fatal("cvs_server: overflow in server path");
                     95:
                     96:        if (mkdir(cvs_server_path, 0700) == -1)
                     97:                fatal("failed to create temporary server directory: %s, %s",
                     98:                    cvs_server_path, strerror(errno));
                     99:
                    100:        if (chdir(cvs_server_path) == -1)
                    101:                fatal("failed to change directory to '%s'", cvs_server_path);
                    102:
                    103:        for (;;) {
                    104:                cmd = cvs_remote_input();
                    105:
                    106:                if ((data = strchr(cmd, ' ')) != NULL)
                    107:                        (*data++) = '\0';
                    108:
                    109:                req = cvs_remote_get_request_info(cmd);
                    110:                if (req == NULL)
                    111:                        fatal("request '%s' is not supported by our server",
                    112:                            cmd);
                    113:
                    114:                if (req->hdlr == NULL)
                    115:                        fatal("opencvs server does not support '%s'", cmd);
                    116:
                    117:                (*req->hdlr)(data);
                    118:                xfree(cmd);
1.14      joris     119:        }
                    120:
1.29      joris     121:        return (0);
                    122: }
                    123:
                    124: void
                    125: cvs_server_send_response(char *fmt, ...)
                    126: {
                    127:        va_list ap;
                    128:        char *data, *s;
                    129:        struct cvs_resp *resp;
                    130:
                    131:        va_start(ap, fmt);
                    132:        vasprintf(&data, fmt, ap);
                    133:        va_end(ap);
                    134:
                    135:        if ((s = strchr(data, ' ')) != NULL)
                    136:                *s = '\0';
                    137:
                    138:        resp = cvs_remote_get_response_info(data);
                    139:        if (resp == NULL)
                    140:                fatal("'%s' is an unknown response", data);
                    141:
                    142:        if (resp->supported != 1)
                    143:                fatal("remote cvs client does not support '%s'", data);
1.14      joris     144:
1.29      joris     145:        if (s != NULL)
                    146:                *s = ' ';
1.14      joris     147:
1.30      joris     148:        cvs_log(LP_TRACE, "%s", data);
1.29      joris     149:        cvs_remote_output(data);
                    150:        xfree(data);
                    151: }
                    152:
                    153: void
                    154: cvs_server_root(char *data)
                    155: {
                    156:        fatal("duplicate Root request from client, violates the protocol");
                    157: }
                    158:
                    159: void
                    160: cvs_server_validresp(char *data)
                    161: {
                    162:        int i;
                    163:        char *sp, *ep;
                    164:        struct cvs_resp *resp;
                    165:
                    166:        sp = data;
                    167:        do {
                    168:                if ((ep = strchr(sp, ' ')) != NULL)
                    169:                        *ep = '\0';
                    170:
                    171:                resp = cvs_remote_get_response_info(sp);
                    172:                if (resp != NULL)
                    173:                        resp->supported = 1;
                    174:
                    175:                if (ep != NULL)
                    176:                        sp = ep + 1;
                    177:        } while (ep != NULL);
                    178:
                    179:        for (i = 0; cvs_responses[i].supported != -1; i++) {
                    180:                resp = &cvs_responses[i];
                    181:                if ((resp->flags & RESP_NEEDED) &&
                    182:                    resp->supported != 1) {
                    183:                        fatal("client does not support required '%s'",
                    184:                            resp->name);
1.1       jfb       185:                }
1.29      joris     186:        }
                    187: }
1.1       jfb       188:
1.29      joris     189: void
                    190: cvs_server_validreq(char *data)
                    191: {
                    192:        BUF *bp;
                    193:        char *d;
                    194:        int i, first;
                    195:
                    196:        first = 0;
                    197:        bp = cvs_buf_alloc(512, BUF_AUTOEXT);
                    198:        for (i = 0; cvs_requests[i].supported != -1; i++) {
                    199:                if (cvs_requests[i].hdlr == NULL)
1.5       jfb       200:                        continue;
1.1       jfb       201:
1.29      joris     202:                if (first != 0)
                    203:                        cvs_buf_append(bp, " ", 1);
                    204:                else
                    205:                        first++;
                    206:
                    207:                cvs_buf_append(bp, cvs_requests[i].name,
                    208:                    strlen(cvs_requests[i].name));
                    209:        }
                    210:
                    211:        cvs_buf_putc(bp, '\0');
                    212:        d = cvs_buf_release(bp);
                    213:
                    214:        cvs_server_send_response("Valid-requests %s", d);
                    215:        cvs_server_send_response("ok");
                    216:        xfree(d);
1.42    ! xsa       217: }
        !           218:
        !           219: void
        !           220: cvs_server_sticky(char *data)
        !           221: {
        !           222:        FILE *fp;
        !           223:        char *tagpath;
        !           224:
        !           225:        tagpath = xmalloc(MAXPATHLEN);
        !           226:        if (cvs_path_cat(server_currentdir, CVS_PATH_TAG, tagpath,
        !           227:            MAXPATHLEN) >= MAXPATHLEN)
        !           228:                fatal("cvs_server_sticky: truncation");
        !           229:
        !           230:        if ((fp = fopen(tagpath ,"w+")) == NULL) {
        !           231:                cvs_log(LP_ERRNO, "%s", tagpath);
        !           232:                goto out;
        !           233:        }
        !           234:
        !           235:        (void)fprintf(fp, "%s\n", data);
        !           236:        (void)fclose(fp);
        !           237: out:
        !           238:        xfree(tagpath);
1.29      joris     239: }
                    240:
                    241: void
                    242: cvs_server_globalopt(char *data)
                    243: {
1.38      xsa       244:        if (!strcmp(data, "-l"))
                    245:                cvs_nolog = 1;
1.29      joris     246:
                    247:        if (!strcmp(data, "-n"))
                    248:                cvs_noexec = 1;
1.38      xsa       249:
                    250:        if (!strcmp(data, "-Q"))
                    251:                verbosity = 0;
                    252:
                    253:        if (!strcmp(data, "-r"))
                    254:                cvs_readonly = 1;
                    255:
                    256:        if (!strcmp(data, "-t"))
                    257:                cvs_trace = 1;
1.29      joris     258:
                    259:        if (!strcmp(data, "-V"))
                    260:                verbosity = 2;
1.39      xsa       261: }
                    262:
                    263: void
                    264: cvs_server_set(char *data)
                    265: {
                    266:        char *ep;
                    267:
                    268:        ep = strchr(data, '=');
                    269:        if (ep == NULL)
                    270:                fatal("no = in variable assignment");
                    271:
                    272:        *(ep++) = '\0';
                    273:        if (cvs_var_set(data, ep) < 0)
                    274:                fatal("cvs_server_set: cvs_var_set failed");
1.29      joris     275: }
1.1       jfb       276:
1.29      joris     277: void
                    278: cvs_server_directory(char *data)
                    279: {
                    280:        int l;
                    281:        CVSENTRIES *entlist;
                    282:        char *dir, *repo, *parent, *entry, *dirn;
                    283:
                    284:        dir = cvs_remote_input();
                    285:        if (strlen(dir) < strlen(current_cvsroot->cr_dir) + 1)
                    286:                fatal("cvs_server_directory: bad Directory request");
                    287:
                    288:        repo = dir + strlen(current_cvsroot->cr_dir) + 1;
                    289:        cvs_mkpath(repo);
                    290:
                    291:        if ((dirn = basename(repo)) == NULL)
                    292:                fatal("cvs_server_directory: %s", strerror(errno));
                    293:
                    294:        if ((parent = dirname(repo)) == NULL)
                    295:                fatal("cvs_server_directory: %s", strerror(errno));
                    296:
                    297:        if (strcmp(parent, ".")) {
                    298:                entlist = cvs_ent_open(parent);
                    299:                entry = xmalloc(CVS_ENT_MAXLINELEN);
                    300:                l = snprintf(entry, CVS_ENT_MAXLINELEN, "D/%s////", dirn);
                    301:                if (l == -1 || l >= CVS_ENT_MAXLINELEN)
                    302:                        fatal("cvs_server_directory: overflow");
                    303:
                    304:                cvs_ent_add(entlist, entry);
                    305:                cvs_ent_close(entlist, ENT_SYNC);
                    306:                xfree(entry);
1.1       jfb       307:        }
                    308:
1.29      joris     309:        if (server_currentdir != NULL)
                    310:                xfree(server_currentdir);
                    311:        server_currentdir = xstrdup(repo);
                    312:
                    313:        xfree(dir);
                    314: }
                    315:
                    316: void
                    317: cvs_server_entry(char *data)
                    318: {
                    319:        CVSENTRIES *entlist;
                    320:
                    321:        entlist = cvs_ent_open(server_currentdir);
                    322:        cvs_ent_add(entlist, data);
                    323:        cvs_ent_close(entlist, ENT_SYNC);
                    324: }
                    325:
                    326: void
                    327: cvs_server_modified(char *data)
                    328: {
                    329:        BUF *bp;
1.41      xsa       330:        int fd;
1.29      joris     331:        size_t flen;
                    332:        mode_t fmode;
                    333:        const char *errstr;
                    334:        char *mode, *len, *fpath;
                    335:
                    336:        mode = cvs_remote_input();
                    337:        len = cvs_remote_input();
                    338:
                    339:        cvs_strtomode(mode, &fmode);
                    340:        xfree(mode);
                    341:
                    342:        flen = strtonum(len, 0, INT_MAX, &errstr);
                    343:        if (errstr != NULL)
                    344:                fatal("cvs_server_modified: %s", errstr);
                    345:        xfree(len);
                    346:
                    347:        bp = cvs_remote_receive_file(flen);
                    348:
                    349:        fpath = xmalloc(MAXPATHLEN);
1.41      xsa       350:        if (cvs_path_cat(server_currentdir, data, fpath, MAXPATHLEN) >=
                    351:            MAXPATHLEN)
                    352:                fatal("cvs_server_modified: truncation");
1.29      joris     353:
                    354:        if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC)) == -1)
                    355:                fatal("cvs_server_modified: %s: %s", fpath, strerror(errno));
                    356:
                    357:        if (cvs_buf_write_fd(bp, fd) == -1)
                    358:                fatal("cvs_server_modified: failed to write file '%s'", fpath);
                    359:
                    360:        if (fchmod(fd, 0600) == -1)
                    361:                fatal("cvs_server_modified: failed to set file mode");
                    362:
                    363:        xfree(fpath);
                    364:        (void)close(fd);
                    365:        cvs_buf_free(bp);
                    366: }
                    367:
                    368: void
                    369: cvs_server_useunchanged(char *data)
                    370: {
                    371: }
                    372:
                    373: void
                    374: cvs_server_unchanged(char *data)
                    375: {
1.41      xsa       376:        int fd;
1.29      joris     377:        char *fpath;
                    378:        CVSENTRIES *entlist;
                    379:        struct cvs_ent *ent;
                    380:        struct timeval tv[2];
                    381:
                    382:        fpath = xmalloc(MAXPATHLEN);
1.41      xsa       383:        if (cvs_path_cat(server_currentdir, data, fpath, MAXPATHLEN) >=
                    384:            MAXPATHLEN)
                    385:                fatal("cvs_server_unchanged: truncation");
1.29      joris     386:
                    387:        if ((fd = open(fpath, O_RDWR | O_CREAT | O_TRUNC)) == -1)
                    388:                fatal("cvs_server_unchanged: %s: %s", fpath, strerror(errno));
                    389:
                    390:        entlist = cvs_ent_open(server_currentdir);
                    391:        ent = cvs_ent_get(entlist, data);
                    392:        if (ent == NULL)
                    393:                fatal("received Unchanged request for non-existing file");
                    394:        cvs_ent_close(entlist, ENT_NOSYNC);
                    395:
                    396:        tv[0].tv_sec = cvs_hack_time(ent->ce_mtime, 0);
                    397:        tv[0].tv_usec = 0;
                    398:        tv[1] = tv[0];
                    399:        if (futimes(fd, tv) == -1)
                    400:                fatal("cvs_server_unchanged: failed to set modified time");
                    401:
                    402:        if (fchmod(fd, 0600) == -1)
                    403:                fatal("cvs_server_unchanged: failed to set mode");
                    404:
                    405:        cvs_ent_free(ent);
                    406:        xfree(fpath);
                    407:        (void)close(fd);
                    408: }
                    409:
                    410: void
                    411: cvs_server_questionable(char *data)
                    412: {
                    413: }
                    414:
                    415: void
                    416: cvs_server_argument(char *data)
                    417: {
                    418:
                    419:        if (server_argc > CVS_CMD_MAXARG)
                    420:                fatal("cvs_server_argument: too many arguments sent");
                    421:
                    422:        server_argv[server_argc++] = xstrdup(data);
1.37      xsa       423: }
                    424:
                    425: void
                    426: cvs_server_argumentx(char *data)
                    427: {
1.29      joris     428: }
                    429:
                    430: void
1.31      xsa       431: cvs_server_add(char *data)
                    432: {
                    433:        if (chdir(server_currentdir) == -1)
                    434:                fatal("cvs_server_add: %s", strerror(errno));
                    435:
                    436:        cvs_cmdop = CVS_OP_ADD;
                    437:        cvs_add(server_argc, server_argv);
                    438:        cvs_server_send_response("ok");
                    439: }
1.35      xsa       440:
                    441: void
                    442: cvs_server_admin(char *data)
                    443: {
                    444:        if (chdir(server_currentdir) == -1)
                    445:                fatal("cvs_server_admin: %s", strerror(errno));
                    446:
                    447:        cvs_cmdop = CVS_OP_ADMIN;
                    448:        cvs_admin(server_argc, server_argv);
                    449:        cvs_server_send_response("ok");
                    450: }
                    451:
1.40      xsa       452: void
                    453: cvs_server_annotate(char *data)
                    454: {
                    455:        if (chdir(server_currentdir) == -1)
                    456:                fatal("cvs_server_annotate: %s", strerror(errno));
                    457:
                    458:        cvs_cmdop = CVS_OP_ANNOTATE;
                    459:        cvs_annotate(server_argc, server_argv);
                    460:        cvs_server_send_response("ok");
                    461: }
1.31      xsa       462:
                    463: void
1.29      joris     464: cvs_server_commit(char *data)
                    465: {
                    466:        if (chdir(server_currentdir) == -1)
                    467:                fatal("cvs_server_commit: %s", strerror(errno));
                    468:
                    469:        cvs_cmdop = CVS_OP_COMMIT;
                    470:        cvs_commit(server_argc, server_argv);
                    471:        cvs_server_send_response("ok");
                    472: }
                    473:
                    474: void
                    475: cvs_server_diff(char *data)
                    476: {
                    477:        if (chdir(server_currentdir) == -1)
                    478:                fatal("cvs_server_diff: %s", strerror(errno));
                    479:
                    480:        cvs_cmdop = CVS_OP_DIFF;
                    481:        cvs_diff(server_argc, server_argv);
1.34      xsa       482:        cvs_server_send_response("ok");
                    483: }
                    484:
                    485: void
                    486: cvs_server_init(char *data)
                    487: {
                    488:        if (chdir(server_currentdir) == -1)
                    489:                fatal("cvs_server_init: %s", strerror(errno));
                    490:
                    491:        cvs_cmdop = CVS_OP_INIT;
                    492:        cvs_init(server_argc, server_argv);
1.31      xsa       493:        cvs_server_send_response("ok");
                    494: }
                    495:
                    496: void
                    497: cvs_server_remove(char *data)
                    498: {
                    499:        if (chdir(server_currentdir) == -1)
                    500:                fatal("cvs_server_remove: %s", strerror(errno));
                    501:
                    502:        cvs_cmdop = CVS_OP_REMOVE;
                    503:        cvs_remove(server_argc, server_argv);
1.29      joris     504:        cvs_server_send_response("ok");
                    505: }
                    506:
                    507: void
                    508: cvs_server_status(char *data)
                    509: {
                    510:        if (chdir(server_currentdir) == -1)
                    511:                fatal("cvs_server_status: %s", strerror(errno));
                    512:
                    513:        cvs_cmdop = CVS_OP_STATUS;
                    514:        cvs_status(server_argc, server_argv);
                    515:        cvs_server_send_response("ok");
                    516: }
                    517:
                    518: void
                    519: cvs_server_log(char *data)
                    520: {
                    521:        if (chdir(server_currentdir) == -1)
                    522:                fatal("cvs_server_log: %s", strerror(errno));
                    523:
                    524:        cvs_cmdop = CVS_OP_LOG;
1.32      xsa       525:        cvs_getlog(server_argc, server_argv);
                    526:        cvs_server_send_response("ok");
                    527: }
                    528:
                    529: void
                    530: cvs_server_tag(char *data)
                    531: {
                    532:        if (chdir(server_currentdir) == -1)
                    533:                fatal("cvs_server_tag: %s", strerror(errno));
                    534:
                    535:        cvs_cmdop = CVS_OP_TAG;
1.33      xsa       536:        cvs_tag(server_argc, server_argv);
1.29      joris     537:        cvs_server_send_response("ok");
                    538: }
                    539:
                    540: void
                    541: cvs_server_update(char *data)
                    542: {
                    543:        if (chdir(server_currentdir) == -1)
                    544:                fatal("cvs_server_update: %s", strerror(errno));
1.14      joris     545:
1.29      joris     546:        cvs_cmdop = CVS_OP_UPDATE;
                    547:        cvs_update(server_argc, server_argv);
1.36      xsa       548:        cvs_server_send_response("ok");
                    549: }
                    550:
                    551: void
                    552: cvs_server_version(char *data)
                    553: {
                    554:        cvs_cmdop = CVS_OP_VERSION;
                    555:        cvs_version(server_argc, server_argv);
1.29      joris     556:        cvs_server_send_response("ok");
1.1       jfb       557: }