Identifying disks by name

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Identifying disks by name

Wouter Coene
Hi all,

The patch below builds on the disk UID code to implement disk names. Disk
names must match [a-zA-Z0-9_]{1,10} and are stored encoded as 6 bits per
character into the disklabel UID field. With this patch, you can use disk
names in /etc/fstab:

        bootdisk.a / ffs rw 1 1

And with every other program that uses the disk mapper or opendev(3).

The name can be set through the disklabel 'i' command:

        > i
        The disklabel UID is currently 9b3cf8a2ddef0000 ('bootdisk')
        duid: [] foo
        > l
        ...
        duid: ab3cc00000000000 ('foo')

When parsing a UID/name, the decision to parse as a UID or as a name is made
based on the length of the string: 16-character strings are parsed as UIDs,
whereas anything <= 10 is parsed as a name.

When displaying a UID/name, it is displayed both as a UID and as a name, as it
is unfortunately not possible to detect whether it was entered as a UID or a
name. This results in garbage names for randomly-generated UIDs:

        > l
        ...
        duid: c7b55168cd92a85f ('mwKGPBrHf4')

The pronouncibility of such names may leave something to be desired. :)

It's possible to change the encoding to 5 bits per character to gain an
additional 2 characters for the name, but this reduces the available character
set to 31 characters, not enough to store a full alphanumeric character set.
Changing over to 8 bits per character would reduce the maximum name length to
8 characters and make it necessary to guard against nefarious names that
scramble the terminal. So all-in-all I figured 6 bits is probably optimal.

Anyway, have fun with it.

Regards,
Wouter

PS, to mlarkin@ & armani@: I've been out of it all for a while, I'll get back
to kvirt once I've got everything here up and running again.


Index: subr_disk.c
===================================================================
RCS file: /cvs/src/sys/kern/subr_disk.c,v
retrieving revision 1.114
diff -u -r1.114 subr_disk.c
--- subr_disk.c 24 Nov 2010 15:31:34 -0000 1.114
+++ subr_disk.c 22 Jun 2011 16:40:27 -0000
@@ -1352,49 +1352,96 @@
  u_char uid[8];
  char c, part;
  int i;
+ size_t len;

  /*
- * Attempt to map a request for a disklabel UID to the correct device.
- * We should be supplied with a disklabel UID which has the following
- * format:
+ * Attempt to map a request for a disk name or disklabel UID to the
+ * correct device. A disk name is a string up to 10 characters long,
+ * and can consist of alphabetical and numeric characters and the
+ * '_' character.
  *
- * [disklabel uid] . [partition]
+ * If the DM_OPENPART flag is not set, the name or UID must be
+ * followed by the partition:
  *
- * Alternatively, if the DM_OPENPART flag is set the disklabel UID can
- * based passed on its own.
+ * [name or uid] . [partition]
  */

+ /* Verify that the device name is properly formed. */
  if (strchr(path, '/') != NULL)
  return -1;
-
- /* Verify that the device name is properly formed. */
- if (!((strlen(path) == 16 && (flags & DM_OPENPART)) ||
-    (strlen(path) == 18 && path[16] == '.')))
+ len = strlen(path);
+ if (len > 18)
  return -1;
+ if ((len <= 2 || path[len - 2] != '.') && !(flags & DM_OPENPART))
+ return -1;
+ if (len > 2 && path[len - 2] == '.')
+ len -= 2;

  /* Get partition. */
  if (flags & DM_OPENPART)
  part = 'a' + RAW_PART;
  else
- part = path[17];
+ part = path[len + 1];

  if (part < 'a' || part >= 'a' + MAXPARTITIONS)
  return -1;

