diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/lvm/libsvm/common | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/lvm/libsvm/common')
| -rw-r--r-- | usr/src/lib/lvm/libsvm/common/check_svm.c | 169 | ||||
| -rw-r--r-- | usr/src/lib/lvm/libsvm/common/debug.c | 76 | ||||
| -rw-r--r-- | usr/src/lib/lvm/libsvm/common/getdrvname.c | 90 | ||||
| -rw-r--r-- | usr/src/lib/lvm/libsvm/common/hdrs/libsvm.h | 70 | ||||
| -rw-r--r-- | usr/src/lib/lvm/libsvm/common/hdrs/svm.h | 95 | ||||
| -rw-r--r-- | usr/src/lib/lvm/libsvm/common/metaconf.c | 195 | ||||
| -rw-r--r-- | usr/src/lib/lvm/libsvm/common/metainterfaces.c | 490 | ||||
| -rw-r--r-- | usr/src/lib/lvm/libsvm/common/modops.c | 120 | ||||
| -rw-r--r-- | usr/src/lib/lvm/libsvm/common/start_svm.c | 284 | ||||
| -rw-r--r-- | usr/src/lib/lvm/libsvm/common/update_mdconf.c | 379 |
10 files changed, 1968 insertions, 0 deletions
diff --git a/usr/src/lib/lvm/libsvm/common/check_svm.c b/usr/src/lib/lvm/libsvm/common/check_svm.c new file mode 100644 index 0000000000..5c92ac2788 --- /dev/null +++ b/usr/src/lib/lvm/libsvm/common/check_svm.c @@ -0,0 +1,169 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <meta.h> +#include <sys/types.h> +#include <sys/mkdev.h> +#include <sys/stat.h> +#include <limits.h> +#include <svm.h> + +/* + * FUNCTION: valid_bootlist + * + * INPUT: file pointer, line buffer, line_length + * + * RETURN VALUES: + * 0 - SUCCESS + * -1 - FAIL + * + */ + +int +valid_bootlist(FILE *fp, int line_len) +{ + char *bp = NULL; + char *line; + + /* + * errno may not be cleared by callee routines and we + * we want to catch fgets failures hence errno is reset. + */ + errno = 0; + if ((line = malloc(line_len)) == NULL) + return (RET_ERROR); + + while (fgets(line, line_len, fp) != NULL) { + bp = strstr(line, "mddb_bootlist"); + if (bp != NULL) { + /* if not commented out then breakout */ + if (*line != '*' && *line != '#') { + break; + } + } + } + + free(line); + if (bp == NULL || errno != 0) + return (RET_ERROR); + + return (RET_SUCCESS); +} + +/* + * FUNCTION: svm_check + * Check the existance of DiskSuite or SVM + * + * INPUT: rootpath + * + * RETURN VALUES: + * 0 - SUCCESS + * -1 - FAIL + */ + +int +svm_check(char *path) +{ + FILE *fp; + char tmppath[PATH_MAX]; + int rval; + + (void) strcat(strcpy(tmppath, path), MD_CONF); + + if ((fp = fopen(tmppath, "r")) == NULL) { + rval = errno; + goto free_exit; + } + + rval = valid_bootlist(fp, MDDB_BOOTLIST_MAX_LEN); + + debug_printf("svm_check(): valid bootlist in %s. status %d\n", + tmppath, rval); + + if (rval == RET_SUCCESS) { + goto free_exit; + } + (void) fclose(fp); + + /* not found in md.conf try etc/system */ + (void) strcat(strcpy(tmppath, path), SYSTEM_FILE); + + if ((fp = fopen(tmppath, "r")) == NULL) { + rval = errno; + goto free_exit; + } + + rval = valid_bootlist(fp, MDDB_BOOTLIST_MAX_LEN); + + debug_printf("svm_check(): valid bootlist in %s. status %d\n", + tmppath, rval); +free_exit: + (void) fclose(fp); + if (rval > 0) + rval = RET_ERROR; + return (rval); +} + +/* + * FUNCTION: svm_is_md + * Check if the the given device name has an md driver. + * INPUT: special device name (/dev/dsk/c0t0d0s0 or /dev/md/dsk/d10) + * + * RETURN: + * 1 - if it is a metadevice. + * 0 - if it is not a metadevice. + */ + +int +svm_is_md(char *device_name) +{ + char buf[30]; + struct stat sbuf; + int rval = 0; + + (void) memset(buf, 0, 30); + + debug_printf("svm_is_md(): device %s\n", device_name); + if (stat(device_name, &sbuf) != 0) + return (RET_ERROR); + + if (get_drv_name(major(sbuf.st_rdev), "/", buf) == RET_ERROR) { + debug_printf("svm_is_md(): device get_drv_name failed: %s\n", + device_name); + return (0); + } + if (strcmp(buf, MD_MODULE) == 0) { + debug_printf("svm_is_md(): device %s succeed\n", device_name); + rval = 1; + } + return (rval); +} diff --git a/usr/src/lib/lvm/libsvm/common/debug.c b/usr/src/lib/lvm/libsvm/common/debug.c new file mode 100644 index 0000000000..38f7ae56cc --- /dev/null +++ b/usr/src/lib/lvm/libsvm/common/debug.c @@ -0,0 +1,76 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> + +/* The following defines are for tracing output (from libsmpicommon) */ + +#define LOG 0x1 /* write message to log file */ +#define SCR 0x2 /* write message to the screen */ +#define LOGSCR LOG|SCR /* write message to the log and screen */ +#define LEVEL0 0x0001 /* message level 0 */ +#define LEVEL1 0x0002 /* message level 1 */ +#define LEVEL2 0x0004 /* message level 2 */ +#define LEVEL3 0x0010 /* message level 3 */ + +extern int get_trace_level(void); +extern int write_status(unsigned char, unsigned int, char *, ...); + +const char libsvm_str[] = "LIB_SVM: "; +const int libsvm_len = sizeof (libsvm_str); + +/*PRINTFLIKE1*/ +void +debug_printf(char *fmt, ...) +{ + va_list ap; + char *cp; + char *buf; + + if (get_trace_level() > 5) { + if ((buf = calloc(PATH_MAX, sizeof (char))) == NULL) + return; + (void) strcpy(buf, libsvm_str); + /* + * libsvm_len - 1 is because the length includes NULL + */ + + cp = buf + (libsvm_len - 1); + va_start(ap, fmt); + if (vsnprintf(cp, (PATH_MAX - (libsvm_len - 1)), + fmt, ap) >= 0) { + write_status(LOGSCR, LEVEL0, buf); + } + free(buf); + va_end(ap); + } +} diff --git a/usr/src/lib/lvm/libsvm/common/getdrvname.c b/usr/src/lib/lvm/libsvm/common/getdrvname.c new file mode 100644 index 0000000000..9bef7fa115 --- /dev/null +++ b/usr/src/lib/lvm/libsvm/common/getdrvname.c @@ -0,0 +1,90 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <svm.h> + +/* + * Macros to produce a quoted string containing the value of a + * preprocessor macro. For example, if SIZE is defined to be 256, + * VAL2STR(SIZE) is "256". This is used to construct format + * strings for scanf-family functions below. + */ +#define QUOTE(x) #x +#define VAL2STR(x) QUOTE(x) + +/* + * FUNCTION: + * Return the driver name for a major number + * + * INPUT: major number, mount point for name_to_major file, pointer + * to a valid buffer. + * + * RETURN VALUES: + * 0 - SUCCESS - buf contain the driver name. + * -1 - FAIL + * + */ + +int +get_drv_name(major_t major, char *mnt, char *buf) +{ + FILE *fp; + char drv[FILENAME_MAX + 1]; + char entry[FILENAME_MAX + 1]; + char line[MAX_N2M_ALIAS_LINE]; + char fname[PATH_MAX]; + + int status = RET_NOERROR; + (void) snprintf(fname, sizeof (fname), "%s%s", mnt, NAME_TO_MAJOR); + + if ((fp = fopen(fname, "r")) == NULL) { + return (RET_ERROR); + } + + while ((fgets(line, sizeof (line), fp) != NULL) && + status == RET_NOERROR) { + if (sscanf(line, + "%" VAL2STR(FILENAME_MAX) "s %" VAL2STR(FILENAME_MAX) "s", + drv, entry) != 2) { + status = RET_ERROR; + } + if (atoi(entry) == major) + break; + + } + + if (status == RET_NOERROR) + (void) strcpy(buf, drv); + (void) fclose(fp); + return (status); +} diff --git a/usr/src/lib/lvm/libsvm/common/hdrs/libsvm.h b/usr/src/lib/lvm/libsvm/common/hdrs/libsvm.h new file mode 100644 index 0000000000..98c13a2684 --- /dev/null +++ b/usr/src/lib/lvm/libsvm/common/hdrs/libsvm.h @@ -0,0 +1,70 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _LIBSVM_H +#define _LIBSVM_H + +#pragma ident "%Z%%M% %I% %E% SMI" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * The following declarations are for libsvm which provides + * Solaris Install with a set of interfaces required to upgrade + * mirrored roots. These are controlled by a Contract PSARC 2000/049 + * and should not be changed without informing Install. + */ + +typedef struct { + char *root_md; /* metaroot device name */ + int count; /* number of components in the metadevice */ + char *md_comps[1]; /* array of "ctds" component names */ +} svm_info_t; + +/* Convertion of MDDB flags */ +#define SVM_DONT_CONV 0x01 /* Don't convert MDDB to devid mode */ +#define SVM_CONV 0x02 /* Convert MDDB to devid mode */ + + +extern int svm_check(char *rootpath); +extern int svm_start(char *rootpath, svm_info_t **svm_infopp, + int repl_state_flag); +extern int svm_stop(); +extern void svm_free(svm_info_t *svm_infop); +extern int svm_is_md(char *device_name); +extern int svm_get_components(char *root_md_device, svm_info_t **svmpp); +extern svm_info_t *svm_alloc(); +extern int get_mdcomponents(char *devname, svm_info_t **pp); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBSVM_H */ diff --git a/usr/src/lib/lvm/libsvm/common/hdrs/svm.h b/usr/src/lib/lvm/libsvm/common/hdrs/svm.h new file mode 100644 index 0000000000..cb5d60f30f --- /dev/null +++ b/usr/src/lib/lvm/libsvm/common/hdrs/svm.h @@ -0,0 +1,95 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +#ifndef _SVM_H +#define _SVM_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define RET_SUCCESS 0 +#define RET_ERROR -1 +#define RET_NOERROR RET_SUCCESS + + +#define PROP_KEEP_REPL_STATE "md_keep_repl_state" +#define PROP_DEVID_DESTROY "md_devid_destroy" + +#define MD_CONF "/kernel/drv/md.conf" +#define MD_CONF_ORIG "/tmp/md.conf.orig" +#define SYSTEM_FILE "/etc/system" +#define NAME_TO_MAJOR "/etc/name_to_major" +#define VFSTAB "/etc/vfstab" + +#define MD_MODULE "md" +#define ROOT_MNTPT "/" +#define ROOT_METADEVICE "/dev/md/dsk/" + + +typedef enum { + MD_STR_NOTFOUND, /* bootlist not found */ + MD_STR_START, /* bootlist found, convertion started */ + MD_STR_DONE /* bootlist converversion done */ +} convflag_t; + +/* The following defines have been taken from addrem.h */ +#define MAX_CMD_LINE 256 +#define MAX_N2M_ALIAS_LINE FILENAME_MAX + FILENAME_MAX + 1 +#define MAXLEN_NAM_TO_MAJ_ENT FILENAME_MAX + MAX_STR_MAJOR + 1 +#define OPT_LEN 128 +#define CADDR_HEX_STR 16 +#define UINT_STR 10 +#define MODLINE_ENT_MAX (4 * UINT_STR) + CADDR_HEX_STR + MODMAXNAMELEN +#define MAX_STR_MAJOR UINT_STR +#define STR_LONG 10 +#define PERM_STR 4 +#define MAX_PERM_ENTRY (2 * STR_LONG) + PERM_STR + (2 * FILENAME_MAX) + 1 +#define MAX_DBFILE_ENTRY MAX_PERM_ENTRY + +extern void create_diskset_links(); +extern int copyfile(char *from, char *to); +extern int get_drv_name(major_t major, char *file_name, char *buf); +extern int mod_unload(char *modname); +extern int valid_bootlist(FILE *fp, int line_size); +extern int convert_bootlist(char *systemfile, char *mdconf, char **tmpfilename); +extern int write_xlate_to_mdconf(char *rootpath); +extern int write_targ_nm_table(char *rootpath); +extern int get_rootmetadevice(char *rootpath, char **devname); +extern void set_upgrade_prop(char *prop_name, int val); +extern int is_upgrade_prop(char *prop_name); +extern int create_in_file_prop(char *prop_name, char *fname); +extern void debug_printf(char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* _SVM_H */ diff --git a/usr/src/lib/lvm/libsvm/common/metaconf.c b/usr/src/lib/lvm/libsvm/common/metaconf.c new file mode 100644 index 0000000000..504f38ba73 --- /dev/null +++ b/usr/src/lib/lvm/libsvm/common/metaconf.c @@ -0,0 +1,195 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/mkdev.h> +#include <sys/stat.h> +#include <unistd.h> +#include <dirent.h> +#include <limits.h> +#include <string.h> +#include <libsvm.h> +#include <svm.h> +#include <errno.h> + + +#define VERSION "1.0" +#define DISK_DIR "/dev/rdsk" + +extern int _map_to_effective_dev(); + +int +is_blankline(char *buf) +{ + for (; *buf != 0; buf++) { + if (!isspace(*buf)) + return (0); + } + return (1); +} + +/* + * FUNCTION: write_targ_nm_table + * creates a tuple table of <driver name, major number > in md.conf + * INPUT: rootpath + * + * RETURN VALUES: + * RET_SUCCESS + * RET_ERROR + */ + +int +write_targ_nm_table(char *path) +{ + FILE *targfp = NULL; + FILE *mdfp = NULL; + char buf[PATH_MAX], *cp; + int retval = RET_SUCCESS; + int first_entry = 1; + + if ((mdfp = fopen(MD_CONF, "a")) == NULL) + return (RET_ERROR); + + (void) snprintf(buf, sizeof (buf), "%s%s", path, NAME_TO_MAJOR); + + if ((targfp = fopen(buf, "r")) == NULL) { + (void) fclose(mdfp); + return (RET_ERROR); + } + + while (fgets(buf, PATH_MAX, targfp) != NULL && + (retval == RET_SUCCESS)) { + cp = strrchr(buf, '\n'); + *cp = 0; + if (is_blankline(buf)) + continue; + if (first_entry) { + if (fprintf(mdfp, "md_targ_nm_table=\"%s\"", buf) < 0) + retval = RET_ERROR; + first_entry = 0; + } + if (fprintf(mdfp, ",\"%s\"", buf) < 0) + retval = RET_ERROR; + } + if (!first_entry) + if (fprintf(mdfp, ";\n") < 0) + retval = RET_ERROR; + (void) fclose(mdfp); + (void) fclose(targfp); + return (retval); +} + +/* + * FUNCTION: write_xlate_to_mdconf + * creates a tuple table of <miniroot devt, target devt> in md.conf + * INPUT: rootpath + * + * RETURN VALUES: + * RET_SUCCESS + * RET_ERROR + */ + +int +write_xlate_to_mdconf(char *path) +{ + FILE *fptr = NULL; + struct dirent *dp; + DIR *dirp; + struct stat statb_dev; + struct stat statb_edev; + char *devname; + char edevname[PATH_MAX]; + char targname[PATH_MAX]; + char diskdir[PATH_MAX]; + int first_devid = 1; + int ret = RET_SUCCESS; + + if ((fptr = fopen(MD_CONF, "a")) == NULL) { + return (RET_ERROR); + } + + + (void) snprintf(diskdir, sizeof (diskdir), "%s%s", path, DISK_DIR); + if ((dirp = opendir(diskdir)) == NULL) { + (void) fclose(fptr); + return (RET_ERROR); + } + + /* special case to write the first tuple in the table */ + while (((dp = readdir(dirp)) != (struct dirent *)0) && + (ret != RET_ERROR)) { + if ((strcmp(dp->d_name, ".") == 0) || + (strcmp(dp->d_name, "..") == 0)) + continue; + + if ((strlen(diskdir) + strlen(dp->d_name) + 2) > PATH_MAX) { + continue; + } + + (void) snprintf(targname, sizeof (targname), "%s/%s", + diskdir, dp->d_name); + + if (stat(targname, &statb_dev) != 0) { + continue; + } + + if ((devname = strstr(targname, DISK_DIR)) == NULL) { + continue; + } + + if (_map_to_effective_dev((char *)devname, (char *)&edevname) + != 0) { + continue; + } + + if (stat(edevname, &statb_edev) != 0) { + continue; + } + + if (first_devid) { + if (fprintf(fptr, "md_xlate_ver=\"%s\";\n" + "md_xlate=%lu,%lu", VERSION, + statb_edev.st_rdev, statb_dev.st_rdev) < 0) + ret = RET_ERROR; + first_devid = 0; + } + if (fprintf(fptr, ",%lu,%lu", statb_edev.st_rdev, + statb_dev.st_rdev) < 0) + ret = RET_ERROR; + } /* end while */ + + if (!first_devid) + if (fprintf(fptr, ";\n") < 0) + ret = RET_ERROR; + (void) fclose(fptr); + (void) closedir(dirp); + return (ret); +} diff --git a/usr/src/lib/lvm/libsvm/common/metainterfaces.c b/usr/src/lib/lvm/libsvm/common/metainterfaces.c new file mode 100644 index 0000000000..20746d4b58 --- /dev/null +++ b/usr/src/lib/lvm/libsvm/common/metainterfaces.c @@ -0,0 +1,490 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <string.h> +#include <sys/vfstab.h> +#include <meta.h> +#include <libsvm.h> +#include <svm.h> +#include <sdssc.h> + + +extern int mod_unload(char *modname); +static int inited = 0; + +/* + * FUNCTION: init_metalib + * initialize libmeta only once. + * + * RETURN VALUES: + * 0 - SUCCESS + * -1 - FAIL + */ + +static int +init_metalib() +{ + int largc = 1; + char *largv = "libsvm"; + md_error_t status = mdnullerror; + + if (!inited) { + if (md_init_nosig(largc, &largv, 0, 1, &status) != 0 || + meta_check_root(&status) != 0) { + return (-1); + } + inited = 1; + } + return (RET_SUCCESS); +} + +/* + * FUNCTION: reset_metalib + * + * INPUT: ptr to md_error_t + */ + +static void +reset_metalib(md_error_t *ep) +{ + inited = 0; + (void) close_admin(ep); +} + +/* + * FUNCTION: metahalt + * halt the metadb + * + */ + +static void +metahalt() +{ + mdsetname_t *sp; + md_error_t status = mdnullerror; + + (void) init_metalib(); + if ((sp = metasetname(MD_LOCAL_NAME, &status)) == NULL) { + return; + } + if (meta_lock(sp, TRUE, &status)) { + return; + } + if (metaioctl(MD_HALT, NULL, &status, NULL) != 0) { + debug_printf("metahalt(): errno %d\n", + status.info.md_error_info_t_u.sys_error.errnum); + } + (void) meta_unlock(sp, &status); + reset_metalib(&status); +} + +/* + * FUNCTION: svm_stop + * Halt the SDS/SVM configuration and unload md module. + * + * RETURN VALUES: + * 0 - SUCCESS + * RET_ERROR + */ + +#define MAX_TIMEOUT 1800 +int +svm_stop() +{ + int rval = RET_SUCCESS; + int timeval = 0; + int sleep_int = 5; + + metahalt(); + + if ((rval = mod_unload(MD_MODULE)) != 0) { + timeval += sleep_int; + (void) sleep(sleep_int); + while (timeval < MAX_TIMEOUT) { + if ((rval = mod_unload(MD_MODULE)) == 0) { + debug_printf("svm_stop(): mod_unload succeeded." + " Time %d\n", timeval); + + break; + } + + debug_printf("svm_stop(): mod_unload failed. Trying " + "in %d s (%d)\n", sleep_int, timeval); + + timeval += sleep_int; + (void) sleep(sleep_int); + metahalt(); + } + + if (rval != 0) { + rval = RET_ERROR; + debug_printf("svm_stop(): mod_unload FAILED!\n"); + } + } + + return (rval); +} + +/* + * FUNCTION: get_rootmetadevice + * parses the vfstab to return the metadevice + * + * INPUT: + * mount point + * mdname - pointer to string pointer that will contain the + * metadevice name. Caller must free the allocated space. + * RETURN VALUES: + * mdname - md root device name + * 0 - SUCCESS + * !0 - FAIL + * > 0 errno + * RET_ERROR + */ + +int +get_rootmetadevice(char *mntpath, char **mdname) +{ + struct vfstab v; + FILE *fp; + int rval = RET_SUCCESS; + char *cp; + char vfstab_name[PATH_MAX + 1]; + + if (mdname == NULL) + return (EINVAL); + + *mdname = NULL; + + if (snprintf(vfstab_name, PATH_MAX + 1, "%s%s", mntpath, VFSTAB) < 0) + return (ENOMEM); + + debug_printf("get_rootmetadevice(): mntpath %s %s\n", mntpath, + vfstab_name); + + if ((fp = fopen(vfstab_name, "r")) == NULL) { + rval = errno; + return (rval); + } + + if ((rval = getvfsfile(fp, &v, ROOT_MNTPT)) != 0) { + goto out; + } + + + debug_printf("get_rootmetadevice(): vfs_special %s\n", v.vfs_special); + if (strstr(v.vfs_special, ROOT_METADEVICE) == NULL) { + /* md device not found */ + rval = RET_ERROR; + goto out; + } + + /* found a match fill it and return */ + cp = v.vfs_special + strlen(ROOT_METADEVICE); + + *mdname = (char *)malloc(strlen(cp) + 1); + + if (*mdname == NULL) { + rval = ENOMEM; + goto out; + } + (void) strcpy(*mdname, cp); + debug_printf("get_rootmetadevice(): *mdname %s rval %d\n", + *mdname, rval); +out: + (void) fclose(fp); + return (rval); +} + +/* + * FUNCTION: create_diskset_links + * Create the diskset name symlinks in /dev/md from the diskset + * names found in the set records. These are normally created + * in rpc.metad when you create the set but those symlinks are + * sitting out on the real system disk and we're running off the + * devfs that got created when we booted off the install image. + */ + +void +create_diskset_links() +{ + int max_sets; + int i; + md_error_t error = mdnullerror; + + /* + * Resolve the function pointers for libsds_sc so that we can + * snarf the set records. + */ + (void) sdssc_bind_library(); + (void) init_metalib(); + + if ((max_sets = get_max_sets(&error)) == 0) { + debug_printf("create_diskset_links(): get_max_sets failed\n"); + mdclrerror(&error); + return; + } + + for (i = 1; i < max_sets; i++) { + md_set_record *sr; + char setname[MAXPATHLEN]; + char setnum[MAXPATHLEN]; + + if ((sr = metad_getsetbynum(i, &error)) == NULL) { + mdclrerror(&error); + continue; + } + + (void) snprintf(setname, MAXPATHLEN, "/dev/md/%s", + sr->sr_setname); + (void) snprintf(setnum, MAXPATHLEN, "shared/%d", i); + /* + * Ignore failures to create the symlink. This could + * happen because suninstall is restartable so the + * symlink might have already been created. + */ + (void) symlink(setnum, setname); + } +} + +/* + * FUNCTION: svm_alloc + * Return a pointer to an opaque piece of zeroed memory. + * + * RETURN VALUES: + * Non null - SUCCESS + * NULL - FAIL + */ + +svm_info_t * +svm_alloc() +{ + return ((svm_info_t *)calloc(1, sizeof (svm_info_t))); +} + +/* + * FUNCTION: svm_free + * + * INPUT: pointer to struct svm_info + */ + +void +svm_free(svm_info_t *svmp) +{ + int i; + + if (svmp == NULL) + return; + + for (i = 0; i < svmp->count; i++) { + free(svmp->md_comps[i]); + } + free(svmp->root_md); + free(svmp); +} + +/* + * FUNCTION: get_mdcomponents + * Given "uname" metadevice, return the physical components + * of that metadevice. + * + * INPUT: + * uname - metadevice name + * + * RETURN VALUES: + * svmp - structure containing md name and components + * RET_SUCCESS + * RET_ERROR + * + */ + +int +get_mdcomponents(char *uname, svm_info_t **svmpp) +{ + + svm_info_t *svmp; + md_error_t status, *ep; + mdname_t *namep; + mdnamelist_t *nlp = NULL; + mdnamelist_t *p; + mdsetname_t *sp = NULL; + char *strp = NULL; + int rval, cnt; + + rval = RET_SUCCESS; + cnt = 0; + status = mdnullerror; + ep = &status; + svmp = *svmpp; + + (void) init_metalib(); + + debug_printf("get_mdcomponents(): Enter unit name %s\n", uname); + + if (((namep = metaname(&sp, uname, ep)) == NULL) || + (metachkmeta(namep, ep) != 0)) { + debug_printf("get_mdcomponents(): " + "metaname or metachkmeta failed\n"); + mdclrerror(ep); + return (RET_ERROR); + } + + debug_printf("get_mdcomponents(): meta_getdevs %s\n", namep->cname); + + if ((meta_getdevs(sp, namep, &nlp, ep)) < 0) { + debug_printf("get_mdcomponents(): " + "comp %s - meta_getdevs failed\n", uname); + metafreenamelist(nlp); + mdclrerror(ep); + return (RET_ERROR); + } + + /* compute the number of devices */ + + for (p = nlp, cnt = 0; p != NULL; p = p->next, cnt++) + ; + + /* + * Need to add n -1 components since slvmp already has space + * for one device. + */ + + svmp = (svm_info_t *)realloc(svmp, sizeof (svm_info_t) + + (sizeof (char *) * (cnt - 1))); + + if (svmp == NULL) { + debug_printf("get_mdcomponents(): realloc of svmp failed\n"); + metafreenamelist(nlp); + return (RET_ERROR); + } + + + for (p = nlp, cnt = 0; p != NULL; p = p->next, cnt++) { + mdname_t *devnp = p->namep; + + if ((strp = strdup(devnp->cname)) == NULL) { + rval = RET_ERROR; + break; + } + svmp->md_comps[cnt] = strp; + } + + /* count is set to the number of devices in the list */ + + svmp->count = cnt; + svmp->root_md = strdup(uname); + if (rval == RET_SUCCESS && svmp->root_md != NULL) { + debug_printf("get_mdcomponents(): root_md %s count %d \n", + svmp->root_md, svmp->count); + for (cnt = 0; cnt < svmp->count; cnt++) + debug_printf("get_mdcomponents(): %s\n", + svmp->md_comps[cnt]); + } else { + rval = RET_ERROR; + svm_free(svmp); + svmp = NULL; + debug_printf("get_mdcomponents(): malloc failed\n"); + + } + + + metafreenamelist(nlp); + *svmpp = svmp; + return (rval); +} + + +/* + * FUNCTION: svm_get_components + * return svm_infop with the components of a metadevice. + * + * INPUT: + * md_device - eg. /dev/md/dsk/d10, /dev/md/foo/dsk/d10, or + * /dev/md/shared/1/dsk/d10 + * + * RETURN: + * 0 - SUCCESS + * !0 - FAIL + */ + +int +svm_get_components(char *md_device, svm_info_t **svmpp) +{ + int len; + + /* + * If this is a named diskset with a shared name + * (e.g. /dev/md/shared/1/dsk/d10) call get_mdcomponents with + * the diskset and metadevice name (e.g. foo/d10). + * Otherwise this is a regular name (e.g. /dev/md/dsk/d10 or + * /dev/md/foo/dsk/d10 or d10 or foo/d10) all of which + * get_mdcomponents can handle directly. + */ + + len = strlen("/dev/md/shared/"); + if (strncmp(md_device, "/dev/md/shared/", len) == 0) { + int numlen; + int setnum; + char *cp; + char *slashp; + char mdname[MAXPATHLEN]; + mdsetname_t *sp; + md_error_t error = mdnullerror; + + cp = md_device + len; + + if ((slashp = strstr(cp, "/")) == NULL) + return (RET_ERROR); + numlen = slashp - cp; + if (numlen >= MAXPATHLEN - 1) + return (RET_ERROR); + + (void) strlcpy(mdname, cp, numlen + 1); + /* setnum now contains the diskset number */ + setnum = atoi(mdname); + if ((sp = metasetnosetname(setnum, &error)) == NULL || + !mdisok(&error)) + return (RET_ERROR); + + cp = slashp + 1; + /* cp now pointing at dsk/... */ + if ((slashp = strstr(cp, "/")) == NULL) + return (RET_ERROR); + + (void) snprintf(mdname, MAXPATHLEN, "%s/%s", sp->setname, + slashp + 1); + /* mdname now contains diskset and metadevice name e.g. foo/d10 */ + + debug_printf("svm_get_components(): mdname %s\n", mdname); + return (get_mdcomponents(mdname, svmpp)); + + } else { + debug_printf("svm_get_components(): md_device %s\n", md_device); + return (get_mdcomponents(md_device, svmpp)); + } +} diff --git a/usr/src/lib/lvm/libsvm/common/modops.c b/usr/src/lib/lvm/libsvm/common/modops.c new file mode 100644 index 0000000000..78914a9069 --- /dev/null +++ b/usr/src/lib/lvm/libsvm/common/modops.c @@ -0,0 +1,120 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/errno.h> +#include <sys/modctl.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <svm.h> + +/* + * FUNCTION: get modid + * Given a module name returns module id. + * + * INPUT: module name + * + * RETURN VALUES: + * > 0 SUCCESS + * -1 FAIL + */ + +static int +get_modid(char *modname) +{ + struct modinfo modinfo; + int id; + int rval = RET_ERROR; + + id = -1; /* look for all modules */ + + modinfo.mi_id = modinfo.mi_nextid = id; + modinfo.mi_info = MI_INFO_ALL | MI_INFO_NOBASE; + + do { + if (modctl(MODINFO, id, &modinfo) < 0) + break; + + modinfo.mi_name[MODMAXNAMELEN - 1] = '\0'; + /* if we find a match break out */ + if (strcmp(modinfo.mi_name, modname) == 0) { + rval = modinfo.mi_id; + break; + } + /* LINTED */ + } while (1); + + return (rval); +} + +/* + * FUNCTION: mod_unload + * unload a module. + * + * INPUT: module name + * + * RETURN VALUES: + * 0 - SUCCESS + * !0 - FAIL + * > 0 errno + * -1 + * NOTE: If we fail to get the module id because the module is not + * currently loaded we still want to try to force a reload of the + * .conf file when it does load. + */ +int +mod_unload(char *modname) +{ + int id; + major_t major; + int rval = RET_SUCCESS; + + id = get_modid(modname); + + if (id != -1) { + if (modctl(MODUNLOAD, id) < 0) { + rval = errno; + } + } + + if ((modctl(MODGETMAJBIND, modname, strlen(modname) + 1, + &major)) != 0) { + return (errno); + } + + if ((modctl(MODUNLOADDRVCONF, major) != 0) || + (modctl(MODLOADDRVCONF, major) != 0)) { + return (errno); + } + + return (rval); +} diff --git a/usr/src/lib/lvm/libsvm/common/start_svm.c b/usr/src/lib/lvm/libsvm/common/start_svm.c new file mode 100644 index 0000000000..f423d4f418 --- /dev/null +++ b/usr/src/lib/lvm/libsvm/common/start_svm.c @@ -0,0 +1,284 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <ctype.h> +#include <malloc.h> +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <limits.h> +#include <meta.h> +#include <svm.h> +#include <libsvm.h> + +#define MODEBITS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) +#define ISREG(A) (((A).st_mode & S_IFMT) == S_IFREG) +#define DEFAULT_ROOTDIR "/a" + + +/* + * FUNCTION: svm_start + * starts SDS/SVM configuration. If root mirroring exists then the + * components of the root mirror are returned in svmpp. + * + * INPUT: mntpnt - root mount point + * svmpp - prealloced structure to return components + * repl_state_flag - SVM_CONV/SVM_DONT_CONV + * + * RETURN: + * 0 - SUCCESS + * !0 - ERROR + * if > 0 errno + */ + +int +svm_start(char *mntpnt, svm_info_t **svmpp, int repl_state_flag) +{ + char *rootdir, *tf; + char *mdevnamep = NULL; + char system_file[PATH_MAX]; + char mdconf[PATH_MAX]; + int rval = 0; + + if (mntpnt == NULL) + rootdir = DEFAULT_ROOTDIR; + else + rootdir = mntpnt; + + if ((rval = snprintf(system_file, PATH_MAX, "%s%s", + rootdir, SYSTEM_FILE)) < 0) { + return (RET_ERROR); + } + + if ((rval = snprintf(mdconf, PATH_MAX, "%s%s", + rootdir, MD_CONF)) < 0) { + return (RET_ERROR); + } + + debug_printf("svm_start(): repl_state_flag %s\n", + (repl_state_flag == SVM_DONT_CONV) ? "SVM_DONT_CONV": + "SVM_CONV"); + + if (copyfile(MD_CONF, MD_CONF_ORIG)) + return (RET_ERROR); + + switch (rval = convert_bootlist(system_file, mdconf, &tf)) { + case 0: + case -1: /* found in etc/system flag */ + break; + default: /* convert bootlist failed */ + debug_printf("svm_start(): convert_bootlist failed." + "rval %d\n", rval); + goto errout; + } + + if (repl_state_flag == SVM_DONT_CONV) { + rval = create_in_file_prop(PROP_KEEP_REPL_STATE, tf); + if (rval != 0) + goto errout; + } + + if (is_upgrade_prop(PROP_DEVID_DESTROY)) { + rval = create_in_file_prop(PROP_DEVID_DESTROY, tf); + /* + * For the idempotent behavior reset internal + * flag incase we have to return due to errors + */ + set_upgrade_prop(PROP_DEVID_DESTROY, 0); + if (rval != 0) + goto errout; + } + + + /* + * Since svm_start is called only after svm_check, + * we can assume that there is a valid metadb. If the mddb_bootlist + * is not found in etc/system, then it must be in md.conf which + * we copied to temporary file pointed to by tf + */ + if (copyfile(tf, MD_CONF)) { + debug_printf("svm_start(): copy of %s to %s failed\n", tf, + MD_CONF); + goto errout; + } + + if ((rval = write_xlate_to_mdconf(rootdir)) != 0) { + debug_printf("svm_start(): write_xlate_to_mdconf(%s) failed\n", + rootdir); + goto errout; + } + + if ((rval = write_targ_nm_table(rootdir)) != 0) { + goto errout; + } + + /* run devfsadm to create the devices specified in md.conf */ + if ((rval = system("/usr/sbin/devfsadm -r /tmp -p " + "/tmp/root/etc/path_to_inst -i md")) != 0) { + debug_printf("svm_start(): devfsadm -i md failed: %d\n", rval); + goto errout; + } + + /* + * We have to unload md after the devfsadm run so that when metainit + * loads things it gets the right information from md.conf. + */ + if (rval = svm_stop()) { + debug_printf("svm_start(): svm_stop failed.\n"); + return (RET_ERROR); + } + + if ((rval = system("/usr/sbin/metainit -r")) != 0) { + debug_printf("svm_start(): metainit -r failed: %d\n", rval); + goto errout; + } + + create_diskset_links(); + + if ((rval = system("/usr/sbin/metasync -r")) != 0) { + debug_printf("svm_start(): metasync -r failed: %d\n", rval); + goto errout; + } + + /* + * We ignore failures from metadevadm, since it can fail if + * miniroot dev_t's don't match target dev_ts. But it still + * will update md.conf with device Id information which is + * why we are calling it here. + */ + + (void) system("/usr/sbin/metadevadm -r"); + + /* + * check to see if we have a root metadevice and if so + * get its components. + */ + + if ((rval = get_rootmetadevice(rootdir, &mdevnamep)) == 0) { + if (rval = get_mdcomponents(mdevnamep, svmpp)) { + debug_printf("svm_start(): get_mdcomponents(%s,..)" + "failed %d\n", mdevnamep, rval); + goto errout; + } + + } else { + rval = 0; /* not a mirrored root */ + debug_printf("svm_start(): get_rootmetadevice(%s,..) " + "No root mirrors! ", rootdir); + } +errout: + free(mdevnamep); + if (rval != 0) { + struct stat sbuf; + if (stat(MD_CONF_ORIG, &sbuf) == 0) + (void) copyfile(MD_CONF_ORIG, MD_CONF); + debug_printf("svm_start(): svm_start failed: %d\n", rval); + } else { + int i; + + if ((*svmpp)->count > 0) { + debug_printf("svmpp: "); + debug_printf(" root_md: %s", (*svmpp)->root_md); + debug_printf(" count: %d", (*svmpp)->count); + for (i = 0; i < (*svmpp)->count; i++) { + debug_printf(" md_comps[%d]: %s", i, + (*svmpp)->md_comps[i]); + } + debug_printf(" \n"); + } else { + if ((*svmpp)->count == 0) + debug_printf("svm_start(): no mirrored root\n"); + } + debug_printf("svm_start(): svm_start succeeded.\n"); + } + return (rval); +} + +/* + * FUNCTION: copyfile + * + * INPUT: self descriptive + * + * RETURN: + * RET_SUCCESS + * RET_ERROR + */ +int +copyfile(char *from, char *to) +{ + int fromfd, tofd; + char buf[1024]; + ssize_t rbytes; + struct stat fromstat; + + if ((fromfd = open(from, O_RDONLY | O_NDELAY)) < 0) + return (RET_ERROR); + + if ((fstat(fromfd, &fromstat) < 0) || ! ISREG(fromstat)) { + (void) close(fromfd); + return (RET_ERROR); + } + + if ((tofd = open(to, O_CREAT | O_WRONLY | O_TRUNC, + (fromstat.st_mode & MODEBITS))) < 0) { + (void) close(fromfd); + return (RET_ERROR); + } + + /* + * in case the file exists then perm is forced by this chmod + */ + (void) fchmod(tofd, fromstat.st_mode & MODEBITS); + + for (;;) { + rbytes = read(fromfd, buf, sizeof (buf)); + /* + * no need to check for negative values since the file + * has been successfully stat'ed + */ + if (rbytes == 0) + break; + if (write(tofd, buf, rbytes) != rbytes) { + rbytes = -1; + break; + } + } + + (void) close(fromfd); + (void) close(tofd); + if (rbytes < 0) { + (void) unlink(to); + return (RET_ERROR); + } + return (RET_SUCCESS); +} diff --git a/usr/src/lib/lvm/libsvm/common/update_mdconf.c b/usr/src/lib/lvm/libsvm/common/update_mdconf.c new file mode 100644 index 0000000000..f757648911 --- /dev/null +++ b/usr/src/lib/lvm/libsvm/common/update_mdconf.c @@ -0,0 +1,379 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <devid.h> +#include <errno.h> +#include <string.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <meta.h> +#include <libsvm.h> +#include <svm.h> + +/* + * magic strings in system + */ +#define BEGMDDBSTR "* Begin MDD database info (do not edit)\n" +#define ENDMDDBSTR "* End MDD database info (do not edit)\n" +#define NEW_BEGMDDBSTR "# Begin MDD database info (do not edit)\n" +#define NEW_ENDMDDBSTR "# End MDD database info (do not edit)\n" + +#define MDDBBOOTLIST "mddb_bootlist" + +#define SYS_COMMENTCHAR '*' +#define CONF_COMMENTCHAR '#' + +typedef struct { + char *prop_name; + int prop_val; +} md_prop_t; + +typedef enum { + MDDB_SYS_FILE, + MDDB_MDCONF_FILE +} ftype_t; + +static md_prop_t upgrade_props[] = { + { PROP_KEEP_REPL_STATE, 0 }, + { PROP_DEVID_DESTROY, 0}, + { NULL, 0} +}; + +/* + * The following functions manage upgrade properties + */ + +void +set_upgrade_prop(char *prop_name, int val) +{ + md_prop_t *upp; + + upp = &upgrade_props[0]; + + for (; upp->prop_name != NULL; upp++) { + if (strcmp(upp->prop_name, prop_name) == 0) { + upp->prop_val = val; + return; + } + } +} + +int +is_upgrade_prop(char *prop_name) +{ + md_prop_t *upp; + + upp = &upgrade_props[0]; + + for (; upp->prop_name != NULL; upp++) { + if (strcmp(upp->prop_name, prop_name) == 0) { + return (upp->prop_val == 1); + } + } + return (0); +} + +int +create_in_file_prop(char *prop_name, char *fname) +{ + FILE *fp; + md_prop_t *upp; + int rval = RET_ERROR; + + if ((fp = fopen(fname, "a")) == NULL) { + return (errno); + } + + upp = &upgrade_props[0]; + + for (; upp->prop_name != NULL; upp++) { + if (strcmp(upp->prop_name, prop_name) == 0) { + (void) fprintf(fp, "%s = 1;\n", upp->prop_name); + rval = RET_SUCCESS; + break; + } + } + (void) fclose(fp); + return (rval); +} + +static int +is_devid_added(char *str) +{ + int cnt = 0; + char *cp; + + /* there are exactly 3 colons in the string for devid */ + for (cnt = 0; cnt < 4; cnt++) { + if ((cp = strchr(str, ':')) == NULL) + break; + str = ++cp; + } + return (cnt == 3); +} + +/* + * FUNCTION: parse_bootlist + * Parse the bootlist and add the extra field to mddb_boolist entry to + * conform to devid changes. + * + * Old format: <drivername>:<minor_number>:<offset> + * New format: <drivername>:<minor_number>:<offset>:<devid> + * Devid of id0 implies no device id. + * + * INPUT: *line - contains the mddb_bootlist + * *tfp - File pointer to the md.conf.tmp file. + * + * RETURN: + * 0 - Success + * > 0 - Failure. Errno returned + */ + +static int +parse_bootlist(char *line, FILE *tfp) +{ + char output[1024]; + char *cp; + int retval = RET_SUCCESS; + + (void) memset(output, 0, sizeof (output)); + + if (line[0] == SYS_COMMENTCHAR) { + output[0] = CONF_COMMENTCHAR; + } + /* move the line start of mddbbootlist */ + cp = strstr(line, MDDBBOOTLIST); + if (cp != NULL) + line = cp; + + /* grab the "mddb_boolist" word */ + cp = strtok(line, "= "); + (void) strcat(output, cp); + (void) strcat(output, "=\042"); /* add back the EQUAL and QUOTE chars */ + + /* + * The line passed in is for example, + * mddb_bootlist1="sd:7:16:id1,sd@SIBM_DDRS34560SUN4.2G2N9688_____/h"; + * At this point mddb_bootlist and "=" have been parsed out. + * The remaining string consists of driver name, colon separator and + * the device id(if it exists) within quotes. + * The deviceid string can contain upper and lower letters, digits + * and +-.=_~. Quotes, spaces and \n and \t are not + * allowed. They are converted to either _ or their ascii value. + * So using space,\n,;and quotes as a separator is safe. + */ + + while ((cp = strtok(NULL, " \n\042;")) != NULL) { + (void) strcat(output, cp); + if (!is_devid_added(cp)) { + /* append :id0 for devid */ + (void) strcat(strcat(output, ":"), + devid_str_encode(NULL, NULL)); + + /* no devid => SDS->SLVM migration. Set the flag */ + set_upgrade_prop(PROP_DEVID_DESTROY, 1); + } + (void) strcat(output, " "); /* leave space between entries */ + } + + /* remove the extra space at the end */ + output[strlen(output) - 1] = 0; + (void) strcat(output, "\042;\n"); + if (fprintf(tfp, "%s", output) < 0) { + retval = errno; + } + return (retval); +} + +/* + * FUNCTION: snarf_n_modify_bootlist + * This function stuffs the mddb_bootlist from either etc/system + * or kernel/drv/md.conf of the target system into a temporary file tname. + * The boolist in the temporary file is in device ID format. + * + * INPUT: *fp - file pointer that contains the mddb_bootlist. + * *tname - file into which the modified bootlist will be written to. + * * buf - buffer handed by upper level routine for reading in contents. + * * bufsiz - size of the buffer. + * mddb_file - flag + * + * RETURN: + * 0 - Success + * > 0 - Failure. Errno returned. + */ + +static int +snarf_n_modify_bootlist( + FILE *fp, /* File pointer to snarf from */ + char *tname, /* name of the temporary file */ + char *buf, /* Buffer to read into */ + int bufsz, /* buffer size */ + ftype_t mddb_file /* flag to indicate if its /etc/system or md.conf */ +) +{ + FILE *tfp; + int rval = RET_SUCCESS; + char *fname = SYSTEM_FILE; + char *mddb_start = BEGMDDBSTR; + char *mddb_end = ENDMDDBSTR; + convflag_t cstatus = MD_STR_NOTFOUND; + + if (mddb_file == MDDB_MDCONF_FILE) { + fname = MD_CONF; + mddb_start = NEW_BEGMDDBSTR; + mddb_end = NEW_ENDMDDBSTR; + } + + if ((tfp = fopen(tname, "a")) == NULL) + return (errno); + debug_printf("Convert from %s\n", fname); + + rewind(fp); + while (fgets(buf, bufsz, fp) != NULL) { + if (strcmp(buf, mddb_start) == 0) { + cstatus = MD_STR_START; + if (fprintf(tfp, "%s", NEW_BEGMDDBSTR) < 0) { + rval = errno; + break; + } + continue; + } + if (cstatus == MD_STR_START) { + if (strcmp(buf, mddb_end) == 0) { + cstatus = MD_STR_DONE; + if (fprintf(tfp, "%s", NEW_ENDMDDBSTR) < 0) { + rval = errno; + break; + } + + if (mddb_file == MDDB_MDCONF_FILE) + continue; + else + break; + } + + rval = parse_bootlist(buf, tfp); + if (rval == RET_SUCCESS) + continue; + else + break; + } + if (mddb_file == MDDB_MDCONF_FILE) { + if (fprintf(tfp, "%s\n", buf) < 0) { + rval = errno; + break; + } + } + + } /* while (fgets */ + + if (cstatus == MD_STR_NOTFOUND || cstatus == MD_STR_START) + rval = RET_ERROR; + (void) fclose(tfp); + return (rval); +} + + +/* + * FUNCTION: convert_bootlist + * Get the bootlist from $ROOT/etc/system and add modified bootlist to + * md.conf. + * The function converts the mddb_boolist format from that in /etc/system + * to md.conf. Also new fields are added to handle the devid id format. + * A copy of md.conf is created and the new entries are added to it. + * The name of the new file is returned to the calling program. + * + * Input: system file name + * md.conf file name + * pointer to temp file name. + * RETURN: + * *tname - name of the file that has md.conf + new mddb_boolist entries + * 0 - success + * -1 - mddb_bootlist not found + * > 0 - errno + * + */ + +int +convert_bootlist( + char *sname, /* system file name */ + char *mdconf, /* md.conf file name */ + char **tname /* temp file name */ +) +{ + FILE *fp; + char cmd_buf[MDDB_BOOTLIST_MAX_LEN]; + int retval = RET_SUCCESS; + + /* check names */ + assert(sname != NULL); + assert(tname != NULL); + + /* get temp name */ + *tname = tmpnam(NULL); + + if ((fp = fopen(sname, "r")) == NULL) { + retval = errno; + goto out; + } + if (valid_bootlist(fp, MDDB_BOOTLIST_MAX_LEN) == RET_SUCCESS) { + if ((retval = copyfile(mdconf, *tname)) == RET_ERROR) { + debug_printf("convert_bootlist: copy %s %s failed\n", + mdconf, *tname); + goto out; + } + retval = snarf_n_modify_bootlist(fp, *tname, cmd_buf, + MDDB_BOOTLIST_MAX_LEN, MDDB_SYS_FILE); + } else { + (void) fclose(fp); /* close system file */ + if ((fp = fopen(mdconf, "r")) == NULL) { + retval = errno; + goto out; + } + if (valid_bootlist(fp, MDDB_BOOTLIST_MAX_LEN) == RET_ERROR) { + retval = RET_ERROR; + goto out; + } + retval = snarf_n_modify_bootlist(fp, *tname, cmd_buf, + MDDB_BOOTLIST_MAX_LEN, MDDB_MDCONF_FILE); + } +out: + debug_printf("convert_bootlist: retval %d\n", retval); + if (fp != NULL) + (void) fclose(fp); + + if ((retval != RET_SUCCESS) && (*tname != NULL)) { + (void) unlink(*tname); + free(*tname); + } + return (retval); +} |
