#include <stdio.h>
#include <stdlib.h>
#include <sys/disk.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#define HFS_VOLHDR_OFFSET 1024
#define HFS_VOLHDR_SIZE 512
#define E_OPENDEV -1
#define E_READ -5
void usage(void);
char *rawname(char *name);
char *unrawname(char *name);
int checkVolHdr(const unsigned char *volhdr);
char *blockcheck(char *origname);
char *progname;
int
main(int argc, char **argv)
{
unsigned char volhdr[HFS_VOLHDR_SIZE] = {0};
int fd, retval;
char *devname;
fd = -1;
retval = 0;
if ((progname = strrchr(*argv, '/')))
++progname;
else
progname = *argv;
if (argc != 2) {
usage();
} else {
devname = blockcheck(argv[1]);
if (devname != NULL) {
if ((fd = open(devname, O_RDONLY, 0)) < 0) {
retval = E_OPENDEV;
} else if (pread(fd, volhdr, HFS_VOLHDR_SIZE, HFS_VOLHDR_OFFSET) != HFS_VOLHDR_SIZE) {
retval = E_READ;
} else {
retval = checkVolHdr(volhdr);
}
if (-1 != fd) {
close(fd);
fd = -1;
}
}
}
return retval;
}
void
usage(void)
{
fprintf(stdout, "usage: %s device\n", progname);
return;
}
char *
rawname(char *name)
{
static char rawbuf[32];
char *dp;
if ((dp = strrchr(name, '/')) == 0)
return (0);
*dp = 0;
(void) strcpy(rawbuf, name);
*dp = '/';
(void) strcat(rawbuf, "/r");
(void) strcat(rawbuf, &dp[1]);
return (rawbuf);
}
char *
unrawname(char *name)
{
char *dp;
struct stat stb;
if ((dp = strrchr(name, '/')) == 0)
return (name);
if (stat(name, &stb) < 0)
return (name);
if ((stb.st_mode & S_IFMT) != S_IFCHR)
return (name);
if (dp[1] != 'r')
return (name);
(void) strcpy(&dp[1], &dp[2]);
return (name);
}
char *
blockcheck(char *origname)
{
struct stat stblock, stchar;
char *newname, *raw;
int retried;
retried = 0;
newname = origname;
retry:
if (stat(newname, &stblock) < 0) {
perror(newname);
fprintf(stderr, "Can't stat %s\n", newname);
return NULL;
}
if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
raw = rawname(newname);
if (stat(raw, &stchar) < 0) {
perror(raw);
fprintf(stderr, "Can't stat %s\n", raw);
return NULL;
}
if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
return (raw);
} else {
fprintf(stderr, "%s is not a character device\n", raw);
return NULL;
}
} else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
newname = unrawname(newname);
retried++;
goto retry;
}
return NULL;
}
int
checkVolHdr(const unsigned char *volhdr)
{
int retval;
retval = 0;
if (strncmp((const char *)volhdr, "H+", 2) == 0) {
retval = (volhdr[3] == 4);
} else if (strncmp((const char *)volhdr, "HX", 2) == 0) {
retval = (volhdr[3] == 5);
}
return retval;
}