- /* Derive label UID. */
- bzero(uid, sizeof(uid));
- for (i = 0; i < 16; i++) {
- c = path[i];
- if (c >= '0' && c <= '9')
- c -= '0';
- else if (c >= 'a' && c <= 'f')
- c -= ('a' - 10);
-                else
- return -1;
-
- uid[i / 2] <<= 4;
- uid[i / 2] |= c & 0xf;
- }
+ /* Decode UID or name. */
+ if (len == 16) {
+ for (i = 0; i < 16; i++) {
+ c = path[i];
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'a' && c <= 'f')
+ c -= ('a' - 10);
+ else
+ return -1;
+
+ uid[i / 2] <<= 4;
+ uid[i / 2] |= c & 0xf;
+ }
+ } else if (len <= 10) {
+ u_char *p = uid;
+ int v = 0;
+
+ /* This is basically base64: read in 4 chars, shift out 3. */
+ bzero(uid, sizeof(uid));
+ for (i = 0; i < len; i++) {
+ c = path[i];
+ if (c >= '0' && c <= '9')
+ c -= '0' - 1;
+ else if (c >= 'A' && c <= 'A')
+ c -= 'A' - 11;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 37;
+ else if (c == '_')
+ c = 63;
+ else
+ return -1;
+
+ v = (v << 6) + c;
+ if (i % 4 == 3) {
+ *(p++) = v >> 16;
+ *(p++) = v >> 8;
+ *(p++) = v;
+ v = 0;
+ }
+ }
+
+ /* When we reach the end of the name we can have at most two
+ * bytes left to output, so just write them. This should be
+ * safe, since the loop above only writes up to uid[5]. */
+ if (v != 0) {
+ v <<= 6 * (4 - (i % 4));
+ *(p++) = v >> 16;
+ *(p++) = v >> 8;
+
+ /* Flush last byte if stopping prematurely. */
+ if (i < 10)
+ *(p++) = v;
+ }
+ } else
+ return -1;

  mdk = NULL;
  TAILQ_FOREACH(dk, &disklist, dk_link) {
Index: disklabel.c
===================================================================
RCS file: /cvs/src/sbin/disklabel/disklabel.c,v
retrieving revision 1.175
diff -u -r1.175 disklabel.c
--- disklabel.c 13 Dec 2010 01:01:41 -0000 1.175
+++ disklabel.c 22 Jun 2011 16:40:40 -0000
@@ -783,9 +783,9 @@
     lp->d_typename);
  fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
     lp->d_packname);
- fprintf(f, "duid: %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
-            lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3],
-            lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]);
+ fprintf(f, "duid: ");
+ duid_print(f, lp);
+ fprintf(f, "\n");
  fprintf(f, "flags:");
  if (lp->d_flags & D_BADSECT)
  fprintf(f, " badsect");
@@ -990,26 +990,107 @@
  u_char duid[8];
  char c;
  int i;
+ size_t len;
+
+ len = strlen(s);
+ if (len == 16) {
+ for (i = 0; i < 16; i++) {
+ c = s[i];
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'a' && c <= 'f')
+ c -= ('a' - 10);
+ else if (c >= 'A' && c <= 'F')
+ c -= ('A' - 10);
+ else
+ return -1;
+ duid[i / 2] <<= 4;
+ duid[i / 2] |= c & 0xf;
+ }
+ } else if (len <= 10) {
+ u_char *p = duid;
+ int v = 0;
+
+ /* This is basically base64: read in 4 chars, shift out 3. */
+ bzero(duid, sizeof(duid));
+ for (i = 0; i < len; i++) {
+ c = s[i];
+ if (c >= '0' && c <= '9')
+ c -= '0' - 1;
+ else if (c >= 'A' && c <= 'A')
+ c -= 'A' - 11;
+ else if (c >= 'a' && c <= 'z')
+ c -= 'a' - 37;
+ else if (c == '_')
+ c = 63;
+ else
+ return -1;
+
+ v = (v << 6) + c;
+ if (i % 4 == 3) {
+ *(p++) = v >> 16;
+ *(p++) = v >> 8;
+ *(p++) = v;
+ v = 0;
+ }
+ }

- if (strlen(s) != 16)
+ /* When we reach the end of the name we can have at most two
+ * bytes left to output, so just write them. This should be
+ * safe, since the loop above only writes up to uid[5]. */
+ if (v != 0) {
+ v <<= 6 * (4 - (i % 4));
+ *(p++) = v >> 16;
+ *(p++) = v >> 8;
+
+ /* Flush last byte if stopping prematurely. */
+ if (i < 10)
+ *(p++) = v;
+ }
+ } else
  return -1;

