Home | History | Annotate | Download | only in diskomizer
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  *	Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  *	Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"@(#)findap.c	1.18	09/05/26 SMI"
     28 
     29 #include <unistd.h>
     30 #include <ftw.h>
     31 #include <stdlib.h>
     32 #include <stdio.h>
     33 #include <strings.h>
     34 #include <search.h>
     35 #include <errno.h>
     36 #include <sys/vtoc.h>
     37 
     38 #define	COMMA ','
     39 #define	COLON ':'
     40 
     41 #include "findap.h"
     42 struct devstore {
     43 	struct other_paths *raw_or_cooked[2];
     44 };
     45 struct partstore {
     46 	int nparts;
     47 	struct devstore *devs;
     48 };
     49 struct lunstore {
     50 	int nluns;
     51 	struct partstore *parts;
     52 };
     53 struct pathstore {
     54 	char *wwa;
     55 	struct lunstore luns;
     56 };
     57 
     58 static struct pathstore *ps;
     59 static int last_pathstore;
     60 #ifdef FIND_AP_STATS
     61 static int hit_count;
     62 static int miss_count;
     63 #endif
     64 static size_t ndevtree;
     65 
     66 static int
     67 pscmp(const void *a, const void *b)
     68 {
     69 	struct pathstore *as, *bs;
     70 	as = (struct pathstore *)a;
     71 	bs = (struct pathstore *)b;
     72 	return (strcmp(as->wwa, bs->wwa));
     73 }
     74 static int
     75 add_to_dev_tree(const char *path, struct about_dev *entry)
     76 {
     77 	struct pathstore *new_ps;
     78 	struct other_paths *op;
     79 	struct pathstore *x;
     80 
     81 	if ((new_ps = realloc(ps, (ndevtree + 1) *
     82 	    sizeof (struct pathstore))) == NULL ||
     83 		(op = malloc(sizeof (struct other_paths))) == NULL) {
     84 		return (1);
     85 	}
     86 
     87 	if ((x = (struct pathstore *)
     88 		calloc(1, sizeof (struct pathstore))) == NULL) {
     89 		free(op);
     90 		return (1);
     91 	}
     92 	op->path = strdup(path);
     93 	x->wwa = entry->wwa;
     94 	/*
     95 	 * This extra check is a cheat, but a cheat that works.
     96 	 * Since the devices tend to get created all at the same time
     97 	 * nftw will tend to do all the nodes for the same disk
     98 	 * one after another. This check stops us having to do
     99 	 * any more lsearch() calls than are really needed.
    100 	 */
    101 	if (ps != NULL && pscmp(x, &new_ps[last_pathstore]) == 0) {
    102 #ifdef FIND_AP_STATS
    103 		hit_count++;
    104 #endif
    105 		ps = new_ps;
    106 		new_ps = &new_ps[last_pathstore];
    107 	} else {
    108 #ifdef FIND_AP_STATS
    109 		miss_count++;
    110 #endif
    111 		ps = new_ps;
    112 		new_ps = lsearch(x, ps, &ndevtree,
    113 		    sizeof (struct pathstore), pscmp);
    114 		last_pathstore = new_ps - ps;
    115 	}
    116 	if (new_ps->wwa != entry->wwa)
    117 		free(entry->wwa);
    118 	free(x);
    119 	if (new_ps->luns.nluns <= entry->lun) {
    120 		struct partstore *tmp;
    121 		int i;
    122 
    123 		tmp = realloc(new_ps->luns.parts, sizeof (struct partstore) *
    124 		    (entry->lun + 1));
    125 		if (tmp == NULL)
    126 			return (1);
    127 		for (i = new_ps->luns.nluns; i <= entry->lun; i++) {
    128 			tmp[i].nparts = 0;
    129 			tmp[i].devs = NULL;
    130 		}
    131 		new_ps->luns.parts = tmp;
    132 		new_ps->luns.nluns = entry->lun + 1;
    133 	}
    134 	if (new_ps->luns.parts[entry->lun].nparts <= entry->part) {
    135 		struct devstore *tmp;
    136 		int i, nparts;
    137 
    138 		nparts = entry->part + 1;
    139 		if (nparts < V_NUMPAR)
    140 			nparts = V_NUMPAR;
    141 
    142 		tmp = realloc(new_ps->luns.parts[entry->lun].devs,
    143 		    sizeof (struct devstore) * nparts);
    144 		if (tmp == NULL)
    145 			return (1);
    146 		for (i = new_ps->luns.parts[entry->lun].nparts;
    147 		    i < nparts; i++) {
    148 			tmp[i].raw_or_cooked[0] = NULL;
    149 			tmp[i].raw_or_cooked[1] = NULL;
    150 		}
    151 		new_ps->luns.parts[entry->lun].devs = tmp;
    152 		new_ps->luns.parts[entry->lun].nparts = nparts;
    153 	}
    154 
    155 	op->next = new_ps->luns.parts[
    156 	    entry->lun].devs[entry->part].raw_or_cooked[entry->israw];
    157 	new_ps->luns.parts[entry->lun].devs[
    158 	    entry->part].raw_or_cooked[entry->israw] = op;
    159 
    160 	return (0);
    161 }
    162 static char *
    163 get_wwa(const char *path)
    164 {
    165 	char *tofree, *tmp;
    166 	char *basename;
    167 
    168 	tofree = strdup(path);
    169 	tmp = tofree;
    170 
    171 	if (tmp == NULL) {
    172 		perror("strdup failed");
    173 		return (NULL);
    174 	}
    175 
    176 	basename = strrchr(tofree, '/');
    177 
    178 	if (basename == NULL)
    179 		basename = tofree;
    180 	else
    181 		basename += 1;
    182 
    183 	if (strncmp(basename, "ssd@", 4) != 0 || strlen(basename) <= 8) {
    184 		free(tofree);
    185 		return (NULL);
    186 	}
    187 
    188 	basename += 7;
    189 
    190 	tmp = strchr(basename, COLON);
    191 	if (tmp != NULL) {
    192 		*tmp = NULL;
    193 	}
    194 	tmp = strchr(basename, COMMA);
    195 
    196 	if (tmp != NULL) {
    197 		*tmp = NULL;
    198 		tmp = strdup(basename);
    199 	} else {
    200 		tmp = NULL;
    201 	}
    202 
    203 	free(tofree);
    204 
    205 	return (tmp);
    206 }
    207 
    208 static long
    209 get_lun(const char *path)
    210 {
    211 	int lun;
    212 	char *tmp;
    213 	tmp = strrchr(path, COLON);
    214 
    215 	if (tmp == NULL)
    216 		return (-1);
    217 	while (tmp > path) {
    218 		if (*tmp == COMMA)
    219 			break;
    220 		tmp--;
    221 	}
    222 	if (tmp <= path)
    223 		return (-1);
    224 	tmp++;
    225 
    226 	errno = 0;
    227 	lun = strtol(tmp, NULL, 16);
    228 
    229 	if (lun == 0 && errno == EINVAL) {
    230 		return (-1);
    231 	}
    232 	return (lun);
    233 }
    234 static char
    235 find_part(const char *path)
    236 {
    237 	char part;
    238 	char *tmp;
    239 
    240 	tmp = strrchr(path, COLON);
    241 
    242 	if (tmp == NULL)
    243 		return (-1);
    244 
    245 	tmp++;
    246 
    247 	part = *tmp - 'a';
    248 
    249 	if (part > (V_NUMPAR - 1) || part < 0)
    250 		part = -1;
    251 	return (part);
    252 }
    253 static char
    254 is_raw(const char *path)
    255 {
    256 	char *tmp;
    257 
    258 	tmp = strrchr(path, COMMA);
    259 
    260 	if (tmp == NULL) {
    261 		return (-1);
    262 	}
    263 
    264 	tmp++;
    265 
    266 	if (strcmp(tmp, "raw") == 0)
    267 		return (1);
    268 	else
    269 		return (0);
    270 }
    271 
    272 #ifdef NOT_USED
    273 static void
    274 print_dev(struct about_dev *dv)
    275 {
    276 	char *tmp;
    277 
    278 	switch (dv->israw) {
    279 		case 0: tmp = "block device";
    280 				break;
    281 		case 1: tmp = "raw device";
    282 			break;
    283 		default:
    284 			tmp = "error";
    285 			break;
    286 	}
    287 	(void) printf("WWA = %s, part = %c, %s\n",
    288 	    dv->wwa == NULL ? "(nil)" : dv->wwa,
    289 	    dv->part + 'a', tmp);
    290 }
    291 #endif
    292 static void
    293 print_otherpaths(struct other_paths *paths)
    294 {
    295 	while (paths != NULL) {
    296 		(void) printf("%s\n", paths->path);
    297 		paths = paths->next;
    298 	}
    299 }
    300 void
    301 print_paths(struct paths *paths)
    302 {
    303 	(void) printf("Logical path %s\n", paths->logicalpath);
    304 	(void) print_otherpaths(paths->op);
    305 }
    306 
    307 static void
    308 free_otherpaths(struct other_paths *paths)
    309 {
    310 	struct other_paths *p;
    311 
    312 	while (paths) {
    313 		p = paths->next;
    314 		free(paths->path);
    315 		free(paths);
    316 		paths = p;
    317 	}
    318 }
    319 void
    320 free_paths(struct paths *paths)
    321 {
    322 	free_otherpaths(paths->op);
    323 	if (paths->logicalpath != NULL)
    324 		free(paths->logicalpath);
    325 	free(paths);
    326 }
    327 static struct paths *
    328 dup_paths(struct paths *src)
    329 {
    330 	struct paths *top;
    331 	struct other_paths *tmp, *srctmp;
    332 
    333 	if (src == NULL || (top = calloc(1, sizeof (struct paths))) == NULL) {
    334 		return (NULL);
    335 	}
    336 	if ((top->logicalpath = strdup(src->logicalpath)) == NULL) {
    337 		free(top);
    338 		return (NULL);
    339 	}
    340 	if ((top->op = calloc(1, sizeof (struct other_paths))) == NULL) {
    341 		free_paths(top);
    342 		return (NULL);
    343 	}
    344 	for (tmp = top->op, srctmp = src->op; srctmp != NULL;
    345 	    srctmp = srctmp->next) {
    346 		if ((tmp->path = strdup(srctmp->path)) == NULL) {
    347 			free_paths(top);
    348 			return (NULL);
    349 		}
    350 		if (srctmp->next == NULL)
    351 			break;
    352 		if ((tmp->next = calloc(1, sizeof (struct other_paths))) ==
    353 		    NULL) {
    354 			free(tmp->path);
    355 			free_paths(top);
    356 			return (NULL);
    357 		}
    358 		tmp = tmp->next;
    359 	}
    360 	return (top);
    361 }
    362 /*ARGSUSED*/
    363 static int
    364 ftwfunc(const char *path, const struct stat *stat, int flag, struct FTW *ftw)
    365 {
    366 	struct about_dev thisdv;
    367 	if (flag != FTW_F)
    368 		return (0);
    369 
    370 
    371 	thisdv.wwa = get_wwa(path);
    372 	thisdv.part = find_part(path);
    373 	thisdv.lun = get_lun(path);
    374 	thisdv.israw = is_raw(path);
    375 
    376 	if (thisdv.lun != -1 && thisdv.part != -1 && thisdv.wwa != NULL) {
    377 		return (add_to_dev_tree(path, &thisdv));
    378 	}
    379 	return (0);
    380 }
    381 char *
    382 full_path(char *link, char *target)
    383 {
    384 	char *tmp_target, *tmp_link;
    385 	if ((link = strdup(link)) == NULL)
    386 		return (NULL);
    387 	/* first remove the link from the path leaving just the directories */
    388 	tmp_link = strrchr(link, '/');
    389 	if (tmp_link != NULL) {
    390 		*tmp_link = NULL;
    391 	}
    392 
    393 	for (tmp_target = target; strncmp("../", tmp_target, 3) == 0;
    394 	    tmp_target += 3) {
    395 		tmp_link = strrchr(link, '/');
    396 		if (tmp_link != NULL) {
    397 			*tmp_link = NULL;
    398 		}
    399 	}
    400 	tmp_link = malloc(strlen(link) + 1 + strlen(tmp_target) + 1);
    401 	if (tmp_link != NULL)
    402 		(void) sprintf(tmp_link, "%s/%s", link, tmp_target);
    403 
    404 	free(link);
    405 	return (tmp_link);
    406 }
    407 struct paths *
    408 findap(const char *inpath, const char *devices)
    409 {
    410 	char link_data[1024];
    411 	char *path, *fullpath = NULL;
    412 	struct paths *pa;
    413 	struct pathstore *entry;
    414 	struct about_dev dv;
    415 	struct pathstore this_ps;
    416 
    417 	path = strdup(inpath);
    418 
    419 	if (path == NULL)
    420 		return (NULL);
    421 
    422 	(void) memset(&link_data[0], NULL, 1024);
    423 
    424 	if (readlink(path, &link_data[0], 1024) == -1) {
    425 
    426 		dv.part = find_part(path);
    427 		if (dv.part == -1) {
    428 			free(path);
    429 			return (NULL);
    430 		}
    431 		dv.wwa = get_wwa(path);
    432 		dv.lun = get_lun(path);
    433 		dv.israw = is_raw(path);
    434 		fullpath = strdup(path);
    435 	} else {
    436 		dv.wwa = get_wwa(&link_data[0]);
    437 		dv.lun = get_lun(&link_data[0]);
    438 		dv.part = find_part(&link_data[0]);
    439 		if (dv.part == -1) {
    440 			free(path);
    441 			return (NULL);
    442 		}
    443 		dv.israw = is_raw(&link_data[0]);
    444 		fullpath = full_path(path, &link_data[0]);
    445 	}
    446 	if (fullpath == NULL) {
    447 		free(path);
    448 		if (dv.wwa != NULL) {
    449 			free(dv.wwa);
    450 		}
    451 		return (NULL);
    452 	}
    453 	if (dv.wwa == NULL) {
    454 		pa = (struct paths *)calloc(1, sizeof (struct paths));
    455 		pa->logicalpath = path;
    456 		if ((pa->op = calloc(1, sizeof (struct other_paths))) == NULL) {
    457 			free(pa);
    458 			pa = NULL;
    459 			free(fullpath);
    460 		} else {
    461 			pa->op->path = fullpath;
    462 		}
    463 		return (pa);
    464 	}
    465 	this_ps.wwa = dv.wwa;
    466 
    467 	if (ndevtree == 0) {
    468 		(void) nftw(devices, ftwfunc, 64, FTW_MOUNT);
    469 		qsort(ps, ndevtree, sizeof (struct pathstore), pscmp);
    470 	}
    471 
    472 	entry = bsearch(&this_ps, (void *)ps, ndevtree,
    473 	    sizeof (struct pathstore), pscmp);
    474 	free(dv.wwa);
    475 	if (entry != NULL) {
    476 		struct other_paths **ep, *prev = NULL;
    477 		struct paths *pa_out;
    478 
    479 		if (*(ep = &entry->luns.parts[dv.lun].devs[
    480 		    dv.part].raw_or_cooked[dv.israw]) == NULL)
    481 			return (NULL);
    482 
    483 		pa = (struct paths *)calloc(1, sizeof (struct paths));
    484 		if (pa != NULL) {
    485 			for (pa->op = *ep; pa->op != NULL &&
    486 			    strcmp(pa->op->path, fullpath);
    487 			    pa->op = pa->op->next) {
    488 				prev = pa->op;
    489 			}
    490 			pa->logicalpath = path;
    491 			if (prev != NULL && pa->op != NULL) {
    492 				prev->next = pa->op->next;
    493 				pa->op->next = *ep;
    494 				*ep = pa->op;
    495 			}
    496 		} else {
    497 			free(path);
    498 		}
    499 		if (pa->op) {
    500 			pa_out = dup_paths(pa);
    501 		} else {
    502 			pa_out = NULL;
    503 		}
    504 		free(pa->logicalpath);
    505 		free(pa);
    506 		free(fullpath);
    507 		return (pa_out);
    508 	}
    509 	free(fullpath);
    510 	free(path);
    511 	return (NULL);
    512 }
    513 static void
    514 free_devstore(struct devstore *dev)
    515 {
    516 	if (dev == NULL)
    517 		return;
    518 	if (dev->raw_or_cooked[0])
    519 		free_otherpaths(dev->raw_or_cooked[0]);
    520 	if (dev->raw_or_cooked[1])
    521 		free_otherpaths(dev->raw_or_cooked[1]);
    522 }
    523 static void
    524 free_partstore(struct partstore *pas)
    525 {
    526 	int i;
    527 
    528 	if (pas == NULL)
    529 		return;
    530 
    531 	for (i = 0; i < pas->nparts; i++)
    532 		free_devstore(&pas->devs[i]);
    533 	if (pas->devs)
    534 		free(pas->devs);
    535 }
    536 static void
    537 free_lunstore(struct lunstore *ls)
    538 {
    539 	int i;
    540 
    541 	if (ls == NULL)
    542 		return;
    543 	for (i = 0; i < ls->nluns; i++)
    544 		free_partstore(&ls->parts[i]);
    545 	if (ls->parts)
    546 		free(ls->parts);
    547 }
    548 void
    549 findap_fini(void)
    550 {
    551 	int i;
    552 
    553 	for (i = 0; i < ndevtree; i++) {
    554 		free_lunstore(&ps[i].luns);
    555 		free(ps[i].wwa);
    556 	}
    557 	if (ps != NULL) {
    558 		free(ps);
    559 		ps = NULL;
    560 	}
    561 #ifdef FIND_AP_STATS
    562 	printf("Hits = %d\nMisses %d\n", hit_count, miss_count);
    563 #endif
    564 	ndevtree = 0;
    565 }
    566