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