- for (i = 0; i < 16; i++) {
- c = s[i];
- if (c >= '0' && c <= '9')
- c -= '0';
- else if (c >= 'a' && c <= 'f')
- c -= ('a' - 10);
- else if (c >= 'A' && c <= 'F')
- c -= ('A' - 10);
+ memcpy(lp->d_uid, &duid, sizeof(lp->d_uid));
+ return 0;
+}
+
+void
+duid_print(FILE *f, struct disklabel *lp)
+{
+ char name[11];
+ int i, v;
+ u_char c, *p;
+
+ p = lp->d_uid;
+ bzero(name, sizeof(name));
+ for (i = 0; i < 10; i++) {
+ if (i % 4 == 0) {
+ v  = ((int) *(p++) << 16);
+ v += ((int) *(p++) <<  8);
+ if (i < 8)
+ v += *(p++);
+ }
+
+ c = (v >> 6 * 3) & 0x3f;
+ v <<= 6;
+ if (c == 63)
+ c = '_';
+ else if (c >= 37)
+ c += 'a' - 37;
+ else if (c >= 11)
+ c += 'A' - 11;
+ else if (c >= 1)
+ c += '0' - 1;
  else
- return -1;
- duid[i / 2] <<= 4;
- duid[i / 2] |= c & 0xf;
+ break;
+
+ name[i] = c;
  }

- memcpy(lp->d_uid, &duid, sizeof(lp->d_uid));
- return 0;
+ fprintf(f, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx ('%s')",
+    lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3],
+    lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7],
+    name);
 }

 /*
Index: editor.c
===================================================================
RCS file: /cvs/src/sbin/disklabel/editor.c,v
retrieving revision 1.248
diff -u -r1.248 editor.c
--- editor.c 19 Feb 2011 21:18:59 -0000 1.248
+++ editor.c 22 Jun 2011 16:40:41 -0000
@@ -1619,14 +1619,14 @@
  char *s;
  int i;

- printf("The disklabel UID is currently: "
-    "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\n",
-            lp->d_uid[0], lp->d_uid[1], lp->d_uid[2], lp->d_uid[3],
-            lp->d_uid[4], lp->d_uid[5], lp->d_uid[6], lp->d_uid[7]);
+ printf("The disklabel UID is currently: ");
+ duid_print(stdout, lp);
+ printf("\n");

  do {
- s = getstring("duid", "The disklabel UID, given as a 16 "
-    "character hexadecimal string.", NULL);
+ s = getstring("duid", "The disklabel UID, given as a 10 "
+    "character name or 16 character hexadecimal string.",
+    NULL);
  if (s == NULL || strlen(s) == 0) {
  fputs("Command aborted\n", stderr);
  return;
Index: extern.h
===================================================================
RCS file: /cvs/src/sbin/disklabel/extern.h,v
retrieving revision 1.21
diff -u -r1.21 extern.h
--- extern.h 24 Nov 2010 14:15:31 -0000 1.21
+++ extern.h 22 Jun 2011 16:40:41 -0000
@@ -26,6 +26,7 @@
 void display(FILE *, struct disklabel *, char, int);
 void display_partition(FILE *, struct disklabel *, int, char);
 int duid_parse(struct disklabel *, char *);
+void duid_print(FILE *, struct disklabel *);

 void readlabel(int);
 struct disklabel *makebootarea(char *, struct disklabel *, int);
Index: duid.c
===================================================================
RCS file: /cvs/src/lib/libutil/duid.c,v
retrieving revision 1.1
diff -u -r1.1 duid.c
--- duid.c 15 Nov 2010 15:07:40 -0000 1.1
+++ duid.c 22 Jun 2011 16:40:48 -0000
@@ -23,18 +23,34 @@
 {
  char c;
  int i;
+ size_t len;

  /* Basic format check. */
- if (!((strlen(duid) == 16 && (dflags & OPENDEV_PART)) ||
-    (strlen(duid) == 18 && duid[16] == '.')))
+ len = strlen(duid);
+ if (len > 18 ||
+    ((len <= 2 || duid[(int) len - 2] != '.') && !(dflags & OPENDEV_PART)))
  return 0;
