Annotation of src/usr.bin/cvs/client.c, Revision 1.16
1.16 ! xsa 1: /* $OpenBSD: client.c,v 1.15 2006/10/31 15:23:40 xsa Exp $ */
1.1 jfb 2: /*
1.9 joris 3: * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
1.1 jfb 4: *
1.9 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.
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.
1.1 jfb 16: */
17:
1.9 joris 18: #include "includes.h"
1.1 jfb 19:
20: #include "cvs.h"
21: #include "log.h"
1.9 joris 22: #include "diff.h"
23: #include "remote.h"
1.1 jfb 24:
1.9 joris 25: struct cvs_req cvs_requests[] = {
26: /* this is what our client will use, the server should support it */
27: { "Root", 1, cvs_server_root, REQ_NEEDED },
28: { "Valid-responses", 1, cvs_server_validresp, REQ_NEEDED },
29: { "valid-requests", 1, cvs_server_validreq, REQ_NEEDED },
30: { "Global_option", 0, cvs_server_globalopt, REQ_NEEDED },
31: { "Directory", 0, cvs_server_directory, REQ_NEEDED },
32: { "Entry", 0, cvs_server_entry, REQ_NEEDED },
33: { "Modified", 0, cvs_server_modified, REQ_NEEDED },
34: { "UseUnchanged", 0, cvs_server_useunchanged, REQ_NEEDED },
35: { "Unchanged", 0, cvs_server_unchanged, REQ_NEEDED },
36: { "Questionable", 0, cvs_server_questionable, REQ_NEEDED },
37: { "Argument", 0, cvs_server_argument, REQ_NEEDED },
1.1 jfb 38:
1.9 joris 39: /*
40: * used to tell the server what is going on in our
41: * working copy, unsupported until we are told otherwise
42: */
43: { "Max-dotdot", 0, NULL, 0 },
44: { "Static-directory", 0, NULL, 0 },
45: { "Sticky", 0, NULL, 0 },
46: { "Checkin-prog", 0, NULL, 0 },
47: { "Update-prog", 0, NULL, 0 },
48: { "Kopt", 0, NULL, 0 },
49: { "Checkin-time", 0, NULL, 0 },
50: { "Is-modified", 0, NULL, 0 },
51: { "Notify", 0, NULL, 0 },
52: { "Case", 0, NULL, 0 },
53: { "Argumentx", 0, NULL, 0 },
54: { "Gzip-stream", 0, NULL, 0 },
55: { "Kerberos-encrypt", 0, NULL, 0 },
56: { "Gssapi-encrypt", 0, NULL, 0 },
57: { "Gssapi-authenticate", 0, NULL, 0 },
58: { "Set", 0, NULL, 0 },
59: { "expand-modules", 0, NULL, 0 },
60:
61: /* commands that might be supported */
62: { "ci", 0, cvs_server_commit, 0 },
63: { "co", 0, NULL, 0 },
64: { "diff", 0, cvs_server_diff, 0 },
65: { "tag", 0, NULL, 0 },
66: { "status", 0, cvs_server_status, 0 },
67: { "admin", 0, NULL, 0 },
68: { "history", 0, NULL, 0 },
69: { "watchers", 0, NULL, 0 },
70: { "editors", 0, NULL, 0 },
71: { "annotate", 0, NULL, 0 },
72: { "log", 0, cvs_server_log, 0 },
73: { "export", 0, NULL, 0 },
74: { "rdiff", 0, NULL, 0 },
75: { "rtag", 0, NULL, 0 },
76: { "init", 0, NULL, 0 },
77: { "update", 0, cvs_server_update, 0 },
78: { "import", 0, NULL, 0 },
1.15 xsa 79: { "add", 0, cvs_server_add, 0 },
80: { "remove", 0, cvs_server_remove, 0 },
1.9 joris 81: { "watch-on", 0, NULL, 0 },
82: { "watch-off", 0, NULL, 0 },
83: { "watch-add", 0, NULL, 0 },
84: { "watch-remove", 0, NULL, 0 },
85: { "release", 0, NULL, 0 },
86: { "noop", 0, NULL, 0 },
87: { "update-patches", 0, NULL, 0 },
88: { "gzip-file-contents", 0, NULL, 0 },
89: { "wrapper-sendme-rcsOptions", 0, NULL, 0 },
90: { "", -1, NULL, 0 }
91: };
92:
1.16 ! xsa 93: static void client_check_directory(char *);
! 94: static char *client_get_supported_responses(void);
! 95: static char *lastdir = NULL;
! 96: static int end_of_response = 0;
! 97:
! 98: static void cvs_client_initlog(void);
! 99:
! 100: /*
! 101: * File descriptors for protocol logging when the CVS_CLIENT_LOG environment
! 102: * variable is set.
! 103: */
! 104: static int cvs_client_logon = 0;
! 105: static int cvs_client_inlog_fd = -1;
! 106: static int cvs_client_outlog_fd = -1;
! 107:
1.9 joris 108:
109: static char *
110: client_get_supported_responses(void)
111: {
112: BUF *bp;
113: char *d;
114: int i, first;
115:
116: first = 0;
117: bp = cvs_buf_alloc(512, BUF_AUTOEXT);
118: for (i = 0; cvs_responses[i].supported != -1; i++) {
119: if (cvs_responses[i].hdlr == NULL)
120: continue;
121:
122: if (first != 0)
123: cvs_buf_append(bp, " ", 1);
124: else
125: first++;
126: cvs_buf_append(bp, cvs_responses[i].name,
127: strlen(cvs_responses[i].name));
128: }
129:
130: cvs_buf_putc(bp, '\0');
131: d = cvs_buf_release(bp);
132: return (d);
133: }
1.1 jfb 134:
1.10 joris 135: static void
136: client_check_directory(char *data)
137: {
138: int l;
139: CVSENTRIES *entlist;
140: char *entry, *parent, *base;
141:
142: STRIP_SLASH(data);
143:
144: cvs_mkpath(data);
145:
146: if ((base = basename(data)) == NULL)
147: fatal("client_check_directory: overflow");
148:
149: if ((parent = dirname(data)) == NULL)
150: fatal("client_check_directory: overflow");
1.11 joris 151:
152: if (!strcmp(parent, "."))
153: return;
1.10 joris 154:
155: entry = xmalloc(CVS_ENT_MAXLINELEN);
156: l = snprintf(entry, CVS_ENT_MAXLINELEN, "D/%s////", base);
157: if (l == -1 || l >= CVS_ENT_MAXLINELEN)
158: fatal("client_check_directory: overflow");
159:
160: entlist = cvs_ent_open(parent);
161: cvs_ent_add(entlist, entry);
162: cvs_ent_close(entlist, ENT_SYNC);
163:
164: xfree(entry);
165: }
166:
1.9 joris 167: void
168: cvs_client_connect_to_server(void)
169: {
170: char *cmd, *argv[9], *resp;
171: int ifd[2], ofd[2], argc;
1.1 jfb 172:
1.9 joris 173: switch (current_cvsroot->cr_method) {
174: case CVS_METHOD_PSERVER:
175: case CVS_METHOD_KSERVER:
176: case CVS_METHOD_GSERVER:
177: case CVS_METHOD_FORK:
178: case CVS_METHOD_EXT:
1.14 joris 179: fatal("the specified connection method is not supported");
1.9 joris 180: default:
181: break;
182: }
183:
184: if (pipe(ifd) == -1)
185: fatal("cvs_client_connect: %s", strerror(errno));
186: if (pipe(ofd) == -1)
187: fatal("cvs_client_connect: %s", strerror(errno));
188:
189: switch (fork()) {
190: case -1:
191: fatal("cvs_client_connect: fork failed: %s", strerror(errno));
192: case 0:
193: if (dup2(ifd[0], STDIN_FILENO) == -1)
194: fatal("cvs_client_connect: %s", strerror(errno));
195: if (dup2(ofd[1], STDOUT_FILENO) == -1)
196: fatal("cvs_client_connect: %s", strerror(errno));
1.1 jfb 197:
1.9 joris 198: close(ifd[1]);
199: close(ofd[0]);
1.1 jfb 200:
1.9 joris 201: if ((cmd = getenv("CVS_SERVER")) == NULL)
202: cmd = CVS_SERVER_DEFAULT;
1.1 jfb 203:
204: argc = 0;
205: argv[argc++] = cvs_rsh;
206:
1.9 joris 207: if (current_cvsroot->cr_user != NULL) {
1.1 jfb 208: argv[argc++] = "-l";
1.9 joris 209: argv[argc++] = current_cvsroot->cr_user;
1.1 jfb 210: }
211:
1.9 joris 212: argv[argc++] = current_cvsroot->cr_host;
213: argv[argc++] = cmd;
1.1 jfb 214: argv[argc++] = "server";
215: argv[argc] = NULL;
216:
1.9 joris 217: cvs_log(LP_TRACE, "connecting to server %s",
218: current_cvsroot->cr_host);
219:
1.1 jfb 220: execvp(argv[0], argv);
1.9 joris 221: fatal("cvs_client_connect: failed to execute cvs server");
222: default:
223: break;
1.1 jfb 224: }
225:
1.9 joris 226: close(ifd[0]);
227: close(ofd[1]);
228:
229: if ((current_cvsroot->cr_srvin = fdopen(ifd[1], "w")) == NULL)
230: fatal("cvs_client_connect: %s", strerror(errno));
231: if ((current_cvsroot->cr_srvout = fdopen(ofd[0], "r")) == NULL)
232: fatal("cvs_client_connect: %s", strerror(errno));
1.1 jfb 233:
1.9 joris 234: setvbuf(current_cvsroot->cr_srvin, NULL,_IOLBF, 0);
235: setvbuf(current_cvsroot->cr_srvout, NULL, _IOLBF, 0);
1.1 jfb 236:
1.16 ! xsa 237: cvs_client_initlog();
! 238:
1.9 joris 239: cvs_client_send_request("Root %s", current_cvsroot->cr_dir);
1.1 jfb 240:
1.9 joris 241: resp = client_get_supported_responses();
242: cvs_client_send_request("Valid-responses %s", resp);
243: xfree(resp);
1.1 jfb 244:
1.9 joris 245: cvs_client_send_request("valid-requests");
246: cvs_client_get_responses();
1.1 jfb 247:
1.9 joris 248: if (cvs_trace)
249: cvs_client_send_request("Global_option -t");
1.1 jfb 250:
1.9 joris 251: if (verbosity == 2)
252: cvs_client_send_request("Global_option -V");
1.1 jfb 253:
1.9 joris 254: cvs_client_send_request("UseUnchanged");
1.1 jfb 255: }
256:
1.9 joris 257: void
258: cvs_client_send_request(char *fmt, ...)
259: {
260: va_list ap;
261: char *data, *s;
262: struct cvs_req *req;
263:
264: va_start(ap, fmt);
265: vasprintf(&data, fmt, ap);
266: va_end(ap);
1.1 jfb 267:
1.9 joris 268: if ((s = strchr(data, ' ')) != NULL)
269: *s = '\0';
1.1 jfb 270:
1.9 joris 271: req = cvs_remote_get_request_info(data);
272: if (req == NULL)
273: fatal("'%s' is an unknown request", data);
1.1 jfb 274:
1.9 joris 275: if (req->supported != 1)
276: fatal("remote cvs server does not support '%s'", data);
1.1 jfb 277:
1.9 joris 278: if (s != NULL)
279: *s = ' ';
1.1 jfb 280:
1.12 joris 281: cvs_log(LP_TRACE, "%s", data);
1.16 ! xsa 282:
! 283: if (cvs_client_inlog_fd != -1) {
! 284: BUF *bp;
! 285:
! 286: bp = cvs_buf_alloc(strlen(data), BUF_AUTOEXT);
! 287:
! 288: if (cvs_buf_append(bp, data, strlen(data)) < 0)
! 289: fatal("cvs_client_send_request: cvs_buf_append");
! 290:
! 291: cvs_buf_putc(bp, '\n');
! 292:
! 293: if (cvs_buf_write_fd(bp, cvs_client_inlog_fd) < 0)
! 294: fatal("cvs_client_send_request: cvs_buf_write_fd");
! 295:
! 296: cvs_buf_free(bp);
! 297: }
! 298:
1.9 joris 299: cvs_remote_output(data);
300: xfree(data);
301: }
1.1 jfb 302:
1.9 joris 303: void
304: cvs_client_read_response(void)
1.1 jfb 305: {
1.9 joris 306: char *cmd, *data;
307: struct cvs_resp *resp;
1.1 jfb 308:
1.9 joris 309: cmd = cvs_remote_input();
310: if ((data = strchr(cmd, ' ')) != NULL)
311: (*data++) = '\0';
1.1 jfb 312:
1.9 joris 313: resp = cvs_remote_get_response_info(cmd);
314: if (resp == NULL)
315: fatal("response '%s' is not supported by our client", cmd);
1.1 jfb 316:
1.9 joris 317: if (resp->hdlr == NULL)
318: fatal("opencvs client does not support '%s'", cmd);
1.1 jfb 319:
1.16 ! xsa 320: if (cvs_client_outlog_fd != -1) {
! 321: BUF *bp;
! 322:
! 323: bp = cvs_buf_alloc(strlen(cmd), BUF_AUTOEXT);
! 324:
! 325: if (cvs_buf_append(bp, cmd, strlen(cmd)) < 0)
! 326: fatal("cvs_client_read_response: cvs_buf_append");
! 327:
! 328: if (cvs_buf_append(bp,
! 329: (data == NULL) ? "" : " ",
! 330: (data == NULL) ? 0 : 1) < 0) {
! 331: fatal("cvs_client_read_response: cvs_buf_append");
! 332: }
! 333:
! 334: if (cvs_buf_append(bp,
! 335: (data == NULL) ? "" : data,
! 336: (data == NULL) ? 0 : strlen(data)) < 0) {
! 337: fatal("cvs_client_read_response: cvs_buf_append");
! 338: }
! 339:
! 340: cvs_buf_putc(bp, '\n');
! 341:
! 342: if (cvs_buf_write_fd(bp, cvs_client_outlog_fd) < 0)
! 343: fatal("cvs_client_read_response: cvs_buf_write_fd");
! 344:
! 345: cvs_buf_free(bp);
! 346: }
! 347:
1.9 joris 348: (*resp->hdlr)(data);
1.16 ! xsa 349:
1.9 joris 350: xfree(cmd);
1.1 jfb 351: }
352:
1.9 joris 353: void
354: cvs_client_get_responses(void)
355: {
356: while (end_of_response != 1)
357: cvs_client_read_response();
1.1 jfb 358:
1.9 joris 359: end_of_response = 0;
360: }
1.1 jfb 361:
1.9 joris 362: void
363: cvs_client_senddir(const char *dir)
1.1 jfb 364: {
1.9 joris 365: char *repo;
366:
367: if (lastdir != NULL && !strcmp(dir, lastdir))
368: return;
1.1 jfb 369:
1.9 joris 370: cvs_client_send_request("Directory %s", dir);
1.1 jfb 371:
1.9 joris 372: repo = xmalloc(MAXPATHLEN);
373: cvs_get_repository_path(dir, repo, MAXPATHLEN);
374: cvs_remote_output(repo);
375: xfree(repo);
1.1 jfb 376:
1.9 joris 377: if (lastdir != NULL)
378: xfree(lastdir);
379: lastdir = xstrdup(dir);
380: }
1.1 jfb 381:
1.9 joris 382: void
383: cvs_client_sendfile(struct cvs_file *cf)
1.1 jfb 384: {
1.9 joris 385: int l;
386: size_t len;
387: char rev[16], timebuf[64], sticky[32];
1.1 jfb 388:
1.9 joris 389: if (cf->file_type != CVS_FILE)
390: return;
1.1 jfb 391:
1.9 joris 392: cvs_client_senddir(cf->file_wd);
393: cvs_remote_classify_file(cf);
394:
1.10 joris 395: if (cf->file_type == CVS_DIR)
396: return;
397:
1.9 joris 398: if (cf->file_ent != NULL) {
399: if (cf->file_status == FILE_ADDED) {
400: len = strlcpy(rev, "0", sizeof(rev));
401: if (len >= sizeof(rev))
402: fatal("cvs_client_sendfile: truncation");
403:
404: len = strlcpy(timebuf, "Initial ", sizeof(timebuf));
405: if (len >= sizeof(timebuf))
406: fatal("cvs_client_sendfile: truncation");
407:
408: len = strlcat(timebuf, cf->file_name, sizeof(timebuf));
409: if (len >= sizeof(timebuf))
410: fatal("cvs_client_sendfile: truncation");
411: } else {
412: rcsnum_tostr(cf->file_ent->ce_rev, rev, sizeof(rev));
413: ctime_r(&cf->file_ent->ce_mtime, timebuf);
414: }
1.1 jfb 415:
1.9 joris 416: if (cf->file_ent->ce_conflict == NULL) {
417: if (timebuf[strlen(timebuf) - 1] == '\n')
418: timebuf[strlen(timebuf) - 1] = '\0';
419: } else {
420: len = strlcpy(timebuf, cf->file_ent->ce_conflict,
421: sizeof(timebuf));
422: if (len >= sizeof(timebuf))
423: fatal("cvs_client_sendfile: truncation");
424: }
1.1 jfb 425:
1.9 joris 426: sticky[0] = '\0';
427: if (cf->file_ent->ce_tag != NULL) {
428: l = snprintf(sticky, sizeof(sticky), "T%s",
429: cf->file_ent->ce_tag);
430: if (l == -1 || l >= (int)sizeof(sticky))
431: fatal("cvs_client_sendfile: overflow");
1.1 jfb 432: }
433:
1.13 joris 434: cvs_client_send_request("Entry /%s/%s%s/%s//%s",
1.9 joris 435: cf->file_name, (cf->file_status == FILE_REMOVED) ? "-" : "",
436: rev, timebuf, sticky);
437: }
438:
439: switch (cf->file_status) {
440: case FILE_UNKNOWN:
441: if (cf->fd != -1)
442: cvs_client_send_request("Questionable %s",
443: cf->file_name);
444: break;
445: case FILE_ADDED:
446: case FILE_MODIFIED:
447: cvs_client_send_request("Modified %s", cf->file_name);
448: cvs_remote_send_file(cf->file_path);
449: break;
450: case FILE_UPTODATE:
451: cvs_client_send_request("Unchanged %s", cf->file_name);
452: break;
1.1 jfb 453: }
1.9 joris 454: }
1.1 jfb 455:
1.9 joris 456: void
457: cvs_client_send_files(char **argv, int argc)
458: {
459: int i;
1.1 jfb 460:
1.9 joris 461: for (i = 0; i < argc; i++)
462: cvs_client_send_request("Argument %s", argv[i]);
463: }
1.1 jfb 464:
1.9 joris 465: void
466: cvs_client_ok(char *data)
467: {
468: end_of_response = 1;
1.1 jfb 469: }
470:
1.9 joris 471: void
472: cvs_client_error(char *data)
473: {
474: end_of_response = 1;
475: }
1.1 jfb 476:
1.9 joris 477: void
478: cvs_client_validreq(char *data)
1.1 jfb 479: {
1.9 joris 480: int i;
481: char *sp, *ep;
482: struct cvs_req *req;
483:
484: sp = data;
485: do {
486: if ((ep = strchr(sp, ' ')) != NULL)
487: *ep = '\0';
488:
489: req = cvs_remote_get_request_info(sp);
490: if (req != NULL)
491: req->supported = 1;
492:
493: if (ep != NULL)
494: sp = ep + 1;
495: } while (ep != NULL);
496:
497: for (i = 0; cvs_requests[i].supported != -1; i++) {
498: req = &cvs_requests[i];
499: if ((req->flags & REQ_NEEDED) &&
500: req->supported != 1) {
501: fatal("server does not support required '%s'",
502: req->name);
503: }
1.1 jfb 504: }
1.9 joris 505: }
1.1 jfb 506:
1.9 joris 507: void
508: cvs_client_e(char *data)
509: {
510: cvs_printf("%s\n", data);
511: }
1.1 jfb 512:
1.9 joris 513: void
514: cvs_client_m(char *data)
515: {
516: cvs_printf("%s\n", data);
517: }
1.1 jfb 518:
1.9 joris 519: void
520: cvs_client_checkedin(char *data)
521: {
522: int l;
523: CVSENTRIES *entlist;
524: struct cvs_ent *ent, *newent;
525: char *dir, *entry, rev[16], timebuf[64], sticky[16];
1.1 jfb 526:
1.9 joris 527: dir = cvs_remote_input();
528: entry = cvs_remote_input();
529: xfree(dir);
1.1 jfb 530:
1.9 joris 531: entlist = cvs_ent_open(data);
532: newent = cvs_ent_parse(entry);
533: ent = cvs_ent_get(entlist, newent->ce_name);
534: xfree(entry);
1.1 jfb 535:
1.9 joris 536: entry = xmalloc(CVS_ENT_MAXLINELEN);
1.1 jfb 537:
1.9 joris 538: rcsnum_tostr(newent->ce_rev, rev, sizeof(rev));
539: ctime_r(&ent->ce_mtime, timebuf);
540: if (timebuf[strlen(timebuf) - 1] == '\n')
541: timebuf[strlen(timebuf) - 1] = '\0';
1.1 jfb 542:
1.9 joris 543: sticky[0] = '\0';
544: if (ent->ce_tag != NULL) {
545: l = snprintf(sticky, sizeof(sticky), "T%s", ent->ce_tag);
546: if (l == -1 || l >= (int)sizeof(sticky))
547: fatal("cvs_client_checkedin: overflow");
1.2 jfb 548: }
1.1 jfb 549:
1.9 joris 550: l = snprintf(entry, CVS_ENT_MAXLINELEN, "/%s/%s/%s//%s/",
551: newent->ce_name, rev, timebuf, sticky);
552: if (l == -1 || l >= CVS_ENT_MAXLINELEN)
553: fatal("cvs_client_checkedin: overflow");
554:
555: cvs_ent_free(ent);
556: cvs_ent_free(newent);
557: cvs_ent_add(entlist, entry);
558: cvs_ent_close(entlist, ENT_SYNC);
1.1 jfb 559:
1.9 joris 560: xfree(entry);
1.1 jfb 561: }
562:
1.9 joris 563: void
564: cvs_client_updated(char *data)
565: {
566: BUF *bp;
567: int l, fd;
568: time_t now;
569: mode_t fmode;
570: size_t flen;
571: CVSENTRIES *ent;
572: struct cvs_ent *e;
573: const char *errstr;
574: struct timeval tv[2];
575: char timebuf[32], *repo, *rpath, *entry, *mode;
576: char revbuf[32], *len, *fpath, *wdir;
577:
1.10 joris 578: client_check_directory(data);
1.9 joris 579:
580: rpath = cvs_remote_input();
581: entry = cvs_remote_input();
582: mode = cvs_remote_input();
583: len = cvs_remote_input();
584:
585: repo = xmalloc(MAXPATHLEN);
586: cvs_get_repository_path(".", repo, MAXPATHLEN);
587:
588: if (strlen(repo) + 1 > strlen(rpath))
589: fatal("received a repository path that is too short");
590:
591: fpath = rpath + strlen(repo) + 1;
592: if ((wdir = dirname(fpath)) == NULL)
593: fatal("cvs_client_updated: dirname: %s", strerror(errno));
594: xfree(repo);
595:
596: flen = strtonum(len, 0, INT_MAX, &errstr);
597: if (errstr != NULL)
598: fatal("cvs_client_updated: %s: %s", len, errstr);
599: xfree(len);
600:
601: cvs_strtomode(mode, &fmode);
602: xfree(mode);
603:
604: time(&now);
605: now = cvs_hack_time(now, 0);
606: ctime_r(&now, timebuf);
607: if (timebuf[strlen(timebuf) - 1] == '\n')
608: timebuf[strlen(timebuf) - 1] = '\0';
609:
610: e = cvs_ent_parse(entry);
611: xfree(entry);
612: rcsnum_tostr(e->ce_rev, revbuf, sizeof(revbuf));
613: entry = xmalloc(CVS_ENT_MAXLINELEN);
614: l = snprintf(entry, CVS_ENT_MAXLINELEN, "/%s/%s/%s//", e->ce_name,
615: revbuf, timebuf);
616: if (l == -1 || l >= CVS_ENT_MAXLINELEN)
617: fatal("cvs_client_updated: overflow");
618:
619: cvs_ent_free(e);
620: ent = cvs_ent_open(wdir);
621: cvs_ent_add(ent, entry);
622: cvs_ent_close(ent, ENT_SYNC);
623: xfree(entry);
624:
625: bp = cvs_remote_receive_file(flen);
626: if ((fd = open(fpath, O_CREAT | O_WRONLY | O_TRUNC)) == -1)
627: fatal("cvs_client_updated: open: %s: %s",
628: fpath, strerror(errno));
1.1 jfb 629:
1.9 joris 630: if (cvs_buf_write_fd(bp, fd) == -1)
631: fatal("cvs_client_updated: cvs_buf_write_fd failed for %s",
632: fpath);
1.1 jfb 633:
1.9 joris 634: cvs_buf_free(bp);
1.1 jfb 635:
1.9 joris 636: now = cvs_hack_time(now, 0);
637: tv[0].tv_sec = now;
638: tv[0].tv_usec = 0;
639: tv[1] = tv[0];
1.1 jfb 640:
1.9 joris 641: if (futimes(fd, tv) == -1)
642: fatal("cvs_client_updated: futimes: %s", strerror(errno));
1.1 jfb 643:
1.9 joris 644: if (fchmod(fd, fmode) == -1)
645: fatal("cvs_client_updated: fchmod: %s", strerror(errno));
1.1 jfb 646:
1.9 joris 647: (void)close(fd);
1.1 jfb 648:
1.9 joris 649: xfree(rpath);
1.1 jfb 650: }
651:
1.9 joris 652: void
653: cvs_client_merged(char *data)
654: {
655: }
1.1 jfb 656:
1.9 joris 657: void
658: cvs_client_removed(char *data)
659: {
1.13 joris 660: char *dir;
661:
662: dir = cvs_remote_input();
663: xfree(dir);
1.9 joris 664: }
1.1 jfb 665:
1.9 joris 666: void
667: cvs_client_remove_entry(char *data)
1.1 jfb 668: {
1.9 joris 669: char *dir;
1.1 jfb 670:
1.9 joris 671: dir = cvs_remote_input();
672: xfree(dir);
1.16 ! xsa 673: }
! 674: /*
! 675: * cvs_client_initlog()
! 676: *
! 677: * Initialize protocol logging if the CVS_CLIENT_LOG environment variable is
! 678: * set. In this case, the variable's value is used as a path to which the
! 679: * appropriate suffix is added (".in" for client input and ".out" for server
! 680: * output).
! 681: */
! 682: static void
! 683: cvs_client_initlog(void)
! 684: {
! 685: int l;
! 686: u_int i;
! 687: char *env, *envdup, buf[MAXPATHLEN], fpath[MAXPATHLEN];
! 688: char rpath[MAXPATHLEN], *s;
! 689: struct stat st;
! 690: time_t now;
! 691: struct passwd *pwd;
! 692:
! 693: /* avoid doing it more than once */
! 694: if (cvs_client_logon)
! 695: return;
! 696:
! 697: if ((env = getenv("CVS_CLIENT_LOG")) == NULL)
! 698: return;
! 699:
! 700: envdup = xstrdup(env);
! 701: if ((s = strchr(envdup, '%')) != NULL)
! 702: *s = '\0';
! 703:
! 704: if (strlcpy(buf, env, sizeof(buf)) >= sizeof(buf))
! 705: fatal("cvs_client_initlog: truncation");
! 706:
! 707: if (strlcpy(rpath, envdup, sizeof(rpath)) >= sizeof(rpath))
! 708: fatal("cvs_client_initlog: truncation");
! 709:
! 710: xfree(envdup);
! 711:
! 712: s = buf;
! 713: while ((s = strchr(s, '%')) != NULL) {
! 714: s++;
! 715: switch (*s) {
! 716: case 'c':
! 717: if (strlcpy(fpath, cvs_command, sizeof(fpath)) >=
! 718: sizeof(fpath))
! 719: fatal("cvs_client_initlog: truncation");
! 720: break;
! 721: case 'd':
! 722: time(&now);
! 723: if (strlcpy(fpath, ctime(&now), sizeof(fpath)) >=
! 724: sizeof(fpath))
! 725: fatal("cvs_client_initlog: truncation");
! 726: break;
! 727: case 'p':
! 728: snprintf(fpath, sizeof(fpath), "%d", getpid());
! 729: break;
! 730: case 'u':
! 731: if ((pwd = getpwuid(getuid())) != NULL) {
! 732: if (strlcpy(fpath, pwd->pw_name,
! 733: sizeof(fpath)) >= sizeof(fpath))
! 734: fatal("cvs_client_initlog: truncation");
! 735: } else {
! 736: fpath[0] = '\0';
! 737: }
! 738: endpwent();
! 739: break;
! 740: default:
! 741: fpath[0] = '\0';
! 742: break;
! 743: }
! 744:
! 745: if (fpath[0] != '\0') {
! 746: if (strlcat(rpath, "-", sizeof(rpath)) >= sizeof(rpath))
! 747: fatal("cvs_client_initlog: truncation");
! 748:
! 749: if (strlcat(rpath, fpath, sizeof(rpath))
! 750: >= sizeof(rpath))
! 751: fatal("cvs_client_initlog: truncation");
! 752: }
! 753: }
! 754:
! 755: for (i = 0; i < UINT_MAX; i++) {
! 756: l = snprintf(fpath, sizeof(fpath), "%s-%d.in", rpath, i);
! 757: if (l == -1 || l >= (int)sizeof(fpath))
! 758: fatal("cvs_client_initlog: overflow");
! 759:
! 760: if (stat(fpath, &st) != -1)
! 761: continue;
! 762:
! 763: if (errno != ENOENT)
! 764: fatal("cvs_client_initlog() stat failed '%s'",
! 765: strerror(errno));
! 766:
! 767: break;
! 768: }
! 769:
! 770: if ((cvs_client_inlog_fd = open(fpath,
! 771: O_RDWR | O_CREAT | O_TRUNC, 0644)) == NULL) {
! 772: fatal("cvs_client_initlog: open `%s': %s",
! 773: fpath, strerror(errno));
! 774: }
! 775:
! 776: for (i = 0; i < UINT_MAX; i++) {
! 777: l = snprintf(fpath, sizeof(fpath), "%s-%d.out", rpath, i);
! 778: if (l == -1 || l >= (int)sizeof(fpath))
! 779: fatal("cvs_client_initlog: overflow");
! 780:
! 781: if (stat(fpath, &st) != -1)
! 782: continue;
! 783:
! 784: if (errno != ENOENT)
! 785: fatal("cvs_client_initlog() stat failed '%s'",
! 786: strerror(errno));
! 787:
! 788: break;
! 789: }
! 790:
! 791: if ((cvs_client_outlog_fd = open(fpath,
! 792: O_RDWR | O_CREAT | O_TRUNC, 0644)) == NULL) {
! 793: fatal("cvs_client_initlog: open `%s': %s",
! 794: fpath, strerror(errno));
! 795: }
! 796:
! 797: cvs_client_logon = 1;
1.1 jfb 798: }