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