+ if (len > 2 && duid[(int) len - 2] == '.')
+ len -= 2;

  /* Check UID. */
- for (i = 0; i < 16; i++) {
- c = duid[i];
- if ((c < '0' || c > '9') && (c < 'a' || c > 'f'))
- return 0;
- }
+ if (len == 16) {
+ for (i = 0; i < 16; i++) {
+ c = duid[i];
+ if ((c < '0' || c > '9') && (c < 'a' || c > 'f'))
+ return 0;
+ }
+ } else if (len <= 10) {
+ for (i = 0; i < (int) len; i++) {
+ c = duid[i];
+ if ((c < '0' || c > '9') &&
+    (c < 'A' || c > 'Z') &&
+    (c < 'a' || c > 'z') &&
+    (c != '_'))
+ return 0;
+ }
+ } else
+ return 0;

  return 1;
 }
Index: isduid.3
===================================================================
RCS file: /cvs/src/lib/libutil/isduid.3,v
retrieving revision 1.1
diff -u -r1.1 isduid.3
--- isduid.3 17 Nov 2010 10:10:31 -0000 1.1
+++ isduid.3 22 Jun 2011 16:40:48 -0000
@@ -19,7 +19,7 @@
 .Os
 .Sh NAME
 .Nm isduid
-.Nd disklabel UID test
+.Nd disk name or disklabel UID test
 .Sh SYNOPSIS
 .Fd #include <util.h>
 .Ft int
@@ -29,7 +29,7 @@
 .Fn isduid
 function tests the string
 .Fa duid
-to see if it is a valid
+to see if it is a valid disk name or
 .Xr disklabel 8
 UID.
 The
@@ -37,11 +37,17 @@
 are specified using the same flags as used by
 .Xr opendev 3 .
 .Pp
-If the OPENDEV_PART flag is included in
+When
+.Fa duid
+is intended as a disk name, it can be up to 10 characters long and must
+consist only of alphabetical and numeric characters and the character
+.Sq \. .
+When intended as a disklabel UID,
+.Fa duid
+must consist of a 16-character hexadecimal string.
+If the OPENDEV_PART flag is not included in
 .Fa dflags
-the disklabel UID must consist of a 16-character hexadecimal string.
-Otherwise the disklabel UID must consist of a 16-character hexidecimal
string
-followed by a
+the disk name or disklabel UID must be followed by a
 .Sq \&.
 and a partition letter.
 .Sh RETURN VALUES

Reply | Threaded
Open this post in threaded view
|

Re: Identifying disks by name

Kenneth R Westerback
On Wed, Jun 22, 2011 at 06:48:14PM +0200, Wouter Coene wrote:
> Hi all,
>
> The patch below builds on the disk UID code to implement disk names. Disk
> names must match [a-zA-Z0-9_]{1,10} and are stored encoded as 6 bits per
> character into the disklabel UID field. With this patch, you can use disk
> names in /etc/fstab:
>
> bootdisk.a / ffs rw 1 1

Why? This seems to add nothing but extra code and increase the
chances some twit will name multiple disks 'MYDISK' and screw
her/himself royally. Also, DUIDs identify a DISKLABEL and not a
disk.

.... Ken

Reply | Threaded
Open this post in threaded view
|

Re: Identifying disks by name

Wouter Coene
On 22 jun 2011, at 20:53, Kenneth R Westerback wrote:

> On Wed, Jun 22, 2011 at 06:48:14PM +0200, Wouter Coene wrote:
>> The patch below builds on the disk UID code to implement disk names. Disk
>> names must match [a-zA-Z0-9_]{1,10} and are stored encoded as 6 bits per
>> character into the disklabel UID field. With this patch, you can use disk
>> names in /etc/fstab:
>>
>> bootdisk.a / ffs rw 1 1
>
> Why? This seems to add nothing but extra code and increase the
> chances some twit will name multiple disks 'MYDISK' and screw
> her/himself royally. Also, DUIDs identify a DISKLABEL and not a
> disk.

