Merge "Clean up init /proc/cmdline handling."

This commit is contained in:
Elliott Hughes 2015-05-07 18:04:24 +00:00 committed by Gerrit Code Review
commit 55c2e1f4ba
6 changed files with 69 additions and 106 deletions

View file

@ -43,6 +43,7 @@
#include <base/file.h>
#include <base/stringprintf.h>
#include <base/strings.h>
#include <cutils/android_reboot.h>
#include <cutils/fs.h>
#include <cutils/iosched_policy.h>
@ -205,16 +206,15 @@ void service_start(struct service *svc, const char *dynamic_args)
return;
}
struct stat s;
if (stat(svc->args[0], &s) != 0) {
ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
struct stat sb;
if (stat(svc->args[0], &sb) == -1) {
ERROR("cannot find '%s' (%s), disabling '%s'\n", svc->args[0], strerror(errno), svc->name);
svc->flags |= SVC_DISABLED;
return;
}
if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
svc->args[0]);
ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", svc->args[0]);
svc->flags |= SVC_DISABLED;
return;
}
@ -746,36 +746,20 @@ static int console_init_action(int nargs, char **args)
return 0;
}
static void import_kernel_nv(char *name, bool for_emulator)
{
char *value = strchr(name, '=');
int name_len = strlen(name);
if (value == 0) return;
*value++ = 0;
if (name_len == 0) return;
static void import_kernel_nv(const std::string& key, const std::string& value, bool for_emulator) {
if (key.empty()) return;
if (for_emulator) {
/* in the emulator, export any kernel option with the
* ro.kernel. prefix */
char buff[PROP_NAME_MAX];
int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );
if (len < (int)sizeof(buff))
property_set( buff, value );
// In the emulator, export any kernel option with the "ro.kernel." prefix.
property_set(android::base::StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());
return;
}
if (!strcmp(name,"qemu")) {
strlcpy(qemu, value, sizeof(qemu));
} else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {
const char *boot_prop_name = name + 12;
char prop[PROP_NAME_MAX];
int cnt;
cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);
if (cnt < PROP_NAME_MAX)
property_set(prop, value);
if (key == "qemu") {
strlcpy(qemu, value.c_str(), sizeof(qemu));
} else if (android::base::StartsWith(key, "androidboot.")) {
property_set(android::base::StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(),
value.c_str());
}
}
@ -799,8 +783,7 @@ static void export_kernel_boot_props() {
}
}
static void process_kernel_dt(void)
{
static void process_kernel_dt() {
static const char android_dir[] = "/proc/device-tree/firmware/android";
std::string file_name = android::base::StringPrintf("%s/compatible", android_dir);
@ -813,13 +796,13 @@ static void process_kernel_dt(void)
}
std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
if (!dir)
return;
if (!dir) return;
struct dirent *dp;
while ((dp = readdir(dir.get())) != NULL) {
if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible"))
if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible")) {
continue;
}
file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name);
@ -831,18 +814,15 @@ static void process_kernel_dt(void)
}
}
static void process_kernel_cmdline(void)
{
/* don't expose the raw commandline to nonpriv processes */
static void process_kernel_cmdline() {
// Don't expose the raw commandline to unprivileged processes.
chmod("/proc/cmdline", 0440);
/* first pass does the common stuff, and finds if we are in qemu.
* second pass is only necessary for qemu to export all kernel params
* as props.
*/
// The first pass does the common stuff, and finds if we are in qemu.
// The second pass is only necessary for qemu to export all kernel params
// as properties.
import_kernel_cmdline(false, import_kernel_nv);
if (qemu[0])
import_kernel_cmdline(true, import_kernel_nv);
if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);
}
static int queue_property_triggers_action(int nargs, char **args)
@ -865,17 +845,11 @@ enum selinux_enforcing_status { SELINUX_PERMISSIVE, SELINUX_ENFORCING };
static selinux_enforcing_status selinux_status_from_cmdline() {
selinux_enforcing_status status = SELINUX_ENFORCING;
std::function<void(char*,bool)> fn = [&](char* name, bool in_qemu) {
char *value = strchr(name, '=');
if (value == nullptr) { return; }
*value++ = '\0';
if (strcmp(name, "androidboot.selinux") == 0) {
if (strcmp(value, "permissive") == 0) {
status = SELINUX_PERMISSIVE;
}
import_kernel_cmdline(false, [&](const std::string& key, const std::string& value, bool in_qemu) {
if (key == "androidboot.selinux" && value == "permissive") {
status = SELINUX_PERMISSIVE;
}
};
import_kernel_cmdline(false, fn);
});
return status;
}
@ -989,7 +963,7 @@ int main(int argc, char** argv) {
klog_init();
klog_set_level(KLOG_NOTICE_LEVEL);
NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");
NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");
if (!is_first_stage) {
// Indicate that booting is in progress to background fw loaders, etc.
@ -1002,7 +976,7 @@ int main(int argc, char** argv) {
process_kernel_dt();
process_kernel_cmdline();
// Propogate the kernel variables to internal variables
// Propagate the kernel variables to internal variables
// used by init as well as the current required properties.
export_kernel_boot_props();
}
@ -1028,7 +1002,7 @@ int main(int argc, char** argv) {
// These directories were necessarily created before initial policy load
// and therefore need their security context restored to the proper value.
// This must happen before /dev is populated by ueventd.
INFO("Running restorecon...\n");
NOTICE("Running restorecon...\n");
restorecon("/dev");
restorecon("/dev/socket");
restorecon("/dev/__properties__");

View file

@ -426,29 +426,27 @@ static void parse_config(const char *fn, const std::string& data)
parser_done:
list_for_each(node, &import_list) {
struct import *import = node_to_item(node, struct import, list);
int ret;
ret = init_parse_config_file(import->filename);
if (ret)
ERROR("could not import file '%s' from '%s'\n",
import->filename, fn);
struct import* import = node_to_item(node, struct import, list);
if (!init_parse_config_file(import->filename)) {
ERROR("could not import file '%s' from '%s': %s\n",
import->filename, fn, strerror(errno));
}
}
}
int init_parse_config_file(const char* path) {
bool init_parse_config_file(const char* path) {
INFO("Parsing %s...\n", path);
Timer t;
std::string data;
if (!read_file(path, &data)) {
return -1;
return false;
}
parse_config(path, data);
dump_parser_state();
NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration());
return 0;
return true;
}
static int valid_name(const char *name)

View file

@ -31,7 +31,7 @@ void queue_property_triggers(const char *name, const char *value);
void queue_all_property_triggers();
void queue_builtin_action(int (*func)(int nargs, char **args), const char *name);
int init_parse_config_file(const char *fn);
bool init_parse_config_file(const char* path);
int expand_props(char *dst, const char *src, int len);
service* make_exec_oneshot_service(int argc, char** argv);

View file

@ -14,30 +14,35 @@
* limitations under the License.
*/
#include "log.h"
#include <stdlib.h>
#include <string.h>
#include <sys/uio.h>
#include <selinux/selinux.h>
#include "log.h"
#include <base/stringprintf.h>
static void init_klog_vwrite(int level, const char* fmt, va_list ap) {
static const char* tag = basename(getprogname());
char prefix[64];
snprintf(prefix, sizeof(prefix), "<%d>%s: ", level, tag);
// The kernel's printk buffer is only 1024 bytes.
// TODO: should we automatically break up long lines into multiple lines?
// Or we could log but with something like "..." at the end?
char buf[1024];
size_t prefix_size = snprintf(buf, sizeof(buf), "<%d>%s: ", level, tag);
size_t msg_size = vsnprintf(buf + prefix_size, sizeof(buf) - prefix_size, fmt, ap);
if (msg_size >= sizeof(buf) - prefix_size) {
msg_size = snprintf(buf + prefix_size, sizeof(buf) - prefix_size,
"(%zu-byte message too long for printk)\n", msg_size);
}
char msg[512];
vsnprintf(msg, sizeof(msg), fmt, ap);
iovec iov[1];
iov[0].iov_base = buf;
iov[0].iov_len = prefix_size + msg_size;
iovec iov[2];
iov[0].iov_base = prefix;
iov[0].iov_len = strlen(prefix);
iov[1].iov_base = msg;
iov[1].iov_len = strlen(msg);
klog_writev(level, iov, 2);
klog_writev(level, iov, 1);
}
void init_klog_write(int level, const char* fmt, ...) {

View file

@ -33,6 +33,7 @@
#include <sys/un.h>
#include <base/file.h>
#include <base/strings.h>
/* for ANDROID_SOCKET_* */
#include <cutils/sockets.h>
@ -403,32 +404,16 @@ void open_devnull_stdio(void)
}
}
void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)> import_kernel_nv)
{
char cmdline[2048];
char *ptr;
int fd;
void import_kernel_cmdline(bool in_qemu,
std::function<void(const std::string&, const std::string&, bool)> fn) {
std::string cmdline;
android::base::ReadFileToString("/proc/cmdline", &cmdline);
fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
int n = read(fd, cmdline, sizeof(cmdline) - 1);
if (n < 0) n = 0;
/* get rid of trailing newline, it happens */
if (n > 0 && cmdline[n-1] == '\n') n--;
cmdline[n] = 0;
close(fd);
} else {
cmdline[0] = 0;
}
ptr = cmdline;
while (ptr && *ptr) {
char *x = strchr(ptr, ' ');
if (x != 0) *x++ = 0;
import_kernel_nv(ptr, in_qemu);
ptr = x;
for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
std::vector<std::string> pieces = android::base::Split(entry, "=");
if (pieces.size() == 2) {
fn(pieces[0], pieces[1], in_qemu);
}
}
}

View file

@ -58,7 +58,8 @@ void make_link(const char *oldpath, const char *newpath);
void remove_link(const char *oldpath, const char *newpath);
int wait_for_file(const char *filename, int timeout);
void open_devnull_stdio(void);
void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)>);
void import_kernel_cmdline(bool in_qemu,
std::function<void(const std::string&, const std::string&, bool)>);
int make_dir(const char *path, mode_t mode);
int restorecon(const char *pathname);
int restorecon_recursive(const char *pathname);