1 /*-
2  * Copyright (c) 2000-2005 MAEKAWA Masahide <maekawa@cvsync.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/uio.h>
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 
37 #include <limits.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include "compat_stdbool.h"
42 #include "compat_stdint.h"
43 #include "compat_inttypes.h"
44 #include "compat_limits.h"
45 
46 #include "attribute.h"
47 #include "collection.h"
48 #include "cvsync.h"
49 #include "logmsg.h"
50 #include "mdirent.h"
51 #include "network.h"
52 #include "scanfile.h"
53 
54 #include "defs.h"
55 
56 bool cvscan(struct collection *);
57 void usage(void);
58 
59 int
main(int argc,char * argv[])60 main(int argc, char *argv[])
61 {
62 	const char *cfname = NULL;
63 	struct collection *cls = NULL, *cl, base_cl;
64 	struct config *cf;
65 	size_t len;
66 	int ch, status = EXIT_SUCCESS;
67 	bool log_flag = false;
68 
69 	cl = &base_cl;
70 	collection_init(cl);
71 
72 	while ((ch = getopt(argc, argv, "FLc:f:hlqr:v")) != -1) {
73 		switch (ch) {
74 		case 'F':
75 			if (!cl->cl_symfollow) {
76 				usage();
77 				/* NOTREACHED */
78 			}
79 			cl->cl_symfollow = false;
80 			break;
81 		case 'L':
82 			if (cl->cl_errormode != CVSYNC_ERRORMODE_UNSPEC) {
83 				usage();
84 				/* NOTREACHED */
85 			}
86 			cl->cl_errormode = CVSYNC_ERRORMODE_FIXUP;
87 			break;
88 		case 'c':
89 			if (cfname != NULL) {
90 				usage();
91 				/* NOTREACHED */
92 			}
93 			cfname = optarg;
94 			break;
95 		case 'f':
96 			if (strlen(cl->cl_scan_name) != 0) {
97 				usage();
98 				/* NOTREACHED */
99 			}
100 			len = strlen(optarg);
101 			if (len >= sizeof(cl->cl_scan_name)) {
102 				usage();
103 				/* NOTREACHED */
104 			}
105 			(void)memcpy(cl->cl_scan_name, optarg, len);
106 			cl->cl_scan_name[len] = '\0';
107 			break;
108 		case 'h':
109 			usage();
110 			/* NOTREACHED */
111 		case 'l':
112 			if (cl->cl_errormode != CVSYNC_ERRORMODE_UNSPEC) {
113 				usage();
114 				/* NOTREACHED */
115 			}
116 			cl->cl_errormode = CVSYNC_ERRORMODE_IGNORE;
117 			break;
118 		case 'q':
119 			if (log_flag) {
120 				usage();
121 				/* NOTREACHED */
122 			}
123 			logmsg_quiet = true;
124 			log_flag = true;
125 			break;
126 		case 'r':
127 			if (strlen(cl->cl_release) != 0) {
128 				usage();
129 				/* NOTREACHED */
130 			}
131 			len = strlen(optarg);
132 			if (len >= sizeof(cl->cl_release)) {
133 				usage();
134 				/* NOTREACHED */
135 			}
136 			(void)memcpy(cl->cl_release, optarg, len);
137 			cl->cl_release[len] = '\0';
138 			break;
139 		case 'v':
140 			if (log_flag) {
141 				usage();
142 				/* NOTREACHED */
143 			}
144 			logmsg_detail = true;
145 			log_flag = true;
146 			break;
147 		default:
148 			usage();
149 			/* NOTREACHED */
150 		}
151 	}
152 	argc -= optind;
153 	argv += optind;
154 
155 	if (cl->cl_errormode == CVSYNC_ERRORMODE_UNSPEC)
156 		cl->cl_errormode = CVSYNC_ERRORMODE_ABORT;
157 
158 	if (!cvsync_init())
159 		exit(EXIT_FAILURE);
160 
161 	if (cfname == NULL) {
162 		if (argc != 1) {
163 			usage();
164 			/* NOTREACHED */
165 		}
166 		if (!collection_set_default(cl, argv[0]))
167 			exit(EXIT_FAILURE);
168 		if (strlen(cl->cl_scan_name) == 0) {
169 			logmsg_err("Not specified the output file.");
170 			exit(EXIT_FAILURE);
171 		}
172 		if (!cvscan(cl))
173 			status = EXIT_FAILURE;
174 	} else {
175 		if (!collection_set_default(cl, NULL))
176 			exit(EXIT_FAILURE);
177 
178 		if ((cf = config_load(cfname)) == NULL)
179 			exit(EXIT_FAILURE);
180 
181 		switch (argc) {
182 		case 0:
183 			cls = cf->cf_collections;
184 			break;
185 		case 1:
186 			cls = collection_lookup(cf->cf_collections, argv[0],
187 					       base_cl.cl_release);
188 			if (cls == NULL) {
189 				logmsg_err("Not such a collection: %s/%s",
190 					   argv[0], base_cl.cl_release);
191 				config_destroy(cf);
192 				exit(EXIT_FAILURE);
193 			}
194 			if (strlen(cls->cl_scan_name) == 0) {
195 				logmsg_err("Not specified the output file.");
196 				collection_destroy(cls);
197 				config_destroy(cf);
198 				exit(EXIT_FAILURE);
199 			}
200 			break;
201 		default:
202 			usage();
203 			/* NOTREACHED */
204 		}
205 
206 		for (cl = cls ; cl != NULL ; cl = cl->cl_next) {
207 			if (!cvscan(cl))
208 				status = EXIT_FAILURE;
209 		}
210 
211 		if (argc != 0)
212 			collection_destroy(cls);
213 		config_destroy(cf);
214 	}
215 
216 	exit(status);
217 	/* NOTREACHED */
218 }
219 
220 bool
cvscan(struct collection * cl)221 cvscan(struct collection *cl)
222 {
223 	struct scanfile_create_args sca;
224 	struct mdirent_args mda;
225 
226 	if (strlen(cl->cl_scan_name) == 0)
227 		return (true);
228 	if ((cl->cl_super != NULL) &&
229 	    (strcmp(cl->cl_super->cl_scan_name, cl->cl_scan_name) == 0)) {
230 		return (true);
231 	}
232 
233 	logmsg("Scanfile: name %s, release %s, prefix %s", cl->cl_name,
234 	       cl->cl_release, cl->cl_prefix);
235 
236 	mda.mda_errormode = cl->cl_errormode;
237 	mda.mda_symfollow = cl->cl_symfollow;
238 	mda.mda_remove = false;
239 
240 	sca.sca_name = cl->cl_scan_name;
241 	sca.sca_prefix = cl->cl_prefix;
242 	sca.sca_release = cl->cl_release;
243 	sca.sca_rprefix = cl->cl_rprefix;
244 	sca.sca_rprefixlen = cl->cl_rprefixlen;
245 	sca.sca_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
246 	sca.sca_mdirent_args = &mda;
247 	sca.sca_umask = cl->cl_umask;
248 
249 	if (!scanfile_create(&sca))
250 		return (false);
251 
252 	logmsg("Finished successfully");
253 
254 	return (true);
255 }
256 
257 void
usage(void)258 usage(void)
259 {
260 	logmsg_err("Usage: cvscan [-hqv] [-r <release>] -c <file> [<name>]\n"
261 		   "       cvscan [-FLhlqv] [-r <release>] -f <file> "
262 		   "<directory>");
263 	exit(EXIT_FAILURE);
264 }
265