Annotation of src/usr.bin/rcs/ci.c, Revision 1.58
1.58 ! niallo 1: /* $OpenBSD: ci.c,v 1.57 2005/11/08 15:58:38 xsa Exp $ */
1.1 niallo 2: /*
3: * Copyright (c) 2005 Niall O'Higgins <niallo@openbsd.org>
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following cinditions
8: * are met:
9: *
10: * 1. Redistributions of source cide must retain the above cipyright
11: * notice, this list of cinditions and the following disclaimer.
12: * 2. The name of the author may not be used to endorse or promote products
13: * derived from this software without specific prior written permission.
14: *
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: #include <sys/param.h>
28: #include <sys/types.h>
29: #include <sys/stat.h>
30: #include <sys/wait.h>
31:
32: #include <err.h>
33: #include <pwd.h>
34: #include <errno.h>
35: #include <stdio.h>
36: #include <ctype.h>
37: #include <stdlib.h>
38: #include <unistd.h>
39: #include <string.h>
1.20 niallo 40: #include <time.h>
1.1 niallo 41:
42: #include "log.h"
43: #include "rcs.h"
1.4 niallo 44: #include "diff.h"
1.1 niallo 45: #include "rcsprog.h"
1.9 niallo 46:
1.58 ! niallo 47: #define CI_OPTSTRING "d::f::i::j::k:l::m:M::N:n:qr::s:u::Vw:"
1.25 niallo 48: #define DATE_NOW -1
49: #define DATE_MTIME -2
50:
1.58 ! niallo 51: #define LOG_INIT "Initial revision"
! 52: #define LOG_PROMPT "enter log message, terminated with a single '.' " \
! 53: "or end of file:\n>> "
! 54: #define DESC_PROMPT "enter description, terminated with single '.' " \
! 55: "or end of file:\nNOTE: This is NOT the log message!\n"
! 56:
! 57: struct checkin_params {
! 58: int flags, openflags;
! 59: mode_t fmode;
! 60: time_t date;
! 61: RCSFILE *file;
! 62: RCSNUM *frev, *newrev;
! 63: char fpath[MAXPATHLEN], *rcs_msg, *username, *deltatext, *filename;
! 64: const char *symbol, *state;
! 65: };
! 66:
! 67: static int checkin_attach_symbol(struct checkin_params *pb);
! 68: static int checkin_checklock(struct checkin_params *pb);
! 69: static char * checkin_diff_file(struct checkin_params *);
! 70: static char * checkin_getdesc(void);
! 71: static char * checkin_getinput(const char *);
1.34 niallo 72: static char * checkin_getlogmsg(RCSNUM *, RCSNUM *);
1.58 ! niallo 73: static void checkin_init(struct checkin_params *);
! 74: static void checkin_revert(struct checkin_params *pb);
1.4 niallo 75:
1.1 niallo 76: void
77: checkin_usage(void)
78: {
79: fprintf(stderr,
1.58 ! niallo 80: "usage: ci [-MNqV] [-d[date]] [-f[rev]] [-i[rev]] [-j[rev]]\n"
! 81: " [-kmode] [-l[rev]] [-M[rev]] [-mmsg] [-Nsymbol]\n"
! 82: " [-nsymbol] [-r[rev]] [-sstate] [-u[rev]] [-wusername]\n"
! 83: " file ...\n");
! 84: }
! 85:
1.55 niallo 86:
1.1 niallo 87:
88: /*
89: * checkin_main()
90: *
91: * Handler for the `ci' program.
92: * Returns 0 on success, or >0 on error.
93: */
94: int
95: checkin_main(int argc, char **argv)
96: {
1.58 ! niallo 97: int i, ch, status;
! 98: char *filec;
! 99: struct stat sb;
! 100: struct checkin_params pb;
1.4 niallo 101: BUF *bp;
1.1 niallo 102:
1.58 ! niallo 103: pb.date = DATE_NOW;
! 104: pb.file = NULL;
! 105: pb.rcs_msg = pb.username = NULL;
! 106: pb.state = pb.symbol = NULL;
! 107: pb.newrev = NULL;
! 108: pb.fmode = pb.flags = status = 0;
1.1 niallo 109:
1.58 ! niallo 110: pb.flags = INTERACTIVE;
! 111: pb.openflags = RCS_RDWR|RCS_CREATE;
1.9 niallo 112:
1.58 ! niallo 113: while ((ch = rcs_getopt(argc, argv, CI_OPTSTRING)) != -1) {
1.1 niallo 114: switch (ch) {
1.20 niallo 115: case 'd':
1.25 niallo 116: if (rcs_optarg == NULL)
1.58 ! niallo 117: pb.date = DATE_MTIME;
! 118: else if ((pb.date = cvs_date_parse(rcs_optarg)) <= 0) {
1.20 niallo 119: cvs_log(LP_ERR, "invalide date");
120: exit(1);
121: }
122: break;
1.29 niallo 123: case 'f':
1.58 ! niallo 124: rcs_set_rev(rcs_optarg, &pb.newrev);
! 125: pb.flags |= FORCE;
1.29 niallo 126: break;
1.1 niallo 127: case 'h':
128: (usage)();
129: exit(0);
1.58 ! niallo 130: case 'i':
! 131: rcs_set_rev(rcs_optarg, &pb.newrev);
! 132: pb.openflags |= RCS_CREATE;
! 133: break;
! 134: case 'j':
! 135: rcs_set_rev(rcs_optarg, &pb.newrev);
! 136: pb.openflags &= ~RCS_CREATE;
! 137: break;
1.30 niallo 138: case 'l':
1.58 ! niallo 139: rcs_set_rev(rcs_optarg, &pb.newrev);
! 140: pb.flags |= CO_LOCK;
1.54 niallo 141: break;
142: case 'M':
1.58 ! niallo 143: rcs_set_rev(rcs_optarg, &pb.newrev);
! 144: pb.flags |= CO_REVDATE;
1.30 niallo 145: break;
1.1 niallo 146: case 'm':
1.58 ! niallo 147: pb.rcs_msg = rcs_optarg;
! 148: if (pb.rcs_msg == NULL) {
! 149: cvs_log(LP_ERR,
! 150: "missing message for -m option");
! 151: exit(1);
! 152: }
! 153: pb.flags &= ~INTERACTIVE;
1.3 joris 154: break;
1.42 niallo 155: case 'N':
1.58 ! niallo 156: if ((pb.symbol = strdup(rcs_optarg)) == NULL) {
1.42 niallo 157: cvs_log(LP_ERRNO, "out of memory");
158: exit(1);
159: }
1.58 ! niallo 160: if (rcs_sym_check(pb.symbol) != 1) {
! 161: cvs_log(LP_ERR, "invalid symbol `%s'",
! 162: pb.symbol);
1.42 niallo 163: exit(1);
164: }
1.58 ! niallo 165: pb.flags |= CI_SYMFORCE;
1.42 niallo 166: break;
1.38 niallo 167: case 'n':
1.58 ! niallo 168: if ((pb.symbol = strdup(rcs_optarg)) == NULL) {
1.38 niallo 169: cvs_log(LP_ERRNO, "out of memory");
170: exit(1);
171: }
1.58 ! niallo 172: if (rcs_sym_check(pb.symbol) != 1) {
! 173: cvs_log(LP_ERR, "invalid symbol `%s'",
! 174: pb.symbol);
1.38 niallo 175: exit(1);
176: }
177: break;
1.3 joris 178: case 'q':
179: verbose = 0;
1.1 niallo 180: break;
1.30 niallo 181: case 'r':
1.58 ! niallo 182: rcs_set_rev(rcs_optarg, &pb.newrev);
! 183: pb.flags |= CI_DEFAULT;
1.9 niallo 184: break;
1.51 niallo 185: case 's':
1.58 ! niallo 186: pb.state = rcs_optarg;
! 187: if (rcs_state_check(pb.state) < 0) {
! 188: cvs_log(LP_ERR, "invalid state `%s'",
! 189: pb.state);
1.51 niallo 190: exit(1);
191: }
192: break;
1.9 niallo 193: case 'u':
1.58 ! niallo 194: rcs_set_rev(rcs_optarg, &pb.newrev);
! 195: pb.flags |= CO_UNLOCK;
1.9 niallo 196: break;
1.30 niallo 197: case 'V':
198: printf("%s\n", rcs_version);
199: exit(0);
1.31 niallo 200: case 'w':
1.58 ! niallo 201: pb.username = rcs_optarg;
1.31 niallo 202: break;
1.1 niallo 203: default:
204: (usage)();
205: exit(1);
206: }
207: }
208:
1.24 joris 209: argc -= rcs_optind;
210: argv += rcs_optind;
211:
1.1 niallo 212: if (argc == 0) {
213: cvs_log(LP_ERR, "no input file");
214: (usage)();
215: exit(1);
216: }
217:
1.58 ! niallo 218: if ((pb.username == NULL) && (pb.username = getlogin()) == NULL) {
1.31 niallo 219: cvs_log(LP_ERRNO, "failed to get username");
220: exit(1);
221: }
222:
223:
1.1 niallo 224: for (i = 0; i < argc; i++) {
1.58 ! niallo 225: pb.filename = argv[i];
! 226: if (rcs_statfile(pb.filename, pb.fpath, sizeof(pb.fpath)) < 0)
1.1 niallo 227: continue;
228:
1.58 ! niallo 229: /*
! 230: * Test for existence of ,v file. If we are expected to
! 231: * create one, set NEWFILE flag.
! 232: */
! 233: if ((pb.openflags & RCS_CREATE) && (stat(pb.fpath, &sb) < 0))
! 234: pb.flags |= NEWFILE;
! 235: else
! 236: pb.openflags &= ~RCS_CREATE;
! 237:
! 238: pb.file = rcs_open(pb.fpath, pb.openflags, pb.fmode);
! 239:
! 240: if (pb.file == NULL) {
! 241: cvs_log(LP_ERR, "failed to open rcsfile '%s'", pb.fpath);
1.1 niallo 242: exit(1);
243: }
1.29 niallo 244:
1.58 ! niallo 245: if (verbose == 1)
! 246: printf("%s <-- %s\n", pb.fpath, pb.filename);
1.36 niallo 247:
1.58 ! niallo 248: pb.frev = pb.file->rf_head;
1.29 niallo 249:
1.17 niallo 250: /*
251: * If revision passed on command line is less than HEAD, bail.
252: */
1.58 ! niallo 253: if ((pb.newrev != NULL)
! 254: && (rcsnum_cmp(pb.newrev, pb.frev, 0) > 0)) {
1.17 niallo 255: cvs_log(LP_ERR, "revision is too low!");
256: status = 1;
1.58 ! niallo 257: rcs_close(pb.file);
1.17 niallo 258: continue;
259: }
1.4 niallo 260:
261: /*
262: * Load file contents
263: */
264: if ((bp = cvs_buf_load(argv[i], BUF_AUTOEXT)) == NULL) {
1.58 ! niallo 265: cvs_log(LP_ERR, "failed to load '%s'", pb.filename);
1.4 niallo 266: exit(1);
267: }
268:
1.12 niallo 269: if (cvs_buf_putc(bp, '\0') < 0)
270: exit(1);
271:
1.23 niallo 272: filec = (char *)cvs_buf_release(bp);
1.13 joris 273:
1.6 niallo 274: /*
1.29 niallo 275: * Get RCS patch
276: */
1.58 ! niallo 277: if ((pb.deltatext = checkin_diff_file(&pb)) == NULL) {
1.29 niallo 278: cvs_log(LP_ERR, "failed to get diff");
279: exit(1);
280: }
281:
282: /*
1.58 ! niallo 283: * If -f is not specified and there are no differences, tell
! 284: * the user and revert to latest version.
1.29 niallo 285: */
1.58 ! niallo 286: if (!(pb.flags & FORCE) && (strlen(pb.deltatext) < 1)) {
! 287: checkin_revert(&pb);
1.29 niallo 288: continue;
289: }
290:
291: /*
1.16 niallo 292: * Check for a lock belonging to this user. If none,
293: * abort check-in.
294: */
1.58 ! niallo 295: if (checkin_checklock(&pb) < 0) {
1.16 niallo 296: status = 1;
297: continue;
298: }
299:
300: /*
1.6 niallo 301: * If no log message specified, get it interactively.
302: */
1.58 ! niallo 303: if (pb.flags & INTERACTIVE)
! 304: pb.rcs_msg = checkin_getlogmsg(pb.frev, pb.newrev);
1.4 niallo 305:
306: /*
307: * Remove the lock
308: */
1.58 ! niallo 309: if (rcs_lock_remove(pb.file, pb.frev) < 0) {
1.4 niallo 310: if (rcs_errno != RCS_ERR_NOENT)
311: cvs_log(LP_WARN, "failed to remove lock");
312: }
313:
314: /*
315: * Current head revision gets the RCS patch as rd_text
316: */
1.58 ! niallo 317: if (rcs_deltatext_set(pb.file, pb.frev, pb.deltatext) == -1) {
1.7 niallo 318: cvs_log(LP_ERR,
319: "failed to set new rd_text for head rev");
1.4 niallo 320: exit (1);
1.25 niallo 321: }
1.32 joris 322:
1.25 niallo 323: /*
1.58 ! niallo 324: * Set the date of the revision to be the last modification
! 325: * time of the working file if -d has no argument.
1.25 niallo 326: */
1.58 ! niallo 327: if (pb.date == DATE_MTIME) {
! 328: if (stat(pb.filename, &sb) != 0) {
1.33 niallo 329: cvs_log(LP_ERRNO, "failed to stat: `%s'",
1.58 ! niallo 330: pb.filename);
! 331: rcs_close(pb.file);
1.25 niallo 332: continue;
333: }
1.58 ! niallo 334: pb.date = (time_t)sb.st_mtimespec.tv_sec;
1.4 niallo 335: }
1.32 joris 336:
1.4 niallo 337: /*
338: * Now add our new revision
339: */
1.58 ! niallo 340: if (rcs_rev_add(pb.file,
! 341: (pb.newrev == NULL ? RCS_HEAD_REV : pb.newrev),
! 342: pb.rcs_msg, pb.date, pb.username) != 0) {
1.4 niallo 343: cvs_log(LP_ERR, "failed to add new revision");
344: exit(1);
345: }
346:
347: /*
1.12 niallo 348: * If we are checking in to a non-default (ie user-specified)
349: * revision, set head to this revision.
350: */
1.58 ! niallo 351: if (pb.newrev != NULL)
! 352: rcs_head_set(pb.file, pb.newrev);
1.15 niallo 353: else
1.58 ! niallo 354: pb.newrev = pb.file->rf_head;
1.32 joris 355:
1.12 niallo 356: /*
1.4 niallo 357: * New head revision has to contain entire file;
358: */
1.58 ! niallo 359: if (rcs_deltatext_set(pb.file, pb.frev, filec) == -1) {
1.4 niallo 360: cvs_log(LP_ERR, "failed to set new head revision");
361: exit(1);
1.38 niallo 362: }
363:
364: /*
365: * Attach a symbolic name to this revision if specified.
366: */
1.58 ! niallo 367: if (pb.symbol != NULL
! 368: && (checkin_attach_symbol(&pb) < 0)) {
! 369: status = 1;
! 370: continue;
1.4 niallo 371: }
1.51 niallo 372:
373: /*
374: * Set the state of this revision if specified.
375: */
1.58 ! niallo 376: if (pb.state != NULL)
! 377: (void)rcs_state_set(pb.file, pb.newrev, pb.state);
1.4 niallo 378:
1.58 ! niallo 379: free(pb.deltatext);
1.4 niallo 380: free(filec);
1.58 ! niallo 381: (void)unlink(pb.filename);
1.4 niallo 382:
1.9 niallo 383: /*
384: * Do checkout if -u or -l are specified.
385: */
1.58 ! niallo 386: if (((pb.flags & CO_LOCK) || (pb.flags & CO_UNLOCK))
! 387: && !(pb.flags & CI_DEFAULT))
! 388: checkout_rev(pb.file, pb.newrev, pb.filename, pb.flags,
! 389: pb.username);
1.28 niallo 390:
1.4 niallo 391: /* File will NOW be synced */
1.58 ! niallo 392: rcs_close(pb.file);
1.4 niallo 393:
1.58 ! niallo 394: if (pb.flags & INTERACTIVE) {
! 395: free(pb.rcs_msg);
! 396: pb.rcs_msg = NULL;
1.6 niallo 397: }
1.4 niallo 398: }
399:
1.16 niallo 400: return (status);
1.4 niallo 401: }
402:
403: static char *
1.58 ! niallo 404: checkin_diff_file(struct checkin_params *pb)
1.4 niallo 405: {
406: char path1[MAXPATHLEN], path2[MAXPATHLEN];
407: BUF *b1, *b2, *b3;
408: char rbuf[64], *deltatext;
409:
1.58 ! niallo 410: rcsnum_tostr(pb->frev, rbuf, sizeof(rbuf));
1.4 niallo 411:
1.58 ! niallo 412: if ((b1 = cvs_buf_load(pb->filename, BUF_AUTOEXT)) == NULL) {
! 413: cvs_log(LP_ERR, "failed to load file: '%s'", pb->filename);
1.4 niallo 414: return (NULL);
1.1 niallo 415: }
416:
1.58 ! niallo 417: if ((b2 = rcs_getrev(pb->file, pb->frev)) == NULL) {
1.4 niallo 418: cvs_log(LP_ERR, "failed to load revision");
419: cvs_buf_free(b1);
420: return (NULL);
421: }
422:
1.57 xsa 423: if ((b3 = cvs_buf_alloc((size_t)128, BUF_AUTOEXT)) == NULL) {
1.4 niallo 424: cvs_log(LP_ERR, "failed to allocated buffer for diff");
425: cvs_buf_free(b1);
426: cvs_buf_free(b2);
427: return (NULL);
428: }
429:
1.50 xsa 430: strlcpy(path1, rcs_tmpdir, sizeof(path1));
431: strlcat(path1, "/diff1.XXXXXXXXXX", sizeof(path1));
1.4 niallo 432: if (cvs_buf_write_stmp(b1, path1, 0600) == -1) {
433: cvs_log(LP_ERRNO, "could not write temporary file");
434: cvs_buf_free(b1);
435: cvs_buf_free(b2);
436: return (NULL);
437: }
438: cvs_buf_free(b1);
439:
1.50 xsa 440: strlcpy(path2, rcs_tmpdir, sizeof(path2));
441: strlcat(path2, "/diff2.XXXXXXXXXX", sizeof(path2));
1.4 niallo 442: if (cvs_buf_write_stmp(b2, path2, 0600) == -1) {
443: cvs_buf_free(b2);
444: (void)unlink(path1);
445: return (NULL);
446: }
447: cvs_buf_free(b2);
448:
1.5 niallo 449: diff_format = D_RCSDIFF;
1.4 niallo 450: cvs_diffreg(path1, path2, b3);
451: (void)unlink(path1);
452: (void)unlink(path2);
453:
454: cvs_buf_putc(b3, '\0');
455: deltatext = (char *)cvs_buf_release(b3);
456:
457: return (deltatext);
1.6 niallo 458: }
459:
460: /*
461: * Get log message from user interactively.
462: */
463: static char *
1.34 niallo 464: checkin_getlogmsg(RCSNUM *rev, RCSNUM *rev2)
1.6 niallo 465: {
1.58 ! niallo 466: char *rcs_msg, nrev[16], prev[16];
1.6 niallo 467: RCSNUM *tmprev;
468:
1.7 niallo 469: rcs_msg = NULL;
1.6 niallo 470: tmprev = rcsnum_alloc();
471: rcsnum_cpy(rev, tmprev, 16);
1.9 niallo 472: rcsnum_tostr(tmprev, prev, sizeof(prev));
1.12 niallo 473: if (rev2 == NULL)
474: rcsnum_tostr(rcsnum_inc(tmprev), nrev, sizeof(nrev));
475: else
476: rcsnum_tostr(rev2, nrev, sizeof(nrev));
1.6 niallo 477: rcsnum_free(tmprev);
478:
1.47 niallo 479: if (verbose == 1)
480: printf("new revision: %s; previous revision: %s\n", nrev,
481: prev);
1.32 joris 482:
1.58 ! niallo 483: rcs_msg = checkin_getinput(LOG_PROMPT);
! 484: return (rcs_msg);
! 485: }
! 486:
! 487:
! 488: /*
! 489: * checkin_getdesc()
! 490: *
! 491: * Get file description interactively.
! 492: * Returns NULL on failure.
! 493: */
! 494: static char *
! 495: checkin_getdesc()
! 496: {
! 497: char *description;
! 498:
! 499: description = checkin_getinput(DESC_PROMPT);
! 500: return (description);
! 501: }
! 502:
! 503: /*
! 504: * checkin_getinput()
! 505: *
! 506: * Get some input from the user.
! 507: */
! 508: static char *
! 509: checkin_getinput(const char *prompt)
! 510: {
! 511: BUF *inputbuf;
! 512: char *input, buf[128];
! 513:
! 514: if ((inputbuf = cvs_buf_alloc((size_t)64, BUF_AUTOEXT)) == NULL) {
! 515: cvs_log(LP_ERR, "failed to allocate input buffer");
! 516: return (NULL);
! 517: }
! 518:
! 519: printf(prompt);
1.6 niallo 520: for (;;) {
521: fgets(buf, (int)sizeof(buf), stdin);
1.9 niallo 522: if (feof(stdin) || ferror(stdin) || buf[0] == '.')
1.6 niallo 523: break;
1.58 ! niallo 524: cvs_buf_append(inputbuf, buf, strlen(buf));
1.46 joris 525: printf(">> ");
1.6 niallo 526: }
1.32 joris 527:
1.58 ! niallo 528: cvs_buf_putc(inputbuf, '\0');
! 529: input = (char *)cvs_buf_release(inputbuf);
! 530:
! 531: return (input);
! 532: }
! 533:
! 534: /*
! 535: * checkin_init()
! 536: *
! 537: * Does an initial check in, just enough to create the new ,v file
! 538: */
! 539: static void
! 540: checkin_init(struct checkin_params *pb)
! 541: {
! 542: BUF *bp;
! 543: char *rcs_desc, *filec;
! 544:
! 545: /*
! 546: * Load file contents
! 547: */
! 548: if ((bp = cvs_buf_load(pb->filename, BUF_AUTOEXT)) == NULL) {
! 549: cvs_log(LP_ERR, "failed to load '%s'", pb->filename);
! 550: exit(1);
! 551: }
! 552:
! 553: if (cvs_buf_putc(bp, '\0') < 0)
! 554: exit(1);
! 555:
! 556: filec = (char *)cvs_buf_release(bp);
! 557:
! 558: /*
! 559: * Get description from user
! 560: */
! 561: rcs_desc = checkin_getdesc();
! 562: rcs_desc_set(pb->file, rcs_desc);
! 563:
! 564: /*
! 565: * Now add our new revision
! 566: */
! 567: if (rcs_rev_add(pb->file, RCS_HEAD_REV, LOG_INIT,
! 568: -1, pb->username) != 0) {
! 569: cvs_log(LP_ERR, "failed to add new revision");
! 570: exit(1);
! 571: }
! 572: }
! 573:
! 574: static int
! 575: checkin_attach_symbol(struct checkin_params *pb)
! 576: {
! 577: char rbuf[16];
! 578: int ret;
! 579: if (verbose == 1)
! 580: printf("symbol: %s\n", pb->symbol);
! 581: if (pb->flags & CI_SYMFORCE)
! 582: rcs_sym_remove(pb->file, pb->symbol);
! 583: if ((ret = rcs_sym_add(pb->file, pb->symbol, pb->newrev) == -1)
! 584: && (rcs_errno == RCS_ERR_DUPENT)) {
! 585: rcsnum_tostr(rcs_sym_getrev(pb->file, pb->symbol),
! 586: rbuf, sizeof(rbuf));
! 587: cvs_log(LP_ERR,
! 588: "symbolic name %s already bound to %s",
! 589: pb->symbol, rbuf);
! 590: rcs_close(pb->file);
! 591: return (-1);
! 592: } else if (ret == -1) {
! 593: cvs_log(LP_ERR, "problem adding symbol: %s",
! 594: pb->symbol);
! 595: rcs_close(pb->file);
! 596: return (-1);
! 597: }
! 598: return (0);
! 599: }
! 600:
! 601: static void
! 602: checkin_revert(struct checkin_params *pb)
! 603: {
! 604: char rbuf[16];
! 605:
! 606: rcsnum_tostr(pb->frev, rbuf, sizeof(rbuf));
! 607: cvs_log(LP_WARN,
! 608: "file is unchanged; reverting to previous revision %s",
! 609: rbuf);
! 610: (void)unlink(pb->filename);
! 611: if ((pb->flags & CO_LOCK) || (pb->flags & CO_UNLOCK))
! 612: checkout_rev(pb->file, pb->frev, pb->filename,
! 613: pb->flags, pb->username);
! 614: rcs_lock_remove(pb->file, pb->frev);
! 615: rcs_close(pb->file);
! 616: if (verbose == 1)
! 617: printf("done\n");
! 618: }
! 619:
! 620: static int
! 621: checkin_checklock(struct checkin_params *pb)
! 622: {
! 623: int found = 0, notlocked = 1;
! 624: struct rcs_lock *lkp;
! 625:
! 626: if (!TAILQ_EMPTY(&(pb->file->rf_locks))) {
! 627: TAILQ_FOREACH(lkp, &(pb->file->rf_locks), rl_list) {
! 628: if (!strcmp(lkp->rl_name, pb->username))
! 629: notlocked = 0;
! 630:
! 631: if (!strcmp(lkp->rl_name, pb->username) &&
! 632: !rcsnum_cmp(lkp->rl_num, pb->frev, 0)) {
! 633: found = 1;
! 634: return (0);
! 635: }
! 636: }
! 637: }
1.32 joris 638:
1.58 ! niallo 639: if ((found == 0) && (notlocked == 0)) {
! 640: cvs_log(LP_ERR, "no locks set for '%s'", pb->username);
! 641: rcs_close(pb->file);
! 642: return (-1);
! 643: }
! 644: return (0);
1.1 niallo 645: }