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