Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2020 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : : * Copyright (c) 2013 Vsevolod Stakhov <vsevolod@FreeBSD.org>
5 : : * All rights reserved.
6 : : *
7 : : * Redistribution and use in source and binary forms, with or without
8 : : * modification, are permitted provided that the following conditions
9 : : * are met:
10 : : * 1. Redistributions of source code must retain the above copyright
11 : : * notice, this list of conditions and the following disclaimer
12 : : * in this position and unchanged.
13 : : * 2. Redistributions in binary form must reproduce the above copyright
14 : : * notice, this list of conditions and the following disclaimer in the
15 : : * documentation and/or other materials provided with the distribution.
16 : : *
17 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
18 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
21 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : : */
28 : :
29 : : #include <pkg_config.h>
30 : :
31 : : #include <sys/socket.h>
32 : : #include <sys/stat.h>
33 : : #include <sys/param.h>
34 : : #include <stdio.h>
35 : :
36 : : #include <assert.h>
37 : : #include <errno.h>
38 : : #include <fcntl.h>
39 : : #include <stdlib.h>
40 : : #include <unistd.h>
41 : : #include <string.h>
42 : : #include <ucl.h>
43 : : #include <utlist.h>
44 : : #include <ctype.h>
45 : : #include <fnmatch.h>
46 : : #include <paths.h>
47 : : #include <float.h>
48 : : #include <math.h>
49 : : #include <regex.h>
50 : :
51 : : #include <bsd_compat.h>
52 : :
53 : : #include "pkg.h"
54 : : #include "private/event.h"
55 : : #include "private/utils.h"
56 : : #include "private/pkg.h"
57 : : #include "xmalloc.h"
58 : :
59 : : extern struct pkg_ctx ctx;
60 : :
61 : : bool
62 : 3976 : match_ucl_lists(const char *buf, const ucl_object_t *globs, const ucl_object_t *regexes)
63 : : {
64 : : const ucl_object_t *cur;
65 : : ucl_object_iter_t it;
66 : :
67 : 3976 : if (globs == NULL && regexes == NULL)
68 : 428 : return (false);
69 : :
70 : 3544 : if (globs != NULL) {
71 : 3544 : it = NULL;
72 [ + + ]: 7492 : while ((cur = ucl_iterate_object(globs, &it, true))) {
73 [ + + ]: 3968 : if (fnmatch(ucl_object_tostring(cur), buf, 0) == 0)
74 : 20 : return (true);
75 : : }
76 : 3524 : }
77 : :
78 : 3944 : if (regexes != NULL) {
79 : 3104 : it = NULL;
80 [ + + ]: 6204 : while ((cur = ucl_iterate_object(regexes, &it, true))) {
81 : : regex_t re;
82 : 3104 : regcomp(&re, ucl_object_tostring(cur),
83 : : REG_EXTENDED|REG_NOSUB);
84 [ + + ]: 3104 : if (regexec(&re, buf, 0, NULL, 0) == 0) {
85 : 4 : regfree(&re);
86 : 4 : return (true);
87 : : }
88 : 3100 : regfree(&re);
89 : : }
90 : 3100 : }
91 : :
92 : 3524 : return (false);
93 : 3976 : }
94 : :
95 : : int
96 : 2044 : mkdirs(const char *_path)
97 : : {
98 : : char path[MAXPATHLEN];
99 : : char *p;
100 : :
101 : 2044 : strlcpy(path, _path, sizeof(path));
102 : 2044 : p = path;
103 : 2044 : if (*p == '/')
104 : 1208 : p++;
105 : :
106 : 6743 : for (;;) {
107 : 6743 : if ((p = strchr(p, '/')) != NULL)
108 : 4699 : *p = '\0';
109 : :
110 : 6594 : if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
111 : 6594 : if (errno != EEXIST && errno != EISDIR) {
112 : 0 : pkg_emit_errno("mkdir", path);
113 : 0 : return (EPKG_FATAL);
114 : : }
115 : :
116 : : /* that was the last element of the path */
117 [ + + ]: 6743 : if (p == NULL)
118 : 2044 : break;
119 : :
120 : 4699 : *p = '/';
121 : 4699 : p++;
122 : : }
123 : :
124 : 2044 : return (EPKG_OK);
125 : 2044 : }
126 : : int
127 : 239 : file_to_bufferat(int dfd, const char *path, char **buffer, off_t *sz)
128 : : {
129 : 239 : int fd = -1;
130 : : struct stat st;
131 : 239 : int retcode = EPKG_OK;
132 : :
133 : 239 : assert(path != NULL && path[0] != '\0');
134 [ + - ]: 239 : assert(buffer != NULL);
135 [ + - ]: 239 : assert(sz != NULL);
136 : :
137 [ - + ]: 239 : if ((fd = openat(dfd, path, O_RDONLY)) == -1) {
138 : 0 : pkg_emit_errno("openat", path);
139 : 0 : retcode = EPKG_FATAL;
140 : 0 : goto cleanup;
141 : : }
142 : :
143 [ - + ]: 239 : if (fstatat(dfd, path, &st, 0) == -1) {
144 : 0 : pkg_emit_errno("fstatat", path);
145 : 0 : retcode = EPKG_FATAL;
146 : 0 : goto cleanup;
147 : : }
148 : :
149 : 239 : *buffer = xmalloc(st.st_size + 1);
150 : :
151 [ - + ]: 239 : if (read(fd, *buffer, st.st_size) == -1) {
152 : 0 : pkg_emit_errno("read", path);
153 : 0 : retcode = EPKG_FATAL;
154 : 0 : goto cleanup;
155 : : }
156 : :
157 : : cleanup:
158 : 239 : if (fd >= 0)
159 : 239 : close(fd);
160 : :
161 [ + - ]: 239 : if (retcode == EPKG_OK) {
162 : 239 : (*buffer)[st.st_size] = '\0';
163 : 239 : *sz = st.st_size;
164 : 239 : } else {
165 : 0 : *buffer = NULL;
166 : 0 : *sz = -1;
167 : : }
168 : 239 : return (retcode);
169 : : }
170 : :
171 : : int
172 : 8 : file_to_buffer(const char *path, char **buffer, off_t *sz)
173 : : {
174 : 8 : int fd = -1;
175 : : struct stat st;
176 : 8 : int retcode = EPKG_OK;
177 : :
178 : 8 : assert(path != NULL && path[0] != '\0');
179 [ + - ]: 8 : assert(buffer != NULL);
180 [ + - ]: 8 : assert(sz != NULL);
181 : :
182 [ - + ]: 8 : if ((fd = open(path, O_RDONLY)) == -1) {
183 : 0 : pkg_emit_errno("open", path);
184 : 0 : retcode = EPKG_FATAL;
185 : 0 : goto cleanup;
186 : : }
187 : :
188 [ - + ]: 8 : if (fstat(fd, &st) == -1) {
189 : 0 : pkg_emit_errno("fstat", path);
190 : 0 : retcode = EPKG_FATAL;
191 : 0 : goto cleanup;
192 : : }
193 : :
194 : 8 : *buffer = xmalloc(st.st_size + 1);
195 : :
196 [ - + ]: 8 : if (read(fd, *buffer, st.st_size) == -1) {
197 : 0 : pkg_emit_errno("read", path);
198 : 0 : retcode = EPKG_FATAL;
199 : 0 : goto cleanup;
200 : : }
201 : :
202 : : cleanup:
203 : 8 : if (fd >= 0)
204 : 8 : close(fd);
205 : :
206 [ + - ]: 8 : if (retcode == EPKG_OK) {
207 : 8 : (*buffer)[st.st_size] = '\0';
208 : 8 : *sz = st.st_size;
209 : 8 : } else {
210 : 0 : *buffer = NULL;
211 : 0 : *sz = -1;
212 : : }
213 : 8 : return (retcode);
214 : : }
215 : :
216 : : int
217 : 24 : format_exec_cmd(char **dest, const char *in, const char *prefix,
218 : : const char *plist_file, const char *line, int argc, char **argv, bool lua)
219 : : {
220 : : xstring *buf;
221 : : char path[MAXPATHLEN];
222 : : char *cp;
223 : : size_t sz;
224 : :
225 : 24 : buf = xstring_new();
226 : :
227 : 24 : if (line != NULL && argv != NULL) {
228 [ + + ]: 24 : if (lua) {
229 : 8 : fprintf(buf->fp, "-- args: %s\n", line);
230 : 8 : } else {
231 : 16 : fprintf(buf->fp, "# args: %s\n", line);
232 : : }
233 : 24 : }
234 : :
235 [ + + ]: 740 : while (in[0] != '\0') {
236 [ + + ]: 720 : if (in[0] != '%') {
237 : 688 : fputc(in[0], buf->fp);
238 : 688 : in++;
239 : 688 : continue;
240 : : }
241 : 32 : in++;
242 [ - - - - : 32 : switch(in[0]) {
- - + ]
243 : : case 'D':
244 : 0 : fprintf(buf->fp, "%s", prefix);
245 : 0 : break;
246 : : case 'F':
247 : 0 : if (plist_file == NULL || plist_file[0] == '\0') {
248 : 0 : pkg_emit_error("No files defined %%F couldn't "
249 : 0 : "be expanded, ignoring %s", in);
250 : 0 : xstring_free(buf);
251 : 0 : return (EPKG_FATAL);
252 : : }
253 : 0 : fprintf(buf->fp, "%s", plist_file);
254 : 0 : break;
255 : : case 'f':
256 : 0 : if (plist_file == NULL || plist_file[0] == '\0') {
257 : 0 : pkg_emit_error("No files defined %%f couldn't "
258 : 0 : "be expanded, ignoring %s", in);
259 : 0 : xstring_free(buf);
260 : 0 : return (EPKG_FATAL);
261 : : }
262 [ # # ]: 0 : if (prefix[strlen(prefix) - 1] == '/')
263 : 0 : snprintf(path, sizeof(path), "%s%s",
264 : 0 : prefix, plist_file);
265 : : else
266 : 0 : snprintf(path, sizeof(path), "%s/%s",
267 : 0 : prefix, plist_file);
268 : 0 : cp = strrchr(path, '/');
269 : 0 : cp ++;
270 : 0 : fprintf(buf->fp, "%s", cp);
271 : 0 : break;
272 : : case 'B':
273 : 0 : if (plist_file == NULL || plist_file[0] == '\0') {
274 : 0 : pkg_emit_error("No files defined %%B couldn't "
275 : 0 : "be expanded, ignoring %s", in);
276 : 0 : xstring_free(buf);
277 : 0 : return (EPKG_FATAL);
278 : : }
279 [ # # ]: 0 : if (prefix[strlen(prefix) - 1] == '/')
280 : 0 : snprintf(path, sizeof(path), "%s%s", prefix,
281 : 0 : plist_file);
282 : : else
283 : 0 : snprintf(path, sizeof(path), "%s/%s", prefix,
284 : 0 : plist_file);
285 : 0 : cp = strrchr(path, '/');
286 : 0 : cp[0] = '\0';
287 : 0 : fprintf(buf->fp, "%s", path);
288 : 0 : break;
289 : : case '%':
290 : 0 : fputc('%', buf->fp);
291 : 0 : break;
292 : : case '@':
293 [ # # ]: 0 : if (line != NULL) {
294 : 0 : fprintf(buf->fp, "%s", line);
295 : 0 : break;
296 : : }
297 : :
298 : : /*
299 : : * no break here because if line is not
300 : : * given (default exec) %@ does not
301 : : * exists
302 : : */
303 : : /* FALLTHRU */
304 : : case '#':
305 : 0 : fprintf(buf->fp, "%d", argc);
306 : 0 : break;
307 : : default:
308 [ + - ]: 32 : if ((sz = strspn(in, "0123456789")) > 0) {
309 : 32 : int pos = strtol(in, NULL, 10);
310 [ + + ]: 32 : if (pos > argc) {
311 : 4 : pkg_emit_error("Requesting argument "
312 : : "%%%d while only %d arguments are"
313 : 4 : " available", pos, argc);
314 : 4 : xstring_free(buf);
315 : 4 : return (EPKG_FATAL);
316 : : }
317 : 28 : fprintf(buf->fp, "%s", argv[pos -1]);
318 : 28 : in += sz -1;
319 : 28 : break;
320 : : }
321 : 0 : fprintf(buf->fp, "%c%c", '%', in[0]);
322 : 0 : break;
323 : : }
324 : :
325 : 28 : in++;
326 : : }
327 : :
328 : 20 : *dest = xstring_get(buf);
329 : :
330 : 20 : return (EPKG_OK);
331 : 24 : }
332 : :
333 : : int
334 : 831 : is_dir(const char *path)
335 : : {
336 : : struct stat st;
337 : :
338 : 831 : return (stat(path, &st) == 0 && S_ISDIR(st.st_mode));
339 : : }
340 : :
341 : : int
342 : 0 : is_link(const char *path)
343 : : {
344 : : struct stat st;
345 : :
346 : 0 : return (lstat(path, &st) == 0 && S_ISLNK(st.st_mode));
347 : : }
348 : :
349 : : bool
350 : 92 : check_for_hardlink(hardlinks_t *hl, struct stat *st)
351 : : {
352 : : int absent;
353 : :
354 : 92 : kh_put_hardlinks(hl, st->st_ino, &absent);
355 [ + + ]: 92 : if (absent == 0)
356 : 46 : return (true);
357 : :
358 : 46 : return (false);
359 : 92 : }
360 : :
361 : : bool
362 : 694 : is_valid_abi(const char *arch, bool emit_error) {
363 : : const char *myarch, *myarch_legacy;
364 : :
365 : 694 : myarch = pkg_object_string(pkg_config_get("ABI"));
366 : 694 : myarch_legacy = pkg_object_string(pkg_config_get("ALTABI"));
367 : :
368 : 694 : if (fnmatch(arch, myarch, FNM_CASEFOLD) == FNM_NOMATCH &&
369 : 0 : fnmatch(arch, myarch_legacy, FNM_CASEFOLD) == FNM_NOMATCH &&
370 : 0 : strncasecmp(arch, myarch, strlen(myarch)) != 0 &&
371 : 0 : strncasecmp(arch, myarch_legacy, strlen(myarch_legacy)) != 0) {
372 : 0 : if (emit_error)
373 : 0 : pkg_emit_error("wrong architecture: %s instead of %s",
374 : 0 : arch, myarch);
375 : 0 : return (false);
376 : : }
377 : :
378 : 694 : return (true);
379 : 694 : }
380 : :
381 : : bool
382 : 694 : is_valid_os_version(struct pkg *pkg)
383 : : {
384 : : #ifdef __FreeBSD__
385 : : const char *fbsd_version;
386 : 694 : const char *errstr = NULL;
387 : : int fbsdver;
388 : : char query_buf[512];
389 : : /* -1: not checked, 0: not allowed, 1: allowed */
390 : : static int osver_mismatch_allowed = -1;
391 : : bool ret;
392 : :
393 [ - + ]: 694 : if (pkg_object_bool(pkg_config_get("IGNORE_OSVERSION")))
394 : 0 : return (true);
395 : 694 : if ((fbsd_version = pkg_kv_get(&pkg->annotations, "FreeBSD_version")) != NULL) {
396 : 570 : fbsdver = strtonum(fbsd_version, 1, INT_MAX, &errstr);
397 [ - + ]: 570 : if (errstr != NULL) {
398 : 0 : pkg_emit_error("Invalid FreeBSD version %s for package %s",
399 : 0 : fbsd_version, pkg->name);
400 : 0 : return (false);
401 : : }
402 [ - + ]: 570 : if (fbsdver > ctx.osversion) {
403 [ # # ]: 0 : if (fbsdver - ctx.osversion < 100000) {
404 : : /* Negligible difference, ask user to enforce */
405 : 0 : if (osver_mismatch_allowed == -1) {
406 : 0 : snprintf(query_buf, sizeof(query_buf),
407 : : "Newer FreeBSD version for package %s:\n"
408 : : "To ignore this error set IGNORE_OSVERSION=yes\n"
409 : : "- package: %d\n"
410 : : "- running kernel: %d\n"
411 : 0 : "Ignore the mismatch and continue? ", pkg->name,
412 : 0 : fbsdver, ctx.osversion);
413 : 0 : ret = pkg_emit_query_yesno(false, query_buf);
414 : 0 : osver_mismatch_allowed = ret;
415 : 0 : }
416 : :
417 : 0 : return (osver_mismatch_allowed);
418 : : }
419 : : else {
420 : 0 : pkg_emit_error("Newer FreeBSD version for package %s:\n"
421 : : "To ignore this error set IGNORE_OSVERSION=yes\n"
422 : : "- package: %d\n"
423 : : "- running kernel: %d\n",
424 : 0 : pkg->name,
425 : 0 : fbsdver, ctx.osversion);
426 : 0 : return (false);
427 : : }
428 : : }
429 : 570 : }
430 : 694 : return (true);
431 : : #else
432 : : return (true);
433 : : #endif
434 : :
435 : 694 : }
436 : :
437 : : void
438 : 0 : set_nonblocking(int fd)
439 : : {
440 : : int flags;
441 : :
442 [ # # ]: 0 : if ((flags = fcntl(fd, F_GETFL)) == -1)
443 : 0 : return;
444 : 0 : if (!(flags & O_NONBLOCK)) {
445 : 0 : flags |= O_NONBLOCK;
446 : 0 : fcntl(fd, F_SETFL, flags);
447 : 0 : }
448 : 0 : }
449 : :
450 : : void
451 : 0 : set_blocking(int fd)
452 : : {
453 : : int flags;
454 : :
455 [ # # ]: 0 : if ((flags = fcntl(fd, F_GETFL)) == -1)
456 : 0 : return;
457 : 0 : if (flags & O_NONBLOCK) {
458 : 0 : flags &= ~O_NONBLOCK;
459 : 0 : fcntl(fd, F_SETFL, flags);
460 : 0 : }
461 : 0 : }
462 : :
463 : : /* Spawn a process from pfunc, returning it's pid. The fds array passed will
464 : : * be filled with two descriptors: fds[0] will read from the child process,
465 : : * and fds[1] will write to it.
466 : : * Similarly, the child process will receive a reading/writing fd set (in
467 : : * that same order) as arguments.
468 : : */
469 : : extern char **environ;
470 : : pid_t
471 : 0 : process_spawn_pipe(FILE *inout[2], const char *command)
472 : : {
473 : : pid_t pid;
474 : : int pipes[4];
475 : : char *argv[4];
476 : :
477 : : /* Parent read/child write pipe */
478 [ # # ]: 0 : if (pipe(&pipes[0]) == -1)
479 : 0 : return (-1);
480 : :
481 : : /* Child read/parent write pipe */
482 [ # # ]: 0 : if (pipe(&pipes[2]) == -1) {
483 : 0 : close(pipes[0]);
484 : 0 : close(pipes[1]);
485 : 0 : return (-1);
486 : : }
487 : :
488 : 0 : argv[0] = __DECONST(char *, "sh");
489 : 0 : argv[1] = __DECONST(char *, "-c");
490 : 0 : argv[2] = __DECONST(char *, command);
491 : 0 : argv[3] = NULL;
492 : :
493 : 0 : pid = fork();
494 [ # # ]: 0 : if (pid > 0) {
495 : : /* Parent process */
496 : 0 : inout[0] = fdopen(pipes[0], "r");
497 : 0 : inout[1] = fdopen(pipes[3], "w");
498 : :
499 : 0 : close(pipes[1]);
500 : 0 : close(pipes[2]);
501 : :
502 : 0 : return (pid);
503 : :
504 [ # # ]: 0 : } else if (pid == 0) {
505 : 0 : close(pipes[0]);
506 : 0 : close(pipes[3]);
507 : :
508 : 0 : if (pipes[1] != STDOUT_FILENO) {
509 : 0 : dup2(pipes[1], STDOUT_FILENO);
510 : 0 : close(pipes[1]);
511 : 0 : }
512 : 0 : if (pipes[2] != STDIN_FILENO) {
513 : 0 : dup2(pipes[2], STDIN_FILENO);
514 : 0 : close(pipes[2]);
515 : 0 : }
516 : 0 : closefrom(STDERR_FILENO + 1);
517 : :
518 : 0 : execve(_PATH_BSHELL, argv, environ);
519 : :
520 : 0 : exit(127);
521 : : }
522 : :
523 : 0 : return (-1); /* ? */
524 : 0 : }
525 : :
526 : : static int
527 : 14141 : ucl_file_append_character(unsigned char c, size_t len, void *data)
528 : : {
529 : : size_t i;
530 : 14141 : FILE *out = data;
531 : :
532 [ + + ]: 28282 : for (i = 0; i < len; i++)
533 : 14141 : fprintf(out, "%c", c);
534 : :
535 : 14141 : return (0);
536 : : }
537 : :
538 : : static int
539 : 15607 : ucl_file_append_len(const unsigned char *str, size_t len, void *data)
540 : : {
541 : 15607 : FILE *out = data;
542 : :
543 : 15607 : fprintf(out, "%.*s", (int)len, str);
544 : :
545 : 15607 : return (0);
546 : : }
547 : :
548 : : static int
549 : 797 : ucl_file_append_int(int64_t val, void *data)
550 : : {
551 : 797 : FILE *out = data;
552 : :
553 : 797 : fprintf(out, "%"PRId64, val);
554 : :
555 : 797 : return (0);
556 : : }
557 : :
558 : : static int
559 : 0 : ucl_file_append_double(double val, void *data)
560 : : {
561 : 0 : FILE *out = data;
562 : 0 : const double delta = 0.0000001;
563 : :
564 [ # # ]: 0 : if (val == (double)(int)val) {
565 : 0 : fprintf(out, "%.1lf", val);
566 [ # # ]: 0 : } else if (fabs(val - (double)(int)val) < delta) {
567 : 0 : fprintf(out, "%.*lg", DBL_DIG, val);
568 : 0 : } else {
569 : 0 : fprintf(out, "%lf", val);
570 : : }
571 : :
572 : 0 : return (0);
573 : : }
574 : :
575 : : static int
576 : 198321 : ucl_buf_append_character(unsigned char c, size_t len, void *data)
577 : : {
578 : 198321 : xstring *buf = data;
579 : : size_t i;
580 : :
581 [ + + ]: 396954 : for (i = 0; i < len; i++)
582 : 198633 : fprintf(buf->fp, "%c", c);
583 : :
584 : 198321 : return (0);
585 : : }
586 : :
587 : : static int
588 : 72976 : ucl_buf_append_len(const unsigned char *str, size_t len, void *data)
589 : : {
590 : 72976 : xstring *buf = data;
591 : :
592 : 72976 : fprintf(buf->fp, "%.*s", (int)len, str);
593 : :
594 : 72976 : return (0);
595 : : }
596 : :
597 : : static int
598 : 2017 : ucl_buf_append_int(int64_t val, void *data)
599 : : {
600 : 2017 : xstring *buf = data;
601 : :
602 : 2017 : fprintf(buf->fp, "%"PRId64, val);
603 : :
604 : 2017 : return (0);
605 : : }
606 : :
607 : : static int
608 : 0 : ucl_buf_append_double(double val, void *data)
609 : : {
610 : 0 : xstring *buf = data;
611 : 0 : const double delta = 0.0000001;
612 : :
613 [ # # ]: 0 : if (val == (double)(int)val) {
614 : 0 : fprintf(buf->fp, "%.1lf", val);
615 [ # # ]: 0 : } else if (fabs(val - (double)(int)val) < delta) {
616 : 0 : fprintf(buf->fp, "%.*lg", DBL_DIG, val);
617 : 0 : } else {
618 : 0 : fprintf(buf->fp, "%lf", val);
619 : : }
620 : :
621 : 0 : return (0);
622 : : }
623 : :
624 : : bool
625 : 797 : ucl_object_emit_file(const ucl_object_t *obj, enum ucl_emitter emit_type,
626 : : FILE *out)
627 : : {
628 : 797 : struct ucl_emitter_functions func = {
629 : : .ucl_emitter_append_character = ucl_file_append_character,
630 : : .ucl_emitter_append_len = ucl_file_append_len,
631 : : .ucl_emitter_append_int = ucl_file_append_int,
632 : : .ucl_emitter_append_double = ucl_file_append_double
633 : : };
634 : :
635 [ - + ]: 797 : if (obj == NULL)
636 : 0 : return (false);
637 : :
638 : 797 : func.ud = out;
639 : :
640 : 797 : return (ucl_object_emit_full(obj, emit_type, &func, NULL));
641 : 797 : }
642 : :
643 : : bool
644 : 2017 : ucl_object_emit_buf(const ucl_object_t *obj, enum ucl_emitter emit_type,
645 : : xstring **buf)
646 : : {
647 : 2017 : bool ret = false;
648 : 2017 : struct ucl_emitter_functions func = {
649 : : .ucl_emitter_append_character = ucl_buf_append_character,
650 : : .ucl_emitter_append_len = ucl_buf_append_len,
651 : : .ucl_emitter_append_int = ucl_buf_append_int,
652 : : .ucl_emitter_append_double = ucl_buf_append_double
653 : : };
654 : :
655 [ + + ]: 2017 : xstring_renew(*buf);
656 : :
657 : 2017 : func.ud = *buf;
658 : :
659 : 2017 : ret = ucl_object_emit_full(obj, emit_type, &func, NULL);
660 : :
661 : 2017 : return (ret);
662 : : }
663 : :
664 : : /* A bit like strsep(), except it accounts for "double" and 'single'
665 : : quotes. Unlike strsep(), returns the next arg string, trimmed of
666 : : whitespace or enclosing quotes, and updates **args to point at the
667 : : character after that. Sets *args to NULL when it has been
668 : : completely consumed. Quoted strings run from the first encountered
669 : : quotemark to the next one of the same type or the terminating NULL.
670 : : Quoted strings can contain the /other/ type of quote mark, which
671 : : loses any special significance. There isn't an escape
672 : : character. */
673 : :
674 : : enum parse_states {
675 : : START,
676 : : ORDINARY_TEXT,
677 : : OPEN_SINGLE_QUOTES,
678 : : IN_SINGLE_QUOTES,
679 : : OPEN_DOUBLE_QUOTES,
680 : : IN_DOUBLE_QUOTES,
681 : : };
682 : :
683 : : char *
684 : 200 : pkg_utils_tokenize(char **args)
685 : : {
686 : : char *p, *p_start;
687 : 200 : enum parse_states parse_state = START;
688 : :
689 [ + - ]: 200 : assert(*args != NULL);
690 : :
691 [ + + ]: 594 : for (p = p_start = *args; *p != '\0'; p++) {
692 [ + + - - : 508 : switch (parse_state) {
- - ]
693 : : case START:
694 [ + - ]: 200 : if (!isspace(*p)) {
695 [ - + ]: 200 : if (*p == '"')
696 : 0 : parse_state = OPEN_DOUBLE_QUOTES;
697 [ - + ]: 200 : else if (*p == '\'')
698 : 0 : parse_state = OPEN_SINGLE_QUOTES;
699 : : else {
700 : 200 : parse_state = ORDINARY_TEXT;
701 : 200 : p_start = p;
702 : : }
703 : 200 : } else
704 : 0 : p_start = p;
705 : 200 : break;
706 : : case ORDINARY_TEXT:
707 [ + + ]: 308 : if (isspace(*p))
708 : 114 : goto finish;
709 : 194 : break;
710 : : case OPEN_SINGLE_QUOTES:
711 : 0 : p_start = p;
712 [ # # ]: 0 : if (*p == '\'')
713 : 0 : goto finish;
714 : :
715 : 0 : parse_state = IN_SINGLE_QUOTES;
716 : 0 : break;
717 : : case IN_SINGLE_QUOTES:
718 [ # # ]: 0 : if (*p == '\'')
719 : 0 : goto finish;
720 : 0 : break;
721 : : case OPEN_DOUBLE_QUOTES:
722 : 0 : p_start = p;
723 [ # # ]: 0 : if (*p == '"')
724 : 0 : goto finish;
725 : 0 : parse_state = IN_DOUBLE_QUOTES;
726 : 0 : break;
727 : : case IN_DOUBLE_QUOTES:
728 [ # # ]: 0 : if (*p == '"')
729 : 0 : goto finish;
730 : 0 : break;
731 : : }
732 : 480 : }
733 : :
734 : : finish:
735 [ + + ]: 200 : if (*p == '\0')
736 : 86 : *args = NULL; /* All done */
737 : : else {
738 : 114 : *p = '\0';
739 : 114 : p++;
740 : 114 : if (*p == '\0' || parse_state == START)
741 : 0 : *args = NULL; /* whitespace or nothing left */
742 : : else
743 : 114 : *args = p;
744 : : }
745 : 200 : return (p_start);
746 : : }
747 : :
748 : : int
749 : 86 : pkg_utils_count_spaces(const char *args)
750 : : {
751 : : int spaces;
752 : : const char *p;
753 : :
754 [ + + ]: 594 : for (spaces = 0, p = args; *p != '\0'; p++)
755 : 622 : if (isspace(*p))
756 : 114 : spaces++;
757 : :
758 : 86 : return (spaces);
759 : : }
760 : :
761 : : /* unlike realpath(3), this routine does not expand symbolic links */
762 : : char *
763 : 4046 : pkg_absolutepath(const char *src, char *dest, size_t dest_size, bool fromroot) {
764 : : size_t dest_len, src_len, cur_len;
765 : : const char *cur, *next;
766 : :
767 : 4046 : src_len = strlen(src);
768 : 4046 : bzero(dest, dest_size);
769 : 4046 : if (src_len != 0 && src[0] != '/') {
770 [ # # ]: 0 : if (fromroot)
771 : 0 : *dest = '/';
772 : : /* relative path, we use cwd */
773 [ # # ]: 0 : else if (getcwd(dest, dest_size) == NULL)
774 : 0 : return (NULL);
775 : 0 : }
776 : 4046 : dest_len = strlen(dest);
777 : :
778 [ + + + + ]: 26801 : for (cur = next = src; next != NULL; cur = (next == NULL) ? NULL : next + 1) {
779 : 22755 : next = strchr(cur, '/');
780 [ + + ]: 22755 : if (next != NULL)
781 : 18709 : cur_len = next - cur;
782 : : else
783 : 4046 : cur_len = strlen(cur);
784 : :
785 : : /* check for special cases "", "." and ".." */
786 [ + + ]: 22755 : if (cur_len == 0)
787 : 4186 : continue;
788 : 18569 : else if (cur_len == 1 && cur[0] == '.')
789 : 0 : continue;
790 : 1099 : else if (cur_len == 2 && cur[0] == '.' && cur[1] == '.') {
791 : 0 : const char *slash = strrchr(dest, '/');
792 : 0 : if (slash != NULL) {
793 : 0 : dest_len = slash - dest;
794 : 0 : dest[dest_len] = '\0';
795 : 0 : }
796 : 0 : continue;
797 : : }
798 : :
799 [ - + ]: 18569 : if (dest_len + 1 + cur_len >= dest_size)
800 : 0 : return (NULL);
801 : 18569 : dest[dest_len++] = '/';
802 : 18569 : (void)memcpy(dest + dest_len, cur, cur_len);
803 : 18569 : dest_len += cur_len;
804 : 18569 : dest[dest_len] = '\0';
805 : 18569 : }
806 : :
807 : 4046 : if (dest_len == 0) {
808 [ # # ]: 0 : if (strlcpy(dest, "/", dest_size) >= dest_size)
809 : 0 : return (NULL);
810 : 0 : }
811 : :
812 : 4046 : return (dest);
813 : 4046 : }
814 : :
815 : : bool
816 : 120 : mkdirat_p(int fd, const char *path)
817 : : {
818 : : const char *next;
819 : : char *walk, *walkorig, pathdone[MAXPATHLEN];
820 : :
821 : 120 : walk = walkorig = xstrdup(path);
822 : 120 : pathdone[0] = '\0';
823 : :
824 [ + + ]: 596 : while ((next = strsep(&walk, "/")) != NULL) {
825 [ + + ]: 476 : if (*next == '\0')
826 : 4 : continue;
827 : 472 : strlcat(pathdone, next, sizeof(pathdone));
828 [ + + ]: 472 : if (mkdirat(fd, pathdone, 0755) == -1) {
829 [ + - ]: 80 : if (errno == EEXIST) {
830 : 80 : strlcat(pathdone, "/", sizeof(pathdone));
831 : 80 : continue;
832 : : }
833 : 0 : pkg_errno("Fail to create /%s", pathdone);
834 : 0 : free(walkorig);
835 : 0 : return (false);
836 : : }
837 : 392 : strlcat(pathdone, "/", sizeof(pathdone));
838 : : }
839 : 120 : free(walkorig);
840 : 120 : return (true);
841 : 120 : }
842 : :
843 : : int
844 : 180 : pkg_namecmp(struct pkg *a, struct pkg *b)
845 : : {
846 : :
847 : 180 : return (strcmp(a->name, b->name));
848 : : }
849 : :
850 : : int
851 : 835 : get_socketpair(int *pipe)
852 : : {
853 : : int r;
854 : :
855 : : #ifdef HAVE_DECL_SOCK_SEQPACKET
856 : 835 : r = socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, pipe);
857 : 835 : if (r == -1) {
858 : 0 : r = socketpair(AF_LOCAL, SOCK_DGRAM, 0, pipe);
859 : 0 : }
860 : : #else
861 : : r = socketpair(AF_LOCAL, SOCK_DGRAM, 0, pipe);
862 : : #endif
863 : :
864 : 835 : return (r);
865 : : }
866 : :
867 : : char *
868 : 280 : get_dirname(char *d)
869 : : {
870 : : char *walk;
871 : :
872 [ - + ]: 280 : if (d == NULL)
873 : 0 : return (__DECONST(char *, "."));
874 : :
875 : 280 : walk = strrchr(d, '/');
876 [ + + ]: 280 : if (walk == NULL) {
877 : 108 : d[0] = '.';
878 : 108 : d[1] = '\0';
879 : 108 : } else {
880 : 172 : *walk = '\0';
881 : : }
882 : :
883 : 280 : return (d);
884 : 280 : }
885 : :
886 : : char *
887 : 181 : rtrimspace(char *buf)
888 : : {
889 : 181 : char *cp = buf + strlen(buf) -1;
890 : :
891 [ + + ]: 194 : while (cp > buf && isspace(*cp)) {
892 : 13 : *cp = 0;
893 : 13 : cp --;
894 : : }
895 : :
896 : 181 : return (buf);
897 : : }
|