summaryrefslogtreecommitdiff
path: root/usr/src/lib/libadm/common/fulldevnm.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libadm/common/fulldevnm.c')
-rw-r--r--usr/src/lib/libadm/common/fulldevnm.c489
1 files changed, 489 insertions, 0 deletions
diff --git a/usr/src/lib/libadm/common/fulldevnm.c b/usr/src/lib/libadm/common/fulldevnm.c
new file mode 100644
index 0000000000..f22035342e
--- /dev/null
+++ b/usr/src/lib/libadm/common/fulldevnm.c
@@ -0,0 +1,489 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*LINTLIBRARY*/
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/vfstab.h>
+#include <sys/lofi.h>
+#include <sys/ramdisk.h>
+#include <sys/fssnap_if.h>
+#include "libadm.h"
+
+/*
+ * Globals:
+ * getfullrawname - returns a fully-qualified raw device name
+ * getfullblkname - returns a fully-qualified block device name
+ *
+ * These two routines take a device pathname and return corresponding
+ * the raw or block device name.
+ *
+ * First the device name is fully qualified:
+ * If the device name does not start with a '/' or starts with
+ * './' then the current working directory is added to the beginning
+ * of the pathname.
+ *
+ * If the device name starts with a '../' then all but the last
+ * sub-directory of the current working directory is added to the
+ * the beginning of the pathname.
+ *
+ * Second if the fully-qualified device name given is the raw/block
+ * device that is being asked for then the fully-qualified device name is
+ * returned.
+ *
+ * Third if an entry is found in /etc/vfstab which matches the given name
+ * then the corresponding raw/block device is returned. This allows
+ * non-standard names to be converted (.i.e., block device "/dev/joe" can
+ * be converted to raw device "/dev/fred", via this mechanism).
+ *
+ * Last standard names are converted. Standard names are those
+ * with a '/dsk/' for block or '/rdsk/' for raw sub-directory components
+ * in the device name. Or, the filename component has an 'r' for raw or
+ * no 'r' for block (e.g., rsd0a <=> sd0a).
+ *
+ * Caveat:
+ * It is assumed that the block and raw devices have the
+ * same device number, and this is used to verify the conversion
+ * happened corretly. If this happens not to be true, due to mapping
+ * of minor numbers or sometheing, then entries can be put in the
+ * the '/etc/vfstab' file to over-ride this checking.
+ *
+ *
+ * Return Values:
+ * raw/block device name - (depending on which routine is used)
+ * null string - When the conversion failed
+ * null pointer - malloc problems
+ *
+ * It is up to the user of these routines to free the memory, of
+ * the device name or null string returned by these library routines,
+ * when appropriate by the application.
+ */
+#define GET_BLK 0
+#define GET_RAW 1
+
+static int test_if_blk(char *, dev_t);
+static int test_if_raw(char *, dev_t);
+static char *getblkcomplete(char *, struct stat64 *);
+static char *getrawcomplete(char *, struct stat64 *);
+
+/*
+ * getfullname() - Builds a fully qualified pathname.
+ * This handles . and .. as well.
+ * NOTE: This is different from realpath(3C) because
+ * it does not follow links.
+ */
+static char *
+getfullname(char *path)
+{
+ char cwd[MAXPATHLEN];
+ char *c;
+ char *wa;
+ size_t len;
+
+ if (*path == '/')
+ return (strdup(path));
+
+ if (getcwd(cwd, sizeof (cwd)) == NULL)
+ return (strdup(""));
+
+ /* handle . and .. */
+ if (strncmp(path, "./", 2) == 0) {
+ /* strip the ./ from the given path */
+ path += 2;
+ } else if (strncmp(path, "../", 3) == 0) {
+ /* strip the last directory component from cwd */
+ c = strrchr(cwd, '/');
+ *c = '\0';
+
+ /* strip the ../ from the given path */
+ path += 3;
+ }
+
+ /*
+ * Adding 2 takes care of slash and null terminator.
+ */
+ len = strlen(cwd) + strlen(path) + 2;
+ if ((wa = malloc(len)) == NULL)
+ return (NULL);
+
+ (void) strcpy(wa, cwd);
+ (void) strcat(wa, "/");
+ (void) strcat(wa, path);
+
+ return (wa);
+}
+
+/*
+ * test the path/fname to see if is blk special
+ */
+static int
+test_if_blk(char *new_path, dev_t raw_dev)
+{
+ struct stat64 buf;
+
+ /* check if we got a char special file */
+ if (stat64(new_path, &buf) != 0)
+ return (0);
+
+ if (!S_ISBLK(buf.st_mode))
+ return (0);
+
+ if (raw_dev != buf.st_rdev)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * test the path/fname to see if is char special
+ */
+static int
+test_if_raw(char *new_path, dev_t blk_dev)
+{
+ struct stat64 buf;
+
+ /* check if we got a char special file */
+ if (stat64(new_path, &buf) != 0)
+ return (0);
+
+ if (!S_ISCHR(buf.st_mode))
+ return (0);
+
+ if (blk_dev != buf.st_rdev)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * complete getblkrawname() for blk->raw to handle volmgt devices
+ */
+
+static char *
+getblkcomplete(char *cp, struct stat64 *dat)
+{
+ char *dp;
+ char *new_path;
+ char c;
+
+ /* ok, so we either have a bad device or a floppy */
+
+ /* try the rfd# form */
+ if ((dp = strstr(cp, "/rfd")) != NULL) {
+ if ((new_path = malloc(strlen(cp))) == NULL)
+ return (NULL);
+
+ c = *++dp; /* save the 'r' */
+ *dp = '\0'; /* replace it with a null */
+ (void) strcpy(new_path, cp); /* save first part of it */
+ *dp++ = c; /* give the 'r' back */
+ (void) strcat(new_path, dp); /* copy, skipping the 'r' */
+
+ if (test_if_blk(new_path, dat->st_rdev))
+ return (new_path);
+
+ free(new_path);
+ return (strdup(""));
+ }
+
+ /* try the rdiskette form */
+ if ((dp = strstr(cp, "/rdiskette")) != NULL) {
+ if ((new_path = malloc(strlen(cp))) == NULL)
+ return (NULL);
+
+ c = *++dp; /* save the 'r' */
+ *dp = '\0'; /* replace it with a null */
+ (void) strcpy(new_path, cp); /* save first part of it */
+ *dp++ = c; /* give the 'r' back */
+ (void) strcat(new_path, dp); /* copy, skipping the 'r' */
+
+ if (test_if_blk(new_path, dat->st_rdev))
+ return (new_path);
+
+ free(new_path);
+ return (strdup(""));
+ }
+
+ /* no match found */
+ return (strdup(""));
+}
+
+/*
+ * complete getfullrawname() for raw->blk to handle volmgt devices
+ */
+
+static char *
+getrawcomplete(char *cp, struct stat64 *dat)
+{
+ char *dp;
+ char *new_path;
+ char c;
+
+ /* ok, so we either have a bad device or a floppy */
+
+ /* try the fd# form */
+ if ((dp = strstr(cp, "/fd")) != NULL) {
+ /* malloc path for new_path to hold raw */
+ if ((new_path = malloc(strlen(cp)+2)) == NULL)
+ return (NULL);
+
+ c = *++dp; /* save the 'f' */
+ *dp = '\0'; /* replace it with a null */
+ (void) strcpy(new_path, cp); /* save first part of it */
+ *dp = c; /* put the 'f' back */
+ (void) strcat(new_path, "r"); /* insert an 'r' */
+ (void) strcat(new_path, dp); /* copy the rest */
+
+ if (test_if_raw(new_path, dat->st_rdev))
+ return (new_path);
+
+ free(new_path);
+ }
+
+ /* try the diskette form */
+ if ((dp = strstr(cp, "/diskette")) != NULL) {
+ /* malloc path for new_path to hold raw */
+ if ((new_path = malloc(strlen(cp)+2)) == NULL)
+ return (NULL);
+
+ c = *++dp; /* save at 'd' */
+ *dp = '\0'; /* replace it with a null */
+ (void) strcpy(new_path, cp); /* save first part */
+ *dp = c; /* put the 'd' back */
+ (void) strcat(new_path, "r"); /* insert an 'r' */
+ (void) strcat(new_path, dp); /* copy the rest */
+
+ if (test_if_raw(new_path, dat->st_rdev))
+ return (new_path);
+
+ free(new_path);
+ return (strdup(""));
+ }
+
+ /* failed to build raw name, return null string */
+ return (strdup(""));
+
+
+
+}
+
+static char *
+getvfsspecial(char *path, int raw_special)
+{
+ FILE *fp;
+ struct vfstab vp;
+ struct vfstab ref_vp;
+
+ if ((fp = fopen("/etc/vfstab", "r")) == NULL)
+ return (NULL);
+
+ (void) memset(&ref_vp, 0, sizeof (struct vfstab));
+
+ if (raw_special)
+ ref_vp.vfs_special = path;
+ else
+ ref_vp.vfs_fsckdev = path;
+
+ if (getvfsany(fp, &vp, &ref_vp)) {
+ (void) fclose(fp);
+ return (NULL);
+ }
+
+ (void) fclose(fp);
+
+ if (raw_special)
+ return (vp.vfs_fsckdev);
+
+ return (vp.vfs_special);
+}
+
+/*
+ * change the device name to a block device name
+ */
+char *
+getfullblkname(char *cp)
+{
+ struct stat64 buf;
+ char *dp;
+ char *new_path;
+ dev_t raw_dev;
+
+ if (cp == NULL)
+ return (strdup(""));
+
+ /*
+ * Create a fully qualified name.
+ */
+ if ((cp = getfullname(cp)) == NULL)
+ return (NULL);
+
+ if (*cp == '\0')
+ return (cp);
+
+ if (stat64(cp, &buf) != 0) {
+ free(cp);
+ return (strdup(""));
+ }
+
+ if (S_ISBLK(buf.st_mode))
+ return (cp);
+
+ if (!S_ISCHR(buf.st_mode)) {
+ free(cp);
+ return (strdup(""));
+ }
+
+ if ((dp = getvfsspecial(cp, GET_BLK)) != NULL) {
+ free(cp);
+ return (strdup(dp));
+ }
+
+ raw_dev = buf.st_rdev;
+
+ /*
+ * We have a raw device name, go find the block name.
+ */
+ if ((dp = strstr(cp, "/rdsk/")) == NULL &&
+ (dp = strstr(cp, "/" LOFI_CHAR_NAME "/")) == NULL &&
+ (dp = strstr(cp, "/" RD_CHAR_NAME "/")) == NULL &&
+ (dp = strstr(cp, "/" SNAP_CHAR_NAME "/")) == NULL &&
+ (dp = strrchr(cp, '/')) == NULL) {
+ /* this is not really possible */
+ free(cp);
+ return (strdup(""));
+ }
+ dp++;
+ if (*dp != 'r') {
+ dp = getblkcomplete(cp, &buf);
+ free(cp);
+ return (dp);
+ }
+ if ((new_path = malloc(strlen(cp))) == NULL) {
+ free(cp);
+ return (NULL);
+ }
+ (void) strncpy(new_path, cp, dp - cp);
+
+ /* fill in the rest of the unraw name */
+ (void) strcpy(new_path + (dp - cp), dp + 1);
+
+ if (test_if_blk(new_path, raw_dev)) {
+ free(cp);
+ /* block name was found, return it here */
+ return (new_path);
+ }
+ free(new_path);
+
+ dp = getblkcomplete(cp, &buf);
+ free(cp);
+ return (dp);
+}
+
+/*
+ * change the device name to a raw devname
+ */
+char *
+getfullrawname(char *cp)
+{
+ struct stat64 buf;
+ char *dp;
+ char *new_path;
+ dev_t blk_dev;
+
+ if (cp == NULL)
+ return (strdup(""));
+
+ /*
+ * Create a fully qualified name.
+ */
+ if ((cp = getfullname(cp)) == NULL)
+ return (NULL);
+
+ if (*cp == '\0')
+ return (cp);
+
+ if (stat64(cp, &buf) != 0) {
+ free(cp);
+ return (strdup(""));
+ }
+
+ if (S_ISCHR(buf.st_mode))
+ return (cp);
+
+ if (!S_ISBLK(buf.st_mode)) {
+ free(cp);
+ return (strdup(""));
+ }
+
+ blk_dev = buf.st_rdev;
+
+ if ((dp = getvfsspecial(cp, GET_RAW)) != NULL) {
+ free(cp);
+ return (strdup(dp));
+ }
+
+ /*
+ * We have a block device name, go find the raw name.
+ */
+ if ((dp = strstr(cp, "/dsk/")) == NULL &&
+ (dp = strstr(cp, "/" LOFI_BLOCK_NAME "/")) == NULL &&
+ (dp = strstr(cp, "/" RD_BLOCK_NAME "/")) == NULL &&
+ (dp = strstr(cp, "/" SNAP_BLOCK_NAME "/")) == NULL &&
+ (dp = strrchr(cp, '/')) == NULL) {
+ /* this is not really possible */
+ free(cp);
+ return (strdup(""));
+ }
+ dp++;
+
+ if ((new_path = malloc(strlen(cp)+2)) == NULL) {
+ free(cp);
+ return (NULL);
+ }
+ (void) strncpy(new_path, cp, dp - cp);
+ /* fill in the rest of the raw name */
+ new_path[dp - cp] = 'r';
+ (void) strcpy(new_path + (dp - cp) + 1, dp);
+
+ if (test_if_raw(new_path, blk_dev)) {
+ free(cp);
+ return (new_path);
+ }
+ free(new_path);
+
+ dp = getrawcomplete(cp, &buf);
+ free(cp);
+ return (dp);
+}