Print this page
3946 ::gcore
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libproc/common/Pzone.c
+++ new/usr/src/lib/libproc/common/Pzone.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26 /*
27 27 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
28 + * Copyright (c) 2013 by Delphix. All rights reserved.
28 29 */
29 30
30 31 #include <assert.h>
31 32 #include <dlfcn.h>
32 33 #include <errno.h>
33 34 #include <libzonecfg.h>
34 35 #include <link.h>
35 36 #include <string.h>
36 37 #include <strings.h>
37 38 #include <sys/list.h>
38 39 #include <sys/types.h>
39 40 #include <sys/mkdev.h>
40 41 #include <sys/mman.h>
41 42 #include <sys/mnttab.h>
42 43
43 44 #include "Pcontrol.h"
44 45
45 46 struct path_node {
46 47 struct path_node *pn_next;
47 48 char *pn_path;
48 49 };
49 50 typedef struct path_node path_node_t;
50 51
51 52 /*
52 53 * Parameters of the lofs lookup cache.
53 54 */
54 55 static struct stat64 lofs_mstat; /* last stat() of MNTTAB */
55 56 static struct lofs_mnttab { /* linked list of all lofs mount points */
56 57 struct lofs_mnttab *l_next;
57 58 char *l_special; /* extracted from MNTTAB */
58 59 char *l_mountp; /* ditto */
59 60 } *lofs_mnttab = NULL;
60 61 static mutex_t lofs_lock = DEFAULTMUTEX; /* protects the lofs cache */
61 62
62 63 static void
63 64 rebuild_lofs_cache(void)
64 65 {
65 66 struct mnttab mt;
66 67 struct mnttab mt_find;
67 68 struct lofs_mnttab *lmt;
68 69 struct lofs_mnttab *next;
69 70 FILE *fp;
70 71
71 72 assert(MUTEX_HELD(&lofs_lock));
72 73
73 74 /* destroy the old cache */
74 75 for (lmt = lofs_mnttab; lmt != NULL; lmt = next) {
75 76 next = lmt->l_next;
76 77 free(lmt->l_special);
77 78 free(lmt->l_mountp);
78 79 free(lmt);
79 80 }
80 81 lofs_mnttab = NULL;
81 82
82 83 /* prepare to create the new cache */
83 84 if ((fp = fopen(MNTTAB, "r")) == NULL)
84 85 return;
85 86
86 87 /*
87 88 * We only care about lofs mount points. But we need to
88 89 * ignore lofs mounts where the source path is the same
89 90 * as the target path. (This can happen when a non-global
90 91 * zone has a lofs mount of a global zone filesystem, since
91 92 * the source path can't expose information about global
92 93 * zone paths to the non-global zone.)
93 94 */
94 95 bzero(&mt_find, sizeof (mt_find));
95 96 mt_find.mnt_fstype = "lofs";
96 97 while (getmntany(fp, &mt, &mt_find) == 0 &&
97 98 (strcmp(mt.mnt_fstype, "lofs") == 0) &&
98 99 (strcmp(mt.mnt_special, mt.mnt_mountp) != 0)) {
99 100 if ((lmt = malloc(sizeof (struct lofs_mnttab))) == NULL)
100 101 break;
101 102 lmt->l_special = strdup(mt.mnt_special);
102 103 lmt->l_mountp = strdup(mt.mnt_mountp);
103 104 lmt->l_next = lofs_mnttab;
104 105 lofs_mnttab = lmt;
105 106 }
106 107
107 108 (void) fclose(fp);
108 109 }
109 110
110 111 static const char *
111 112 lookup_lofs_mount_point(const char *mountp)
112 113 {
113 114 struct lofs_mnttab *lmt;
114 115
115 116 assert(MUTEX_HELD(&lofs_lock));
116 117
117 118 for (lmt = lofs_mnttab; lmt != NULL; lmt = lmt->l_next) {
118 119 if (strcmp(lmt->l_mountp, mountp) == 0)
119 120 return (lmt->l_special);
120 121 }
121 122 return (NULL);
122 123 }
123 124
124 125 static path_node_t *
125 126 pn_push(path_node_t **pnp, char *path)
126 127 {
127 128 path_node_t *pn;
128 129
129 130 if ((pn = calloc(sizeof (path_node_t), 1)) == NULL)
130 131 return (NULL);
131 132
132 133 if ((pn->pn_path = strdup(path)) == NULL) {
133 134 free(pn);
134 135 return (NULL);
135 136 }
136 137 pn->pn_next = *pnp;
137 138 return (*pnp = pn);
138 139 }
139 140
140 141 static void
141 142 pn_free(path_node_t **pnp)
142 143 {
143 144 path_node_t *pn;
144 145
145 146 while (*pnp != NULL) {
146 147 pn = *pnp;
147 148 *pnp = pn->pn_next;
148 149 free(pn->pn_path);
149 150 free(pn);
150 151 }
151 152 }
152 153
153 154 static void
154 155 pn_free2(path_node_t **pn1, path_node_t **pn2)
155 156 {
156 157 pn_free(pn1);
157 158 pn_free(pn2);
158 159 }
159 160
160 161 static char *
161 162 pn_pop(path_node_t **pnp, char *path)
162 163 {
163 164 path_node_t *pn;
164 165
165 166 if (*pnp == NULL)
166 167 return (NULL);
167 168
168 169 pn = *pnp;
169 170 *pnp = pn->pn_next;
170 171 pn->pn_next = NULL;
171 172
172 173 if (path == NULL) {
173 174 pn_free(&pn);
174 175 return (NULL);
175 176 }
176 177 (void) strlcpy(path, pn->pn_path, PATH_MAX);
177 178 pn_free(&pn);
178 179 return (path);
179 180 }
180 181
181 182
182 183 /*
183 184 * Libzonecfg.so links against libproc, so libproc can't link against
184 185 * libzonecfg.so. Also, libzonecfg.so is optional and might not be
185 186 * installed. Hence instead of relying on linking to access libzonecfg.so,
186 187 * we'll try dlopening it here. This trick is borrowed from
187 188 * libc`zone_get_id(), see that function for more detailed comments.
188 189 */
189 190 static int
190 191 i_zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
191 192 {
192 193 typedef int (*zone_get_zonepath_t)(char *, char *, size_t);
193 194 static zone_get_zonepath_t zone_get_zonepath_fp = NULL;
194 195
195 196 if (zone_get_zonepath_fp == NULL) {
196 197 /* There's no harm in doing this multiple times. */
197 198 void *dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY);
198 199 void *sym = (void *)(-1);
199 200 if (dlhandle != NULL &&
200 201 (sym = dlsym(dlhandle, "zone_get_zonepath")) == NULL) {
201 202 sym = (void *)(-1);
202 203 (void) dlclose(dlhandle);
203 204 }
204 205 zone_get_zonepath_fp = (zone_get_zonepath_t)sym;
205 206 }
206 207
207 208 /* If we've successfully loaded it, call the real function */
208 209 if (zone_get_zonepath_fp != (zone_get_zonepath_t)(-1))
209 210 return (zone_get_zonepath_fp(zone_name, zonepath, rp_sz));
210 211 return (Z_NO_ZONE);
211 212 }
212 213
213 214 char *
214 215 Pbrandname(struct ps_prochandle *P, char *buf, size_t buflen)
215 216 {
216 217 long addr;
217 218
218 219 if ((addr = Pgetauxval(P, AT_SUN_BRANDNAME)) == -1)
219 220 return (NULL);
220 221
221 222 if (Pread_string(P, buf, buflen, addr) == -1)
222 223 return (NULL);
223 224
↓ open down ↓ |
186 lines elided |
↑ open up ↑ |
224 225 return (buf);
225 226 }
226 227
227 228 /*
228 229 * Get the zone name from the core file if we have it; look up the
229 230 * name based on the zone id if this is a live process.
230 231 */
231 232 char *
232 233 Pzonename(struct ps_prochandle *P, char *s, size_t n)
233 234 {
234 - if (P->state == PS_IDLE) {
235 - errno = ENODATA;
236 - return (NULL);
237 - }
238 -
239 - if (P->state == PS_DEAD) {
240 - if (P->core->core_zonename == NULL) {
241 - errno = ENODATA;
242 - return (NULL);
243 - }
244 - (void) strlcpy(s, P->core->core_zonename, n);
245 - } else {
246 - if (getzonenamebyid(P->status.pr_zoneid, s, n) < 0)
247 - return (NULL);
248 - s[n - 1] = '\0';
249 - }
250 - return (s);
235 + return (P->ops.pop_zonename(P, s, n, P->data));
251 236 }
252 237
253 238 char *
254 239 Pzoneroot(struct ps_prochandle *P, char *s, size_t n)
255 240 {
256 241 char zname[ZONENAME_MAX], zpath[PATH_MAX], tmp[PATH_MAX];
257 242 int rv;
258 243
259 244 if (P->zoneroot != NULL) {
260 245 (void) strlcpy(s, P->zoneroot, n);
261 246 return (s);
262 247 }
263 248
264 249 if ((Pzonename(P, zname, sizeof (zname)) == NULL) ||
265 250 (strcmp(zname, GLOBAL_ZONENAME) == 0)) {
266 251 if ((P->zoneroot = strdup("")) == NULL) {
267 252 errno = ENOMEM;
268 253 return (NULL);
269 254 }
270 255 dprintf("Pzoneroot defaulting to '%s'\n", GLOBAL_ZONENAME);
271 256 (void) strlcpy(s, P->zoneroot, n);
272 257 return (s);
273 258 }
274 259
275 260 if (i_zone_get_zonepath(zname, zpath, sizeof (zpath)) != Z_OK) {
276 261 if ((P->zoneroot = strdup("")) == NULL) {
277 262 errno = ENOMEM;
278 263 return (NULL);
279 264 }
280 265 dprintf(
281 266 "Pzoneroot zone not found '%s', defaulting to '%s'\n",
282 267 zname, GLOBAL_ZONENAME);
283 268 (void) strlcpy(s, P->zoneroot, n);
284 269 return (s);
285 270 }
286 271 (void) strlcat(zpath, "/root", sizeof (zpath));
287 272
288 273 if ((rv = resolvepath(zpath, tmp, sizeof (tmp) - 1)) < 0) {
289 274 if ((P->zoneroot = strdup("")) == NULL) {
290 275 errno = ENOMEM;
291 276 return (NULL);
292 277 }
293 278 dprintf(
294 279 "Pzoneroot can't access '%s:%s', defaulting to '%s'\n",
295 280 zname, zpath, GLOBAL_ZONENAME);
296 281 (void) strlcpy(s, P->zoneroot, n);
297 282 return (s);
298 283 }
299 284 tmp[rv] = '\0';
300 285 (void) strlcpy(zpath, tmp, sizeof (zpath));
301 286
302 287 if ((P->zoneroot = strdup(zpath)) == NULL) {
303 288 errno = ENOMEM;
304 289 return (NULL);
305 290 }
306 291 dprintf("Pzoneroot found zone root '%s:%s'\n", zname, zpath);
307 292 (void) strlcpy(s, P->zoneroot, n);
308 293 return (s);
309 294 }
310 295
311 296 /*
312 297 * Plofspath() takes a path, "path", and removes any lofs components from
313 298 * that path. The resultant path (if different from the starting path)
314 299 * is placed in "s", which is limited to "n" characters, and the return
315 300 * value is the pointer s. If there are no lofs components in the path
316 301 * the NULL is returned and s is not modified. It's ok for "path" and
317 302 * "s" to be the same pointer. (ie, the results can be stored directly
318 303 * in the input buffer.) The path that is passed in must be an absolute
319 304 * path.
320 305 *
321 306 * Example:
322 307 * if "path" == "/foo/bar", and "/candy/" is lofs mounted on "/foo/"
323 308 * then "/candy/bar/" will be written into "s" and "s" will be returned.
324 309 */
325 310 char *
326 311 Plofspath(const char *path, char *s, size_t n)
327 312 {
328 313 char tmp[PATH_MAX + 1];
329 314 struct stat64 statb;
330 315 const char *special;
331 316 char *p, *p2;
332 317 int rv;
333 318
334 319 dprintf("Plofspath path '%s'\n", path);
335 320
336 321 /* We only deal with absolute paths */
337 322 if (path[0] != '/')
338 323 return (NULL);
339 324
340 325 /* Make a copy of the path so that we can muck with it */
341 326 (void) strlcpy(tmp, path, sizeof (tmp) - 1);
342 327
343 328 /*
344 329 * Use resolvepath() to make sure there are no consecutive or
345 330 * trailing '/'s in the path.
346 331 */
347 332 if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0)
348 333 tmp[rv] = '\0';
349 334
350 335 (void) mutex_lock(&lofs_lock);
351 336
352 337 /*
353 338 * If /etc/mnttab has been modified since the last time
354 339 * we looked, then rebuild the lofs lookup cache.
355 340 */
356 341 if (stat64(MNTTAB, &statb) == 0 &&
357 342 (statb.st_mtim.tv_sec != lofs_mstat.st_mtim.tv_sec ||
358 343 statb.st_mtim.tv_nsec != lofs_mstat.st_mtim.tv_nsec ||
359 344 statb.st_ctim.tv_sec != lofs_mstat.st_ctim.tv_sec ||
360 345 statb.st_ctim.tv_nsec != lofs_mstat.st_ctim.tv_nsec)) {
361 346 lofs_mstat = statb;
362 347 rebuild_lofs_cache();
363 348 }
364 349
365 350 /*
366 351 * So now we're going to search the path for any components that
367 352 * might be lofs mounts. We'll start out search from the full
368 353 * path and then step back through each parent directly till
369 354 * we reach the root. If we find a lofs mount point in the path
370 355 * then we'll replace the initial portion of the path (up
371 356 * to that mount point) with the source of that mount point
372 357 * and then start our search over again.
373 358 *
374 359 * Here's some of the variables we're going to use:
375 360 *
376 361 * tmp - A pointer to our working copy of the path. Sometimes
377 362 * this path will be divided into two strings by a
378 363 * '\0' (NUL) character. The first string is the
379 364 * component we're currently checking and the second
380 365 * string is the path components we've already checked.
381 366 *
382 367 * p - A pointer to the last '/' seen in the string.
383 368 *
384 369 * p[1] - A pointer to the component of the string we've already
385 370 * checked.
386 371 *
387 372 * Initially, p will point to the end of our path and p[1] will point
388 373 * to an extra '\0' (NUL) that we'll append to the end of the string.
389 374 * (This is why we declared tmp with a size of PATH_MAX + 1).
390 375 */
391 376 p = &tmp[strlen(tmp)];
392 377 p[1] = '\0';
393 378 for (;;) {
394 379 if ((special = lookup_lofs_mount_point(tmp)) != NULL) {
395 380 char tmp2[PATH_MAX + 1];
396 381
397 382 /*
398 383 * We found a lofs mount. Update the path that we're
399 384 * checking and start over. This means append the
400 385 * portion of the path we've already checked to the
401 386 * source of the lofs mount and re-start this entire
402 387 * lofs resolution loop. Use resolvepath() to make
403 388 * sure there are no consecutive or trailing '/'s
404 389 * in the path.
405 390 */
406 391 (void) strlcpy(tmp2, special, sizeof (tmp2) - 1);
407 392 (void) strlcat(tmp2, "/", sizeof (tmp2) - 1);
408 393 (void) strlcat(tmp2, &p[1], sizeof (tmp2) - 1);
409 394 (void) strlcpy(tmp, tmp2, sizeof (tmp) - 1);
410 395 if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0)
411 396 tmp[rv] = '\0';
412 397 p = &tmp[strlen(tmp)];
413 398 p[1] = '\0';
414 399 continue;
415 400 }
416 401
417 402 /* No lofs mount found */
418 403 if ((p2 = strrchr(tmp, '/')) == NULL) {
419 404 char tmp2[PATH_MAX];
420 405
421 406 (void) mutex_unlock(&lofs_lock);
422 407
423 408 /*
424 409 * We know that tmp was an absolute path, so if we
425 410 * made it here we know that (p == tmp) and that
426 411 * (*p == '\0'). This means that we've managed
427 412 * to check the whole path and so we're done.
428 413 */
429 414 assert(p == tmp);
430 415 assert(p[0] == '\0');
431 416
432 417 /* Restore the leading '/' in the path */
433 418 p[0] = '/';
434 419
435 420 if (strcmp(tmp, path) == 0) {
436 421 /* The path didn't change */
437 422 return (NULL);
438 423 }
439 424
440 425 /*
441 426 * It's possible that lofs source path we just
442 427 * obtained contains a symbolic link. Use
443 428 * resolvepath() to clean it up.
444 429 */
445 430 (void) strlcpy(tmp2, tmp, sizeof (tmp2));
446 431 if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0)
447 432 tmp[rv] = '\0';
448 433
449 434 /*
450 435 * It's always possible that our lofs source path is
451 436 * actually another lofs mount. So call ourselves
452 437 * recursively to resolve that path.
453 438 */
454 439 (void) Plofspath(tmp, tmp, PATH_MAX);
455 440
456 441 /* Copy out our final resolved lofs source path */
457 442 (void) strlcpy(s, tmp, n);
458 443 dprintf("Plofspath path result '%s'\n", s);
459 444 return (s);
460 445 }
461 446
462 447 /*
463 448 * So the path we just checked is not a lofs mount. Next we
464 449 * want to check the parent path component for a lofs mount.
465 450 *
466 451 * First, restore any '/' that we replaced with a '\0' (NUL).
467 452 * We can determine if we should do this by looking at p[1].
468 453 * If p[1] points to a '\0' (NUL) then we know that p points
469 454 * to the end of the string and there is no '/' to restore.
470 455 * if p[1] doesn't point to a '\0' (NUL) then it points to
471 456 * the part of the path that we've already verified so there
472 457 * is a '/' to restore.
473 458 */
474 459 if (p[1] != '\0')
475 460 p[0] = '/';
476 461
477 462 /*
478 463 * Second, replace the last '/' in the part of the path
479 464 * that we've already checked with a '\0' (NUL) so that
480 465 * when we loop around we check the parent component of the
481 466 * path.
482 467 */
483 468 p2[0] = '\0';
484 469 p = p2;
485 470 }
486 471 /*NOTREACHED*/
487 472 }
488 473
489 474 /*
490 475 * Pzonepath() - Way too much code to attempt to derive the full path of
491 476 * an object within a zone.
492 477 *
493 478 * Pzonepath() takes a path and attempts to resolve it relative to the
494 479 * root associated with the current process handle. If it fails it will
495 480 * not update the results string. It is safe to specify the same pointer
496 481 * for the file string and the results string.
497 482 *
498 483 * Doing this resolution is more difficult than it initially sounds.
499 484 * We can't simply append the file path to the zone root, because in
500 485 * a root directory, '..' is treated the same as '.'. Also, symbolic
501 486 * links that specify an absolute path need to be interpreted relative
502 487 * to the zone root.
503 488 *
504 489 * It seems like perhaps we could do a chroot(<zone root>) followed by a
505 490 * resolvepath(). But we can't do this because chroot requires special
506 491 * privileges and affects the entire process. Perhaps if there was a
507 492 * special version of resolvepath() which took an addition root path
508 493 * we could use that, but this isn't ideal either. The reason is
509 494 * that we want to have special handling for native paths. (A native path
510 495 * is a path that begins with "/native/" or "/.SUNWnative/".) Native
511 496 * paths could be passed explicity to this function or could be embedded
512 497 * in a symlink that is part of the path passed into this function.
513 498 * These paths are always lofs mounts of global zone paths, but lofs
514 499 * mounts only exist when a zone is booted. So if we were to try to do
515 500 * a resolvepath() on a native path when the zone wasn't booted the
516 501 * resolvepath() would fail even though we know that the components
517 502 * exists in the global zone.
518 503 *
519 504 * Given all these constraints, we just implement a path walking function
520 505 * that resolves a file path relative to a zone root by manually inspecting
521 506 * each of the path components and verifying its existence. This means that
522 507 * we must have access to the zone and that all the components of the
523 508 * path must exist for this operation to succeed.
524 509 */
525 510 char *
526 511 Pzonepath(struct ps_prochandle *P, const char *path, char *s, size_t n)
527 512 {
528 513 char zroot[PATH_MAX], zpath[PATH_MAX], tmp[PATH_MAX], link[PATH_MAX];
529 514 path_node_t *pn_stack = NULL, *pn_links = NULL, *pn;
530 515 struct stat64 sb;
531 516 char *p;
532 517 int i, rv;
533 518
534 519 dprintf("Pzonepath lookup '%s'\n", path);
535 520
536 521 /* First lookup the zone root */
537 522 if (Pzoneroot(P, zroot, sizeof (zroot)) == NULL)
538 523 return (NULL);
539 524
540 525 /*
541 526 * Make a temporary copy of the path specified.
542 527 * If it's a relative path then make it into an absolute path.
543 528 */
544 529 tmp[0] = '\0';
545 530 if (path[0] != '/')
546 531 (void) strlcat(tmp, "/", sizeof (tmp));
547 532 (void) strlcat(tmp, path, sizeof (tmp));
548 533
549 534 /*
550 535 * If the path that was passed in is the zone root, we're done.
551 536 * If the path that was passed in already contains the zone root
552 537 * then strip the zone root out and verify the rest of the path.
553 538 */
554 539 if (strcmp(tmp, zroot) == 0) {
555 540 (void) Plofspath(zroot, zroot, sizeof (zroot));
556 541 dprintf("Pzonepath found zone path (1) '%s'\n", zroot);
557 542 (void) strlcpy(s, zroot, n);
558 543 return (s);
559 544 }
560 545 i = strlen(zroot);
561 546 if ((strncmp(tmp, zroot, i) == 0) && (tmp[i] == '/'))
562 547 (void) memmove(tmp, tmp + i, strlen(tmp + i) + 1);
563 548
564 549 /* If no path is passed in, then it maps to the zone root */
565 550 if (strlen(tmp) == 0) {
566 551 (void) Plofspath(zroot, zroot, sizeof (zroot));
567 552 dprintf("Pzonepath found zone path (2) '%s'\n", zroot);
568 553 (void) strlcpy(s, zroot, n);
569 554 return (s);
570 555 }
571 556
572 557 /*
573 558 * Push each path component that we plan to verify onto a stack of
574 559 * path components, with parent components at the top of the stack.
575 560 * So for example, if we're going to verify the path /foo/bar/bang
576 561 * then our stack will look like:
577 562 * foo (top)
578 563 * bar
579 564 * bang (bottom)
580 565 */
581 566 while ((p = strrchr(tmp, '/')) != NULL) {
582 567 *p = '\0';
583 568 if (pn_push(&pn_stack, &p[1]) != NULL)
584 569 continue;
585 570 pn_free(&pn_stack);
586 571 return (NULL);
587 572 }
588 573
589 574 /* We're going to store the final zone relative path in zpath */
590 575 *zpath = '\0';
591 576
592 577 while (pn_pop(&pn_stack, tmp) != NULL) {
593 578 /*
594 579 * Drop zero length path components (which come from
595 580 * consecutive '/'s) and '.' path components.
596 581 */
597 582 if ((strlen(tmp) == 0) || (strcmp(tmp, ".") == 0))
598 583 continue;
599 584
600 585 /*
601 586 * Check the current path component for '..', if found
602 587 * drop any previous path component.
603 588 */
604 589 if (strcmp(tmp, "..") == 0) {
605 590 if ((p = strrchr(zpath, '/')) != NULL)
606 591 *p = '\0';
607 592 continue;
608 593 }
609 594
610 595 /* The path we want to verify now is zpath + / + tmp. */
611 596 (void) strlcat(zpath, "/", sizeof (zpath));
612 597 (void) strlcat(zpath, tmp, sizeof (zpath));
613 598
614 599 /*
615 600 * Check if this is a native object. A native object is an
616 601 * object from the global zone that is running in a branded
617 602 * zone. These objects are lofs mounted into a zone. So if a
618 603 * branded zone is not booted then lofs mounts won't be setup
619 604 * so we won't be able to find these objects. Luckily, we know
620 605 * that they exist in the global zone with the same path sans
621 606 * the initial native component, so we'll just strip out the
622 607 * native component here.
623 608 */
624 609 if ((strncmp(zpath, "/native", sizeof ("/native")) == 0) ||
625 610 (strncmp(zpath, "/.SUNWnative",
626 611 sizeof ("/.SUNWnative")) == 0)) {
627 612
628 613 /* Free any cached symlink paths */
629 614 pn_free(&pn_links);
630 615
631 616 /* Reconstruct the path from our path component stack */
632 617 *zpath = '\0';
633 618 while (pn_pop(&pn_stack, tmp) != NULL) {
634 619 (void) strlcat(zpath, "/", sizeof (zpath));
635 620 (void) strlcat(zpath, tmp, sizeof (zpath));
636 621 }
637 622
638 623 /* Verify that the path actually exists */
639 624 rv = resolvepath(zpath, tmp, sizeof (tmp) - 1);
640 625 if (rv < 0) {
641 626 dprintf("Pzonepath invalid native path '%s'\n",
642 627 zpath);
643 628 return (NULL);
644 629 }
645 630 tmp[rv] = '\0';
646 631
647 632 /* Return the path */
648 633 dprintf("Pzonepath found native path '%s'\n", tmp);
649 634 (void) Plofspath(tmp, tmp, sizeof (tmp));
650 635 (void) strlcpy(s, tmp, n);
651 636 return (s);
652 637 }
653 638
654 639 /*
655 640 * Check if the path points to a symlink. We do this
656 641 * explicitly since any absolute symlink needs to be
657 642 * interpreted relativly to the zone root and not "/".
658 643 */
659 644 (void) strlcpy(tmp, zroot, sizeof (tmp));
660 645 (void) strlcat(tmp, zpath, sizeof (tmp));
661 646 if (lstat64(tmp, &sb) != 0) {
662 647 pn_free2(&pn_stack, &pn_links);
663 648 return (NULL);
664 649 }
665 650 if (!S_ISLNK(sb.st_mode)) {
666 651 /*
667 652 * Since the lstat64() above succeeded we know that
668 653 * zpath exists, since this is not a symlink loop
669 654 * around and check the next path component.
670 655 */
671 656 continue;
672 657 }
673 658
674 659 /*
675 660 * Symlink allow for paths with loops. Make sure
676 661 * we're not stuck in a loop.
677 662 */
678 663 for (pn = pn_links; pn != NULL; pn = pn->pn_next) {
679 664 if (strcmp(zpath, pn->pn_path) != 0)
680 665 continue;
681 666
682 667 /* We have a loop. Fail. */
683 668 dprintf("Pzonepath symlink loop '%s'\n", zpath);
684 669 pn_free2(&pn_stack, &pn_links);
685 670 return (NULL);
686 671 }
687 672
688 673 /* Save this symlink path for future loop checks */
689 674 if (pn_push(&pn_links, zpath) == NULL) {
690 675 /* Out of memory */
691 676 pn_free2(&pn_stack, &pn_links);
692 677 return (NULL);
693 678 }
694 679
695 680 /* Now follow the contents of the symlink */
696 681 bzero(link, sizeof (link));
697 682 if (readlink(tmp, link, sizeof (link)) == -1) {
698 683 pn_free2(&pn_stack, &pn_links);
699 684 return (NULL);
700 685 }
701 686
702 687 dprintf("Pzonepath following symlink '%s' -> '%s'\n",
703 688 zpath, link);
704 689
705 690 /*
706 691 * Push each path component of the symlink target onto our
707 692 * path components stack since we need to verify each one.
708 693 */
709 694 while ((p = strrchr(link, '/')) != NULL) {
710 695 *p = '\0';
711 696 if (pn_push(&pn_stack, &p[1]) != NULL)
712 697 continue;
713 698 pn_free2(&pn_stack, &pn_links);
714 699 return (NULL);
715 700 }
716 701
717 702 /* absolute or relative symlink? */
718 703 if (*link == '\0') {
719 704 /* Absolute symlink, nuke existing zpath. */
720 705 *zpath = '\0';
721 706 continue;
722 707 }
723 708
724 709 /*
725 710 * Relative symlink. Push the first path component of the
726 711 * symlink target onto our stack for verification and then
727 712 * remove the current path component from zpath.
728 713 */
729 714 if (pn_push(&pn_stack, link) == NULL) {
730 715 pn_free2(&pn_stack, &pn_links);
731 716 return (NULL);
732 717 }
733 718 p = strrchr(zpath, '/');
734 719 assert(p != NULL);
735 720 *p = '\0';
736 721 continue;
737 722 }
738 723 pn_free(&pn_links);
739 724
740 725 /* Place the final result in zpath */
741 726 (void) strlcpy(tmp, zroot, sizeof (tmp));
742 727 (void) strlcat(tmp, zpath, sizeof (tmp));
743 728 (void) strlcpy(zpath, tmp, sizeof (zpath));
744 729
745 730 (void) Plofspath(zpath, zpath, sizeof (zpath));
746 731 dprintf("Pzonepath found zone path (3) '%s'\n", zpath);
747 732
748 733 (void) strlcpy(s, zpath, n);
749 734 return (s);
750 735 }
751 736
752 737 char *
753 738 Pfindobj(struct ps_prochandle *P, const char *path, char *s, size_t n)
754 739 {
755 740 int len;
756 741
757 742 dprintf("Pfindobj '%s'\n", path);
758 743
759 744 /* We only deal with absolute paths */
760 745 if (path[0] != '/')
761 746 return (NULL);
762 747
763 748 /* First try to resolve the path to some zone */
764 749 if (Pzonepath(P, path, s, n) != NULL)
765 750 return (s);
766 751
767 752 /* If that fails resolve any lofs links in the path */
768 753 if (Plofspath(path, s, n) != NULL)
769 754 return (s);
770 755
771 756 /* If that fails then just see if the path exists */
772 757 if ((len = resolvepath(path, s, n)) > 0) {
773 758 s[len] = '\0';
774 759 return (s);
775 760 }
776 761
777 762 return (NULL);
778 763 }
779 764
780 765 char *
781 766 Pfindmap(struct ps_prochandle *P, map_info_t *mptr, char *s, size_t n)
782 767 {
783 768 file_info_t *fptr = mptr->map_file;
784 769 char buf[PATH_MAX];
785 770 int len;
786 771
787 772 /* If it's already been explicity set return that */
788 773 if ((fptr != NULL) && (fptr->file_rname != NULL)) {
789 774 (void) strlcpy(s, fptr->file_rname, n);
790 775 return (s);
791 776 }
792 777
793 778 /* If it's the a.out segment, defer to the magical Pexecname() */
794 779 if ((P->map_exec == mptr) ||
795 780 (strcmp(mptr->map_pmap.pr_mapname, "a.out") == 0) ||
796 781 ((fptr != NULL) && (fptr->file_lname != NULL) &&
797 782 (strcmp(fptr->file_lname, "a.out") == 0))) {
798 783 if (Pexecname(P, buf, sizeof (buf)) != NULL) {
799 784 (void) strlcpy(s, buf, n);
800 785 return (s);
801 786 }
802 787 }
803 788
804 789 /* Try /proc first to get the real object name */
805 790 if ((Pstate(P) != PS_DEAD) && (mptr->map_pmap.pr_mapname[0] != '\0')) {
806 791 (void) snprintf(buf, sizeof (buf), "%s/%d/path/%s",
807 792 procfs_path, (int)P->pid, mptr->map_pmap.pr_mapname);
808 793 if ((len = readlink(buf, buf, sizeof (buf))) > 0) {
809 794 buf[len] = '\0';
810 795 (void) Plofspath(buf, buf, sizeof (buf));
811 796 (void) strlcpy(s, buf, n);
812 797 return (s);
813 798 }
814 799 }
815 800
816 801 /*
817 802 * If we couldn't get the name from /proc, take the lname and
818 803 * try to expand it on the current system to a real object path.
819 804 */
820 805 fptr = mptr->map_file;
821 806 if ((fptr != NULL) && (fptr->file_lname != NULL)) {
822 807 (void) strlcpy(buf, fptr->file_lname, sizeof (buf));
823 808 if (Pfindobj(P, buf, buf, sizeof (buf)) == NULL)
824 809 return (NULL);
825 810 (void) strlcpy(s, buf, n);
826 811 return (s);
827 812 }
828 813
829 814 return (NULL);
830 815 }
↓ open down ↓ |
570 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX