Annotation of src/usr.bin/rcs/ci.c, Revision 1.4
1.4 ! niallo 1: /* $OpenBSD: ci.c,v 1.3 2005/09/30 17:39:48 joris 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 <signal.h>
40: #include <string.h>
41:
42: #include "log.h"
43: #include "rcs.h"
1.4 ! niallo 44: #include "diff.h"
1.1 niallo 45: #include "rcsprog.h"
46:
47: extern char *__progname;
48:
1.4 ! niallo 49: static char * checkin_diff_file(RCSFILE *, RCSNUM *, const char *);
! 50:
1.1 niallo 51: void
52: checkin_usage(void)
53: {
54: fprintf(stderr,
55: "usage: %s [-jlMNqu] [-d date | -r rev] [-m msg] [-k mode] "
56: "file ...\n", __progname);
57: }
58:
59: /*
60: * checkin_main()
61: *
62: * Handler for the `ci' program.
63: * Returns 0 on success, or >0 on error.
64: */
65: /*
66: Options:
67:
68: -r | -r[rev]: check in revision rev
69: -l[rev]: ", but do co -l
70: -u[rev]: ", bt do co -u
71: -f[rev]: force a deposit (check in?)
72: -k[rev]: ?
73: -q[rev]: quiet mode
74: -i[rev]: initial check in, errors if RCS file already exists.
75: -j[rev]: just checkin and do not initialize, errors if RCS file already exists.
76: -I[rev]: user is prompted even if stdin is not a tty
77: -d[date]: uses date for checkin dat and time.
78: -M[rev]: set modification time on any new working file to be that of the retrieved version.
79: -mmsg: msg is the log message, don't start editor. log messages with #are comments.
80: */
81: int
82: checkin_main(int argc, char **argv)
83: {
84: int i, ch, dflag, flags, lkmode;
85: mode_t fmode;
86: RCSFILE *file;
1.4 ! niallo 87: RCSNUM *frev;
1.1 niallo 88: char fpath[MAXPATHLEN];
1.4 ! niallo 89: char *rcs_msg, *rev, *filec, *deltatext;
! 90: BUF *bp;
1.1 niallo 91:
92: lkmode = -1;
93: flags = RCS_RDWR;
94: file = NULL;
1.4 ! niallo 95: rcs_msg = rev = NULL;
1.1 niallo 96: fmode = dflag = 0;
97:
1.3 joris 98: while ((ch = getopt(argc, argv, "j:l:M:N:qu:d:r::m:k:V")) != -1) {
1.1 niallo 99: switch (ch) {
100: case 'h':
101: (usage)();
102: exit(0);
103: case 'm':
104: rcs_msg = optarg;
1.3 joris 105: break;
106: case 'q':
107: verbose = 0;
1.1 niallo 108: break;
109: case 'V':
110: printf("%s\n", rcs_version);
111: exit(0);
112: default:
113: (usage)();
114: exit(1);
115: }
116: }
117:
118: argc -= optind;
119: argv += optind;
120: if (argc == 0) {
121: cvs_log(LP_ERR, "no input file");
122: (usage)();
123: exit(1);
124: }
125:
126: for (i = 0; i < argc; i++) {
127: if (rcs_statfile(argv[i], fpath, sizeof(fpath)) < 0)
128: continue;
129:
1.4 ! niallo 130: file = rcs_open(fpath, RCS_RDWR, fmode);
1.1 niallo 131: if (file == NULL) {
1.4 ! niallo 132: cvs_log(LP_ERR, "failed to open rcsfile '%s'", fpath);
1.1 niallo 133: exit(1);
134: }
1.4 ! niallo 135:
1.1 niallo 136: if (rcs_msg == NULL) {
137: cvs_log(LP_ERR, "no log message");
138: exit(1);
139: }
1.4 ! niallo 140:
! 141: if (dflag) {
1.1 niallo 142: /* XXX */
143: }
1.4 ! niallo 144:
! 145: if (rev == NULL)
! 146: frev = file->rf_head;
! 147:
! 148: /*
! 149: * Load file contents
! 150: */
! 151: if ((bp = cvs_buf_load(argv[i], BUF_AUTOEXT)) == NULL) {
! 152: cvs_log(LP_ERR, "failed to load '%s'", argv[i]);
! 153: exit(1);
! 154: }
! 155:
! 156: if (cvs_buf_putc(bp, '\0') < 0)
! 157: exit(1);
! 158:
! 159: filec = cvs_buf_release(bp);
! 160:
! 161: /*
! 162: * Remove the lock
! 163: */
! 164: if (rcs_lock_remove(file, frev) < 0) {
! 165: if (rcs_errno != RCS_ERR_NOENT)
! 166: cvs_log(LP_WARN, "failed to remove lock");
! 167: }
! 168:
! 169: /*
! 170: * Get RCS patch
! 171: */
! 172: if ((deltatext = checkin_diff_file(file, frev, argv[i])) == NULL) {
! 173: cvs_log(LP_ERR, "failed to get diff");
! 174: exit(1);
! 175: }
! 176:
! 177: /*
! 178: * Current head revision gets the RCS patch as rd_text
! 179: */
! 180: if (rcs_deltatext_set(file, file->rf_head, deltatext) == -1) {
! 181: cvs_log(LP_ERR, "failed to set new rd_text for head rev");
! 182: exit (1);
! 183: }
! 184:
! 185: /*
! 186: * Now add our new revision
! 187: */
! 188: if (rcs_rev_add(file, RCS_HEAD_REV, rcs_msg, -1) != 0) {
! 189: cvs_log(LP_ERR, "failed to add new revision");
! 190: exit(1);
! 191: }
! 192:
! 193: /*
! 194: * New head revision has to contain entire file;
! 195: */
! 196: if (rcs_deltatext_set(file, frev, filec) == -1) {
! 197: cvs_log(LP_ERR, "failed to set new head revision");
! 198: exit(1);
! 199: }
! 200:
! 201: free(deltatext);
! 202: free(filec);
! 203:
! 204: /* File will NOW be synced */
1.1 niallo 205: rcs_close(file);
1.4 ! niallo 206:
! 207: /* XXX:
! 208: * Delete the working file - we do not support -u/-l just yet
! 209: */
! 210: (void)unlink(argv[i]);
! 211: }
! 212:
! 213: return (0);
! 214: }
! 215:
! 216: static char *
! 217: checkin_diff_file(RCSFILE *rfp, RCSNUM *rev, const char *filename)
! 218: {
! 219: char path1[MAXPATHLEN], path2[MAXPATHLEN];
! 220: BUF *b1, *b2, *b3;
! 221: char rbuf[64], *deltatext;
! 222:
! 223: rcsnum_tostr(rev, rbuf, sizeof(rbuf));
! 224: if (verbose)
! 225: printf("retrieving revision %s\n", rbuf);
! 226:
! 227: if ((b1 = cvs_buf_load(filename, BUF_AUTOEXT)) == NULL) {
! 228: cvs_log(LP_ERR, "failed to load file: '%s'", filename);
! 229: return (NULL);
1.1 niallo 230: }
231:
1.4 ! niallo 232: if ((b2 = rcs_getrev(rfp, rev)) == NULL) {
! 233: cvs_log(LP_ERR, "failed to load revision");
! 234: cvs_buf_free(b1);
! 235: return (NULL);
! 236: }
! 237:
! 238: if ((b3 = cvs_buf_alloc(128, BUF_AUTOEXT)) == NULL) {
! 239: cvs_log(LP_ERR, "failed to allocated buffer for diff");
! 240: cvs_buf_free(b1);
! 241: cvs_buf_free(b2);
! 242: return (NULL);
! 243: }
! 244:
! 245: strlcpy(path1, "/tmp/diff1.XXXXXXXXXX", sizeof(path1));
! 246: if (cvs_buf_write_stmp(b1, path1, 0600) == -1) {
! 247: cvs_log(LP_ERRNO, "could not write temporary file");
! 248: cvs_buf_free(b1);
! 249: cvs_buf_free(b2);
! 250: return (NULL);
! 251: }
! 252: cvs_buf_free(b1);
! 253:
! 254: strlcpy(path2, "/tmp/diff2.XXXXXXXXXX", sizeof(path2));
! 255: if (cvs_buf_write_stmp(b2, path2, 0600) == -1) {
! 256: cvs_buf_free(b2);
! 257: (void)unlink(path1);
! 258: return (NULL);
! 259: }
! 260: cvs_buf_free(b2);
! 261:
! 262: diff_format = D_RCSDIFF;
! 263: cvs_diffreg(path1, path2, b3);
! 264: (void)unlink(path1);
! 265: (void)unlink(path2);
! 266:
! 267: cvs_buf_putc(b3, '\0');
! 268: deltatext = (char *)cvs_buf_release(b3);
! 269:
! 270: return (deltatext);
1.1 niallo 271: }