Commit | Line | Data |
---|---|---|
81b86775 DG |
1 | /* |
2 | * Copyright (C) 2012 - David Goulet <dgoulet@efficios.com> | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License, version 2 only, as | |
6 | * published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License along with | |
14 | * this program; if not, write to the Free Software Foundation, Inc., 51 | |
15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
16 | */ | |
17 | ||
18 | #define _GNU_SOURCE | |
35f90c40 | 19 | #include <assert.h> |
81b86775 DG |
20 | #include <ctype.h> |
21 | #include <fcntl.h> | |
22 | #include <limits.h> | |
23 | #include <stdlib.h> | |
24 | #include <string.h> | |
2d851108 DG |
25 | #include <sys/types.h> |
26 | #include <sys/stat.h> | |
27 | #include <unistd.h> | |
81b86775 DG |
28 | |
29 | #include <common/common.h> | |
30 | ||
31 | #include "utils.h" | |
32 | ||
33 | /* | |
34 | * Return the realpath(3) of the path even if the last directory token does not | |
35 | * exist. For example, with /tmp/test1/test2, if test2/ does not exist but the | |
36 | * /tmp/test1 does, the real path is returned. In normal time, realpath(3) | |
37 | * fails if the end point directory does not exist. | |
38 | */ | |
90e535ef | 39 | LTTNG_HIDDEN |
81b86775 DG |
40 | char *utils_expand_path(const char *path) |
41 | { | |
42 | const char *end_path = path; | |
43 | char *next, *cut_path = NULL, *expanded_path = NULL; | |
44 | ||
45 | /* Safety net */ | |
46 | if (path == NULL) { | |
47 | goto error; | |
48 | } | |
49 | ||
50 | /* Find last token delimited by '/' */ | |
51 | while ((next = strpbrk(end_path + 1, "/"))) { | |
52 | end_path = next; | |
53 | } | |
54 | ||
55 | /* Cut last token from original path */ | |
56 | cut_path = strndup(path, end_path - path); | |
57 | ||
58 | expanded_path = zmalloc(PATH_MAX); | |
59 | if (expanded_path == NULL) { | |
60 | PERROR("zmalloc expand path"); | |
61 | goto error; | |
62 | } | |
63 | ||
64 | expanded_path = realpath((char *)cut_path, expanded_path); | |
65 | if (expanded_path == NULL) { | |
66 | switch (errno) { | |
67 | case ENOENT: | |
68 | ERR("%s: No such file or directory", cut_path); | |
69 | break; | |
70 | default: | |
71 | PERROR("realpath utils expand path"); | |
72 | break; | |
73 | } | |
74 | goto error; | |
75 | } | |
76 | ||
77 | /* Add end part to expanded path */ | |
c30ce0b3 | 78 | strncat(expanded_path, end_path, PATH_MAX - strlen(expanded_path) - 1); |
81b86775 DG |
79 | |
80 | free(cut_path); | |
81 | return expanded_path; | |
82 | ||
83 | error: | |
84 | free(expanded_path); | |
85 | free(cut_path); | |
86 | return NULL; | |
87 | } | |
88 | ||
89 | /* | |
90 | * Create a pipe in dst. | |
91 | */ | |
90e535ef | 92 | LTTNG_HIDDEN |
81b86775 DG |
93 | int utils_create_pipe(int *dst) |
94 | { | |
95 | int ret; | |
96 | ||
97 | if (dst == NULL) { | |
98 | return -1; | |
99 | } | |
100 | ||
101 | ret = pipe(dst); | |
102 | if (ret < 0) { | |
103 | PERROR("create pipe"); | |
104 | } | |
105 | ||
106 | return ret; | |
107 | } | |
108 | ||
109 | /* | |
110 | * Create pipe and set CLOEXEC flag to both fd. | |
111 | * | |
112 | * Make sure the pipe opened by this function are closed at some point. Use | |
113 | * utils_close_pipe(). | |
114 | */ | |
90e535ef | 115 | LTTNG_HIDDEN |
81b86775 DG |
116 | int utils_create_pipe_cloexec(int *dst) |
117 | { | |
118 | int ret, i; | |
119 | ||
120 | if (dst == NULL) { | |
121 | return -1; | |
122 | } | |
123 | ||
124 | ret = utils_create_pipe(dst); | |
125 | if (ret < 0) { | |
126 | goto error; | |
127 | } | |
128 | ||
129 | for (i = 0; i < 2; i++) { | |
130 | ret = fcntl(dst[i], F_SETFD, FD_CLOEXEC); | |
131 | if (ret < 0) { | |
132 | PERROR("fcntl pipe cloexec"); | |
133 | goto error; | |
134 | } | |
135 | } | |
136 | ||
137 | error: | |
138 | return ret; | |
139 | } | |
140 | ||
141 | /* | |
142 | * Close both read and write side of the pipe. | |
143 | */ | |
90e535ef | 144 | LTTNG_HIDDEN |
81b86775 DG |
145 | void utils_close_pipe(int *src) |
146 | { | |
147 | int i, ret; | |
148 | ||
149 | if (src == NULL) { | |
150 | return; | |
151 | } | |
152 | ||
153 | for (i = 0; i < 2; i++) { | |
154 | /* Safety check */ | |
155 | if (src[i] < 0) { | |
156 | continue; | |
157 | } | |
158 | ||
159 | ret = close(src[i]); | |
160 | if (ret) { | |
161 | PERROR("close pipe"); | |
162 | } | |
163 | } | |
164 | } | |
a4b92340 DG |
165 | |
166 | /* | |
167 | * Create a new string using two strings range. | |
168 | */ | |
90e535ef | 169 | LTTNG_HIDDEN |
a4b92340 DG |
170 | char *utils_strdupdelim(const char *begin, const char *end) |
171 | { | |
172 | char *str; | |
173 | ||
174 | str = zmalloc(end - begin + 1); | |
175 | if (str == NULL) { | |
176 | PERROR("zmalloc strdupdelim"); | |
177 | goto error; | |
178 | } | |
179 | ||
180 | memcpy(str, begin, end - begin); | |
181 | str[end - begin] = '\0'; | |
182 | ||
183 | error: | |
184 | return str; | |
185 | } | |
b662582b DG |
186 | |
187 | /* | |
188 | * Set CLOEXEC flag to the give file descriptor. | |
189 | */ | |
90e535ef | 190 | LTTNG_HIDDEN |
b662582b DG |
191 | int utils_set_fd_cloexec(int fd) |
192 | { | |
193 | int ret; | |
194 | ||
195 | if (fd < 0) { | |
196 | ret = -EINVAL; | |
197 | goto end; | |
198 | } | |
199 | ||
200 | ret = fcntl(fd, F_SETFD, FD_CLOEXEC); | |
201 | if (ret < 0) { | |
202 | PERROR("fcntl cloexec"); | |
203 | ret = -errno; | |
204 | } | |
205 | ||
206 | end: | |
207 | return ret; | |
208 | } | |
35f90c40 DG |
209 | |
210 | /* | |
211 | * Create pid file to the given path and filename. | |
212 | */ | |
90e535ef | 213 | LTTNG_HIDDEN |
35f90c40 DG |
214 | int utils_create_pid_file(pid_t pid, const char *filepath) |
215 | { | |
216 | int ret; | |
217 | FILE *fp; | |
218 | ||
219 | assert(filepath); | |
220 | ||
221 | fp = fopen(filepath, "w"); | |
222 | if (fp == NULL) { | |
223 | PERROR("open pid file %s", filepath); | |
224 | ret = -1; | |
225 | goto error; | |
226 | } | |
227 | ||
228 | ret = fprintf(fp, "%d\n", pid); | |
229 | if (ret < 0) { | |
230 | PERROR("fprintf pid file"); | |
231 | } | |
232 | ||
233 | fclose(fp); | |
234 | DBG("Pid %d written in file %s", pid, filepath); | |
235 | error: | |
236 | return ret; | |
237 | } | |
2d851108 DG |
238 | |
239 | /* | |
240 | * Recursively create directory using the given path and mode. | |
241 | * | |
242 | * On success, return 0 else a negative error code. | |
243 | */ | |
90e535ef | 244 | LTTNG_HIDDEN |
2d851108 DG |
245 | int utils_mkdir_recursive(const char *path, mode_t mode) |
246 | { | |
247 | char *p, tmp[PATH_MAX]; | |
248 | struct stat statbuf; | |
249 | size_t len; | |
250 | int ret; | |
251 | ||
252 | assert(path); | |
253 | ||
254 | ret = snprintf(tmp, sizeof(tmp), "%s", path); | |
255 | if (ret < 0) { | |
256 | PERROR("snprintf mkdir"); | |
257 | goto error; | |
258 | } | |
259 | ||
260 | len = ret; | |
261 | if (tmp[len - 1] == '/') { | |
262 | tmp[len - 1] = 0; | |
263 | } | |
264 | ||
265 | for (p = tmp + 1; *p; p++) { | |
266 | if (*p == '/') { | |
267 | *p = 0; | |
268 | if (tmp[strlen(tmp) - 1] == '.' && | |
269 | tmp[strlen(tmp) - 2] == '.' && | |
270 | tmp[strlen(tmp) - 3] == '/') { | |
271 | ERR("Using '/../' is not permitted in the trace path (%s)", | |
272 | tmp); | |
273 | ret = -1; | |
274 | goto error; | |
275 | } | |
276 | ret = stat(tmp, &statbuf); | |
277 | if (ret < 0) { | |
278 | ret = mkdir(tmp, mode); | |
279 | if (ret < 0) { | |
280 | if (errno != EEXIST) { | |
281 | PERROR("mkdir recursive"); | |
282 | ret = -errno; | |
283 | goto error; | |
284 | } | |
285 | } | |
286 | } | |
287 | *p = '/'; | |
288 | } | |
289 | } | |
290 | ||
291 | ret = mkdir(tmp, mode); | |
292 | if (ret < 0) { | |
293 | if (errno != EEXIST) { | |
294 | PERROR("mkdir recursive last piece"); | |
295 | ret = -errno; | |
296 | } else { | |
297 | ret = 0; | |
298 | } | |
299 | } | |
300 | ||
301 | error: | |
302 | return ret; | |
303 | } |