/ libpkg / utils.c
utils.c
   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   * Copyright (c) 2023 Serenity Cyber Security, LLC
   6   *                    Author: Gleb Popov <arrowd@FreeBSD.org>
   7   * All rights reserved.
   8   *
   9   * Redistribution and use in source and binary forms, with or without
  10   * modification, are permitted provided that the following conditions
  11   * are met:
  12   * 1. Redistributions of source code must retain the above copyright
  13   *    notice, this list of conditions and the following disclaimer
  14   *    in this position and unchanged.
  15   * 2. Redistributions in binary form must reproduce the above copyright
  16   *    notice, this list of conditions and the following disclaimer in the
  17   *    documentation and/or other materials provided with the distribution.
  18   *
  19   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
  20   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22   * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
  23   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29   */
  30  
  31  #include <pkg_config.h>
  32  
  33  #include <sys/socket.h>
  34  #include <sys/stat.h>
  35  #include <sys/param.h>
  36  #include <stdio.h>
  37  
  38  #include <assert.h>
  39  #include <errno.h>
  40  #include <fcntl.h>
  41  #include <stdlib.h>
  42  #include <unistd.h>
  43  #include <string.h>
  44  #include <ucl.h>
  45  #include <utlist.h>
  46  #include <ctype.h>
  47  #include <fnmatch.h>
  48  #include <paths.h>
  49  #include <float.h>
  50  #include <math.h>
  51  #include <regex.h>
  52  #include <pwd.h>
  53  #include <grp.h>
  54  
  55  #include <bsd_compat.h>
  56  
  57  #include "pkg.h"
  58  #include "pkg/vec.h"
  59  #include "private/event.h"
  60  #include "private/pkg_abi.h"
  61  #include "private/utils.h"
  62  #include "private/pkg.h"
  63  #include "xmalloc.h"
  64  
  65  extern struct pkg_ctx ctx;
  66  
  67  bool
  68  match_ucl_lists(const char *buf, const ucl_object_t *globs, const ucl_object_t *regexes)
  69  {
  70  	const ucl_object_t *cur;
  71  	ucl_object_iter_t it;
  72  
  73  	if (globs == NULL && regexes == NULL)
  74  		return (false);
  75  
  76  	if (globs != NULL) {
  77  		it = NULL;
  78  		while ((cur = ucl_iterate_object(globs, &it, true))) {
  79  			if (fnmatch(ucl_object_tostring(cur), buf, 0) == 0)
  80  				return (true);
  81  		}
  82  	}
  83  
  84  	if (regexes != NULL) {
  85  		it = NULL;
  86  		while ((cur = ucl_iterate_object(regexes, &it, true))) {
  87  			regex_t re;
  88  			regcomp(&re, ucl_object_tostring(cur),
  89  			   REG_EXTENDED|REG_NOSUB);
  90  			if (regexec(&re, buf, 0, NULL, 0) == 0) {
  91  				regfree(&re);
  92  				return (true);
  93  			}
  94  			regfree(&re);
  95  		}
  96  	}
  97  
  98  	return (false);
  99  }
 100  
 101  /* Check if two absolute directory paths are equal, collapsing consecutive
 102   * path separators and ignoring trailing path separators. */
 103  static bool
 104  dir_paths_equal(const char *a, const char *b)
 105  {
 106  	assert(a != NULL);
 107  	assert(b != NULL);
 108  	assert(*a == '/');
 109  	assert(*b == '/');
 110  
 111  	while (*a == *b) {
 112  		if (*a == '\0') {
 113  			return (true);
 114  		}
 115  
 116  		/* Skip over consecutive path separators */
 117  		if (*a == '/') {
 118  			while (*a == '/') a++;
 119  			while (*b == '/') b++;
 120  		} else {
 121  			a++;
 122  			b++;
 123  		}
 124  	}
 125  
 126  	/* There may be trailing path separators on one path but not the other */
 127  	while (*a == '/') a++;
 128  	while (*b == '/') b++;
 129  
 130  	return (*a == *b);
 131  }
 132  
 133  /*
 134   * Given a ucl list of directory paths, check if the file is in one of the
 135   * directories in the list (subdirectories not included).
 136   *
 137   * Asserts that file is an absolute path that does not end in /. */
 138  bool
 139  pkg_match_paths_list(const ucl_object_t *paths, const char *file)
 140  {
 141  	assert(file != NULL);
 142  	assert(file[0] == '/');
 143  
 144  	char *copy = xstrdup(file);
 145  	char *final_slash = strrchr(copy, '/');
 146  	assert(final_slash != NULL);
 147  	assert(*(final_slash + 1) != '\0');
 148  	if (final_slash == copy) {
 149  		*(final_slash + 1) = '\0';
 150  	} else {
 151  		*final_slash = '\0';
 152  	}
 153  	const char *dirname = copy;
 154  
 155  	bool found = false;
 156  	const ucl_object_t *cur;
 157  	ucl_object_iter_t it = NULL;
 158  	while ((cur = ucl_object_iterate(paths, &it, true))) {
 159  		if (dir_paths_equal(dirname, ucl_object_tostring(cur))) {
 160  			found = true;
 161  			break;
 162  		}
 163  	}
 164  
 165  	free(copy);
 166  
 167  	return (found);
 168  }
 169  
 170  int
 171  pkg_mkdirs(const char *_path)
 172  {
 173  	char path[MAXPATHLEN];
 174  	char *p;
 175  	int dirfd;
 176  
 177  	dirfd = open(_path, O_RDONLY|O_DIRECTORY);
 178  	if (dirfd >= 0) {
 179  		close(dirfd);
 180  		return EPKG_OK;
 181  	}
 182  
 183  	strlcpy(path, _path, sizeof(path));
 184  	p = path;
 185  	while (*p == '/')
 186  		p++;
 187  
 188  	for (;;) {
 189  		if ((p = strchr(p, '/')) != NULL)
 190  			*p = '\0';
 191  
 192  		if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
 193  			if (errno != EEXIST && errno != EISDIR) {
 194  				pkg_emit_errno("mkdir", path);
 195  				return (EPKG_FATAL);
 196  			}
 197  
 198  		/* that was the last element of the path */
 199  		if (p == NULL)
 200  			break;
 201  
 202  		*p = '/';
 203  		p++;
 204  	}
 205  
 206  	return (EPKG_OK);
 207  }
 208  int
 209  file_to_bufferat(int dfd, const char *path, char **buffer, off_t *sz)
 210  {
 211  	int fd = -1;
 212  	struct stat st;
 213  	int retcode = EPKG_OK;
 214  
 215  	assert(path != NULL && path[0] != '\0');
 216  	assert(buffer != NULL);
 217  	assert(sz != NULL);
 218  
 219  	if ((fd = openat(dfd, path, O_RDONLY)) == -1) {
 220  		pkg_emit_errno("openat", path);
 221  		retcode = EPKG_FATAL;
 222  		goto cleanup;
 223  	}
 224  
 225  	if (fstat(fd, &st) == -1) {
 226  		pkg_emit_errno("fstatat", path);
 227  		retcode = EPKG_FATAL;
 228  		goto cleanup;
 229  	}
 230  
 231  	*buffer = xmalloc(st.st_size + 1);
 232  
 233  	if (read(fd, *buffer, st.st_size) == -1) {
 234  		pkg_emit_errno("read", path);
 235  		retcode = EPKG_FATAL;
 236  		goto cleanup;
 237  	}
 238  
 239  cleanup:
 240  	if (fd >= 0)
 241  		close(fd);
 242  
 243  	if (retcode == EPKG_OK) {
 244  		(*buffer)[st.st_size] = '\0';
 245  		*sz = st.st_size;
 246  	} else {
 247  		free(*buffer);
 248  		*buffer = NULL;
 249  		*sz = -1;
 250  	}
 251  	return (retcode);
 252  }
 253  
 254  int
 255  file_to_buffer(const char *path, char **buffer, off_t *sz)
 256  {
 257  	return file_to_bufferat(AT_FDCWD, path, buffer, sz);
 258  }
 259  
 260  int
 261  format_exec_cmd(char **dest, const char *in, const char *prefix,
 262      const char *plist_file, const char *line, int argc, char **argv, bool lua)
 263  {
 264  	xstring *buf;
 265  	char path[MAXPATHLEN];
 266  	char *cp;
 267  	const char *ptr;
 268  	size_t sz;
 269  
 270  	buf = xstring_new();
 271  	cp = NULL;
 272  
 273  	if (line != NULL && argv != NULL) {
 274  		if (lua) {
 275  			fprintf(buf->fp, "-- args: %s\n", line);
 276  		} else {
 277  			fprintf(buf->fp, "# args: %s\n", line);
 278  		}
 279  	}
 280  
 281  	while (in[0] != '\0') {
 282  		if (in[0] != '%') {
 283  			fputc(in[0], buf->fp);
 284  			in++;
 285  			continue;
 286  		}
 287  		in++;
 288  		switch(in[0]) {
 289  		case 'D':
 290  			fprintf(buf->fp, "%s", prefix);
 291  			break;
 292  		case 'F':
 293  			if (plist_file == NULL || plist_file[0] == '\0') {
 294  				pkg_emit_error("No files defined %%F couldn't "
 295  				    "be expanded, ignoring %s", in);
 296  				xstring_free(buf);
 297  				return (EPKG_FATAL);
 298  			}
 299  			fprintf(buf->fp, "%s", plist_file);
 300  			break;
 301  		case 'f':
 302  			if (plist_file == NULL || plist_file[0] == '\0') {
 303  				pkg_emit_error("No files defined %%f couldn't "
 304  				    "be expanded, ignoring %s", in);
 305  				xstring_free(buf);
 306  				return (EPKG_FATAL);
 307  			}
 308  			ptr = strrchr(plist_file, '/');
 309  			if (ptr != NULL)
 310  				ptr++;
 311  			else
 312  				ptr = plist_file;
 313  			fprintf(buf->fp, "%s", ptr);
 314  			break;
 315  		case 'B':
 316  			if (plist_file == NULL || plist_file[0] == '\0') {
 317  				pkg_emit_error("No files defined %%B couldn't "
 318  				    "be expanded, ignoring %s", in);
 319  				xstring_free(buf);
 320  				return (EPKG_FATAL);
 321  			}
 322  			if (prefix[strlen(prefix) - 1] == '/')
 323  				snprintf(path, sizeof(path), "%s%s", prefix,
 324  				    plist_file);
 325  			else
 326  				snprintf(path, sizeof(path), "%s/%s", prefix,
 327  				    plist_file);
 328  			cp = strrchr(path, '/');
 329  			cp[0] = '\0';
 330  			fprintf(buf->fp, "%s", path);
 331  			break;
 332  		case '%':
 333  			fputc('%', buf->fp);
 334  			break;
 335  		case '@':
 336  			if (line != NULL) {
 337  				fprintf(buf->fp, "%s", line);
 338  				break;
 339  			}
 340  
 341  			/*
 342  			 * no break here because if line is not
 343  			 * given (default exec) %@ does not
 344  			 * exists
 345  			 */
 346  			/* FALLTHRU */
 347  		case '#':
 348  			fprintf(buf->fp, "%d", argc);
 349  			break;
 350  		default:
 351  			if ((sz = strspn(in, "0123456789")) > 0) {
 352  				int pos = strtol(in, NULL, 10);
 353  				if (pos > argc) {
 354  					pkg_emit_error("Requesting argument "
 355  					    "%%%d while only %d arguments are"
 356  					    " available", pos, argc);
 357  					xstring_free(buf);
 358  					return (EPKG_FATAL);
 359  				}
 360  				fprintf(buf->fp, "%s", argv[pos -1]);
 361  				in += sz -1;
 362  				break;
 363  			}
 364  			fprintf(buf->fp, "%c%c", '%', in[0]);
 365  			break;
 366  		}
 367  
 368  		in++;
 369  	}
 370  
 371  	*dest = xstring_get(buf);
 372  
 373  	return (EPKG_OK);
 374  }
 375  
 376  int
 377  is_dir(const char *path)
 378  {
 379  	struct stat st;
 380  
 381  	return (stat(path, &st) == 0 && S_ISDIR(st.st_mode));
 382  }
 383  
 384  int
 385  is_link(const char *path)
 386  {
 387  	struct stat st;
 388  
 389  	return (lstat(path, &st) == 0 && S_ISLNK(st.st_mode));
 390  }
 391  
 392  bool
 393  check_for_hardlink(hardlinks_t *hl, struct stat *st)
 394  {
 395  	struct hardlink *h;
 396  
 397  	vec_foreach(*hl, i) {
 398  		h = hl->d[i];
 399  		if (h->ino == st->st_ino &&
 400  		    h->dev == st->st_dev)
 401  			return (true);
 402  	}
 403  	h = xcalloc(1, sizeof(*h));
 404  	h->ino = st->st_ino;
 405  	h->dev = st->st_dev;
 406  	vec_push(hl, h);
 407  
 408  	return (false);
 409  }
 410  
 411  /*
 412   * ABI validation:
 413   * - lowest match (case insensitive)
 414   * - glob matching
 415   *
 416   * A package which is valid for installation on any FreeBSD now simply has
 417   * to define itself as: abi: "FreeBSD" or "FreeBSD:*"
 418   * A package which is valid for installation on any FreeBSD 15 regarless of
 419   * the arch
 420   * abi: "FreeBSD:15" or "FreeBSD:15:*"
 421   *
 422   */
 423  
 424  bool
 425  is_valid_abi(const char *testabi, bool emit_error)
 426  {
 427  	const char *abi = pkg_object_string(pkg_config_get("ABI"));
 428  
 429  	if (strncasecmp(testabi, abi, strlen(testabi)) != 0 &&
 430  	    fnmatch(testabi, abi, FNM_CASEFOLD) == FNM_NOMATCH) {
 431  		if (emit_error)
 432  			pkg_emit_error("wrong architecture: %s instead of %s",
 433  			    testabi, abi);
 434  		return (false);
 435  	}
 436  
 437  	return (true);
 438  }
 439  
 440  bool
 441  is_valid_os_version(struct pkg *pkg)
 442  {
 443  	if (ctx.abi.os != PKG_OS_FREEBSD)
 444  		return (true);
 445  	const char *fbsd_version;
 446  	const char *errstr = NULL;
 447  	char query_buf[512];
 448  	/* -1: not checked, 0: not allowed, 1: allowed */
 449  	static int osver_mismatch_allowed = -1;
 450  	bool ret;
 451  
 452  	if (pkg_object_bool(pkg_config_get("IGNORE_OSVERSION")))
 453  		return (true);
 454  	if ((fbsd_version = pkg_kv_get(&pkg->annotations, "FreeBSD_version")) != NULL) {
 455  		int pkg_osversion = strtonum(fbsd_version, 1, INT_MAX, &errstr);
 456  		if (errstr != NULL) {
 457  			pkg_emit_error("Invalid FreeBSD version %s for package %s",
 458  			    fbsd_version, pkg->name);
 459  			return (false);
 460  		}
 461  		int abi_osversion = pkg_abi_get_freebsd_osversion(&ctx.abi);
 462  		if (pkg_osversion > abi_osversion) {
 463  			if (pkg_osversion - abi_osversion < 100000) {
 464  				/* Negligible difference, ask user to enforce */
 465  				if (osver_mismatch_allowed == -1) {
 466  					snprintf(query_buf, sizeof(query_buf),
 467  							"Newer FreeBSD version for package %s:\n"
 468  							"To ignore this error set IGNORE_OSVERSION=yes\n"
 469  							"- package: %d\n"
 470  							"- running userland: %d\n"
 471  							"Ignore the mismatch and continue? ", pkg->name,
 472  							pkg_osversion, abi_osversion);
 473  					ret = pkg_emit_query_yesno(false, query_buf);
 474  					osver_mismatch_allowed = ret;
 475  				}
 476  
 477  				return (osver_mismatch_allowed);
 478  			}
 479  			else {
 480  				pkg_emit_error("Newer FreeBSD version for package %s:\n"
 481  					"To ignore this error set IGNORE_OSVERSION=yes\n"
 482  					"- package: %d\n"
 483  					"- running kernel: %d\n",
 484  					pkg->name,
 485  					pkg_osversion, abi_osversion);
 486  				return (false);
 487  			}
 488  		}
 489  	}
 490  	return (true);
 491  }
 492  
 493  void
 494  set_nonblocking(int fd)
 495  {
 496  	int flags;
 497  
 498  	if ((flags = fcntl(fd, F_GETFL)) == -1)
 499  		return;
 500  	if (!(flags & O_NONBLOCK)) {
 501  		flags |= O_NONBLOCK;
 502  		fcntl(fd, F_SETFL, flags);
 503  	}
 504  }
 505  
 506  void
 507  set_blocking(int fd)
 508  {
 509  	int flags;
 510  
 511  	if ((flags = fcntl(fd, F_GETFL)) == -1)
 512  		return;
 513  	if (flags & O_NONBLOCK) {
 514  		flags &= ~O_NONBLOCK;
 515  		fcntl(fd, F_SETFL, flags);
 516  	}
 517  }
 518  
 519  /* Spawn a process from pfunc, returning it's pid. The fds array passed will
 520   * be filled with two descriptors: fds[0] will read from the child process,
 521   * and fds[1] will write to it.
 522   * Similarly, the child process will receive a reading/writing fd set (in
 523   * that same order) as arguments.
 524  */
 525  extern char **environ;
 526  pid_t
 527  process_spawn_pipe(FILE *inout[2], const char *command)
 528  {
 529  	pid_t pid;
 530  	int pipes[4];
 531  	char *argv[4];
 532  
 533  	/* Parent read/child write pipe */
 534  	if (pipe(&pipes[0]) == -1)
 535  		return (-1);
 536  
 537  	/* Child read/parent write pipe */
 538  	if (pipe(&pipes[2]) == -1) {
 539  		close(pipes[0]);
 540  		close(pipes[1]);
 541  		return (-1);
 542  	}
 543  
 544  	argv[0] = __DECONST(char *, "sh");
 545  	argv[1] = __DECONST(char *, "-c");
 546  	argv[2] = __DECONST(char *, command);
 547  	argv[3] = NULL;
 548  
 549  	pid = fork();
 550  	if (pid > 0) {
 551  		/* Parent process */
 552  		inout[0] = fdopen(pipes[0], "r");
 553  		inout[1] = fdopen(pipes[3], "w");
 554  
 555  		close(pipes[1]);
 556  		close(pipes[2]);
 557  
 558  		return (pid);
 559  
 560  	} else if (pid == 0) {
 561  		close(pipes[0]);
 562  		close(pipes[3]);
 563  
 564  		if (pipes[1] != STDOUT_FILENO) {
 565  			dup2(pipes[1], STDOUT_FILENO);
 566  			close(pipes[1]);
 567  		}
 568  		if (pipes[2] != STDIN_FILENO) {
 569  			dup2(pipes[2], STDIN_FILENO);
 570  			close(pipes[2]);
 571  		}
 572  		closefrom(STDERR_FILENO + 1);
 573  
 574  		execve(_PATH_BSHELL, argv, environ);
 575  
 576  		_exit(127);
 577  	}
 578  
 579  	return (-1); /* ? */
 580  }
 581  
 582  static int
 583  ucl_buf_append_character(unsigned char c, size_t len, void *data)
 584  {
 585  	xstring *buf = data;
 586  	size_t i;
 587  
 588  	for (i = 0; i < len; i++)
 589  		fprintf(buf->fp, "%c", c);
 590  
 591  	return (0);
 592  }
 593  
 594  static int
 595  ucl_buf_append_len(const unsigned char *str, size_t len, void *data)
 596  {
 597  	xstring *buf = data;
 598  
 599  	fprintf(buf->fp, "%.*s", (int)len, str);
 600  
 601  	return (0);
 602  }
 603  
 604  static int
 605  ucl_buf_append_int(int64_t val, void *data)
 606  {
 607  	xstring *buf = data;
 608  
 609  	fprintf(buf->fp, "%"PRId64, val);
 610  
 611  	return (0);
 612  }
 613  
 614  static int
 615  ucl_buf_append_double(double val, void *data)
 616  {
 617  	xstring *buf = data;
 618  	const double delta = 0.0000001;
 619  
 620  	if (val == (double)(int)val) {
 621  		fprintf(buf->fp, "%.1lf", val);
 622  	} else if (fabs(val - (double)(int)val) < delta) {
 623  		fprintf(buf->fp, "%.*lg", DBL_DIG, val);
 624  	} else {
 625  		fprintf(buf->fp, "%lf", val);
 626  	}
 627  
 628  	return (0);
 629  }
 630  
 631  bool
 632  ucl_object_emit_file(const ucl_object_t *obj, enum ucl_emitter emit_type,
 633      FILE *out)
 634  {
 635  	struct ucl_emitter_functions *f = ucl_object_emit_file_funcs(out);
 636  	bool ret = false;
 637  
 638  	if (obj == NULL)
 639  		return (false);
 640  
 641  	ret = ucl_object_emit_full(obj, emit_type, f, NULL);
 642  	ucl_object_emit_funcs_free(f);
 643  
 644  	return (ret);
 645  }
 646  
 647  bool
 648  ucl_object_emit_fd(const ucl_object_t *obj, enum ucl_emitter emit_type, int fd)
 649  {
 650  	struct ucl_emitter_functions *f = ucl_object_emit_fd_funcs(fd);
 651  	bool ret = false;
 652  
 653  	if (obj == NULL)
 654  		return (false);
 655  	ret = ucl_object_emit_full(obj, emit_type, f, NULL);
 656  	ucl_object_emit_funcs_free(f);
 657  
 658  	return (ret);
 659  }
 660  
 661  
 662  bool
 663  ucl_object_emit_buf(const ucl_object_t *obj, enum ucl_emitter emit_type,
 664                       xstring **buf)
 665  {
 666  	bool ret = false;
 667  	struct ucl_emitter_functions func = {
 668  		.ucl_emitter_append_character = ucl_buf_append_character,
 669  		.ucl_emitter_append_len = ucl_buf_append_len,
 670  		.ucl_emitter_append_int = ucl_buf_append_int,
 671  		.ucl_emitter_append_double = ucl_buf_append_double
 672  	};
 673  
 674  	xstring_renew(*buf);
 675  
 676  	func.ud = *buf;
 677  
 678  	ret = ucl_object_emit_full(obj, emit_type, &func, NULL);
 679  
 680  	return (ret);
 681  }
 682  
 683  /* A bit like strsep(), except it accounts for "double" and 'single'
 684     quotes.  Unlike strsep(), returns the next arg string, trimmed of
 685     whitespace or enclosing quotes, and updates **args to point at the
 686     character after that.  Sets *args to NULL when it has been
 687     completely consumed.  Quoted strings run from the first encountered
 688     quotemark to the next one of the same type or the terminating NULL.
 689     Quoted strings can contain the /other/ type of quote mark, which
 690     loses any special significance.  There isn't an escape
 691     character. */
 692  
 693  enum parse_states {
 694  	START,
 695  	ORDINARY_TEXT,
 696  	OPEN_SINGLE_QUOTES,
 697  	IN_SINGLE_QUOTES,
 698  	OPEN_DOUBLE_QUOTES,
 699  	IN_DOUBLE_QUOTES,
 700  };
 701  
 702  char *
 703  pkg_utils_tokenize(char **args)
 704  {
 705  	char			*p, *p_start;
 706  	enum parse_states	 parse_state = START;
 707  
 708  	assert(*args != NULL);
 709  
 710  	for (p = p_start = *args; *p != '\0'; p++) {
 711  		switch (parse_state) {
 712  		case START:
 713  			if (!isspace(*p)) {
 714  				if (*p == '"')
 715  					parse_state = OPEN_DOUBLE_QUOTES;
 716  				else if (*p == '\'')
 717  					parse_state = OPEN_SINGLE_QUOTES;
 718  				else {
 719  					parse_state = ORDINARY_TEXT;
 720  					p_start = p;
 721  				}
 722  			} else
 723  				p_start = p;
 724  			break;
 725  		case ORDINARY_TEXT:
 726  			if (isspace(*p))
 727  				goto finish;
 728  			break;
 729  		case OPEN_SINGLE_QUOTES:
 730  			p_start = p;
 731  			if (*p == '\'')
 732  				goto finish;
 733  
 734  			parse_state = IN_SINGLE_QUOTES;
 735  			break;
 736  		case IN_SINGLE_QUOTES:
 737  			if (*p == '\'')
 738  				goto finish;
 739  			break;
 740  		case OPEN_DOUBLE_QUOTES:
 741  			p_start = p;
 742  			if (*p == '"')
 743  				goto finish;
 744  			parse_state = IN_DOUBLE_QUOTES;
 745  			break;
 746  		case IN_DOUBLE_QUOTES:
 747  			if (*p == '"')
 748  				goto finish;
 749  			break;
 750  		}
 751  	}
 752  
 753  finish:
 754  	if (*p == '\0')
 755  		*args = NULL;	/* All done */
 756  	else {
 757  		*p = '\0';
 758  		p++;
 759  		if (*p == '\0' || parse_state == START)
 760  			*args = NULL; /* whitespace or nothing left */
 761  		else
 762  			*args = p;
 763  	}
 764  	return (p_start);
 765  }
 766  
 767  int
 768  pkg_utils_count_spaces(const char *args)
 769  {
 770  	int		spaces;
 771  	const char	*p;
 772  
 773  	for (spaces = 0, p = args; *p != '\0'; p++)
 774  		if (isspace(*p))
 775  			spaces++;
 776  
 777  	return (spaces);
 778  }
 779  
 780  /* unlike realpath(3), this routine does not expand symbolic links */
 781  char *
 782  pkg_absolutepath(const char *src, char *dest, size_t dest_size, bool fromroot) {
 783  	size_t dest_len, src_len, cur_len;
 784  	const char *cur, *next;
 785  
 786  	src_len = strlen(src);
 787  	memset(dest, '\0', dest_size);
 788  
 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
 836  mkdirat_p(int fd, const char *path)
 837  {
 838  	const char *next;
 839  	char pathdone[MAXPATHLEN], walkbuf[MAXPATHLEN], *walk;
 840  
 841  	pathdone[0] = '\0';
 842  	strlcpy(walkbuf, path, sizeof(walkbuf));
 843  	walk = walkbuf;
 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("Failed to create /%s", pathdone);
 854  			return (false);
 855  		}
 856  		strlcat(pathdone, "/", sizeof(pathdone));
 857  	}
 858  	return (true);
 859  }
 860  
 861  int
 862  pkg_namecmp(struct pkg *a, struct pkg *b)
 863  {
 864  
 865  	return (strcmp(a->name, b->name));
 866  }
 867  
 868  int
 869  get_socketpair(int *pipe)
 870  {
 871  	int r;
 872  
 873  #ifdef SOCK_SEQPACKET
 874  	r = socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, pipe);
 875  	if (r == -1) {
 876  		r = socketpair(AF_LOCAL, SOCK_DGRAM, 0, pipe);
 877  	}
 878  #else
 879  	r = socketpair(AF_LOCAL, SOCK_DGRAM, 0, pipe);
 880  #endif
 881  
 882  	return (r);
 883  }
 884  
 885  /*
 886   * Modify the passed C-String by stripping off the last component delimited by '/'.
 887   * Return the string. Return a constant "." when passed NULL or the empty string.
 888   * FIXME: This routine corrupts memory when passed the empty string.
 889   * FIXME: This routine should propagate NULL.
 890   * TODO: Refactor at call sites.
 891   */
 892  char *
 893  get_dirname(char *d)
 894  {
 895  	char *walk;
 896  
 897  	if (d == NULL)
 898  		return (__DECONST(char *, "."));
 899  
 900  	walk = strrchr(d, '/');
 901  	if (walk == NULL) {
 902  		d[0] = '.';
 903  		d[1] = '\0';
 904  	} else {
 905  		*walk = '\0';
 906  	}
 907  
 908  	return (d);
 909  }
 910  
 911  char *
 912  rtrimspace(char *buf)
 913  {
 914  	char *cp = buf + strlen(buf) -1;
 915  
 916  	while (cp > buf && isspace(*cp)) {
 917  		*cp = 0;
 918  		cp --;
 919  	}
 920  
 921  	return (buf);
 922  }
 923  
 924  static ssize_t
 925  _copy_file(int from, int to)
 926  {
 927  	char buf[BUFSIZ];
 928  	ssize_t r, wresid, w = 0;
 929  	char *bufp;
 930  
 931  	r = read(from, buf, sizeof(buf));
 932  	if (r < 0)
 933  		return (r);
 934  	for (bufp = buf, wresid = r; ; bufp += w, wresid -= w) {
 935  		w = write(to, bufp, wresid);
 936  		if (w <= 0)
 937  			break;
 938  		if (w >= (ssize_t)wresid)
 939  			break;
 940  	}
 941  	return (w < 0 ? w : r);
 942  }
 943  
 944  bool
 945  pkg_copy_file(int from, int to)
 946  {
 947  #ifdef HAVE_COPY_FILE_RANGE
 948  	bool cfr = true;
 949  #endif
 950  	ssize_t r;
 951  
 952  	do {
 953  #ifdef HAVE_COPY_FILE_RANGE
 954  		if (cfr) {
 955  			r = copy_file_range(from, NULL, to, NULL, SSIZE_MAX, 0);
 956  			if (r < 0 && (errno == EINVAL || errno == EXDEV)) {
 957  				/* probably a non seekable FD */
 958  				cfr = false;
 959  			}
 960  		}
 961  		if (!cfr) {
 962  #endif
 963  			r = _copy_file(from, to);
 964  #ifdef HAVE_COPY_FILE_RANGE
 965  		}
 966  #endif
 967  	} while (r > 0);
 968  
 969  	return (r >= 0);
 970  }
 971  
 972  static const unsigned char litchar[] =
 973  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 974  
 975  void
 976  append_random_suffix(char *buf, int buflen, int suflen)
 977  {
 978  	int nchars = strlen(buf);
 979  	char *pos;
 980  	int r;
 981  
 982  	/* 2 being the "." and the \0 */
 983  	if (nchars + suflen > buflen - 2) {
 984  		suflen = buflen - nchars - 2;
 985  		if (suflen <= 0)
 986  			return;
 987  	}
 988  
 989  	buf[nchars++] = '.';
 990  	pos = buf + nchars;
 991  
 992  	while(suflen --) {
 993  #ifndef HAVE_ARC4RANDOM
 994  		r = rand() % (sizeof(litchar) - 1);
 995  #else
 996  		r = arc4random_uniform(sizeof(litchar) - 1);
 997  #endif
 998  		*pos++ = litchar[r];
 999  	}
1000  
1001  	*pos = '\0';
1002  }
1003  
1004  void
1005  hidden_tempfile(char *buf, int buflen, const char *path)
1006  {
1007  	const char *fname;
1008  	int suffixlen = 12;
1009  	int nbuflen;
1010  	const char *prefix = ".pkgtemp.";
1011  
1012  	fname = strrchr(path, '/');
1013  	if (fname != NULL)
1014  		fname++;
1015  
1016  	/*
1017  	 * try to reduce the temporary name as much as possible to fit with very
1018  	 * long file names if possible. by default
1019  	 * .pkgtemp. fname . <suffix>
1020  	 * otherwise
1021  	 * . fname . <suffix>
1022  	 * keep if suffix of at least 5 if possible
1023  	 */
1024  	if (fname != NULL) {
1025  		if (strlen(fname) >= (NAME_MAX - 15))
1026  			prefix = ".";
1027  		snprintf(buf, buflen, "%.*s%s%s", (int)(fname - path), path, prefix, fname);
1028  		nbuflen = buflen;
1029  	} else {
1030  		if (strlen(path) >= NAME_MAX - 15)
1031  			prefix = ".";
1032  		snprintf(buf, buflen, "%s%s", prefix, path);
1033  		nbuflen = NAME_MAX;
1034  	}
1035  
1036  
1037  	append_random_suffix(buf, nbuflen, suffixlen);
1038  }
1039  
1040  char *
1041  json_escape(const char *str)
1042  {
1043  	xstring *buf = xstring_new();
1044  
1045  	while (str != NULL && *str != '\0') {
1046  		if (*str == '"' || *str == '\\')
1047  			fputc('\\', buf->fp);
1048  		fputc(*str, buf->fp);
1049  		str++;
1050  	}
1051  
1052  	return (xstring_get(buf));
1053  }
1054  
1055  const char *
1056  get_http_auth(void)
1057  {
1058  	const char *str = getenv("HTTP_AUTH");
1059  	if (str == NULL)
1060  		return (NULL);
1061  	if ((str = strchr(str, ':')) == NULL) {
1062  		pkg_emit_error("malformed HTTP_AUTH");
1063  		return (NULL);
1064  	}
1065  	if ((str = strchr(++str, ':')) == NULL) {
1066  		pkg_emit_error("malformed HTTP_AUTH");
1067  		return (NULL);
1068  	}
1069  	if (strchr(++str, ':') == NULL) {
1070  		pkg_emit_error("malformed HTTP_AUTH");
1071  		return (NULL);
1072  	}
1073  	return (str);
1074  }
1075  
1076  bool
1077  charv_contains(charv_t *v, const char *el, bool casesensitive)
1078  {
1079  	vec_foreach(*v, i) {
1080  		if (casesensitive) {
1081  			if (STREQ(v->d[i], el))
1082  				return (true);
1083  		} else {
1084  			if (STRIEQ(v->d[i], el)) {
1085  				return (true);
1086  			}
1087  		}
1088  	}
1089  	return (false);
1090  }
1091  
1092  bool
1093  c_charv_contains(c_charv_t *v, const char *el, bool casesensitive)
1094  {
1095  	vec_foreach(*v, i) {
1096  		if (casesensitive) {
1097  			if (STREQ(v->d[i], el))
1098  				return (true);
1099  		} else {
1100  			if (STRIEQ(v->d[i], el)) {
1101  				return (true);
1102  			}
1103  		}
1104  	}
1105  	return (false);
1106  }
1107  
1108  bool
1109  str_ends_with(const char *str, const char *end)
1110  {
1111  	size_t el, sl;
1112  
1113  	if (end == NULL)
1114  		return (true);
1115  	if (str == NULL)
1116  		return (false);
1117  
1118  	sl = strlen(str);
1119  	el = strlen(end);
1120  	if (sl < el)
1121  		return (false);
1122  	return (strncmp(str + (sl - el), end, el) == 0);
1123  }
1124  
1125  int
1126  char_cmp(const void *a, const void *b) {
1127  	return strcmp(*(char **)a, *(char **)b);
1128  }
1129  
1130  DEFINE_VEC_INSERT_SORTED_FUNC(charv_t, charv, char *, char_cmp);
1131  
1132  const char *
1133  charv_search(charv_t *v, const char *el)
1134  {
1135  	if (v->len == 0)
1136  		return (NULL);
1137  	const char **res = bsearch(&el, v->d, v->len, sizeof(char *), char_cmp);
1138  	if (res == NULL)
1139  		return (NULL);
1140  	return *res;
1141  }
1142  
1143  uid_t
1144  get_uid_from_uname(const char *uname)
1145  {
1146  	static char user_buffer[1024];
1147  	static struct passwd pwent;
1148  	struct passwd *result;
1149  	int err;
1150  	const char *testuname = uname ? uname : "";
1151  
1152  	if (pwent.pw_name != NULL && STREQ(testuname, pwent.pw_name))
1153  		goto out;
1154  	pwent.pw_name = NULL;
1155  	err = getpwnam_r(testuname, &pwent, user_buffer, sizeof(user_buffer),
1156  	    &result);
1157  	if (err != 0) {
1158  		pkg_emit_error("getpwnam_r(%s): %s", testuname, strerror(err));
1159  		return (0);
1160  	}
1161  	if (result == NULL)
1162  		return (0);
1163  out:
1164  	return (pwent.pw_uid);
1165  }
1166  
1167  gid_t
1168  get_gid_from_gname(const char *gname)
1169  {
1170  	static char group_buffer[1024];
1171  	static struct group grent;
1172  	struct group *result;
1173  	int err;
1174  	const char *testgname = gname ? gname : "";
1175  
1176  	if (grent.gr_name != NULL && STREQ(testgname, grent.gr_name))
1177  		goto out;
1178  	grent.gr_name = NULL;
1179  	err = getgrnam_r(testgname, &grent, group_buffer, sizeof(group_buffer),
1180  	    &result);
1181  	if (err != 0) {
1182  		pkg_emit_error("getgrnam_r(%s): %s", testgname, strerror(err));
1183  		return (0);
1184  	}
1185  	if (result == NULL)
1186  		return (0);
1187  out:
1188  	return (grent.gr_gid);
1189  }
1190  
1191  const char *
1192  pkg_meta_attribute_tostring(enum pkg_meta_attribute attrib)
1193  {
1194  	switch (attrib) {
1195  	case PKG_META_ATTR_TYPE: return "type";
1196  	case PKG_META_ATTR_UNAME: return "uname";
1197  	case PKG_META_ATTR_GNAME: return "gname";
1198  	case PKG_META_ATTR_PERM: return "perm";
1199  	case PKG_META_ATTR_FFLAGS: return "fflags";
1200  	case PKG_META_ATTR_MTIME: return "mtime";
1201  	case PKG_META_ATTR_SYMLINK: return "symlink";
1202  	}
1203  
1204  	return "???";
1205  }