Annotation of src/usr.bin/cvs/server.c, Revision 1.77
1.77 ! tobias 1: /* $OpenBSD: server.c,v 1.76 2008/01/21 16:36:46 tobias Exp $ */
1.1 jfb 2: /*
1.29 joris 3: * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
1.1 jfb 4: *
1.29 joris 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.
1.1 jfb 8: *
1.29 joris 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.
1.1 jfb 16: */
17:
1.73 tobias 18: #include <sys/types.h>
1.55 otto 19: #include <sys/stat.h>
20:
21: #include <errno.h>
22: #include <fcntl.h>
23: #include <libgen.h>
1.68 tobias 24: #include <stdio.h>
1.55 otto 25: #include <stdlib.h>
26: #include <string.h>
27: #include <unistd.h>
1.1 jfb 28:
29: #include "cvs.h"
1.29 joris 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 },
1.46 xsa 44: { "Set-static-directory", 0, cvs_client_set_static_directory, RESP_NEEDED },
1.45 xsa 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 },
1.29 joris 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: };
1.1 jfb 70:
1.29 joris 71: int cvs_server(int, char **);
72: char *cvs_server_path = NULL;
1.1 jfb 73:
1.29 joris 74: static char *server_currentdir = NULL;
75: static char *server_argv[CVS_CMD_MAXARG];
76: static int server_argc = 1;
1.8 joris 77:
1.17 jfb 78: struct cvs_cmd cvs_cmd_server = {
1.29 joris 79: CVS_OP_SERVER, 0, "server", { "", "" },
80: "server mode",
1.17 jfb 81: NULL,
1.29 joris 82: NULL,
83: NULL,
84: cvs_server
1.17 jfb 85: };
1.1 jfb 86:
1.14 joris 87:
1.1 jfb 88: int
89: cvs_server(int argc, char **argv)
90: {
1.29 joris 91: char *cmd, *data;
92: struct cvs_req *req;
93:
1.68 tobias 94: if (argc > 1)
95: fatal("server does not take any extra arguments");
96:
1.70 tobias 97: /* Be on server-side very verbose per default. */
98: verbosity = 2;
99:
1.68 tobias 100: setvbuf(stdin, NULL, _IOLBF, 0);
101: setvbuf(stdout, NULL, _IOLBF, 0);
102:
103: cvs_server_active = 1;
104:
1.29 joris 105: server_argv[0] = xstrdup("server");
106:
1.58 ray 107: (void)xasprintf(&cvs_server_path, "%s/cvs-serv%d", cvs_tmpdir,
108: getpid());
1.29 joris 109:
110: if (mkdir(cvs_server_path, 0700) == -1)
111: fatal("failed to create temporary server directory: %s, %s",
112: cvs_server_path, strerror(errno));
113:
114: if (chdir(cvs_server_path) == -1)
115: fatal("failed to change directory to '%s'", cvs_server_path);
116:
117: for (;;) {
118: cmd = cvs_remote_input();
119:
120: if ((data = strchr(cmd, ' ')) != NULL)
121: (*data++) = '\0';
122:
123: req = cvs_remote_get_request_info(cmd);
124: if (req == NULL)
125: fatal("request '%s' is not supported by our server",
126: cmd);
127:
128: if (req->hdlr == NULL)
129: fatal("opencvs server does not support '%s'", cmd);
1.63 joris 130:
131: if ((req->flags & REQ_NEEDDIR) && (server_currentdir == NULL))
132: fatal("`%s' needs a directory to be sent with "
133: "the `Directory` request first", cmd);
1.29 joris 134:
135: (*req->hdlr)(data);
136: xfree(cmd);
1.14 joris 137: }
138:
1.29 joris 139: return (0);
140: }
141:
142: void
143: cvs_server_send_response(char *fmt, ...)
144: {
145: va_list ap;
1.59 ray 146: char *data;
1.29 joris 147:
148: va_start(ap, fmt);
1.56 ray 149: if (vasprintf(&data, fmt, ap) == -1)
150: fatal("vasprintf: %s", strerror(errno));
1.29 joris 151: va_end(ap);
1.14 joris 152:
1.30 joris 153: cvs_log(LP_TRACE, "%s", data);
1.29 joris 154: cvs_remote_output(data);
155: xfree(data);
156: }
157:
158: void
159: cvs_server_root(char *data)
160: {
1.68 tobias 161: if (data == NULL)
162: fatal("Missing argument for Root");
163:
164: if (current_cvsroot != NULL)
165: return;
166:
167: if (data[0] != '/' || (current_cvsroot = cvsroot_get(data)) == NULL)
168: fatal("Invalid Root specified!");
1.73 tobias 169:
170: cvs_parse_configfile();
171: umask(cvs_umask);
1.29 joris 172: }
173:
174: void
175: cvs_server_validresp(char *data)
176: {
177: int i;
178: char *sp, *ep;
179: struct cvs_resp *resp;
180:
1.57 ray 181: if ((sp = data) == NULL)
182: fatal("Missing argument for Valid-responses");
183:
1.29 joris 184: do {
185: if ((ep = strchr(sp, ' ')) != NULL)
186: *ep = '\0';
187:
188: resp = cvs_remote_get_response_info(sp);
189: if (resp != NULL)
190: resp->supported = 1;
191:
192: if (ep != NULL)
193: sp = ep + 1;
194: } while (ep != NULL);
195:
196: for (i = 0; cvs_responses[i].supported != -1; i++) {
197: resp = &cvs_responses[i];
198: if ((resp->flags & RESP_NEEDED) &&
199: resp->supported != 1) {
200: fatal("client does not support required '%s'",
201: resp->name);
1.1 jfb 202: }
1.29 joris 203: }
204: }
1.1 jfb 205:
1.29 joris 206: void
207: cvs_server_validreq(char *data)
208: {
209: BUF *bp;
210: char *d;
211: int i, first;
212:
213: first = 0;
214: bp = cvs_buf_alloc(512, BUF_AUTOEXT);
215: for (i = 0; cvs_requests[i].supported != -1; i++) {
216: if (cvs_requests[i].hdlr == NULL)
1.5 jfb 217: continue;
1.1 jfb 218:
1.29 joris 219: if (first != 0)
220: cvs_buf_append(bp, " ", 1);
221: else
222: first++;
223:
224: cvs_buf_append(bp, cvs_requests[i].name,
225: strlen(cvs_requests[i].name));
226: }
227:
228: cvs_buf_putc(bp, '\0');
229: d = cvs_buf_release(bp);
230:
231: cvs_server_send_response("Valid-requests %s", d);
232: cvs_server_send_response("ok");
233: xfree(d);
1.42 xsa 234: }
235:
236: void
1.43 xsa 237: cvs_server_static_directory(char *data)
238: {
239: FILE *fp;
1.51 otto 240: char fpath[MAXPATHLEN];
1.43 xsa 241:
1.54 xsa 242: (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s",
243: server_currentdir, CVS_PATH_STATICENTRIES);
1.43 xsa 244:
245: if ((fp = fopen(fpath, "w+")) == NULL) {
246: cvs_log(LP_ERRNO, "%s", fpath);
1.51 otto 247: return;
1.43 xsa 248: }
249: (void)fclose(fp);
250: }
251:
252: void
1.42 xsa 253: cvs_server_sticky(char *data)
254: {
255: FILE *fp;
1.51 otto 256: char tagpath[MAXPATHLEN];
1.42 xsa 257:
1.57 ray 258: if (data == NULL)
259: fatal("Missing argument for Sticky");
260:
1.54 xsa 261: (void)xsnprintf(tagpath, MAXPATHLEN, "%s/%s",
262: server_currentdir, CVS_PATH_TAG);
1.42 xsa 263:
1.43 xsa 264: if ((fp = fopen(tagpath, "w+")) == NULL) {
1.42 xsa 265: cvs_log(LP_ERRNO, "%s", tagpath);
1.51 otto 266: return;
1.42 xsa 267: }
268:
269: (void)fprintf(fp, "%s\n", data);
270: (void)fclose(fp);
1.29 joris 271: }
272:
273: void
274: cvs_server_globalopt(char *data)
275: {
1.57 ray 276: if (data == NULL)
277: fatal("Missing argument for Global_option");
278:
1.38 xsa 279: if (!strcmp(data, "-l"))
280: cvs_nolog = 1;
1.29 joris 281:
282: if (!strcmp(data, "-n"))
283: cvs_noexec = 1;
1.38 xsa 284:
285: if (!strcmp(data, "-Q"))
286: verbosity = 0;
287:
1.70 tobias 288: if (!strcmp(data, "-q"))
289: verbosity = 1;
290:
1.38 xsa 291: if (!strcmp(data, "-r"))
292: cvs_readonly = 1;
293:
294: if (!strcmp(data, "-t"))
295: cvs_trace = 1;
1.39 xsa 296: }
297:
298: void
299: cvs_server_set(char *data)
300: {
301: char *ep;
302:
1.57 ray 303: if (data == NULL)
304: fatal("Missing argument for Set");
305:
1.39 xsa 306: ep = strchr(data, '=');
307: if (ep == NULL)
308: fatal("no = in variable assignment");
309:
310: *(ep++) = '\0';
311: if (cvs_var_set(data, ep) < 0)
312: fatal("cvs_server_set: cvs_var_set failed");
1.29 joris 313: }
1.1 jfb 314:
1.29 joris 315: void
316: cvs_server_directory(char *data)
317: {
318: CVSENTRIES *entlist;
1.51 otto 319: char *dir, *repo, *parent, entry[CVS_ENT_MAXLINELEN], *dirn, *p;
1.68 tobias 320:
321: if (current_cvsroot == NULL)
322: fatal("No Root specified for Directory");
1.29 joris 323:
324: dir = cvs_remote_input();
1.49 joris 325: STRIP_SLASH(dir);
326:
327: if (strlen(dir) < strlen(current_cvsroot->cr_dir))
1.29 joris 328: fatal("cvs_server_directory: bad Directory request");
329:
1.49 joris 330: repo = dir + strlen(current_cvsroot->cr_dir);
331:
332: /*
333: * This is somewhat required for checkout, as the
334: * directory request will be:
335: *
336: * Directory .
337: * /path/to/cvs/root
338: */
339: if (repo[0] == '\0')
340: p = xstrdup(".");
341: else
342: p = xstrdup(repo + 1);
343:
1.65 joris 344: cvs_mkpath(p, NULL);
1.29 joris 345:
1.49 joris 346: if ((dirn = basename(p)) == NULL)
1.29 joris 347: fatal("cvs_server_directory: %s", strerror(errno));
348:
1.49 joris 349: if ((parent = dirname(p)) == NULL)
1.29 joris 350: fatal("cvs_server_directory: %s", strerror(errno));
351:
352: if (strcmp(parent, ".")) {
353: entlist = cvs_ent_open(parent);
1.53 xsa 354: (void)xsnprintf(entry, CVS_ENT_MAXLINELEN, "D/%s////", dirn);
1.29 joris 355:
356: cvs_ent_add(entlist, entry);
357: cvs_ent_close(entlist, ENT_SYNC);
1.1 jfb 358: }
359:
1.29 joris 360: if (server_currentdir != NULL)
361: xfree(server_currentdir);
1.61 ray 362: server_currentdir = p;
1.29 joris 363:
364: xfree(dir);
365: }
366:
367: void
368: cvs_server_entry(char *data)
369: {
370: CVSENTRIES *entlist;
371:
1.57 ray 372: if (data == NULL)
373: fatal("Missing argument for Entry");
374:
1.29 joris 375: entlist = cvs_ent_open(server_currentdir);
376: cvs_ent_add(entlist, data);
377: cvs_ent_close(entlist, ENT_SYNC);
378: }
379:
380: void
381: cvs_server_modified(char *data)
382: {
1.41 xsa 383: int fd;
1.29 joris 384: size_t flen;
385: mode_t fmode;
386: const char *errstr;
1.51 otto 387: char *mode, *len, fpath[MAXPATHLEN];
1.29 joris 388:
1.57 ray 389: if (data == NULL)
390: fatal("Missing argument for Modified");
391:
1.29 joris 392: mode = cvs_remote_input();
393: len = cvs_remote_input();
394:
395: cvs_strtomode(mode, &fmode);
396: xfree(mode);
397:
398: flen = strtonum(len, 0, INT_MAX, &errstr);
399: if (errstr != NULL)
400: fatal("cvs_server_modified: %s", errstr);
401: xfree(len);
402:
1.54 xsa 403: (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", server_currentdir, data);
1.29 joris 404:
405: if ((fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC)) == -1)
406: fatal("cvs_server_modified: %s: %s", fpath, strerror(errno));
407:
1.48 joris 408: cvs_remote_receive_file(fd, flen);
1.29 joris 409:
410: if (fchmod(fd, 0600) == -1)
411: fatal("cvs_server_modified: failed to set file mode");
412:
413: (void)close(fd);
414: }
415:
416: void
417: cvs_server_useunchanged(char *data)
418: {
419: }
420:
421: void
422: cvs_server_unchanged(char *data)
423: {
1.51 otto 424: char fpath[MAXPATHLEN];
1.29 joris 425: CVSENTRIES *entlist;
426: struct cvs_ent *ent;
1.71 joris 427: char sticky[CVS_ENT_MAXLINELEN];
428: char rev[CVS_REV_BUFSZ], entry[CVS_ENT_MAXLINELEN];
1.29 joris 429:
1.57 ray 430: if (data == NULL)
431: fatal("Missing argument for Unchanged");
432:
1.54 xsa 433: (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", server_currentdir, data);
1.29 joris 434:
435: entlist = cvs_ent_open(server_currentdir);
436: ent = cvs_ent_get(entlist, data);
437: if (ent == NULL)
438: fatal("received Unchanged request for non-existing file");
439:
1.71 joris 440: sticky[0] = '\0';
441: if (ent->ce_tag != NULL)
442: (void)xsnprintf(sticky, sizeof(sticky), "T%s", ent->ce_tag);
443:
444: rcsnum_tostr(ent->ce_rev, rev, sizeof(rev));
445: (void)xsnprintf(entry, sizeof(entry), "/%s/%s/%s/%s/%s",
446: ent->ce_name, rev, CVS_SERVER_UNCHANGED, ent->ce_opts ?
447: ent->ce_opts : "", sticky);
1.29 joris 448:
449: cvs_ent_free(ent);
1.71 joris 450: cvs_ent_add(entlist, entry);
451: cvs_ent_close(entlist, ENT_SYNC);
1.29 joris 452: }
453:
454: void
455: cvs_server_questionable(char *data)
456: {
457: }
458:
459: void
460: cvs_server_argument(char *data)
461: {
1.60 ray 462: if (server_argc >= CVS_CMD_MAXARG)
1.29 joris 463: fatal("cvs_server_argument: too many arguments sent");
1.57 ray 464:
465: if (data == NULL)
466: fatal("Missing argument for Argument");
1.29 joris 467:
468: server_argv[server_argc++] = xstrdup(data);
1.37 xsa 469: }
470:
471: void
472: cvs_server_argumentx(char *data)
473: {
1.66 joris 474: int idx;
475: size_t len;
476:
477: if (server_argc < 0)
478: fatal("Protocol Error: ArgumentX without previous argument");
479:
480: idx = server_argc - 1;
481:
482: len = strlen(server_argv[idx]) + strlen(data) + 2;
483: server_argv[idx] = xrealloc(server_argv[idx], len, sizeof(char));
484: strlcat(server_argv[idx], "\n", len);
485: strlcat(server_argv[idx], data, len);
1.44 xsa 486: }
487:
488: void
489: cvs_server_update_patches(char *data)
490: {
491: /*
492: * This does not actually do anything.
493: * It is used to tell that the server is able to
494: * generate patches when given an `update' request.
495: * The client must issue the -u argument to `update'
496: * to receive patches.
497: */
1.29 joris 498: }
499:
500: void
1.31 xsa 501: cvs_server_add(char *data)
502: {
503: if (chdir(server_currentdir) == -1)
504: fatal("cvs_server_add: %s", strerror(errno));
505:
506: cvs_cmdop = CVS_OP_ADD;
507: cvs_add(server_argc, server_argv);
1.50 joris 508: cvs_server_send_response("ok");
509: }
510:
511: void
512: cvs_server_import(char *data)
513: {
514: if (chdir(server_currentdir) == -1)
515: fatal("cvs_server_import: %s", strerror(errno));
516:
517: cvs_cmdop = CVS_OP_IMPORT;
518: cvs_import(server_argc, server_argv);
1.31 xsa 519: cvs_server_send_response("ok");
520: }
1.35 xsa 521:
522: void
523: cvs_server_admin(char *data)
524: {
525: if (chdir(server_currentdir) == -1)
526: fatal("cvs_server_admin: %s", strerror(errno));
527:
528: cvs_cmdop = CVS_OP_ADMIN;
529: cvs_admin(server_argc, server_argv);
530: cvs_server_send_response("ok");
531: }
532:
1.40 xsa 533: void
534: cvs_server_annotate(char *data)
535: {
536: if (chdir(server_currentdir) == -1)
537: fatal("cvs_server_annotate: %s", strerror(errno));
538:
539: cvs_cmdop = CVS_OP_ANNOTATE;
540: cvs_annotate(server_argc, server_argv);
541: cvs_server_send_response("ok");
542: }
1.31 xsa 543:
544: void
1.29 joris 545: cvs_server_commit(char *data)
546: {
547: if (chdir(server_currentdir) == -1)
548: fatal("cvs_server_commit: %s", strerror(errno));
549:
550: cvs_cmdop = CVS_OP_COMMIT;
551: cvs_commit(server_argc, server_argv);
1.49 joris 552: cvs_server_send_response("ok");
553: }
554:
555: void
556: cvs_server_checkout(char *data)
1.77 ! tobias 557: {
! 558: if (chdir(server_currentdir) == -1)
1.49 joris 559: fatal("cvs_server_checkout: %s", strerror(errno));
560:
561: cvs_cmdop = CVS_OP_CHECKOUT;
562: cvs_checkout(server_argc, server_argv);
1.29 joris 563: cvs_server_send_response("ok");
564: }
565:
566: void
567: cvs_server_diff(char *data)
568: {
569: if (chdir(server_currentdir) == -1)
570: fatal("cvs_server_diff: %s", strerror(errno));
571:
572: cvs_cmdop = CVS_OP_DIFF;
573: cvs_diff(server_argc, server_argv);
1.76 tobias 574: cvs_server_send_response("ok");
575: }
576:
577: void
578: cvs_server_export(char *data)
1.77 ! tobias 579: {
! 580: if (chdir(server_currentdir) == -1)
! 581: fatal("cvs_server_export: %s", strerror(errno));
1.76 tobias 582:
583: cvs_cmdop = CVS_OP_EXPORT;
584: cvs_checkout(server_argc, server_argv);
1.34 xsa 585: cvs_server_send_response("ok");
586: }
587:
588: void
589: cvs_server_init(char *data)
590: {
1.69 tobias 591: if (data == NULL)
592: fatal("Missing argument for init");
593:
594: if (current_cvsroot != NULL)
595: fatal("Root in combination with init is not supported");
596:
597: if ((current_cvsroot = cvsroot_get(data)) == NULL)
598: fatal("Invalid argument for init");
1.34 xsa 599:
600: cvs_cmdop = CVS_OP_INIT;
601: cvs_init(server_argc, server_argv);
1.64 xsa 602: cvs_server_send_response("ok");
603: }
604:
605: void
606: cvs_server_release(char *data)
607: {
608: if (chdir(server_currentdir) == -1)
1.67 xsa 609: fatal("cvs_server_release: %s", strerror(errno));
1.64 xsa 610:
611: cvs_cmdop = CVS_OP_RELEASE;
612: cvs_release(server_argc, server_argv);
1.31 xsa 613: cvs_server_send_response("ok");
614: }
615:
616: void
617: cvs_server_remove(char *data)
618: {
619: if (chdir(server_currentdir) == -1)
620: fatal("cvs_server_remove: %s", strerror(errno));
621:
622: cvs_cmdop = CVS_OP_REMOVE;
623: cvs_remove(server_argc, server_argv);
1.29 joris 624: cvs_server_send_response("ok");
625: }
626:
627: void
628: cvs_server_status(char *data)
629: {
630: if (chdir(server_currentdir) == -1)
631: fatal("cvs_server_status: %s", strerror(errno));
632:
633: cvs_cmdop = CVS_OP_STATUS;
634: cvs_status(server_argc, server_argv);
635: cvs_server_send_response("ok");
636: }
637:
638: void
639: cvs_server_log(char *data)
640: {
641: if (chdir(server_currentdir) == -1)
642: fatal("cvs_server_log: %s", strerror(errno));
643:
644: cvs_cmdop = CVS_OP_LOG;
1.62 niallo 645: cvs_getlog(server_argc, server_argv);
646: cvs_server_send_response("ok");
647: }
648:
649: void
650: cvs_server_rlog(char *data)
651: {
1.74 tobias 652: if (chdir(current_cvsroot->cr_dir) == -1)
1.67 xsa 653: fatal("cvs_server_rlog: %s", strerror(errno));
1.62 niallo 654:
655: cvs_cmdop = CVS_OP_RLOG;
1.32 xsa 656: cvs_getlog(server_argc, server_argv);
657: cvs_server_send_response("ok");
658: }
659:
660: void
661: cvs_server_tag(char *data)
662: {
663: if (chdir(server_currentdir) == -1)
664: fatal("cvs_server_tag: %s", strerror(errno));
665:
666: cvs_cmdop = CVS_OP_TAG;
1.75 tobias 667: cvs_tag(server_argc, server_argv);
668: cvs_server_send_response("ok");
669: }
670:
671: void
672: cvs_server_rtag(char *data)
673: {
674: if (chdir(current_cvsroot->cr_dir) == -1)
1.77 ! tobias 675: fatal("cvs_server_rtag: %s", strerror(errno));
1.75 tobias 676:
677: cvs_cmdop = CVS_OP_RTAG;
1.33 xsa 678: cvs_tag(server_argc, server_argv);
1.29 joris 679: cvs_server_send_response("ok");
680: }
681:
682: void
683: cvs_server_update(char *data)
684: {
685: if (chdir(server_currentdir) == -1)
686: fatal("cvs_server_update: %s", strerror(errno));
1.14 joris 687:
1.29 joris 688: cvs_cmdop = CVS_OP_UPDATE;
689: cvs_update(server_argc, server_argv);
1.36 xsa 690: cvs_server_send_response("ok");
691: }
692:
693: void
694: cvs_server_version(char *data)
695: {
696: cvs_cmdop = CVS_OP_VERSION;
697: cvs_version(server_argc, server_argv);
1.29 joris 698: cvs_server_send_response("ok");
1.47 joris 699: }
700:
701: void
702: cvs_server_update_entry(const char *resp, struct cvs_file *cf)
703: {
1.58 ray 704: char *p;
1.65 joris 705: char repo[MAXPATHLEN], fpath[MAXPATHLEN];
1.47 joris 706:
707: if ((p = strrchr(cf->file_rpath, ',')) != NULL)
708: *p = '\0';
709:
1.65 joris 710: cvs_get_repository_path(cf->file_wd, repo, MAXPATHLEN);
711: (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s", repo, cf->file_name);
712:
1.58 ray 713: cvs_server_send_response("%s %s/", resp, cf->file_wd);
1.65 joris 714: cvs_remote_output(fpath);
1.47 joris 715:
716: if (p != NULL)
717: *p = ',';
1.65 joris 718: }
719:
720: void
721: cvs_server_set_sticky(char *dir, char *tag)
722: {
1.72 joris 723: char fpath[MAXPATHLEN];
1.65 joris 724:
725: (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s",
726: current_cvsroot->cr_dir, dir);
727:
728: cvs_server_send_response("Set-sticky %s", dir);
729: cvs_remote_output(fpath);
1.72 joris 730: cvs_remote_output(tag);
1.65 joris 731: }
732:
733: void
734: cvs_server_clear_sticky(char *dir)
735: {
736: char fpath[MAXPATHLEN];
737:
738: (void)xsnprintf(fpath, MAXPATHLEN, "%s/%s",
739: current_cvsroot->cr_dir, dir);
740:
741: cvs_server_send_response("Clear-sticky %s", dir);
742: cvs_remote_output(fpath);
1.1 jfb 743: }