1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2012 Joshua M. Clulow <josh@sysmgr.org>
  24  */
  25 
  26 #include <stdlib.h>
  27 #include <string.h>
  28 #include <strings.h>
  29 #include <errno.h>
  30 #include <unistd.h>
  31 #include <limits.h>
  32 #include <fcntl.h>
  33 #include <err.h>
  34 #include <libintl.h>
  35 #include <sys/types.h>
  36 #include <sys/stat.h>
  37 #include <sys/wait.h>
  38 #include <dirent.h>
  39 #include <stddef.h>
  40 #include <libscf.h>
  41 
  42 #include "utils.h"
  43 
  44 #define _(x)    gettext(x)
  45 
  46 void *
  47 xmalloc(size_t sz)
  48 {
  49         void *x = malloc(sz);
  50         if (x == NULL)
  51                 abort();
  52         bzero(x, sz);
  53         return (x);
  54 }
  55 
  56 char *
  57 xstrdup(const char *a)
  58 {
  59         char *x = strdup(a);
  60         if (x == NULL)
  61                 abort();
  62         return (x);
  63 }
  64 
  65 int
  66 xasprintf(char **str, const char *format, ...)
  67 {
  68         va_list ap;
  69         int ret;
  70 
  71         *str = NULL;
  72         va_start(ap, format);
  73         ret = vasprintf(str, format, ap);
  74         va_end(ap);
  75 
  76         if (ret == -1)
  77                 abort();
  78 
  79         return (ret);
  80 }
  81 
  82 int
  83 xexists(char *path)
  84 {
  85         struct stat buf;
  86         if (stat(path, &buf) != 0) {
  87                 if (errno == ENOENT)
  88                         return (0);
  89                 else
  90                         err(SMF_EXIT_ERR_FATAL, _("stat on path: %s"), path);
  91         }
  92         return (1);
  93 }
  94 
  95 char *
  96 xreadlink(char *path)
  97 {
  98         char tmp[PATH_MAX];
  99         int len;
 100 
 101         len = readlink(path, tmp, sizeof (tmp) - 1);
 102         if (len == -1 || len >= (int)sizeof (tmp))
 103                 err(SMF_EXIT_ERR_FATAL, _("readlink failure on path: %s"),
 104                     path);
 105         tmp[len] = '\0'; /* NUL-terminate what readlink gives us */
 106 
 107         return (xstrdup(tmp));
 108 }
 109 
 110 char *
 111 xrealpath(char *path)
 112 {
 113         char *ret;
 114         char tmp[PATH_MAX];
 115 
 116         ret = realpath(path, tmp);
 117         if (ret == NULL) {
 118                 if (errno == ENOENT)
 119                         return (xstrdup(path));
 120                 else
 121                         err(SMF_EXIT_ERR_FATAL, _("realpath failure on"
 122                             " path: %s"), path);
 123         }
 124 
 125         return (xstrdup(tmp));
 126 }
 127 
 128 void
 129 xunlink(const char *path)
 130 {
 131         if (unlink(path) != 0)
 132                 err(SMF_EXIT_ERR_FATAL, _("could not unlink: %s"), path);
 133 }
 134 
 135 char *
 136 xmakerelative(char *relativetodir, char *path)
 137 {
 138         int i;
 139         int comlen = 0;
 140         int extraelems = 0;
 141         char tmp[PATH_MAX];
 142         char *lastsrc, *lastpath, *srccomp, *pathcomp;
 143         char *trelativetodir = strdup(relativetodir);
 144         char *tpath = strdup(path);
 145 
 146         if (relativetodir[0] != '/' || path[0] != '/')
 147                 abort();
 148 
 149         srccomp = strtok_r(trelativetodir, "/", &lastsrc);
 150         pathcomp = strtok_r(tpath, "/", &lastpath);
 151 
 152         /* discard elements common to both paths */
 153         while (srccomp != NULL && pathcomp != NULL &&
 154             strcmp(srccomp, pathcomp) == 0) {
 155                 srccomp = strtok_r(NULL, "/", &lastsrc);
 156                 pathcomp = strtok_r(NULL, "/", &lastpath);
 157         }
 158         /* record the start of the unique part of the target path */
 159         comlen = pathcomp - tpath;
 160         /* count the number of non-common path elements in the target dir */
 161         while (srccomp != NULL) {
 162                 extraelems++;
 163                 srccomp = strtok_r(NULL, "/", &lastsrc);
 164         }
 165 
 166         if (extraelems * 3 + strlen(&path[comlen]) + 1 > PATH_MAX)
 167                 errx(17, "relative path generation error");
 168 
 169         /*
 170          * generate a path that escapes only the non-common elements of the
 171          * target directory
 172          */
 173         tmp[0] = '\0';
 174         for (i = 0; i < extraelems; i++)
 175                 strcat(tmp, "../");
 176         strcat(tmp, &path[comlen]);
 177 
 178         free(trelativetodir);
 179         free(tpath);
 180 
 181         return (strdup(tmp));
 182 }