summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorLaMont Jones <lamont@debian.org>2009-03-20 10:36:40 -0600
committerLaMont Jones <lamont@debian.org>2009-03-20 10:36:40 -0600
commit4923b27bb6c6ff2b357b3e7e68e72c4c6023f98b (patch)
tree3b371c4f47f6a61796d297b7229bb26a2b177f13 /lib
parente218b8a8c0f7a9f9eb3591a91d2e2120da4171c8 (diff)
parent3dafbfb726a97d0fe624a19b8690094998796495 (diff)
downloadutil-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/.gitignore2
-rw-r--r--lib/Makefile.am14
-rw-r--r--lib/blkdev.c2
-rw-r--r--lib/canonicalize.c152
-rw-r--r--lib/fsprobe.c390
-rw-r--r--lib/ismounted.c203
-rw-r--r--lib/pttype.c292
-rw-r--r--lib/wholedisk.c58
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