LCOV - code coverage report
Current view: top level - libpkg - utils.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 180 374 48.1 %
Date: 2015-08-15 Functions: 21 28 75.0 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2011-2014 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/stat.h>
      32             : #include <sys/param.h>
      33             : #include <stdio.h>
      34             : 
      35             : #include <assert.h>
      36             : #include <errno.h>
      37             : #include <fcntl.h>
      38             : #include <stdlib.h>
      39             : #include <unistd.h>
      40             : #include <string.h>
      41             : #include <ucl.h>
      42             : #include <uthash.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             : 
      50             : #include <bsd_compat.h>
      51             : 
      52             : #include "pkg.h"
      53             : #include "private/event.h"
      54             : #include "private/utils.h"
      55             : 
      56             : void
      57         824 : sbuf_init(struct sbuf **buf)
      58             : {
      59         824 :         if (*buf == NULL)
      60         644 :                 *buf = sbuf_new_auto();
      61             :         else
      62         180 :                 sbuf_clear(*buf);
      63         824 : }
      64             : 
      65             : int
      66          50 : sbuf_set(struct sbuf **buf, const char *str)
      67             : {
      68          50 :         if (*buf == NULL)
      69          50 :                 *buf = sbuf_new_auto();
      70             : 
      71          50 :         if (str == NULL)
      72           0 :                 return (-1);
      73             : 
      74          50 :         sbuf_cpy(*buf, str);
      75          50 :         sbuf_finish(*buf);
      76          50 :         return (0);
      77             : }
      78             : 
      79             : void
      80          12 : sbuf_reset(struct sbuf *buf)
      81             : {
      82          12 :         if (buf != NULL) {
      83          12 :                 sbuf_clear(buf);
      84          12 :                 sbuf_finish(buf);
      85             :         }
      86          12 : }
      87             : 
      88             : void
      89        2302 : sbuf_free(struct sbuf *buf)
      90             : {
      91        2302 :         if (buf != NULL)
      92         152 :                 sbuf_delete(buf);
      93        2302 : }
      94             : 
      95             : int
      96          75 : mkdirs(const char *_path)
      97             : {
      98             :         char path[MAXPATHLEN];
      99             :         char *p;
     100             : 
     101          75 :         strlcpy(path, _path, sizeof(path));
     102          75 :         p = path;
     103          75 :         if (*p == '/')
     104          33 :                 p++;
     105             : 
     106             :         for (;;) {
     107         149 :                 if ((p = strchr(p, '/')) != NULL)
     108          74 :                         *p = '\0';
     109             : 
     110         149 :                 if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
     111         149 :                         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         149 :                 if (p == NULL)
     118          75 :                         break;
     119             : 
     120          74 :                 *p = '/';
     121          74 :                 p++;
     122          74 :         }
     123             : 
     124          75 :         return (EPKG_OK);
     125             : }
     126             : int
     127          25 : file_to_bufferat(int dfd, const char *path, char **buffer, off_t *sz)
     128             : {
     129          25 :         int fd = -1;
     130             :         struct stat st;
     131          25 :         int retcode = EPKG_OK;
     132             : 
     133          25 :         assert(path != NULL && path[0] != '\0');
     134          25 :         assert(buffer != NULL);
     135          25 :         assert(sz != NULL);
     136             : 
     137          25 :         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          25 :         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          25 :         if ((*buffer = malloc(st.st_size + 1)) == NULL) {
     150           0 :                 pkg_emit_errno("malloc", "");
     151           0 :                 retcode = EPKG_FATAL;
     152           0 :                 goto cleanup;
     153             :         }
     154             : 
     155          25 :         if (read(fd, *buffer, st.st_size) == -1) {
     156           0 :                 pkg_emit_errno("read", path);
     157           0 :                 retcode = EPKG_FATAL;
     158           0 :                 goto cleanup;
     159             :         }
     160             : 
     161             :         cleanup:
     162          25 :         if (fd >= 0)
     163          25 :                 close(fd);
     164             : 
     165          25 :         if (retcode == EPKG_OK) {
     166          25 :                 (*buffer)[st.st_size] = '\0';
     167          25 :                 *sz = st.st_size;
     168             :         } else {
     169           0 :                 *buffer = NULL;
     170           0 :                 *sz = -1;
     171             :         }
     172          25 :         return (retcode);
     173             : }
     174             : 
     175             : int
     176           0 : file_to_buffer(const char *path, char **buffer, off_t *sz)
     177             : {
     178           0 :         int fd = -1;
     179             :         struct stat st;
     180           0 :         int retcode = EPKG_OK;
     181             : 
     182           0 :         assert(path != NULL && path[0] != '\0');
     183           0 :         assert(buffer != NULL);
     184           0 :         assert(sz != NULL);
     185             : 
     186           0 :         if ((fd = open(path, O_RDONLY)) == -1) {
     187           0 :                 pkg_emit_errno("open", path);
     188           0 :                 retcode = EPKG_FATAL;
     189           0 :                 goto cleanup;
     190             :         }
     191             : 
     192           0 :         if (fstat(fd, &st) == -1) {
     193           0 :                 pkg_emit_errno("fstat", path);
     194           0 :                 retcode = EPKG_FATAL;
     195           0 :                 goto cleanup;
     196             :         }
     197             : 
     198           0 :         if ((*buffer = malloc(st.st_size + 1)) == NULL) {
     199           0 :                 pkg_emit_errno("malloc", "");
     200           0 :                 retcode = EPKG_FATAL;
     201           0 :                 goto cleanup;
     202             :         }
     203             : 
     204           0 :         if (read(fd, *buffer, st.st_size) == -1) {
     205           0 :                 pkg_emit_errno("read", path);
     206           0 :                 retcode = EPKG_FATAL;
     207           0 :                 goto cleanup;
     208             :         }
     209             : 
     210             :         cleanup:
     211           0 :         if (fd >= 0)
     212           0 :                 close(fd);
     213             : 
     214           0 :         if (retcode == EPKG_OK) {
     215           0 :                 (*buffer)[st.st_size] = '\0';
     216           0 :                 *sz = st.st_size;
     217             :         } else {
     218           0 :                 *buffer = NULL;
     219           0 :                 *sz = -1;
     220             :         }
     221           0 :         return (retcode);
     222             : }
     223             : 
     224             : int
     225           8 : format_exec_cmd(char **dest, const char *in, const char *prefix,
     226             :     const char *plist_file, char *line, int argc, char **argv)
     227             : {
     228           8 :         struct sbuf *buf = sbuf_new_auto();
     229             :         char path[MAXPATHLEN];
     230             :         char *cp;
     231             :         size_t sz;
     232             : 
     233          78 :         while (in[0] != '\0') {
     234          64 :                 if (in[0] != '%') {
     235          48 :                         sbuf_putc(buf, in[0]);
     236          48 :                         in++;
     237          48 :                         continue;
     238             :                 }
     239          16 :                 in++;
     240          16 :                 switch(in[0]) {
     241             :                 case 'D':
     242           0 :                         sbuf_cat(buf, prefix);
     243           0 :                         break;
     244             :                 case 'F':
     245           0 :                         if (plist_file == NULL || plist_file[0] == '\0') {
     246           0 :                                 pkg_emit_error("No files defined %%F couldn't "
     247             :                                     "be expanded, ignoring %s", in);
     248           0 :                                 sbuf_finish(buf);
     249           0 :                                 sbuf_free(buf);
     250           0 :                                 return (EPKG_FATAL);
     251             :                         }
     252           0 :                         sbuf_cat(buf, plist_file);
     253           0 :                         break;
     254             :                 case 'f':
     255           0 :                         if (plist_file == NULL || plist_file[0] == '\0') {
     256           0 :                                 pkg_emit_error("No files defined %%f couldn't "
     257             :                                     "be expanded, ignoring %s", in);
     258           0 :                                 sbuf_finish(buf);
     259           0 :                                 sbuf_free(buf);
     260           0 :                                 return (EPKG_FATAL);
     261             :                         }
     262           0 :                         if (prefix[strlen(prefix) - 1] == '/')
     263           0 :                                 snprintf(path, sizeof(path), "%s%s",
     264             :                                     prefix, plist_file);
     265             :                         else
     266           0 :                                 snprintf(path, sizeof(path), "%s/%s",
     267             :                                     prefix, plist_file);
     268           0 :                         cp = strrchr(path, '/');
     269           0 :                         cp ++;
     270           0 :                         sbuf_cat(buf, 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             :                                     "be expanded, ignoring %s", in);
     276           0 :                                 sbuf_finish(buf);
     277           0 :                                 sbuf_free(buf);
     278           0 :                                 return (EPKG_FATAL);
     279             :                         }
     280           0 :                         if (prefix[strlen(prefix) - 1] == '/')
     281           0 :                                 snprintf(path, sizeof(path), "%s%s", prefix,
     282             :                                     plist_file);
     283             :                         else
     284           0 :                                 snprintf(path, sizeof(path), "%s/%s", prefix,
     285             :                                     plist_file);
     286           0 :                         cp = strrchr(path, '/');
     287           0 :                         cp[0] = '\0';
     288           0 :                         sbuf_cat(buf, path);
     289           0 :                         break;
     290             :                 case '%':
     291           0 :                         sbuf_putc(buf, '%');
     292           0 :                         break;
     293             :                 case '@':
     294           0 :                         if (line != NULL) {
     295           0 :                                 sbuf_cat(buf, line);
     296           0 :                                 break;
     297             :                         }
     298             : 
     299             :                         /*
     300             :                          * no break here because if line is not
     301             :                          * given (default exec) %@ does not
     302             :                          * exists
     303             :                          */
     304             :                 case '#':
     305           0 :                         sbuf_putc(buf, argc);
     306           0 :                         break;
     307             :                 default:
     308          16 :                         if ((sz = strspn(in, "0123456789")) > 0) {
     309          16 :                                 int pos = strtol(in, NULL, 10);
     310          16 :                                 if (pos > argc) {
     311           2 :                                         pkg_emit_error("Requesting argument "
     312             :                                             "%%%d while only %d arguments are"
     313             :                                             " available", pos, argc);
     314           2 :                                         sbuf_finish(buf);
     315           2 :                                         sbuf_free(buf);
     316           2 :                                         return (EPKG_FATAL);
     317             :                                 }
     318          14 :                                 sbuf_cat(buf, argv[pos -1]);
     319          14 :                                 in += sz -1;
     320          14 :                                 break;
     321             :                         }
     322           0 :                         sbuf_putc(buf, '%');
     323           0 :                         sbuf_putc(buf, in[0]);
     324           0 :                         break;
     325             :                 }
     326             : 
     327          14 :                 in++;
     328             :         }
     329             : 
     330           6 :         sbuf_finish(buf);
     331           6 :         *dest = strdup(sbuf_data(buf));
     332           6 :         sbuf_free(buf);
     333             :         
     334           6 :         return (EPKG_OK);
     335             : }
     336             : 
     337             : int
     338          74 : is_dir(const char *path)
     339             : {
     340             :         struct stat st;
     341             : 
     342          74 :         return (stat(path, &st) == 0 && S_ISDIR(st.st_mode));
     343             : }
     344             : 
     345             : bool
     346          18 : string_end_with(const char *path, const char *str)
     347             : {
     348             :         size_t n, s;
     349          18 :         const char *p = NULL;
     350             : 
     351          18 :         s = strlen(str);
     352          18 :         n = strlen(path);
     353             : 
     354          18 :         if (n < s)
     355           0 :                 return (false);
     356             : 
     357          18 :         p = &path[n - s];
     358             : 
     359          18 :         if (strcmp(p, str) == 0)
     360           0 :                 return (true);
     361             : 
     362          18 :         return (false);
     363             : }
     364             : 
     365             : bool
     366           0 : check_for_hardlink(hardlinks_t *hl, struct stat *st)
     367             : {
     368             :         int absent;
     369             : 
     370           0 :         kh_put_hardlinks(hl, st->st_ino, &absent);
     371           0 :         if (absent == 0)
     372           0 :                 return (true);
     373             : 
     374           0 :         return (false);
     375             : }
     376             : 
     377             : bool
     378          35 : is_valid_abi(const char *arch, bool emit_error) {
     379             :         const char *myarch, *myarch_legacy;
     380             : 
     381          35 :         myarch = pkg_object_string(pkg_config_get("ABI"));
     382          35 :         myarch_legacy = pkg_object_string(pkg_config_get("ALTABI"));
     383             : 
     384          58 :         if (fnmatch(arch, myarch, FNM_CASEFOLD) == FNM_NOMATCH &&
     385          46 :             strncasecmp(arch, myarch, strlen(myarch)) != 0 &&
     386          23 :             strncasecmp(arch, myarch_legacy, strlen(myarch_legacy)) != 0) {
     387           0 :                 if (emit_error)
     388           0 :                         pkg_emit_error("wrong architecture: %s instead of %s",
     389             :                             arch, myarch);
     390           0 :                 return (false);
     391             :         }
     392             : 
     393          35 :         return (true);
     394             : }
     395             : 
     396             : void
     397           0 : set_nonblocking(int fd)
     398             : {
     399             :         int flags;
     400             : 
     401           0 :         if ((flags = fcntl(fd, F_GETFL)) == -1)
     402           0 :                 return;
     403           0 :         if (!(flags & O_NONBLOCK)) {
     404           0 :                 flags |= O_NONBLOCK;
     405           0 :                 fcntl(fd, F_SETFL, flags);
     406             :         }
     407             : }
     408             : 
     409             : void
     410           0 : set_blocking(int fd)
     411             : {
     412             :         int flags;
     413             : 
     414           0 :         if ((flags = fcntl(fd, F_GETFL)) == -1)
     415           0 :                 return;
     416           0 :         if (flags & O_NONBLOCK) {
     417           0 :                 flags &= ~O_NONBLOCK;
     418           0 :                 fcntl(fd, F_SETFL, flags);
     419             :         }
     420             : }
     421             : 
     422             : /* Spawn a process from pfunc, returning it's pid. The fds array passed will
     423             :  * be filled with two descriptors: fds[0] will read from the child process,
     424             :  * and fds[1] will write to it.
     425             :  * Similarly, the child process will receive a reading/writing fd set (in
     426             :  * that same order) as arguments.
     427             : */
     428             : extern char **environ;
     429             : pid_t
     430           0 : process_spawn_pipe(FILE *inout[2], const char *command)
     431             : {
     432             :         pid_t pid;
     433             :         int pipes[4];
     434             :         char *argv[4];
     435             : 
     436             :         /* Parent read/child write pipe */
     437           0 :         if (pipe(&pipes[0]) == -1)
     438           0 :                 return (-1);
     439             : 
     440             :         /* Child read/parent write pipe */
     441           0 :         if (pipe(&pipes[2]) == -1) {
     442           0 :                 close(pipes[0]);
     443           0 :                 close(pipes[1]);
     444           0 :                 return (-1);
     445             :         }
     446             : 
     447           0 :         argv[0] = __DECONST(char *, "sh");
     448           0 :         argv[1] = __DECONST(char *, "-c");
     449           0 :         argv[2] = __DECONST(char *, command);
     450           0 :         argv[3] = NULL;
     451             : 
     452           0 :         pid = fork();
     453           0 :         if (pid > 0) {
     454             :                 /* Parent process */
     455           0 :                 inout[0] = fdopen(pipes[0], "r");
     456           0 :                 inout[1] = fdopen(pipes[3], "w");
     457             : 
     458           0 :                 close(pipes[1]);
     459           0 :                 close(pipes[2]);
     460             : 
     461           0 :                 return (pid);
     462             : 
     463           0 :         } else if (pid == 0) {
     464           0 :                 close(pipes[0]);
     465           0 :                 close(pipes[3]);
     466             : 
     467           0 :                 if (pipes[1] != STDOUT_FILENO) {
     468           0 :                         dup2(pipes[1], STDOUT_FILENO);
     469           0 :                         close(pipes[1]);
     470             :                 }
     471           0 :                 if (pipes[2] != STDIN_FILENO) {
     472           0 :                         dup2(pipes[2], STDIN_FILENO);
     473           0 :                         close(pipes[2]);
     474             :                 }
     475           0 :                 closefrom(STDERR_FILENO + 1);
     476             : 
     477           0 :                 execve(_PATH_BSHELL, argv, environ);
     478             : 
     479           0 :                 exit(127);
     480             :         }
     481             : 
     482           0 :         return (-1); /* ? */
     483             : }
     484             : 
     485             : static int
     486         176 : ucl_file_append_character(unsigned char c, size_t len, void *data)
     487             : {
     488             :         size_t i;
     489         176 :         FILE *out = data;
     490             : 
     491         352 :         for (i = 0; i < len; i++)
     492         176 :                 fprintf(out, "%c", c);
     493             : 
     494         176 :         return (0);
     495             : }
     496             : 
     497             : static int
     498         385 : ucl_file_append_len(const unsigned char *str, size_t len, void *data)
     499             : {
     500         385 :         FILE *out = data;
     501             : 
     502         385 :         fprintf(out, "%.*s", (int)len, str);
     503             : 
     504         385 :         return (0);
     505             : }
     506             : 
     507             : static int
     508          11 : ucl_file_append_int(int64_t val, void *data)
     509             : {
     510          11 :         FILE *out = data;
     511             : 
     512          11 :         fprintf(out, "%"PRId64, val);
     513             : 
     514          11 :         return (0);
     515             : }
     516             : 
     517             : static int
     518           0 : ucl_file_append_double(double val, void *data)
     519             : {
     520           0 :         FILE *out = data;
     521           0 :         const double delta = 0.0000001;
     522             : 
     523           0 :         if (val == (double)(int)val) {
     524           0 :                 fprintf(out, "%.1lf", val);
     525           0 :         } else if (fabs(val - (double)(int)val) < delta) {
     526           0 :                 fprintf(out, "%.*lg", DBL_DIG, val);
     527             :         } else {
     528           0 :                 fprintf(out, "%lf", val);
     529             :         }
     530             : 
     531           0 :         return (0);
     532             : }
     533             : 
     534             : static int
     535       14188 : ucl_sbuf_append_character(unsigned char c, size_t len, void *data)
     536             : {
     537       14188 :         struct sbuf *buf = data;
     538             :         size_t i;
     539             : 
     540       28376 :         for (i = 0; i < len; i++)
     541       14188 :                 sbuf_putc(buf, c);
     542             : 
     543       14188 :         return (0);
     544             : }
     545             : 
     546             : static int
     547        4421 : ucl_sbuf_append_len(const unsigned char *str, size_t len, void *data)
     548             : {
     549        4421 :         struct sbuf *buf = data;
     550             : 
     551        4421 :         sbuf_bcat(buf, str, len);
     552             : 
     553        4421 :         return (0);
     554             : }
     555             : 
     556             : static int
     557         180 : ucl_sbuf_append_int(int64_t val, void *data)
     558             : {
     559         180 :         struct sbuf *buf = data;
     560             : 
     561         180 :         sbuf_printf(buf, "%"PRId64, val);
     562             : 
     563         180 :         return (0);
     564             : }
     565             : 
     566             : static int
     567           0 : ucl_sbuf_append_double(double val, void *data)
     568             : {
     569           0 :         struct sbuf *buf = data;
     570           0 :         const double delta = 0.0000001;
     571             : 
     572           0 :         if (val == (double)(int)val) {
     573           0 :                 sbuf_printf(buf, "%.1lf", val);
     574           0 :         } else if (fabs(val - (double)(int)val) < delta) {
     575           0 :                 sbuf_printf(buf, "%.*lg", DBL_DIG, val);
     576             :         } else {
     577           0 :                 sbuf_printf(buf, "%lf", val);
     578             :         }
     579             : 
     580           0 :         return (0);
     581             : }
     582             : 
     583             : bool
     584          11 : ucl_object_emit_file(const ucl_object_t *obj, enum ucl_emitter emit_type,
     585             :     FILE *out)
     586             : {
     587          11 :         struct ucl_emitter_functions func = {
     588             :                 .ucl_emitter_append_character = ucl_file_append_character,
     589             :                 .ucl_emitter_append_len = ucl_file_append_len,
     590             :                 .ucl_emitter_append_int = ucl_file_append_int,
     591             :                 .ucl_emitter_append_double = ucl_file_append_double
     592             :         };
     593             : 
     594          11 :         if (obj == NULL)
     595           0 :                 return (false);
     596             : 
     597          11 :         func.ud = out;
     598             : 
     599          11 :         return (ucl_object_emit_full(obj, emit_type, &func));
     600             : 
     601             : 
     602             : }
     603             : 
     604             : bool
     605         149 : ucl_object_emit_sbuf(const ucl_object_t *obj, enum ucl_emitter emit_type,
     606             :                      struct sbuf **buf)
     607             : {
     608         149 :         bool ret = false;
     609         149 :         struct ucl_emitter_functions func = {
     610             :                 .ucl_emitter_append_character = ucl_sbuf_append_character,
     611             :                 .ucl_emitter_append_len = ucl_sbuf_append_len,
     612             :                 .ucl_emitter_append_int = ucl_sbuf_append_int,
     613             :                 .ucl_emitter_append_double = ucl_sbuf_append_double
     614             :         };
     615             : 
     616         149 :         if (*buf == NULL)
     617           0 :                 *buf = sbuf_new_auto();
     618             :         else
     619         149 :                 sbuf_clear(*buf);
     620             : 
     621         149 :         func.ud = *buf;
     622             : 
     623         149 :         ret = ucl_object_emit_full(obj, emit_type, &func);
     624         149 :         sbuf_finish(*buf);
     625             : 
     626         149 :         return (ret);
     627             : }
     628             : 
     629             : /* A bit like strsep(), except it accounts for "double" and 'single'
     630             :    quotes.  Unlike strsep(), returns the next arg string, trimmed of
     631             :    whitespace or enclosing quotes, and updates **args to point at the
     632             :    character after that.  Sets *args to NULL when it has been
     633             :    completely consumed.  Quoted strings run from the first encountered
     634             :    quotemark to the next one of the same type or the terminating NULL.
     635             :    Quoted strings can contain the /other/ type of quote mark, which
     636             :    loses any special significance.  There isn't an escape
     637             :    character. */
     638             : 
     639             : enum parse_states {
     640             :         START,
     641             :         ORDINARY_TEXT,
     642             :         OPEN_SINGLE_QUOTES,
     643             :         IN_SINGLE_QUOTES,
     644             :         OPEN_DOUBLE_QUOTES,
     645             :         IN_DOUBLE_QUOTES,
     646             : };
     647             : 
     648             : char *
     649          18 : pkg_utils_tokenize(char **args)
     650             : {
     651             :         char                    *p, *p_start;
     652          18 :         enum parse_states        parse_state = START;
     653             : 
     654          18 :         assert(*args != NULL);
     655             : 
     656          54 :         for (p = p_start = *args; *p != '\0'; p++) {
     657          44 :                 switch (parse_state) {
     658             :                 case START:
     659          18 :                         if (!isspace(*p)) {
     660          18 :                                 if (*p == '"')
     661           0 :                                         parse_state = OPEN_DOUBLE_QUOTES;
     662          18 :                                 else if (*p == '\'')
     663           0 :                                         parse_state = OPEN_SINGLE_QUOTES;
     664             :                                 else {
     665          18 :                                         parse_state = ORDINARY_TEXT;
     666          18 :                                         p_start = p;
     667             :                                 }                               
     668             :                         } else 
     669           0 :                                 p_start = p;
     670          18 :                         break;
     671             :                 case ORDINARY_TEXT:
     672          26 :                         if (isspace(*p))
     673           8 :                                 goto finish;
     674          18 :                         break;
     675             :                 case OPEN_SINGLE_QUOTES:
     676           0 :                         p_start = p;
     677           0 :                         if (*p == '\'')
     678           0 :                                 goto finish;
     679             : 
     680           0 :                         parse_state = IN_SINGLE_QUOTES;
     681           0 :                         break;
     682             :                 case IN_SINGLE_QUOTES:
     683           0 :                         if (*p == '\'')
     684           0 :                                 goto finish;
     685           0 :                         break;
     686             :                 case OPEN_DOUBLE_QUOTES:
     687           0 :                         p_start = p;
     688           0 :                         if (*p == '"')
     689           0 :                                 goto finish;
     690           0 :                         parse_state = IN_DOUBLE_QUOTES;
     691           0 :                         break;
     692             :                 case IN_DOUBLE_QUOTES:
     693           0 :                         if (*p == '"')
     694           0 :                                 goto finish;
     695           0 :                         break;
     696             :                 }
     697             :         }
     698             : 
     699             : finish:
     700          18 :         if (*p == '\0')
     701          10 :                 *args = NULL;   /* All done */
     702             :         else {
     703           8 :                 *p = '\0';
     704           8 :                 p++;
     705           8 :                 if (*p == '\0' || parse_state == START)
     706           0 :                         *args = NULL; /* whitespace or nothing left */
     707             :                 else
     708           8 :                         *args = p;
     709             :         }
     710          18 :         return (p_start);
     711             : }
     712             : 
     713             : int
     714          10 : pkg_utils_count_spaces(const char *args)
     715             : {
     716             :         int             spaces;
     717             :         const char      *p;
     718             : 
     719          54 :         for (spaces = 0, p = args; *p != '\0'; p++) 
     720          44 :                 if (isspace(*p))
     721           8 :                         spaces++;
     722             : 
     723          10 :         return (spaces);
     724             : }
     725             : 
     726             : /* unlike realpath(3), this routine does not expand symbolic links */
     727             : char *
     728         235 : pkg_absolutepath(const char *src, char *dest, size_t dest_size) {
     729             :         size_t dest_len, src_len, cur_len;
     730             :         const char *cur, *next;
     731             : 
     732         235 :         src_len = strlen(src);
     733         235 :         bzero(dest, dest_size);
     734         235 :         if (src_len != 0 && src[0] != '/') {
     735             :                 /* relative path, we use cwd */
     736           0 :                 if (getcwd(dest, dest_size) == NULL)
     737           0 :                         return (NULL);
     738             :         }
     739         235 :         dest_len = strlen(dest);
     740             : 
     741        1283 :         for (cur = next = src; next != NULL; cur = next + 1) {
     742        1048 :                 next = strchr(cur, '/');
     743        1048 :                 if (next != NULL)
     744         813 :                         cur_len = next - cur;
     745             :                 else
     746         235 :                         cur_len = strlen(cur);
     747             : 
     748             :                 /* check for special cases "", "." and ".." */
     749        1048 :                 if (cur_len == 0)
     750         251 :                         continue;
     751         797 :                 else if (cur_len == 1 && cur[0] == '.')
     752           0 :                         continue;
     753         797 :                 else if (cur_len == 2 && cur[0] == '.' && cur[1] == '.') {
     754           0 :                         const char *slash = strrchr(dest, '/');
     755           0 :                         if (slash != NULL) {
     756           0 :                                 dest_len = slash - dest;
     757           0 :                                 dest[dest_len] = '\0';
     758             :                         }
     759           0 :                         continue;
     760             :                 }
     761             : 
     762         797 :                 if (dest_len + 1 + cur_len >= dest_size)
     763           0 :                         return (NULL);
     764         797 :                 dest[dest_len++] = '/';
     765         797 :                 (void)memcpy(dest + dest_len, cur, cur_len);
     766         797 :                 dest_len += cur_len;
     767         797 :                 dest[dest_len] = '\0';
     768             :         }
     769             : 
     770         235 :         if (dest_len == 0) {
     771           0 :                 if (strlcpy(dest, "/", dest_size) >= dest_size)
     772           0 :                         return (NULL);
     773             :         }
     774             : 
     775         235 :         return (dest);
     776             : }

Generated by: LCOV version 1.10