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

1.29    ! joris       1: /*     $OpenBSD$       */
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.29    ! joris     148:        cvs_remote_output(data);
        !           149:        xfree(data);
        !           150: }
        !           151:
        !           152: void
        !           153: cvs_server_root(char *data)
        !           154: {
        !           155:        fatal("duplicate Root request from client, violates the protocol");
        !           156: }
        !           157:
        !           158: void
        !           159: cvs_server_validresp(char *data)
        !           160: {
        !           161:        int i;
        !           162:        char *sp, *ep;
        !           163:        struct cvs_resp *resp;
        !           164:
        !           165:        sp = data;
        !           166:        do {
        !           167:                if ((ep = strchr(sp, ' ')) != NULL)
        !           168:                        *ep = '\0';
        !           169:
        !           170:                resp = cvs_remote_get_response_info(sp);
        !           171:                if (resp != NULL)
        !           172:                        resp->supported = 1;
        !           173:
        !           174:                if (ep != NULL)
        !           175:                        sp = ep + 1;
        !           176:        } while (ep != NULL);
        !           177:
        !           178:        for (i = 0; cvs_responses[i].supported != -1; i++) {
        !           179:                resp = &cvs_responses[i];
        !           180:                if ((resp->flags & RESP_NEEDED) &&
        !           181:                    resp->supported != 1) {
        !           182:                        fatal("client does not support required '%s'",
        !           183:                            resp->name);
1.1       jfb       184:                }
1.29    ! joris     185:        }
        !           186: }
1.1       jfb       187:
1.29    ! joris     188: void
        !           189: cvs_server_validreq(char *data)
        !           190: {
        !           191:        BUF *bp;
        !           192:        char *d;
        !           193:        int i, first;
        !           194:
        !           195:        first = 0;
        !           196:        bp = cvs_buf_alloc(512, BUF_AUTOEXT);
        !           197:        for (i = 0; cvs_requests[i].supported != -1; i++) {
        !           198:                if (cvs_requests[i].hdlr == NULL)
1.5       jfb       199:                        continue;
1.1       jfb       200:
1.29    ! joris     201:                if (first != 0)
        !           202:                        cvs_buf_append(bp, " ", 1);
        !           203:                else
        !           204:                        first++;
        !           205:
        !           206:                cvs_buf_append(bp, cvs_requests[i].name,
        !           207:                    strlen(cvs_requests[i].name));
        !           208:        }
        !           209:
        !           210:        cvs_buf_putc(bp, '\0');
        !           211:        d = cvs_buf_release(bp);
        !           212:
        !           213:        cvs_server_send_response("Valid-requests %s", d);
        !           214:        cvs_server_send_response("ok");
        !           215:        xfree(d);
        !           216: }
        !           217:
        !           218: void
        !           219: cvs_server_globalopt(char *data)
        !           220: {
        !           221:        if (!strcmp(data, "-t"))
        !           222:                cvs_trace = 1;
        !           223:
        !           224:        if (!strcmp(data, "-n"))
        !           225:                cvs_noexec = 1;
        !           226:
        !           227:        if (!strcmp(data, "-V"))
        !           228:                verbosity = 2;
1.1       jfb       229:
1.29    ! joris     230:        cvs_log(LP_TRACE, "cvs_server_globalopt(%s)", data);
        !           231: }
