1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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/param.h> 30 #include <sys/systm.h> 31 #include <sys/kernel.h> 32 #include <sys/malloc.h> 33 #include <sys/kobj.h> 34 #include <sys/gpt.h> 35 #include <sys/sbuf.h> 36 37 #include <geom/geom.h> 38 #include <geom/label/g_label.h> 39 #include <geom/part/g_part.h> 40 41 #define PART_CLASS_NAME "PART" 42 #define SCHEME_NAME "GPT" 43 44 /* XXX: Also defined in geom/part/g_part_gpt.c */ 45 struct g_part_gpt_entry { 46 struct g_part_entry base; 47 struct gpt_ent ent; 48 }; 49 50 /* XXX: Shamelessly stolen from g_part_gpt.c */ 51 static void 52 sbuf_nprintf_utf16(struct sbuf *sb, uint16_t *str, size_t len) 53 { 54 u_int bo; 55 uint32_t ch; 56 uint16_t c; 57 58 bo = LITTLE_ENDIAN; /* GPT is little-endian */ 59 while (len > 0 && *str != 0) { 60 ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str); 61 str++, len--; 62 if ((ch & 0xf800) == 0xd800) { 63 if (len > 0) { 64 c = (bo == BIG_ENDIAN) ? be16toh(*str) 65 : le16toh(*str); 66 str++, len--; 67 } else 68 c = 0xfffd; 69 if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) { 70 ch = ((ch & 0x3ff) << 10) + (c & 0x3ff); 71 ch += 0x10000; 72 } else 73 ch = 0xfffd; 74 } else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */ 75 bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN; 76 continue; 77 } else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */ 78 continue; 79 80 /* Write the Unicode character in UTF-8 */ 81 if (ch < 0x80) 82 sbuf_printf(sb, "%c", ch); 83 else if (ch < 0x800) 84 sbuf_printf(sb, "%c%c", 0xc0 | (ch >> 6), 85 0x80 | (ch & 0x3f)); 86 else if (ch < 0x10000) 87 sbuf_printf(sb, "%c%c%c", 0xe0 | (ch >> 12), 88 0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f)); 89 else if (ch < 0x200000) 90 sbuf_printf(sb, "%c%c%c%c", 0xf0 | (ch >> 18), 91 0x80 | ((ch >> 12) & 0x3f), 92 0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f)); 93 } 94 } 95 96 static void 97 g_label_gpt_taste(struct g_consumer *cp, char *label, size_t size) 98 { 99 struct g_provider *pp; 100 struct g_part_table *tp; 101 struct g_part_gpt_entry *part_gpt_entry; 102 struct sbuf *lbl; 103 104 g_topology_assert_not(); 105 pp = cp->provider; 106 tp = (struct g_part_table *)pp->geom->softc; 107 label[0] = '\0'; 108 109 /* We taste only partitions handled by GPART */ 110 if (strncmp(pp->geom->class->name, PART_CLASS_NAME, sizeof(PART_CLASS_NAME))) 111 return; 112 /* and only GPT */ 113 if (strncmp(tp->gpt_scheme->name, SCHEME_NAME, sizeof(SCHEME_NAME))) 114 return; 115 116 part_gpt_entry = (struct g_part_gpt_entry *)pp->private; 117 118 /* 119 * Create sbuf with biggest possible size. 120 * We need max. 4 bytes for every 2-byte utf16 char. 121 */ 122 lbl = sbuf_new(NULL, NULL, sizeof(part_gpt_entry->ent.ent_name) << 1, SBUF_FIXEDLEN); 123 /* Size is the number of characters, not bytes */ 124 sbuf_nprintf_utf16(lbl, part_gpt_entry->ent.ent_name, sizeof(part_gpt_entry->ent.ent_name) >> 1); 125 sbuf_finish(lbl); 126 strlcpy(label, sbuf_data(lbl), size); 127 sbuf_delete(lbl); 128 } 129 130 static void 131 g_label_gpt_uuid_taste(struct g_consumer *cp, char *label, size_t size) 132 { 133 struct g_provider *pp; 134 struct g_part_table *tp; 135 struct g_part_gpt_entry *part_gpt_entry; 136 137 g_topology_assert_not(); 138 pp = cp->provider; 139 tp = (struct g_part_table *)pp->geom->softc; 140 label[0] = '\0'; 141 142 /* We taste only partitions handled by GPART */ 143 if (strncmp(pp->geom->class->name, PART_CLASS_NAME, sizeof(PART_CLASS_NAME))) 144 return; 145 /* and only GPT */ 146 if (strncmp(tp->gpt_scheme->name, SCHEME_NAME, sizeof(SCHEME_NAME))) 147 return; 148 149 part_gpt_entry = (struct g_part_gpt_entry *)pp->private; 150 snprintf_uuid(label, size, &part_gpt_entry->ent.ent_uuid); 151 } 152 153 struct g_label_desc g_label_gpt = { 154 .ld_taste = g_label_gpt_taste, 155 .ld_dirprefix = "gpt/", 156 .ld_enabled = 1 157 }; 158 159 struct g_label_desc g_label_gpt_uuid = { 160 .ld_taste = g_label_gpt_uuid_taste, 161 .ld_dirprefix = "gptid/", 162 .ld_enabled = 1 163 }; 164 165 G_LABEL_INIT(gpt, g_label_gpt, "Create device nodes for GPT labels"); 166 G_LABEL_INIT(gptid, g_label_gpt_uuid, "Create device nodes for GPT UUIDs"); 167