Right now, nothing is stopping you from naming multiple disks 1234567890abcdef
either. Twits will be twits, I'm just looking for something that's easier to
type (and remember) than a hex-string.

Also, this is certainly not useless if you have more than a handfull of disks
or SAN volumes, or for removable media. Which of the following is more
readable?

        mount 1234567890abcdef.a /mnt
        mount backups.a /mnt

Regards,
Wouter

Reply | Threaded
Open this post in threaded view
|

Re: Identifying disks by name

Stuart Henderson
On 2011/06/22 21:07, Wouter Coene wrote:
>
> Also, this is certainly not useless if you have more than a handfull of disks
> or SAN volumes, or for removable media. Which of the following is more
> readable?
>
> mount 1234567890abcdef.a /mnt
> mount backups.a /mnt

mount bac0000000000001.a /mnt isn't too bad :-)

Reply | Threaded
Open this post in threaded view
|

Re: Identifying disks by name

Thordur Bjornsson-2
In reply to this post by Wouter Coene
On Wed, Jun 22, 2011 at 09:07:41PM +0200, Wouter Coene wrote:

> On 22 jun 2011, at 20:53, Kenneth R Westerback wrote:
> > On Wed, Jun 22, 2011 at 06:48:14PM +0200, Wouter Coene wrote:
> >> The patch below builds on the disk UID code to implement disk names. Disk
> >> names must match [a-zA-Z0-9_]{1,10} and are stored encoded as 6 bits per
> >> character into the disklabel UID field. With this patch, you can use disk
> >> names in /etc/fstab:
> >>
> >> bootdisk.a / ffs rw 1 1
> >
> > Why? This seems to add nothing but extra code and increase the
> > chances some twit will name multiple disks 'MYDISK' and screw
> > her/himself royally. Also, DUIDs identify a DISKLABEL and not a
> > disk.
>
> Right now, nothing is stopping you from naming multiple disks 1234567890abcdef
> either. Twits will be twits, I'm just looking for something that's easier to
> type (and remember) than a hex-string.
>
> Also, this is certainly not useless if you have more than a handfull of disks
> or SAN volumes, or for removable media. Which of the following is more
> readable?
>
> mount 1234567890abcdef.a /mnt
> mount backups.a /mnt
For this type of stuff, you are looking for hotplugd(8); And duids make
writing hotplug scripts much easier.

While I do see the allure of having nice names for "disks", this is
problematic (like ken pointed out) so I think I'll have to agree with
ken for now that this is extra code for a very minimal gain.

Anyways, always nice to see diffs!

cheers, thib.

Reply | Threaded
Open this post in threaded view
|

Re: Identifying disks by name

Janjaap van Velthooven
In reply to this post by Stuart Henderson
On Wed, Jun 22, 2011 at 08:12:28PM +0100, Stuart Henderson wrote:
> On 2011/06/22 21:07, Wouter Coene wrote:
> > Also, this is certainly not useless if you have more than a handfull of disks
> > or SAN volumes, or for removable media. Which of the following is more
> > readable?
> >
> > mount 1234567890abcdef.a /mnt
> > mount backups.a /mnt
>
> mount bac0000000000001.a /mnt isn't too bad :-)

Just a vague idea for the moment;

How aboot some mechanism that can do number lookups by name for disks?
( just like is done for host protocols ports or users and groups and possibly
more things.. )

for instance an /etc/disks with lines like:
1234567890abcdef backups bac0000000000001

Anyways, as I have no code for something like this at this moment I'll shut up
for now on this.

        Janjaap van Velthooven
--  ________________________________________
   / __/ /_    / ______/ /_  __/ __/ /___  /
  / /_  __/___/_/_  /___  / / __/ /___  / /          [hidden email]
 /___/_/_________/_____/_/_/_/_______/_/_/        

Reply | Threaded
Open this post in threaded view
|

Re: Identifying disks by name

Stuart Henderson
On 2011-06-22, Janjaap van Velthooven <[hidden email]> wrote:
> How aboot some mechanism that can do number lookups by name for disks?

Perhaps something like http://tinyurl.com/6jykr8g ?

