| /* |
| * Copyright (c) 2014 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <limits.h> |
| #include <pwd.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/file.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| |
| #include "util.h" |
| |
| static int daemon_pipe[2] = { -1, -1 }; |
| |
| static int openfd(char *path, int flags, int reqfd) |
| { |
| int fd = open(path, flags); |
| if (fd < 0) |
| return -1; |
| |
| if (fd == reqfd) |
| return reqfd; |
| |
| if (dup2(fd, reqfd) >= 0) { |
| close(fd); |
| return reqfd; |
| } |
| |
| close(fd); |
| return -1; |
| } |
| |
| static int init_daemon_stdio(void) |
| { |
| close(STDIN_FILENO); |
| close(STDOUT_FILENO); |
| close(STDERR_FILENO); |
| |
| if (openfd("/dev/null", O_RDONLY, STDIN_FILENO) < 0) |
| return -1; |
| |
| if (openfd("/dev/kmsg", O_WRONLY, STDOUT_FILENO) < 0) |
| return -1; |
| |
| if (openfd("/dev/kmsg", O_WRONLY, STDERR_FILENO) < 0) |
| return -1; |
| |
| return 0; |
| } |
| |
| void daemonize(bool wait_child) |
| { |
| pid_t pid; |
| |
| if (wait_child) |
| if (pipe(daemon_pipe) < 0) |
| exit(EXIT_FAILURE); |
| |
| pid = fork(); |
| if (pid == -1) |
| return; |
| else if (pid != 0) { |
| if (wait_child) { |
| char code = EXIT_FAILURE; |
| close(daemon_pipe[1]); |
| if (read(daemon_pipe[0], &code, sizeof(code)) < 0) { |
| int c; |
| /* Child has died? */ |
| if (errno == EPIPE) |
| if (waitpid(pid, &c, 0) >= 0) |
| exit(c); /* Propagate child exit code. */ |
| /* Just report failure. */ |
| exit(EXIT_FAILURE); |
| } |
| exit(code); |
| } |
| exit(EXIT_SUCCESS); |
| } |
| |
| if (wait_child) |
| close(daemon_pipe[0]); |
| if (setsid() == -1) |
| return; |
| |
| init_daemon_stdio(); |
| } |
| |
| void daemon_exit_code(char code) |
| { |
| if (write(daemon_pipe[1], &code, sizeof(code)) != sizeof(code)) { |
| LOG(ERROR, "failed to report exit code back to daemon parent"); |
| } |
| close(daemon_pipe[1]); |
| } |
| |
| static int is_valid_fd(int fd) |
| { |
| return fcntl(fd, F_GETFL) != -1 || errno != EBADF; |
| } |
| |
| void fix_stdio(void) |
| { |
| if (!is_valid_fd(STDIN_FILENO) |
| || !is_valid_fd(STDOUT_FILENO) |
| || !is_valid_fd(STDERR_FILENO)) |
| init_daemon_stdio(); |
| } |
| |
| void parse_location(char* loc_str, int* x, int* y) |
| { |
| int count = 0; |
| char* savedptr; |
| char* str; |
| int* results[] = {x, y}; |
| long tmp; |
| |
| for (char* token = str = loc_str; token != NULL; str = NULL) { |
| if (count > 1) |
| break; |
| |
| token = strtok_r(str, ",", &savedptr); |
| if (token) { |
| tmp = MIN(INT_MAX, strtol(token, NULL, 0)); |
| *(results[count++]) = (int)tmp; |
| } |
| } |
| } |
| |
| void parse_filespec(char* filespec, char* filename, |
| int32_t* offset_x, int32_t* offset_y, uint32_t* duration, |
| uint32_t default_duration, |
| int32_t default_x, int32_t default_y) |
| { |
| char* saved_ptr; |
| char* token; |
| |
| // defaults |
| *offset_x = default_x; |
| *offset_y = default_y; |
| *duration = default_duration; |
| |
| token = filespec; |
| token = strtok_r(token, ":", &saved_ptr); |
| if (token) |
| strcpy(filename, token); |
| |
| token = strtok_r(NULL, ":", &saved_ptr); |
| if (token) { |
| *duration = strtoul(token, NULL, 0); |
| token = strtok_r(NULL, ",", &saved_ptr); |
| if (token) { |
| token = strtok_r(token, ",", &saved_ptr); |
| if (token) { |
| *offset_x = strtol(token, NULL, 0); |
| token = strtok_r(token, ",", &saved_ptr); |
| if (token) |
| *offset_y = strtol(token, NULL, 0); |
| } |
| } |
| } |
| } |
| |
| void parse_image_option(char* optionstr, char** name, char** val) |
| { |
| char** result[2] = { name, val }; |
| int count = 0; |
| char* str; |
| char* savedptr; |
| |
| for (char* token = str = optionstr; token != NULL; str = NULL) { |
| if (count > 1) |
| break; |
| |
| token = strtok_r(str, ":", &savedptr); |
| if (token) { |
| *(result[count]) = malloc(strlen(token) + 1); |
| strcpy(*(result[count]), token); |
| count++; |
| } |
| } |
| } |
| |
| bool write_string_to_file(const char *path, const char *s) |
| { |
| int fd; |
| size_t towrite; |
| ssize_t written; |
| |
| fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); |
| if (!fd) |
| return false; |
| |
| towrite = strlen(s); |
| written = write(fd, s, towrite); |
| close(fd); |
| |
| if (written != (ssize_t)towrite) { |
| LOG(ERROR, "Failed to write string%s to %s", s, path); |
| unlink(path); |
| return false; |
| } |
| return true; |
| } |