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

1.54    ! xsa         1: /*     $OpenBSD: server.c,v 1.53 2007/01/31 21:07:36 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 },
1.46      xsa        37:        { "Set-static-directory",       0,      cvs_client_set_static_directory, RESP_NEEDED },
1.45      xsa        38:        { "Clear-static-directory",     0,      cvs_client_clear_static_directory, RESP_NEEDED },
                     39:        { "Set-sticky",         0,      cvs_client_set_sticky, RESP_NEEDED },
                     40:        { "Clear-sticky",       0,      cvs_client_clear_sticky, RESP_NEEDED },
1.29      joris      41:
                     42:        /* unsupported responses until told otherwise */
                     43:        { "New-entry",                  0,      NULL, 0 },
                     44:        { "Created",                    0,      NULL, 0 },
                     45:        { "Update-existing",            0,      NULL, 0 },
                     46:        { "Rcs-diff",                   0,      NULL, 0 },
                     47:        { "Patched",                    0,      NULL, 0 },
                     48:        { "Mode",                       0,      NULL, 0 },
                     49:        { "Mod-time",                   0,      NULL, 0 },
                     50:        { "Checksum",                   0,      NULL, 0 },
                     51:        { "Copy-file",                  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:        char *cmd, *data;
                     85:        struct cvs_req *req;
                     86:
                     87:        server_argv[0] = xstrdup("server");
                     88:
                     89:        cvs_server_path = xmalloc(MAXPATHLEN);
1.53      xsa        90:        (void)xsnprintf(cvs_server_path, MAXPATHLEN, "%s/cvs-serv%d",
1.29      joris      91:            cvs_tmpdir, getpid());
                     92:
                     93:        if (mkdir(cvs_server_path, 0700) == -1)
                     94:                fatal("failed to create temporary server directory: %s, %s",
                     95:                    cvs_server_path, strerror(errno));
                     96:
                     97:        if (chdir(cvs_server_path) == -1)
                     98:                fatal("failed to change directory to '%s'", cvs_server_path);
                     99:
                    100:        for (;;) {
                    101:                cmd = cvs_remote_input();
                    102:
                    103:                if ((data = strchr(cmd, ' ')) != NULL)
                    104:                        (*data++) = '\0';
                    105:
                    106:                req = cvs_remote_get_request_info(cmd);
                    107:                if (req == NULL)
                    108:                        fatal("request '%s' is not supported by our server",
                    109:                            cmd);
                    110:
                    111:                if (req->hdlr == NULL)
                    112:                        fatal("opencvs server does not support '%s'", cmd);
                    113:
                    114:                (*req->hdlr)(data);
                    115:                xfree(cmd);
1.14      joris     116:        }
                    117:
1.29      joris     118:        return (0);
                    119: }
                    120:
                    121: void
                    122: cvs_server_send_response(char *fmt, ...)
                    123: {
                    124:        va_list ap;
                    125:        char *data, *s;
                    126:        struct cvs_resp *resp;
                    127:
                    128:        va_start(ap, fmt);
                    129:        vasprintf(&data, fmt, ap);
                    130:        va_end(ap);
                    131:
                    132:        if ((s = strchr(data, ' ')) != NULL)
                    133:                *s = '\0';
                    134:
                    135:        resp = cvs_remote_get_response_info(data);
                    136:        if (resp == NULL)
                    137:                fatal("'%s' is an unknown response", data);
                    138:
                    139:        if (resp->supported != 1)
                    140:                fatal("remote cvs client does not support '%s'", data);
1.14      joris     141:
1.29      joris     142:        if (s != NULL)
                    143:                *s = ' ';
1.14      joris     144:
1.30      joris     145:        cvs_log(LP_TRACE, "%s", data);
1.29      joris     146:        cvs_remote_output(data);
                    147:        xfree(data);
                    148: }
                    149:
                    150: void
                    151: cvs_server_root(char *data)
                    152: {
                    153:        fatal("duplicate Root request from client, violates the protocol");
                    154: }
                    155:
                    156: void
                    157: cvs_server_validresp(char *data)
                    158: {
                    159:        int i;
                    160:        char *sp, *ep;
                    161:        struct cvs_resp *resp;
                    162:
                    163:        sp = data;
                    164:        do {
                    165:                if ((ep = strchr(sp, ' ')) != NULL)
                    166:                        *ep = '\0';
                    167:
                    168:                resp = cvs_remote_get_response_info(sp);
                    169:                if (resp != NULL)
                    170:                        resp->supported = 1;
                    171:
                    172:                if (ep != NULL)
                    173:                        sp = ep + 1;
                    174:        } while (ep != NULL);
                    175:
                    176:        for (i = 0; cvs_responses[i].supported != -1; i++) {
                    177:                resp = &cvs_responses[i];
                    178:                if ((resp->flags & RESP_NEEDED) &&
                    179:                    resp->supported != 1) {
                    180:                        fatal("client does not support required '%s'",
                    181:                            resp->name);
1.1       jfb       182:                }
1.29      joris     183:        }
                    184: }
