diff options
author | LaMont Jones <lamont@debian.org> | 2009-03-20 10:36:40 -0600 |
---|---|---|
committer | LaMont Jones <lamont@debian.org> | 2009-03-20 10:36:40 -0600 |
commit | 4923b27bb6c6ff2b357b3e7e68e72c4c6023f98b (patch) | |
tree | 3b371c4f47f6a61796d297b7229bb26a2b177f13 /lib | |
parent | e218b8a8c0f7a9f9eb3591a91d2e2120da4171c8 (diff) | |
parent | 3dafbfb726a97d0fe624a19b8690094998796495 (diff) | |
download | util-linux-old-4923b27bb6c6ff2b357b3e7e68e72c4c6023f98b.tar.gz |
Merge commit 'origin/master'
Conflicts:
NEWS
config/include-Makefile.am
configure.ac
mount/Makefile.am
mount/mount.c
po/ca.po
po/cs.po
po/da.po
po/de.po
po/es.po
po/et.po
po/eu.po
po/fi.po
po/fr.po
po/hu.po
po/id.po
po/it.po
po/ja.po
po/nl.po
po/pl.po
po/pt_BR.po
po/ru.po
po/sl.po
po/sv.po
po/tr.po
po/uk.po
po/util-linux-ng.pot
po/vi.po
po/zh_CN.po
Diffstat (limited to 'lib')
-rw-r--r-- | lib/.gitignore | 2 | ||||
-rw-r--r-- | lib/Makefile.am | 14 | ||||
-rw-r--r-- | lib/blkdev.c | 2 | ||||
-rw-r--r-- | lib/canonicalize.c | 152 | ||||
-rw-r--r-- | lib/fsprobe.c | 390 | ||||
-rw-r--r-- | lib/ismounted.c | 203 | ||||
-rw-r--r-- | lib/pttype.c | 292 | ||||
-rw-r--r-- | lib/wholedisk.c | 58 |
8 files changed, 1105 insertions, 8 deletions
diff --git a/lib/.gitignore b/lib/.gitignore index b3968c73..145f5d74 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -1 +1 @@ -test_blkdev +test_* diff --git a/lib/Makefile.am b/lib/Makefile.am index 37205dcd..0b648069 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,13 +1,15 @@ include $(top_srcdir)/config/include-Makefile.am -noinst_PROGRAMS = test_blkdev +AM_CPPFLAGS += -DTEST_PROGRAM -test_blkdev_SOURCES = $(top_srcdir)/lib/blkdev.c +noinst_PROGRAMS = test_blkdev test_ismounted test_pttype test_wholedisk + +test_blkdev_SOURCES = blkdev.c +test_ismounted_SOURCES = ismounted.c +test_pttype_SOURCES = pttype.c +test_wholedisk_SOURCES = wholedisk.c if LINUX -test_blkdev_SOURCES += $(top_srcdir)/lib/linux_version.c +test_blkdev_SOURCES += linux_version.c endif -test_blkdev_CFLAGS = -DMAIN_TEST_BLKDEV - - diff --git a/lib/blkdev.c b/lib/blkdev.c index 79a366ca..7c6c7bab 100644 --- a/lib/blkdev.c +++ b/lib/blkdev.c @@ -107,7 +107,7 @@ blkdev_get_sector_size(int fd, int *sector_size) } -#ifdef MAIN_TEST_BLKDEV +#ifdef TEST_PROGRAM #include <stdio.h> #include <stdlib.h> #include <fcntl.h> diff --git a/lib/canonicalize.c b/lib/canonicalize.c new file mode 100644 index 00000000..b888fbb8 --- /dev/null +++ b/lib/canonicalize.c @@ -0,0 +1,152 @@ +/* + * canonicalize.c -- canonicalize pathname by removing symlinks + * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library Public License for more details. + * + */ + +/* + * This routine is part of libc. We include it nevertheless, + * since the libc version has some security flaws. + * + * TODO: use canonicalize_file_name() when exist in glibc + */ +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +#include "canonicalize.h" + +#ifndef MAXSYMLINKS +# define MAXSYMLINKS 256 +#endif + +static char * +myrealpath(const char *path, char *resolved_path, int maxreslth) { + int readlinks = 0; + char *npath; + char link_path[PATH_MAX+1]; + int n; + char *buf = NULL; + + npath = resolved_path; + + /* If it's a relative pathname use getcwd for starters. */ + if (*path != '/') { + if (!getcwd(npath, maxreslth-2)) + return NULL; + npath += strlen(npath); + if (npath[-1] != '/') + *npath++ = '/'; + } else { + *npath++ = '/'; + path++; + } + + /* Expand each slash-separated pathname component. */ + while (*path != '\0') { + /* Ignore stray "/" */ + if (*path == '/') { + path++; + continue; + } + if (*path == '.' && (path[1] == '\0' || path[1] == '/')) { + /* Ignore "." */ + path++; + continue; + } + if (*path == '.' && path[1] == '.' && + (path[2] == '\0' || path[2] == '/')) { + /* Backup for ".." */ + path += 2; + while (npath > resolved_path+1 && + (--npath)[-1] != '/') + ; + continue; + } + /* Safely copy the next pathname component. */ + while (*path != '\0' && *path != '/') { + if (npath-resolved_path > maxreslth-2) { + errno = ENAMETOOLONG; + goto err; + } + *npath++ = *path++; + } + + /* Protect against infinite loops. */ + if (readlinks++ > MAXSYMLINKS) { + errno = ELOOP; + goto err; + } + + /* See if last pathname component is a symlink. */ + *npath = '\0'; + n = readlink(resolved_path, link_path, PATH_MAX); + if (n < 0) { + /* EINVAL means the file exists but isn't a symlink. */ + if (errno != EINVAL) + goto err; + } else { + int m; + char *newbuf; + + /* Note: readlink doesn't add the null byte. */ + link_path[n] = '\0'; + if (*link_path == '/') + /* Start over for an absolute symlink. */ + npath = resolved_path; + else + /* Otherwise back up over this component. */ + while (*(--npath) != '/') + ; + + /* Insert symlink contents into path. */ + m = strlen(path); + newbuf = malloc(m + n + 1); + if (!newbuf) + goto err; + memcpy(newbuf, link_path, n); + memcpy(newbuf + n, path, m + 1); + free(buf); + path = buf = newbuf; + } + *npath++ = '/'; + } + /* Delete trailing slash but don't whomp a lone slash. */ + if (npath != resolved_path+1 && npath[-1] == '/') + npath--; + /* Make sure it's null terminated. */ + *npath = '\0'; + + free(buf); + return resolved_path; + + err: + free(buf); + return NULL; +} + +char * +canonicalize_path(const char *path) { + char canonical[PATH_MAX+2]; + + if (path == NULL) + return NULL; + + if (myrealpath (path, canonical, PATH_MAX+1)) + return strdup(canonical); + + return strdup(path); +} + + diff --git a/lib/fsprobe.c b/lib/fsprobe.c new file mode 100644 index 00000000..8c9eb6dc --- /dev/null +++ b/lib/fsprobe.c @@ -0,0 +1,390 @@ +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <stdlib.h> + +#include <blkid.h> + +#include "blkdev.h" +#include "canonicalize.h" +#include "pathnames.h" +#include "fsprobe.h" + +#if defined(HAVE_BLKID_EVALUATE_SPEC) || defined(HAVE_LIBVOLUME_ID) +/* ask kernel developers why we need such ugly open() method... */ +static int +open_device(const char *devname) +{ + int retries = 0; + + do { + int fd = open(devname, O_RDONLY); + if (fd >= 0) + return fd; + if (errno != ENOMEDIUM) + break; + if (retries >= CRDOM_NOMEDIUM_RETRIES) + break; + ++retries; + sleep(3); + } while(1); + + return -1; +} +#endif + +/* + * Parses NAME=value, returns -1 on parse error, 0 success. The success is also + * when the 'spec' doesn't contain name=value pair (because the spec could be + * a devname too). In particular case the pointer 'name' is set to NULL. + + * The result is a new allocated string (the 'name' pointer). + */ +int +fsprobe_parse_spec(const char *spec, char **name, char **value) +{ + char *vl, *tk, *cp; + + *name = NULL; + *value = NULL; + + if (!(cp = strchr(spec, '='))) + return 0; /* no name= */ + + tk = strdup(spec); + vl = tk + (cp - spec); + *vl++ = '\0'; + + if (*vl == '"' || *vl == '\'') { + if (!(cp = strrchr(vl+1, *vl))) { + free(tk); + return -1; /* parse error */ + } + vl++; + *cp = '\0'; + } + + *name = tk; + *value = vl; + return 0; +} + +char * +fsprobe_get_devname_by_spec(const char *spec) +{ + char *name, *value; + + if (!spec) + return NULL; + if (fsprobe_parse_spec(spec, &name, &value) != 0) + return NULL; /* parse error */ + if (name) { + char *nspec = NULL; + + if (!strcmp(name,"LABEL")) + nspec = fsprobe_get_devname_by_label(value); + else if (!strcmp(name,"UUID")) + nspec = fsprobe_get_devname_by_uuid(value); + + free((void *) name); + return nspec; + } + + return canonicalize_path(spec); +} + +#ifdef HAVE_LIBBLKID +static blkid_cache blcache; + +void +fsprobe_init(void) +{ + blcache = NULL; +} + +int +fsprobe_known_fstype(const char *fstype) +{ + return blkid_known_fstype(fstype); +} + +#ifdef HAVE_BLKID_EVALUATE_SPEC +/* + * libblkid from util-linux-ng + * -- recommended + */ +static blkid_probe blprobe; + +void +fsprobe_exit(void) +{ + if (blprobe) + blkid_free_probe(blprobe); + if (blcache) + blkid_put_cache(blcache); +} + +/* returns device LABEL, UUID, FSTYPE, ... by low-level + * probing interface + */ +static char * +fsprobe_get_value(const char *name, const char *devname) +{ + int fd; + const char *data = NULL; + + if (!devname || !name) + return NULL; + fd = open_device(devname); + if (fd < 0) + return NULL; + if (!blprobe) + blprobe = blkid_new_probe(); + if (!blprobe) + goto done; + if (blkid_probe_set_device(blprobe, fd, 0, 0)) + goto done; + if (blkid_probe_set_request(blprobe, BLKID_PROBREQ_LABEL | + BLKID_PROBREQ_UUID | BLKID_PROBREQ_TYPE )) + goto done; + if (blkid_do_safeprobe(blprobe)) + goto done; + if (blkid_probe_lookup_value(blprobe, name, &data, NULL)) + goto done; +done: + close(fd); + return data ? strdup((char *) data) : NULL; +} + +char * +fsprobe_get_label_by_devname(const char *devname) +{ + return fsprobe_get_value("LABEL", devname); +} + +char * +fsprobe_get_uuid_by_devname(const char *devname) +{ + return fsprobe_get_value("UUID", devname); +} + +char * +fsprobe_get_fstype_by_devname(const char *devname) +{ + return fsprobe_get_value("TYPE", devname); +} + +char * +fsprobe_get_devname_by_uuid(const char *uuid) +{ + return blkid_evaluate_spec("UUID", uuid, &blcache); +} + +char * +fsprobe_get_devname_by_label(const char *label) +{ + return blkid_evaluate_spec("LABEL", label, &blcache); +} + +#else /* !HAVE_BLKID_EVALUATE_SPEC */ + +/* + * Classic libblkid (from e2fsprogs) without blkid_evaluate_spec() + * -- deprecated + */ +#define BLKID_EMPTY_CACHE "/dev/null" + +void +fsprobe_exit(void) +{ + if (blcache) + blkid_put_cache(blcache); +} + +char * +fsprobe_get_devname_by_uuid(const char *uuid) +{ + if (!blcache) + blkid_get_cache(&blcache, NULL); + + return blkid_get_devname(blcache, "UUID", uuid); +} + +char * +fsprobe_get_devname_by_label(const char *label) +{ + if (!blcache) + blkid_get_cache(&blcache, NULL); + + return blkid_get_devname(blcache, "LABEL", label); +} + +char * +fsprobe_get_fstype_by_devname(const char *devname) +{ + blkid_cache c; + char *tp; + + if (blcache) + return blkid_get_tag_value(blcache, "TYPE", devname); + + /* The cache is not initialized yet. Use empty cache rather than waste + * time with /etc/blkid.tab. It seems that probe FS is faster than + * parse the cache file. -- kzak (17-May-2007) + */ + blkid_get_cache(&c, BLKID_EMPTY_CACHE); + tp = blkid_get_tag_value(c, "TYPE", devname); + blkid_put_cache(c); + + return tp; +} + +char * +fsprobe_get_label_by_devname(const char *devname) +{ + if (!blcache) + blkid_get_cache(&blcache, NULL); + + return blkid_get_tag_value(blcache, "LABEL", devname); +} + +char * +fsprobe_get_uuid_by_devname(const char *devname) +{ + if (!blcache) + blkid_get_cache(&blcache, NULL); + + return blkid_get_tag_value(blcache, "UUID", devname); +} + +#endif /* !HAVE_BLKID_EVALUATE_SPEC */ +#else /* !HAVE_LIBBLKID */ + +/* + * libvolume_id from udev + * -- deprecated + */ +#include <libvolume_id.h> + +enum probe_type { + VOLUME_ID_NONE, + VOLUME_ID_LABEL, + VOLUME_ID_UUID, + VOLUME_ID_TYPE, +}; + +static char +*probe(const char *device, enum probe_type type) +{ + int fd; + uint64_t size; + struct volume_id *id; + const char *val; + char *value = NULL; + int retries = 0; + + fd = open_device(devname); + if (fd < 0) + return NULL; + id = volume_id_open_fd(fd); + if (!id) { + close(fd); + return NULL; + } + if (blkdev_get_size(fd, &size) != 0) + size = 0; + if (volume_id_probe_all(id, 0, size) == 0) { + switch(type) { + case VOLUME_ID_LABEL: + if (volume_id_get_label(id, &val)) + value = strdup(val); + break; + case VOLUME_ID_UUID: + if (volume_id_get_uuid(id, &val)) + value = strdup(val); + break; + case VOLUME_ID_TYPE: + if (volume_id_get_type(id, &val)) + value = strdup(val); + break; + default: + break; + } + } + volume_id_close(id); + close(fd); + return value; +} + +void +fsprobe_init(void) +{ +} + +void +fsprobe_exit(void) +{ +} + +int +fsprobe_known_fstype(const char *fstype) +{ + if (volume_id_get_prober_by_type(fstype) != NULL) + return 1; + return 0; +} + +char * +fsprobe_get_uuid_by_devname(const char *devname) +{ + return probe(devname, VOLUME_ID_UUID); +} + +char * +fsprobe_get_label_by_devname(const char *devname) +{ + return probe(devname, VOLUME_ID_LABEL); +} + +char * +fsprobe_get_fstype_by_devname(const char *devname) +{ + return probe(devname, VOLUME_ID_TYPE); +} + +char * +fsprobe_get_devname_by_uuid(const char *uuid) +{ + char dev[PATH_MAX]; + size_t len; + + if (!uuid) + return NULL; + + strcpy(dev, _PATH_DEV_BYUUID "/"); + len = strlen(_PATH_DEV_BYUUID "/"); + if (!volume_id_encode_string(uuid, &dev[len], sizeof(dev) - len)) + return NULL; + return canonicalize_path(dev); +} + +char * +fsprobe_get_devname_by_label(const char *label) +{ + char dev[PATH_MAX]; + size_t len; + + if (!label) + return NULL; + strcpy(dev, _PATH_DEV_BYLABEL "/"); + len = strlen(_PATH_DEV_BYLABEL "/"); + if (!volume_id_encode_string(label, &dev[len], sizeof(dev) - len)) + return NULL; + return canonicalize_path(dev); +} + +#endif /* HAVE_LIBVOLUME_ID */ diff --git a/lib/ismounted.c b/lib/ismounted.c new file mode 100644 index 00000000..0481c77e --- /dev/null +++ b/lib/ismounted.c @@ -0,0 +1,203 @@ +/* + * ismounted.c --- Check to see if the filesystem was mounted + * + * Copyright (C) 1995,1996,1997,1998,1999,2000,2008 Theodore Ts'o. + * + * This file may be redistributed under the terms of the GNU Public + * License. + */ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <linux/fd.h> +#include <mntent.h> +#include <string.h> +#include <sys/stat.h> +#include <ctype.h> + +#include "pathnames.h" +#include "ismounted.h" + +/* + * ext2fs_check_if_mounted flags + */ +#define MF_MOUNTED 1 + +static char *skip_over_blank(char *cp) +{ + while (*cp && isspace(*cp)) + cp++; + return cp; +} + +static char *skip_over_word(char *cp) +{ + while (*cp && !isspace(*cp)) + cp++; + return cp; +} + +static char *parse_word(char **buf) +{ + char *word, *next; + + word = *buf; + if (*word == 0) + return 0; + + word = skip_over_blank(word); + next = skip_over_word(word); + if (*next) + *next++ = 0; + *buf = next; + return word; +} + +/* + * Helper function which checks a file in /etc/mtab format to see if a + * filesystem is mounted. Returns an error if the file doesn't exist + * or can't be opened. + */ +static int check_mntent_file(const char *mtab_file, const char *file, + int *mount_flags) +{ + struct stat st_buf; + int retval = 0; + dev_t file_dev=0, file_rdev=0; + ino_t file_ino=0; + FILE *f; + char buf[1024], *device = 0, *mnt_dir = 0, *cp; + + *mount_flags = 0; + if ((f = fopen(mtab_file, "r")) == NULL) + return errno; + + if ((f = setmntent (mtab_file, "r")) == NULL) + return errno; + if (stat(file, &st_buf) == 0) { + if (S_ISBLK(st_buf.st_mode)) { +#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ + file_rdev = st_buf.st_rdev; +#endif /* __GNU__ */ + } else { + file_dev = st_buf.st_dev; + file_ino = st_buf.st_ino; + } + } + while (1) { + if (!fgets(buf, sizeof(buf), f)) { + device = mnt_dir = 0; + break; + } + buf[sizeof(buf)-1] = 0; + + cp = buf; + device = parse_word(&cp); + if (!device || *device == '#') + return 0; /* Ignore blank lines and comments */ + mnt_dir = parse_word(&cp); + + if (device[0] != '/') + continue; + + if (strcmp(file, device) == 0) + break; + if (stat(device, &st_buf) == 0) { + if (S_ISBLK(st_buf.st_mode)) { +#ifndef __GNU__ + if (file_rdev && (file_rdev == st_buf.st_rdev)) + break; +#endif /* __GNU__ */ + } else { + if (file_dev && ((file_dev == st_buf.st_dev) && + (file_ino == st_buf.st_ino))) + break; + } + } + } + + if (mnt_dir == 0) { +#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ + /* + * Do an extra check to see if this is the root device. We + * can't trust /etc/mtab, and /proc/mounts will only list + * /dev/root for the root filesystem. Argh. Instead we + * check if the given device has the same major/minor number + * as the device that the root directory is on. + */ + if (file_rdev && (stat("/", &st_buf) == 0) && + (st_buf.st_dev == file_rdev)) + *mount_flags = MF_MOUNTED; +#endif /* __GNU__ */ + goto errout; + } +#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */ + /* Validate the entry in case /etc/mtab is out of date */ + /* + * We need to be paranoid, because some broken distributions + * (read: Slackware) don't initialize /etc/mtab before checking + * all of the non-root filesystems on the disk. + */ + if (stat(mnt_dir, &st_buf) < 0) { + retval = errno; + if (retval == ENOENT) { +#ifdef DEBUG + printf("Bogus entry in %s! (%s does not exist)\n", + mtab_file, mnt_dir); +#endif /* DEBUG */ + retval = 0; + } + goto errout; + } + if (file_rdev && (st_buf.st_dev != file_rdev)) { +#ifdef DEBUG + printf("Bogus entry in %s! (%s not mounted on %s)\n", + mtab_file, file, mnt_dir); +#endif /* DEBUG */ + goto errout; + } +#endif /* __GNU__ */ + *mount_flags = MF_MOUNTED; + + retval = 0; +errout: + endmntent (f); + return retval; +} + +int is_mounted(const char *file) +{ + int retval; + int mount_flags = 0; + +#ifdef __linux__ + retval = check_mntent_file(_PATH_PROC_MOUNTS, file, &mount_flags); + if (retval) + return 0; + if (mount_flags) + return 1; +#endif /* __linux__ */ + retval = check_mntent_file(_PATH_MOUNTED, file, &mount_flags); + if (retval) + return 0; + return mount_flags; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + if (argc < 2) { + fprintf(stderr, "Usage: %s device\n", argv[0]); + return EXIT_FAILURE; + } + + if (is_mounted(argv[1])) { + printf("mounted\n"); + return EXIT_SUCCESS; + } + printf("not mounted\n"); + return EXIT_FAILURE; +} +#endif /* DEBUG */ diff --git a/lib/pttype.c b/lib/pttype.c new file mode 100644 index 00000000..c2294f13 --- /dev/null +++ b/lib/pttype.c @@ -0,0 +1,292 @@ +/* + * Based on libdisk from xfsprogs and Linux fdisk. + * + * Copyright (c) 2000-2001 Silicon Graphics, Inc. + * Copyright (C) 2009 Karel Zak <kzak@redhat.com> + */ +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <stdlib.h> + +#include "blkdev.h" + +/* we need to read two sectors, beacuse BSD label offset is 512 */ +#define PTTYPE_BUFSIZ (2 * DEFAULT_SECTOR_SIZE) /* 1024 */ + +/* + * SGI + */ +struct sgi_device_parameter { /* 48 bytes */ + unsigned char skew; + unsigned char gap1; + unsigned char gap2; + unsigned char sparecyl; + unsigned short pcylcount; + unsigned short head_vol0; + unsigned short ntrks; /* tracks in cyl 0 or vol 0 */ + unsigned char cmd_tag_queue_depth; + unsigned char unused0; + unsigned short unused1; + unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */ + unsigned short bytes; + unsigned short ilfact; + unsigned int flags; /* controller flags */ + unsigned int datarate; + unsigned int retries_on_error; + unsigned int ms_per_word; + unsigned short xylogics_gap1; + unsigned short xylogics_syncdelay; + unsigned short xylogics_readdelay; + unsigned short xylogics_gap2; + unsigned short xylogics_readgate; + unsigned short xylogics_writecont; +}; + +#define SGI_VOLHDR 0x00 +/* 1 and 2 were used for drive types no longer supported by SGI */ +#define SGI_SWAP 0x03 +/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */ +#define SGI_VOLUME 0x06 +#define SGI_EFS 0x07 +#define SGI_LVOL 0x08 +#define SGI_RLVOL 0x09 +#define SGI_XFS 0x0a +#define SGI_XFSLOG 0x0b +#define SGI_XLV 0x0c +#define SGI_XVM 0x0d +#define ENTIRE_DISK SGI_VOLUME +/* + * controller flags + */ +#define SECTOR_SLIP 0x01 +#define SECTOR_FWD 0x02 +#define TRACK_FWD 0x04 +#define TRACK_MULTIVOL 0x08 +#define IGNORE_ERRORS 0x10 +#define RESEEK 0x20 +#define CMDTAGQ_ENABLE 0x40 + +struct sgi_volume_header { + unsigned int magic; /* expect SGI_LABEL_MAGIC */ + unsigned short boot_part; /* active boot partition */ + unsigned short swap_part; /* active swap partition */ + unsigned char boot_file[16]; /* name of the bootfile */ + struct sgi_device_parameter devparam; /* 1 * 48 bytes */ + struct volume_directory { /* 15 * 16 bytes */ + unsigned char vol_file_name[8]; /* a character array */ + unsigned int vol_file_start; /* number of logical block */ + unsigned int vol_file_size; /* number of bytes */ + } directory[15]; + struct sgi_partition { /* 16 * 12 bytes */ + unsigned int num_sectors; /* number of blocks */ + unsigned int start_sector; /* must be cylinder aligned */ + unsigned int id; + } partitions[16]; + unsigned int csum; + unsigned int fillbytes; +}; + +#define SGI_LABEL_MAGIC 0x0be5a941 + +static uint32_t +twos_complement_32bit_sum(u_int32_t *base, int size) +{ + int i; + u_int32_t sum = 0; + + size = size / sizeof(u_int32_t); + for (i = 0; i < size; i++) + sum = sum - ntohl(base[i]); + return sum; +} + +static int +sgi_parttable(unsigned char *base) +{ + u_int32_t csum; + struct sgi_volume_header *vh = (struct sgi_volume_header *) base; + + if (ntohl(vh->magic) != SGI_LABEL_MAGIC) + return 0; + csum = twos_complement_32bit_sum((uint32_t *)vh, + sizeof(struct sgi_volume_header)); + return !csum; +} + +/* + * DOS + */ +static int +dos_parttable(unsigned char *base) +{ + return (base[510] == 0x55 && base[511] == 0xaa); +} + +/* + * AIX + */ +typedef struct { + unsigned int magic; /* expect AIX_LABEL_MAGIC */ + /* ... */ +} aix_partition; + +#define AIX_LABEL_MAGIC 0xc9c2d4c1 +#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9 +#define aixlabel(x) ((aix_partition *)x) + +static int +aix_parttable(unsigned char *base) +{ + return (aixlabel(base)->magic == AIX_LABEL_MAGIC || + aixlabel(base)->magic == AIX_LABEL_MAGIC_SWAPPED); +} + +/* + * SUN + */ +typedef struct { + unsigned char info[128]; /* Informative text string */ + unsigned char spare0[14]; + struct sun_info { + unsigned char spare1; + unsigned char id; + unsigned char spare2; + unsigned char flags; + } infos[8]; + unsigned char spare1[246]; /* Boot information etc. */ + unsigned short rspeed; /* Disk rotational speed */ + unsigned short pcylcount; /* Physical cylinder count */ + unsigned short sparecyl; /* extra sects per cylinder */ + unsigned char spare2[4]; /* More magic... */ + unsigned short ilfact; /* Interleave factor */ + unsigned short ncyl; /* Data cylinder count */ + unsigned short nacyl; /* Alt. cylinder count */ + unsigned short ntrks; /* Tracks per cylinder */ + unsigned short nsect; /* Sectors per track */ + unsigned char spare3[4]; /* Even more magic... */ + struct sun_partition { + u_int32_t start_cylinder; + u_int32_t num_sectors; + } partitions[8]; + unsigned short magic; /* Magic number */ + unsigned short csum; /* Label xor'd checksum */ +} sun_partition; + +#define SUN_LABEL_MAGIC 0xDABE +#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA +#define sunlabel(x) ((sun_partition *)x) + +static int +sun_parttable(unsigned char *base) +{ + unsigned short *ush; + int csum = 0; + + if (sunlabel(base)->magic != SUN_LABEL_MAGIC && + sunlabel(base)->magic != SUN_LABEL_MAGIC_SWAPPED) + return csum; + ush = ((unsigned short *) (sunlabel(base) + 1)) - 1; + while (ush >= (unsigned short *)sunlabel(base)) + csum ^= *ush--; + return !csum; +} + +/* + * MAC + */ +typedef struct { + unsigned short magic; + /* ... */ +} mac_partition; + +#define MAC_LABEL_MAGIC 0x4552 +#define MAC_PARTITION_MAGIC 0x504d +#define MAC_OLD_PARTITION_MAGIC 0x5453 +#define maclabel(x) ((mac_partition *)x) + +static int +mac_parttable(unsigned char *base) +{ + return (ntohs(maclabel(base)->magic) == MAC_LABEL_MAGIC || + ntohs(maclabel(base)->magic) == MAC_PARTITION_MAGIC || + ntohs(maclabel(base)->magic) == MAC_OLD_PARTITION_MAGIC); +} + +/* + * BSD subpartitions listed in a disklabel, under a dos-like partition. + */ +#define BSD_DISKMAGIC 0x82564557UL /* The disk magic number */ +#define BSD_DISKMAGIC_SWAPED 0x57455682UL +struct bsd_disklabel { + uint32_t magic; /* the magic number */ + /* ... */ +}; + +static int +bsd_parttable(unsigned char *base) +{ + struct bsd_disklabel *l = (struct bsd_disklabel *) + (base + (DEFAULT_SECTOR_SIZE * 1)); + + return (l->magic == BSD_DISKMAGIC || l->magic == BSD_DISKMAGIC_SWAPED); +} + +const char * +get_pt_type_fd(int fd) +{ + char *type = NULL; + unsigned char buf[PTTYPE_BUFSIZ]; + + if (read(fd, buf, PTTYPE_BUFSIZ) != PTTYPE_BUFSIZ) + ; + else { + if (sgi_parttable(buf)) + type = "SGI"; + else if (sun_parttable(buf)) + type = "Sun"; + else if (aix_parttable(buf)) + type = "AIX"; + else if (dos_parttable(buf)) + type = "DOS"; + else if (mac_parttable(buf)) + type = "Mac"; + else if (bsd_parttable(buf)) + type = "BSD"; + } + return type; +} + +const char * +get_pt_type(const char *device) +{ + int fd; + const char *type; + + fd = open(device, O_RDONLY); + if (fd == -1) + return NULL; + type = get_pt_type_fd(fd); + close(fd); + return type; +} + +#ifdef TEST_PROGRAM +int +main(int argc, char **argv) +{ + const char *type; + + if (argc < 2) { + fprintf(stderr, "usage: %s <device>\n", argv[0]); + exit(EXIT_FAILURE); + } + + type = get_pt_type(argv[1]); + if (type) + printf("Partition type: %s\n", type); + exit(EXIT_SUCCESS); +} +#endif diff --git a/lib/wholedisk.c b/lib/wholedisk.c new file mode 100644 index 00000000..35f143d2 --- /dev/null +++ b/lib/wholedisk.c @@ -0,0 +1,58 @@ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +#include "blkdev.h" +#include "wholedisk.h" + +int is_whole_disk_fd(int fd, const char *name) +{ +#ifdef HDIO_GETGEO + struct hd_geometry geometry; + int i = 0; + + if (fd != -1) + i = ioctl(fd, HDIO_GETGEO, &geometry); + if (i == 0) + return geometry.start == 0; +#endif + /* + * The "silly heuristic" is still sexy for us, because + * for example Xen doesn't implement HDIO_GETGEO for virtual + * block devices (/dev/xvda). + * + * -- kzak@redhat.com (23-Feb-2006) + */ + while (*name) + name++; + return !isdigit(name[-1]); +} + +int is_whole_disk(const char *name) +{ + int fd = -1, res = 0; +#ifdef HDIO_GETGEO + fd = open(name, O_RDONLY); + if (fd != -1) +#endif + res = is_whole_disk_fd(fd, name); + + if (fd != -1) + close(fd); + return res; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + if (argc < 2) { + fprintf(stderr, "usage: %s <device>\n", argv[0]); + exit(EXIT_FAILURE); + } + + printf("%s: is%s whole disk\n", argv[1], + is_whole_disk(argv[1]) ? "" : " NOT"); + exit(EXIT_SUCCESS); +} +#endif |