1 /*
2 * Copyright © 2013 Guillem Jover <guillem@hadrons.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <errno.h>
28 #include <stddef.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <err.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <sys/param.h>
36 #include <libzutil.h>
37
38 static struct {
39 /* Original value. */
40 const char *arg0;
41
42 /* Title space available. */
43 char *base, *end;
44
45 /* Pointer to original nul character within base. */
46 char *nul;
47
48 boolean_t warned;
49 boolean_t reset;
50 int error;
51 } SPT;
52
53 #define LIBBSD_IS_PATHNAME_SEPARATOR(c) ((c) == '/')
54 #define SPT_MAXTITLE 255
55
56 extern const char *__progname;
57
58 static const char *
59 getprogname(void)
60 {
61 return (__progname);
62 }
63
64 static void
65 setprogname(const char *progname)
66 {
67 size_t i;
68
69 for (i = strlen(progname); i > 0; i--) {
70 if (LIBBSD_IS_PATHNAME_SEPARATOR(progname[i - 1])) {
71 __progname = progname + i;
72 return;
73 }
74 }
75 __progname = progname;
76 }
77
78
79 static inline size_t
80 spt_min(size_t a, size_t b)
81 {
82 return ((a < b) ? a : b);
83 }
84
85 /*
86 * For discussion on the portability of the various methods, see
87 * https://lists.freebsd.org/pipermail/freebsd-stable/2008-June/043136.html
88 */
89 static int
90 spt_clearenv(void)
91 {
92 char **tmp;
93
94 tmp = malloc(sizeof (*tmp));
95 if (tmp == NULL)
96 return (errno);
97
98 tmp[0] = NULL;
99 environ = tmp;
100
101 return (0);
102 }
103
104 static int
105 spt_copyenv(int envc, char *envp[])
106 {
107 char **envcopy;
108 char *eq;
109 int envsize;
110 int i, error;
111
112 if (environ != envp)
113 return (0);
114
115 /*
116 * Make a copy of the old environ array of pointers, in case
117 * clearenv() or setenv() is implemented to free the internal
118 * environ array, because we will need to access the old environ
119 * contents to make the new copy.
120 */
121 envsize = (envc + 1) * sizeof (char *);
122 envcopy = malloc(envsize);
123 if (envcopy == NULL)
124 return (errno);
125 memcpy(envcopy, envp, envsize);
126
127 error = spt_clearenv();
128 if (error) {
129 environ = envp;
130 free(envcopy);
131 return (error);
132 }
133
134 for (i = 0; envcopy[i]; i++) {
135 eq = strchr(envcopy[i], '=');
136 if (eq == NULL)
137 continue;
138
139 *eq = '\0';
140 if (setenv(envcopy[i], eq + 1, 1) < 0)
141 error = errno;
142 *eq = '=';
143
144 if (error) {
145 environ = envp;
146 free(envcopy);
147 return (error);
148 }
149 }
150
151 /*
152 * Dispose of the shallow copy, now that we've finished transfering
153 * the old environment.
154 */
155 free(envcopy);
156
157 return (0);
158 }
159
160 static int
161 spt_copyargs(int argc, char *argv[])
162 {
163 char *tmp;
164 int i;
165
166 for (i = 1; i < argc || (i >= argc && argv[i]); i++) {
167 if (argv[i] == NULL)
168 continue;
169
170 tmp = strdup(argv[i]);
171 if (tmp == NULL)
172 return (errno);
173
174 argv[i] = tmp;
175 }
176
177 return (0);
178 }
179
180 void
181 zfs_setproctitle_init(int argc, char *argv[], char *envp[])
182 {
183 char *base, *end, *nul, *tmp;
184 int i, envc, error;
185
186 /* Try to make sure we got called with main() arguments. */
187 if (argc < 0)
188 return;
189
190 base = argv[0];
191 if (base == NULL)
192 return;
193
194 nul = base + strlen(base);
195 end = nul + 1;
196
197 for (i = 0; i < argc || (i >= argc && argv[i]); i++) {
198 if (argv[i] == NULL || argv[i] != end)
199 continue;
200
201 end = argv[i] + strlen(argv[i]) + 1;
202 }
203
204 for (i = 0; envp[i]; i++) {
205 if (envp[i] != end)
206 continue;
207
208 end = envp[i] + strlen(envp[i]) + 1;
209 }
210 envc = i;
211
212 SPT.arg0 = strdup(argv[0]);
213 if (SPT.arg0 == NULL) {
214 SPT.error = errno;
215 return;
216 }
217
218 tmp = strdup(getprogname());
219 if (tmp == NULL) {
220 SPT.error = errno;
221 return;
222 }
223 setprogname(tmp);
224
225 error = spt_copyenv(envc, envp);
226 if (error) {
227 SPT.error = error;
228 return;
229 }
230
231 error = spt_copyargs(argc, argv);
232 if (error) {
233 SPT.error = error;
234 return;
235 }
236
237 SPT.nul = nul;
238 SPT.base = base;
239 SPT.end = end;
240 }
241
242 void
243 zfs_setproctitle(const char *fmt, ...)
244 {
245 /* Use buffer in case argv[0] is passed. */
246 char buf[SPT_MAXTITLE + 1];
247 va_list ap;
248 char *nul;
249 int len;
250 if (SPT.base == NULL) {
251 if (!SPT.warned) {
252 warnx("setproctitle not initialized, please"
253 "call zfs_setproctitle_init()");
254 SPT.warned = B_TRUE;
255 }
256 return;
257 }
258
259 if (fmt) {
260 if (fmt[0] == '-') {
261 /* Skip program name prefix. */
262 fmt++;
263 len = 0;
264 } else {
265 /* Print program name heading for grep. */
266 snprintf(buf, sizeof (buf), "%s: ", getprogname());
267 len = strlen(buf);
268 }
269
270 va_start(ap, fmt);
271 len += vsnprintf(buf + len, sizeof (buf) - len, fmt, ap);
272 va_end(ap);
273 } else {
274 len = snprintf(buf, sizeof (buf), "%s", SPT.arg0);
275 }
276
277 if (len <= 0) {
278 SPT.error = errno;
279 return;
280 }
281
282 if (!SPT.reset) {
283 memset(SPT.base, 0, SPT.end - SPT.base);
284 SPT.reset = B_TRUE;
285 } else {
286 memset(SPT.base, 0, spt_min(sizeof (buf), SPT.end - SPT.base));
287 }
288
289 len = spt_min(len, spt_min(sizeof (buf), SPT.end - SPT.base) - 1);
290 memcpy(SPT.base, buf, len);
291 nul = SPT.base + len;
292
293 if (nul < SPT.nul) {
294 *SPT.nul = '.';
295 } else if (nul == SPT.nul && nul + 1 < SPT.end) {
296 *SPT.nul = ' ';
297 *++nul = '\0';
298 }
299 }
Cache object: 94b8338e3e804f94129e9d82f29ccd30
|