xref: /openbsd/usr.bin/cvs/modules.c (revision 76d0caae)
1 /*	$OpenBSD: modules.c,v 1.19 2015/11/05 09:48:21 nicm Exp $	*/
2 /*
3  * Copyright (c) 2008 Joris Vink <joris@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/types.h>
19 #include <sys/dirent.h>
20 #include <sys/resource.h>
21 
22 #include <ctype.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "cvs.h"
27 #include "config.h"
28 
29 TAILQ_HEAD(, module_info)	modules;
30 
31 struct module_checkout *current_module = NULL;
32 char *module_repo_root = NULL;
33 
34 void
35 cvs_parse_modules(void)
36 {
37 	cvs_log(LP_TRACE, "cvs_parse_modules()");
38 
39 	TAILQ_INIT(&modules);
40 	cvs_read_config(CVS_PATH_MODULES, modules_parse_line);
41 }
42 
43 void
44 cvs_modules_list(void)
45 {
46 	struct module_info *mi;
47 
48 	TAILQ_FOREACH(mi, &modules, m_list)
49 		cvs_printf("%s\n", mi->mi_str);
50 }
51 
52 int
53 modules_parse_line(char *line, int lineno)
54 {
55 	int flags;
56 	struct module_info *mi;
57 	char *bline, *val, *p, *module, *sp, *dp;
58 	char *dirname, fpath[PATH_MAX], *prog;
59 
60 	prog = NULL;
61 	bline = xstrdup(line);
62 
63 	flags = 0;
64 	p = val = line;
65 	while (!isspace((unsigned char)*p) && *p != '\0')
66 		p++;
67 
68 	if (*p == '\0')
69 		goto bad;
70 
71 	*(p++) = '\0';
72 	module = val;
73 
74 	while (isspace((unsigned char)*p))
75 		p++;
76 
77 	if (*p == '\0')
78 		goto bad;
79 
80 	val = p;
81 	while (!isspace((unsigned char)*p) && *p != '\0')
82 		p++;
83 
84 	while (val[0] == '-') {
85 		p = val;
86 		while (!isspace((unsigned char)*p) && *p != '\0')
87 			p++;
88 
89 		if (*p == '\0')
90 			goto bad;
91 
92 		*(p++) = '\0';
93 
94 		switch (val[1]) {
95 		case 'a':
96 			if (flags & MODULE_TARGETDIR) {
97 				cvs_log(LP_NOTICE, "cannot use -a with -d");
98 				goto bad;
99 			}
100 			flags |= MODULE_ALIAS;
101 			break;
102 		case 'd':
103 			if (flags & MODULE_ALIAS) {
104 				cvs_log(LP_NOTICE, "cannot use -d with -a");
105 				goto bad;
106 			}
107 			flags |= MODULE_TARGETDIR;
108 			break;
109 		case 'l':
110 			flags |= MODULE_NORECURSE;
111 			break;
112 		case 'o':
113 			if (flags != 0 || prog != NULL) {
114 				cvs_log(LP_NOTICE,
115 				    "-o cannot be used with other flags");
116 				goto bad;
117 			}
118 
119 			val = p;
120 			while (!isspace((unsigned char)*val) && *val != '\0')
121 				val++;
122 			if (*val == '\0')
123 				goto bad;
124 
125 			*(val++) = '\0';
126 			prog = xstrdup(p);
127 			p = val;
128 			flags |= MODULE_RUN_ON_CHECKOUT;
129 			break;
130 		case 'i':
131 			if (flags != 0 || prog != NULL) {
132 				cvs_log(LP_NOTICE,
133 				    "-i cannot be used with other flags");
134 				goto bad;
135 			}
136 
137 			if ((val = strchr(p, ' ' )) == NULL)
138 				goto bad;
139 
140 			*(val++) = '\0';
141 			prog = xstrdup(p);
142 			p = val;
143 			flags |= MODULE_RUN_ON_COMMIT;
144 			break;
145 		default:
146 			goto bad;
147 		}
148 
149 		val = p;
150 	}
151 
152 	if (*val == '\0')
153 		goto bad;
154 
155 	mi = xmalloc(sizeof(*mi));
156 	mi->mi_name = xstrdup(module);
157 	mi->mi_flags = flags;
158 	mi->mi_prog = prog;
159 	mi->mi_str = bline;
160 
161 	dirname = NULL;
162 	RB_INIT(&(mi->mi_modules));
163 	RB_INIT(&(mi->mi_ignores));
164 
165 	for (sp = val; *sp != '\0'; sp = dp) {
166 		dp = sp;
167 		while (!isspace((unsigned char)*dp) && *dp != '\0')
168 			dp++;
169 		if (*dp != '\0')
170 			*(dp++) = '\0';
171 
172 		if (mi->mi_flags & MODULE_ALIAS) {
173 			if (sp[0] == '!') {
174 				if (strlen(sp) < 2)
175 					fatal("invalid ! pattern");
176 				cvs_file_get((sp + 1), 0,
177 				    &(mi->mi_ignores), 0);
178 			} else {
179 				cvs_file_get(sp, 0,
180 				    &(mi->mi_modules), 0);
181 			}
182 		} else if (sp == val) {
183 			dirname = sp;
184 		} else {
185 			if (sp[0] == '!') {
186 				if (strlen(sp) < 2)
187 					fatal("invalid ! pattern");
188 
189 				sp++;
190 				(void)xsnprintf(fpath, sizeof(fpath), "%s/%s",
191 				    dirname, sp);
192 				cvs_file_get(fpath, 0,
193 				    &(mi->mi_ignores), 0);
194 			} else {
195 				(void)xsnprintf(fpath, sizeof(fpath), "%s/%s",
196 				    dirname, sp);
197 				cvs_file_get(fpath, 0,
198 				    &(mi->mi_modules), 0);
199 			}
200 		}
201 	}
202 
203 	if (!(mi->mi_flags & MODULE_ALIAS) && RB_EMPTY(&(mi->mi_modules)))
204 		cvs_file_get(dirname, 0, &(mi->mi_modules), 0);
205 
206 	TAILQ_INSERT_TAIL(&modules, mi, m_list);
207 	return (0);
208 
209 bad:
210 	free(prog);
211 	free(bline);
212 	cvs_log(LP_NOTICE, "malformed line in CVSROOT/modules: %d", lineno);
213 	return (0);
214 }
215 
216 struct module_checkout *
217 cvs_module_lookup(char *name)
218 {
219 	struct module_checkout *mc;
220 	struct module_info *mi;
221 
222 	mc = xmalloc(sizeof(*mc));
223 
224 	TAILQ_FOREACH(mi, &modules, m_list) {
225 		if (!strcmp(name, mi->mi_name)) {
226 			mc->mc_modules = mi->mi_modules;
227 			mc->mc_ignores = mi->mi_ignores;
228 			mc->mc_canfree = 0;
229 			mc->mc_name = mi->mi_name;
230 			mc->mc_flags = mi->mi_flags;
231 			mc->mc_prog = mi->mi_prog;
232 			return (mc);
233 		}
234 	}
235 
236 	RB_INIT(&(mc->mc_modules));
237 	RB_INIT(&(mc->mc_ignores));
238 	cvs_file_get(name, 0, &(mc->mc_modules), 0);
239 	mc->mc_canfree = 1;
240 	mc->mc_name = name;
241 	mc->mc_flags = MODULE_ALIAS;
242 	mc->mc_prog = NULL;
243 
244 	return (mc);
245 }
246