1.1       jfb       185:
1.29      joris     186: void
                    187: cvs_server_validreq(char *data)
                    188: {
                    189:        BUF *bp;
                    190:        char *d;
                    191:        int i, first;
                    192:
                    193:        first = 0;
                    194:        bp = cvs_buf_alloc(512, BUF_AUTOEXT);
                    195:        for (i = 0; cvs_requests[i].supported != -1; i++) {
                    196:                if (cvs_requests[i].hdlr == NULL)
1.5       jfb       197:                        continue;
1.1       jfb       198:
1.29      joris     199:                if (first != 0)
                    200:                        cvs_buf_append(bp, " ", 1);
                    201:                else
                    202:                        first++;
                    203:
                    204:                cvs_buf_append(bp, cvs_requests[i].name,
                    205:                    strlen(cvs_requests[i].name));
                    206:        }
                    207:
                    208:        cvs_buf_putc(bp, '\0');
                    209:        d = cvs_buf_release(bp);
                    210:
                    211:        cvs_server_send_response("Valid-requests %s", d);
                    212:        cvs_server_send_response("ok");
                    213:        xfree(d);
1.42      xsa       214: }
                    215:
                    216: void
1.43      xsa       217: cvs_server_static_directory(char *data)
                    218: {
                    219:        FILE *fp;
1.51      otto      220:        char fpath[MAXPATHLEN];
1.43      xsa       221:
1.54    ! xsa       222:        (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s",
        !           223:            server_currentdir, CVS_PATH_STATICENTRIES);
1.43      xsa       224:
                    225:        if ((fp = fopen(fpath, "w+")) == NULL) {
                    226:                cvs_log(LP_ERRNO, "%s", fpath);
1.51      otto      227:                return;
1.43      xsa       228:        }
                    229:        (void)fclose(fp);
                    230: }
                    231:
                    232: void
