1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | #include <sys/stat.h> |
19 | |
20 | #include <errno.h> |
21 | #include <stdlib.h> |
22 | #include <string.h> |
23 | #include <time.h> |
24 | #include <unistd.h> |
25 | |
26 | #include "cvs.h" |
27 | #include "remote.h" |
28 | |
29 | #define E_COMMIT 0x01 |
30 | #define E_EDIT 0x02 |
31 | #define E_UNEDIT 0x04 |
32 | #define E_ALL (E_EDIT|E_COMMIT|E_UNEDIT) |
33 | |
34 | #define BASE_ADD 0x01 |
35 | #define BASE_GET 0x02 |
36 | #define BASE_REMOVE 0x04 |
37 | |
38 | static void cvs_edit_local(struct cvs_file *); |
39 | static void cvs_editors_local(struct cvs_file *); |
40 | static void cvs_unedit_local(struct cvs_file *); |
41 | |
42 | static RCSNUM *cvs_base_handle(struct cvs_file *, int); |
43 | |
44 | static int edit_aflags = 0; |
45 | |
46 | struct cvs_cmd cvs_cmd_edit = { |
47 | CVS_OP_EDIT, CVS_USE_WDIR, "edit", |
48 | { { 0 }, { 0 } }, |
49 | "Get ready to edit a watched file", |
50 | "[-lR] [-a action] [file ...]", |
51 | "a:lR", |
52 | NULL, |
53 | cvs_edit |
54 | }; |
55 | |
56 | struct cvs_cmd cvs_cmd_editors = { |
57 | CVS_OP_EDITORS, CVS_USE_WDIR, "editors", |
58 | { { 0 }, { 0 } }, |
59 | "See who is editing a watched file", |
60 | "[-lR] [file ...]", |
61 | "lR", |
62 | NULL, |
63 | cvs_editors |
64 | }; |
65 | |
66 | struct cvs_cmd cvs_cmd_unedit = { |
67 | CVS_OP_UNEDIT, CVS_USE_WDIR, "unedit", |
68 | { { 0 }, { 0 } }, |
69 | "Undo an edit command", |
70 | "[-lR] [file ...]", |
71 | "lR", |
72 | NULL, |
73 | cvs_unedit |
74 | }; |
75 | |
76 | int |
77 | cvs_edit(int argc, char **argv) |
78 | { |
79 | int ch; |
80 | int flags; |
81 | struct cvs_recursion cr; |
82 | |
83 | flags = CR_RECURSE_DIRS; |
84 | |
85 | while ((ch = getopt(argc, argv, cvs_cmd_edit.cmd_opts)) != -1) { |
86 | switch (ch) { |
87 | case 'a': |
88 | if (strcmp(optarg, "edit") == 0) |
89 | edit_aflags |= E_EDIT; |
90 | else if (strcmp(optarg, "unedit") == 0) |
91 | edit_aflags |= E_UNEDIT; |
92 | else if (strcmp(optarg, "commit") == 0) |
93 | edit_aflags |= E_COMMIT; |
94 | else if (strcmp(optarg, "all") == 0) |
95 | edit_aflags |= E_ALL; |
96 | else if (strcmp(optarg, "none") == 0) |
97 | edit_aflags &= ~E_ALL; |
98 | else |
99 | fatal("%s", cvs_cmd_edit.cmd_synopsis); |
100 | break; |
101 | case 'l': |
102 | flags &= ~CR_RECURSE_DIRS; |
103 | break; |
104 | case 'R': |
105 | flags |= CR_RECURSE_DIRS; |
106 | break; |
107 | default: |
108 | fatal("%s", cvs_cmd_edit.cmd_synopsis); |
109 | } |
110 | } |
111 | |
112 | argc -= optind; |
113 | argv += optind; |
114 | |
115 | if (argc == 0) |
116 | fatal("%s", cvs_cmd_edit.cmd_synopsis); |
117 | |
118 | if (edit_aflags == 0) |
119 | edit_aflags |= E_ALL; |
120 | |
121 | cr.enterdir = NULL; |
122 | cr.leavedir = NULL; |
123 | |
124 | if (cvsroot_is_remote()) { |
125 | cvs_client_connect_to_server(); |
126 | cr.fileproc = cvs_client_sendfile; |
127 | |
128 | if (!(flags & CR_RECURSE_DIRS)) |
129 | cvs_client_send_request("Argument -l"); |
130 | } else { |
131 | cr.fileproc = cvs_edit_local; |
132 | } |
133 | |
134 | cr.flags = flags; |
135 | |
136 | cvs_file_run(argc, argv, &cr); |
137 | |
138 | if (cvsroot_is_remote()) { |
139 | cvs_client_send_files(argv, argc); |
140 | cvs_client_senddir("."); |
141 | cvs_client_send_request("edit"); |
142 | cvs_client_get_responses(); |
143 | } |
144 | |
145 | return (0); |
146 | } |
147 | |
148 | int |
149 | cvs_editors(int argc, char **argv) |
150 | { |
151 | int ch; |
152 | int flags; |
153 | struct cvs_recursion cr; |
154 | |
155 | flags = CR_RECURSE_DIRS; |
156 | |
157 | while ((ch = getopt(argc, argv, cvs_cmd_editors.cmd_opts)) != -1) { |
158 | switch (ch) { |
159 | case 'l': |
160 | flags &= ~CR_RECURSE_DIRS; |
161 | break; |
162 | case 'R': |
163 | flags |= CR_RECURSE_DIRS; |
164 | break; |
165 | default: |
166 | fatal("%s", cvs_cmd_editors.cmd_synopsis); |
167 | } |
168 | } |
169 | |
170 | argc -= optind; |
171 | argv += optind; |
172 | |
173 | if (argc == 0) |
174 | fatal("%s", cvs_cmd_editors.cmd_synopsis); |
175 | |
176 | cr.enterdir = NULL; |
177 | cr.leavedir = NULL; |
178 | |
179 | if (cvsroot_is_remote()) { |
180 | cvs_client_connect_to_server(); |
181 | cr.fileproc = cvs_client_sendfile; |
182 | |
183 | if (!(flags & CR_RECURSE_DIRS)) |
184 | cvs_client_send_request("Argument -l"); |
185 | } else { |
186 | cr.fileproc = cvs_editors_local; |
187 | } |
188 | |
189 | cr.flags = flags; |
190 | |
191 | cvs_file_run(argc, argv, &cr); |
192 | |
193 | if (cvsroot_is_remote()) { |
194 | cvs_client_send_files(argv, argc); |
195 | cvs_client_senddir("."); |
196 | cvs_client_send_request("editors"); |
197 | cvs_client_get_responses(); |
198 | } |
199 | |
200 | return (0); |
201 | } |
202 | |
203 | int |
204 | cvs_unedit(int argc, char **argv) |
205 | { |
206 | int ch; |
207 | int flags; |
208 | struct cvs_recursion cr; |
209 | |
210 | flags = CR_RECURSE_DIRS; |
211 | |
212 | while ((ch = getopt(argc, argv, cvs_cmd_unedit.cmd_opts)) != -1) { |
213 | switch (ch) { |
214 | case 'l': |
215 | flags &= ~CR_RECURSE_DIRS; |
216 | break; |
217 | case 'R': |
218 | flags |= CR_RECURSE_DIRS; |
219 | break; |
220 | default: |
221 | fatal("%s", cvs_cmd_unedit.cmd_synopsis); |
222 | } |
223 | } |
224 | |
225 | argc -= optind; |
226 | argv += optind; |
227 | |
228 | if (argc == 0) |
229 | fatal("%s", cvs_cmd_unedit.cmd_synopsis); |
230 | |
231 | cr.enterdir = NULL; |
232 | cr.leavedir = NULL; |
233 | |
234 | if (cvsroot_is_remote()) { |
235 | cvs_client_connect_to_server(); |
236 | cr.fileproc = cvs_client_sendfile; |
237 | |
238 | if (!(flags & CR_RECURSE_DIRS)) |
239 | cvs_client_send_request("Argument -l"); |
240 | } else { |
241 | cr.fileproc = cvs_unedit_local; |
242 | } |
243 | |
244 | cr.flags = flags; |
245 | |
246 | cvs_file_run(argc, argv, &cr); |
247 | |
248 | if (cvsroot_is_remote()) { |
249 | cvs_client_send_files(argv, argc); |
250 | cvs_client_senddir("."); |
251 | cvs_client_send_request("unedit"); |
252 | cvs_client_get_responses(); |
253 | } |
254 | |
255 | return (0); |
256 | } |
257 | |
258 | static void |
259 | cvs_edit_local(struct cvs_file *cf) |
260 | { |
261 | FILE *fp; |
262 | struct tm t; |
263 | time_t now; |
264 | char timebuf[CVS_TIME_BUFSZ], thishost[HOST_NAME_MAX+1]; |
265 | char bfpath[PATH_MAX], wdir[PATH_MAX]; |
266 | |
267 | if (cvs_noexec == 1) |
268 | return; |
269 | |
270 | cvs_log(LP_TRACE, "cvs_edit_local(%s)", cf->file_path); |
271 | |
272 | cvs_file_classify(cf, cvs_directory_tag); |
273 | |
274 | if ((fp = fopen(CVS_PATH_NOTIFY, "a")) == NULL) |
275 | fatal("cvs_edit_local: fopen: `%s': %s", |
276 | CVS_PATH_NOTIFY, strerror(errno)); |
277 | |
278 | (void)time(&now); |
279 | gmtime_r(&now, &t); |
280 | asctime_r(&t, timebuf); |
281 | timebuf[strcspn(timebuf, "\n")] = '\0'; |
282 | |
283 | if (gethostname(thishost, sizeof(thishost)) == -1) |
284 | fatal("gethostname failed"); |
285 | |
286 | if (getcwd(wdir, sizeof(wdir)) == NULL) |
287 | fatal("getcwd failed"); |
288 | |
289 | (void)fprintf(fp, "E%s\t%s GMT\t%s\t%s\t", |
290 | cf->file_name, timebuf, thishost, wdir); |
291 | |
292 | if (edit_aflags & E_EDIT) |
293 | (void)fprintf(fp, "E"); |
294 | if (edit_aflags & E_UNEDIT) |
295 | (void)fprintf(fp, "U"); |
296 | if (edit_aflags & E_COMMIT) |
297 | (void)fprintf(fp, "C"); |
298 | |
299 | (void)fprintf(fp, "\n"); |
300 | |
301 | (void)fclose(fp); |
302 | |
303 | if (fchmod(cf->fd, 0644) == -1) |
304 | fatal("cvs_edit_local: fchmod %s", strerror(errno)); |
305 | |
306 | (void)xsnprintf(bfpath, PATH_MAX, "%s/%s", |
307 | CVS_PATH_BASEDIR, cf->file_name); |
308 | |
309 | if (mkdir(CVS_PATH_BASEDIR, 0755) == -1 && errno != EEXIST) |
310 | fatal("cvs_edit_local: `%s': %s", CVS_PATH_BASEDIR, |
311 | strerror(errno)); |
312 | |
313 | if (cvs_file_copy(cf->file_path, bfpath) == -1) |
314 | fatal("cvs_edit_local: cvs_file_copy failed"); |
315 | |
316 | (void)cvs_base_handle(cf, BASE_ADD); |
317 | } |
318 | |
319 | static void |
320 | cvs_editors_local(struct cvs_file *cf) |
321 | { |
322 | } |
323 | |
324 | static void |
325 | cvs_unedit_local(struct cvs_file *cf) |
326 | { |
327 | FILE *fp; |
328 | struct stat st; |
329 | struct tm t; |
330 | time_t now; |
331 | char bfpath[PATH_MAX], timebuf[64], thishost[HOST_NAME_MAX+1]; |
332 | char wdir[PATH_MAX], sticky[CVS_ENT_MAXLINELEN]; |
333 | RCSNUM *ba_rev; |
334 | |
335 | cvs_log(LP_TRACE, "cvs_unedit_local(%s)", cf->file_path); |
336 | |
337 | if (cvs_noexec == 1) |
| 1 | Assuming 'cvs_noexec' is not equal to 1 | |
|
| |
338 | return; |
339 | |
340 | cvs_file_classify(cf, cvs_directory_tag); |
341 | |
342 | (void)xsnprintf(bfpath, PATH_MAX, "%s/%s", |
343 | CVS_PATH_BASEDIR, cf->file_name); |
344 | |
345 | if (stat(bfpath, &st) == -1) |
| 3 | | Assuming the condition is false | |
|
| |
346 | return; |
347 | |
348 | if (cvs_file_cmp(cf->file_path, bfpath) != 0) { |
| 5 | | Assuming the condition is false | |
|
| |
349 | cvs_printf("%s has been modified; revert changes? ", |
350 | cf->file_name); |
351 | |
352 | if (cvs_yesno() == -1) |
353 | return; |
354 | } |
355 | |
356 | cvs_rename(bfpath, cf->file_path); |
357 | |
358 | if ((fp = fopen(CVS_PATH_NOTIFY, "a")) == NULL) |
| 7 | | Assuming the condition is false | |
|
| |
359 | fatal("cvs_unedit_local: fopen: `%s': %s", |
360 | CVS_PATH_NOTIFY, strerror(errno)); |
361 | |
362 | (void)time(&now); |
363 | gmtime_r(&now, &t); |
364 | asctime_r(&t, timebuf); |
365 | timebuf[strcspn(timebuf, "\n")] = '\0'; |
366 | |
367 | if (gethostname(thishost, sizeof(thishost)) == -1) |
| 9 | | Assuming the condition is false | |
|
| |
368 | fatal("gethostname failed"); |
369 | |
370 | if (getcwd(wdir, sizeof(wdir)) == NULL) |
| 11 | | Assuming the condition is false | |
|
| |
371 | fatal("getcwd failed"); |
372 | |
373 | (void)fprintf(fp, "U%s\t%s GMT\t%s\t%s\t\n", |
374 | cf->file_name, timebuf, thishost, wdir); |
375 | |
376 | (void)fclose(fp); |
377 | |
378 | if ((ba_rev = cvs_base_handle(cf, BASE_GET)) == NULL) { |
| 13 | | Calling 'cvs_base_handle' | |
|
379 | cvs_log(LP_ERR, "%s not mentioned in %s", |
380 | cf->file_name, CVS_PATH_BASEREV); |
381 | return; |
382 | } |
383 | |
384 | if (cf->file_ent != NULL) { |
385 | CVSENTRIES *entlist; |
386 | struct cvs_ent *ent; |
387 | char *entry, rbuf[CVS_REV_BUFSZ]; |
388 | |
389 | entlist = cvs_ent_open(cf->file_wd); |
390 | |
391 | if ((ent = cvs_ent_get(entlist, cf->file_name)) == NULL) |
392 | fatal("cvs_unedit_local: cvs_ent_get failed"); |
393 | |
394 | (void)rcsnum_tostr(ba_rev, rbuf, sizeof(rbuf)); |
395 | |
396 | memset(timebuf, 0, sizeof(timebuf)); |
397 | ctime_r(&cf->file_ent->ce_mtime, timebuf); |
398 | timebuf[strcspn(timebuf, "\n")] = '\0'; |
399 | |
400 | sticky[0] = '\0'; |
401 | if (cf->file_ent->ce_tag != NULL) |
402 | (void)xsnprintf(sticky, sizeof(sticky), "T%s", |
403 | cf->file_ent->ce_tag); |
404 | |
405 | (void)xasprintf(&entry, "/%s/%s/%s/%s/%s", |
406 | cf->file_name, rbuf, timebuf, cf->file_ent->ce_opts ? |
407 | cf->file_ent->ce_opts : "", sticky); |
408 | |
409 | cvs_ent_add(entlist, entry); |
410 | |
411 | cvs_ent_free(ent); |
412 | |
413 | free(entry); |
414 | } |
415 | |
416 | free(ba_rev); |
417 | |
418 | (void)cvs_base_handle(cf, BASE_REMOVE); |
419 | |
420 | if (fchmod(cf->fd, 0644) == -1) |
421 | fatal("cvs_unedit_local: fchmod %s", strerror(errno)); |
422 | } |
423 | |
424 | static RCSNUM * |
425 | cvs_base_handle(struct cvs_file *cf, int flags) |
426 | { |
427 | FILE *fp, *tfp; |
428 | RCSNUM *ba_rev; |
429 | int i; |
430 | char *dp, *sp; |
431 | char buf[PATH_MAX], *fields[2], rbuf[CVS_REV_BUFSZ]; |
432 | |
433 | cvs_log(LP_TRACE, "cvs_base_handle(%s)", cf->file_path); |
434 | |
435 | tfp = NULL; |
436 | ba_rev = NULL; |
437 | |
438 | if (((fp = fopen(CVS_PATH_BASEREV, "r")) == NULL) && errno != ENOENT) { |
| 14 | | Assuming the condition is false | |
|
439 | cvs_log(LP_ERRNO, "%s", CVS_PATH_BASEREV); |
440 | goto out; |
441 | } |
442 | |
443 | if (flags & (BASE_ADD|BASE_REMOVE)) { |
| |
444 | if ((tfp = fopen(CVS_PATH_BASEREVTMP, "w")) == NULL) { |
445 | cvs_log(LP_ERRNO, "%s", CVS_PATH_BASEREVTMP); |
446 | goto out; |
447 | } |
448 | } |
449 | |
450 | if (fp != NULL) { |
| |
451 | while (fgets(buf, sizeof(buf), fp)) { |
| 17 | | Loop condition is true. Entering loop body | |
|
452 | buf[strcspn(buf, "\n")] = '\0'; |
453 | |
454 | if (buf[0] != 'B') |
| 18 | | Assuming the condition is false | |
|
| |
455 | continue; |
456 | |
457 | sp = buf + 1; |
458 | i = 0; |
459 | do { |
| 22 | | Loop condition is false. Exiting loop | |
|
460 | if ((dp = strchr(sp, '/')) != NULL) |
| 20 | | Assuming the condition is false | |
|
| |
461 | *(dp++) = '\0'; |
462 | fields[i++] = sp; |
463 | sp = dp; |
464 | } while (dp != NULL && i < 2); |
465 | |
466 | if (cvs_file_cmpname(fields[0], cf->file_path) == 0) { |
| 23 | | Assuming the condition is true | |
|
| |
467 | if (flags & BASE_GET) { |
| |
468 | ba_rev = rcsnum_parse(fields[1]); |
| 26 | | 1st function call argument is an uninitialized value |
|
469 | if (ba_rev == NULL) |
470 | fatal("cvs_base_handle: " |
471 | "rcsnum_parse"); |
472 | goto got_rev; |
473 | } |
474 | } else { |
475 | if (flags & (BASE_ADD|BASE_REMOVE)) |
476 | (void)fprintf(tfp, "%s\n", buf); |
477 | } |
478 | } |
479 | } |
480 | |
481 | got_rev: |
482 | if (flags & (BASE_ADD)) { |
483 | (void)rcsnum_tostr(cf->file_ent->ce_rev, rbuf, sizeof(rbuf)); |
484 | (void)fprintf(tfp, "B%s/%s/\n", cf->file_path, rbuf); |
485 | } |
486 | |
487 | out: |
488 | if (fp != NULL) |
489 | (void)fclose(fp); |
490 | |
491 | if (tfp != NULL) { |
492 | (void)fclose(tfp); |
493 | (void)cvs_rename(CVS_PATH_BASEREVTMP, CVS_PATH_BASEREV); |
494 | } |
495 | |
496 | return (ba_rev); |
497 | } |