1 /*- 2 * Copyright (c) 2008 Marius Nuennerich 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/malloc.h> 34 #include <sys/kobj.h> 35 #include <sys/gpt.h> 36 #include <sys/sbuf.h> 37 38 #include <geom/geom.h> 39 #include <geom/label/g_label.h> 40 #include <geom/part/g_part.h> 41 42 #define PART_CLASS_NAME "PART" 43 #define SCHEME_NAME "GPT" 44 45 #define G_LABEL_GPT_VOLUME_DIR "gpt" 46 #define G_LABEL_GPT_ID_DIR "gptid" 47 48 /* XXX: Also defined in geom/part/g_part_gpt.c */ 49 struct g_part_gpt_entry { 50 struct g_part_entry base; 51 struct gpt_ent ent; 52 }; 53 54 /* XXX: Shamelessly stolen from g_part_gpt.c */ 55 static void 56 sbuf_nprintf_utf16(struct sbuf *sb, uint16_t *str, size_t len) 57 { 58 u_int bo; 59 uint32_t ch; 60 uint16_t c; 61 62 bo = LITTLE_ENDIAN; /* GPT is little-endian */ 63 while (len > 0 && *str != 0) { 64 ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str); 65 str++, len--; 66 if ((ch & 0xf800) == 0xd800) { 67 if (len > 0) { 68 c = (bo == BIG_ENDIAN) ? be16toh(*str) 69 : le16toh(*str); 70 str++, len--; 71 } else 72 c = 0xfffd; 73 if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) { 74 ch = ((ch & 0x3ff) << 10) + (c & 0x3ff); 75 ch += 0x10000; 76 } else 77 ch = 0xfffd; 78 } else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */ 79 bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN; 80 continue; 81 } else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */ 82 continue; 83 84 /* Write the Unicode character in UTF-8 */ 85 if (ch < 0x80) 86 sbuf_printf(sb, "%c", ch); 87 else if (ch < 0x800) 88 sbuf_printf(sb, "%c%c", 0xc0 | (ch >> 6), 89 0x80 | (ch & 0x3f)); 90 else if (ch < 0x10000) 91 sbuf_printf(sb, "%c%c%c", 0xe0 | (ch >> 12), 92 0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f)); 93 else if (ch < 0x200000) 94 sbuf_printf(sb, "%c%c%c%c", 0xf0 | (ch >> 18), 95 0x80 | ((ch >> 12) & 0x3f), 96 0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f)); 97 } 98 } 99 100 static void 101 g_label_gpt_taste(struct g_consumer *cp, char *label, size_t size) 102 { 103 struct g_provider *pp; 104 struct g_part_table *tp; 105 struct g_part_gpt_entry *part_gpt_entry; 106 struct sbuf *lbl; 107 108 g_topology_assert_not(); 109 pp = cp->provider; 110 tp = (struct g_part_table *)pp->geom->softc; 111 label[0] = '\0'; 112 113 /* We taste only partitions handled by GPART */ 114 if (strncmp(pp->geom->class->name, PART_CLASS_NAME, sizeof(PART_CLASS_NAME))) 115 return; 116 /* and only GPT */ 117 if (strncmp(tp->gpt_scheme->name, SCHEME_NAME, sizeof(SCHEME_NAME))) 118 return; 119 120 part_gpt_entry = (struct g_part_gpt_entry *)pp->private; 121 122 /* 123 * Create sbuf with biggest possible size. 124 * We need max. 4 bytes for every 2-byte utf16 char. 125 */ 126 lbl = sbuf_new(NULL, NULL, sizeof(part_gpt_entry->ent.ent_name) << 1, SBUF_FIXEDLEN); 127 /* Size is the number of characters, not bytes */ 128 sbuf_nprintf_utf16(lbl, part_gpt_entry->ent.ent_name, sizeof(part_gpt_entry->ent.ent_name) >> 1); 129 sbuf_finish(lbl); 130 strlcpy(label, sbuf_data(lbl), size); 131 sbuf_delete(lbl); 132 } 133 134 static void 135 g_label_gpt_uuid_taste(struct g_consumer *cp, char *label, size_t size) 136 { 137 struct g_provider *pp; 138 struct g_part_table *tp; 139 struct g_part_gpt_entry *part_gpt_entry; 140 141 g_topology_assert_not(); 142 pp = cp->provider; 143 tp = (struct g_part_table *)pp->geom->softc; 144 label[0] = '\0'; 145 146 /* We taste only partitions handled by GPART */ 147 if (strncmp(pp->geom->class->name, PART_CLASS_NAME, sizeof(PART_CLASS_NAME))) 148 return; 149 /* and only GPT */ 150 if (strncmp(tp->gpt_scheme->name, SCHEME_NAME, sizeof(SCHEME_NAME))) 151 return; 152 153 part_gpt_entry = (struct g_part_gpt_entry *)pp->private; 154 snprintf_uuid(label, size, &part_gpt_entry->ent.ent_uuid); 155 } 156 157 struct g_label_desc g_label_gpt = { 158 .ld_taste = g_label_gpt_taste, 159 .ld_dir = G_LABEL_GPT_VOLUME_DIR, 160 .ld_enabled = 1 161 }; 162 163 struct g_label_desc g_label_gpt_uuid = { 164 .ld_taste = g_label_gpt_uuid_taste, 165 .ld_dir = G_LABEL_GPT_ID_DIR, 166 .ld_enabled = 1 167 }; 168 169 G_LABEL_INIT(gpt, g_label_gpt, "Create device nodes for GPT labels"); 170 G_LABEL_INIT(gptid, g_label_gpt_uuid, "Create device nodes for GPT UUIDs"); 171