#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"
#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 *);
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(""));
if (strncmp(path, "./", 2) == 0) {
path += 2;
} else if (strncmp(path, "../", 3) == 0) {
c = strrchr(cwd, '/');
*c = '\0';
path += 3;
}
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);
}
static int
test_if_blk(char *new_path, dev_t raw_dev)
{
struct stat64 buf;
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);
}
static int
test_if_raw(char *new_path, dev_t blk_dev)
{
struct stat64 buf;
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);
}
static char *
getblkcomplete(char *cp, struct stat64 *dat)
{
char *dp;
char *new_path;
char c;
if ((dp = strstr(cp, "/rfd")) != NULL) {
if ((new_path = malloc(strlen(cp))) == NULL)
return (NULL);
c = *++dp;
*dp = '\0';
(void) strcpy(new_path, cp);
*dp++ = c;
(void) strcat(new_path, dp);
if (test_if_blk(new_path, dat->st_rdev))
return (new_path);
free(new_path);
return (strdup(""));
}
if ((dp = strstr(cp, "/rdiskette")) != NULL) {
if ((new_path = malloc(strlen(cp))) == NULL)
return (NULL);
c = *++dp;
*dp = '\0';
(void) strcpy(new_path, cp);
*dp++ = c;
(void) strcat(new_path, dp);
if (test_if_blk(new_path, dat->st_rdev))
return (new_path);
free(new_path);
return (strdup(""));
}
return (strdup(""));
}
static char *
getrawcomplete(char *cp, struct stat64 *dat)
{
char *dp;
char *new_path;
char c;
if ((dp = strstr(cp, "/fd")) != NULL) {
if ((new_path = malloc(strlen(cp)+2)) == NULL)
return (NULL);
c = *++dp;
*dp = '\0';
(void) strcpy(new_path, cp);
*dp = c;
(void) strcat(new_path, "r");
(void) strcat(new_path, dp);
if (test_if_raw(new_path, dat->st_rdev))
return (new_path);
free(new_path);
}
if ((dp = strstr(cp, "/diskette")) != NULL) {
if ((new_path = malloc(strlen(cp)+2)) == NULL)
return (NULL);
c = *++dp;
*dp = '\0';
(void) strcpy(new_path, cp);
*dp = c;
(void) strcat(new_path, "r");
(void) strcat(new_path, dp);
if (test_if_raw(new_path, dat->st_rdev))
return (new_path);
free(new_path);
return (strdup(""));
}
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);
}
char *
getfullblkname(char *cp)
{
struct stat64 buf;
char *dp;
char *new_path;
dev_t raw_dev;
if (cp == NULL)
return (strdup(""));
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;
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) {
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);
(void) strcpy(new_path + (dp - cp), dp + 1);
if (test_if_blk(new_path, raw_dev)) {
free(cp);
return (new_path);
}
free(new_path);
dp = getblkcomplete(cp, &buf);
free(cp);
return (dp);
}
char *
getfullrawname(char *cp)
{
struct stat64 buf;
char *dp;
char *new_path;
dev_t blk_dev;
if (cp == NULL)
return (strdup(""));
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));
}
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) {
free(cp);
return (strdup(""));
}
dp++;
if ((new_path = malloc(strlen(cp)+2)) == NULL) {
free(cp);
return (NULL);
}
(void) strncpy(new_path, cp, dp - cp);
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);
}