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