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
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
cvs_server(int argc,char ** argv)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 free(cmd);
142 }
143
144 return (0);
145 }
146
147 void
cvs_server_send_response(char * fmt,...)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 free(data);
163 }
164
165 void
cvs_server_root(char * data)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
cvs_server_validresp(char * data)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
cvs_server_validreq(char * data)215 cvs_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
243 void
cvs_server_static_directory(char * data)244 cvs_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
259 void
cvs_server_sticky(char * data)260 cvs_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
280 void
cvs_server_globalopt(char * data)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
cvs_server_set(char * data)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
cvs_server_directory(char * data)323 cvs_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
380 void
cvs_server_entry(char * data)381 cvs_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
392 void
cvs_server_modified(char * data)393 cvs_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
431 void
cvs_server_useunchanged(char * data)432 cvs_server_useunchanged(char *data)
433 {
434 }
435
436 void
cvs_server_unchanged(char * data)437 cvs_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
471 void
cvs_server_questionable(char * data)472 cvs_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
490 void
cvs_server_argument(char * data)491 cvs_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
502 void
cvs_server_argumentx(char * data)503 cvs_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
519 void
cvs_server_update_patches(char * data)520 cvs_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
531 void
cvs_server_add(char * data)532 cvs_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
543 void
cvs_server_import(char * data)544 cvs_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
555 void
cvs_server_admin(char * data)556 cvs_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
567 void
cvs_server_annotate(char * data)568 cvs_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
579 void
cvs_server_rannotate(char * data)580 cvs_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
591 void
cvs_server_commit(char * data)592 cvs_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
603 void
cvs_server_checkout(char * data)604 cvs_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
615 void
cvs_server_diff(char * data)616 cvs_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
627 void
cvs_server_rdiff(char * data)628 cvs_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
639 void
cvs_server_export(char * data)640 cvs_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
651 void
cvs_server_init(char * data)652 cvs_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
669 void
cvs_server_release(char * data)670 cvs_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
681 void
cvs_server_remove(char * data)682 cvs_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
693 void
cvs_server_status(char * data)694 cvs_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
705 void
cvs_server_log(char * data)706 cvs_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
717 void
cvs_server_rlog(char * data)718 cvs_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
729 void
cvs_server_tag(char * data)730 cvs_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
741 void
cvs_server_rtag(char * data)742 cvs_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
753 void
cvs_server_update(char * data)754 cvs_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
765 void
cvs_server_version(char * data)766 cvs_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
774 void
cvs_server_update_entry(const char * resp,struct cvs_file * cf)775 cvs_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
793 void
cvs_server_set_sticky(const char * dir,char * tag)794 cvs_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
807 void
cvs_server_clear_sticky(char * dir)808 cvs_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
820 void
cvs_server_exp_modules(char * module)821 cvs_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 }
839