jcs's openbsd hax
openbsd
at jcs 838 lines 19 kB view raw
1/* $OpenBSD: server.c,v 1.106 2020/10/19 19:51:20 naddy 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 32struct 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 73int cvs_server(int, char **); 74char *cvs_server_path = NULL; 75 76static char *server_currentdir = NULL; 77static char **server_argv; 78static int server_argc = 1; 79 80extern int disable_fast_checkout; 81 82struct 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 92int 93cvs_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 free(cmd); 142 } 143 144 return (0); 145} 146 147void 148cvs_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 free(data); 163} 164 165void 166cvs_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 182void 183cvs_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 214void 215cvs_server_validreq(char *data) 216{ 217 BUF *bp; 218 char *d; 219 int i, first; 220 221 first = 0; 222 bp = 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 buf_putc(bp, ' '); 229 else 230 first++; 231 232 buf_puts(bp, cvs_requests[i].name); 233 } 234 235 buf_putc(bp, '\0'); 236 d = buf_release(bp); 237 238 cvs_server_send_response("Valid-requests %s", d); 239 cvs_server_send_response("ok"); 240 free(d); 241} 242 243void 244cvs_server_static_directory(char *data) 245{ 246 FILE *fp; 247 char fpath[PATH_MAX]; 248 249 (void)xsnprintf(fpath, PATH_MAX, "%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 259void 260cvs_server_sticky(char *data) 261{ 262 FILE *fp; 263 char tagpath[PATH_MAX]; 264 265 if (data == NULL) 266 fatal("Missing argument for Sticky"); 267 268 (void)xsnprintf(tagpath, PATH_MAX, "%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 280void 281cvs_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 305void 306cvs_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 322void 323cvs_server_directory(char *data) 324{ 325 CVSENTRIES *entlist; 326 char *dir, *repo, *parent, *entry, *dirn, *p; 327 char parentbuf[PATH_MAX], dirnbuf[PATH_MAX]; 328 329 if (current_cvsroot == NULL) 330 fatal("No Root specified for Directory"); 331 332 dir = cvs_remote_input(); 333 STRIP_SLASH(dir); 334 335 if (strlen(dir) < strlen(current_cvsroot->cr_dir)) 336 fatal("cvs_server_directory: bad Directory request"); 337 338 repo = dir + strlen(current_cvsroot->cr_dir); 339 340 /* 341 * This is somewhat required for checkout, as the 342 * directory request will be: 343 * 344 * Directory . 345 * /path/to/cvs/root 346 */ 347 if (repo[0] == '\0') 348 p = xstrdup("."); 349 else 350 p = xstrdup(repo + 1); 351 352 cvs_mkpath(p, NULL); 353 354 if (strlcpy(dirnbuf, p, sizeof(dirnbuf)) >= sizeof(dirnbuf)) 355 fatal("cvs_server_directory: truncation"); 356 if ((dirn = basename(dirnbuf)) == NULL) 357 fatal("cvs_server_directory: %s", strerror(errno)); 358 359 if (strlcpy(parentbuf, p, sizeof(parentbuf)) >= sizeof(parentbuf)) 360 fatal("cvs_server_directory: truncation"); 361 if ((parent = dirname(parentbuf)) == NULL) 362 fatal("cvs_server_directory: %s", strerror(errno)); 363 364 if (strcmp(parent, ".")) { 365 entry = xmalloc(CVS_ENT_MAXLINELEN); 366 cvs_ent_line_str(dirn, NULL, NULL, NULL, NULL, 1, 0, 367 entry, CVS_ENT_MAXLINELEN); 368 369 entlist = cvs_ent_open(parent); 370 cvs_ent_add(entlist, entry); 371 free(entry); 372 } 373 374 free(server_currentdir); 375 server_currentdir = p; 376 377 free(dir); 378} 379 380void 381cvs_server_entry(char *data) 382{ 383 CVSENTRIES *entlist; 384 385 if (data == NULL) 386 fatal("Missing argument for Entry"); 387 388 entlist = cvs_ent_open(server_currentdir); 389 cvs_ent_add(entlist, data); 390} 391 392void 393cvs_server_modified(char *data) 394{ 395 int fd; 396 size_t flen; 397 mode_t fmode; 398 const char *errstr; 399 char *mode, *len, fpath[PATH_MAX]; 400 401 if (data == NULL) 402 fatal("Missing argument for Modified"); 403 404 /* sorry, we have to use TMP_DIR */ 405 disable_fast_checkout = 1; 406 407 mode = cvs_remote_input(); 408 len = cvs_remote_input(); 409 410 cvs_strtomode(mode, &fmode); 411 free(mode); 412 413 flen = strtonum(len, 0, INT_MAX, &errstr); 414 if (errstr != NULL) 415 fatal("cvs_server_modified: %s", errstr); 416 free(len); 417 418 (void)xsnprintf(fpath, PATH_MAX, "%s/%s", server_currentdir, data); 419 420 if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC)) == -1) 421 fatal("cvs_server_modified: %s: %s", fpath, strerror(errno)); 422 423 cvs_remote_receive_file(fd, flen); 424 425 if (fchmod(fd, 0600) == -1) 426 fatal("cvs_server_modified: failed to set file mode"); 427 428 (void)close(fd); 429} 430 431void 432cvs_server_useunchanged(char *data) 433{ 434} 435 436void 437cvs_server_unchanged(char *data) 438{ 439 char fpath[PATH_MAX]; 440 CVSENTRIES *entlist; 441 struct cvs_ent *ent; 442 char sticky[CVS_ENT_MAXLINELEN]; 443 char rev[CVS_REV_BUFSZ], entry[CVS_ENT_MAXLINELEN]; 444 445 if (data == NULL) 446 fatal("Missing argument for Unchanged"); 447 448 /* sorry, we have to use TMP_DIR */ 449 disable_fast_checkout = 1; 450 451 (void)xsnprintf(fpath, PATH_MAX, "%s/%s", server_currentdir, data); 452 453 entlist = cvs_ent_open(server_currentdir); 454 ent = cvs_ent_get(entlist, data); 455 if (ent == NULL) 456 fatal("received Unchanged request for non-existing file"); 457 458 sticky[0] = '\0'; 459 if (ent->ce_tag != NULL) 460 (void)xsnprintf(sticky, sizeof(sticky), "T%s", ent->ce_tag); 461 462 rcsnum_tostr(ent->ce_rev, rev, sizeof(rev)); 463 (void)xsnprintf(entry, sizeof(entry), "/%s/%s/%s/%s/%s", 464 ent->ce_name, rev, CVS_SERVER_UNCHANGED, ent->ce_opts ? 465 ent->ce_opts : "", sticky); 466 467 cvs_ent_free(ent); 468 cvs_ent_add(entlist, entry); 469} 470 471void 472cvs_server_questionable(char *data) 473{ 474 CVSENTRIES *entlist; 475 char entry[CVS_ENT_MAXLINELEN]; 476 477 if (data == NULL) 478 fatal("Questionable request with no data attached"); 479 480 (void)xsnprintf(entry, sizeof(entry), "/%s/%c///", data, 481 CVS_SERVER_QUESTIONABLE); 482 483 entlist = cvs_ent_open(server_currentdir); 484 cvs_ent_add(entlist, entry); 485 486 /* sorry, we have to use TMP_DIR */ 487 disable_fast_checkout = 1; 488} 489 490void 491cvs_server_argument(char *data) 492{ 493 if (data == NULL) 494 fatal("Missing argument for Argument"); 495 496 server_argv = xreallocarray(server_argv, server_argc + 2, 497 sizeof(*server_argv)); 498 server_argv[server_argc] = xstrdup(data); 499 server_argv[++server_argc] = NULL; 500} 501 502void 503cvs_server_argumentx(char *data) 504{ 505 int idx; 506 size_t len; 507 508 if (server_argc == 1) 509 fatal("Protocol Error: ArgumentX without previous argument"); 510 511 idx = server_argc - 1; 512 513 len = strlen(server_argv[idx]) + strlen(data) + 2; 514 server_argv[idx] = xreallocarray(server_argv[idx], len, sizeof(char)); 515 strlcat(server_argv[idx], "\n", len); 516 strlcat(server_argv[idx], data, len); 517} 518 519void 520cvs_server_update_patches(char *data) 521{ 522 /* 523 * This does not actually do anything. 524 * It is used to tell that the server is able to 525 * generate patches when given an `update' request. 526 * The client must issue the -u argument to `update' 527 * to receive patches. 528 */ 529} 530 531void 532cvs_server_add(char *data) 533{ 534 if (chdir(server_currentdir) == -1) 535 fatal("cvs_server_add: %s", strerror(errno)); 536 537 cvs_cmdop = CVS_OP_ADD; 538 cmdp->cmd_flags = cvs_cmd_add.cmd_flags; 539 cvs_add(server_argc, server_argv); 540 cvs_server_send_response("ok"); 541} 542 543void 544cvs_server_import(char *data) 545{ 546 if (chdir(server_currentdir) == -1) 547 fatal("cvs_server_import: %s", strerror(errno)); 548 549 cvs_cmdop = CVS_OP_IMPORT; 550 cmdp->cmd_flags = cvs_cmd_import.cmd_flags; 551 cvs_import(server_argc, server_argv); 552 cvs_server_send_response("ok"); 553} 554 555void 556cvs_server_admin(char *data) 557{ 558 if (chdir(server_currentdir) == -1) 559 fatal("cvs_server_admin: %s", strerror(errno)); 560 561 cvs_cmdop = CVS_OP_ADMIN; 562 cmdp->cmd_flags = cvs_cmd_admin.cmd_flags; 563 cvs_admin(server_argc, server_argv); 564 cvs_server_send_response("ok"); 565} 566 567void 568cvs_server_annotate(char *data) 569{ 570 if (chdir(server_currentdir) == -1) 571 fatal("cvs_server_annotate: %s", strerror(errno)); 572 573 cvs_cmdop = CVS_OP_ANNOTATE; 574 cmdp->cmd_flags = cvs_cmd_annotate.cmd_flags; 575 cvs_annotate(server_argc, server_argv); 576 cvs_server_send_response("ok"); 577} 578 579void 580cvs_server_rannotate(char *data) 581{ 582 if (chdir(server_currentdir) == -1) 583 fatal("cvs_server_rannotate: %s", strerror(errno)); 584 585 cvs_cmdop = CVS_OP_RANNOTATE; 586 cmdp->cmd_flags = cvs_cmd_rannotate.cmd_flags; 587 cvs_annotate(server_argc, server_argv); 588 cvs_server_send_response("ok"); 589} 590 591void 592cvs_server_commit(char *data) 593{ 594 if (chdir(server_currentdir) == -1) 595 fatal("cvs_server_commit: %s", strerror(errno)); 596 597 cvs_cmdop = CVS_OP_COMMIT; 598 cmdp->cmd_flags = cvs_cmd_commit.cmd_flags; 599 cvs_commit(server_argc, server_argv); 600 cvs_server_send_response("ok"); 601} 602 603void 604cvs_server_checkout(char *data) 605{ 606 if (chdir(server_currentdir) == -1) 607 fatal("cvs_server_checkout: %s", strerror(errno)); 608 609 cvs_cmdop = CVS_OP_CHECKOUT; 610 cmdp->cmd_flags = cvs_cmd_checkout.cmd_flags; 611 cvs_checkout(server_argc, server_argv); 612 cvs_server_send_response("ok"); 613} 614 615void 616cvs_server_diff(char *data) 617{ 618 if (chdir(server_currentdir) == -1) 619 fatal("cvs_server_diff: %s", strerror(errno)); 620 621 cvs_cmdop = CVS_OP_DIFF; 622 cmdp->cmd_flags = cvs_cmd_diff.cmd_flags; 623 cvs_diff(server_argc, server_argv); 624 cvs_server_send_response("ok"); 625} 626 627void 628cvs_server_rdiff(char *data) 629{ 630 if (chdir(server_currentdir) == -1) 631 fatal("cvs_server_rdiff: %s", strerror(errno)); 632 633 cvs_cmdop = CVS_OP_RDIFF; 634 cmdp->cmd_flags = cvs_cmd_rdiff.cmd_flags; 635 cvs_diff(server_argc, server_argv); 636 cvs_server_send_response("ok"); 637} 638 639void 640cvs_server_export(char *data) 641{ 642 if (chdir(server_currentdir) == -1) 643 fatal("cvs_server_export: %s", strerror(errno)); 644 645 cvs_cmdop = CVS_OP_EXPORT; 646 cmdp->cmd_flags = cvs_cmd_export.cmd_flags; 647 cvs_export(server_argc, server_argv); 648 cvs_server_send_response("ok"); 649} 650 651void 652cvs_server_init(char *data) 653{ 654 if (data == NULL) 655 fatal("Missing argument for init"); 656 657 if (current_cvsroot != NULL) 658 fatal("Root in combination with init is not supported"); 659 660 if ((current_cvsroot = cvsroot_get(data)) == NULL) 661 fatal("Invalid argument for init"); 662 663 cvs_cmdop = CVS_OP_INIT; 664 cmdp->cmd_flags = cvs_cmd_init.cmd_flags; 665 cvs_init(server_argc, server_argv); 666 cvs_server_send_response("ok"); 667} 668 669void 670cvs_server_release(char *data) 671{ 672 if (chdir(server_currentdir) == -1) 673 fatal("cvs_server_release: %s", strerror(errno)); 674 675 cvs_cmdop = CVS_OP_RELEASE; 676 cmdp->cmd_flags = cvs_cmd_release.cmd_flags; 677 cvs_release(server_argc, server_argv); 678 cvs_server_send_response("ok"); 679} 680 681void 682cvs_server_remove(char *data) 683{ 684 if (chdir(server_currentdir) == -1) 685 fatal("cvs_server_remove: %s", strerror(errno)); 686 687 cvs_cmdop = CVS_OP_REMOVE; 688 cmdp->cmd_flags = cvs_cmd_remove.cmd_flags; 689 cvs_remove(server_argc, server_argv); 690 cvs_server_send_response("ok"); 691} 692 693void 694cvs_server_status(char *data) 695{ 696 if (chdir(server_currentdir) == -1) 697 fatal("cvs_server_status: %s", strerror(errno)); 698 699 cvs_cmdop = CVS_OP_STATUS; 700 cmdp->cmd_flags = cvs_cmd_status.cmd_flags; 701 cvs_status(server_argc, server_argv); 702 cvs_server_send_response("ok"); 703} 704 705void 706cvs_server_log(char *data) 707{ 708 if (chdir(server_currentdir) == -1) 709 fatal("cvs_server_log: %s", strerror(errno)); 710 711 cvs_cmdop = CVS_OP_LOG; 712 cmdp->cmd_flags = cvs_cmd_log.cmd_flags; 713 cvs_getlog(server_argc, server_argv); 714 cvs_server_send_response("ok"); 715} 716 717void 718cvs_server_rlog(char *data) 719{ 720 if (chdir(current_cvsroot->cr_dir) == -1) 721 fatal("cvs_server_rlog: %s", strerror(errno)); 722 723 cvs_cmdop = CVS_OP_RLOG; 724 cmdp->cmd_flags = cvs_cmd_rlog.cmd_flags; 725 cvs_getlog(server_argc, server_argv); 726 cvs_server_send_response("ok"); 727} 728 729void 730cvs_server_tag(char *data) 731{ 732 if (chdir(server_currentdir) == -1) 733 fatal("cvs_server_tag: %s", strerror(errno)); 734 735 cvs_cmdop = CVS_OP_TAG; 736 cmdp->cmd_flags = cvs_cmd_tag.cmd_flags; 737 cvs_tag(server_argc, server_argv); 738 cvs_server_send_response("ok"); 739} 740 741void 742cvs_server_rtag(char *data) 743{ 744 if (chdir(current_cvsroot->cr_dir) == -1) 745 fatal("cvs_server_rtag: %s", strerror(errno)); 746 747 cvs_cmdop = CVS_OP_RTAG; 748 cmdp->cmd_flags = cvs_cmd_rtag.cmd_flags; 749 cvs_tag(server_argc, server_argv); 750 cvs_server_send_response("ok"); 751} 752 753void 754cvs_server_update(char *data) 755{ 756 if (chdir(server_currentdir) == -1) 757 fatal("cvs_server_update: %s", strerror(errno)); 758 759 cvs_cmdop = CVS_OP_UPDATE; 760 cmdp->cmd_flags = cvs_cmd_update.cmd_flags; 761 cvs_update(server_argc, server_argv); 762 cvs_server_send_response("ok"); 763} 764 765void 766cvs_server_version(char *data) 767{ 768 cvs_cmdop = CVS_OP_VERSION; 769 cmdp->cmd_flags = cvs_cmd_version.cmd_flags; 770 cvs_version(server_argc, server_argv); 771 cvs_server_send_response("ok"); 772} 773 774void 775cvs_server_update_entry(const char *resp, struct cvs_file *cf) 776{ 777 char *p; 778 char repo[PATH_MAX], fpath[PATH_MAX]; 779 780 if ((p = strrchr(cf->file_rpath, ',')) != NULL) 781 *p = '\0'; 782 783 cvs_get_repository_path(cf->file_wd, repo, PATH_MAX); 784 (void)xsnprintf(fpath, PATH_MAX, "%s/%s", repo, cf->file_name); 785 786 cvs_server_send_response("%s %s/", resp, cf->file_wd); 787 cvs_remote_output(fpath); 788 789 if (p != NULL) 790 *p = ','; 791} 792 793void 794cvs_server_set_sticky(const char *dir, char *tag) 795{ 796 char fpath[PATH_MAX]; 797 char repo[PATH_MAX]; 798 799 cvs_get_repository_path(dir, repo, PATH_MAX); 800 (void)xsnprintf(fpath, PATH_MAX, "%s/", repo); 801 802 cvs_server_send_response("Set-sticky %s/", dir); 803 cvs_remote_output(fpath); 804 cvs_remote_output(tag); 805} 806 807void 808cvs_server_clear_sticky(char *dir) 809{ 810 char fpath[PATH_MAX]; 811 char repo[PATH_MAX]; 812 813 cvs_get_repository_path(dir, repo, PATH_MAX); 814 (void)xsnprintf(fpath, PATH_MAX, "%s/", repo); 815 816 cvs_server_send_response("Clear-sticky %s//", dir); 817 cvs_remote_output(fpath); 818} 819 820void 821cvs_server_exp_modules(char *module) 822{ 823 struct module_checkout *mo; 824 struct cvs_filelist *fl; 825 826 if (server_argc != 2) 827 fatal("expand-modules with no arguments"); 828 829 mo = cvs_module_lookup(server_argv[1]); 830 831 RB_FOREACH(fl, cvs_flisthead, &(mo->mc_modules)) 832 cvs_server_send_response("Module-expansion %s", fl->file_path); 833 cvs_server_send_response("ok"); 834 835 server_argc--; 836 free(server_argv[1]); 837 server_argv[1] = NULL; 838}