/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
*/
#include <assert.h>
#include <dlfcn.h>
#include <errno.h>
#include <libzonecfg.h>
#include <link.h>
#include <string.h>
#include <strings.h>
#include "Pcontrol.h"
struct path_node {
char *pn_path;
};
/*
* Parameters of the lofs lookup cache.
*/
static void
rebuild_lofs_cache(void)
{
/* destroy the old cache */
}
lofs_mnttab = NULL;
/* prepare to create the new cache */
return;
/*
* We only care about lofs mount points. But we need to
* ignore lofs mounts where the source path is the same
* as the target path. (This can happen when a non-global
* zone has a lofs mount of a global zone filesystem, since
* the source path can't expose information about global
* zone paths to the non-global zone.)
*/
break;
lofs_mnttab = lmt;
}
}
static const char *
{
}
return (NULL);
}
static path_node_t *
{
return (NULL);
return (NULL);
}
}
static void
{
}
}
static void
{
}
static char *
{
return (NULL);
return (NULL);
}
return (path);
}
/*
* Libzonecfg.so links against libproc, so libproc can't link against
* libzonecfg.so. Also, libzonecfg.so is optional and might not be
* installed. Hence instead of relying on linking to access libzonecfg.so,
* we'll try dlopening it here. This trick is borrowed from
* libc`zone_get_id(), see that function for more detailed comments.
*/
static int
{
if (zone_get_zonepath_fp == NULL) {
/* There's no harm in doing this multiple times. */
sym = (void *)(-1);
}
}
/* If we've successfully loaded it, call the real function */
return (Z_NO_ZONE);
}
char *
{
long addr;
return (NULL);
return (NULL);
return (buf);
}
/*
* Get the zone name from the core file if we have it; look up the
* name based on the zone id if this is a live process.
*/
char *
{
}
char *
{
int rv;
return (s);
}
return (NULL);
}
return (s);
}
return (NULL);
}
"Pzoneroot zone not found '%s', defaulting to '%s'\n",
return (s);
}
return (NULL);
}
"Pzoneroot can't access '%s:%s', defaulting to '%s'\n",
return (s);
}
return (NULL);
}
return (s);
}
/*
* Plofspath() takes a path, "path", and removes any lofs components from
* that path. The resultant path (if different from the starting path)
* is placed in "s", which is limited to "n" characters, and the return
* value is the pointer s. If there are no lofs components in the path
* the NULL is returned and s is not modified. It's ok for "path" and
* "s" to be the same pointer. (ie, the results can be stored directly
* in the input buffer.) The path that is passed in must be an absolute
* path.
*
* Example:
*/
char *
{
const char *special;
char *p, *p2;
int rv;
/* We only deal with absolute paths */
if (path[0] != '/')
return (NULL);
/* Make a copy of the path so that we can muck with it */
/*
* Use resolvepath() to make sure there are no consecutive or
* trailing '/'s in the path.
*/
(void) mutex_lock(&lofs_lock);
/*
* we looked, then rebuild the lofs lookup cache.
*/
lofs_mstat = statb;
}
/*
* So now we're going to search the path for any components that
* might be lofs mounts. We'll start out search from the full
* path and then step back through each parent directly till
* we reach the root. If we find a lofs mount point in the path
* then we'll replace the initial portion of the path (up
* to that mount point) with the source of that mount point
* and then start our search over again.
*
* Here's some of the variables we're going to use:
*
* tmp - A pointer to our working copy of the path. Sometimes
* this path will be divided into two strings by a
* '\0' (NUL) character. The first string is the
* component we're currently checking and the second
* string is the path components we've already checked.
*
* p - A pointer to the last '/' seen in the string.
*
* p[1] - A pointer to the component of the string we've already
* checked.
*
* Initially, p will point to the end of our path and p[1] will point
* to an extra '\0' (NUL) that we'll append to the end of the string.
* (This is why we declared tmp with a size of PATH_MAX + 1).
*/
p[1] = '\0';
for (;;) {
/*
* We found a lofs mount. Update the path that we're
* checking and start over. This means append the
* portion of the path we've already checked to the
* source of the lofs mount and re-start this entire
* lofs resolution loop. Use resolvepath() to make
* sure there are no consecutive or trailing '/'s
* in the path.
*
* However, we need to be careful to handle the case of
* a lofs mounted file under a lofs mounted file system.
* In this case, we just keep going.
*/
0) {
p[1] = '\0';
continue;
}
}
/* No lofs mount found */
(void) mutex_unlock(&lofs_lock);
/*
* We know that tmp was an absolute path, so if we
* made it here we know that (p == tmp) and that
* (*p == '\0'). This means that we've managed
* to check the whole path and so we're done.
*/
assert(p[0] == '\0');
/* Restore the leading '/' in the path */
p[0] = '/';
/* The path didn't change */
return (NULL);
}
/*
* It's possible that lofs source path we just
* obtained contains a symbolic link. Use
* resolvepath() to clean it up.
*/
/*
* It's always possible that our lofs source path is
* actually another lofs mount. So call ourselves
* recursively to resolve that path.
*/
/* Copy out our final resolved lofs source path */
dprintf("Plofspath path result '%s'\n", s);
return (s);
}
/*
* So the path we just checked is not a lofs mount. Next we
* want to check the parent path component for a lofs mount.
*
* First, restore any '/' that we replaced with a '\0' (NUL).
* We can determine if we should do this by looking at p[1].
* If p[1] points to a '\0' (NUL) then we know that p points
* to the end of the string and there is no '/' to restore.
* if p[1] doesn't point to a '\0' (NUL) then it points to
* the part of the path that we've already verified so there
* is a '/' to restore.
*/
if (p[1] != '\0')
p[0] = '/';
/*
* Second, replace the last '/' in the part of the path
* that we've already checked with a '\0' (NUL) so that
* when we loop around we check the parent component of the
* path.
*/
p2[0] = '\0';
p = p2;
}
/*NOTREACHED*/
}
/*
* Pzonepath() - Way too much code to attempt to derive the full path of
* an object within a zone.
*
* Pzonepath() takes a path and attempts to resolve it relative to the
* root associated with the current process handle. If it fails it will
* not update the results string. It is safe to specify the same pointer
* for the file string and the results string.
*
* Doing this resolution is more difficult than it initially sounds.
* We can't simply append the file path to the zone root, because in
* a root directory, '..' is treated the same as '.'. Also, symbolic
* links that specify an absolute path need to be interpreted relative
* to the zone root.
*
* It seems like perhaps we could do a chroot(<zone root>) followed by a
* resolvepath(). But we can't do this because chroot requires special
* privileges and affects the entire process. Perhaps if there was a
* special version of resolvepath() which took an addition root path
* we could use that, but this isn't ideal either. The reason is
* that we want to have special handling for native paths. (A native path
* is a path that begins with "/native/" or "/.SUNWnative/".) Native
* paths could be passed explicity to this function or could be embedded
* in a symlink that is part of the path passed into this function.
* These paths are always lofs mounts of global zone paths, but lofs
* mounts only exist when a zone is booted. So if we were to try to do
* a resolvepath() on a native path when the zone wasn't booted the
* resolvepath() would fail even though we know that the components
* exists in the global zone.
*
* Given all these constraints, we just implement a path walking function
* that resolves a file path relative to a zone root by manually inspecting
* each of the path components and verifying its existence. This means that
* we must have access to the zone and that all the components of the
* path must exist for this operation to succeed.
*/
char *
{
char *p;
int i, rv;
/* First lookup the zone root */
return (NULL);
/*
* Make a temporary copy of the path specified.
* If it's a relative path then make it into an absolute path.
*/
tmp[0] = '\0';
if (path[0] != '/')
/*
* If the path that was passed in is the zone root, we're done.
* If the path that was passed in already contains the zone root
* then strip the zone root out and verify the rest of the path.
*/
return (s);
}
/* If no path is passed in, then it maps to the zone root */
return (s);
}
/*
* Push each path component that we plan to verify onto a stack of
* path components, with parent components at the top of the stack.
* then our stack will look like:
* foo (top)
* bar
* bang (bottom)
*/
*p = '\0';
continue;
return (NULL);
}
/* We're going to store the final zone relative path in zpath */
*zpath = '\0';
/*
* Drop zero length path components (which come from
* consecutive '/'s) and '.' path components.
*/
continue;
/*
* Check the current path component for '..', if found
* drop any previous path component.
*/
*p = '\0';
continue;
}
/* The path we want to verify now is zpath + / + tmp. */
/*
* Check if this is a native object. A native object is an
* object from the global zone that is running in a branded
* zone. These objects are lofs mounted into a zone. So if a
* branded zone is not booted then lofs mounts won't be setup
* so we won't be able to find these objects. Luckily, we know
* that they exist in the global zone with the same path sans
* the initial native component, so we'll just strip out the
* native component here.
*/
sizeof ("/.SUNWnative")) == 0)) {
/* Free any cached symlink paths */
/* Reconstruct the path from our path component stack */
*zpath = '\0';
}
/* Verify that the path actually exists */
if (rv < 0) {
dprintf("Pzonepath invalid native path '%s'\n",
zpath);
return (NULL);
}
/* Return the path */
return (s);
}
/*
* Check if the path points to a symlink. We do this
* explicitly since any absolute symlink needs to be
* interpreted relativly to the zone root and not "/".
*/
return (NULL);
}
/*
* Since the lstat64() above succeeded we know that
* zpath exists, since this is not a symlink loop
* around and check the next path component.
*/
continue;
}
/*
* Symlink allow for paths with loops. Make sure
* we're not stuck in a loop.
*/
continue;
/* We have a loop. Fail. */
return (NULL);
}
/* Save this symlink path for future loop checks */
/* Out of memory */
return (NULL);
}
/* Now follow the contents of the symlink */
return (NULL);
}
dprintf("Pzonepath following symlink '%s' -> '%s'\n",
/*
* Push each path component of the symlink target onto our
* path components stack since we need to verify each one.
*/
*p = '\0';
continue;
return (NULL);
}
/* absolute or relative symlink? */
if (*link == '\0') {
/* Absolute symlink, nuke existing zpath. */
*zpath = '\0';
continue;
}
/*
* Relative symlink. Push the first path component of the
* symlink target onto our stack for verification and then
* remove the current path component from zpath.
*/
return (NULL);
}
*p = '\0';
continue;
}
/* Place the final result in zpath */
return (s);
}
char *
{
int len;
/* We only deal with absolute paths */
if (path[0] != '/')
return (NULL);
/* First try to resolve the path to some zone */
return (s);
/* If that fails resolve any lofs links in the path */
return (s);
/* If that fails then just see if the path exists */
s[len] = '\0';
return (s);
}
return (NULL);
}
char *
{
int len;
/* If it's already been explicity set return that */
return (s);
}
/* If it's the a.out segment, defer to the magical Pexecname() */
return (s);
}
}
/* Try /proc first to get the real object name */
return (s);
}
}
/*
* If we couldn't get the name from /proc, take the lname and
* try to expand it on the current system to a real object path.
*/
return (NULL);
return (s);
}
return (NULL);
}