1 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
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.
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.
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.
16 // version 0.0.7, 2003-11-21
17 // * made it compilable with non-C99 compilers
19 // version 0.0.6, 2003-11-21
20 // * added rpm-4.0.4 compatibility (define RPM404 macro)
22 // version 0.0.5, 2003-11-21
23 // * added '--uid' and '--gid' options
24 // * use macros for option-ids
26 // version 0.0.4, 2003-11-19
27 // * set 'force' flag on parseSpec() to ignore missing sources & patches
29 // version 0.0.3, 2003-11-19
30 // * fixed buffer-overflow in '--with[out]' statements
32 // version 0.0.2, 2003-11-19
33 // * big rewrite; implemented nearly the full functionality
35 // version 0.0.1, 2003-11-19
45 #include <sys/types.h>
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
63 static struct option const
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 },
92 char const * specfile;
103 writeStr(int fd, char const *cmd)
105 (void)write(fd, cmd, strlen(cmd));
108 #define WRITE_MSG(FD,X) (void)(write(FD,X,sizeof(X)-1))
109 #define WRITE_STR(FD,X) writeStr(FD,X)
112 showHelp(int fd, char const *cmd, int res)
114 char tmp[strlen(cmd)+1];
117 WRITE_MSG(fd, "Usage: ");
118 WRITE_STR(fd, basename(tmp));
120 " [--define '<macro> <value>']* [--with[out] <key>]* [--chroot <dir>]\n"
121 " [--target <target>] [--rcfile <rcfile>] [--] <specfile>\n");
126 addDefine(struct Arguments *args, char const *val)
128 register size_t c = args->macros.cnt;
129 if (args->macros.reserved <= c) {
130 args->macros.reserved *= 2;
131 args->macros.reserved += 1;
133 args->macros.values = realloc(args->macros.values,
134 args->macros.reserved * sizeof(char const *));
135 if (args->macros.values==0) {
141 args->macros.values[c] = strdup(val);
146 setWithMacro(struct Arguments *args,
147 char const *name, char const *prefix, size_t prefix_len)
149 size_t len = strlen(name);
150 char tmp[2*len + 2*prefix_len + sizeof("__ ---")];
153 // set '_<prefix>_<name>'
155 memcpy(ptr, prefix, prefix_len); ptr += prefix_len;
157 memcpy(ptr, name, len); ptr += len;
160 // append ' --<prefix>-<name>'
163 memcpy(ptr, prefix, prefix_len); ptr += prefix_len;
165 memcpy(ptr, name, len); ptr += len;
168 addDefine(args, tmp);
173 parseArgs(struct Arguments *args, int argc, char *argv[])
176 int c = getopt_long(argc, argv, "", CMDLINE_OPTIONS, 0);
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;
189 WRITE_MSG(2, "Try '");
190 WRITE_STR(2, argv[0]);
191 WRITE_MSG(2, " --help\" for more information.\n");
196 if (optind+1!=argc) {
197 write(2, "No/too much specfile(s) given; aborting\n", 40);
201 if (args->gid==(gid_t)(-1))
202 args->gid = args->uid;
204 args->specfile = argv[optind];
208 setMacros(char const * const *macros, size_t cnt)
211 for (i=0; i<cnt; ++i)
212 rpmDefineMacro(rpmGlobalMacroContext, macros[i], 0);
216 printDepSet(struct DepSet set, char const *prefix)
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);
223 rpmtdNext(set.version);
228 evaluateHeader(Header h)
230 struct DepSet buildreqs;
231 struct DepSet conflicts;
233 buildreqs.flags = rpmtdNew();
234 buildreqs.name = rpmtdNew();
235 buildreqs.version = rpmtdNew();
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;
245 conflicts.flags = rpmtdNew();
246 conflicts.name = rpmtdNew();
247 conflicts.version = rpmtdNew();
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;
257 printDepSet(buildreqs, "+ ");
258 printDepSet(conflicts, "- ");
261 int main(int argc, char *argv[])
263 struct Arguments args = { 0,0,0,-1,-1, {0,0,0}, 0 };
266 parseArgs(&args, argc, argv);
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()");
276 rpmSetVerbosity(RPMLOG_ERR);
278 rpmReadConfigFiles(args.rcfile, args.target);
279 setMacros(args.macros.values, args.macros.cnt);
281 s = rpmSpecParse(args.specfile, RPMSPEC_FORCE, NULL);
282 evaluateHeader(rpmSpecSourceHeader(s));