summaryrefslogtreecommitdiff
path: root/usr/src/cmd/hal/utils/fsutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/hal/utils/fsutils.c')
-rw-r--r--usr/src/cmd/hal/utils/fsutils.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/usr/src/cmd/hal/utils/fsutils.c b/usr/src/cmd/hal/utils/fsutils.c
new file mode 100644
index 0000000000..5dfada0a37
--- /dev/null
+++ b/usr/src/cmd/hal/utils/fsutils.c
@@ -0,0 +1,250 @@
+/***************************************************************************
+ *
+ * fsutils.c : filesystem utilities
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/scsi/impl/uscsi.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/dkio.h>
+#include <libintl.h>
+#include <sys/dktp/fdisk.h>
+#include <sys/fs/pc_label.h>
+
+#include <libhal.h>
+#include "fsutils.h"
+
+/*
+ * Separates dos notation device spec into device and drive number
+ */
+boolean_t
+dos_to_dev(char *path, char **devpath, int *num)
+{
+ char *p;
+
+ if ((p = strrchr(path, ':')) == NULL) {
+ return (B_FALSE);
+ }
+ if ((*num = atoi(p + 1)) == 0) {
+ return (B_FALSE);
+ }
+ p[0] = '\0';
+ *devpath = strdup(path);
+ p[0] = ':';
+ return (*devpath != NULL);
+}
+
+char *
+get_slice_name (char *devlink)
+{
+ char *part, *slice, *disk;
+ char *s = NULL;
+ char *p;
+
+ if ((p = strstr(devlink, "/lofi/")) != 0) {
+ return (p + sizeof ("/lofi/") - 1);
+ }
+
+ part = strrchr(devlink, 'p');
+ slice = strrchr(devlink, 's');
+ disk = strrchr(devlink, 'd');
+
+ if ((part != NULL) && (part > slice) && (part > disk)) {
+ s = part;
+ } else if ((slice != NULL) && (slice > disk)) {
+ s = slice;
+ } else {
+ s = disk;
+ }
+ if ((s != NULL) && isdigit(s[1])) {
+ return (s);
+ } else {
+ return ("");
+ }
+}
+
+boolean_t
+is_dos_drive(uchar_t type)
+{
+ return ((type == 1) || (type == 4) || (type == 5) || (type == 6) ||
+ ((type >= 8) && (type <= 0xf)));
+}
+
+boolean_t
+is_dos_extended(uchar_t id)
+{
+ return ((id == EXTDOS) || (id == FDISK_EXTLBA));
+}
+
+struct part_find_s {
+ int num;
+ int count;
+ int systid;
+ int r_systid;
+ int r_relsect;
+ int r_numsect;
+};
+
+enum { WALK_CONTINUE, WALK_TERMINATE };
+
+/*
+ * Walk partition tables and invoke a callback for each.
+ */
+static void
+walk_partitions(int fd, int startsec, int (*f)(void *, int, int, int),
+ void *arg)
+{
+ uint32_t buf[1024/4];
+ int bufsize = 1024;
+ struct mboot *mboot = (struct mboot *)&buf[0];
+ struct ipart ipart[FD_NUMPART];
+ int sec = startsec;
+ int lastsec = sec + 1;
+ int relsect;
+ int ext = 0;
+ int systid;
+ boolean_t valid;
+ int i;
+
+ while (sec != lastsec) {
+ if (pread(fd, buf, bufsize, (off_t)sec * 512) != bufsize) {
+ break;
+ }
+ lastsec = sec;
+ if (ltohs(mboot->signature) != MBB_MAGIC) {
+ break;
+ }
+ bcopy(mboot->parts, ipart, FD_NUMPART * sizeof (struct ipart));
+
+ for (i = 0; i < FD_NUMPART; i++) {
+ systid = ipart[i].systid;
+ relsect = sec + ltohi(ipart[i].relsect);
+ if (systid == 0) {
+ continue;
+ }
+ valid = B_TRUE;
+ if (is_dos_extended(systid) && (sec == lastsec)) {
+ sec = startsec + ltohi(ipart[i].relsect);
+ if (ext++ == 0) {
+ relsect = startsec = sec;
+ } else {
+ valid = B_FALSE;
+ }
+ }
+ if (valid && f(arg, ipart[i].systid, relsect,
+ ltohi(ipart[i].numsect)) == WALK_TERMINATE) {
+ return;
+ }
+ }
+ }
+}
+
+static int
+find_dos_drive_cb(void *arg, int systid, int relsect, int numsect)
+{
+ struct part_find_s *p = arg;
+
+ if (is_dos_drive(systid)) {
+ if (++p->count == p->num) {
+ p->r_relsect = relsect;
+ p->r_numsect = numsect;
+ p->r_systid = systid;
+ return (WALK_TERMINATE);
+ }
+ }
+
+ return (WALK_CONTINUE);
+}
+
+/*
+ * Given a dos drive number, return its relative sector number,
+ * number of sectors in partition and the system id.
+ */
+boolean_t
+find_dos_drive(int fd, int num, int *relsect, int *numsect, int *systid)
+{
+ struct part_find_s p = { 0, 0, 0, 0, 0, 0 };
+
+ p.num = num;
+
+ if (num > 0) {
+ walk_partitions(fd, 0, find_dos_drive_cb, &p);
+ if (p.count == num) {
+ *relsect = p.r_relsect;
+ *numsect = p.r_numsect;
+ *systid = p.r_systid;
+ return (B_TRUE);
+ }
+ }
+
+ return (B_FALSE);
+}
+
+static int
+get_num_dos_drives_cb(void *arg, int systid, int relsect, int numsect)
+{
+ if (is_dos_drive(systid)) {
+ (*(int *)arg)++;
+ }
+ return (WALK_CONTINUE);
+}
+
+int
+get_num_dos_drives(int fd)
+{
+ int count = 0;
+
+ walk_partitions(fd, 0, get_num_dos_drives_cb, &count);
+
+ return (count);
+}
+
+/*
+ * Return true if all non-empty slices in vtoc have identical start/size and
+ * are tagged backup/entire disk.
+ */
+boolean_t
+vtoc_one_slice_entire_disk(struct vtoc *vtoc)
+{
+ int i;
+ struct partition *p;
+ daddr_t prev_start;
+ long prev_size;
+
+ for (i = 0; i < vtoc->v_nparts; i++) {
+ p = &vtoc->v_part[i];
+ if (p->p_size == 0) {
+ continue;
+ }
+ if ((p->p_tag != V_BACKUP) && ((p->p_tag != V_UNASSIGNED))) {
+ return (B_FALSE);
+ }
+ if ((i > 0) &&
+ ((p->p_start != prev_start) || (p->p_size != prev_size))) {
+ return (B_FALSE);
+ }
+ prev_start = p->p_start;
+ prev_size = p->p_size;
+ }
+
+ return (B_TRUE);
+}