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: }