> ( just like is done for host protocols ports or users and groups and possibly
> more things.. )
>
> for instance an /etc/disks with lines like:
> 1234567890abcdef backups bac0000000000001
>
> Anyways, as I have no code for something like this at this moment I'll shut up
> for now on this.
>
> Janjaap van Velthooven
> --  ________________________________________
>    / __/ /_    / ______/ /_  __/ __/ /___  /
>   / /_  __/___/_/_  /___  / / __/ /___  / /          [hidden email]
>  /___/_/_________/_____/_/_/_/_______/_/_/        

Reply | Threaded
Open this post in threaded view
|

Re: Identifying disks by name

Thordur Bjornsson-2
In reply to this post by Janjaap van Velthooven
On Wed, Jun 22, 2011 at 09:34:55PM +0200, Janjaap van Velthooven wrote:

> On Wed, Jun 22, 2011 at 08:12:28PM +0100, Stuart Henderson wrote:
> > On 2011/06/22 21:07, Wouter Coene wrote:
> > > Also, this is certainly not useless if you have more than a handfull of disks
> > > or SAN volumes, or for removable media. Which of the following is more
> > > readable?
> > >
> > > mount 1234567890abcdef.a /mnt
> > > mount backups.a /mnt
> >
> > mount bac0000000000001.a /mnt isn't too bad :-)
>
> Just a vague idea for the moment;
>
> How aboot some mechanism that can do number lookups by name for disks?
> ( just like is done for host protocols ports or users and groups and possibly
> more things.. )
>
> for instance an /etc/disks with lines like:
> 1234567890abcdef backups bac0000000000001
>
> Anyways, as I have no code for something like this at this moment I'll shut up
> for now on this.

/etc/disks
DUID myrootdisk

/etc/fstab
myrootdisk.a / ffs rw,softdep 1 1

And now I'm royally fucked.

Reply | Threaded
Open this post in threaded view
|

Re: Identifying disks by name

roberth-5
In reply to this post by Wouter Coene
On Wed, 22 Jun 2011 21:07:41 +0200
Wouter Coene <[hidden email]> wrote:

> mount 1234567890abcdef.a /mnt
> mount backups.a /mnt

# export backups=1234567890abcdef
# mount $backups.a /mnt

I myself prefere to include the slice, less to remember/look up.

Reply | Threaded
Open this post in threaded view
|

Re: Identifying disks by name

Thordur Bjornsson-2
In reply to this post by Thordur Bjornsson-2
On Wed, Jun 22, 2011 at 09:54:07PM +0200, Janjaap van Velthooven wrote:

> Thordur Bjornsson wrote and mailed:
> > On Wed, Jun 22, 2011 at 09:34:55PM +0200, Janjaap van Velthooven wrote:
> > > Just a vague idea for the moment;
> > >
> > > How aboot some mechanism that can do number lookups by name for disks?
> > > ( just like is done for host protocols ports or users and groups and possibly
> > > more things.. )
> > >
> > > for instance an /etc/disks with lines like:
> > > 1234567890abcdef backups bac0000000000001
> > >
> > > Anyways, as I have no code for something like this at this moment I'll shut up
> > > for now on this.
>
> > /etc/disks
> > DUID myrootdisk
> >
> > /etc/fstab
> > myrootdisk.a / ffs rw,softdep 1 1
> >
> > And now I'm royally fucked.

And I smoke to much dope (or not enough?).

Reply | Threaded
Open this post in threaded view
|

Re: Identifying disks by name

Henning Brauer-5
In reply to this post by Janjaap van Velthooven
* Janjaap van Velthooven <[hidden email]> [2011-06-22 21:37]:
> Just a vague idea for the moment;
>
> How aboot some mechanism that can do number lookups by name for disks?

like... fstab?

b6c15508a519d7ae.d /backup/ftp ffs rw,softdep,nodev,nosuid,noexec,noatime,noauto

--
Henning Brauer, [hidden email], [hidden email]
BS Web Services, http://bsws.de
Full-Service ISP - Secure Hosting, Mail and DNS Services
Dedicated Servers, Rootservers, Application Hosting