Example #1
0
//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;
}
Example #2
0
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);
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
File: main.c Project: OPK/xpwn
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;
}
Example #6
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;
}
Example #7
0
/**
 * 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;
}