2 const char *__progname;
6 #include <rpm/rpmbuild.h>
7 #include <rpm/header.h>
9 #include "lib/rpmlead.h"
10 #include "build/buildio.h"
14 typedef enum injmode_e { INJ_UNKNOWN, INJ_ADD, INJ_DELETE, INJ_MODIFY } injmode_t;
16 injmode_t injmode = INJ_UNKNOWN;
18 typedef struct cmd_s {
32 static const char * pr_injmode(injmode_t injmode)
35 case INJ_ADD: return("add");
36 case INJ_DELETE: return("delete");
37 case INJ_MODIFY: return("modify");
38 case INJ_UNKNOWN: return("unknown");
39 default: return("???");
43 enum cvtaction {CA_OLD, CA_NEW, CA_OMIT, CA_ERR};
45 static enum cvtaction convertAMD(enum cvtaction ca, rpmTagType type,
46 void ** nvalsp, rpm_count_t *ncountp, cmd_t *newc)
52 if (!(nvalsp && ncountp))
67 { int32_t *intp = xmalloc(newc->nvals * sizeof(*intp));
68 for (i = 0; i < newc->nvals; i++) {
72 ival = strtol(newc->vals[i], &end, 0);
75 if ((((unsigned long)ival) >> (8*sizeof(*intp))) != 0)
79 if (i < newc->nvals) {
85 *ncountp = newc->nvals;
87 case RPM_BIN_TYPE: /* icons & signatures */
89 if (newc->nvals != 1) {
94 *nvalsp = xstrdup(newc->vals[0]);
95 *ncountp = newc->nvals;
97 case RPM_STRING_ARRAY_TYPE:
98 { const char **av = xmalloc((newc->nvals+1) * sizeof(char *));
99 for (i = 0; i < newc->nvals; i++) {
100 av[i] = newc->vals[i];
102 av[newc->nvals] = NULL;
104 *ncountp = newc->nvals;
108 case RPM_INT8_TYPE: /* arch & os */
109 case RPM_INT16_TYPE: /* file modes & rdevs */
110 case RPM_I18NSTRING_TYPE:
111 default: /* this conversion cannot be performed (yet) */
122 static enum cvtaction convertExistingAMD(rpmTag tag, rpmTagType type,
123 rpm_data_t valsp, rpm_count_t *countp, void ** nvalsp, rpm_count_t *ncountp,
124 cmd_t *cmds[], int ncmds)
127 enum cvtaction ca = CA_OLD;
130 if (!((tag >= RPMTAG_NAME && tag < RPMTAG_FIRSTFREE_TAG)
131 || tag >= RPMTAG_EXTERNAL_TAG))
134 for (i = 0; i < ncmds; i++) {
138 if (tag != c->tagval)
143 switch (c->injmode) {
145 if (ca != CA_OMIT) {/* old tag was deleted, now adding again */
153 case INJ_MODIFY: /* XXX for now, this is delete, then add */
154 if (ca == CA_OMIT) {/* old tag was deleted, can't modify */
163 if (ca == CA_OMIT) {/* old tag was deleted, now deleting again */
179 ca = convertAMD(ca, type, nvalsp, ncountp, newc);
183 newc->oldcnt = *countp;
194 Header headerCopyWithConvert(Header h, cmd_t *cmds[], int ncmds)
196 HeaderIterator headerIter;
197 Header res = headerNew();
200 headerIter = headerInitIterator(h);
202 while (headerNext(headerIter, &td)) {
204 struct rpmtd_s ntd = { .type = td.type, .tag = td.tag,
205 .count = 0, .data = NULL
208 ca = convertExistingAMD(td.tag, td.type, &td.data, &td.count,
209 &ntd.data, &ntd.count, cmds, ncmds);
212 case CA_OLD: /* copy old tag and values to header */
214 /* Don't copy the old changelog, we'll do that later. */
216 case RPMTAG_CHANGELOGTIME:
217 case RPMTAG_CHANGELOGNAME:
218 case RPMTAG_CHANGELOGTEXT:
221 headerPut(res, &td, HEADERPUT_DEFAULT);
225 case CA_NEW: /* copy new tag and values to header */
226 headerPut(res, &ntd, HEADERPUT_DEFAULT);
228 case CA_OMIT: /* delete old tag and values from header */
237 headerFreeIterator(headerIter);
242 static char * genChangelog(cmd_t *cmds[], int ncmds)
244 #define MYBUFSIZ (2*BUFSIZ)
245 char *b, *buf = xmalloc(MYBUFSIZ);
249 for (i = 0; i < ncmds; i++) {
252 if ((c = cmds[i]) == NULL)
255 b += sprintf(b, "- %s tag %s(%d)",
256 pr_injmode(c->injmode), c->tag, c->tagval);
258 if (c->oldcnt || c->nvals) {
262 b += sprintf(b, "oldcnt %d", c->oldcnt);
263 if (c->oldcnt && c->nvals) {
268 b += sprintf(b, "nvals %d", c->nvals);
279 headerInject(Header *hdrp, cmd_t *cmds[], int ncmds)
285 if (!(hdrp && cmds && ncmds > 0))
288 h = headerCopyWithConvert(*hdrp, cmds, ncmds);
289 for (i = 0; i < ncmds; i++) {
293 if ((c = cmds[i]) == NULL)
296 rc = headerIsEntry(h, c->tagval);
297 if (!rc && !c->done && c->injmode != INJ_DELETE) {
301 td.type = (c->nvals > 0) ? RPM_STRING_ARRAY_TYPE : RPM_STRING_TYPE;
303 ca = convertAMD(CA_NEW, td.type, &td.data, &td.count, c);
305 headerPut(h, &td, HEADERPUT_DEFAULT);
306 rc = headerIsEntry(h, c->tagval);
311 if (!(rc && c->done > 0)) {
312 warnx("failed to add tag %s", rpmTagGetName(c->tagval));
317 if (!(!rc && c->done > 0)) {
318 warnx("failed to delete tag %s", rpmTagGetName(c->tagval));
323 if (!(rc && c->done > 0)) {
324 warnx("failed to modify tag %s", rpmTagGetName(c->tagval));
334 /* XXX possibly need strict mode to exit immediately here */
337 if (ec == 0 && *hdrp) {
338 static char name[512] = "";
339 static const char *text = NULL;
340 static rpmTag cltags[] = {
341 RPMTAG_CHANGELOGTIME,
342 RPMTAG_CHANGELOGNAME,
343 RPMTAG_CHANGELOGTEXT,
348 sprintf(name, "rpminject <%s@%s>", getUname(getuid()), buildHost());
350 text = genChangelog(cmds, ncmds);
352 addChangelogEntry(h, *getBuildTime(), name, text);
353 headerCopyTags(*hdrp, h, cltags);
355 *hdrp = headerFree(*hdrp);
364 /* ========================================================================= */
367 rewriteRPM(const char *fni, const char *fno, cmd_t *cmds[], int ncmds)
371 struct cpioSourceArchive_s csabuf, *csa = &csabuf;
374 csa->cpioArchiveSize = 0;
375 csa->cpioFdIn = fdNew();
376 csa->cpioList = NULL;
378 /* Read rpm and (partially) recreate spec/pkg control structures */
379 if ((rc = readRPM(fni, &spec, &sigs, csa)) != 0)
382 /* Inject new strings into header tags */
383 if ((rc = headerInject(&spec->packages->header, cmds, ncmds)) != 0)
386 /* Rewrite the rpm */
387 if (headerIsSource(spec->packages->header)) {
388 rc = writeRPM(&spec->packages->header, NULL, fno, csa, &(spec->cookie));
390 rc = writeRPM(&spec->packages->header, NULL, fno, csa, NULL);
394 Fclose(csa->cpioFdIn);
399 /* ========================================================================= */
402 do_inject(cmd_t *cmds[], int ncmds, const char *argv[])
407 if (argv == NULL || *argv == NULL) {
408 /* XXX generate lead/header to stdout */
412 while ((arg = *argv++) != NULL) {
413 char *fni = xmalloc(strlen(arg) + sizeof("-SAVE"));
414 const char *fno = arg;
417 strcat(fni, "-SAVE");
419 if (link(fno, fni)) {
420 warn("can't link temp input file %s", fni);
424 if (rewriteRPM(fni, fno, cmds, ncmds)) {
426 if (rename(fni, fno))
427 warn("can't rename %s to %s", fni, fno);
436 static struct poptOption optionsTable[] = {
437 { "add", 'a', 0, 0, 'a', NULL, NULL },
438 { "del", 'd', 0, 0, 'd', NULL, NULL },
439 { "injtags", 'i', 0, 0, 'i', NULL, NULL },
440 { "modify", 'm', 0, 0, 'm', NULL, NULL },
441 { "tag", 't', POPT_ARG_STRING, 0, 't', NULL, NULL },
442 { "value", 'v', POPT_ARG_STRING, 0, 'v', NULL, NULL },
443 { NULL, 0, 0, 0, 0, NULL, NULL }
447 main(int argc, char *argv[])
454 injmode_t lastmode = INJ_UNKNOWN;
456 setprogname(argv[0]); /* Retrofit glibc __progname */
457 #if defined(ENABLE_NLS)
458 (void)setlocale(LC_ALL, "" );
460 (void)bindtextdomain(PACKAGE, LOCALEDIR);
461 (void)textdomain(PACKAGE);
464 optCon = poptGetContext("rpminject", argc, (const char **) argv, optionsTable, 0);
465 #if RPM_USES_POPTREADDEFAULTCONFIG
466 poptReadDefaultConfig(optCon, 1);
469 while ((arg = poptGetNextOpt(optCon)) > 0) {
470 optArg = poptGetOptArg(optCon);
476 injmode = INJ_DELETE;
479 injmode = INJ_MODIFY;
482 if (ncmds == 0 || c == NULL)
483 errx(EXIT_FAILURE, "missing inject mode before \"--tag %s\"", optArg);
485 if (c->injmode != INJ_DELETE &&
486 (c->nvals <= 0 || c->vals == NULL))
487 errx(EXIT_FAILURE, "add/modify inject mode with \"--tag %s\" needs a value", c->tag);
488 cmds[ncmds] = c = xcalloc(1, sizeof(cmd_t));
489 cmds[ncmds]->injmode = cmds[ncmds-1]->injmode;
492 c->tagval = rpmTagGetValue(optArg);
493 if (c->tagval == RPMTAG_NOT_FOUND)
494 errx(EXIT_FAILURE, "unknown rpm tag \"--tag %s\"", optArg);
495 c->tag = xstrdup(optArg);
498 if (ncmds == 0 || c == NULL)
499 errx(EXIT_FAILURE, "missing inject mode before \"--value %s\"", optArg);
501 errx(EXIT_FAILURE, "missing tag name before \"--value %s\"", optArg);
502 if (c->nvals == 0 || c->vals == NULL) {
503 c->vals = xcalloc(2, sizeof(char *));
505 c->vals = xrealloc(c->vals,
506 (c->nvals+2)*sizeof(char *));
508 c->vals[c->nvals++] = xstrdup(optArg);
509 c->vals[c->nvals] = NULL;
512 rpmDisplayQueryTags(stdout);
516 errx(EXIT_FAILURE, "unknown popt return (%d)", arg);
520 if (injmode != lastmode) {
521 cmds[ncmds] = c = xcalloc(1, sizeof(cmd_t));
522 cmds[ncmds]->injmode = lastmode = injmode;
527 /* XXX I don't want to read rpmrc */
528 addMacro(NULL, "_tmppath", NULL, "/tmp", RMIL_DEFAULT);
530 ec = do_inject(cmds, ncmds, poptGetArgs(optCon));
532 optCon = poptFreeContext(optCon);