blob: a962a998bf37e87f84932c192cc91835aa8f96ad [file] [log] [blame]
David Sodmanbbcb0522014-09-19 10:34:07 -07001/*
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 Behr2b9f1232016-08-02 01:11:12 -07007#include <errno.h>
David Sodman8ef20062015-01-06 09:23:40 -08008#include <fcntl.h>
9#include <limits.h>
10#include <pwd.h>
David Sodmanbbcb0522014-09-19 10:34:07 -070011#include <stdio.h>
12#include <stdlib.h>
David Sodmane46ea8a2015-03-13 15:47:12 -070013#include <string.h>
Daniel Nicoara76622c32015-03-18 17:47:54 -040014#include <sys/file.h>
David Sodmanef1ba362015-03-16 10:50:24 -070015#include <sys/stat.h>
Dominik Behr09f2b722016-10-05 12:02:04 -070016#include <sys/types.h>
17#include <sys/wait.h>
David Sodmanbbcb0522014-09-19 10:34:07 -070018
David Sodmane46ea8a2015-03-13 15:47:12 -070019#include "util.h"
20
Dominik Behr09f2b722016-10-05 12:02:04 -070021static int daemon_pipe[2] = { -1, -1 };
22
Dominik Behr2b9f1232016-08-02 01:11:12 -070023static int openfd(char *path, int flags, int reqfd)
24{
25 int fd = open(path, flags);
26 if (fd < 0)
27 return -1;
28
29 if (fd == reqfd)
30 return reqfd;
31
32 if (dup2(fd, reqfd) >= 0) {
33 close(fd);
34 return reqfd;
35 }
36
37 close(fd);
38 return -1;
39}
40
41static int init_daemon_stdio(void)
42{
43 close(STDIN_FILENO);
44 close(STDOUT_FILENO);
45 close(STDERR_FILENO);
46
47 if (openfd("/dev/null", O_RDONLY, STDIN_FILENO) < 0)
48 return -1;
49
50 if (openfd("/dev/kmsg", O_WRONLY, STDOUT_FILENO) < 0)
51 return -1;
52
53 if (openfd("/dev/kmsg", O_WRONLY, STDERR_FILENO) < 0)
54 return -1;
55
56 return 0;
57}
58
Dominik Behr09f2b722016-10-05 12:02:04 -070059void daemonize(bool wait_child)
David Sodmanbbcb0522014-09-19 10:34:07 -070060{
61 pid_t pid;
David Sodmanbbcb0522014-09-19 10:34:07 -070062
Dominik Behr09f2b722016-10-05 12:02:04 -070063 if (wait_child)
64 if (pipe(daemon_pipe) < 0)
65 exit(EXIT_FAILURE);
66
David Sodmanbbcb0522014-09-19 10:34:07 -070067 pid = fork();
68 if (pid == -1)
69 return;
Dominik Behr09f2b722016-10-05 12:02:04 -070070 else if (pid != 0) {
71 if (wait_child) {
72 char code = EXIT_FAILURE;
73 close(daemon_pipe[1]);
74 if (read(daemon_pipe[0], &code, sizeof(code)) < 0) {
75 int c;
76 /* Child has died? */
77 if (errno == EPIPE)
78 if (waitpid(pid, &c, 0) >= 0)
79 exit(c); /* Propagate child exit code. */
80 /* Just report failure. */
81 exit(EXIT_FAILURE);
82 }
83 exit(code);
84 }
David Sodmanbbcb0522014-09-19 10:34:07 -070085 exit(EXIT_SUCCESS);
Dominik Behr09f2b722016-10-05 12:02:04 -070086 }
David Sodmanbbcb0522014-09-19 10:34:07 -070087
Dominik Behr09f2b722016-10-05 12:02:04 -070088 if (wait_child)
89 close(daemon_pipe[0]);
David Sodmanbbcb0522014-09-19 10:34:07 -070090 if (setsid() == -1)
91 return;
92
Dominik Behr2b9f1232016-08-02 01:11:12 -070093 init_daemon_stdio();
94}
David Sodmanbbcb0522014-09-19 10:34:07 -070095
Dominik Behr09f2b722016-10-05 12:02:04 -070096void daemon_exit_code(char code)
97{
98 if (write(daemon_pipe[1], &code, sizeof(code)) != sizeof(code)) {
99 LOG(ERROR, "failed to report exit code back to daemon parent");
100 }
101 close(daemon_pipe[1]);
102}
103
Dominik Behr2b9f1232016-08-02 01:11:12 -0700104static int is_valid_fd(int fd)
105{
106 return fcntl(fd, F_GETFL) != -1 || errno != EBADF;
107}
David Sodmanbbcb0522014-09-19 10:34:07 -0700108
Dominik Behr2b9f1232016-08-02 01:11:12 -0700109void fix_stdio(void)
110{
111 if (!is_valid_fd(STDIN_FILENO)
112 || !is_valid_fd(STDOUT_FILENO)
113 || !is_valid_fd(STDERR_FILENO))
114 init_daemon_stdio();
David Sodmanbbcb0522014-09-19 10:34:07 -0700115}
116
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800117void parse_location(char* loc_str, int* x, int* y)
David Sodman8ef20062015-01-06 09:23:40 -0800118{
119 int count = 0;
120 char* savedptr;
David Sodman8ef20062015-01-06 09:23:40 -0800121 char* str;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800122 int* results[] = {x, y};
David Sodman8ef20062015-01-06 09:23:40 -0800123 long tmp;
124
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800125 for (char* token = str = loc_str; token != NULL; str = NULL) {
David Sodman8ef20062015-01-06 09:23:40 -0800126 if (count > 1)
127 break;
128
129 token = strtok_r(str, ",", &savedptr);
130 if (token) {
131 tmp = MIN(INT_MAX, strtol(token, NULL, 0));
132 *(results[count++]) = (int)tmp;
133 }
134 }
135}
136
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800137void parse_filespec(char* filespec, char* filename,
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800138 int32_t* offset_x, int32_t* offset_y, uint32_t* duration,
139 uint32_t default_duration,
140 int32_t default_x, int32_t default_y)
David Sodman8ef20062015-01-06 09:23:40 -0800141{
142 char* saved_ptr;
143 char* token;
144
145 // defaults
146 *offset_x = default_x;
147 *offset_y = default_y;
148 *duration = default_duration;
149
150 token = filespec;
151 token = strtok_r(token, ":", &saved_ptr);
152 if (token)
153 strcpy(filename, token);
154
David Sodman8ef20062015-01-06 09:23:40 -0800155 token = strtok_r(NULL, ":", &saved_ptr);
156 if (token) {
157 *duration = strtoul(token, NULL, 0);
158 token = strtok_r(NULL, ",", &saved_ptr);
159 if (token) {
160 token = strtok_r(token, ",", &saved_ptr);
161 if (token) {
162 *offset_x = strtol(token, NULL, 0);
163 token = strtok_r(token, ",", &saved_ptr);
164 if (token)
165 *offset_y = strtol(token, NULL, 0);
166 }
167 }
168 }
169}
170
171void parse_image_option(char* optionstr, char** name, char** val)
172{
173 char** result[2] = { name, val };
174 int count = 0;
David Sodman8ef20062015-01-06 09:23:40 -0800175 char* str;
176 char* savedptr;
177
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800178 for (char* token = str = optionstr; token != NULL; str = NULL) {
David Sodman8ef20062015-01-06 09:23:40 -0800179 if (count > 1)
180 break;
181
182 token = strtok_r(str, ":", &savedptr);
183 if (token) {
184 *(result[count]) = malloc(strlen(token) + 1);
185 strcpy(*(result[count]), token);
186 count++;
187 }
188 }
189}
190
Dominik Behrda6df412016-08-02 12:56:42 -0700191bool write_string_to_file(const char *path, const char *s)
192{
193 int fd;
194 size_t towrite;
195 ssize_t written;
196
197 fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR);
198 if (!fd)
199 return false;
200
201 towrite = strlen(s);
202 written = write(fd, s, towrite);
203 close(fd);
204
205 if (written != (ssize_t)towrite) {
206 LOG(ERROR, "Failed to write string%s to %s", s, path);
207 unlink(path);
208 return false;
209 }
210 return true;
211}