1 /* $OpenBSD: server.c,v 1.91 2008/06/14 03:19:15 joris Exp $ */ 2 /* 3 * Copyright (c) 2006 Joris Vink <joris@openbsd.org> 4 * 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. 8 * 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. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/stat.h> 20 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <libgen.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 #include "cvs.h" 30 #include "remote.h" 31 32 struct cvs_resp cvs_responses[] = { 33 /* this is what our server uses, the client should support it */ 34 { "Valid-requests", 1, cvs_client_validreq, RESP_NEEDED }, 35 { "ok", 0, cvs_client_ok, RESP_NEEDED}, 36 { "error", 0, cvs_client_error, RESP_NEEDED }, 37 { "E", 0, cvs_client_e, RESP_NEEDED }, 38 { "M", 0, cvs_client_m, RESP_NEEDED }, 39 { "Checked-in", 0, cvs_client_checkedin, RESP_NEEDED }, 40 { "Updated", 0, cvs_client_updated, RESP_NEEDED }, 41 { "Merged", 0, cvs_client_merged, RESP_NEEDED }, 42 { "Removed", 0, cvs_client_removed, RESP_NEEDED }, 43 { "Remove-entry", 0, cvs_client_remove_entry, RESP_NEEDED }, 44 { "Set-static-directory", 0, cvs_client_set_static_directory, RESP_NEEDED }, 45 { "Clear-static-directory", 0, cvs_client_clear_static_directory, RESP_NEEDED }, 46 { "Set-sticky", 0, cvs_client_set_sticky, RESP_NEEDED }, 47 { "Clear-sticky", 0, cvs_client_clear_sticky, RESP_NEEDED }, 48 49 /* unsupported responses until told otherwise */ 50 { "New-entry", 0, NULL, 0 }, 51 { "Created", 0, NULL, 0 }, 52 { "Update-existing", 0, NULL, 0 }, 53 { "Rcs-diff", 0, NULL, 0 }, 54 { "Patched", 0, NULL, 0 }, 55 { "Mode", 0, NULL, 0 }, 56 { "Mod-time", 0, NULL, 0 }, 57 { "Checksum", 0, NULL, 0 }, 58 { "Copy-file", 0, NULL, 0 }, 59 { "Template", 0, NULL, 0 }, 60 { "Set-checkin-prog", 0, NULL, 0 }, 61 { "Set-update-prog", 0, NULL, 0 }, 62 { "Notified", 0, NULL, 0 }, 63 { "Module-expansion", 0, NULL, 0 }, 64 { "Wrapper-rcsOption", 0, NULL, 0 }, 65 { "Mbinary", 0, NULL, 0 }, 66 { "F", 0, NULL, 0 }, 67 { "MT", 0, NULL, 0 }, 68 { "", -1, NULL, 0 } 69 }; 70 71 int cvs_server(int, char **); 72 char *cvs_server_path = NULL; 73 74 static char *server_currentdir = NULL; 75 static char **server_argv; 76 static int server_argc = 1; 77 78 extern int disable_fast_checkout; 79 80 struct cvs_cmd cvs_cmd_server = { 81 CVS_OP_SERVER, CVS_USE_WDIR, "server", { "", "" }, 82 "server mode", 83 NULL, 84 NULL, 85 NULL, 86 cvs_server 87 }; 88 89 90 int 91 cvs_server(int argc, char **argv) 92 { 93 char *cmd, *data; 94 struct cvs_req *req; 95 96 if (argc > 1) 97 fatal("server does not take any extra arguments"); 98 99 /* Be on server-side very verbose per default. */ 100 verbosity = 2; 101 102 setvbuf(stdin, NULL, _IOLBF, 0); 103 setvbuf(stdout, NULL, _IOLBF, 0); 104 105 cvs_server_active = 1; 106 107 server_argv = xcalloc(server_argc + 1, sizeof(*server_argv)); 108 server_argv[0] = xstrdup("server"); 109 110 (void)xasprintf(&cvs_server_path, "%s/cvs-serv%d", cvs_tmpdir, 111 getpid()); 112 113 if (mkdir(cvs_server_path, 0700) == -1) 114 fatal("failed to create temporary server directory: %s, %s", 115 cvs_server_path, strerror(errno)); 116 117 if (chdir(cvs_server_path) == -1) 118 fatal("failed to change directory to '%s'", cvs_server_path); 119 120 for (;;) { 121 cmd = cvs_remote_input(); 122 123 if ((data = strchr(cmd, ' ')) != NULL) 124 (*data++) = '\0'; 125 126 req = cvs_remote_get_request_info(cmd); 127 if (req == NULL) 128 fatal("request '%s' is not supported by our server", 129 cmd); 130 131 if (req->hdlr == NULL) 132 fatal("opencvs server does not support '%s'", cmd); 133 134 if ((req->flags & REQ_NEEDDIR) && (server_currentdir == NULL)) 135 fatal("`%s' needs a directory to be sent with " 136 "the `Directory` request first", cmd); 137 138 (*req->hdlr)(data); 139 xfree(cmd); 140 } 141 142 return (0); 143 } 144 145 void 146 cvs_server_send_response(char *fmt, ...) 147 { 148 int i; 149 va_list ap; 150 char *data; 151 152 va_start(ap, fmt); 153 i = vasprintf(&data, fmt, ap); 154 va_end(ap); 155 if (i == -1) 156 fatal("cvs_server_send_response: could not allocate memory"); 157 158 cvs_log(LP_TRACE, "%s", data); 159 cvs_remote_output(data); 160 xfree(data); 161 } 162 163 void 164 cvs_server_root(char *data) 165 { 166 if (data == NULL) 167 fatal("Missing argument for Root"); 168 169 if (current_cvsroot != NULL) 170 return; 171 172 if (data[0] != '/' || (current_cvsroot = cvsroot_get(data)) == NULL) 173 fatal("Invalid Root specified!"); 174 175 cvs_parse_configfile(); 176 cvs_parse_modules(); 177 umask(cvs_umask); 178 } 179 180 void 181 cvs_server_validresp(char *data) 182 { 183 int i; 184 char *sp, *ep; 185 struct cvs_resp *resp; 186 187 if ((sp = data) == NULL) 188 fatal("Missing argument for Valid-responses"); 189 190 do { 191 if ((ep = strchr(sp, ' ')) != NULL) 192 *ep = '\0'; 193 194 resp = cvs_remote_get_response_info(sp); 195 if (resp != NULL) 196 resp->supported = 1; 197 198 if (ep != NULL) 199 sp = ep + 1; 200 } while (ep != NULL); 201 202 for (i = 0; cvs_responses[i].supported != -1; i++) { 203 resp = &cvs_responses[i]; 204 if ((resp->flags & RESP_NEEDED) && 205 resp->supported != 1) { 206 fatal("client does not support required '%s'", 207 resp->name); 208 } 209 } 210 } 211 212 void 213 cvs_server_validreq(char *data) 214 { 215 BUF *bp; 216 char *d; 217 int i, first; 218 219 first = 0; 220 bp = cvs_buf_alloc(512); 221 for (i = 0; cvs_requests[i].supported != -1; i++) { 222 if (cvs_requests[i].hdlr == NULL) 223 continue; 224 225 if (first != 0) 226 cvs_buf_putc(bp, ' '); 227 else 228 first++; 229 230 cvs_buf_puts(bp, cvs_requests[i].name); 231 } 232 233 cvs_buf_putc(bp, '\0'); 234 d = cvs_buf_release(bp); 235 236 cvs_server_send_response("Valid-requests %s", d); 237 cvs_server_send_response("ok"); 238 xfree(d); 239 } 240 241 void 242 cvs_server_static_directory(char *data) 243 { 244 FILE *fp; 245 char fpath[MAXPATHLEN]; 246 247 (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", 248 server_currentdir, CVS_PATH_STATICENTRIES); 249 250 if ((fp = fopen(fpath, "w+")) == NULL) { 251 cvs_log(LP_ERRNO, "%s", fpath); 252 return; 253 } 254 (void)fclose(fp); 255 } 256 257 void 258 cvs_server_sticky(char *data) 259 { 260 FILE *fp; 261 char tagpath[MAXPATHLEN]; 262 263 if (data == NULL) 264 fatal("Missing argument for Sticky"); 265 266 (void)xsnprintf(tagpath, MAXPATHLEN, "%s/%s", 267 server_currentdir, CVS_PATH_TAG); 268 269 if ((fp = fopen(tagpath, "w+")) == NULL) { 270 cvs_log(LP_ERRNO, "%s", tagpath); 271 return; 272 } 273 274 (void)fprintf(fp, "%s\n", data); 275 (void)fclose(fp); 276 } 277 278 void 279 cvs_server_globalopt(char *data) 280 { 281 if (data == NULL) 282 fatal("Missing argument for Global_option"); 283 284 if (!strcmp(data, "-l")) 285 cvs_nolog = 1; 286 287 if (!strcmp(data, "-n")) 288 cvs_noexec = 1; 289 290 if (!strcmp(data, "-Q")) 291 verbosity = 0; 292 293 if (!strcmp(data, "-q")) 294 verbosity = 1; 295 296 if (!strcmp(data, "-r")) 297 cvs_readonly = 1; 298 299 if (!strcmp(data, "-t")) 300 cvs_trace = 1; 301 } 302 303 void 304 cvs_server_set(char *data) 305 { 306 char *ep; 307 308 if (data == NULL) 309 fatal("Missing argument for Set"); 310 311 ep = strchr(data, '='); 312 if (ep == NULL) 313 fatal("no = in variable assignment"); 314 315 *(ep++) = '\0'; 316 if (cvs_var_set(data, ep) < 0) 317 fatal("cvs_server_set: cvs_var_set failed"); 318 } 319 320 void 321 cvs_server_directory(char *data) 322 { 323 CVSENTRIES *entlist; 324 char *dir, *repo, *parent, *entry, *dirn, *p; 325 326 if (current_cvsroot == NULL) 327 fatal("No Root specified for Directory"); 328 329 dir = cvs_remote_input(); 330 STRIP_SLASH(dir); 331 332 if (strlen(dir) < strlen(current_cvsroot->cr_dir)) 333 fatal("cvs_server_directory: bad Directory request"); 334 335 repo = dir + strlen(current_cvsroot->cr_dir); 336 337 /* 338 * This is somewhat required for checkout, as the 339 * directory request will be: 340 * 341 * Directory . 342 * /path/to/cvs/root 343 */ 344 if (repo[0] == '\0') 345 p = xstrdup("."); 346 else 347 p = xstrdup(repo + 1); 348 349 cvs_mkpath(p, NULL); 350 351 if ((dirn = basename(p)) == NULL) 352 fatal("cvs_server_directory: %s", strerror(errno)); 353 354 if ((parent = dirname(p)) == NULL) 355 fatal("cvs_server_directory: %s", strerror(errno)); 356 357 if (strcmp(parent, ".")) { 358 entry = xmalloc(CVS_ENT_MAXLINELEN); 359 cvs_ent_line_str(dirn, NULL, NULL, NULL, NULL, 1, 0, 360 entry, CVS_ENT_MAXLINELEN); 361 362 entlist = cvs_ent_open(parent); 363 cvs_ent_add(entlist, entry); 364 xfree(entry); 365 } 366 367 if (server_currentdir != NULL) 368 xfree(server_currentdir); 369 server_currentdir = p; 370 371 xfree(dir); 372 } 373 374 void 375 cvs_server_entry(char *data) 376 { 377 CVSENTRIES *entlist; 378 379 if (data == NULL) 380 fatal("Missing argument for Entry"); 381 382 entlist = cvs_ent_open(server_currentdir); 383 cvs_ent_add(entlist, data); 384 } 385 386 void 387 cvs_server_modified(char *data) 388 { 389 int fd; 390 size_t flen; 391 mode_t fmode; 392 const char *errstr; 393 char *mode, *len, fpath[MAXPATHLEN]; 394 395 if (data == NULL) 396 fatal("Missing argument for Modified"); 397 398 /* sorry, we have to use TMP_DIR */ 399 disable_fast_checkout = 1; 400 401 mode = cvs_remote_input(); 402 len = cvs_remote_input(); 403 404 cvs_strtomode(mode, &fmode); 405 xfree(mode); 406 407 flen = strtonum(len, 0, INT_MAX, &errstr); 408 if (errstr != NULL) 409 fatal("cvs_server_modified: %s", errstr); 410 xfree(len); 411 412 (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", server_currentdir, data); 413 414 if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC)) == -1) 415 fatal("cvs_server_modified: %s: %s", fpath, strerror(errno)); 416 417 cvs_remote_receive_file(fd, flen); 418 419 if (fchmod(fd, 0600) == -1) 420 fatal("cvs_server_modified: failed to set file mode"); 421 422 (void)close(fd); 423 } 424 425 void 426 cvs_server_useunchanged(char *data) 427 { 428 } 429 430 void 431 cvs_server_unchanged(char *data) 432 { 433 char fpath[MAXPATHLEN]; 434 CVSENTRIES *entlist; 435 struct cvs_ent *ent; 436 char sticky[CVS_ENT_MAXLINELEN]; 437 char rev[CVS_REV_BUFSZ], entry[CVS_ENT_MAXLINELEN]; 438 439 if (data == NULL) 440 fatal("Missing argument for Unchanged"); 441 442 /* sorry, we have to use TMP_DIR */ 443 disable_fast_checkout = 1; 444 445 (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", server_currentdir, data); 446 447 entlist = cvs_ent_open(server_currentdir); 448 ent = cvs_ent_get(entlist, data); 449 if (ent == NULL) 450 fatal("received Unchanged request for non-existing file"); 451 452 sticky[0] = '\0'; 453 if (ent->ce_tag != NULL) 454 (void)xsnprintf(sticky, sizeof(sticky), "T%s", ent->ce_tag); 455 456 rcsnum_tostr(ent->ce_rev, rev, sizeof(rev)); 457 (void)xsnprintf(entry, sizeof(entry), "/%s/%s/%s/%s/%s", 458 ent->ce_name, rev, CVS_SERVER_UNCHANGED, ent->ce_opts ? 459 ent->ce_opts : "", sticky); 460 461 cvs_ent_free(ent); 462 cvs_ent_add(entlist, entry); 463 } 464 465 void 466 cvs_server_questionable(char *data) 467 { 468 /* sorry, we have to use TMP_DIR */ 469 disable_fast_checkout = 1; 470 } 471 472 void 473 cvs_server_argument(char *data) 474 { 475 if (data == NULL) 476 fatal("Missing argument for Argument"); 477 478 server_argv = xrealloc(server_argv, server_argc + 2, 479 sizeof(*server_argv)); 480 server_argv[server_argc] = xstrdup(data); 481 server_argv[++server_argc] = NULL; 482 } 483 484 void 485 cvs_server_argumentx(char *data) 486 { 487 int idx; 488 size_t len; 489 490 if (server_argc == 1) 491 fatal("Protocol Error: ArgumentX without previous argument"); 492 493 idx = server_argc - 1; 494 495 len = strlen(server_argv[idx]) + strlen(data) + 2; 496 server_argv[idx] = xrealloc(server_argv[idx], len, sizeof(char)); 497 strlcat(server_argv[idx], "\n", len); 498 strlcat(server_argv[idx], data, len); 499 } 500 501 void 502 cvs_server_update_patches(char *data) 503 { 504 /* 505 * This does not actually do anything. 506 * It is used to tell that the server is able to 507 * generate patches when given an `update' request. 508 * The client must issue the -u argument to `update' 509 * to receive patches. 510 */ 511 } 512 513 void 514 cvs_server_add(char *data) 515 { 516 if (chdir(server_currentdir) == -1) 517 fatal("cvs_server_add: %s", strerror(errno)); 518 519 cvs_cmdop = CVS_OP_ADD; 520 cmdp->cmd_flags = cvs_cmd_add.cmd_flags; 521 cvs_add(server_argc, server_argv); 522 cvs_server_send_response("ok"); 523 } 524 525 void 526 cvs_server_import(char *data) 527 { 528 if (chdir(server_currentdir) == -1) 529 fatal("cvs_server_import: %s", strerror(errno)); 530 531 cvs_cmdop = CVS_OP_IMPORT; 532 cmdp->cmd_flags = cvs_cmd_import.cmd_flags; 533 cvs_import(server_argc, server_argv); 534 cvs_server_send_response("ok"); 535 } 536 537 void 538 cvs_server_admin(char *data) 539 { 540 if (chdir(server_currentdir) == -1) 541 fatal("cvs_server_admin: %s", strerror(errno)); 542 543 cvs_cmdop = CVS_OP_ADMIN; 544 cmdp->cmd_flags = cvs_cmd_admin.cmd_flags; 545 cvs_admin(server_argc, server_argv); 546 cvs_server_send_response("ok"); 547 } 548 549 void 550 cvs_server_annotate(char *data) 551 { 552 if (chdir(server_currentdir) == -1) 553 fatal("cvs_server_annotate: %s", strerror(errno)); 554 555 cvs_cmdop = CVS_OP_ANNOTATE; 556 cmdp->cmd_flags = cvs_cmd_annotate.cmd_flags; 557 cvs_annotate(server_argc, server_argv); 558 cvs_server_send_response("ok"); 559 } 560 561 void 562 cvs_server_rannotate(char *data) 563 { 564 if (chdir(server_currentdir) == -1) 565 fatal("cvs_server_rannotate: %s", strerror(errno)); 566 567 cvs_cmdop = CVS_OP_RANNOTATE; 568 cmdp->cmd_flags = cvs_cmd_rannotate.cmd_flags; 569 cvs_annotate(server_argc, server_argv); 570 cvs_server_send_response("ok"); 571 } 572 573 void 574 cvs_server_commit(char *data) 575 { 576 if (chdir(server_currentdir) == -1) 577 fatal("cvs_server_commit: %s", strerror(errno)); 578 579 cvs_cmdop = CVS_OP_COMMIT; 580 cmdp->cmd_flags = cvs_cmd_commit.cmd_flags; 581 cvs_commit(server_argc, server_argv); 582 cvs_server_send_response("ok"); 583 } 584 585 void 586 cvs_server_checkout(char *data) 587 { 588 if (chdir(server_currentdir) == -1) 589 fatal("cvs_server_checkout: %s", strerror(errno)); 590 591 cvs_cmdop = CVS_OP_CHECKOUT; 592 cmdp->cmd_flags = cvs_cmd_checkout.cmd_flags; 593 cvs_checkout(server_argc, server_argv); 594 cvs_server_send_response("ok"); 595 } 596 597 void 598 cvs_server_diff(char *data) 599 { 600 if (chdir(server_currentdir) == -1) 601 fatal("cvs_server_diff: %s", strerror(errno)); 602 603 cvs_cmdop = CVS_OP_DIFF; 604 cmdp->cmd_flags = cvs_cmd_diff.cmd_flags; 605 cvs_diff(server_argc, server_argv); 606 cvs_server_send_response("ok"); 607 } 608 609 void 610 cvs_server_rdiff(char *data) 611 { 612 if (chdir(server_currentdir) == -1) 613 fatal("cvs_server_rdiff: %s", strerror(errno)); 614 615 cvs_cmdop = CVS_OP_RDIFF; 616 cmdp->cmd_flags = cvs_cmd_rdiff.cmd_flags; 617 cvs_diff(server_argc, server_argv); 618 cvs_server_send_response("ok"); 619 } 620 621 void 622 cvs_server_export(char *data) 623 { 624 if (chdir(server_currentdir) == -1) 625 fatal("cvs_server_export: %s", strerror(errno)); 626 627 cvs_cmdop = CVS_OP_EXPORT; 628 cmdp->cmd_flags = cvs_cmd_export.cmd_flags; 629 cvs_export(server_argc, server_argv); 630 cvs_server_send_response("ok"); 631 } 632 633 void 634 cvs_server_init(char *data) 635 { 636 if (data == NULL) 637 fatal("Missing argument for init"); 638 639 if (current_cvsroot != NULL) 640 fatal("Root in combination with init is not supported"); 641 642 if ((current_cvsroot = cvsroot_get(data)) == NULL) 643 fatal("Invalid argument for init"); 644 645 cvs_cmdop = CVS_OP_INIT; 646 cmdp->cmd_flags = cvs_cmd_init.cmd_flags; 647 cvs_init(server_argc, server_argv); 648 cvs_server_send_response("ok"); 649 } 650 651 void 652 cvs_server_release(char *data) 653 { 654 if (chdir(server_currentdir) == -1) 655 fatal("cvs_server_release: %s", strerror(errno)); 656 657 cvs_cmdop = CVS_OP_RELEASE; 658 cmdp->cmd_flags = cvs_cmd_release.cmd_flags; 659 cvs_release(server_argc, server_argv); 660 cvs_server_send_response("ok"); 661 } 662 663 void 664 cvs_server_remove(char *data) 665 { 666 if (chdir(server_currentdir) == -1) 667 fatal("cvs_server_remove: %s", strerror(errno)); 668 669 cvs_cmdop = CVS_OP_REMOVE; 670 cmdp->cmd_flags = cvs_cmd_remove.cmd_flags; 671 cvs_remove(server_argc, server_argv); 672 cvs_server_send_response("ok"); 673 } 674 675 void 676 cvs_server_status(char *data) 677 { 678 if (chdir(server_currentdir) == -1) 679 fatal("cvs_server_status: %s", strerror(errno)); 680 681 cvs_cmdop = CVS_OP_STATUS; 682 cmdp->cmd_flags = cvs_cmd_status.cmd_flags; 683 cvs_status(server_argc, server_argv); 684 cvs_server_send_response("ok"); 685 } 686 687 void 688 cvs_server_log(char *data) 689 { 690 if (chdir(server_currentdir) == -1) 691 fatal("cvs_server_log: %s", strerror(errno)); 692 693 cvs_cmdop = CVS_OP_LOG; 694 cmdp->cmd_flags = cvs_cmd_log.cmd_flags; 695 cvs_getlog(server_argc, server_argv); 696 cvs_server_send_response("ok"); 697 } 698 699 void 700 cvs_server_rlog(char *data) 701 { 702 if (chdir(current_cvsroot->cr_dir) == -1) 703 fatal("cvs_server_rlog: %s", strerror(errno)); 704 705 cvs_cmdop = CVS_OP_RLOG; 706 cmdp->cmd_flags = cvs_cmd_rlog.cmd_flags; 707 cvs_getlog(server_argc, server_argv); 708 cvs_server_send_response("ok"); 709 } 710 711 void 712 cvs_server_tag(char *data) 713 { 714 if (chdir(server_currentdir) == -1) 715 fatal("cvs_server_tag: %s", strerror(errno)); 716 717 cvs_cmdop = CVS_OP_TAG; 718 cmdp->cmd_flags = cvs_cmd_tag.cmd_flags; 719 cvs_tag(server_argc, server_argv); 720 cvs_server_send_response("ok"); 721 } 722 723 void 724 cvs_server_rtag(char *data) 725 { 726 if (chdir(current_cvsroot->cr_dir) == -1) 727 fatal("cvs_server_rtag: %s", strerror(errno)); 728 729 cvs_cmdop = CVS_OP_RTAG; 730 cmdp->cmd_flags = cvs_cmd_rtag.cmd_flags; 731 cvs_tag(server_argc, server_argv); 732 cvs_server_send_response("ok"); 733 } 734 735 void 736 cvs_server_update(char *data) 737 { 738 if (chdir(server_currentdir) == -1) 739 fatal("cvs_server_update: %s", strerror(errno)); 740 741 cvs_cmdop = CVS_OP_UPDATE; 742 cmdp->cmd_flags = cvs_cmd_update.cmd_flags; 743 cvs_update(server_argc, server_argv); 744 cvs_server_send_response("ok"); 745 } 746 747 void 748 cvs_server_version(char *data) 749 { 750 cvs_cmdop = CVS_OP_VERSION; 751 cmdp->cmd_flags = cvs_cmd_version.cmd_flags; 752 cvs_version(server_argc, server_argv); 753 cvs_server_send_response("ok"); 754 } 755 756 void 757 cvs_server_update_entry(const char *resp, struct cvs_file *cf) 758 { 759 char *p; 760 char repo[MAXPATHLEN], fpath[MAXPATHLEN]; 761 762 if ((p = strrchr(cf->file_rpath, ',')) != NULL) 763 *p = '\0'; 764 765 cvs_get_repository_path(cf->file_wd, repo, MAXPATHLEN); 766 (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", repo, cf->file_name); 767 768 cvs_server_send_response("%s %s/", resp, cf->file_wd); 769 cvs_remote_output(fpath); 770 771 if (p != NULL) 772 *p = ','; 773 } 774 775 void 776 cvs_server_set_sticky(char *dir, char *tag) 777 { 778 char fpath[MAXPATHLEN]; 779 780 if (module_repo_root != NULL) { 781 (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s/%s", 782 current_cvsroot->cr_dir, module_repo_root, dir); 783 } else { 784 (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", 785 current_cvsroot->cr_dir, dir); 786 } 787 788 cvs_server_send_response("Set-sticky %s", dir); 789 cvs_remote_output(fpath); 790 cvs_remote_output(tag); 791 } 792 793 void 794 cvs_server_clear_sticky(char *dir) 795 { 796 char fpath[MAXPATHLEN]; 797 798 if (module_repo_root != NULL) { 799 (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s/%s", 800 current_cvsroot->cr_dir, module_repo_root, dir); 801 } else { 802 (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", 803 current_cvsroot->cr_dir, dir); 804 } 805 806 cvs_server_send_response("Clear-sticky %s", dir); 807 cvs_remote_output(fpath); 808 } 809