1.42      xsa       233: cvs_server_sticky(char *data)
                    234: {
                    235:        FILE *fp;
1.51      otto      236:        char tagpath[MAXPATHLEN];
1.42      xsa       237:
1.54    ! xsa       238:        (void)xsnprintf(tagpath, MAXPATHLEN, "%s/%s",
        !           239:            server_currentdir, CVS_PATH_TAG);
1.42      xsa       240:
1.43      xsa       241:        if ((fp = fopen(tagpath, "w+")) == NULL) {
1.42      xsa       242:                cvs_log(LP_ERRNO, "%s", tagpath);
1.51      otto      243:                return;
1.42      xsa       244:        }
                    245:
                    246:        (void)fprintf(fp, "%s\n", data);
                    247:        (void)fclose(fp);
1.29      joris     248: }
                    249:
                    250: void
                    251: cvs_server_globalopt(char *data)
                    252: {
1.38      xsa       253:        if (!strcmp(data, "-l"))
                    254:                cvs_nolog = 1;
1.29      joris     255:
                    256:        if (!strcmp(data, "-n"))
                    257:                cvs_noexec = 1;
1.38      xsa       258:
                    259:        if (!strcmp(data, "-Q"))
                    260:                verbosity = 0;
                    261:
                    262:        if (!strcmp(data, "-r"))
                    263:                cvs_readonly = 1;
                    264:
                    265:        if (!strcmp(data, "-t"))
                    266:                cvs_trace = 1;
1.29      joris     267:
                    268:        if (!strcmp(data, "-V"))
                    269:                verbosity = 2;
1.39      xsa       270: }
                    271:
                    272: void
                    273: cvs_server_set(char *data)
                    274: {
                    275:        char *ep;
                    276:
                    277:        ep = strchr(data, '=');
                    278:        if (ep == NULL)
                    279:                fatal("no = in variable assignment");
                    280:
                    281:        *(ep++) = '\0';
                    282:        if (cvs_var_set(data, ep) < 0)
                    283:                fatal("cvs_server_set: cvs_var_set failed");
1.29      joris     284: }
1.1       jfb       285:
1.29      joris     286: void
                    287: cvs_server_directory(char *data)
                    288: {
                    289:        CVSENTRIES *entlist;
1.51      otto      290:        char *dir, *repo, *parent, entry[CVS_ENT_MAXLINELEN], *dirn, *p;
1.29      joris     291:
                    292:        dir = cvs_remote_input();
1.49      joris     293:        STRIP_SLASH(dir);
                    294:
                    295:        if (strlen(dir) < strlen(current_cvsroot->cr_dir))
1.29      joris     296:                fatal("cvs_server_directory: bad Directory request");
                    297:
1.49      joris     298:        repo = dir + strlen(current_cvsroot->cr_dir);
                    299:
                    300:        /*
                    301:         * This is somewhat required for checkout, as the
                    302:         * directory request will be:
                    303:         *
                    304:         * Directory .
                    305:         * /path/to/cvs/root
                    306:         */
                    307:        if (repo[0] == '\0')
                    308:                p = xstrdup(".");
                    309:        else
                    310:                p = xstrdup(repo + 1);
                    311:
                    312:        cvs_mkpath(p);
1.29      joris     313:
1.49      joris     314:        if ((dirn = basename(p)) == NULL)
1.29      joris     315:                fatal("cvs_server_directory: %s", strerror(errno));
                    316:
1.49      joris     317:        if ((parent = dirname(p)) == NULL)
1.29      joris     318:                fatal("cvs_server_directory: %s", strerror(errno));
                    319:
                    320:        if (strcmp(parent, ".")) {
                    321:                entlist = cvs_ent_open(parent);
1.53      xsa       322:                (void)xsnprintf(entry, CVS_ENT_MAXLINELEN, "D/%s////", dirn);
1.29      joris     323:
                    324:                cvs_ent_add(entlist, entry);
                    325:                cvs_ent_close(entlist, ENT_SYNC);
1.1       jfb       326:        }
                    327:
1.29      joris     328:        if (server_currentdir != NULL)
                    329:                xfree(server_currentdir);
1.49      joris     330:        server_currentdir = xstrdup(p);
1.29      joris     331:
1.49      joris     332:        xfree(p);
1.29      joris     333:        xfree(dir);
                    334: }
                    335:
                    336: void
                    337: cvs_server_entry(char *data)
                    338: {
                    339:        CVSENTRIES *entlist;
                    340:
                    341:        entlist = cvs_ent_open(server_currentdir);
                    342:        cvs_ent_add(entlist, data);
                    343:        cvs_ent_close(entlist, ENT_SYNC);
                    344: }
                    345:
                    346: void
                    347: cvs_server_modified(char *data)
                    348: {
1.41      xsa       349:        int fd;
1.29      joris     350:        size_t flen;
                    351:        mode_t fmode;
                    352:        const char *errstr;
1.51      otto      353:        char *mode, *len, fpath[MAXPATHLEN];
1.29      joris     354:
                    355:        mode = cvs_remote_input();
                    356:        len = cvs_remote_input();
                    357:
                    358:        cvs_strtomode(mode, &fmode);
                    359:        xfree(mode);
                    360:
                    361:        flen = strtonum(len, 0, INT_MAX, &errstr);
                    362:        if (errstr != NULL)
                    363:                fatal("cvs_server_modified: %s", errstr);
                    364:        xfree(len);
                    365:
1.54    ! xsa       366:        (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", server_currentdir, data);
1.29      joris     367:
                    368:        if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC)) == -1)
                    369:                fatal("cvs_server_modified: %s: %s", fpath, strerror(errno));
                    370:
