devinfo_realpath.c revision ff2aee480f8fc985fe6a84c8d593c7a13c7a0481
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * CDDL HEADER START
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * The contents of this file are subject to the terms of the
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Common Development and Distribution License (the "License").
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * You may not use this file except in compliance with the License.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * or http://www.opensolaris.org/os/licensing.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * See the License for the specific language governing permissions
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * and limitations under the License.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * When distributing Covered Code, include this CDDL HEADER in each
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If applicable, add the following below this CDDL HEADER, with the
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * fields enclosed by brackets "[]" replaced with your own identifying
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * information: Portions Copyright [yyyy] [name of copyright owner]
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * CDDL HEADER END
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * Use is subject to license terms.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#pragma ident "%Z%%M% %I% %E% SMI"
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Redistribution and use in source and binary forms, with or without
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * modification, are permitted provided that the following conditions
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * are met:
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * 1. Redistributions of source code must retain the above copyright
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * notice, this list of conditions and the following disclaimer.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * 2. Redistributions in binary form must reproduce the above copyright
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * notice, this list of conditions and the following disclaimer in the
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * documentation and/or other materials provided with the distribution.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * 3. The names of the authors may not be used to endorse or promote
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * products derived from this software without specific prior written
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * permission.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * SUCH DAMAGE.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdlib/realpath.c
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * $OpenBSD: realpath.c,v 1.13 2005/08/08 08:05:37 espie Exp $
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#include <stdio.h>
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#include <unistd.h>
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#include <string.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <limits.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <errno.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/types.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/stat.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/param.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * char *s_realpath(const char *path, char resolved_path[MAXPATHLEN]);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Find the real name of path, by removing all ".", ".." and symlink
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * components. Returns (resolved) on success, or (NULL) on failure,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * in which case the path which caused trouble is left in (resolved).
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * DEVINFO: For libdevinfo we have added code to special case symlinks into
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * /devices - the path below that point is known to not point to any
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * additional symlinks. This knowledge allows us to avoid causing attach.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymchar *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherryms_realpath(const char *path, char *resolved)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct stat sb;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym char *p, *q, *s;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym size_t left_len, resolved_len;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym unsigned symlinks;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int serrno, slen;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym serrno = errno;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym symlinks = 0;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (path[0] == '/') {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym resolved[0] = '/';
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym resolved[1] = '\0';
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (path[1] == '\0')
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (resolved);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym resolved_len = 1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym left_len = strlcpy(left, path + 1, sizeof (left));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (getcwd(resolved, PATH_MAX) == NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) strlcpy(resolved, ".", PATH_MAX);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (NULL);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym resolved_len = strlen(resolved);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson left_len = strlcpy(left, path, sizeof (left));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (left_len >= sizeof (left) || resolved_len >= PATH_MAX) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym errno = ENAMETOOLONG;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (NULL);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Iterate over path components in `left'.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym while (left_len != 0) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Extract the next path component and adjust `left'
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * and its length.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson p = strchr(left, '/');
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson s = p ? p : left + left_len;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (s - left >= sizeof (next_token)) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson errno = ENAMETOOLONG;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (NULL);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) memcpy(next_token, left, s - left);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson next_token[s - left] = '\0';
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson left_len -= s - left;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (p != NULL)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) memmove(left, s + 1, left_len + 1);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (resolved[resolved_len - 1] != '/') {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (resolved_len + 1 >= PATH_MAX) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson errno = ENAMETOOLONG;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (NULL);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson resolved[resolved_len++] = '/';
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson resolved[resolved_len] = '\0';
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (next_token[0] == '\0')
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson continue;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson else if (strcmp(next_token, ".") == 0)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson continue;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson else if (strcmp(next_token, "..") == 0) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * Strip the last path component except when we have
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * single "/"
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (resolved_len > 1) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson resolved[resolved_len - 1] = '\0';
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson q = strrchr(resolved, '/') + 1;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson *q = '\0';
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson resolved_len = q - resolved;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson continue;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * Append the next path component and lstat() it. If
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * lstat() fails we still can return successfully if
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * there are no more path components left.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson resolved_len = strlcat(resolved, next_token, PATH_MAX);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (resolved_len >= PATH_MAX) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson errno = ENAMETOOLONG;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (NULL);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * DEVINFO: Check if link points into /devices and resolve
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * without causing attach if that is the case - there are no
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * further symlinks in /devices.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (strcmp(resolved, "/devices") == 0) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson resolved[resolved_len] = '/';
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym resolved_len = strlcat(resolved, left, sizeof (left));
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson left_len = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (lstat(resolved, &sb) != 0) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (errno == ENOENT && p == NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym errno = serrno;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (resolved);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (NULL);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (S_ISLNK(sb.st_mode)) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (symlinks++ > MAXSYMLINKS) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson errno = ELOOP;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (NULL);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson slen = readlink(resolved, symlink,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym sizeof (symlink) - 1);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (slen < 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (NULL);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym symlink[slen] = '\0';
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (symlink[0] == '/') {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym resolved[1] = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym resolved_len = 1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else if (resolved_len > 1) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* Strip the last path component. */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson resolved[resolved_len - 1] = '\0';
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym q = strrchr(resolved, '/') + 1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *q = '\0';
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym resolved_len = q - resolved;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * If there are any path components left, then
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * append them to symlink. The result is placed
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * in `left'.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (p != NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (symlink[slen - 1] != '/') {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (slen + 1 >= sizeof (symlink)) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym errno = ENAMETOOLONG;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (NULL);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym symlink[slen] = '/';
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym symlink[slen + 1] = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym left_len = strlcat(symlink, left,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym sizeof (left));
if (left_len >= sizeof (left)) {
errno = ENAMETOOLONG;
return (NULL);
}
}
left_len = strlcpy(left, symlink, sizeof (left));
}
}
/*
* Remove trailing slash except when the resolved pathname
* is a single "/".
*/
if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
resolved[resolved_len - 1] = '\0';
return (resolved);
}