David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2014 The Chromium OS Authors. All rights reserved. |
| 3 | * Use of this source code is governed by a BSD-style license that can be |
| 4 | * found in the LICENSE file. |
| 5 | */ |
| 6 | |
Dominik Behr | 2b9f123 | 2016-08-02 01:11:12 -0700 | [diff] [blame] | 7 | #include <errno.h> |
David Sodman | 8ef2006 | 2015-01-06 09:23:40 -0800 | [diff] [blame] | 8 | #include <fcntl.h> |
| 9 | #include <limits.h> |
| 10 | #include <pwd.h> |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 11 | #include <stdio.h> |
| 12 | #include <stdlib.h> |
David Sodman | e46ea8a | 2015-03-13 15:47:12 -0700 | [diff] [blame] | 13 | #include <string.h> |
Daniel Nicoara | 76622c3 | 2015-03-18 17:47:54 -0400 | [diff] [blame] | 14 | #include <sys/file.h> |
David Sodman | ef1ba36 | 2015-03-16 10:50:24 -0700 | [diff] [blame] | 15 | #include <sys/stat.h> |
Dominik Behr | 09f2b72 | 2016-10-05 12:02:04 -0700 | [diff] [blame^] | 16 | #include <sys/types.h> |
| 17 | #include <sys/wait.h> |
David Sodman | 8ef2006 | 2015-01-06 09:23:40 -0800 | [diff] [blame] | 18 | #include <unistd.h> |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 19 | |
David Sodman | e46ea8a | 2015-03-13 15:47:12 -0700 | [diff] [blame] | 20 | #include "util.h" |
| 21 | |
Dominik Behr | 09f2b72 | 2016-10-05 12:02:04 -0700 | [diff] [blame^] | 22 | static int daemon_pipe[2] = { -1, -1 }; |
| 23 | |
Dominik Behr | 2b9f123 | 2016-08-02 01:11:12 -0700 | [diff] [blame] | 24 | static int openfd(char *path, int flags, int reqfd) |
| 25 | { |
| 26 | int fd = open(path, flags); |
| 27 | if (fd < 0) |
| 28 | return -1; |
| 29 | |
| 30 | if (fd == reqfd) |
| 31 | return reqfd; |
| 32 | |
| 33 | if (dup2(fd, reqfd) >= 0) { |
| 34 | close(fd); |
| 35 | return reqfd; |
| 36 | } |
| 37 | |
| 38 | close(fd); |
| 39 | return -1; |
| 40 | } |
| 41 | |
| 42 | static int init_daemon_stdio(void) |
| 43 | { |
| 44 | close(STDIN_FILENO); |
| 45 | close(STDOUT_FILENO); |
| 46 | close(STDERR_FILENO); |
| 47 | |
| 48 | if (openfd("/dev/null", O_RDONLY, STDIN_FILENO) < 0) |
| 49 | return -1; |
| 50 | |
| 51 | if (openfd("/dev/kmsg", O_WRONLY, STDOUT_FILENO) < 0) |
| 52 | return -1; |
| 53 | |
| 54 | if (openfd("/dev/kmsg", O_WRONLY, STDERR_FILENO) < 0) |
| 55 | return -1; |
| 56 | |
| 57 | return 0; |
| 58 | } |
| 59 | |
Dominik Behr | 09f2b72 | 2016-10-05 12:02:04 -0700 | [diff] [blame^] | 60 | void daemonize(bool wait_child) |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 61 | { |
| 62 | pid_t pid; |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 63 | |
Dominik Behr | 09f2b72 | 2016-10-05 12:02:04 -0700 | [diff] [blame^] | 64 | if (wait_child) |
| 65 | if (pipe(daemon_pipe) < 0) |
| 66 | exit(EXIT_FAILURE); |
| 67 | |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 68 | pid = fork(); |
| 69 | if (pid == -1) |
| 70 | return; |
Dominik Behr | 09f2b72 | 2016-10-05 12:02:04 -0700 | [diff] [blame^] | 71 | else if (pid != 0) { |
| 72 | if (wait_child) { |
| 73 | char code = EXIT_FAILURE; |
| 74 | close(daemon_pipe[1]); |
| 75 | if (read(daemon_pipe[0], &code, sizeof(code)) < 0) { |
| 76 | int c; |
| 77 | /* Child has died? */ |
| 78 | if (errno == EPIPE) |
| 79 | if (waitpid(pid, &c, 0) >= 0) |
| 80 | exit(c); /* Propagate child exit code. */ |
| 81 | /* Just report failure. */ |
| 82 | exit(EXIT_FAILURE); |
| 83 | } |
| 84 | exit(code); |
| 85 | } |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 86 | exit(EXIT_SUCCESS); |
Dominik Behr | 09f2b72 | 2016-10-05 12:02:04 -0700 | [diff] [blame^] | 87 | } |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 88 | |
Dominik Behr | 09f2b72 | 2016-10-05 12:02:04 -0700 | [diff] [blame^] | 89 | if (wait_child) |
| 90 | close(daemon_pipe[0]); |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 91 | if (setsid() == -1) |
| 92 | return; |
| 93 | |
Dominik Behr | 2b9f123 | 2016-08-02 01:11:12 -0700 | [diff] [blame] | 94 | init_daemon_stdio(); |
| 95 | } |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 96 | |
Dominik Behr | 09f2b72 | 2016-10-05 12:02:04 -0700 | [diff] [blame^] | 97 | void daemon_exit_code(char code) |
| 98 | { |
| 99 | if (write(daemon_pipe[1], &code, sizeof(code)) != sizeof(code)) { |
| 100 | LOG(ERROR, "failed to report exit code back to daemon parent"); |
| 101 | } |
| 102 | close(daemon_pipe[1]); |
| 103 | } |
| 104 | |
Dominik Behr | 2b9f123 | 2016-08-02 01:11:12 -0700 | [diff] [blame] | 105 | static int is_valid_fd(int fd) |
| 106 | { |
| 107 | return fcntl(fd, F_GETFL) != -1 || errno != EBADF; |
| 108 | } |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 109 | |
Dominik Behr | 2b9f123 | 2016-08-02 01:11:12 -0700 | [diff] [blame] | 110 | void fix_stdio(void) |
| 111 | { |
| 112 | if (!is_valid_fd(STDIN_FILENO) |
| 113 | || !is_valid_fd(STDOUT_FILENO) |
| 114 | || !is_valid_fd(STDERR_FILENO)) |
| 115 | init_daemon_stdio(); |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 116 | } |
| 117 | |
| 118 | #ifdef __clang__ |
| 119 | __attribute__((format (__printf__, 2, 0))) |
| 120 | #endif |
| 121 | void LOG(int severity, const char* fmt, ...) |
| 122 | { |
| 123 | va_list arg_list; |
Dominik Behr | b1abcba | 2016-04-14 14:57:21 -0700 | [diff] [blame] | 124 | fprintf(stderr, "frecon(%d): ", getpid()); |
David Sodman | bbcb052 | 2014-09-19 10:34:07 -0700 | [diff] [blame] | 125 | va_start( arg_list, fmt); |
| 126 | vfprintf(stderr, fmt, arg_list); |
| 127 | va_end(arg_list); |
| 128 | fprintf(stderr, "\n"); |
| 129 | } |
David Sodman | 8ef2006 | 2015-01-06 09:23:40 -0800 | [diff] [blame] | 130 | |
Stéphane Marchesin | 00ff187 | 2015-12-14 13:40:09 -0800 | [diff] [blame] | 131 | void parse_location(char* loc_str, int* x, int* y) |
David Sodman | 8ef2006 | 2015-01-06 09:23:40 -0800 | [diff] [blame] | 132 | { |
| 133 | int count = 0; |
| 134 | char* savedptr; |
David Sodman | 8ef2006 | 2015-01-06 09:23:40 -0800 | [diff] [blame] | 135 | char* str; |
Stéphane Marchesin | 00ff187 | 2015-12-14 13:40:09 -0800 | [diff] [blame] | 136 | int* results[] = {x, y}; |
David Sodman | 8ef2006 | 2015-01-06 09:23:40 -0800 | [diff] [blame] | 137 | long tmp; |
| 138 | |
Stéphane Marchesin | ac14d29 | 2015-12-14 15:27:18 -0800 | [diff] [blame] | 139 | for (char* token = str = loc_str; token != NULL; str = NULL) { |
David Sodman | 8ef2006 | 2015-01-06 09:23:40 -0800 | [diff] [blame] | 140 | if (count > 1) |
| 141 | break; |
| 142 | |
| 143 | token = strtok_r(str, ",", &savedptr); |
| 144 | if (token) { |
| 145 | tmp = MIN(INT_MAX, strtol(token, NULL, 0)); |
| 146 | *(results[count++]) = (int)tmp; |
| 147 | } |
| 148 | } |
| 149 | } |
| 150 | |
Stéphane Marchesin | 00ff187 | 2015-12-14 13:40:09 -0800 | [diff] [blame] | 151 | void parse_filespec(char* filespec, char* filename, |
Stéphane Marchesin | 8fc1352 | 2015-12-14 17:02:28 -0800 | [diff] [blame] | 152 | int32_t* offset_x, int32_t* offset_y, uint32_t* duration, |
| 153 | uint32_t default_duration, |
| 154 | int32_t default_x, int32_t default_y) |
David Sodman | 8ef2006 | 2015-01-06 09:23:40 -0800 | [diff] [blame] | 155 | { |
| 156 | char* saved_ptr; |
| 157 | char* token; |
| 158 | |
| 159 | // defaults |
| 160 | *offset_x = default_x; |
| 161 | *offset_y = default_y; |
| 162 | *duration = default_duration; |
| 163 | |
| 164 | token = filespec; |
| 165 | token = strtok_r(token, ":", &saved_ptr); |
| 166 | if (token) |
| 167 | strcpy(filename, token); |
| 168 | |
David Sodman | 8ef2006 | 2015-01-06 09:23:40 -0800 | [diff] [blame] | 169 | token = strtok_r(NULL, ":", &saved_ptr); |
| 170 | if (token) { |
| 171 | *duration = strtoul(token, NULL, 0); |
| 172 | token = strtok_r(NULL, ",", &saved_ptr); |
| 173 | if (token) { |
| 174 | token = strtok_r(token, ",", &saved_ptr); |
| 175 | if (token) { |
| 176 | *offset_x = strtol(token, NULL, 0); |
| 177 | token = strtok_r(token, ",", &saved_ptr); |
| 178 | if (token) |
| 179 | *offset_y = strtol(token, NULL, 0); |
| 180 | } |
| 181 | } |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | void parse_image_option(char* optionstr, char** name, char** val) |
| 186 | { |
| 187 | char** result[2] = { name, val }; |
| 188 | int count = 0; |
David Sodman | 8ef2006 | 2015-01-06 09:23:40 -0800 | [diff] [blame] | 189 | char* str; |
| 190 | char* savedptr; |
| 191 | |
Stéphane Marchesin | ac14d29 | 2015-12-14 15:27:18 -0800 | [diff] [blame] | 192 | for (char* token = str = optionstr; token != NULL; str = NULL) { |
David Sodman | 8ef2006 | 2015-01-06 09:23:40 -0800 | [diff] [blame] | 193 | if (count > 1) |
| 194 | break; |
| 195 | |
| 196 | token = strtok_r(str, ":", &savedptr); |
| 197 | if (token) { |
| 198 | *(result[count]) = malloc(strlen(token) + 1); |
| 199 | strcpy(*(result[count]), token); |
| 200 | count++; |
| 201 | } |
| 202 | } |
| 203 | } |
| 204 | |
Dominik Behr | da6df41 | 2016-08-02 12:56:42 -0700 | [diff] [blame] | 205 | bool write_string_to_file(const char *path, const char *s) |
| 206 | { |
| 207 | int fd; |
| 208 | size_t towrite; |
| 209 | ssize_t written; |
| 210 | |
| 211 | fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); |
| 212 | if (!fd) |
| 213 | return false; |
| 214 | |
| 215 | towrite = strlen(s); |
| 216 | written = write(fd, s, towrite); |
| 217 | close(fd); |
| 218 | |
| 219 | if (written != (ssize_t)towrite) { |
| 220 | LOG(ERROR, "Failed to write string%s to %s", s, path); |
| 221 | unlink(path); |
| 222 | return false; |
| 223 | } |
| 224 | return true; |
| 225 | } |