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