]>
Commit | Line | Data |
---|---|---|
5f9d9873 JR |
1 | // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de> |
2 | // | |
3 | // This program is free software; you can redistribute it and/or modify | |
4 | // it under the terms of the GNU General Public License as published by | |
5 | // the Free Software Foundation; version 2 of the License. | |
6 | // | |
7 | // This program is distributed in the hope that it will be useful, | |
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | // GNU General Public License for more details. | |
11 | // | |
12 | // You should have received a copy of the GNU General Public License | |
13 | // along with this program; if not, write to the Free Software | |
14 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
15 | ||
16 | // version 0.0.7, 2003-11-21 | |
17 | // * made it compilable with non-C99 compilers | |
18 | // | |
19 | // version 0.0.6, 2003-11-21 | |
20 | // * added rpm-4.0.4 compatibility (define RPM404 macro) | |
21 | // | |
22 | // version 0.0.5, 2003-11-21 | |
23 | // * added '--uid' and '--gid' options | |
24 | // * use macros for option-ids | |
25 | // | |
26 | // version 0.0.4, 2003-11-19 | |
27 | // * set 'force' flag on parseSpec() to ignore missing sources & patches | |
28 | // | |
29 | // version 0.0.3, 2003-11-19 | |
30 | // * fixed buffer-overflow in '--with[out]' statements | |
31 | // | |
32 | // version 0.0.2, 2003-11-19 | |
33 | // * big rewrite; implemented nearly the full functionality | |
34 | // | |
35 | // version 0.0.1, 2003-11-19 | |
36 | // * initial version | |
37 | ||
df2ac7c1 | 38 | #include <assert.h> |
5f9d9873 | 39 | #include <getopt.h> |
df2ac7c1 JR |
40 | #include <grp.h> |
41 | #include <libgen.h> | |
5f9d9873 JR |
42 | #include <stdbool.h> |
43 | #include <string.h> | |
5f9d9873 JR |
44 | #include <sys/time.h> |
45 | #include <sys/types.h> | |
df2ac7c1 | 46 | #include <unistd.h> |
5f9d9873 | 47 | |
df2ac7c1 | 48 | #include <header.h> |
5f9d9873 JR |
49 | #include <rpmbuild.h> |
50 | #include <rpmlib.h> | |
df2ac7c1 JR |
51 | #include <rpmlog.h> |
52 | #include <rpmts.h> | |
5f9d9873 JR |
53 | |
54 | #define ARG_WITH 1024 | |
55 | #define ARG_WITHOUT 1025 | |
56 | #define ARG_DEFINE 1026 | |
57 | #define ARG_TARGET 1027 | |
58 | #define ARG_RCFILE 1028 | |
59 | #define ARG_CHROOT 1029 | |
60 | #define ARG_UID 1030 | |
61 | #define ARG_GID 1031 | |
62 | ||
63 | static struct option const | |
64 | CMDLINE_OPTIONS[] = { | |
65 | { "help", no_argument, 0, 'h' }, | |
66 | { "version", no_argument, 0, 'v' }, | |
67 | { "with", required_argument, 0, ARG_WITH }, | |
68 | { "without", required_argument, 0, ARG_WITHOUT }, | |
69 | { "define", required_argument, 0, ARG_DEFINE }, | |
70 | { "target", required_argument, 0, ARG_TARGET }, | |
71 | { "rcfile", required_argument, 0, ARG_RCFILE }, | |
72 | { "chroot", required_argument, 0, ARG_CHROOT }, | |
73 | { "uid", required_argument, 0, ARG_UID }, | |
74 | { "gid", required_argument, 0, ARG_GID }, | |
75 | { 0,0,0,0 } | |
76 | }; | |
77 | ||
78 | struct Arguments | |
79 | { | |
80 | char const * target; | |
81 | char const * rcfile; | |
82 | char const * chroot; | |
83 | uid_t uid; | |
84 | gid_t gid; | |
85 | ||
86 | struct { | |
87 | char const ** values; | |
88 | size_t cnt; | |
89 | size_t reserved; | |
90 | } macros; | |
91 | ||
92 | char const * specfile; | |
93 | }; | |
94 | ||
95 | struct DepSet { | |
df2ac7c1 JR |
96 | rpmtd flags; |
97 | rpmtd name; | |
98 | rpmtd version; | |
99 | ssize_t cnt; | |
5f9d9873 JR |
100 | }; |
101 | ||
102 | inline static void | |
103 | writeStr(int fd, char const *cmd) | |
104 | { | |
105 | (void)write(fd, cmd, strlen(cmd)); | |
106 | } | |
107 | ||
108 | #define WRITE_MSG(FD,X) (void)(write(FD,X,sizeof(X)-1)) | |
109 | #define WRITE_STR(FD,X) writeStr(FD,X) | |
110 | ||
111 | static void | |
112 | showHelp(int fd, char const *cmd, int res) | |
113 | { | |
114 | char tmp[strlen(cmd)+1]; | |
115 | strcpy(tmp, cmd); | |
116 | ||
117 | WRITE_MSG(fd, "Usage: "); | |
118 | WRITE_STR(fd, basename(tmp)); | |
119 | WRITE_MSG(fd, | |
120 | " [--define '<macro> <value>']* [--with[out] <key>]* [--chroot <dir>]\n" | |
121 | " [--target <target>] [--rcfile <rcfile>] [--] <specfile>\n"); | |
122 | exit(res); | |
123 | } | |
124 | ||
125 | static void | |
126 | addDefine(struct Arguments *args, char const *val) | |
127 | { | |
128 | register size_t c = args->macros.cnt; | |
129 | if (args->macros.reserved <= c) { | |
130 | args->macros.reserved *= 2; | |
131 | args->macros.reserved += 1; | |
132 | ||
133 | args->macros.values = realloc(args->macros.values, | |
134 | args->macros.reserved * sizeof(char const *)); | |
135 | if (args->macros.values==0) { | |
136 | perror("realloc()"); | |
137 | exit(1); | |
138 | } | |
139 | } | |
140 | ||
141 | args->macros.values[c] = strdup(val); | |
142 | ++args->macros.cnt; | |
143 | } | |
144 | ||
145 | static void | |
146 | setWithMacro(struct Arguments *args, | |
147 | char const *name, char const *prefix, size_t prefix_len) | |
148 | { | |
149 | size_t len = strlen(name); | |
150 | char tmp[2*len + 2*prefix_len + sizeof("__ ---")]; | |
151 | char * ptr = tmp; | |
152 | ||
153 | // set '_<prefix>_<name>' | |
154 | *ptr++ = '_'; | |
155 | memcpy(ptr, prefix, prefix_len); ptr += prefix_len; | |
156 | *ptr++ = '_'; | |
157 | memcpy(ptr, name, len); ptr += len; | |
158 | *ptr++ = ' '; | |
159 | ||
160 | // append ' --<prefix>-<name>' | |
161 | *ptr++ = '-'; | |
162 | *ptr++ = '-'; | |
163 | memcpy(ptr, prefix, prefix_len); ptr += prefix_len; | |
164 | *ptr++ = '-'; | |
165 | memcpy(ptr, name, len); ptr += len; | |
166 | *ptr = '\0'; | |
167 | ||
168 | addDefine(args, tmp); | |
169 | } | |
170 | ||
171 | ||
172 | static void | |
173 | parseArgs(struct Arguments *args, int argc, char *argv[]) | |
174 | { | |
175 | while (1) { | |
176 | int c = getopt_long(argc, argv, "", CMDLINE_OPTIONS, 0); | |
177 | if (c==-1) break; | |
178 | switch (c) { | |
179 | case 'h' : showHelp(1, argv[0], 0); | |
180 | case ARG_TARGET : args->target = optarg; break; | |
181 | case ARG_RCFILE : args->rcfile = optarg; break; | |
182 | case ARG_CHROOT : args->chroot = optarg; break; | |
183 | case ARG_UID : args->uid = atoi(optarg); break; | |
184 | case ARG_GID : args->gid = atoi(optarg); break; | |
185 | case ARG_DEFINE : addDefine(args, optarg); break; | |
186 | case ARG_WITH : setWithMacro(args, optarg, "with", 4); break; | |
187 | case ARG_WITHOUT : setWithMacro(args, optarg, "without", 7); break; | |
188 | default: | |
189 | WRITE_MSG(2, "Try '"); | |
190 | WRITE_STR(2, argv[0]); | |
191 | WRITE_MSG(2, " --help\" for more information.\n"); | |
192 | exit(1); | |
193 | } | |
194 | } | |
195 | ||
196 | if (optind+1!=argc) { | |
197 | write(2, "No/too much specfile(s) given; aborting\n", 40); | |
198 | exit(1); | |
199 | } | |
200 | ||
201 | if (args->gid==(gid_t)(-1)) | |
202 | args->gid = args->uid; | |
203 | ||
204 | args->specfile = argv[optind]; | |
205 | } | |
206 | ||
207 | static void | |
208 | setMacros(char const * const *macros, size_t cnt) | |
209 | { | |
210 | size_t i; | |
211 | for (i=0; i<cnt; ++i) | |
212 | rpmDefineMacro(rpmGlobalMacroContext, macros[i], 0); | |
213 | } | |
214 | ||
215 | static void | |
df2ac7c1 | 216 | printDepSet(struct DepSet set, char const *prefix) |
5f9d9873 JR |
217 | { |
218 | ssize_t i; | |
df2ac7c1 JR |
219 | for (i=0; i<set.cnt; ++i) { |
220 | printf("%s%08x %s %s\n", prefix, (uint32_t)rpmtdGetNumber(set.flags), rpmtdGetString(set.name), rpmtdGetString(set.version)); | |
221 | rpmtdNext(set.flags); | |
222 | rpmtdNext(set.name); | |
223 | rpmtdNext(set.version); | |
224 | } | |
5f9d9873 JR |
225 | } |
226 | ||
227 | static void | |
228 | evaluateHeader(Header h) | |
229 | { | |
df2ac7c1 JR |
230 | struct DepSet buildreqs; |
231 | struct DepSet conflicts; | |
232 | ||
233 | buildreqs.flags = rpmtdNew(); | |
234 | buildreqs.name = rpmtdNew(); | |
235 | buildreqs.version = rpmtdNew(); | |
236 | buildreqs.cnt = 0; | |
237 | ||
238 | if (headerGet(h, RPMTAG_REQUIREFLAGS, buildreqs.flags, 0) && | |
239 | headerGet(h, RPMTAG_REQUIRENAME, buildreqs.name, 0) && | |
240 | headerGet(h, RPMTAG_REQUIREVERSION, buildreqs.version, 0)) { | |
241 | assert(buildreqs.flags->count==buildreqs.name->count && buildreqs.name->count==buildreqs.version->count); | |
242 | buildreqs.cnt = buildreqs.flags->count; | |
5f9d9873 JR |
243 | } |
244 | ||
df2ac7c1 JR |
245 | conflicts.flags = rpmtdNew(); |
246 | conflicts.name = rpmtdNew(); | |
247 | conflicts.version = rpmtdNew(); | |
248 | conflicts.cnt = 0; | |
249 | ||
250 | if (headerGet(h, RPMTAG_CONFLICTFLAGS, conflicts.flags, 0) && | |
251 | headerGet(h, RPMTAG_CONFLICTNAME, conflicts.name, 0) && | |
252 | headerGet(h, RPMTAG_CONFLICTVERSION, conflicts.version, 0)) { | |
253 | assert(conflicts.flags->count==conflicts.name->count && conflicts.name->count==conflicts.version->count); | |
254 | conflicts.cnt = conflicts.flags->count; | |
5f9d9873 JR |
255 | } |
256 | ||
df2ac7c1 JR |
257 | printDepSet(buildreqs, "+ "); |
258 | printDepSet(conflicts, "- "); | |
5f9d9873 JR |
259 | } |
260 | ||
261 | int main(int argc, char *argv[]) | |
262 | { | |
263 | struct Arguments args = { 0,0,0,-1,-1, {0,0,0}, 0 }; | |
df2ac7c1 | 264 | rpmSpec s; |
5f9d9873 JR |
265 | |
266 | parseArgs(&args, argc, argv); | |
267 | ||
268 | if ((args.chroot && chroot(args.chroot)==-1) || | |
269 | (args.uid!=(uid_t)(-1) && (setgroups(0,0) ==-1 || getgroups(0,0)!=0)) || | |
270 | (args.gid!=(gid_t)(-1) && (setgid(args.gid)==-1 || getgid()!=args.gid)) || | |
271 | (args.uid!=(uid_t)(-1) && (setuid(args.uid)==-1 || getuid()!=args.uid))) { | |
272 | perror("chroot/setuid/setgid()"); | |
273 | return EXIT_FAILURE; | |
274 | } | |
5f9d9873 | 275 | |
df2ac7c1 | 276 | rpmSetVerbosity(RPMLOG_ERR); |
5f9d9873 | 277 | |
df2ac7c1 JR |
278 | rpmReadConfigFiles(args.rcfile, args.target); |
279 | setMacros(args.macros.values, args.macros.cnt); | |
5f9d9873 | 280 | |
df2ac7c1 JR |
281 | s = rpmSpecParse(args.specfile, RPMSPEC_FORCE, NULL); |
282 | evaluateHeader(rpmSpecSourceHeader(s)); | |
5f9d9873 | 283 | } |