diff options
Diffstat (limited to 'init/util.c')
-rw-r--r-- | init/util.c | 248 |
1 files changed, 247 insertions, 1 deletions
diff --git a/init/util.c b/init/util.c index 0b7667d..377754b 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> @@ -32,7 +33,9 @@ #include <private/android_filesystem_config.h> -#include "init.h" +#include "log.h" +#include "list.h" +#include "util.h" static int log_fd = -1; /* Inital log level before init.rc is parsed and this this is reset. */ @@ -209,3 +212,246 @@ void list_remove(struct listnode *item) 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; +} + +int mkdir_recursive(const char *pathname, mode_t mode) +{ + char buf[128]; + const char *slash; + const char *p = pathname; + int width; + int ret; + struct stat info; + + while ((slash = strchr(p, '/')) != NULL) { + width = slash - pathname; + p = slash + 1; + if (width < 0) + break; + if (width == 0) + continue; + if ((unsigned int)width > sizeof(buf) - 1) { + ERROR("path too long for mkdir_recursive\n"); + return -1; + } + memcpy(buf, pathname, width); + buf[width] = 0; + if (stat(buf, &info) != 0) { + ret = mkdir(buf, mode); + if (ret && errno != EEXIST) + return ret; + } + } + ret = mkdir(pathname, mode); + if (ret && errno != EEXIST) + return ret; + return 0; +} + +void sanitize(char *s) +{ + if (!s) + return; + while (isalnum(*s)) + s++; + *s = 0; +} +void make_link(const char *oldpath, const char *newpath) +{ + int ret; + char buf[256]; + char *slash; + int width; + + slash = strrchr(newpath, '/'); + if (!slash) + return; + width = slash - newpath; + if (width <= 0 || width > (int)sizeof(buf) - 1) + return; + memcpy(buf, newpath, width); + buf[width] = 0; + ret = mkdir_recursive(buf, 0755); + if (ret) + ERROR("Failed to create directory %s: %s (%d)\n", buf, strerror(errno), errno); + + ret = symlink(oldpath, newpath); + if (ret && errno != EEXIST) + ERROR("Failed to symlink %s to %s: %s (%d)\n", oldpath, newpath, strerror(errno), errno); +} + +void remove_link(const char *oldpath, const char *newpath) +{ + char path[256]; + ssize_t ret; + ret = readlink(newpath, path, sizeof(path) - 1); + if (ret <= 0) + return; + path[ret] = 0; + if (!strcmp(path, oldpath)) + unlink(newpath); +} + +int wait_for_file(const char *filename, int timeout) +{ + struct stat info; + time_t timeout_time = gettime() + timeout; + int ret = -1; + + while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0)) + usleep(10000); + + return ret; +} + +void open_devnull_stdio(void) +{ + int fd; + static const char *name = "/dev/__null__"; + if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) { + fd = open(name, O_RDWR); + unlink(name); + if (fd >= 0) { + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + if (fd > 2) { + close(fd); + } + return; + } + } + + exit(1); +} + +void get_hardware_name(char *hardware, unsigned int *revision) +{ + char data[1024]; + int fd, n; + char *x, *hw, *rev; + + /* Hardware string was provided on kernel command line */ + if (hardware[0]) + return; + + fd = open("/proc/cpuinfo", O_RDONLY); + if (fd < 0) return; + + n = read(fd, data, 1023); + close(fd); + if (n < 0) return; + + data[n] = 0; + hw = strstr(data, "\nHardware"); + rev = strstr(data, "\nRevision"); + + if (hw) { + x = strstr(hw, ": "); + if (x) { + x += 2; + n = 0; + while (*x && !isspace(*x)) { + hardware[n++] = tolower(*x); + x++; + if (n == 31) break; + } + hardware[n] = 0; + } + } + + if (rev) { + x = strstr(rev, ": "); + if (x) { + *revision = strtoul(x + 2, 0, 16); + } + } +} |