1.48      joris     371:        cvs_remote_receive_file(fd, flen);
1.29      joris     372:
                    373:        if (fchmod(fd, 0600) == -1)
                    374:                fatal("cvs_server_modified: failed to set file mode");
                    375:
                    376:        (void)close(fd);
                    377: }
                    378:
                    379: void
                    380: cvs_server_useunchanged(char *data)
                    381: {
                    382: }
                    383:
                    384: void
                    385: cvs_server_unchanged(char *data)
                    386: {
1.41      xsa       387:        int fd;
1.51      otto      388:        char fpath[MAXPATHLEN];
1.29      joris     389:        CVSENTRIES *entlist;
                    390:        struct cvs_ent *ent;
                    391:        struct timeval tv[2];
                    392:
1.54    ! xsa       393:        (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", server_currentdir, data);
1.29      joris     394:
                    395:        if ((fd = open(fpath, O_RDWR | O_CREAT | O_TRUNC)) == -1)
                    396:                fatal("cvs_server_unchanged: %s: %s", fpath, strerror(errno));
                    397:
                    398:        entlist = cvs_ent_open(server_currentdir);
                    399:        ent = cvs_ent_get(entlist, data);
                    400:        if (ent == NULL)
                    401:                fatal("received Unchanged request for non-existing file");
                    402:        cvs_ent_close(entlist, ENT_NOSYNC);
                    403:
1.52      joris     404:        tv[0].tv_sec = ent->ce_mtime;
1.29      joris     405:        tv[0].tv_usec = 0;
                    406:        tv[1] = tv[0];
                    407:        if (futimes(fd, tv) == -1)
                    408:                fatal("cvs_server_unchanged: failed to set modified time");
                    409:
                    410:        if (fchmod(fd, 0600) == -1)
                    411:                fatal("cvs_server_unchanged: failed to set mode");
                    412:
                    413:        cvs_ent_free(ent);
                    414:        (void)close(fd);
                    415: }
                    416:
                    417: void
                    418: cvs_server_questionable(char *data)
                    419: {
                    420: }
                    421:
                    422: void
                    423: cvs_server_argument(char *data)
                    424: {
                    425:
                    426:        if (server_argc > CVS_CMD_MAXARG)
                    427:                fatal("cvs_server_argument: too many arguments sent");
                    428:
                    429:        server_argv[server_argc++] = xstrdup(data);
1.37      xsa       430: }
                    431:
                    432: void
                    433: cvs_server_argumentx(char *data)
                    434: {
1.44      xsa       435: }
                    436:
                    437: void
                    438: cvs_server_update_patches(char *data)
                    439: {
                    440:        /*
                    441:         * This does not actually do anything.
                    442:         * It is used to tell that the server is able to
                    443:         * generate patches when given an `update' request.
                    444:         * The client must issue the -u argument to `update'
                    445:         * to receive patches.
                    446:         */
1.29      joris     447: }
                    448:
                    449: void
1.31      xsa       450: cvs_server_add(char *data)
                    451: {
                    452:        if (chdir(server_currentdir) == -1)
                    453:                fatal("cvs_server_add: %s", strerror(errno));
                    454:
                    455:        cvs_cmdop = CVS_OP_ADD;
                    456:        cvs_add(server_argc, server_argv);
1.50      joris     457:        cvs_server_send_response("ok");
                    458: }
                    459:
                    460: void
                    461: cvs_server_import(char *data)
                    462: {
                    463:        if (chdir(server_currentdir) == -1)
                    464:                fatal("cvs_server_import: %s", strerror(errno));
                    465:
                    466:        cvs_cmdop = CVS_OP_IMPORT;
                    467:        cvs_import(server_argc, server_argv);
1.31      xsa       468:        cvs_server_send_response("ok");
                    469: }
1.35      xsa       470:
                    471: void
                    472: cvs_server_admin(char *data)
                    473: {
                    474:        if (chdir(server_currentdir) == -1)
                    475:                fatal("cvs_server_admin: %s", strerror(errno));
                    476:
                    477:        cvs_cmdop = CVS_OP_ADMIN;
                    478:        cvs_admin(server_argc, server_argv);
                    479:        cvs_server_send_response("ok");
                    480: }
                    481:
1.40      xsa       482: void
                    483: cvs_server_annotate(char *data)
                    484: {
                    485:        if (chdir(server_currentdir) == -1)
                    486:                fatal("cvs_server_annotate: %s", strerror(errno));
                    487:
                    488:        cvs_cmdop = CVS_OP_ANNOTATE;
                    489:        cvs_annotate(server_argc, server_argv);
                    490:        cvs_server_send_response("ok");
                    491: }
1.31      xsa       492:
                    493: void
1.29      joris     494: cvs_server_commit(char *data)
                    495: {
                    496:        if (chdir(server_currentdir) == -1)
                    497:                fatal("cvs_server_commit: %s", strerror(errno));
                    498:
                    499:        cvs_cmdop = CVS_OP_COMMIT;
                    500:        cvs_commit(server_argc, server_argv);
1.49      joris     501:        cvs_server_send_response("ok");
                    502: }
                    503:
                    504: void
                    505: cvs_server_checkout(char *data)
                    506: {      if (chdir(server_currentdir) == -1)
                    507:                fatal("cvs_server_checkout: %s", strerror(errno));
                    508:
                    509:        cvs_cmdop = CVS_OP_CHECKOUT;
                    510:        cvs_checkout(server_argc, server_argv);
1.29      joris     511:        cvs_server_send_response("ok");
                    512: }
                    513:
                    514: void
                    515: cvs_server_diff(char *data)
                    516: {
                    517:        if (chdir(server_currentdir) == -1)
                    518:                fatal("cvs_server_diff: %s", strerror(errno));
                    519:
                    520:        cvs_cmdop = CVS_OP_DIFF;
                    521:        cvs_diff(server_argc, server_argv);
1.34      xsa       522:        cvs_server_send_response("ok");
                    523: }
                    524:
                    525: void
                    526: cvs_server_init(char *data)
                    527: {
                    528:        if (chdir(server_currentdir) == -1)
                    529:                fatal("cvs_server_init: %s", strerror(errno));
                    530:
                    531:        cvs_cmdop = CVS_OP_INIT;
                    532:        cvs_init(server_argc, server_argv);
1.31      xsa       533:        cvs_server_send_response("ok");
                    534: }
                    535:
                    536: void
                    537: cvs_server_remove(char *data)
                    538: {
                    539:        if (chdir(server_currentdir) == -1)
                    540:                fatal("cvs_server_remove: %s", strerror(errno));
                    541:
                    542:        cvs_cmdop = CVS_OP_REMOVE;
                    543:        cvs_remove(server_argc, server_argv);
1.29      joris     544:        cvs_server_send_response("ok");
                    545: }
                    546:
                    547: void
                    548: cvs_server_status(char *data)
                    549: {
                    550:        if (chdir(server_currentdir) == -1)
                    551:                fatal("cvs_server_status: %s", strerror(errno));
                    552:
                    553:        cvs_cmdop = CVS_OP_STATUS;
                    554:        cvs_status(server_argc, server_argv);
                    555:        cvs_server_send_response("ok");
                    556: }
                    557:
                    558: void
                    559: cvs_server_log(char *data)
                    560: {
                    561:        if (chdir(server_currentdir) == -1)
                    562:                fatal("cvs_server_log: %s", strerror(errno));
                    563:
                    564:        cvs_cmdop = CVS_OP_LOG;
1.32      xsa       565:        cvs_getlog(server_argc, server_argv);
                    566:        cvs_server_send_response("ok");
                    567: }
                    568:
                    569: void
                    570: cvs_server_tag(char *data)
                    571: {
                    572:        if (chdir(server_currentdir) == -1)
                    573:                fatal("cvs_server_tag: %s", strerror(errno));
                    574:
                    575:        cvs_cmdop = CVS_OP_TAG;
1.33      xsa       576:        cvs_tag(server_argc, server_argv);
1.29      joris     577:        cvs_server_send_response("ok");
                    578: }
                    579:
                    580: void
                    581: cvs_server_update(char *data)
                    582: {
                    583:        if (chdir(server_currentdir) == -1)
                    584:                fatal("cvs_server_update: %s", strerror(errno));
1.14      joris     585:
1.29      joris     586:        cvs_cmdop = CVS_OP_UPDATE;
                    587:        cvs_update(server_argc, server_argv);
1.36      xsa       588:        cvs_server_send_response("ok");
                    589: }
                    590:
                    591: void
                    592: cvs_server_version(char *data)
                    593: {
                    594:        cvs_cmdop = CVS_OP_VERSION;
                    595:        cvs_version(server_argc, server_argv);
1.29      joris     596:        cvs_server_send_response("ok");
1.47      joris     597: }
                    598:
                    599: void
                    600: cvs_server_update_entry(const char *resp, struct cvs_file *cf)
                    601: {
1.51      otto      602:        char *p, response[MAXPATHLEN];
1.47      joris     603:
                    604:        if ((p = strrchr(cf->file_rpath, ',')) != NULL)
                    605:                *p = '\0';
                    606:
1.53      xsa       607:        (void)xsnprintf(response, MAXPATHLEN, "%s %s/", resp, cf->file_wd);
1.47      joris     608:
                    609:        cvs_server_send_response("%s", response);
                    610:        cvs_remote_output(cf->file_rpath);
                    611:
                    612:        if (p != NULL)
                    613:                *p = ',';
1.1       jfb       614: }