//Extractors static T_exp unEx(Tr_exp e){ Temp_temp r; Temp_label t,f; T_exp ex; switch(e->kind){ case Tr_ex: ex = e->u.ex; break; case Tr_cx: r = Temp_newtemp(); t = Temp_newlabel(); f = Temp_newlabel(); doPatch(e->u.cx.trues, t); doPatch(e->u.cx.falses, f); ex = T_Eseq(T_Move(T_Temp(r), T_Const(1)), T_Eseq(e->u.cx.stm, T_Eseq(T_Label(f), T_Eseq(T_Move(T_Temp(r), T_Const(0)), T_Eseq(T_Label(t), T_Temp(r) ) ) ) ) ); break; case Tr_nx: ex = T_Eseq(e->u.nx, T_Const(0)); break; } return ex; }
Tr_exp Tr_whileExp(Tr_exp cond, Tr_exp body){ debug("Tr_whileExp"); T_stm st; struct Cx cx_cond = unCx(cond); Temp_label t = Temp_newlabel(); Temp_label f = LL_peek();//Get done label from the list, which should have been prepared before this function is called. Temp_label start = Temp_newlabel(); doPatch(cx_cond.trues, t); doPatch(cx_cond.falses, f); /* T_Label start cx_cond.stm (true->t, false->f) T_Label(t) body T_Jump start T_Label(f) */ st = T_Seq(T_Label(start), T_Seq(cx_cond.stm, T_Seq(T_Label(t), T_Seq(unNx(body), T_Seq( T_Jump( T_Name(start), Temp_LabelList(start, NULL) ), T_Label(f) ) ) ) ) ); //Pop the label as it's no longer used LL_pop(); return Tr_Nx(st); }
static T_stm unNx(Tr_exp e){ Temp_label t,f; T_stm st; switch(e->kind){ case Tr_ex: st = T_Exp(e->u.ex); break; case Tr_cx: t = Temp_newlabel(); f = Temp_newlabel(); doPatch(e->u.cx.trues, t); doPatch(e->u.cx.falses, f); st = T_Seq(e->u.cx.stm, T_Seq(T_Label(t), T_Label(f))); break; case Tr_nx: st = e->u.nx; break; } return st; }
Tr_exp Tr_ifExp(Tr_exp cond, Tr_exp thenb, Tr_exp elseb){ T_exp ex; T_stm st; Tr_exp ret; struct Cx cx_cond = unCx(cond); Temp_label t = Temp_newlabel(); Temp_label f = Temp_newlabel(); Temp_label join = Temp_newlabel(); doPatch(cx_cond.trues, t); doPatch(cx_cond.falses, f); if(elseb==NULL){ //case 1: if-then debug("Tr_ifExp: if-then"); st = T_Seq(cx_cond.stm, T_Seq(T_Label(t), T_Seq(unNx(thenb), T_Label(f) ) ) ); ret = Tr_Nx(st); } else { //case 2: if-then-else if(thenb->kind==Tr_nx && elseb->kind==Tr_nx){ debug("Tr_ifExp: if-then-else (2 nx)"); //special case: two statements st = T_Seq(cx_cond.stm, T_Seq(T_Label(t), T_Seq(unNx(thenb), T_Seq( T_Jump( T_Name(join), Temp_LabelList(join, NULL) ), T_Seq(T_Label(f), T_Seq(unNx(elseb), T_Label(join) ) ) ) ) ) ); ret = Tr_Nx(st); //TODO: special case - two cx. } else { debug("Tr_ifExp: if-then-else"); Temp_temp r = Temp_newtemp(); ex = T_Eseq(cx_cond.stm, T_Eseq(T_Label(t), T_Eseq(T_Move(T_Temp(r), unEx(thenb)), T_Eseq( T_Jump( T_Name(join), Temp_LabelList(join, NULL) ), T_Eseq(T_Label(f), T_Eseq(T_Move(T_Temp(r), unEx(elseb)), T_Eseq(T_Label(join), T_Temp(r) ) ) ) ) ) ) ); ret = Tr_Ex(ex); } } return ret; }
int main(int argc, char* argv[]) { init_libxpwn(); Dictionary* info; Dictionary* firmwarePatches; Dictionary* patchDict; ArrayValue* patchArray; void* buffer; StringValue* actionValue; StringValue* pathValue; StringValue* fileValue; StringValue* patchValue; char* patchPath; char* rootFSPathInIPSW; io_func* rootFS; Volume* rootVolume; size_t rootSize; size_t preferredRootSize = 0; size_t minimumRootSize = 0; char* ramdiskFSPathInIPSW; unsigned int ramdiskKey[16]; unsigned int ramdiskIV[16]; unsigned int* pRamdiskKey = NULL; unsigned int* pRamdiskIV = NULL; io_func* ramdiskFS; Volume* ramdiskVolume; char* updateRamdiskFSPathInIPSW = NULL; int i; OutputState* outputState; char* bundlePath; char* bundleRoot = "FirmwareBundles/"; int mergePaths; char* outputIPSW; void* imageBuffer; size_t imageSize; AbstractFile* bootloader39 = NULL; AbstractFile* bootloader46 = NULL; AbstractFile* applelogo = NULL; AbstractFile* recoverymode = NULL; char noWipe = FALSE; char unlockBaseband = FALSE; char selfDestruct = FALSE; char use39 = FALSE; char use46 = FALSE; char doBootNeuter = FALSE; char updateBB = FALSE; char useMemory = FALSE; unsigned int key[16]; unsigned int iv[16]; unsigned int* pKey = NULL; unsigned int* pIV = NULL; if(argc < 3) { XLOG(0, "usage %s <input.ipsw> <target.ipsw> [-b <bootimage.png>] [-r <recoveryimage.png>] [-s <system partition size>] [-memory] [-bbupdate] [-nowipe] [-e \"<action to exclude>\"] [[-unlock] [-use39] [-use46] [-cleanup] -3 <bootloader 3.9 file> -4 <bootloader 4.6 file>] <package1.tar> <package2.tar>...\n", argv[0]); return 0; } outputIPSW = argv[2]; int* toRemove = NULL; int numToRemove = 0; for(i = 3; i < argc; i++) { if(argv[i][0] != '-') { break; } if(strcmp(argv[i], "-memory") == 0) { useMemory = TRUE; continue; } if(strcmp(argv[i], "-s") == 0) { int size; sscanf(argv[i + 1], "%d", &size); preferredRootSize = size; i++; continue; } if(strcmp(argv[i], "-nowipe") == 0) { noWipe = TRUE; continue; } if(strcmp(argv[i], "-bbupdate") == 0) { updateBB = TRUE; continue; } if(strcmp(argv[i], "-e") == 0) { numToRemove++; toRemove = realloc(toRemove, numToRemove * sizeof(int)); toRemove[numToRemove - 1] = i + 1; i++; continue; } if(strcmp(argv[i], "-unlock") == 0) { unlockBaseband = TRUE; continue; } if(strcmp(argv[i], "-cleanup") == 0) { selfDestruct = TRUE; continue; } if(strcmp(argv[i], "-use39") == 0) { if(use46) { XLOG(0, "error: select only one of -use39 and -use46\n"); exit(1); } use39 = TRUE; continue; } if(strcmp(argv[i], "-use46") == 0) { if(use39) { XLOG(0, "error: select only one of -use39 and -use46\n"); exit(1); } use46 = TRUE; continue; } if(strcmp(argv[i], "-b") == 0) { applelogo = createAbstractFileFromFile(fopen(argv[i + 1], "rb")); if(!applelogo) { XLOG(0, "cannot open %s\n", argv[i + 1]); exit(1); } i++; continue; } if(strcmp(argv[i], "-r") == 0) { recoverymode = createAbstractFileFromFile(fopen(argv[i + 1], "rb")); if(!recoverymode) { XLOG(0, "cannot open %s\n", argv[i + 1]); exit(1); } i++; continue; } if(strcmp(argv[i], "-3") == 0) { bootloader39 = createAbstractFileFromFile(fopen(argv[i + 1], "rb")); if(!bootloader39) { XLOG(0, "cannot open %s\n", argv[i + 1]); exit(1); } i++; continue; } if(strcmp(argv[i], "-4") == 0) { bootloader46 = createAbstractFileFromFile(fopen(argv[i + 1], "rb")); if(!bootloader46) { XLOG(0, "cannot open %s\n", argv[i + 1]); exit(1); } i++; continue; } } mergePaths = i; if(use39 || use46 || unlockBaseband || selfDestruct || bootloader39 || bootloader46) { if(!(bootloader39) || !(bootloader46)) { XLOG(0, "error: you must specify both bootloader files.\n"); exit(1); } else { doBootNeuter = TRUE; } } info = parseIPSW2(argv[1], bundleRoot, &bundlePath, &outputState, useMemory); if(info == NULL) { XLOG(0, "error: Could not load IPSW\n"); exit(1); } firmwarePatches = (Dictionary*)getValueByKey(info, "FilesystemPatches"); int j; for(j = 0; j < numToRemove; j++) { removeKey(firmwarePatches, argv[toRemove[j]]); } free(toRemove); firmwarePatches = (Dictionary*)getValueByKey(info, "FirmwarePatches"); patchDict = (Dictionary*) firmwarePatches->values; while(patchDict != NULL) { fileValue = (StringValue*) getValueByKey(patchDict, "File"); StringValue* keyValue = (StringValue*) getValueByKey(patchDict, "Key"); StringValue* ivValue = (StringValue*) getValueByKey(patchDict, "IV"); pKey = NULL; pIV = NULL; if(keyValue) { sscanf(keyValue->value, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", &key[0], &key[1], &key[2], &key[3], &key[4], &key[5], &key[6], &key[7], &key[8], &key[9], &key[10], &key[11], &key[12], &key[13], &key[14], &key[15]); pKey = key; } if(ivValue) { sscanf(ivValue->value, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", &iv[0], &iv[1], &iv[2], &iv[3], &iv[4], &iv[5], &iv[6], &iv[7], &iv[8], &iv[9], &iv[10], &iv[11], &iv[12], &iv[13], &iv[14], &iv[15]); pIV = iv; } if(strcmp(patchDict->dValue.key, "Restore Ramdisk") == 0) { ramdiskFSPathInIPSW = fileValue->value; if(pKey) { memcpy(ramdiskKey, key, sizeof(key)); memcpy(ramdiskIV, iv, sizeof(iv)); pRamdiskKey = ramdiskKey; pRamdiskIV = ramdiskIV; } else { pRamdiskKey = NULL; pRamdiskIV = NULL; } } if(strcmp(patchDict->dValue.key, "Update Ramdisk") == 0) { updateRamdiskFSPathInIPSW = fileValue->value; } patchValue = (StringValue*) getValueByKey(patchDict, "Patch2"); if(patchValue) { if(noWipe) { XLOG(0, "%s: ", patchDict->dValue.key); fflush(stdout); doPatch(patchValue, fileValue, bundlePath, &outputState, pKey, pIV, useMemory); patchDict = (Dictionary*) patchDict->dValue.next; continue; /* skip over the normal Patch */ } } patchValue = (StringValue*) getValueByKey(patchDict, "Patch"); if(patchValue) { XLOG(0, "%s: ", patchDict->dValue.key); fflush(stdout); doPatch(patchValue, fileValue, bundlePath, &outputState, pKey, pIV, useMemory); } if(strcmp(patchDict->dValue.key, "AppleLogo") == 0 && applelogo) { XLOG(0, "replacing %s\n", fileValue->value); fflush(stdout); ASSERT((imageBuffer = replaceBootImage(getFileFromOutputState(&outputState, fileValue->value), pKey, pIV, applelogo, &imageSize)) != NULL, "failed to use new image"); addToOutput(&outputState, fileValue->value, imageBuffer, imageSize); } if(strcmp(patchDict->dValue.key, "RecoveryMode") == 0 && recoverymode) { XLOG(0, "replacing %s\n", fileValue->value); fflush(stdout); ASSERT((imageBuffer = replaceBootImage(getFileFromOutputState(&outputState, fileValue->value), pKey, pIV, recoverymode, &imageSize)) != NULL, "failed to use new image"); addToOutput(&outputState, fileValue->value, imageBuffer, imageSize); } patchDict = (Dictionary*) patchDict->dValue.next; } fileValue = (StringValue*) getValueByKey(info, "RootFilesystem"); rootFSPathInIPSW = fileValue->value; size_t defaultRootSize = ((IntegerValue*) getValueByKey(info, "RootFilesystemSize"))->value; minimumRootSize = defaultRootSize * 1000 * 1000; minimumRootSize -= minimumRootSize % 512; if(preferredRootSize == 0) { preferredRootSize = defaultRootSize; } rootSize = preferredRootSize * 1000 * 1000; rootSize -= rootSize % 512; if(useMemory) { buffer = malloc(rootSize); } else { buffer = NULL; } if(buffer == NULL) { XLOG(2, "using filesystem backed temporary storage\n"); } extractDmg( createAbstractFileFromFileVault(getFileFromOutputState(&outputState, rootFSPathInIPSW), ((StringValue*)getValueByKey(info, "RootFilesystemKey"))->value), openRoot((void**)&buffer, &rootSize), -1); rootFS = IOFuncFromAbstractFile(openRoot((void**)&buffer, &rootSize)); rootVolume = openVolume(rootFS); XLOG(0, "Growing root to minimum: %ld\n", (long) defaultRootSize); fflush(stdout); grow_hfs(rootVolume, minimumRootSize); if(rootSize > minimumRootSize) { XLOG(0, "Growing root: %ld\n", (long) preferredRootSize); fflush(stdout); grow_hfs(rootVolume, rootSize); } firmwarePatches = (Dictionary*)getValueByKey(info, "FilesystemPatches"); patchArray = (ArrayValue*) firmwarePatches->values; while(patchArray != NULL) { for(i = 0; i < patchArray->size; i++) { patchDict = (Dictionary*) patchArray->values[i]; fileValue = (StringValue*) getValueByKey(patchDict, "File"); actionValue = (StringValue*) getValueByKey(patchDict, "Action"); if(strcmp(actionValue->value, "ReplaceKernel") == 0) { pathValue = (StringValue*) getValueByKey(patchDict, "Path"); XLOG(0, "replacing kernel... %s -> %s\n", fileValue->value, pathValue->value); fflush(stdout); add_hfs(rootVolume, getFileFromOutputState(&outputState, fileValue->value), pathValue->value); } if(strcmp(actionValue->value, "Patch") == 0) { patchValue = (StringValue*) getValueByKey(patchDict, "Patch"); patchPath = (char*) malloc(sizeof(char) * (strlen(bundlePath) + strlen(patchValue->value) + 2)); strcpy(patchPath, bundlePath); strcat(patchPath, "/"); strcat(patchPath, patchValue->value); XLOG(0, "patching %s (%s)... ", fileValue->value, patchPath); doPatchInPlace(rootVolume, fileValue->value, patchPath); free(patchPath); } } patchArray = (ArrayValue*) patchArray->dValue.next; } for(; mergePaths < argc; mergePaths++) { XLOG(0, "merging %s\n", argv[mergePaths]); AbstractFile* tarFile = createAbstractFileFromFile(fopen(argv[mergePaths], "rb")); if(tarFile == NULL) { XLOG(1, "cannot find %s, make sure your slashes are in the right direction\n", argv[mergePaths]); releaseOutput(&outputState); closeRoot(buffer); exit(0); } hfs_untar(rootVolume, tarFile); tarFile->close(tarFile); } if(pRamdiskKey) { ramdiskFS = IOFuncFromAbstractFile(openAbstractFile2(getFileFromOutputStateForOverwrite(&outputState, ramdiskFSPathInIPSW), pRamdiskKey, pRamdiskIV)); } else { XLOG(0, "unencrypted ramdisk\n"); ramdiskFS = IOFuncFromAbstractFile(openAbstractFile(getFileFromOutputStateForOverwrite(&outputState, ramdiskFSPathInIPSW))); } ramdiskVolume = openVolume(ramdiskFS); XLOG(0, "growing ramdisk: %d -> %d\n", ramdiskVolume->volumeHeader->totalBlocks * ramdiskVolume->volumeHeader->blockSize, (ramdiskVolume->volumeHeader->totalBlocks + 4) * ramdiskVolume->volumeHeader->blockSize); grow_hfs(ramdiskVolume, (ramdiskVolume->volumeHeader->totalBlocks + 4) * ramdiskVolume->volumeHeader->blockSize); if(doBootNeuter) { firmwarePatches = (Dictionary*)getValueByKey(info, "BasebandPatches"); if(firmwarePatches != NULL) { patchDict = (Dictionary*) firmwarePatches->values; while(patchDict != NULL) { pathValue = (StringValue*) getValueByKey(patchDict, "Path"); fileValue = (StringValue*) getValueByKey(patchDict, "File"); if(fileValue) { XLOG(0, "copying %s -> %s... ", fileValue->value, pathValue->value); fflush(stdout); if(copyAcrossVolumes(ramdiskVolume, rootVolume, fileValue->value, pathValue->value)) { patchValue = (StringValue*) getValueByKey(patchDict, "Patch"); if(patchValue) { patchPath = malloc(sizeof(char) * (strlen(bundlePath) + strlen(patchValue->value) + 2)); strcpy(patchPath, bundlePath); strcat(patchPath, "/"); strcat(patchPath, patchValue->value); XLOG(0, "patching %s (%s)... ", pathValue->value, patchPath); fflush(stdout); doPatchInPlace(rootVolume, pathValue->value, patchPath); free(patchPath); } } } if(strcmp(patchDict->dValue.key, "Bootloader 3.9") == 0 && bootloader39 != NULL) { add_hfs(rootVolume, bootloader39, pathValue->value); } if(strcmp(patchDict->dValue.key, "Bootloader 4.6") == 0 && bootloader46 != NULL) { add_hfs(rootVolume, bootloader46, pathValue->value); } patchDict = (Dictionary*) patchDict->dValue.next; } } fixupBootNeuterArgs(rootVolume, unlockBaseband, selfDestruct, use39, use46); } createRestoreOptions(ramdiskVolume, preferredRootSize, updateBB); closeVolume(ramdiskVolume); CLOSE(ramdiskFS); if(updateRamdiskFSPathInIPSW) removeFileFromOutputState(&outputState, updateRamdiskFSPathInIPSW); closeVolume(rootVolume); CLOSE(rootFS); buildDmg(openRoot((void**)&buffer, &rootSize), getFileFromOutputStateForReplace(&outputState, rootFSPathInIPSW)); closeRoot(buffer); writeOutput(&outputState, outputIPSW); releaseDictionary(info); free(bundlePath); return 0; }
/** * Parse %patch line. * @param spec build info * @param line current line from spec file * @return RPMRC_OK on success */ static rpmRC doPatchMacro(Spec spec, const char * line) /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ /*@modifies spec->prep, rpmGlobalMacroContext, fileSystem, internalState @*/ { char *s; char *opt_b; char *opt_d; rpmuint32_t opt_P, opt_p, opt_R, opt_E, opt_F; char buf[BUFSIZ], *bp; rpmuint32_t patch_nums[1024]; /* XXX - we can only handle 1024 patches! */ int patch_index, x; memset(patch_nums, 0, sizeof(patch_nums)); opt_P = opt_p = opt_R = opt_E = 0; opt_F = rpmExpandNumeric("%{?_default_patch_fuzz}%{!?_default_patch_fuzz:-1}"); opt_b = NULL; opt_d = NULL; patch_index = 0; if (! strchr(" \t\n", line[6])) { /* %patchN */ sprintf(buf, "%%patch -P %s", line + 6); } else { strncpy(buf, line, sizeof(buf)-1); buf[sizeof(buf)-1] = '\0'; } /*@-internalglobs@*/ /* FIX: strtok has state */ for (bp = buf; (s = strtok(bp, " \t\n")) != NULL;) { if (bp) { /* remove 1st token (%patch) */ bp = NULL; continue; } if (!strcmp(s, "-P")) { opt_P = 1; } else if (!strcmp(s, "-R")) { opt_R = 1; } else if (!strcmp(s, "-E")) { opt_E = 1; } else if (!strcmp(s, "-b")) { /* orig suffix */ opt_b = strtok(NULL, " \t\n"); if (! opt_b) { rpmlog(RPMLOG_ERR, _("line %d: Need arg to %%patch -b: %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } } else if (!strcmp(s, "-z")) { /* orig suffix */ opt_b = strtok(NULL, " \t\n"); if (! opt_b) { rpmlog(RPMLOG_ERR, _("line %d: Need arg to %%patch -z: %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } } else if (!strcmp(s, "-F")) { /* fuzz factor */ const char * fnum = (!strchr(" \t\n", s[2]) ? s+2 : strtok(NULL, " \t\n")); char * end = NULL; opt_F = (fnum ? strtol(fnum, &end, 10) : 0); if (! opt_F || *end) { rpmlog(RPMLOG_ERR, _("line %d: Bad arg to %%patch -F: %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } } else if (!strcmp(s, "-d")) { /* subdirectory */ opt_d = strtok(NULL, " \t\n"); if (! opt_d) { rpmlog(RPMLOG_ERR, _("line %d: Need arg to %%patch -d: %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } } else if (!strncmp(s, "-p", sizeof("-p")-1)) { /* unfortunately, we must support -pX */ if (! strchr(" \t\n", s[2])) { s = s + 2; } else { s = strtok(NULL, " \t\n"); if (s == NULL) { rpmlog(RPMLOG_ERR, _("line %d: Need arg to %%patch -p: %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } } if (parseNum(s, &opt_p)) { rpmlog(RPMLOG_ERR, _("line %d: Bad arg to %%patch -p: %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } } else { /* Must be a patch num */ if (patch_index == 1024) { rpmlog(RPMLOG_ERR, _("Too many patches!\n")); return RPMRC_FAIL; } if (parseNum(s, &(patch_nums[patch_index]))) { rpmlog(RPMLOG_ERR, _("line %d: Bad arg to %%patch: %s\n"), spec->lineNum, spec->line); return RPMRC_FAIL; } patch_index++; } } /*@=internalglobs@*/ /* All args processed */ if (! opt_P) { s = doPatch(spec, 0, opt_p, opt_b, opt_R, opt_E, opt_F, opt_d); if (s == NULL) return RPMRC_FAIL; spec->prep = rpmiobAppend(spec->prep, s, 1); } for (x = 0; x < patch_index; x++) { s = doPatch(spec, patch_nums[x], opt_p, opt_b, opt_R, opt_E, opt_F, opt_d); if (s == NULL) return RPMRC_FAIL; spec->prep = rpmiobAppend(spec->prep, s, 1); } return RPMRC_OK; }
/** * Parse %patch line. * This supports too many crazy syntaxes: * - %patchN is equal to %patch -P<N> * - -P<N> -P<N+1>... can be used to apply several patch on a single line * - Any trailing arguments are treated as patch numbers * - Any combination of the above, except unless at least one -P is specified, * %patch is treated as %patch -P0 so that "%patch 1" is actually * equal to "%patch -P0 -P1". * * @param spec build info * @param line current line from spec file * @return RPMRC_OK on success */ static rpmRC doPatchMacro(rpmSpec spec, const char *line) { char *opt_b, *opt_P, *opt_d; char *buf = NULL; int opt_p, opt_R, opt_E, opt_F; int argc, c; const char **argv = NULL; ARGV_t patch, patchnums = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ struct poptOption const patchOpts[] = { { NULL, 'P', POPT_ARG_STRING, &opt_P, 'P', NULL, NULL }, { NULL, 'p', POPT_ARG_INT, &opt_p, 'p', NULL, NULL }, { NULL, 'R', POPT_ARG_NONE, &opt_R, 'R', NULL, NULL }, { NULL, 'E', POPT_ARG_NONE, &opt_E, 'E', NULL, NULL }, { NULL, 'b', POPT_ARG_STRING, &opt_b, 'b', NULL, NULL }, { NULL, 'z', POPT_ARG_STRING, &opt_b, 'z', NULL, NULL }, { NULL, 'F', POPT_ARG_INT, &opt_F, 'F', NULL, NULL }, { NULL, 'd', POPT_ARG_STRING, &opt_d, 'd', NULL, NULL }, { NULL, 0, 0, NULL, 0, NULL, NULL } }; poptContext optCon = NULL; opt_p = opt_R = opt_E = 0; opt_F = rpmExpandNumeric("%{_default_patch_fuzz}"); /* get default fuzz factor for %patch */ opt_b = opt_d = NULL; /* Convert %patchN to %patch -PN to simplify further processing */ if (! strchr(" \t\n", line[6])) { rasprintf(&buf, "%%patch -P %s", line + 6); } else { if (strstr(line+6, " -P") == NULL) rasprintf(&buf, "%%patch -P %d %s", INT_MAX, line + 6); /* INT_MAX denotes not numbered %patch */ else buf = xstrdup(line); /* it is not numberless patch because -P is present */ } poptParseArgvString(buf, &argc, &argv); free(buf); /* * Grab all -P<N> numbers for later processing. Stored as strings * at this point so we only have to worry about conversion in one place. */ optCon = poptGetContext(NULL, argc, argv, patchOpts, 0); while ((c = poptGetNextOpt(optCon)) > 0) { switch (c) { case 'P': { char *arg = poptGetOptArg(optCon); if (arg) { argvAdd(&patchnums, arg); free(arg); } break; } default: break; } } if (c < -1) { rpmlog(RPMLOG_ERR, _("%s: %s: %s\n"), poptStrerror(c), poptBadOption(optCon, POPT_BADOPTION_NOALIAS), line); goto exit; } /* Any trailing arguments are treated as patch numbers */ argvAppend(&patchnums, (ARGV_const_t) poptGetArgs(optCon)); /* Convert to number, generate patch command and append to %prep script */ for (patch = patchnums; *patch; patch++) { uint32_t pnum; char *s; if (parseUnsignedNum(*patch, &pnum)) { rpmlog(RPMLOG_ERR, _("Invalid patch number %s: %s\n"), *patch, line); goto exit; } s = doPatch(spec, pnum, opt_p, opt_b, opt_R, opt_E, opt_F, opt_d); if (s == NULL) { goto exit; } appendLineStringBuf(spec->prep, s); free(s); } rc = RPMRC_OK; exit: argvFree(patchnums); free(argv); poptFreeContext(optCon); return rc; }