summaryrefslogtreecommitdiffstats
path: root/arch/sandbox/os/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sandbox/os/common.c')
-rw-r--r--arch/sandbox/os/common.c254
1 files changed, 215 insertions, 39 deletions
diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c
index 3f9cc70770..3446074f99 100644
--- a/arch/sandbox/os/common.c
+++ b/arch/sandbox/os/common.c
@@ -4,9 +4,6 @@
*
* Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
@@ -22,6 +19,7 @@
* These are host includes. Never include any barebox header
* files here...
*/
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -41,12 +39,17 @@
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
+#include <sys/time.h>
/*
* ...except the ones needed to connect with barebox
*/
#include <mach/linux.h>
#include <mach/hostfile.h>
+#define DELETED_OFFSET (sizeof(" (deleted)") - 1)
+
+void __sanitizer_set_death_callback(void (*callback)(void));
+
int sdl_xres;
int sdl_yres;
@@ -72,6 +75,15 @@ static void cookmode(void)
tcsetattr(0, TCSANOW, &term_orig);
}
+static char *stickypage_path;
+
+static void prepare_exit(void)
+{
+ cookmode();
+ if (stickypage_path)
+ remove(stickypage_path);
+}
+
int linux_tstc(int fd)
{
struct timeval tv = {
@@ -119,13 +131,58 @@ uint64_t linux_get_time(void)
void __attribute__((noreturn)) linux_exit(void)
{
- cookmode();
+ prepare_exit();
exit(0);
}
+static char **saved_argv;
+
+static int selfpath(char *buf, size_t len)
+{
+ int ret;
+
+ /* we must follow the symlink, so we can exec an updated executable */
+ ret = readlink("/proc/self/exe", buf, len - 1);
+ if (ret < 0)
+ return ret;
+
+ if (0 < ret && ret < len - 1)
+ buf[ret] = '\0';
+
+ return ret;
+}
+
+void linux_reexec(void)
+{
+ char buf[4097];
+ ssize_t ret;
+
+ cookmode();
+
+ /* we must follow the symlink, so we can exec an updated executable */
+ ret = selfpath(buf, sizeof(buf));
+ if (ret > 0) {
+ execv(buf, saved_argv);
+ if (!strcmp(&buf[ret - DELETED_OFFSET], " (deleted)")) {
+ printf("barebox image on disk changed. Loading new.\n");
+ buf[ret - DELETED_OFFSET] = '\0';
+ execv(buf, saved_argv);
+ }
+ }
+
+ printf("exec(%s) failed: %d\n", buf, errno);
+ /* falls through to generic hang() */
+}
+
+void linux_hang(void)
+{
+ prepare_exit();
+ /* falls through to generic hang() */
+}
+
int linux_open(const char *filename, int readwrite)
{
- return open(filename, readwrite ? O_RDWR : O_RDONLY);
+ return open(filename, (readwrite ? O_RDWR : O_RDONLY) | O_CLOEXEC);
}
int linux_read(int fd, void *buf, size_t count)
@@ -184,7 +241,7 @@ ssize_t linux_write(int fd, const void *buf, size_t count)
return write(fd, buf, count);
}
-off_t linux_lseek(int fd, off_t offset)
+loff_t linux_lseek(int fd, loff_t offset)
{
return lseek(fd, offset, SEEK_SET);
}
@@ -210,45 +267,147 @@ int linux_execve(const char * filename, char *const argv[], char *const envp[])
}
}
+static void linux_watchdog(int signo)
+{
+ linux_reexec();
+ _exit(0);
+}
+
+int linux_watchdog_set_timeout(unsigned int timeout)
+{
+ static int signal_handler_installed;
+
+ if (!signal_handler_installed) {
+ struct sigaction sact = {
+ .sa_flags = SA_NODEFER, .sa_handler = linux_watchdog
+ };
+
+ sigemptyset(&sact.sa_mask);
+ sigaction(SIGALRM, &sact, NULL);
+ signal_handler_installed = 1;
+ }
+
+ return alarm(timeout);
+}
+
extern void start_barebox(void);
extern void mem_malloc_init(void *start, void *end);
-static int add_image(char *str, char *devname_template, int *devname_number)
+extern char * strsep_unescaped(char **s, const char *ct);
+
+static int add_image(const char *_str, char *devname_template, int *devname_number)
{
- struct hf_info *hf = malloc(sizeof(struct hf_info));
- char *filename, *devname;
+ struct hf_info *hf = calloc(1, sizeof(struct hf_info));
+ char *str, *filename, *devname;
char tmp[16];
- int readonly = 0;
- struct stat s;
char *opt;
- int fd, ret;
+ int ret;
if (!hf)
return -1;
- filename = strtok(str, ",");
- while ((opt = strtok(NULL, ","))) {
+ str = strdup(_str);
+
+ filename = strsep_unescaped(&str, ",");
+ while ((opt = strsep_unescaped(&str, ","))) {
if (!strcmp(opt, "ro"))
- readonly = 1;
+ hf->is_readonly = 1;
+ if (!strcmp(opt, "cdev"))
+ hf->is_cdev = 1;
+ if (!strcmp(opt, "blkdev"))
+ hf->is_blockdev = 1;
}
/* parses: "devname=filename" */
- devname = strtok(filename, "=");
- filename = strtok(NULL, "=");
+ devname = strsep_unescaped(&filename, "=");
+ filename = strsep_unescaped(&filename, "=");
if (!filename) {
filename = devname;
snprintf(tmp, sizeof(tmp),
devname_template, (*devname_number)++);
- devname = strdup(tmp);
+ devname = tmp;
}
- printf("add %s backed by file %s%s\n", devname,
- filename, readonly ? "(ro)" : "");
-
- fd = open(filename, readonly ? O_RDONLY : O_RDWR);
- hf->fd = fd;
hf->filename = filename;
+ hf->devname = strdup(devname);
+ ret = barebox_register_filedev(hf);
+ if (ret)
+ free(hf);
+
+ return ret;
+}
+
+extern uint8_t stickypage[4096];
+
+char *linux_get_stickypage_path(void)
+{
+ size_t nwritten;
+ ssize_t ret;
+ int fd;
+
+ ret = asprintf(&stickypage_path, "%s/barebox/stickypage.%lu",
+ getenv("XDG_RUNTIME_DIR") ?: "/run", (long)getpid());
+ if (ret < 0)
+ goto err_asprintf;
+
+ ret = mkdir(dirname(stickypage_path), 0755);
+ if (ret < 0 && errno != EEXIST) {
+ perror("mkdir");
+ goto err_creat;
+ }
+
+ stickypage_path[strlen(stickypage_path)] = '/';
+
+ fd = open(stickypage_path, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0644);
+ if (fd < 0) {
+ if (errno == EEXIST)
+ return stickypage_path;
+
+ perror("open");
+ goto err_creat;
+ }
+
+ for (nwritten = 0; nwritten < sizeof(stickypage); ) {
+ ret = write(fd, &stickypage[nwritten], sizeof(stickypage) - nwritten);
+ if (ret < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ perror("write");
+ goto err_write;
+ }
+
+ nwritten += ret;
+ }
+
+ close(fd);
+
+ return stickypage_path;
+
+err_write:
+ close(fd);
+err_creat:
+ free(stickypage_path);
+err_asprintf:
+ stickypage_path = NULL;
+
+ return NULL;
+}
+
+int linux_open_hostfile(struct hf_info *hf)
+{
+ char *buf = NULL;
+ struct stat s;
+ int fd = -1;
+
+ printf("add %s %sbacked by file %s%s\n", hf->devname,
+ hf->filename ? "" : "initially un", hf->filename ?: "",
+ hf->is_readonly ? "(ro)" : "");
+
+ if (!hf->filename)
+ return -ENOENT;
+
+ fd = hf->fd = open(hf->filename, (hf->is_readonly ? O_RDONLY : O_RDWR) | O_CLOEXEC);
if (fd < 0) {
perror("open");
goto err_out;
@@ -259,30 +418,41 @@ static int add_image(char *str, char *devname_template, int *devname_number)
goto err_out;
}
+ hf->base = (unsigned long)MAP_FAILED;
hf->size = s.st_size;
- hf->devname = strdup(devname);
if (S_ISBLK(s.st_mode)) {
if (ioctl(fd, BLKGETSIZE64, &hf->size) == -1) {
perror("ioctl");
goto err_out;
}
+ if (!hf->is_cdev)
+ hf->is_blockdev = 1;
+ }
+ if (hf->size <= SIZE_MAX) {
+ hf->base = (unsigned long)mmap(NULL, hf->size,
+ PROT_READ | (hf->is_readonly ? 0 : PROT_WRITE),
+ MAP_SHARED, fd, 0);
+
+ if (hf->base == (unsigned long)MAP_FAILED)
+ printf("warning: mmapping %s failed: %s\n",
+ hf->filename, strerror(errno));
+ } else {
+ printf("warning: %s: contiguous map failed\n", hf->filename);
+ }
+
+ if (hf->is_blockdev && hf->size % 512 != 0) {
+ printf("warning: registering %s as block device failed: invalid block size\n",
+ hf->filename);
+ return -EINVAL;
}
- hf->base = (unsigned long)mmap(NULL, hf->size,
- PROT_READ | (readonly ? 0 : PROT_WRITE),
- MAP_SHARED, fd, 0);
- if ((void *)hf->base == MAP_FAILED)
- printf("warning: mmapping %s failed: %s\n", filename, strerror(errno));
- ret = barebox_register_filedev(hf);
- if (ret)
- goto err_out;
return 0;
err_out:
- if (fd > 0)
+ if (fd >= 0)
close(fd);
- free(hf);
+ free(buf);
return -1;
}
@@ -292,7 +462,7 @@ static int add_dtb(const char *file)
void *dtb = NULL;
int fd;
- fd = open(file, O_RDONLY);
+ fd = open(file, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
perror("open");
goto err_out;
@@ -348,6 +518,10 @@ int main(int argc, char *argv[])
int fdno = 0, envno = 0, option_index = 0;
char *aux;
+#ifdef CONFIG_ASAN
+ __sanitizer_set_death_callback(prepare_exit);
+#endif
+
while (1) {
option_index = 0;
opt = getopt_long(argc, argv, optstring,
@@ -385,6 +559,8 @@ int main(int argc, char *argv[])
}
}
+ saved_argv = argv;
+
ram = malloc(malloc_size);
if (!ram) {
printf("unable to get malloc space\n");
@@ -419,7 +595,7 @@ int main(int argc, char *argv[])
exit(1);
break;
case 'O':
- fd = open(optarg, O_WRONLY);
+ fd = open(optarg, O_WRONLY | O_CLOEXEC);
if (fd < 0) {
perror("open");
exit(1);
@@ -428,7 +604,7 @@ int main(int argc, char *argv[])
barebox_register_console(-1, fd);
break;
case 'I':
- fd = open(optarg, O_RDWR);
+ fd = open(optarg, O_RDWR | O_CLOEXEC);
if (fd < 0) {
perror("open");
exit(1);
@@ -444,7 +620,7 @@ int main(int argc, char *argv[])
}
/* open stdout file */
- fd = open(aux + 1, O_WRONLY);
+ fd = open(aux + 1, O_WRONLY | O_CLOEXEC);
if (fd < 0) {
perror("open stdout");
exit(1);
@@ -452,7 +628,7 @@ int main(int argc, char *argv[])
/* open stdin file */
aux = strndup(optarg, aux - optarg);
- fd2 = open(aux, O_RDWR);
+ fd2 = open(aux, O_RDWR | O_CLOEXEC);
if (fd2 < 0) {
perror("open stdin");
exit(1);