GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/cvs/server.c Lines: 0 353 0.0 %
Date: 2017-11-07 Branches: 0 162 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: server.c,v 1.105 2017/08/28 19:33:20 otto 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
		free(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
	free(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 = 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
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
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
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
		free(entry);
367
	}
368
369
	free(server_currentdir);
370
	server_currentdir = p;
371
372
	free(dir);
373
}
374
375
void
376
cvs_server_entry(char *data)
377
{
378
	CVSENTRIES *entlist;
379
380
	if (data == NULL)
381
		fatal("Missing argument for Entry");
382
383
	entlist = cvs_ent_open(server_currentdir);
384
	cvs_ent_add(entlist, data);
385
}
386
387
void
388
cvs_server_modified(char *data)
389
{
390
	int fd;
391
	size_t flen;
392
	mode_t fmode;
393
	const char *errstr;
394
	char *mode, *len, fpath[PATH_MAX];
395
396
	if (data == NULL)
397
		fatal("Missing argument for Modified");
398
399
	/* sorry, we have to use TMP_DIR */
400
	disable_fast_checkout = 1;
401
402
	mode = cvs_remote_input();
403
	len = cvs_remote_input();
404
405
	cvs_strtomode(mode, &fmode);
406
	free(mode);
407
408
	flen = strtonum(len, 0, INT_MAX, &errstr);
409
	if (errstr != NULL)
410
		fatal("cvs_server_modified: %s", errstr);
411
	free(len);
412
413
	(void)xsnprintf(fpath, PATH_MAX, "%s/%s", server_currentdir, data);
414
415
	if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC)) == -1)
416
		fatal("cvs_server_modified: %s: %s", fpath, strerror(errno));
417
418
	cvs_remote_receive_file(fd, flen);
419
420
	if (fchmod(fd, 0600) == -1)
421
		fatal("cvs_server_modified: failed to set file mode");
422
423
	(void)close(fd);
