xref: /openbsd/usr.bin/cvs/release.c (revision 4dcde513)
1 /*	$OpenBSD: release.c,v 1.43 2017/06/01 08:08:24 joris Exp $	*/
2 /*-
3  * Copyright (c) 2005-2007 Xavier Santolaria <xsa@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/stat.h>
19 
20 #include <string.h>
21 #include <unistd.h>
22 
23 #include "cvs.h"
24 #include "remote.h"
25 
26 void	cvs_release_local(struct cvs_file *);
27 
28 static void	release_check_files(struct cvs_file *);
29 
30 static int	dflag = 0;
31 static int	files_altered = 0;
32 
33 struct cvs_cmd cvs_cmd_release = {
34 	CVS_OP_RELEASE, CVS_USE_WDIR, "release",
35 	{ "re", "rel" },
36 	"Indicate that a Module is no longer in use",
37 	"[-d] dir...",
38 	"d",
39 	NULL,
40 	cvs_release
41 };
42 
43 int
cvs_release(int argc,char ** argv)44 cvs_release(int argc, char **argv)
45 {
46 	int ch;
47 	int flags;
48 	struct cvs_recursion cr;
49 
50 	flags = CR_REPO;
51 
52 	while ((ch = getopt(argc, argv, cvs_cmd_release.cmd_opts)) != -1) {
53 		switch (ch) {
54 		case 'd':
55 			dflag = 1;
56 			break;
57 		default:
58 			fatal("%s", cvs_cmd_release.cmd_synopsis);
59 		}
60 	}
61 
62 	argc -= optind;
63 	argv += optind;
64 
65 	if (argc == 0)
66 		fatal("%s", cvs_cmd_release.cmd_synopsis);
67 
68 	cr.enterdir = NULL;
69 	cr.leavedir = NULL;
70 
71 	if (cvsroot_is_remote()) {
72 		cvs_client_connect_to_server();
73 		cr.fileproc = cvs_client_sendfile;
74 
75 		if (dflag == 1)
76 			cvs_client_send_request("Argument -d");
77 	} else
78 		cr.fileproc = cvs_release_local;
79 
80 	cr.flags = flags;
81 
82 	cvs_file_run(argc, argv, &cr);
83 
84 	if (cvsroot_is_remote()) {
85 		cvs_client_send_files(argv, argc);
86 		cvs_client_senddir(".");
87 		cvs_client_send_request("release");
88 		cvs_client_get_responses();
89 	}
90 
91 	return (0);
92 }
93 
94 void
cvs_release_local(struct cvs_file * cf)95 cvs_release_local(struct cvs_file *cf)
96 {
97 	struct stat st;
98 	struct cvs_recursion cr;
99 	char *wdir, cwd[PATH_MAX];
100 	char *arg = ".";
101 	int saved_noexec;
102 
103 	if (cf->file_type == CVS_FILE)
104 		return;
105 
106 	cvs_log(LP_TRACE, "cvs_release_local(%s)", cf->file_path);
107 
108 	cvs_file_classify(cf, cvs_directory_tag);
109 
110 	if (cvs_server_active == 1) {
111 		cvs_history_add(CVS_HISTORY_RELEASE, cf, NULL);
112 		return;
113 	}
114 
115 	if ((wdir = getcwd(cwd, sizeof(cwd))) == NULL)
116 		fatal("getcwd failed");
117 
118 	if (cf->file_type == CVS_DIR) {
119 		if (!strcmp(cf->file_name, "."))
120 			return;
121 
122 		/* chdir before updating the directory. */
123 		cvs_chdir(cf->file_path, 0);
124 
125 		if (stat(CVS_PATH_CVSDIR, &st) == -1 || !S_ISDIR(st.st_mode)) {
126 			if (verbosity > 0)
127 				cvs_log(LP_ERR, "no repository directory: %s",
128 				    cf->file_path);
129 			return;
130 		}
131 	}
132 
133 	/* Skip the interactive part if -Q is specified. */
134 	if (verbosity == 0)
135 		goto delete;
136 
137 	saved_noexec = cvs_noexec;
138 	cvs_noexec = 1;
139 
140 	cr.enterdir = NULL;
141 	cr.leavedir = NULL;
142 	cr.fileproc = cvs_update_local;
143 	cr.flags = CR_REPO | CR_RECURSE_DIRS;
144 
145 	cvs_file_run(1, &arg, &cr);
146 
147 	cvs_noexec = saved_noexec;
148 
149 	cr.enterdir = NULL;
150 	cr.leavedir = NULL;
151 	cr.fileproc = release_check_files;
152 	cr.flags = CR_RECURSE_DIRS;
153 
154 	cvs_file_run(1, &arg, &cr);
155 
156 	(void)printf("You have [%d] altered files in this repository.\n",
157 	    files_altered);
158 	(void)printf("Are you sure you want to release %sdirectory `%s': ",
159 		(dflag == 1) ? "(and delete) " : "", cf->file_path);
160 
161 	if (cvs_yesno() == -1) {
162 		(void)fprintf(stderr,
163 		    "** `%s' aborted by user choice.\n", cmdp->cmd_name);
164 
165 		/* change back to original working dir */
166 		cvs_chdir(wdir, 0);
167 
168 		return;
169 	}
170 
171 	/* change back to original working dir */
172 	cvs_chdir(wdir, 0);
173 
174 delete:
175 	if (dflag == 1) {
176 		if (cvs_rmdir(cf->file_path) != 0)
177 			fatal("cvs_release_local: cvs_rmdir failed");
178 	}
179 }
180 
181 static void
release_check_files(struct cvs_file * cf)182 release_check_files(struct cvs_file *cf)
183 {
184 	cvs_log(LP_TRACE, "release_check_files(%s)", cf->file_path);
185 
186 	cvs_file_classify(cf, cvs_directory_tag);
187 
188 	if (cf->file_status == FILE_MERGE ||
189 	    cf->file_status == FILE_ADDED ||
190 	    cf->file_status == FILE_PATCH ||
191 	    cf->file_status == FILE_CONFLICT)
192 		files_altered++;
193 }
194