am bc39871b: Merge changes I46a91849,I3a24afa2,I1df96964,Ic7a19073,I31db51eb,I11ed0f3e,I8fba9f5f,I04e8f0ae into kraken
diff --git a/init/Android.mk b/init/Android.mk
index d3766d4..3233883 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -10,7 +10,9 @@
property_service.c \
util.c \
parser.c \
- logo.c
+ logo.c \
+ keychords.c \
+ signal_handler.c
ifeq ($(strip $(INIT_BOOTCHART)),true)
LOCAL_SRC_FILES += bootchart.c
diff --git a/init/builtins.c b/init/builtins.c
index b4af700..7696954 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -35,6 +35,8 @@
#include "keywords.h"
#include "property_service.h"
#include "devices.h"
+#include "parser.h"
+#include "util.h"
#include <private/android_filesystem_config.h>
diff --git a/init/devices.c b/init/devices.c
index bde906b..a9ed141 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -40,6 +40,8 @@
#define FIRMWARE_DIR "/etc/firmware"
#define MAX_QEMU_PERM 6
+static int device_fd = -1;
+
struct uevent {
const char *action;
const char *path;
@@ -569,12 +571,12 @@
}
#define UEVENT_MSG_LEN 1024
-void handle_device_fd(int fd)
+void handle_device_fd()
{
char msg[UEVENT_MSG_LEN+2];
int n;
- while((n = recv(fd, msg, UEVENT_MSG_LEN, 0)) > 0) {
+ while((n = recv(device_fd, msg, UEVENT_MSG_LEN, 0)) > 0) {
struct uevent uevent;
if(n == UEVENT_MSG_LEN) /* overflow -- discard */
@@ -599,7 +601,7 @@
** socket's buffer.
*/
-static void do_coldboot(int event_fd, DIR *d)
+static void do_coldboot(DIR *d)
{
struct dirent *de;
int dfd, fd;
@@ -610,7 +612,7 @@
if(fd >= 0) {
write(fd, "add\n", 4);
close(fd);
- handle_device_fd(event_fd);
+ handle_device_fd();
}
while((de = readdir(d))) {
@@ -627,40 +629,42 @@
if(d2 == 0)
close(fd);
else {
- do_coldboot(event_fd, d2);
+ do_coldboot(d2);
closedir(d2);
}
}
}
-static void coldboot(int event_fd, const char *path)
+static void coldboot(const char *path)
{
DIR *d = opendir(path);
if(d) {
- do_coldboot(event_fd, d);
+ do_coldboot(d);
closedir(d);
}
}
-int device_init(void)
+void device_init(void)
{
suseconds_t t0, t1;
- int fd;
- fd = open_uevent_socket();
- if(fd < 0)
- return -1;
+ device_fd = open_uevent_socket();
+ if(device_fd < 0)
+ return;
- fcntl(fd, F_SETFD, FD_CLOEXEC);
- fcntl(fd, F_SETFL, O_NONBLOCK);
+ fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+ fcntl(device_fd, F_SETFL, O_NONBLOCK);
t0 = get_usecs();
- coldboot(fd, "/sys/class");
- coldboot(fd, "/sys/block");
- coldboot(fd, "/sys/devices");
+ coldboot("/sys/class");
+ coldboot("/sys/block");
+ coldboot("/sys/devices");
t1 = get_usecs();
log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));
+}
- return fd;
+int get_device_fd()
+{
+ return device_fd;
}
diff --git a/init/devices.h b/init/devices.h
index b484da4..e14f4c8 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -17,11 +17,11 @@
#ifndef _INIT_DEVICES_H
#define _INIT_DEVICES_H
-extern void handle_device_fd(int fd);
-extern int device_init(void);
+extern void handle_device_fd();
+extern void device_init(void);
extern void qemu_init(void);
extern void qemu_cmdline(const char* name, const char *value);
extern int add_devperms_partners(const char *name, mode_t perm, unsigned int uid,
unsigned int gid, unsigned short prefix);
-
+int get_device_fd();
#endif /* _INIT_DEVICES_H */
diff --git a/init/init.c b/init/init.c
index 65d3d84..3d619b9 100755
--- a/init/init.c
+++ b/init/init.c
@@ -25,20 +25,16 @@
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/poll.h>
-#include <time.h>
#include <errno.h>
#include <stdarg.h>
#include <mtd/mtd-user.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <sys/reboot.h>
#include <cutils/sockets.h>
#include <cutils/iosched_policy.h>
#include <termios.h>
-#include <linux/kd.h>
-#include <linux/keychord.h>
#include <sys/system_properties.h>
@@ -46,6 +42,10 @@
#include "init.h"
#include "property_service.h"
#include "bootchart.h"
+#include "signal_handler.h"
+#include "keychords.h"
+#include "parser.h"
+#include "util.h"
static int property_triggers_enabled = 0;
@@ -62,11 +62,8 @@
static char hardware[32];
static unsigned revision = 0;
static char qemu[32];
-static struct input_keychord *keychords = 0;
-static int keychords_count = 0;
-static int keychords_length = 0;
-static void notify_service_state(const char *name, const char *state)
+void notify_service_state(const char *name, const char *state)
{
char pname[PROP_NAME_MAX];
int len = strlen(name);
@@ -122,24 +119,6 @@
close(fd);
}
-/*
- * gettime() - returns the time in seconds of the system's monotonic clock or
- * zero on error.
- */
-static time_t gettime(void)
-{
- struct timespec ts;
- int ret;
-
- ret = clock_gettime(CLOCK_MONOTONIC, &ts);
- if (ret < 0) {
- ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
- return 0;
- }
-
- return ts.tv_sec;
-}
-
static void publish_socket(const char *name, int fd)
{
char key[64] = ANDROID_SOCKET_ENV_PREFIX;
@@ -328,86 +307,6 @@
}
}
-#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */
-#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery*/
-
-static int wait_for_one_process(int block)
-{
- pid_t pid;
- int status;
- struct service *svc;
- struct socketinfo *si;
- time_t now;
- struct listnode *node;
- struct command *cmd;
-
- while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );
- if (pid <= 0) return -1;
- INFO("waitpid returned pid %d, status = %08x\n", pid, status);
-
- svc = service_find_by_pid(pid);
- if (!svc) {
- ERROR("untracked pid %d exited\n", pid);
- return 0;
- }
-
- NOTICE("process '%s', pid %d exited\n", svc->name, pid);
-
- if (!(svc->flags & SVC_ONESHOT)) {
- kill(-pid, SIGKILL);
- NOTICE("process '%s' killing any children in process group\n", svc->name);
- }
-
- /* remove any sockets we may have created */
- for (si = svc->sockets; si; si = si->next) {
- char tmp[128];
- snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
- unlink(tmp);
- }
-
- svc->pid = 0;
- svc->flags &= (~SVC_RUNNING);
-
- /* oneshot processes go into the disabled state on exit */
- if (svc->flags & SVC_ONESHOT) {
- svc->flags |= SVC_DISABLED;
- }
-
- /* disabled processes do not get restarted automatically */
- if (svc->flags & SVC_DISABLED) {
- notify_service_state(svc->name, "stopped");
- return 0;
- }
-
- now = gettime();
- if (svc->flags & SVC_CRITICAL) {
- if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
- if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
- ERROR("critical process '%s' exited %d times in %d minutes; "
- "rebooting into recovery mode\n", svc->name,
- CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
- sync();
- __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
- LINUX_REBOOT_CMD_RESTART2, "recovery");
- return 0;
- }
- } else {
- svc->time_crashed = now;
- svc->nr_crashed = 1;
- }
- }
-
- svc->flags |= SVC_RESTARTING;
-
- /* Execute all onrestart commands for this service. */
- list_for_each(node, &svc->onrestart.commands) {
- cmd = node_to_item(node, struct command, clist);
- cmd->func(cmd->nargs, cmd->args);
- }
- notify_service_state(svc->name, "restarting");
- return 0;
-}
-
static void restart_service_if_needed(struct service *svc)
{
time_t next_start_time = svc->time_started + 5;
@@ -431,13 +330,6 @@
restart_service_if_needed);
}
-static int signal_fd = -1;
-
-static void sigchld_handler(int s)
-{
- write(signal_fd, &s, 1);
-}
-
static void msg_start(const char *name)
{
struct service *svc;
@@ -486,78 +378,6 @@
}
}
-#define MAX_MTD_PARTITIONS 16
-
-static struct {
- char name[16];
- int number;
-} mtd_part_map[MAX_MTD_PARTITIONS];
-
-static int mtd_part_count = -1;
-
-static void find_mtd_partitions(void)
-{
- int fd;
- char buf[1024];
- char *pmtdbufp;
- ssize_t pmtdsize;
- int r;
-
- fd = open("/proc/mtd", O_RDONLY);
- if (fd < 0)
- return;
-
- buf[sizeof(buf) - 1] = '\0';
- pmtdsize = read(fd, buf, sizeof(buf) - 1);
- pmtdbufp = buf;
- while (pmtdsize > 0) {
- int mtdnum, mtdsize, mtderasesize;
- char mtdname[16];
- mtdname[0] = '\0';
- mtdnum = -1;
- r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
- &mtdnum, &mtdsize, &mtderasesize, mtdname);
- if ((r == 4) && (mtdname[0] == '"')) {
- char *x = strchr(mtdname + 1, '"');
- if (x) {
- *x = 0;
- }
- INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
- if (mtd_part_count < MAX_MTD_PARTITIONS) {
- strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
- mtd_part_map[mtd_part_count].number = mtdnum;
- mtd_part_count++;
- } else {
- ERROR("too many mtd partitions\n");
- }
- }
- while (pmtdsize > 0 && *pmtdbufp != '\n') {
- pmtdbufp++;
- pmtdsize--;
- }
- if (pmtdsize > 0) {
- pmtdbufp++;
- pmtdsize--;
- }
- }
- close(fd);
-}
-
-int mtd_name_to_number(const char *name)
-{
- int n;
- if (mtd_part_count < 0) {
- mtd_part_count = 0;
- find_mtd_partitions();
- }
- for (n = 0; n < mtd_part_count; n++) {
- if (!strcmp(name, mtd_part_map[n].name)) {
- return mtd_part_map[n].number;
- }
- }
- return -1;
-}
-
static void import_kernel_nv(char *name, int in_qemu)
{
char *value = strchr(name, '=');
@@ -712,103 +532,8 @@
exit(1);
}
-void add_service_keycodes(struct service *svc)
-{
- struct input_keychord *keychord;
- int i, size;
-
- if (svc->keycodes) {
- /* add a new keychord to the list */
- size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]);
- keychords = realloc(keychords, keychords_length + size);
- if (!keychords) {
- ERROR("could not allocate keychords\n");
- keychords_length = 0;
- keychords_count = 0;
- return;
- }
-
- keychord = (struct input_keychord *)((char *)keychords + keychords_length);
- keychord->version = KEYCHORD_VERSION;
- keychord->id = keychords_count + 1;
- keychord->count = svc->nkeycodes;
- svc->keychord_id = keychord->id;
-
- for (i = 0; i < svc->nkeycodes; i++) {
- keychord->keycodes[i] = svc->keycodes[i];
- }
- keychords_count++;
- keychords_length += size;
- }
-}
-
-int open_keychord()
-{
- int fd, ret;
-
- service_for_each(add_service_keycodes);
-
- /* nothing to do if no services require keychords */
- if (!keychords)
- return -1;
-
- fd = open("/dev/keychord", O_RDWR);
- if (fd < 0) {
- ERROR("could not open /dev/keychord\n");
- return fd;
- }
- fcntl(fd, F_SETFD, FD_CLOEXEC);
-
- ret = write(fd, keychords, keychords_length);
- if (ret != keychords_length) {
- ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno);
- close(fd);
- fd = -1;
- }
-
- free(keychords);
- keychords = 0;
-
- return fd;
-}
-
-void handle_keychord(int fd)
-{
- struct service *svc;
- char* debuggable;
- char* adb_enabled;
- int ret;
- __u16 id;
-
- // only handle keychords if ro.debuggable is set or adb is enabled.
- // the logic here is that bugreports should be enabled in userdebug or eng builds
- // and on user builds for users that are developers.
- debuggable = property_get("ro.debuggable");
- adb_enabled = property_get("init.svc.adbd");
- if ((debuggable && !strcmp(debuggable, "1")) ||
- (adb_enabled && !strcmp(adb_enabled, "running"))) {
- ret = read(fd, &id, sizeof(id));
- if (ret != sizeof(id)) {
- ERROR("could not read keychord id\n");
- return;
- }
-
- svc = service_find_by_keychord(id);
- if (svc) {
- INFO("starting service %s from keychord\n", svc->name);
- service_start(svc, NULL);
- } else {
- ERROR("service for keychord %d not found\n", id);
- }
- }
-}
-
int main(int argc, char **argv)
{
- int device_fd = -1;
- int property_set_fd = -1;
- int signal_recv_fd = -1;
- int keychord_fd = -1;
int fd_count;
int s[2];
int fd;
@@ -818,12 +543,6 @@
char *tmpdev;
char* debuggable;
- act.sa_handler = sigchld_handler;
- act.sa_flags = SA_NOCLDSTOP;
- act.sa_mask = 0;
- act.sa_restorer = NULL;
- sigaction(SIGCHLD, &act, 0);
-
/* clear the umask */
umask(0);
@@ -866,12 +585,12 @@
drain_action_queue();
INFO("device init\n");
- device_fd = device_init();
+ device_init();
property_init();
// only listen for keychords if ro.debuggable is true
- keychord_fd = open_keychord();
+ keychord_init();
if (console[0]) {
snprintf(tmp, sizeof(tmp), "/dev/%s", console);
@@ -939,22 +658,14 @@
* after the ro.foo properties are set above so
* that /data/local.prop cannot interfere with them.
*/
- property_set_fd = start_property_service();
+ start_property_service();
- /* create a signalling mechanism for the sigchld handler */
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
- signal_fd = s[0];
- signal_recv_fd = s[1];
- fcntl(s[0], F_SETFD, FD_CLOEXEC);
- fcntl(s[0], F_SETFL, O_NONBLOCK);
- fcntl(s[1], F_SETFD, FD_CLOEXEC);
- fcntl(s[1], F_SETFL, O_NONBLOCK);
- }
+ signal_init();
/* make sure we actually have all the pieces we need */
- if ((device_fd < 0) ||
- (property_set_fd < 0) ||
- (signal_recv_fd < 0)) {
+ if ((get_device_fd() < 0) ||
+ (get_property_set_fd() < 0) ||
+ (get_signal_fd() < 0)) {
ERROR("init startup failure\n");
return 1;
}
@@ -971,16 +682,16 @@
/* enable property triggers */
property_triggers_enabled = 1;
- ufds[0].fd = device_fd;
+ ufds[0].fd = get_device_fd();
ufds[0].events = POLLIN;
- ufds[1].fd = property_set_fd;
+ ufds[1].fd = get_property_set_fd();
ufds[1].events = POLLIN;
- ufds[2].fd = signal_recv_fd;
+ ufds[2].fd = get_signal_fd();
ufds[2].events = POLLIN;
fd_count = 3;
- if (keychord_fd > 0) {
- ufds[3].fd = keychord_fd;
+ if (get_keychord_fd() > 0) {
+ ufds[3].fd = get_keychord_fd();
ufds[3].events = POLLIN;
fd_count++;
} else {
@@ -1029,20 +740,17 @@
continue;
if (ufds[2].revents == POLLIN) {
- /* we got a SIGCHLD - reap and restart as needed */
- read(signal_recv_fd, tmp, sizeof(tmp));
- while (!wait_for_one_process(0))
- ;
+ handle_signal();
continue;
}
if (ufds[0].revents == POLLIN)
- handle_device_fd(device_fd);
+ handle_device_fd();
if (ufds[1].revents == POLLIN)
- handle_property_set_fd(property_set_fd);
+ handle_property_set_fd();
if (ufds[3].revents == POLLIN)
- handle_keychord(keychord_fd);
+ handle_keychord();
}
return 0;
diff --git a/init/init.h b/init/init.h
index f92a4d7..1ebdbac 100644
--- a/init/init.h
+++ b/init/init.h
@@ -17,15 +17,8 @@
#ifndef _INIT_INIT_H
#define _INIT_INIT_H
-int mtd_name_to_number(const char *name);
-
void handle_control_message(const char *msg, const char *arg);
-int create_socket(const char *name, int type, mode_t perm,
- uid_t uid, gid_t gid);
-
-void *read_file(const char *fn, unsigned *_sz);
-
void log_init(void);
void log_set_level(int level);
void log_close(void);
@@ -39,8 +32,6 @@
#define LOG_DEFAULT_LEVEL 3 /* messages <= this level are logged */
#define LOG_UEVENTS 0 /* log uevent messages if 1. verbose */
-unsigned int decode_uid(const char *s);
-
struct listnode
{
struct listnode *next;
@@ -156,6 +147,8 @@
int parse_config_file(const char *fn);
+void notify_service_state(const char *name, const char *state);
+
struct service *service_find_by_name(const char *name);
struct service *service_find_by_pid(pid_t pid);
struct service *service_find_by_keychord(int keychord_id);
@@ -168,14 +161,6 @@
void service_start(struct service *svc, const char *dynamic_args);
void property_changed(const char *name, const char *value);
-void drain_action_queue(void);
-struct action *action_remove_queue_head(void);
-void action_add_queue_tail(struct action *act);
-void action_for_each_trigger(const char *trigger,
- void (*func)(struct action *act));
-void queue_property_triggers(const char *name, const char *value);
-void queue_all_property_triggers();
-
#define INIT_IMAGE_FILE "/initlogo.rle"
int load_565rle_image( char *file_name );
diff --git a/init/keychords.c b/init/keychords.c
new file mode 100644
index 0000000..bc286dd
--- /dev/null
+++ b/init/keychords.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/keychord.h>
+
+#include "init.h"
+#include "property_service.h"
+
+static struct input_keychord *keychords = 0;
+static int keychords_count = 0;
+static int keychords_length = 0;
+static int keychord_fd = -1;
+
+void add_service_keycodes(struct service *svc)
+{
+ struct input_keychord *keychord;
+ int i, size;
+
+ if (svc->keycodes) {
+ /* add a new keychord to the list */
+ size = sizeof(*keychord) + svc->nkeycodes * sizeof(keychord->keycodes[0]);
+ keychords = realloc(keychords, keychords_length + size);
+ if (!keychords) {
+ ERROR("could not allocate keychords\n");
+ keychords_length = 0;
+ keychords_count = 0;
+ return;
+ }
+
+ keychord = (struct input_keychord *)((char *)keychords + keychords_length);
+ keychord->version = KEYCHORD_VERSION;
+ keychord->id = keychords_count + 1;
+ keychord->count = svc->nkeycodes;
+ svc->keychord_id = keychord->id;
+
+ for (i = 0; i < svc->nkeycodes; i++) {
+ keychord->keycodes[i] = svc->keycodes[i];
+ }
+ keychords_count++;
+ keychords_length += size;
+ }
+}
+
+void keychord_init()
+{
+ int fd, ret;
+
+ service_for_each(add_service_keycodes);
+
+ /* nothing to do if no services require keychords */
+ if (!keychords)
+ return;
+
+ fd = open("/dev/keychord", O_RDWR);
+ if (fd < 0) {
+ ERROR("could not open /dev/keychord\n");
+ return;
+ }
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ ret = write(fd, keychords, keychords_length);
+ if (ret != keychords_length) {
+ ERROR("could not configure /dev/keychord %d (%d)\n", ret, errno);
+ close(fd);
+ fd = -1;
+ }
+
+ free(keychords);
+ keychords = 0;
+
+ keychord_fd = fd;
+}
+
+void handle_keychord()
+{
+ struct service *svc;
+ const char* debuggable;
+ const char* adb_enabled;
+ int ret;
+ __u16 id;
+
+ // only handle keychords if ro.debuggable is set or adb is enabled.
+ // the logic here is that bugreports should be enabled in userdebug or eng builds
+ // and on user builds for users that are developers.
+ debuggable = property_get("ro.debuggable");
+ adb_enabled = property_get("init.svc.adbd");
+ if ((debuggable && !strcmp(debuggable, "1")) ||
+ (adb_enabled && !strcmp(adb_enabled, "running"))) {
+ ret = read(keychord_fd, &id, sizeof(id));
+ if (ret != sizeof(id)) {
+ ERROR("could not read keychord id\n");
+ return;
+ }
+
+ svc = service_find_by_keychord(id);
+ if (svc) {
+ INFO("starting service %s from keychord\n", svc->name);
+ service_start(svc, NULL);
+ } else {
+ ERROR("service for keychord %d not found\n", id);
+ }
+ }
+}
+
+int get_keychord_fd()
+{
+ return keychord_fd;
+}
diff --git a/init/keychords.h b/init/keychords.h
new file mode 100644
index 0000000..070b858
--- /dev/null
+++ b/init/keychords.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_KEYCHORDS_H_
+#define _INIT_KEYCHORDS_H_
+
+struct service;
+
+void add_service_keycodes(struct service *svc);
+void keychord_init(void);
+void handle_keychord(void);
+int get_keychord_fd(void);
+
+#endif
diff --git a/init/parser.c b/init/parser.c
index 7da0d19..9424e7e 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -9,6 +9,8 @@
#include "init.h"
#include "property_service.h"
+#include "parser.h"
+#include "util.h"
#include <cutils/iosched_policy.h>
diff --git a/init/parser.h b/init/parser.h
new file mode 100644
index 0000000..cec848d
--- /dev/null
+++ b/init/parser.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PARSER_H_
+#define PARSER_H_
+
+struct action;
+
+void drain_action_queue(void);
+struct action *action_remove_queue_head(void);
+void action_add_queue_tail(struct action *act);
+void action_for_each_trigger(const char *trigger,
+ void (*func)(struct action *act));
+int action_queue_empty(void);
+void queue_property_triggers(const char *name, const char *value);
+void queue_all_property_triggers();
+
+#endif /* PARSER_H_ */
diff --git a/init/property_service.c b/init/property_service.c
index d2505dd..b1c6552 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -43,11 +43,14 @@
#include "property_service.h"
#include "init.h"
+#include "util.h"
#define PERSISTENT_PROPERTY_DIR "/data/property"
static int persistent_properties_loaded = 0;
+static int property_set_fd = -1;
+
/* White list of permissions for setting property services. */
struct {
const char *prefix;
@@ -187,7 +190,7 @@
*
* Returns 1 if uid allowed, 0 otherwise.
*/
-static int check_control_perms(const char *name, int uid, int gid) {
+static int check_control_perms(const char *name, unsigned int uid, unsigned int gid) {
int i;
if (uid == AID_SYSTEM || uid == AID_ROOT)
return 1;
@@ -208,7 +211,7 @@
* Checks permissions for setting system properties.
* Returns 1 if uid allowed, 0 otherwise.
*/
-static int check_perms(const char *name, unsigned int uid, int gid)
+static int check_perms(const char *name, unsigned int uid, unsigned int gid)
{
int i;
if (uid == 0)
@@ -344,7 +347,7 @@
return 0;
}
-void handle_property_set_fd(int fd)
+void handle_property_set_fd()
{
prop_msg msg;
int s;
@@ -355,7 +358,7 @@
socklen_t addr_size = sizeof(addr);
socklen_t cr_size = sizeof(cr);
- if ((s = accept(fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
+ if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
return;
}
@@ -493,7 +496,7 @@
load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
}
-int start_property_service(void)
+void start_property_service(void)
{
int fd;
@@ -504,10 +507,15 @@
load_persistent_properties();
fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
- if(fd < 0) return -1;
+ if(fd < 0) return;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
listen(fd, 8);
- return fd;
+ property_set_fd = fd;
+}
+
+int get_property_set_fd()
+{
+ return property_set_fd;
}
diff --git a/init/property_service.h b/init/property_service.h
index d12f1f3..5bfa46c 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -17,12 +17,12 @@
#ifndef _INIT_PROPERTY_H
#define _INIT_PROPERTY_H
-extern void handle_property_fd(int fd);
-extern void handle_property_set_fd(int fd);
+extern void handle_property_set_fd(void);
extern void property_init(void);
-extern int start_property_service(void);
+extern void start_property_service(void);
void get_property_workspace(int *fd, int *sz);
extern const char* property_get(const char *name);
extern int property_set(const char *name, const char *value);
+int get_property_set_fd(void);
#endif /* _INIT_PROPERTY_H */
diff --git a/init/signal_handler.c b/init/signal_handler.c
new file mode 100644
index 0000000..b16eef1
--- /dev/null
+++ b/init/signal_handler.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <cutils/sockets.h>
+#include <sys/reboot.h>
+
+#include "init.h"
+#include "util.h"
+
+static int signal_fd = -1;
+static int signal_recv_fd = -1;
+
+static void sigchld_handler(int s)
+{
+ write(signal_fd, &s, 1);
+}
+
+void signal_init(void)
+{
+ int s[2];
+
+ struct sigaction act;
+
+ act.sa_handler = sigchld_handler;
+ act.sa_flags = SA_NOCLDSTOP;
+ act.sa_mask = 0;
+ act.sa_restorer = NULL;
+ sigaction(SIGCHLD, &act, 0);
+
+ /* create a signalling mechanism for the sigchld handler */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
+ signal_fd = s[0];
+ signal_recv_fd = s[1];
+ fcntl(s[0], F_SETFD, FD_CLOEXEC);
+ fcntl(s[0], F_SETFL, O_NONBLOCK);
+ fcntl(s[1], F_SETFD, FD_CLOEXEC);
+ fcntl(s[1], F_SETFL, O_NONBLOCK);
+ }
+}
+
+#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */
+#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery*/
+
+static int wait_for_one_process(int block)
+{
+ pid_t pid;
+ int status;
+ struct service *svc;
+ struct socketinfo *si;
+ time_t now;
+ struct listnode *node;
+ struct command *cmd;
+
+ while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );
+ if (pid <= 0) return -1;
+ INFO("waitpid returned pid %d, status = %08x\n", pid, status);
+
+ svc = service_find_by_pid(pid);
+ if (!svc) {
+ ERROR("untracked pid %d exited\n", pid);
+ return 0;
+ }
+
+ NOTICE("process '%s', pid %d exited\n", svc->name, pid);
+
+ if (!(svc->flags & SVC_ONESHOT)) {
+ kill(-pid, SIGKILL);
+ NOTICE("process '%s' killing any children in process group\n", svc->name);
+ }
+
+ /* remove any sockets we may have created */
+ for (si = svc->sockets; si; si = si->next) {
+ char tmp[128];
+ snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
+ unlink(tmp);
+ }
+
+ svc->pid = 0;
+ svc->flags &= (~SVC_RUNNING);
+
+ /* oneshot processes go into the disabled state on exit */
+ if (svc->flags & SVC_ONESHOT) {
+ svc->flags |= SVC_DISABLED;
+ }
+
+ /* disabled processes do not get restarted automatically */
+ if (svc->flags & SVC_DISABLED) {
+ notify_service_state(svc->name, "stopped");
+ return 0;
+ }
+
+ now = gettime();
+ if (svc->flags & SVC_CRITICAL) {
+ if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
+ if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
+ ERROR("critical process '%s' exited %d times in %d minutes; "
+ "rebooting into recovery mode\n", svc->name,
+ CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
+ sync();
+ __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+ LINUX_REBOOT_CMD_RESTART2, "recovery");
+ return 0;
+ }
+ } else {
+ svc->time_crashed = now;
+ svc->nr_crashed = 1;
+ }
+ }
+
+ svc->flags |= SVC_RESTARTING;
+
+ /* Execute all onrestart commands for this service. */
+ list_for_each(node, &svc->onrestart.commands) {
+ cmd = node_to_item(node, struct command, clist);
+ cmd->func(cmd->nargs, cmd->args);
+ }
+ notify_service_state(svc->name, "restarting");
+ return 0;
+}
+
+void handle_signal(void)
+{
+ char tmp[32];
+
+ /* we got a SIGCHLD - reap and restart as needed */
+ read(signal_recv_fd, tmp, sizeof(tmp));
+ while (!wait_for_one_process(0))
+ ;
+}
+
+int get_signal_fd()
+{
+ return signal_recv_fd;
+}
diff --git a/init/signal_handler.h b/init/signal_handler.h
new file mode 100644
index 0000000..b092ccb
--- /dev/null
+++ b/init/signal_handler.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_SIGNAL_HANDLER_H_
+#define _INIT_SIGNAL_HANDLER_H_
+
+void signal_init(void);
+void handle_signal(void);
+int get_signal_fd(void);
+
+#endif
diff --git a/init/util.c b/init/util.c
index 0b7667d..6f9a12e 100644
--- a/init/util.c
+++ b/init/util.c
@@ -21,6 +21,7 @@
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
+#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -209,3 +210,92 @@
item->prev->next = item->next;
}
+#define MAX_MTD_PARTITIONS 16
+
+static struct {
+ char name[16];
+ int number;
+} mtd_part_map[MAX_MTD_PARTITIONS];
+
+static int mtd_part_count = -1;
+
+static void find_mtd_partitions(void)
+{
+ int fd;
+ char buf[1024];
+ char *pmtdbufp;
+ ssize_t pmtdsize;
+ int r;
+
+ fd = open("/proc/mtd", O_RDONLY);
+ if (fd < 0)
+ return;
+
+ buf[sizeof(buf) - 1] = '\0';
+ pmtdsize = read(fd, buf, sizeof(buf) - 1);
+ pmtdbufp = buf;
+ while (pmtdsize > 0) {
+ int mtdnum, mtdsize, mtderasesize;
+ char mtdname[16];
+ mtdname[0] = '\0';
+ mtdnum = -1;
+ r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
+ &mtdnum, &mtdsize, &mtderasesize, mtdname);
+ if ((r == 4) && (mtdname[0] == '"')) {
+ char *x = strchr(mtdname + 1, '"');
+ if (x) {
+ *x = 0;
+ }
+ INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
+ if (mtd_part_count < MAX_MTD_PARTITIONS) {
+ strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
+ mtd_part_map[mtd_part_count].number = mtdnum;
+ mtd_part_count++;
+ } else {
+ ERROR("too many mtd partitions\n");
+ }
+ }
+ while (pmtdsize > 0 && *pmtdbufp != '\n') {
+ pmtdbufp++;
+ pmtdsize--;
+ }
+ if (pmtdsize > 0) {
+ pmtdbufp++;
+ pmtdsize--;
+ }
+ }
+ close(fd);
+}
+
+int mtd_name_to_number(const char *name)
+{
+ int n;
+ if (mtd_part_count < 0) {
+ mtd_part_count = 0;
+ find_mtd_partitions();
+ }
+ for (n = 0; n < mtd_part_count; n++) {
+ if (!strcmp(name, mtd_part_map[n].name)) {
+ return mtd_part_map[n].number;
+ }
+ }
+ return -1;
+}
+
+/*
+ * gettime() - returns the time in seconds of the system's monotonic clock or
+ * zero on error.
+ */
+time_t gettime(void)
+{
+ struct timespec ts;
+ int ret;
+
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (ret < 0) {
+ ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
+ return 0;
+ }
+
+ return ts.tv_sec;
+}
diff --git a/init/util.h b/init/util.h
new file mode 100644
index 0000000..4f473ec
--- /dev/null
+++ b/init/util.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_UTIL_H_
+#define _INIT_UTIL_H_
+
+int mtd_name_to_number(const char *name);
+int create_socket(const char *name, int type, mode_t perm,
+ uid_t uid, gid_t gid);
+void *read_file(const char *fn, unsigned *_sz);
+time_t gettime(void);
+unsigned int decode_uid(const char *s);
+
+#endif