Annotation of src/usr.bin/cvs/release.c, Revision 1.6
1.6 ! joris 1: /* $OpenBSD: release.c,v 1.5 2005/05/19 22:07:33 jfb Exp $ */
1.1 xsa 2: /*
3: * Copyright (c) 2005 Xavier Santolaria <xsa@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 <fcntl.h>
32: #include <stdio.h>
33: #include <stdlib.h>
34: #include <string.h>
35: #include <unistd.h>
36:
37: #include "cvs.h"
38: #include "log.h"
39: #include "proto.h"
40:
1.3 xsa 41: #define UPDCMD_FLAGS "-n -q -d"
42:
43: extern char *__progname;
1.1 xsa 44:
45: static int cvs_release_options(char *, int, char **, int *);
46: static int cvs_release_sendflags(struct cvsroot *);
47: static int cvs_release_yesno(void);
48: static int cvs_release_dir(CVSFILE *, void *);
49:
50: struct cvs_cmd_info cvs_release = {
51: cvs_release_options,
52: cvs_release_sendflags,
53: cvs_release_dir,
1.2 xsa 54: NULL, NULL,
1.3 xsa 55: CF_IGNORE | CF_KNOWN | CF_NOFILES | CF_RECURSE,
1.1 xsa 56: CVS_REQ_RELEASE,
57: CVS_CMD_SENDDIR | CVS_CMD_SENDARGS2 | CVS_CMD_ALLOWSPEC
58: };
59:
60: static int dflag; /* -d option */
61:
62: static int
63: cvs_release_options(char *opt, int argc, char **argv, int *arg)
64: {
65: int ch;
66:
67: while ((ch = getopt(argc, argv, opt)) != -1) {
68: switch (ch) {
69: case 'd':
70: dflag = 1;
71: break;
72: default:
73: return (CVS_EX_USAGE);
74: }
75: }
76:
77: argc -= optind;
78: argv += optind;
79: *arg = optind;
80:
81: if (argc == 0)
82: return (CVS_EX_USAGE);
83:
84: return (0);
85: }
86:
87: static int
88: cvs_release_sendflags(struct cvsroot *root)
89: {
90: if (dflag && cvs_sendarg(root, "-d", 0) < 0)
91: return (CVS_EX_PROTO);
92:
93: return (0);
94: }
95:
96: /*
97: * cvs_release_yesno()
98: *
99: * Read from standart input for `y' or `Y' character.
100: * Returns 0 on success, or -1 on failure.
101: */
102: static int
103: cvs_release_yesno(void)
104: {
105: int c, ret;
106:
107: ret = 0;
1.5 jfb 108:
1.1 xsa 109: fflush (stderr);
110: fflush (stdout);
111:
112: if ((c = getchar()) != 'y' && c != 'Y')
113: ret = -1;
114: else
115: while (c != EOF && c != '\n')
116: c = getchar();
117:
118: return (ret);
119: }
120:
121: /*
122: * cvs_release_dir()
123: *
124: * Release specified directorie(s).
125: * Returns 0 on success, or -1 on failure.
126: */
127: static int
128: cvs_release_dir(CVSFILE *cdir, void *arg)
129: {
1.3 xsa 130: FILE *fp;
1.1 xsa 131: int j, l;
1.4 xsa 132: char *wdir, cwd[MAXPATHLEN];
1.3 xsa 133: char buf[256], cdpath[MAXPATHLEN], dpath[MAXPATHLEN];
134: char updcmd[MAXPATHLEN]; /* XXX find a better size; malloc()?? */
1.1 xsa 135: struct stat st;
136: struct cvsroot *root;
137:
138: j = 0; /* number of altered files in the working copy */
139:
140: root = CVS_DIR_ROOT(cdir);
141:
142: cvs_file_getpath(cdir, dpath, sizeof(dpath));
143:
144: l = snprintf(cdpath, sizeof(cdpath), "%s/" CVS_PATH_CVSDIR, dpath);
145: if (l == -1 || l >= (int)sizeof(cdpath)) {
146: errno = ENAMETOOLONG;
147: cvs_log(LP_ERRNO, "%s", cdpath);
1.6 ! joris 148: return (CVS_EX_DATA);
1.1 xsa 149: }
150:
151: if (cdir->cf_type == DT_DIR) {
152: if (!strcmp(CVS_FILE_NAME(cdir), "."))
153: return (0);
154: else {
155: /* test if dir has CVS/ directory */
156: if (stat(cdpath, &st) == -1) {
157: cvs_log(LP_ERR,
158: "no repository directory: %s", dpath);
159: return (0);
160: }
161: }
162:
163: if (root->cr_method != CVS_METHOD_LOCAL) {
1.4 xsa 164: /* XXX kept for compat reason of `cvs update' output */
165: /* save current working directory for further use */
166: if ((wdir = getcwd(cwd, sizeof(cwd))) == NULL)
167: cvs_log(LP_ERRNO, "cannot get current dir");
168:
1.3 xsa 169: /* change dir before running the `cvs update' command */
1.4 xsa 170: if (chdir(dpath) == -1) {
171: cvs_log(LP_ERRNO, "cannot change to dir `%s'",
172: dpath);
1.6 ! joris 173: return (CVS_EX_FILE);
1.4 xsa 174: }
1.3 xsa 175:
176: /* construct `cvs update' command */
177: l = snprintf(updcmd, sizeof(updcmd), "%s %s %s update",
178: __progname, UPDCMD_FLAGS, root->cr_str);
179: if (l == -1 || l >= (int)sizeof(updcmd))
1.6 ! joris 180: return (CVS_EX_DATA);
1.3 xsa 181:
182: /* XXX we should try to avoid a new connection ... */
183: if ((fp = popen(updcmd, "r")) == NULL) {
184: cvs_log(LP_ERROR, "cannot run command `%s'",
185: updcmd);
1.6 ! joris 186: return (CVS_EX_DATA);
1.3 xsa 187: }
1.1 xsa 188:
1.3 xsa 189: while (fgets(buf, sizeof(buf), fp) != NULL) {
190: if (strchr("ACMPRU", buf[0]))
191: j++;
192: (void)fputs(buf, stdout);
193: }
194:
195: if (pclose(fp) != 0) {
196: cvs_log(LP_ERROR, "unable to release `%s'",
197: dpath);
1.6 ! joris 198: return (CVS_EX_DATA);
1.3 xsa 199: }
1.1 xsa 200:
1.3 xsa 201: printf("You have [%d] altered file%s in this "
202: "repository.\n", j, j > 1 ? "s" : "");
1.4 xsa 203:
1.1 xsa 204: printf("Are you sure you want to release "
205: "%sdirectory `%s': ",
206: dflag ? "(and delete) " : "", dpath);
207:
208: if (cvs_release_yesno() == -1) { /* No */
209: (void)fprintf(stderr,
210: "** `%s' aborted by user choice.\n",
211: cvs_command);
212: return (-1);
213: }
214:
1.4 xsa 215: /* change back to original working dir */
216: if (chdir(wdir) == -1) {
217: cvs_log(LP_ERRNO, "cannot change to original "
218: "working dir `%s'", wdir);
1.6 ! joris 219: return (CVS_EX_FILE);
1.4 xsa 220: }
221:
1.1 xsa 222: if (dflag == 1) {
1.4 xsa 223: if (cvs_remove_dir(dpath) != CVS_EX_OK) {
1.1 xsa 224: cvs_log(LP_ERRNO,
1.4 xsa 225: "deletion of directory `%s' failed",
1.1 xsa 226: dpath);
1.6 ! joris 227: return (CVS_EX_FILE);
1.1 xsa 228: }
229: }
230: }
231: } else {
232: cvs_log(LP_ERR, "no such directory: %s", dpath);
1.6 ! joris 233: return (CVS_EX_DATA);
1.1 xsa 234: }
235:
236: return (0);
237: }