/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Just in case we're not in a build environment, make sure that * TEXT_DOMAIN gets set to something. */ #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif /* * patch /kernel/drv/md.conf file */ #include #include #include #include /* * magic strings in system */ #define BEGROOTSTR "* Begin MDD root info (do not edit)\n" #define ENDROOTSTR "* End MDD root info (do not edit)\n" #define BEGMDDBSTR "# Begin MDD database info (do not edit)\n" #define ENDMDDBSTR "# End MDD database info (do not edit)\n" /* * copy system file, yank root and database lines */ int meta_systemfile_copy( char *sname, /* system file name */ int doroot, /* remove mdd root stuff */ int domddb, /* remove mdd database stuff */ int doit, /* really copy file */ int verbose, /* show what we're doing */ char **tname, /* returned temp file name */ FILE **tfp, /* returned open FILE */ md_error_t *ep /* returned error */ ) { FILE *fp; struct stat sbuf; char buf[MDDB_BOOTLIST_MAX_LEN]; int delroot = 0; int delmddb = 0; /* check names */ assert(sname != NULL); assert(tname != NULL); assert(tfp != NULL); /* get temp name */ *tfp = NULL; *tname = Malloc(strlen(sname) + strlen(".tmp") + 1); (void) strcpy(*tname, sname); (void) strcat(*tname, ".tmp"); /* copy system file, yank stuff */ if (((fp = fopen(sname, "r")) == NULL) || (fstat(fileno(fp), &sbuf) != 0)) { if (errno != ENOENT) { (void) mdsyserror(ep, errno, sname); goto out; } } if (doit) { if ((*tfp = fopen(*tname, "w")) == NULL) { /* * If we are on the miniroot we need to create * files in /var/tmp. Opening a writable file * in the miniroot result is EROFS error. */ if (errno != EROFS) { (void) mdsyserror(ep, errno, *tname); goto out; } Free(*tname); *tname = tempnam("/var/tmp", "svm_"); if (*tname == NULL) { (void) mdsyserror(ep, errno, NULL); goto out; } if ((*tfp = fopen(*tname, "w")) == NULL) { (void) mdsyserror(ep, errno, *tname); goto out; } } if (fp != NULL) { if ((fchmod(fileno(*tfp), (sbuf.st_mode & 0777)) != 0) || (fchown(fileno(*tfp), sbuf.st_uid, sbuf.st_gid) != 0)) { (void) mdsyserror(ep, errno, *tname); goto out; } } } if (verbose) { (void) printf(dgettext(TEXT_DOMAIN, "Delete the following lines from %s:\n\n"), sname); } while ((fp != NULL) && (fgets(buf, sizeof (buf), fp) != NULL)) { if ((doroot) && (strcmp(buf, BEGROOTSTR) == 0)) { delroot = 1; if (verbose) (void) printf("%s", buf); continue; } if (delroot) { if (strcmp(buf, ENDROOTSTR) == 0) delroot = 0; if (verbose) (void) printf("%s", buf); continue; } if ((domddb) && (strcmp(buf, BEGMDDBSTR) == 0)) { delmddb = 1; if (verbose) (void) printf("%s", buf); continue; } if (delmddb) { if (strcmp(buf, ENDMDDBSTR) == 0) delmddb = 0; if (verbose) (void) printf("%s", buf); continue; } if (doit) { if (fputs(buf, *tfp) == EOF) { (void) mdsyserror(ep, errno, *tname); goto out; } } } if (fp != NULL) { if ((! feof(fp)) || (fclose(fp) != 0)) { (void) mdsyserror(ep, errno, sname); goto out; } fp = NULL; } if (verbose) (void) printf("\n"); /* make sure we didn't stop mid-delete */ if ((delroot) || (delmddb)) { (void) mderror(ep, MDE_SYSTEM_FILE, sname); goto out; } /* flush stuff */ if (doit) { if ((fflush(*tfp) != 0) || (fsync(fileno(*tfp)) != 0)) { (void) mdsyserror(ep, errno, *tname); goto out; } } /* return success */ return (0); /* cleanup, return error */ out: if (fp != NULL) (void) fclose(fp); if (*tname != NULL) { (void) unlink(*tname); Free(*tname); } if (*tfp != NULL) (void) fclose(*tfp); return (-1); } /* * append root on MD lines to system */ int meta_systemfile_append_mdroot( mdname_t *rootnp, /* root device name */ char *sname, /* system file name */ char *tname, /* temp file name */ FILE *tfp, /* temp FILE */ int ismeta, /* is a metadevice */ int doit, /* really patch file */ int verbose, /* show what we're doing */ md_error_t *ep ) { char *longblkname; /* check names */ assert(sname != NULL); assert(tname != NULL); assert(!doit || tfp != NULL); /* get root /devices name */ if ((longblkname = metagetdevicesname(rootnp, ep)) == NULL) return (-1); /* add header */ if (verbose) { (void) printf(dgettext(TEXT_DOMAIN, "Add the following lines to %s:\n\n"), sname); (void) printf("%s", BEGROOTSTR); } if (doit) { if (fprintf(tfp, "%s", BEGROOTSTR) == EOF) { return (mdsyserror(ep, errno, tname)); } } /* add rootdev */ if (ismeta) { if (verbose) (void) printf("rootdev:%s\n", longblkname); if (doit) { if (fprintf(tfp, "rootdev:%s\n", longblkname) == EOF) { return (mdsyserror(ep, errno, tname)); } } } /* add trailer */ if (verbose) { (void) printf("%s\n", ENDROOTSTR); } if (doit) { if (fprintf(tfp, "%s", ENDROOTSTR) == EOF) { return (mdsyserror(ep, errno, tname)); } } /* flush stuff */ if (doit) { if ((fflush(tfp) != 0) || (fsync(fileno(tfp)) != 0)) { return (mdsyserror(ep, errno, tname)); } } /* return success */ return (0); } /* * parse mddb.cf line * * Caller of this routine needs to free the device id string that * is passed back during a successful return. */ static int confline( char *line, /* line in file */ char **driver, /* returned driver name */ minor_t *mnump, /* returned minor number */ daddr_t *block, /* returned block offset */ char **devid_char_pp /* returned device id string */ ) { char *p = line; int chksum = 0; int i; uint_t devid_size; if (*p == '#') { return (-1); } *driver = p; while ((*p != ' ') && (*p != '\t')) chksum += *p++; if (*driver == p) { return (-1); } *p++ = '\0'; *mnump = strtoul(p, &p, 10); chksum += *mnump; *block = strtol(p, &p, 10); chksum += *block; /* parse out devid */ while ((*p == ' ') || (*p == '\t')) { p++; } i = strcspn(p, " \t"); *devid_char_pp = Malloc(i+1); (void) strncpy(*devid_char_pp, p, i); (*devid_char_pp)[i] = '\0'; devid_size = i; p += devid_size; for (i = 0; i < devid_size; i++) { chksum += (*devid_char_pp)[i]; } chksum += strtol(p, &p, 10); if (chksum != 42) { Free (*devid_char_pp); devid_char_pp = NULL; return (-1); } return (0); } /* * append MDDB lines to system */ int meta_systemfile_append_mddb( char *cname, /* mddb.cf file name */ char *sname, /* system file name */ char *tname, /* temp file name */ FILE *tfp, /* temp FILE */ int doit, /* really patch file */ int verbose, /* show what we're doing */ int check, /* if set check that mddb.cf is not */ /* empty before updating md.conf */ md_error_t *ep /* returned error */ ) { FILE *cfp = NULL; char buf[1024]; char *p; int i; char *driver; minor_t mnum; daddr_t block; char line[MDDB_BOOTLIST_MAX_LEN]; char entry[MDDB_BOOTLIST_MAX_LEN]; char *devid_char_p = NULL; struct stat statbuf; /* check names */ assert(cname != NULL); assert(sname != NULL); assert(tname != NULL); assert(!doit || tfp != NULL); /* open database conf file */ if ((cfp = fopen(cname, "r")) == NULL) { (void) mdsyserror(ep, errno, cname); goto out; } /* Check that it is an ordinary file */ if (stat(cname, &statbuf) != 0) { (void) mdsyserror(ep, errno, cname); goto out; } if ((statbuf.st_mode & S_IFMT) != S_IFREG) { (void) mderror(ep, MDE_MDDB_FILE, cname); goto out; } /* add header */ if (verbose) { (void) printf(dgettext(TEXT_DOMAIN, "Add the following lines to %s:\n\n"), sname); (void) printf("%s", BEGMDDBSTR); } if (doit) { if (fprintf(tfp, "%s", BEGMDDBSTR) == EOF) { (void) mdsyserror(ep, errno, tname); goto out; } } /* append database lines */ while (((p = fgets(buf, sizeof (buf), cfp)) != NULL) && (confline(buf, &driver, &mnum, &block, &devid_char_p) != 0)) ; /* * It is possible to be in a state where the md_devid_destroy flag * has been set and the mdmonitor service not be enabled on reboot * such that metadevadm doesn't get run and the entries in mddb.cf * recreated. The following checks for this condition and will not * allow an empty mddb.cf to overwrite md.conf and lose the users * configuration */ if (check && p == NULL) { (void) mderror(ep, MDE_MDDB_FILE, cname); goto out; } for (i = 1; ((p != NULL) && (i <= MDDB_MAX_PATCH)); ++i) { (void) snprintf(line, sizeof (line), "mddb_bootlist%d=\"%s:%lu:%ld:%s", i, driver, mnum, block, devid_char_p); if (devid_char_p != NULL) { free(devid_char_p); devid_char_p = NULL; } while ((p = fgets(buf, sizeof (buf), cfp)) != NULL) { if (confline(buf, &driver, &mnum, &block, &devid_char_p) != 0) { continue; } (void) snprintf(entry, sizeof (entry), " %s:%lu:%ld:%s", driver, mnum, block, devid_char_p); if ((strlen(line) + strlen(entry) + 4) > sizeof (line)) break; (void) strcat(line, entry); if (devid_char_p != NULL) { free(devid_char_p); devid_char_p = NULL; } } if (verbose) /* CSTYLED */ (void) printf("%s\";\n", line); if (doit) { /* CSTYLED */ if (fprintf(tfp, "%s\";\n", line) <= 0) { (void) mdsyserror(ep, errno, tname); goto out; } } } if (devid_char_p != NULL) { free(devid_char_p); devid_char_p = NULL; } /* add trailer */ if (verbose) (void) printf("%s\n", ENDMDDBSTR); if (doit) { if (fprintf(tfp, "%s", ENDMDDBSTR) == EOF) { (void) mdsyserror(ep, errno, tname); goto out; } } /* close database conf file */ if (fclose(cfp) != 0) { cfp = NULL; (void) mdsyserror(ep, errno, cname); goto out; } cfp = NULL; /* flush stuff */ if (doit) { if ((fflush(tfp) != 0) || (fsync(fileno(tfp)) != 0)) { (void) mdsyserror(ep, errno, tname); goto out; } } /* return success */ return (0); /* cleanup, return error */ out: if (cfp != NULL) (void) fclose(cfp); return (-1); }