1.1       jfb       232:
1.29    ! joris     233: void
        !           234: cvs_server_directory(char *data)
        !           235: {
        !           236:        int l;
        !           237:        CVSENTRIES *entlist;
        !           238:        char *dir, *repo, *parent, *entry, *dirn;
        !           239:
        !           240:        cvs_log(LP_TRACE, "cvs_server_directory(%s)", data);
        !           241:
        !           242:        dir = cvs_remote_input();
        !           243:        if (strlen(dir) < strlen(current_cvsroot->cr_dir) + 1)
        !           244:                fatal("cvs_server_directory: bad Directory request");
        !           245:
        !           246:        repo = dir + strlen(current_cvsroot->cr_dir) + 1;
        !           247:        cvs_mkpath(repo);
        !           248:
        !           249:        if ((dirn = basename(repo)) == NULL)
        !           250:                fatal("cvs_server_directory: %s", strerror(errno));
        !           251:
        !           252:        if ((parent = dirname(repo)) == NULL)
        !           253:                fatal("cvs_server_directory: %s", strerror(errno));
        !           254:
        !           255:        if (strcmp(parent, ".")) {
        !           256:                entlist = cvs_ent_open(parent);
        !           257:                entry = xmalloc(CVS_ENT_MAXLINELEN);
        !           258:                l = snprintf(entry, CVS_ENT_MAXLINELEN, "D/%s////", dirn);
        !           259:                if (l == -1 || l >= CVS_ENT_MAXLINELEN)
        !           260:                        fatal("cvs_server_directory: overflow");
        !           261:
        !           262:                cvs_ent_add(entlist, entry);
        !           263:                cvs_ent_close(entlist, ENT_SYNC);
        !           264:                xfree(entry);
1.1       jfb       265:        }
                    266:
1.29    ! joris     267:        if (server_currentdir != NULL)
        !           268:                xfree(server_currentdir);
        !           269:        server_currentdir = xstrdup(repo);
        !           270:
        !           271:        xfree(dir);
        !           272: }
        !           273:
        !           274: void
        !           275: cvs_server_entry(char *data)
        !           276: {
        !           277:        CVSENTRIES *entlist;
        !           278:
        !           279:        cvs_log(LP_TRACE, "cvs_server_entry(%s)", data);
        !           280:
        !           281:        entlist = cvs_ent_open(server_currentdir);
        !           282:        cvs_ent_add(entlist, data);
        !           283:        cvs_ent_close(entlist, ENT_SYNC);
        !           284: }
        !           285:
        !           286: void
        !           287: cvs_server_modified(char *data)
        !           288: {
        !           289:        BUF *bp;
        !           290:        int fd, l;
        !           291:        size_t flen;
        !           292:        mode_t fmode;
        !           293:        const char *errstr;
        !           294:        char *mode, *len, *fpath;
        !           295:
        !           296:        cvs_log(LP_TRACE, "cvs_server_modified(%s)", data);
        !           297:
        !           298:        mode = cvs_remote_input();
        !           299:        len = cvs_remote_input();
        !           300:
        !           301:        cvs_strtomode(mode, &fmode);
        !           302:        xfree(mode);
        !           303:
        !           304:        flen = strtonum(len, 0, INT_MAX, &errstr);
        !           305:        if (errstr != NULL)
        !           306:                fatal("cvs_server_modified: %s", errstr);
        !           307:        xfree(len);
        !           308:
        !           309:        bp = cvs_remote_receive_file(flen);
        !           310:
        !           311:        fpath = xmalloc(MAXPATHLEN);
        !           312:        l = snprintf(fpath, MAXPATHLEN, "%s/%s", server_currentdir, data);
        !           313:        if (l == -1 || l >= MAXPATHLEN)
        !           314:                fatal("cvs_server_modified: overflow");
        !           315:
        !           316:        if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC)) == -1)
        !           317:                fatal("cvs_server_modified: %s: %s", fpath, strerror(errno));
        !           318:
        !           319:        if (cvs_buf_write_fd(bp, fd) == -1)
        !           320:                fatal("cvs_server_modified: failed to write file '%s'", fpath);
        !           321:
        !           322:        if (fchmod(fd, 0600) == -1)
        !           323:                fatal("cvs_server_modified: failed to set file mode");
        !           324:
        !           325:        xfree(fpath);
        !           326:        (void)close(fd);
        !           327:        cvs_buf_free(bp);
        !           328: }
        !           329:
        !           330: void
        !           331: cvs_server_useunchanged(char *data)
        !           332: {
        !           333:        cvs_log(LP_TRACE, "cvs_server_useunchanged()");
        !           334: }
        !           335:
        !           336: void
        !           337: cvs_server_unchanged(char *data)
        !           338: {
        !           339:        int l, fd;
        !           340:        char *fpath;
        !           341:        CVSENTRIES *entlist;
        !           342:        struct cvs_ent *ent;
        !           343:        struct timeval tv[2];
        !           344:
        !           345:        cvs_log(LP_TRACE, "cvs_server_unchanged(%s)", data);
        !           346:
        !           347:        fpath = xmalloc(MAXPATHLEN);
        !           348:        l = snprintf(fpath, MAXPATHLEN, "%s/%s", server_currentdir, data);
        !           349:        if (l == -1 || l >= MAXPATHLEN)
        !           350:                fatal("cvs_server_unchanged: overflow");
        !           351:
        !           352:        if ((fd = open(fpath, O_RDWR | O_CREAT | O_TRUNC)) == -1)
        !           353:                fatal("cvs_server_unchanged: %s: %s", fpath, strerror(errno));
        !           354:
        !           355:        entlist = cvs_ent_open(server_currentdir);
        !           356:        ent = cvs_ent_get(entlist, data);
        !           357:        if (ent == NULL)
        !           358:                fatal("received Unchanged request for non-existing file");
        !           359:        cvs_ent_close(entlist, ENT_NOSYNC);
        !           360:
        !           361:        tv[0].tv_sec = cvs_hack_time(ent->ce_mtime, 0);
        !           362:        tv[0].tv_usec = 0;
        !           363:        tv[1] = tv[0];
        !           364:        if (futimes(fd, tv) == -1)
        !           365:                fatal("cvs_server_unchanged: failed to set modified time");
        !           366:
        !           367:        if (fchmod(fd, 0600) == -1)
        !           368:                fatal("cvs_server_unchanged: failed to set mode");
        !           369:
        !           370:        cvs_ent_free(ent);
        !           371:        xfree(fpath);
        !           372:        (void)close(fd);
        !           373: }
        !           374:
        !           375: void
        !           376: cvs_server_questionable(char *data)
        !           377: {
        !           378:        cvs_log(LP_TRACE, "cvs_server_questionable(%s)", data);
        !           379: }
        !           380:
        !           381: void
        !           382: cvs_server_argument(char *data)
        !           383: {
        !           384:        cvs_log(LP_TRACE, "cvs_server_argument(%s)", data);
        !           385:
        !           386:        if (server_argc > CVS_CMD_MAXARG)
        !           387:                fatal("cvs_server_argument: too many arguments sent");
        !           388:
        !           389:        server_argv[server_argc++] = xstrdup(data);
        !           390: }
        !           391:
        !           392: void
        !           393: cvs_server_commit(char *data)
        !           394: {
        !           395:        cvs_log(LP_TRACE, "cvs_server_commit()");
        !           396:
        !           397:        if (chdir(server_currentdir) == -1)
        !           398:                fatal("cvs_server_commit: %s", strerror(errno));
        !           399:
        !           400:        cvs_cmdop = CVS_OP_COMMIT;
        !           401:        cvs_commit(server_argc, server_argv);
        !           402:        cvs_server_send_response("ok");
        !           403: }
        !           404:
        !           405: void
        !           406: cvs_server_diff(char *data)
        !           407: {
        !           408:        cvs_log(LP_TRACE, "cvs_server_diff()");
        !           409:
        !           410:        if (chdir(server_currentdir) == -1)
        !           411:                fatal("cvs_server_diff: %s", strerror(errno));
        !           412:
        !           413:        cvs_cmdop = CVS_OP_DIFF;
        !           414:        cvs_diff(server_argc, server_argv);
        !           415:        cvs_server_send_response("ok");
        !           416: }
        !           417:
        !           418: void
        !           419: cvs_server_status(char *data)
        !           420: {
        !           421:        cvs_log(LP_TRACE, "cvs_server_status()");
        !           422:
        !           423:        if (chdir(server_currentdir) == -1)
        !           424:                fatal("cvs_server_status: %s", strerror(errno));
        !           425:
        !           426:        cvs_cmdop = CVS_OP_STATUS;
        !           427:        cvs_status(server_argc, server_argv);
        !           428:        cvs_server_send_response("ok");
        !           429: }
        !           430:
        !           431: void
        !           432: cvs_server_log(char *data)
        !           433: {
        !           434:        cvs_log(LP_TRACE, "cvs_server_log()");
        !           435:
        !           436:        if (chdir(server_currentdir) == -1)
        !           437:                fatal("cvs_server_log: %s", strerror(errno));
        !           438:
        !           439:        cvs_cmdop = CVS_OP_LOG;
        !           440:        cvs_getlog(server_argc, server_argv);
        !           441:        cvs_server_send_response("ok");
        !           442: }
        !           443:
        !           444: void
        !           445: cvs_server_update(char *data)
        !           446: {
        !           447:        cvs_log(LP_TRACE, "cvs_server_update()");
        !           448:
        !           449:        if (chdir(server_currentdir) == -1)
        !           450:                fatal("cvs_server_update: %s", strerror(errno));
1.14      joris     451:
1.29    ! joris     452:        cvs_cmdop = CVS_OP_UPDATE;
        !           453:        cvs_update(server_argc, server_argv);
        !           454:        cvs_server_send_response("ok");
1.1       jfb       455: }