Annotation of src/usr.bin/cvs/edit.c, Revision 1.23
1.23 ! xsa 1: /* $OpenBSD: edit.c,v 1.22 2007/01/05 09:41:30 xsa Exp $ */
1.1 jfb 2: /*
1.15 xsa 3: * Copyright (c) 2006, 2007 Xavier Santolaria <xsa@openbsd.org>
1.1 jfb 4: *
1.14 xsa 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.11 xsa 18: #include "includes.h"
1.1 jfb 19:
20: #include "cvs.h"
21: #include "log.h"
1.14 xsa 22: #include "remote.h"
1.1 jfb 23:
1.18 xsa 24: #define E_COMMIT 0x01
25: #define E_EDIT 0x02
26: #define E_UNEDIT 0x04
27: #define E_ALL (E_EDIT|E_COMMIT|E_UNEDIT)
28:
1.23 ! xsa 29: #define BASE_ADD 0x01
! 30: #define BASE_GET 0x02
! 31: #define BASE_REMOVE 0x04
! 32:
1.18 xsa 33: static void cvs_edit_local(struct cvs_file *);
1.14 xsa 34: static void cvs_editors_local(struct cvs_file *);
1.15 xsa 35: static void cvs_unedit_local(struct cvs_file *);
1.1 jfb 36:
1.23 ! xsa 37: static RCSNUM *cvs_base_handle(struct cvs_file *, int);
! 38:
1.18 xsa 39: static int edit_aflags = 0;
40:
41: struct cvs_cmd cvs_cmd_edit = {
42: CVS_OP_EDIT, 0, "edit",
43: { },
44: "Get ready to edit a watched file",
45: "[-lR] [-a action] [file ...]",
46: "a:lR",
47: NULL,
48: cvs_edit
49: };
50:
1.1 jfb 51: struct cvs_cmd cvs_cmd_editors = {
1.14 xsa 52: CVS_OP_EDITORS, 0, "editors",
1.1 jfb 53: { },
1.14 xsa 54: "See who is editing a watched file",
1.3 xsa 55: "[-lR] [file ...]",
1.1 jfb 56: "lR",
57: NULL,
1.14 xsa 58: cvs_editors
1.1 jfb 59: };
60:
1.15 xsa 61: struct cvs_cmd cvs_cmd_unedit = {
62: CVS_OP_UNEDIT, 0, "unedit",
63: { },
64: "Undo an edit command",
65: "[-lR] [file ...]",
66: "lR",
67: NULL,
68: cvs_unedit
69: };
70:
1.14 xsa 71: int
1.18 xsa 72: cvs_edit(int argc, char **argv)
73: {
74: int ch;
75: int flags;
76: struct cvs_recursion cr;
77:
78: flags = CR_RECURSE_DIRS;
79:
80: while ((ch = getopt(argc, argv, cvs_cmd_edit.cmd_opts)) != -1) {
81: switch (ch) {
82: case 'a':
83: if (strcmp(optarg, "edit") == 0)
84: edit_aflags |= E_EDIT;
85: else if (strcmp(optarg, "unedit") == 0)
86: edit_aflags |= E_UNEDIT;
87: else if (strcmp(optarg, "commit") == 0)
88: edit_aflags |= E_COMMIT;
89: else if (strcmp(optarg, "all") == 0)
90: edit_aflags |= E_ALL;
91: else if (strcmp(optarg, "none") == 0)
92: edit_aflags &= ~E_ALL;
93: else
94: fatal("%s", cvs_cmd_edit.cmd_synopsis);
95: break;
96: case 'l':
97: flags &= ~CR_RECURSE_DIRS;
98: break;
99: case 'R':
100: break;
101: default:
102: fatal("%s", cvs_cmd_edit.cmd_synopsis);
103: }
104: }
105:
106: argc -= optind;
107: argv += optind;
108:
109: if (argc == 0)
110: fatal("%s", cvs_cmd_edit.cmd_synopsis);
111:
112: if (edit_aflags == 0)
113: edit_aflags |= E_ALL;
114:
115: cr.enterdir = NULL;
116: cr.leavedir = NULL;
117:
118: if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
119: cr.fileproc = cvs_client_sendfile;
120:
121: if (!(flags & CR_RECURSE_DIRS))
122: cvs_client_send_request("Argument -l");
123: } else {
124: cr.fileproc = cvs_edit_local;
125: }
126:
127: cr.flags = flags;
128:
129: cvs_file_run(argc, argv, &cr);
130:
131: if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
132: cvs_client_send_files(argv, argc);
133: cvs_client_senddir(".");
134: cvs_client_send_request("edit");
135: cvs_client_get_responses();
136: }
137:
138: return (0);
139: }
140:
141: int
1.14 xsa 142: cvs_editors(int argc, char **argv)
1.1 jfb 143: {
1.12 xsa 144: int ch;
1.14 xsa 145: int flags;
146: struct cvs_recursion cr;
147:
148: flags = CR_RECURSE_DIRS;
1.1 jfb 149:
1.14 xsa 150: while ((ch = getopt(argc, argv, cvs_cmd_editors.cmd_opts)) != -1) {
1.1 jfb 151: switch (ch) {
152: case 'l':
1.14 xsa 153: flags &= ~CR_RECURSE_DIRS;
1.1 jfb 154: break;
155: case 'R':
156: break;
157: default:
1.14 xsa 158: fatal("%s", cvs_cmd_editors.cmd_synopsis);
1.1 jfb 159: }
160: }
161:
1.14 xsa 162: argc -= optind;
163: argv += optind;
1.1 jfb 164:
1.14 xsa 165: if (argc == 0)
166: fatal("%s", cvs_cmd_editors.cmd_synopsis);
1.1 jfb 167:
1.14 xsa 168: cr.enterdir = NULL;
169: cr.leavedir = NULL;
1.1 jfb 170:
1.14 xsa 171: if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
172: cr.fileproc = cvs_client_sendfile;
173:
174: if (!(flags & CR_RECURSE_DIRS))
175: cvs_client_send_request("Argument -l");
176: } else {
177: cr.fileproc = cvs_editors_local;
178: }
1.1 jfb 179:
1.14 xsa 180: cr.flags = flags;
1.9 xsa 181:
1.14 xsa 182: cvs_file_run(argc, argv, &cr);
1.9 xsa 183:
1.14 xsa 184: if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
185: cvs_client_send_files(argv, argc);
186: cvs_client_senddir(".");
187: cvs_client_send_request("editors");
188: cvs_client_get_responses();
1.9 xsa 189: }
190:
1.14 xsa 191: return (0);
192: }
1.9 xsa 193:
1.15 xsa 194: int
195: cvs_unedit(int argc, char **argv)
196: {
197: int ch;
198: int flags;
199: struct cvs_recursion cr;
200:
201: flags = CR_RECURSE_DIRS;
202:
203: while ((ch = getopt(argc, argv, cvs_cmd_unedit.cmd_opts)) != -1) {
204: switch (ch) {
205: case 'l':
206: flags &= ~CR_RECURSE_DIRS;
207: break;
208: case 'R':
209: break;
210: default:
211: fatal("%s", cvs_cmd_unedit.cmd_synopsis);
212: }
213: }
214:
215: argc -= optind;
216: argv += optind;
217:
218: if (argc == 0)
219: fatal("%s", cvs_cmd_unedit.cmd_synopsis);
220:
221: cr.enterdir = NULL;
222: cr.leavedir = NULL;
223:
224: if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
225: cr.fileproc = cvs_client_sendfile;
226:
227: if (!(flags & CR_RECURSE_DIRS))
228: cvs_client_send_request("Argument -l");
229: } else {
230: cr.fileproc = cvs_unedit_local;
231: }
232:
233: cr.flags = flags;
234:
235: cvs_file_run(argc, argv, &cr);
236:
237: if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
238: cvs_client_send_files(argv, argc);
239: cvs_client_senddir(".");
240: cvs_client_send_request("unedit");
241: cvs_client_get_responses();
242: }
243:
244: return (0);
1.18 xsa 245: }
246:
247: static void
248: cvs_edit_local(struct cvs_file *cf)
249: {
250: FILE *fp;
251: struct tm *t;
252: time_t now;
1.21 xsa 253: char *bfpath, timebuf[64], thishost[MAXHOSTNAMELEN], wdir[MAXPATHLEN];
1.18 xsa 254:
255: if (cvs_noexec == 1)
256: return;
257:
1.23 ! xsa 258: cvs_file_classify(cf, NULL, 0);
! 259:
1.18 xsa 260: if ((fp = fopen(CVS_PATH_NOTIFY, "a")) == NULL)
261: fatal("cvs_edit_local: fopen: `%s': %s",
262: CVS_PATH_NOTIFY, strerror(errno));
263:
264: (void)time(&now);
265: if ((t = gmtime(&now)) == NULL)
266: fatal("gmtime failed");
267:
1.20 xsa 268: asctime_r(t, timebuf);
269: if (timebuf[strlen(timebuf) - 1] == '\n')
270: timebuf[strlen(timebuf) - 1] = '\0';
1.18 xsa 271:
1.19 xsa 272: if (gethostname(thishost, sizeof(thishost)) == -1)
273: fatal("gethostname failed");
274:
1.21 xsa 275: if (getcwd(wdir, sizeof(wdir)) == NULL)
276: fatal("getcwd failed");
277:
1.18 xsa 278: (void)fprintf(fp, "E%s\t%s GMT\t%s\t%s\t\n",
1.21 xsa 279: cf->file_name, timebuf, thishost, wdir);
1.18 xsa 280:
281: if (edit_aflags & E_EDIT)
282: (void)fprintf(fp, "E");
283: if (edit_aflags & E_UNEDIT)
284: (void)fprintf(fp, "U");
285: if (edit_aflags & E_COMMIT)
286: (void)fprintf(fp, "C");
287:
288: (void)fprintf(fp, "\n");
289:
290: (void)fclose(fp);
291:
292: if (fchmod(cf->fd, 0644) == -1)
293: fatal("cvs_edit_local: fchmod %s", strerror(errno));
294:
295: bfpath = xmalloc(MAXPATHLEN);
296: if (cvs_path_cat(CVS_PATH_BASEDIR, cf->file_name, bfpath,
297: MAXPATHLEN) >= MAXPATHLEN)
298: fatal("cvs_edit_local: truncation");
1.22 xsa 299:
300: if (mkdir(CVS_PATH_BASEDIR, 0755) == -1 && errno != EEXIST)
301: fatal("cvs_edit_local: `%s': %s", CVS_PATH_BASEDIR,
302: strerror(errno));
1.18 xsa 303:
304: /* XXX: copy cf->file_path to bfpath */
305:
306: xfree(bfpath);
307:
1.23 ! xsa 308: (void)cvs_base_handle(cf, BASE_ADD);
1.15 xsa 309: }
310:
1.14 xsa 311: static void
312: cvs_editors_local(struct cvs_file *cf)
313: {
1.15 xsa 314: }
315:
316: static void
317: cvs_unedit_local(struct cvs_file *cf)
318: {
319: FILE *fp;
320: struct stat st;
321: struct tm *t;
322: time_t now;
1.21 xsa 323: char *bfpath, timebuf[64], thishost[MAXHOSTNAMELEN], wdir[MAXPATHLEN];
1.15 xsa 324:
325: if (cvs_noexec == 1)
326: return;
327:
1.23 ! xsa 328: cvs_file_classify(cf, NULL, 0);
! 329:
1.15 xsa 330: bfpath = xmalloc(MAXPATHLEN);
331: if (cvs_path_cat(CVS_PATH_BASEDIR, cf->file_name, bfpath,
332: MAXPATHLEN) >= MAXPATHLEN)
333: fatal("cvs_unedit_local: truncation");
334:
335: if (stat(bfpath, &st) == -1) {
336: xfree(bfpath);
337: return;
338: }
339:
1.17 xsa 340: if (cvs_file_cmp(cf->file_path, bfpath) != 0) {
341: cvs_printf("%s has been modified; revert changes? ",
342: cf->file_name);
343:
344: if (cvs_yesno() == -1) {
345: xfree(bfpath);
346: return;
347: }
348: }
1.15 xsa 349:
350: cvs_rename(bfpath, cf->file_path);
351: xfree(bfpath);
352:
353: if ((fp = fopen(CVS_PATH_NOTIFY, "a")) == NULL)
354: fatal("cvs_unedit_local: fopen: `%s': %s",
355: CVS_PATH_NOTIFY, strerror(errno));
356:
357: (void)time(&now);
358: if ((t = gmtime(&now)) == NULL)
359: fatal("gmtime failed");
360:
1.20 xsa 361: asctime_r(t, timebuf);
362: if (timebuf[strlen(timebuf) - 1] == '\n')
363: timebuf[strlen(timebuf) - 1] = '\0';
1.15 xsa 364:
1.19 xsa 365: if (gethostname(thishost, sizeof(thishost)) == -1)
366: fatal("gethostname failed");
367:
1.21 xsa 368: if (getcwd(wdir, sizeof(wdir)) == NULL)
1.23 ! xsa 369: fatal("getcwd failed");
1.21 xsa 370:
1.15 xsa 371: (void)fprintf(fp, "U%s\t%s GMT\t%s\t%s\t\n",
1.21 xsa 372: cf->file_name, timebuf, thishost, wdir);
1.15 xsa 373:
374: (void)fclose(fp);
375:
1.23 ! xsa 376: /* XXX: Update the revision number in CVS/Entries from CVS/Baserev */
1.16 xsa 377:
378: if (fchmod(cf->fd, 0644) == -1)
379: fatal("cvs_unedit_local: fchmod %s", strerror(errno));
1.23 ! xsa 380: }
! 381:
! 382: static RCSNUM *
! 383: cvs_base_handle(struct cvs_file *cf, int flags)
! 384: {
! 385: FILE *fp, *tfp;
! 386: RCSNUM *ba_rev;
! 387: size_t len;
! 388: char *filename, *filerev, *p;
! 389: char buf[MAXPATHLEN], rbuf[16];
! 390:
! 391: cvs_log(LP_TRACE, "cvs_base_handle(%s)", cf->file_path);
! 392:
! 393: tfp = NULL;
! 394: ba_rev = NULL;
! 395:
! 396: if ((fp = fopen(CVS_PATH_BASEREV, "r")) == NULL) {
! 397: cvs_log(LP_ERRNO, "%s", CVS_PATH_BASEREV);
! 398: goto out;
! 399: }
! 400:
! 401: if (flags & (BASE_ADD|BASE_REMOVE)) {
! 402: if ((tfp = fopen(CVS_PATH_BASEREVTMP, "w")) == NULL) {
! 403: cvs_log(LP_ERRNO, "%s", CVS_PATH_BASEREVTMP);
! 404: goto out;
! 405: }
! 406: }
! 407:
! 408: while(fgets(buf, sizeof(buf), fp)) {
! 409: len = strlen(buf);
! 410: if (len > 0 && buf[len - 1] == '\n')
! 411: buf[len - 1] = '\0';
! 412:
! 413: if (buf[0] != 'B')
! 414: continue;
! 415:
! 416: filename = buf;
! 417: if((p = strchr(filename, '/')) == NULL)
! 418: continue;
! 419:
! 420: filerev = p;
! 421: if ((p = strchr(filerev, '/')) == NULL)
! 422: continue;
! 423:
! 424: if (cvs_file_cmpname(filename, cf->file_path) == 0) {
! 425: if (flags & BASE_GET) {
! 426: *p = '\0';
! 427: if ((ba_rev = rcsnum_parse(filerev)) == NULL)
! 428: fatal("cvs_base_handle: rcsnum_parse");
! 429: *p = '/';
! 430: goto got_rev;
! 431: }
! 432: } else {
! 433: if (flags & (BASE_ADD|BASE_REMOVE))
! 434: (void)fprintf(tfp, "%s\n", buf);
! 435: }
! 436: }
! 437:
! 438: got_rev:
! 439: if (flags & (BASE_ADD)) {
! 440: (void)rcsnum_tostr(cf->file_ent->ce_rev, rbuf, sizeof(rbuf));
! 441: (void)fprintf(tfp, "B%s/%s/\n", cf->file_path, rbuf);
! 442: }
! 443:
! 444: out:
! 445: if (fp != NULL)
! 446: (void)fclose(fp);
! 447:
! 448: if (tfp != NULL) {
! 449: (void)fclose(tfp);
! 450: (void)cvs_rename(CVS_PATH_BASEREVTMP, CVS_PATH_BASEREV);
! 451: }
! 452:
! 453: return (ba_rev);
1.1 jfb 454: }