1/*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2002 Poul-Henning Kamp 5 * Copyright (c) 2002 Networks Associates Technology, Inc. 6 * All rights reserved. 7 * 8 * This software was developed for the FreeBSD Project by Poul-Henning Kamp 9 * and NAI Labs, the Security Research Division of Network Associates, Inc. 10 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 11 * DARPA CHATS research program. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. The names of the authors may not be used to endorse or promote 22 * products derived from this software without specific prior written 23 * permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38#include <sys/cdefs.h> 39__FBSDID("$FreeBSD$"); 40 41#include <sys/param.h> 42#include <sys/endian.h> 43#include <sys/systm.h> 44#include <sys/sysctl.h> 45#include <sys/kernel.h> 46#include <sys/conf.h> 47#include <sys/bio.h> 48#include <sys/malloc.h> 49#include <sys/lock.h> 50#include <sys/mutex.h> 51#include <sys/md5.h> 52#include <sys/sbuf.h> 53#include <sys/sun_disklabel.h> 54#include <geom/geom.h> 55#include <geom/geom_slice.h> 56#include <machine/endian.h> 57 58FEATURE(geom_sunlabel, "GEOM Sun/Solaris partitioning support"); 59 60#define SUNLABEL_CLASS_NAME "SUN" 61 62struct g_sunlabel_softc { 63 int sectorsize; 64 int nheads; 65 int nsects; 66 int nalt; 67 u_char labelsum[16]; 68}; 69 70static int g_sunlabel_once = 0; 71 72static int 73g_sunlabel_modify(struct g_geom *gp, struct g_sunlabel_softc *ms, u_char *sec0) 74{ 75 int i, error; 76 u_int u, v, csize; 77 struct sun_disklabel sl; 78 MD5_CTX md5sum; 79 80 error = sunlabel_dec(sec0, &sl); 81 if (error) 82 return (error); 83 84 csize = sl.sl_ntracks * sl.sl_nsectors; 85 86 for (i = 0; i < SUN_NPART; i++) { 87 v = sl.sl_part[i].sdkp_cyloffset; 88 u = sl.sl_part[i].sdkp_nsectors; 89 error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK, 90 ((off_t)v * csize) << 9ULL, 91 ((off_t)u) << 9ULL, 92 ms->sectorsize, 93 "%s%c", gp->name, 'a' + i); 94 if (error) 95 return (error); 96 } 97 for (i = 0; i < SUN_NPART; i++) { 98 v = sl.sl_part[i].sdkp_cyloffset; 99 u = sl.sl_part[i].sdkp_nsectors; 100 g_slice_config(gp, i, G_SLICE_CONFIG_SET, 101 ((off_t)v * csize) << 9ULL, 102 ((off_t)u) << 9ULL, 103 ms->sectorsize, 104 "%s%c", gp->name, 'a' + i); 105 } 106 ms->nalt = sl.sl_acylinders; 107 ms->nheads = sl.sl_ntracks; 108 ms->nsects = sl.sl_nsectors; 109 110 /* 111 * Calculate MD5 from the first sector and use it for avoiding 112 * recursive labels creation. 113 */ 114 MD5Init(&md5sum); 115 MD5Update(&md5sum, sec0, ms->sectorsize); 116 MD5Final(ms->labelsum, &md5sum); 117 118 return (0); 119} 120 121static void 122g_sunlabel_hotwrite(void *arg, int flag) 123{ 124 struct bio *bp; 125 struct g_geom *gp; 126 struct g_slicer *gsp; 127 struct g_slice *gsl; 128 struct g_sunlabel_softc *ms; 129 u_char *p; 130 int error; 131 132 KASSERT(flag != EV_CANCEL, ("g_sunlabel_hotwrite cancelled")); 133 bp = arg; 134 gp = bp->bio_to->geom; 135 gsp = gp->softc; 136 ms = gsp->softc; 137 gsl = &gsp->slices[bp->bio_to->index]; 138 /* 139 * XXX: For all practical purposes, this whould be equvivalent to 140 * XXX: "p = (u_char *)bp->bio_data;" because the label is always 141 * XXX: in the first sector and we refuse sectors smaller than the 142 * XXX: label. 143 */ 144 p = (u_char *)bp->bio_data - (bp->bio_offset + gsl->offset); 145 146 error = g_sunlabel_modify(gp, ms, p); 147 if (error) { 148 g_io_deliver(bp, EPERM); 149 return; 150 } 151 g_slice_finish_hot(bp); 152} 153 154static void 155g_sunlabel_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp) 156{ 157 struct g_slicer *gsp; 158 struct g_sunlabel_softc *ms; 159 160 gsp = gp->softc; 161 ms = gsp->softc; 162 g_slice_dumpconf(sb, indent, gp, cp, pp); 163 if (indent == NULL) { 164 sbuf_printf(sb, " sc %u hd %u alt %u", 165 ms->nsects, ms->nheads, ms->nalt); 166 } 167} 168 169struct g_hh01 { 170 struct g_geom *gp; 171 struct g_sunlabel_softc *ms; 172 u_char *label; 173 int error; 174}; 175 176static void 177g_sunlabel_callconfig(void *arg, int flag) 178{ 179 struct g_hh01 *hp; 180 181 hp = arg; 182 hp->error = g_sunlabel_modify(hp->gp, hp->ms, hp->label); 183 if (!hp->error) 184 hp->error = g_write_data(LIST_FIRST(&hp->gp->consumer), 185 0, hp->label, SUN_SIZE); 186} 187 188/* 189 * NB! curthread is user process which GCTL'ed. 190 */ 191static void 192g_sunlabel_config(struct gctl_req *req, struct g_class *mp, const char *verb) 193{ 194 u_char *label; 195 int error, i; 196 struct g_hh01 h0h0; 197 struct g_slicer *gsp; 198 struct g_geom *gp; 199 struct g_consumer *cp; 200 201 g_topology_assert(); 202 gp = gctl_get_geom(req, mp, "geom"); 203 if (gp == NULL) 204 return; 205 cp = LIST_FIRST(&gp->consumer); 206 gsp = gp->softc; 207 if (!strcmp(verb, "write label")) { 208 label = gctl_get_paraml(req, "label", SUN_SIZE); 209 if (label == NULL) 210 return; 211 h0h0.gp = gp; 212 h0h0.ms = gsp->softc; 213 h0h0.label = label; 214 h0h0.error = -1; 215 /* XXX: Does this reference register with our selfdestruct code ? */ 216 error = g_access(cp, 1, 1, 1); 217 if (error) { 218 gctl_error(req, "could not access consumer"); 219 return; 220 } 221 g_sunlabel_callconfig(&h0h0, 0); 222 g_access(cp, -1, -1, -1); 223 } else if (!strcmp(verb, "write bootcode")) { 224 label = gctl_get_paraml(req, "bootcode", SUN_BOOTSIZE); 225 if (label == NULL) 226 return; 227 /* XXX: Does this reference register with our selfdestruct code ? */ 228 error = g_access(cp, 1, 1, 1); 229 if (error) { 230 gctl_error(req, "could not access consumer"); 231 return; 232 } 233 for (i = 0; i < SUN_NPART; i++) { 234 if (gsp->slices[i].length <= SUN_BOOTSIZE) 235 continue; 236 g_write_data(cp, 237 gsp->slices[i].offset + SUN_SIZE, label + SUN_SIZE, 238 SUN_BOOTSIZE - SUN_SIZE); 239 } 240 g_access(cp, -1, -1, -1); 241 } else { 242 gctl_error(req, "Unknown verb parameter"); 243 } 244} 245 246static int 247g_sunlabel_start(struct bio *bp) 248{ 249 struct g_sunlabel_softc *mp; 250 struct g_slicer *gsp; 251 252 gsp = bp->bio_to->geom->softc; 253 mp = gsp->softc; 254 if (bp->bio_cmd == BIO_GETATTR) { 255 if (g_handleattr(bp, "SUN::labelsum", mp->labelsum, 256 sizeof(mp->labelsum))) 257 return (1); 258 } 259 return (0); 260} 261 262static struct g_geom * 263g_sunlabel_taste(struct g_class *mp, struct g_provider *pp, int flags) 264{ 265 struct g_geom *gp; 266 struct g_consumer *cp; 267 struct g_sunlabel_softc *ms; 268 struct g_slicer *gsp; 269 u_char *buf, hash[16]; 270 MD5_CTX md5sum; 271 int error; 272 273 g_trace(G_T_TOPOLOGY, "g_sunlabel_taste(%s,%s)", mp->name, pp->name); 274 g_topology_assert(); 275 if (flags == G_TF_NORMAL && 276 !strcmp(pp->geom->class->name, SUNLABEL_CLASS_NAME)) 277 return (NULL); 278 gp = g_slice_new(mp, 8, pp, &cp, &ms, sizeof *ms, g_sunlabel_start); 279 if (gp == NULL) 280 return (NULL); 281 gsp = gp->softc; 282 do { 283 ms->sectorsize = cp->provider->sectorsize; 284 if (ms->sectorsize < 512) 285 break; 286 g_topology_unlock(); 287 buf = g_read_data(cp, 0, ms->sectorsize, NULL); 288 g_topology_lock(); 289 if (buf == NULL) 290 break; 291 292 /* 293 * Calculate MD5 from the first sector and use it for avoiding 294 * recursive labels creation. 295 */ 296 MD5Init(&md5sum); 297 MD5Update(&md5sum, buf, ms->sectorsize); 298 MD5Final(ms->labelsum, &md5sum); 299 300 error = g_getattr("SUN::labelsum", cp, &hash); 301 if (!error && !bcmp(ms->labelsum, hash, sizeof(hash))) { 302 g_free(buf); 303 break; 304 } 305 306 g_sunlabel_modify(gp, ms, buf); 307 g_free(buf); 308 309 break; 310 } while (0); 311 g_access(cp, -1, 0, 0); 312 if (LIST_EMPTY(&gp->provider)) { 313 g_slice_spoiled(cp); 314 return (NULL); 315 } 316 g_slice_conf_hot(gp, 0, 0, SUN_SIZE, 317 G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL); 318 gsp->hot = g_sunlabel_hotwrite; 319 if (!g_sunlabel_once) { 320 g_sunlabel_once = 1; 321 printf( 322 "WARNING: geom_sunlabel (geom %s) is deprecated, " 323 "use gpart instead.\n", gp->name); 324 } 325 return (gp); 326} 327 328static struct g_class g_sunlabel_class = { 329 .name = SUNLABEL_CLASS_NAME, 330 .version = G_VERSION, 331 .taste = g_sunlabel_taste, 332 .ctlreq = g_sunlabel_config, 333 .dumpconf = g_sunlabel_dumpconf, 334}; 335 336DECLARE_GEOM_CLASS(g_sunlabel_class, g_sunlabel); 337MODULE_VERSION(geom_sunlabel, 0); 338