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