예제 #1
0
int _alpm_runscriptlet(alpm_handle_t *handle, const char *installfn,
                       const char *script, const char *ver, const char *oldver)
{
    char scriptfn[PATH_MAX];
    char cmdline[PATH_MAX];
    char tmpdir[PATH_MAX];
    char *argv[] = { "sh", "-c", cmdline, NULL };
    char *scriptpath;
    int clean_tmpdir = 0;
    int retval = 0;

    if(access(installfn, R_OK)) {
        /* not found */
        _alpm_log(handle, ALPM_LOG_DEBUG, "scriptlet '%s' not found\n", installfn);
        return 0;
    }

    /* creates a directory in $root/tmp/ for copying/extracting the scriptlet */
    snprintf(tmpdir, PATH_MAX, "%stmp/", handle->root);
    if(access(tmpdir, F_OK) != 0) {
        _alpm_makepath_mode(tmpdir, 01777);
    }
    snprintf(tmpdir, PATH_MAX, "%stmp/alpm_XXXXXX", handle->root);
    if(mkdtemp(tmpdir) == NULL) {
        _alpm_log(handle, ALPM_LOG_ERROR, _("could not create temp directory\n"));
        return 1;
    } else {
        clean_tmpdir = 1;
    }

    /* either extract or copy the scriptlet */
    snprintf(scriptfn, PATH_MAX, "%s/.INSTALL", tmpdir);
    if(strcmp(script, "pre_upgrade") == 0 || strcmp(script, "pre_install") == 0) {
        if(_alpm_unpack_single(handle, installfn, tmpdir, ".INSTALL")) {
            retval = 1;
        }
    } else {
        if(_alpm_copyfile(installfn, scriptfn)) {
            _alpm_log(handle, ALPM_LOG_ERROR, _("could not copy tempfile to %s (%s)\n"), scriptfn, strerror(errno));
            retval = 1;
        }
    }
    if(retval == 1) {
        goto cleanup;
    }

    /* chop off the root so we can find the tmpdir in the chroot */
    scriptpath = scriptfn + strlen(handle->root) - 1;

    if(!grep(scriptfn, script)) {
        /* script not found in scriptlet file */
        goto cleanup;
    }

    if(oldver) {
        snprintf(cmdline, PATH_MAX, ". %s; %s %s %s",
                 scriptpath, script, ver, oldver);
    } else {
        snprintf(cmdline, PATH_MAX, ". %s; %s %s",
                 scriptpath, script, ver);
    }

    _alpm_log(handle, ALPM_LOG_DEBUG, "executing \"%s\"\n", cmdline);

    retval = _alpm_run_chroot(handle, "/bin/sh", argv);

cleanup:
    if(clean_tmpdir && _alpm_rmrf(tmpdir)) {
        _alpm_log(handle, ALPM_LOG_WARNING, _("could not remove tmpdir %s\n"), tmpdir);
    }

    return retval;
}
예제 #2
0
int _alpm_runscriptlet(const char *root, const char *installfn,
											 const char *script, const char *ver,
											 const char *oldver, pmtrans_t *trans)
{
	char scriptfn[PATH_MAX];
	char cmdline[PATH_MAX];
	char tmpdir[PATH_MAX];
	char cwd[PATH_MAX];
	char *scriptpath;
	pid_t pid;
	int clean_tmpdir = 0;
	int restore_cwd = 0;
	int retval = 0;

	ALPM_LOG_FUNC;

	if(access(installfn, R_OK)) {
		/* not found */
		_alpm_log(PM_LOG_DEBUG, "scriptlet '%s' not found\n", installfn);
		return(0);
	}

	/* NOTE: popen will use the PARENT's /bin/sh, not the chroot's */
	if(access("/bin/sh", X_OK)) {
		/* not found */
		_alpm_log(PM_LOG_ERROR, _("No /bin/sh in parent environment, aborting scriptlet\n"));
		return(0);
	}

	/* creates a directory in $root/tmp/ for copying/extracting the scriptlet */
	snprintf(tmpdir, PATH_MAX, "%stmp/", root);
	if(access(tmpdir, F_OK) != 0) {
		_alpm_makepath_mode(tmpdir, 01777);
	}
	snprintf(tmpdir, PATH_MAX, "%stmp/alpm_XXXXXX", root);
	if(mkdtemp(tmpdir) == NULL) {
		_alpm_log(PM_LOG_ERROR, _("could not create temp directory\n"));
		return(1);
	} else {
		clean_tmpdir = 1;
	}

	/* either extract or copy the scriptlet */
	snprintf(scriptfn, PATH_MAX, "%s/.INSTALL", tmpdir);
	if(!strcmp(script, "pre_upgrade") || !strcmp(script, "pre_install")) {
		if(_alpm_unpack(installfn, tmpdir, ".INSTALL")) {
			retval = 1;
		}
	} else {
		if(_alpm_copyfile(installfn, scriptfn)) {
			_alpm_log(PM_LOG_ERROR, _("could not copy tempfile to %s (%s)\n"), scriptfn, strerror(errno));
			retval = 1;
		}
	}
	if(retval == 1) {
		goto cleanup;
	}

	/* chop off the root so we can find the tmpdir in the chroot */
	scriptpath = scriptfn + strlen(root) - 1;

	if(!grep(scriptfn, script)) {
		/* script not found in scriptlet file */
		goto cleanup;
	}

	/* save the cwd so we can restore it later */
	if(getcwd(cwd, PATH_MAX) == NULL) {
		_alpm_log(PM_LOG_ERROR, _("could not get current working directory\n"));
	} else {
		restore_cwd = 1;
	}

	/* just in case our cwd was removed in the upgrade operation */
	if(chdir(root) != 0) {
		_alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), root, strerror(errno));
		goto cleanup;
	}

	_alpm_log(PM_LOG_DEBUG, "executing %s script...\n", script);

	if(oldver) {
		snprintf(cmdline, PATH_MAX, ". %s; %s %s %s",
				scriptpath, script, ver, oldver);
	} else {
		snprintf(cmdline, PATH_MAX, ". %s; %s %s",
				scriptpath, script, ver);
	}
	_alpm_log(PM_LOG_DEBUG, "%s\n", cmdline);

	/* fork- parent and child each have seperate code blocks below */
	pid = fork();
	if(pid == -1) {
		_alpm_log(PM_LOG_ERROR, _("could not fork a new process (%s)\n"), strerror(errno));
		retval = 1;
		goto cleanup;
	}

	if(pid == 0) {
		FILE *pipe;
		/* this code runs for the child only (the actual chroot/exec) */
		_alpm_log(PM_LOG_DEBUG, "chrooting in %s\n", root);
		if(chroot(root) != 0) {
			_alpm_log(PM_LOG_ERROR, _("could not change the root directory (%s)\n"),
					strerror(errno));
			exit(1);
		}
		if(chdir("/") != 0) {
			_alpm_log(PM_LOG_ERROR, _("could not change directory to / (%s)\n"),
					strerror(errno));
			exit(1);
		}
		umask(0022);
		_alpm_log(PM_LOG_DEBUG, "executing \"%s\"\n", cmdline);
		/* execl("/bin/sh", "sh", "-c", cmdline, (char *)NULL); */
		pipe = popen(cmdline, "r");
		if(!pipe) {
			_alpm_log(PM_LOG_ERROR, _("call to popen failed (%s)"),
					strerror(errno));
			exit(1);
		}
		while(!feof(pipe)) {
			char line[PATH_MAX];
			if(fgets(line, PATH_MAX, pipe) == NULL)
				break;
			alpm_logaction("%s", line);
			EVENT(trans, PM_TRANS_EVT_SCRIPTLET_INFO, line, NULL);
		}
		retval = pclose(pipe);
		exit(WEXITSTATUS(retval));
	} else {
		/* this code runs for the parent only (wait on the child) */
		pid_t retpid;
		int status;
		while((retpid = waitpid(pid, &status, 0)) == -1 && errno == EINTR);
		if(retpid == -1) {
			_alpm_log(PM_LOG_ERROR, _("call to waitpid failed (%s)\n"),
			          strerror(errno));
			retval = 1;
			goto cleanup;
		} else {
			/* check the return status, make sure it is 0 (success) */
			if(WIFEXITED(status)) {
				_alpm_log(PM_LOG_DEBUG, "call to waitpid succeeded\n");
				if(WEXITSTATUS(status) != 0) {
					_alpm_log(PM_LOG_ERROR, _("scriptlet failed to execute correctly\n"));
					retval = 1;
				}
			}
		}
	}

cleanup:
	if(clean_tmpdir && _alpm_rmrf(tmpdir)) {
		_alpm_log(PM_LOG_WARNING, _("could not remove tmpdir %s\n"), tmpdir);
	}
	if(restore_cwd) {
		chdir(cwd);
	}

	return(retval);
}