424
}
425
426
void
427
cvs_server_useunchanged(char *data)
428
{
429
}
430
431
void
432
cvs_server_unchanged(char *data)
433
{
434
	char fpath[PATH_MAX];
435
	CVSENTRIES *entlist;
436
	struct cvs_ent *ent;
437
	char sticky[CVS_ENT_MAXLINELEN];
438
	char rev[CVS_REV_BUFSZ], entry[CVS_ENT_MAXLINELEN];
439
440
	if (data == NULL)
441
		fatal("Missing argument for Unchanged");
442
443
	/* sorry, we have to use TMP_DIR */
444
	disable_fast_checkout = 1;
445
446
	(void)xsnprintf(fpath, PATH_MAX, "%s/%s", server_currentdir, data);
447
448
	entlist = cvs_ent_open(server_currentdir);
449
	ent = cvs_ent_get(entlist, data);
450
	if (ent == NULL)
451
		fatal("received Unchanged request for non-existing file");
452
453
	sticky[0] = '\0';
454
	if (ent->ce_tag != NULL)
455
		(void)xsnprintf(sticky, sizeof(sticky), "T%s", ent->ce_tag);
456
457
	rcsnum_tostr(ent->ce_rev, rev, sizeof(rev));
458
	(void)xsnprintf(entry, sizeof(entry), "/%s/%s/%s/%s/%s",
459
	    ent->ce_name, rev, CVS_SERVER_UNCHANGED, ent->ce_opts ?
460
	    ent->ce_opts : "", sticky);
461
462
	cvs_ent_free(ent);
463
	cvs_ent_add(entlist, entry);
464
}
465
466
void
467
cvs_server_questionable(char *data)
468
{
469
	CVSENTRIES *entlist;
470
	char entry[CVS_ENT_MAXLINELEN];
471
472
	if (data == NULL)
473
		fatal("Questionable request with no data attached");
474
475
	(void)xsnprintf(entry, sizeof(entry), "/%s/%c///", data,
476
	    CVS_SERVER_QUESTIONABLE);
477
478
	entlist = cvs_ent_open(server_currentdir);
479
	cvs_ent_add(entlist, entry);
480
481
	/* sorry, we have to use TMP_DIR */
482
	disable_fast_checkout = 1;
483
}
484
485
void
486
cvs_server_argument(char *data)
487
{
488
	if (data == NULL)
489
		fatal("Missing argument for Argument");
490
491
	server_argv = xreallocarray(server_argv, server_argc + 2,
492
	    sizeof(*server_argv));
493
	server_argv[server_argc] = xstrdup(data);
494
	server_argv[++server_argc] = NULL;
495
}
496
497
void
498
cvs_server_argumentx(char *data)
499
{
500
	int idx;
501
	size_t len;
502
503
	if (server_argc == 1)
504
		fatal("Protocol Error: ArgumentX without previous argument");
505
506
	idx = server_argc - 1;
507
508
	len = strlen(server_argv[idx]) + strlen(data) + 2;
509
	server_argv[idx] = xreallocarray(server_argv[idx], len, sizeof(char));
510
	strlcat(server_argv[idx], "\n", len);
511
	strlcat(server_argv[idx], data, len);
512
}
513
514
void
515
cvs_server_update_patches(char *data)
516
{
517
	/*
518
	 * This does not actually do anything.
519
	 * It is used to tell that the server is able to
520
	 * generate patches when given an `update' request.
521
	 * The client must issue the -u argument to `update'
522
	 * to receive patches.
523
	 */
524
}
525
526
void
527
cvs_server_add(char *data)
528
{
529
	if (chdir(server_currentdir) == -1)
530
		fatal("cvs_server_add: %s", strerror(errno));
531
532
	cvs_cmdop = CVS_OP_ADD;
533
	cmdp->cmd_flags = cvs_cmd_add.cmd_flags;
534
	cvs_add(server_argc, server_argv);
535
	cvs_server_send_response("ok");
536
}
537
538
void
539
cvs_server_import(char *data)
540
{
541
	if (chdir(server_currentdir) == -1)
542
		fatal("cvs_server_import: %s", strerror(errno));
543
544
	cvs_cmdop = CVS_OP_IMPORT;
545
	cmdp->cmd_flags = cvs_cmd_import.cmd_flags;
546
	cvs_import(server_argc, server_argv);
547
	cvs_server_send_response("ok");
548
}
549
550
void
551
cvs_server_admin(char *data)
552
{
553
	if (chdir(server_currentdir) == -1)
554
		fatal("cvs_server_admin: %s", strerror(errno));
555
556
	cvs_cmdop = CVS_OP_ADMIN;
557
	cmdp->cmd_flags = cvs_cmd_admin.cmd_flags;
558
	cvs_admin(server_argc, server_argv);
559
	cvs_server_send_response("ok");
560
}
561
562
void
563
cvs_server_annotate(char *data)
564
{
565
	if (chdir(server_currentdir) == -1)
566
		fatal("cvs_server_annotate: %s", strerror(errno));
567
568
	cvs_cmdop = CVS_OP_ANNOTATE;
569
	cmdp->cmd_flags = cvs_cmd_annotate.cmd_flags;
570
	cvs_annotate(server_argc, server_argv);
571
	cvs_server_send_response("ok");
572
}
573
574
void
575
cvs_server_rannotate(char *data)
576
{
577
	if (chdir(server_currentdir) == -1)
578
		fatal("cvs_server_rannotate: %s", strerror(errno));
579
580
	cvs_cmdop = CVS_OP_RANNOTATE;
581
	cmdp->cmd_flags = cvs_cmd_rannotate.cmd_flags;
582
	cvs_annotate(server_argc, server_argv);
583
	cvs_server_send_response("ok");
584
}
585
586
void
587
cvs_server_commit(char *data)
588
{
589
	if (chdir(server_currentdir) == -1)
590
		fatal("cvs_server_commit: %s", strerror(errno));
591
592
	cvs_cmdop = CVS_OP_COMMIT;
593
	cmdp->cmd_flags = cvs_cmd_commit.cmd_flags;
594
	cvs_commit(server_argc, server_argv);
595
	cvs_server_send_response("ok");
596
}
597
598
void
599
cvs_server_checkout(char *data)
600
{
601
	if (chdir(server_currentdir) == -1)
602
		fatal("cvs_server_checkout: %s", strerror(errno));
603
604
	cvs_cmdop = CVS_OP_CHECKOUT;
605
	cmdp->cmd_flags = cvs_cmd_checkout.cmd_flags;
606
	cvs_checkout(server_argc, server_argv);
607
	cvs_server_send_response("ok");
608
}
609
610
void
611
cvs_server_diff(char *data)
612
{
613
	if (chdir(server_currentdir) == -1)
614
		fatal("cvs_server_diff: %s", strerror(errno));
615
616
	cvs_cmdop = CVS_OP_DIFF;
617
	cmdp->cmd_flags = cvs_cmd_diff.cmd_flags;
618
	cvs_diff(server_argc, server_argv);
619
	cvs_server_send_response("ok");
620
}
621
622
void
623
cvs_server_rdiff(char *data)
624
{
625
	if (chdir(server_currentdir) == -1)
626
		fatal("cvs_server_rdiff: %s", strerror(errno));
627
628
	cvs_cmdop = CVS_OP_RDIFF;
629
	cmdp->cmd_flags = cvs_cmd_rdiff.cmd_flags;
630
	cvs_diff(server_argc, server_argv);
631
	cvs_server_send_response("ok");
632
}
633
634
void
635
cvs_server_export(char *data)
636
{
637
	if (chdir(server_currentdir) == -1)
638
		fatal("cvs_server_export: %s", strerror(errno));
639
640
	cvs_cmdop = CVS_OP_EXPORT;
641
	cmdp->cmd_flags = cvs_cmd_export.cmd_flags;
642
	cvs_export(server_argc, server_argv);
643
	cvs_server_send_response("ok");
644
}
645
646
void
647
cvs_server_init(char *data)
648
{
649
	if (data == NULL)
650
		fatal("Missing argument for init");
651
652
	if (current_cvsroot != NULL)
653
		fatal("Root in combination with init is not supported");
654
655
	if ((current_cvsroot = cvsroot_get(data)) == NULL)
656
		fatal("Invalid argument for init");
657
658
	cvs_cmdop = CVS_OP_INIT;
659
	cmdp->cmd_flags = cvs_cmd_init.cmd_flags;
660
	cvs_init(server_argc, server_argv);
661
	cvs_server_send_response("ok");
662
}
663
664
void
665
cvs_server_release(char *data)
666
{
667
	if (chdir(server_currentdir) == -1)
668
		fatal("cvs_server_release: %s", strerror(errno));
669
670
	cvs_cmdop = CVS_OP_RELEASE;
671
	cmdp->cmd_flags = cvs_cmd_release.cmd_flags;
672
	cvs_release(server_argc, server_argv);
673
	cvs_server_send_response("ok");
674
}
675
676
void
677
cvs_server_remove(char *data)
678
{
679
	if (chdir(server_currentdir) == -1)
680
		fatal("cvs_server_remove: %s", strerror(errno));
681
682
	cvs_cmdop = CVS_OP_REMOVE;
683
	cmdp->cmd_flags = cvs_cmd_remove.cmd_flags;
684
	cvs_remove(server_argc, server_argv);
685
	cvs_server_send_response("ok");
686
}
687
688
void
689
cvs_server_status(char *data)
690
{
691
	if (chdir(server_currentdir) == -1)
692
		fatal("cvs_server_status: %s", strerror(errno));
693
694
	cvs_cmdop = CVS_OP_STATUS;
695
	cmdp->cmd_flags = cvs_cmd_status.cmd_flags;
696
	cvs_status(server_argc, server_argv);
697
	cvs_server_send_response("ok");
698
}
699
700
void
701
cvs_server_log(char *data)
702
{
703
	if (chdir(server_currentdir) == -1)
704
		fatal("cvs_server_log: %s", strerror(errno));
705
706
	cvs_cmdop = CVS_OP_LOG;
707
	cmdp->cmd_flags = cvs_cmd_log.cmd_flags;
708
	cvs_getlog(server_argc, server_argv);
709
	cvs_server_send_response("ok");
710
}
711
712
void
713
cvs_server_rlog(char *data)
714
{
715
	if (chdir(current_cvsroot->cr_dir) == -1)
716
		fatal("cvs_server_rlog: %s", strerror(errno));
717
718
	cvs_cmdop = CVS_OP_RLOG;
719
	cmdp->cmd_flags = cvs_cmd_rlog.cmd_flags;
720
	cvs_getlog(server_argc, server_argv);
721
	cvs_server_send_response("ok");
722
}
723
724
void
725
cvs_server_tag(char *data)
726
{
727
	if (chdir(server_currentdir) == -1)
728
		fatal("cvs_server_tag: %s", strerror(errno));
729
730
	cvs_cmdop = CVS_OP_TAG;
731
	cmdp->cmd_flags = cvs_cmd_tag.cmd_flags;
732
	cvs_tag(server_argc, server_argv);
733
	cvs_server_send_response("ok");
734
}
735
736
void
737
cvs_server_rtag(char *data)
738
{
739
	if (chdir(current_cvsroot->cr_dir) == -1)
740
		fatal("cvs_server_rtag: %s", strerror(errno));
741
742
	cvs_cmdop = CVS_OP_RTAG;
743
	cmdp->cmd_flags = cvs_cmd_rtag.cmd_flags;
744
	cvs_tag(server_argc, server_argv);
745
	cvs_server_send_response("ok");
746
}
747
748
void
749
cvs_server_update(char *data)
750
{
751
	if (chdir(server_currentdir) == -1)
752
		fatal("cvs_server_update: %s", strerror(errno));
753
754
	cvs_cmdop = CVS_OP_UPDATE;
755
	cmdp->cmd_flags = cvs_cmd_update.cmd_flags;
756
	cvs_update(server_argc, server_argv);
757
	cvs_server_send_response("ok");
758
}
759
760
void
761
cvs_server_version(char *data)
762
{
763
	cvs_cmdop = CVS_OP_VERSION;
764
	cmdp->cmd_flags = cvs_cmd_version.cmd_flags;
765
	cvs_version(server_argc, server_argv);
766
	cvs_server_send_response("ok");
767
}
768
769
void
770
cvs_server_update_entry(const char *resp, struct cvs_file *cf)
771
{
772
	char *p;
773
	char repo[PATH_MAX], fpath[PATH_MAX];
774
775
	if ((p = strrchr(cf->file_rpath, ',')) != NULL)
776
		*p = '\0';
777
778
	cvs_get_repository_path(cf->file_wd, repo, PATH_MAX);
779
	(void)xsnprintf(fpath, PATH_MAX, "%s/%s", repo, cf->file_name);
780
781
	cvs_server_send_response("%s %s/", resp, cf->file_wd);
782
	cvs_remote_output(fpath);
783
784
	if (p != NULL)
785
		*p = ',';
786
}
787
788
void
789
cvs_server_set_sticky(const char *dir, char *tag)
790
{
791
	char fpath[PATH_MAX];
792
	char repo[PATH_MAX];
793
794
	cvs_get_repository_path(dir, repo, PATH_MAX);
795
	(void)xsnprintf(fpath, PATH_MAX, "%s/", repo);
796
797
	cvs_server_send_response("Set-sticky %s/", dir);
798
	cvs_remote_output(fpath);
799
	cvs_remote_output(tag);
800
}
801
802
void
803
cvs_server_clear_sticky(char *dir)
804
{
805
	char fpath[PATH_MAX];
806
	char repo[PATH_MAX];
807
808
	cvs_get_repository_path(dir, repo, PATH_MAX);
809
	(void)xsnprintf(fpath, PATH_MAX, "%s/", repo);
810
811
	cvs_server_send_response("Clear-sticky %s//", dir);
812
	cvs_remote_output(fpath);
813
}
814
815
void
816
cvs_server_exp_modules(char *module)
817
{
818
	struct module_checkout *mo;
819
	struct cvs_filelist *fl;
820
821
	if (server_argc != 2)
822
		fatal("expand-modules with no arguments");
823
824
	mo = cvs_module_lookup(server_argv[1]);
825
826
	RB_FOREACH(fl, cvs_flisthead, &(mo->mc_modules))
827
		cvs_server_send_response("Module-expansion %s", fl->file_path);
828
	cvs_server_send_response("ok");
829
830
	server_argc--;
831
	free(server_argv[1]);
832
	server_argv[1] = NULL;
833
}