Annotation of src/usr.bin/cvs/commit.c, Revision 1.3
1.1 jfb 1: /* $OpenBSD$ */
2: /*
3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@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 conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions 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/types.h>
28: #include <sys/stat.h>
29:
30: #include <errno.h>
31: #include <stdio.h>
32: #include <fcntl.h>
33: #include <stdlib.h>
34: #include <unistd.h>
35: #include <string.h>
36: #include <sysexits.h>
37:
38: #include "cvs.h"
39: #include "log.h"
1.2 jfb 40: #include "proto.h"
1.1 jfb 41:
42:
1.3 ! krapht 43: #define CVS_COMMIT_BIGMSG 8000
! 44: #define CVS_COMMIT_FTMPL "/tmp/cvsXXXXXXXXXX"
! 45: #define CVS_COMMIT_LOGPREFIX "CVS:"
! 46: #define CVS_COMMIT_LOGLINE \
! 47: "----------------------------------------------------------------------"
! 48:
1.1 jfb 49:
50:
51: static char* cvs_commit_openmsg (const char *);
1.3 ! krapht 52: static char* cvs_commit_getmsg (const char *);
1.1 jfb 53:
54:
55: /*
56: * cvs_commit()
57: *
58: * Handler for the `cvs commit' command.
59: */
60:
61: int
62: cvs_commit(int argc, char **argv)
63: {
64: int ch, recurse;
65: char *msg, *mfile;
66:
67: recurse = 1;
68: mfile = NULL;
69: msg = NULL;
70:
1.3 ! krapht 71: #if 0
! 72: cvs_commit_getmsg(".");
! 73: #endif
! 74:
1.1 jfb 75: while ((ch = getopt(argc, argv, "F:flm:R")) != -1) {
76: switch (ch) {
77: case 'F':
78: mfile = optarg;
79: break;
80: case 'f':
81: recurse = 0;
82: break;
83: case 'l':
84: recurse = 0;
85: break;
86: case 'm':
87: msg = optarg;
88: break;
89: case 'R':
90: recurse = 1;
91: break;
92: default:
93: return (EX_USAGE);
94: }
95: }
96:
97: if ((msg != NULL) && (mfile != NULL)) {
98: cvs_log(LP_ERR, "the -F and -m flags are mutually exclusive");
99: return (EX_USAGE);
100: }
101:
102: if ((mfile != NULL) && (msg = cvs_commit_openmsg(mfile)) == NULL)
103: return (EX_DATAERR);
104:
105: argc -= optind;
106: argv += optind;
107:
108: return (0);
109: }
110:
111:
112: /*
113: * cvs_commit_openmsg()
114: *
115: * Open the file specified by <path> and allocate a buffer large enough to
116: * hold all of the file's contents. The returned value must later be freed
117: * using the free() function.
118: * Returns a pointer to the allocated buffer on success, or NULL on failure.
119: */
120:
121: static char*
122: cvs_commit_openmsg(const char *path)
123: {
1.3 ! krapht 124: int fd, ch;
1.1 jfb 125: size_t sz;
1.3 ! krapht 126: char buf[32], *msg;
1.1 jfb 127: struct stat st;
128:
129: if (stat(path, &st) == -1) {
130: cvs_log(LP_ERRNO, "failed to stat `%s'", path);
131: return (NULL);
132: }
133:
1.3 ! krapht 134: if (!S_ISREG(st.st_mode)) {
! 135: cvs_log(LP_ERR, "message file must be a regular file");
! 136: return (NULL);
! 137: }
! 138:
! 139: if (st.st_size > CVS_COMMIT_BIGMSG) {
! 140: do {
! 141: fprintf(stderr,
! 142: "The specified message file seems big. "
! 143: "Proceed anyways? (y/n) ");
! 144: if (fgets(buf, sizeof(buf), stdin) == NULL) {
! 145: cvs_log(LP_ERRNO,
! 146: "failed to read from standard input");
! 147: return (NULL);
! 148: }
! 149:
! 150: sz = strlen(buf);
! 151: if ((sz == 0) || (sz > 2)) {
! 152: continue;
! 153: }
! 154:
! 155: cvs_log(LP_ERR, "aborted by user");
! 156: return (NULL);
! 157: }
! 158:
! 159: fprintf(stderr, "Invalid character\n");
! 160: } while (1);
! 161: }
! 162:
1.1 jfb 163: sz = st.st_size + 1;
164:
165: msg = (char *)malloc(sz);
166: if (msg == NULL) {
167: cvs_log(LP_ERRNO, "failed to allocate message buffer");
168: return (NULL);
169: }
170:
171: fd = open(path, O_RDONLY, 0);
172: if (fd == -1) {
173: cvs_log(LP_ERRNO, "failed to open message file `%s'", path);
174: return (NULL);
175: }
176:
177: if (read(fd, msg, sz - 1) == -1) {
178: cvs_log(LP_ERRNO, "failed to read CVS commit message");
179: return (NULL);
180: }
181: msg[sz - 1] = '\0';
182:
183: return (msg);
1.3 ! krapht 184: }
! 185:
! 186:
! 187: /*
! 188: * cvs_commit_getmsg()
! 189: *
! 190: * Get a commit log message by forking the user's editor.
! 191: * Returns the message in a dynamically allocated string on success, NULL on
! 192: * failure.
! 193: */
! 194:
! 195: static char*
! 196: cvs_commit_getmsg(const char *dir)
! 197: {
! 198: int ret, fd, argc, fds[3];
! 199: char *argv[4], path[MAXPATHLEN], *msg;
! 200: FILE *fp;
! 201:
! 202: fds[0] = -1;
! 203: fds[1] = -1;
! 204: fds[2] = -1;
! 205: strlcpy(path, CVS_COMMIT_FTMPL, sizeof(path));
! 206: argc = 0;
! 207: argv[argc++] = cvs_editor;
! 208: argv[argc++] = path;
! 209: argv[argc] = NULL;
! 210:
! 211: if ((fd = mkstemp(path)) == -1) {
! 212: cvs_log(LP_ERRNO, "failed to create temporary file");
! 213: return (NULL);
! 214: }
! 215:
! 216: fp = fdopen(fd, "w");
! 217: if (fp == NULL) {
! 218: cvs_log(LP_ERRNO, "failed to fdopen");
! 219: exit(1);
! 220: } else {
! 221: fprintf(fp,
! 222: "\n%s %s\n%s Enter Log. Lines beginning with `%s' are "
! 223: "removed automatically\n%s\n%s Commiting in %s\n"
! 224: "%s\n%s Modified Files:\n",
! 225: CVS_COMMIT_LOGPREFIX, CVS_COMMIT_LOGLINE,
! 226: CVS_COMMIT_LOGPREFIX, CVS_COMMIT_LOGPREFIX,
! 227: CVS_COMMIT_LOGPREFIX, CVS_COMMIT_LOGPREFIX,
! 228: dir, CVS_COMMIT_LOGPREFIX, CVS_COMMIT_LOGPREFIX);
! 229:
! 230: /* XXX list files here */
! 231:
! 232: fprintf(fp, "%s %s\n", CVS_COMMIT_LOGPREFIX,
! 233: CVS_COMMIT_LOGLINE);
! 234: }
! 235: (void)fflush(fp);
! 236: (void)fclose(fp);
! 237:
! 238: do {
! 239: ret = cvs_exec(argc, argv, fds);
! 240: if (ret == -1) {
! 241: fprintf(stderr,
! 242: "Log message unchanged or not specified\n"
! 243: "a)bort, c)ontinue, e)dit, !)reuse this message "
! 244: "unchanged for remaining dirs\nAction: () ");
! 245:
! 246: ret = getchar();
! 247: if (ret == 'a') {
! 248: cvs_log(LP_ERR, "aborted by user");
! 249: break;
! 250: } else if (ret == 'c') {
! 251: } else if (ret == 'e') {
! 252: } else if (ret == '!') {
! 253: }
! 254:
! 255: }
! 256: } while (0);
! 257:
! 258: (void)close(fd);
! 259:
! 260: return (msg);
! 261: }
! 262:
! 263:
! 264: /*
! 265: * cvs_commit_gettmpl()
! 266: *
! 267: * Get the template to display when invoking the editor to get a commit
! 268: * message.
! 269: */
! 270:
! 271: cvs_commit_gettmpl(void)
! 272: {
! 273:
1.1 jfb 274: }