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