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