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 }