1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * Just in case we're not in a build environment, make sure that
31*0Sstevel@tonic-gate  * TEXT_DOMAIN gets set to something.
32*0Sstevel@tonic-gate  */
33*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
34*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
35*0Sstevel@tonic-gate #endif
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate /*
38*0Sstevel@tonic-gate  * patch /kernel/drv/md.conf file
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate #include <sys/types.h>
41*0Sstevel@tonic-gate #include <sys/stat.h>
42*0Sstevel@tonic-gate #include <meta.h>
43*0Sstevel@tonic-gate #include <sys/lvm/md_mddb.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate /*
46*0Sstevel@tonic-gate  * magic strings in system
47*0Sstevel@tonic-gate  */
48*0Sstevel@tonic-gate #define	BEGROOTSTR	"* Begin MDD root info (do not edit)\n"
49*0Sstevel@tonic-gate #define	ENDROOTSTR	"* End MDD root info (do not edit)\n"
50*0Sstevel@tonic-gate #define	BEGMDDBSTR	"# Begin MDD database info (do not edit)\n"
51*0Sstevel@tonic-gate #define	ENDMDDBSTR	"# End MDD database info (do not edit)\n"
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate /*
54*0Sstevel@tonic-gate  * copy system file, yank root and database lines
55*0Sstevel@tonic-gate  */
56*0Sstevel@tonic-gate int
57*0Sstevel@tonic-gate meta_systemfile_copy(
58*0Sstevel@tonic-gate 	char		*sname,		/* system file name */
59*0Sstevel@tonic-gate 	int		doroot,		/* remove mdd root stuff */
60*0Sstevel@tonic-gate 	int		domddb,		/* remove mdd database stuff */
61*0Sstevel@tonic-gate 	int		doit,		/* really copy file */
62*0Sstevel@tonic-gate 	int		verbose,	/* show what we're doing */
63*0Sstevel@tonic-gate 	char		**tname,	/* returned temp file name */
64*0Sstevel@tonic-gate 	FILE		**tfp,		/* returned open FILE */
65*0Sstevel@tonic-gate 	md_error_t	*ep		/* returned error */
66*0Sstevel@tonic-gate )
67*0Sstevel@tonic-gate {
68*0Sstevel@tonic-gate 	FILE		*fp;
69*0Sstevel@tonic-gate 	struct stat	sbuf;
70*0Sstevel@tonic-gate 	char		buf[MDDB_BOOTLIST_MAX_LEN];
71*0Sstevel@tonic-gate 	int		delroot = 0;
72*0Sstevel@tonic-gate 	int		delmddb = 0;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 	/* check names */
75*0Sstevel@tonic-gate 	assert(sname != NULL);
76*0Sstevel@tonic-gate 	assert(tname != NULL);
77*0Sstevel@tonic-gate 	assert(tfp != NULL);
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	/* get temp name */
80*0Sstevel@tonic-gate 	*tfp = NULL;
81*0Sstevel@tonic-gate 	*tname = Malloc(strlen(sname) + strlen(".tmp") + 1);
82*0Sstevel@tonic-gate 	(void) strcpy(*tname, sname);
83*0Sstevel@tonic-gate 	(void) strcat(*tname, ".tmp");
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	/* copy system file, yank stuff */
86*0Sstevel@tonic-gate 	if (((fp = fopen(sname, "r")) == NULL) ||
87*0Sstevel@tonic-gate 	    (fstat(fileno(fp), &sbuf) != 0)) {
88*0Sstevel@tonic-gate 		if (errno != ENOENT) {
89*0Sstevel@tonic-gate 			(void) mdsyserror(ep, errno, sname);
90*0Sstevel@tonic-gate 			goto out;
91*0Sstevel@tonic-gate 		}
92*0Sstevel@tonic-gate 	}
93*0Sstevel@tonic-gate 	if (doit) {
94*0Sstevel@tonic-gate 		if ((*tfp = fopen(*tname, "w")) == NULL) {
95*0Sstevel@tonic-gate 			/*
96*0Sstevel@tonic-gate 			 * If we are on the miniroot we need to create
97*0Sstevel@tonic-gate 			 * files in /var/tmp. Opening a writable file
98*0Sstevel@tonic-gate 			 * in the miniroot result is EROFS error.
99*0Sstevel@tonic-gate 			 */
100*0Sstevel@tonic-gate 			if (errno != EROFS) {
101*0Sstevel@tonic-gate 				(void) mdsyserror(ep, errno, *tname);
102*0Sstevel@tonic-gate 				goto out;
103*0Sstevel@tonic-gate 			}
104*0Sstevel@tonic-gate 			Free(*tname);
105*0Sstevel@tonic-gate 			*tname = tempnam("/var/tmp", "svm_");
106*0Sstevel@tonic-gate 			if (*tname == NULL) {
107*0Sstevel@tonic-gate 				(void) mdsyserror(ep, errno, NULL);
108*0Sstevel@tonic-gate 				goto out;
109*0Sstevel@tonic-gate 			}
110*0Sstevel@tonic-gate 			if ((*tfp = fopen(*tname, "w")) == NULL) {
111*0Sstevel@tonic-gate 				(void) mdsyserror(ep, errno, *tname);
112*0Sstevel@tonic-gate 				goto out;
113*0Sstevel@tonic-gate 			}
114*0Sstevel@tonic-gate 		}
115*0Sstevel@tonic-gate 		if (fp != NULL) {
116*0Sstevel@tonic-gate 			if ((fchmod(fileno(*tfp), (sbuf.st_mode & 0777))
117*0Sstevel@tonic-gate 			    != 0) ||
118*0Sstevel@tonic-gate 			    (fchown(fileno(*tfp), sbuf.st_uid, sbuf.st_gid)
119*0Sstevel@tonic-gate 			    != 0)) {
120*0Sstevel@tonic-gate 				(void) mdsyserror(ep, errno, *tname);
121*0Sstevel@tonic-gate 				goto out;
122*0Sstevel@tonic-gate 			}
123*0Sstevel@tonic-gate 		}
124*0Sstevel@tonic-gate 	}
125*0Sstevel@tonic-gate 	if (verbose) {
126*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
127*0Sstevel@tonic-gate 		    "Delete the following lines from %s:\n\n"), sname);
128*0Sstevel@tonic-gate 	}
129*0Sstevel@tonic-gate 	while ((fp != NULL) && (fgets(buf, sizeof (buf), fp) != NULL)) {
130*0Sstevel@tonic-gate 		if ((doroot) && (strcmp(buf, BEGROOTSTR) == 0)) {
131*0Sstevel@tonic-gate 			delroot = 1;
132*0Sstevel@tonic-gate 			if (verbose)
133*0Sstevel@tonic-gate 				(void) printf("%s", buf);
134*0Sstevel@tonic-gate 			continue;
135*0Sstevel@tonic-gate 		}
136*0Sstevel@tonic-gate 		if (delroot) {
137*0Sstevel@tonic-gate 			if (strcmp(buf, ENDROOTSTR) == 0)
138*0Sstevel@tonic-gate 				delroot = 0;
139*0Sstevel@tonic-gate 			if (verbose)
140*0Sstevel@tonic-gate 				(void) printf("%s", buf);
141*0Sstevel@tonic-gate 			continue;
142*0Sstevel@tonic-gate 		}
143*0Sstevel@tonic-gate 		if ((domddb) && (strcmp(buf, BEGMDDBSTR) == 0)) {
144*0Sstevel@tonic-gate 			delmddb = 1;
145*0Sstevel@tonic-gate 			if (verbose)
146*0Sstevel@tonic-gate 				(void) printf("%s", buf);
147*0Sstevel@tonic-gate 			continue;
148*0Sstevel@tonic-gate 		}
149*0Sstevel@tonic-gate 		if (delmddb) {
150*0Sstevel@tonic-gate 			if (strcmp(buf, ENDMDDBSTR) == 0)
151*0Sstevel@tonic-gate 				delmddb = 0;
152*0Sstevel@tonic-gate 			if (verbose)
153*0Sstevel@tonic-gate 				(void) printf("%s", buf);
154*0Sstevel@tonic-gate 			continue;
155*0Sstevel@tonic-gate 		}
156*0Sstevel@tonic-gate 		if (doit) {
157*0Sstevel@tonic-gate 			if (fputs(buf, *tfp) == EOF) {
158*0Sstevel@tonic-gate 				(void) mdsyserror(ep, errno, *tname);
159*0Sstevel@tonic-gate 				goto out;
160*0Sstevel@tonic-gate 			}
161*0Sstevel@tonic-gate 		}
162*0Sstevel@tonic-gate 	}
163*0Sstevel@tonic-gate 	if (fp != NULL) {
164*0Sstevel@tonic-gate 		if ((! feof(fp)) ||
165*0Sstevel@tonic-gate 		    (fclose(fp) != 0)) {
166*0Sstevel@tonic-gate 			(void) mdsyserror(ep, errno, sname);
167*0Sstevel@tonic-gate 			goto out;
168*0Sstevel@tonic-gate 		}
169*0Sstevel@tonic-gate 		fp = NULL;
170*0Sstevel@tonic-gate 	}
171*0Sstevel@tonic-gate 	if (verbose)
172*0Sstevel@tonic-gate 		(void) printf("\n");
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 	/* make sure we didn't stop mid-delete */
175*0Sstevel@tonic-gate 	if ((delroot) || (delmddb)) {
176*0Sstevel@tonic-gate 		(void) mderror(ep, MDE_SYSTEM_FILE, sname);
177*0Sstevel@tonic-gate 		goto out;
178*0Sstevel@tonic-gate 	}
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	/* flush stuff */
181*0Sstevel@tonic-gate 	if (doit) {
182*0Sstevel@tonic-gate 		if ((fflush(*tfp) != 0) ||
183*0Sstevel@tonic-gate 		    (fsync(fileno(*tfp)) != 0)) {
184*0Sstevel@tonic-gate 			(void) mdsyserror(ep, errno, *tname);
185*0Sstevel@tonic-gate 			goto out;
186*0Sstevel@tonic-gate 		}
187*0Sstevel@tonic-gate 	}
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	/* return success */
190*0Sstevel@tonic-gate 	return (0);
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	/* cleanup, return error */
193*0Sstevel@tonic-gate out:
194*0Sstevel@tonic-gate 	if (fp != NULL)
195*0Sstevel@tonic-gate 		(void) fclose(fp);
196*0Sstevel@tonic-gate 	if (*tname != NULL) {
197*0Sstevel@tonic-gate 		(void) unlink(*tname);
198*0Sstevel@tonic-gate 		Free(*tname);
199*0Sstevel@tonic-gate 	}
200*0Sstevel@tonic-gate 	if (*tfp != NULL)
201*0Sstevel@tonic-gate 		(void) fclose(*tfp);
202*0Sstevel@tonic-gate 	return (-1);
203*0Sstevel@tonic-gate }
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate /*
206*0Sstevel@tonic-gate  * append root on MD lines to system
207*0Sstevel@tonic-gate  */
208*0Sstevel@tonic-gate int
209*0Sstevel@tonic-gate meta_systemfile_append_mdroot(
210*0Sstevel@tonic-gate 	mdname_t	*rootnp,	/* root device name */
211*0Sstevel@tonic-gate 	char		*sname,		/* system file name */
212*0Sstevel@tonic-gate 	char		*tname,		/* temp file name */
213*0Sstevel@tonic-gate 	FILE		*tfp,		/* temp FILE */
214*0Sstevel@tonic-gate 	int		ismeta,		/* is a metadevice */
215*0Sstevel@tonic-gate 	int		doit,		/* really patch file */
216*0Sstevel@tonic-gate 	int		verbose,	/* show what we're doing */
217*0Sstevel@tonic-gate 	md_error_t	*ep
218*0Sstevel@tonic-gate )
219*0Sstevel@tonic-gate {
220*0Sstevel@tonic-gate 	char		*longblkname;
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	/* check names */
223*0Sstevel@tonic-gate 	assert(sname != NULL);
224*0Sstevel@tonic-gate 	assert(tname != NULL);
225*0Sstevel@tonic-gate 	assert(!doit || tfp != NULL);
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	/* get root /devices name */
228*0Sstevel@tonic-gate 	if ((longblkname = metagetdevicesname(rootnp, ep)) == NULL)
229*0Sstevel@tonic-gate 		return (-1);
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	/* add header */
232*0Sstevel@tonic-gate 	if (verbose) {
233*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
234*0Sstevel@tonic-gate 		    "Add the following lines to %s:\n\n"), sname);
235*0Sstevel@tonic-gate 		(void) printf("%s", BEGROOTSTR);
236*0Sstevel@tonic-gate 	}
237*0Sstevel@tonic-gate 	if (doit) {
238*0Sstevel@tonic-gate 		if (fprintf(tfp, "%s", BEGROOTSTR) == EOF) {
239*0Sstevel@tonic-gate 			return (mdsyserror(ep, errno, tname));
240*0Sstevel@tonic-gate 		}
241*0Sstevel@tonic-gate 	}
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	/* add rootdev */
244*0Sstevel@tonic-gate 	if (ismeta) {
245*0Sstevel@tonic-gate 		if (verbose)
246*0Sstevel@tonic-gate 			(void) printf("rootdev:%s\n", longblkname);
247*0Sstevel@tonic-gate 		if (doit) {
248*0Sstevel@tonic-gate 			if (fprintf(tfp, "rootdev:%s\n", longblkname) == EOF) {
249*0Sstevel@tonic-gate 				return (mdsyserror(ep, errno, tname));
250*0Sstevel@tonic-gate 			}
251*0Sstevel@tonic-gate 		}
252*0Sstevel@tonic-gate 	}
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	/* add trailer */
255*0Sstevel@tonic-gate 	if (verbose) {
256*0Sstevel@tonic-gate 		(void) printf("%s\n", ENDROOTSTR);
257*0Sstevel@tonic-gate 	}
258*0Sstevel@tonic-gate 	if (doit) {
259*0Sstevel@tonic-gate 		if (fprintf(tfp, "%s", ENDROOTSTR) == EOF) {
260*0Sstevel@tonic-gate 			return (mdsyserror(ep, errno, tname));
261*0Sstevel@tonic-gate 		}
262*0Sstevel@tonic-gate 	}
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 	/* flush stuff */
265*0Sstevel@tonic-gate 	if (doit) {
266*0Sstevel@tonic-gate 		if ((fflush(tfp) != 0) ||
267*0Sstevel@tonic-gate 		    (fsync(fileno(tfp)) != 0)) {
268*0Sstevel@tonic-gate 			return (mdsyserror(ep, errno, tname));
269*0Sstevel@tonic-gate 		}
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	/* return success */
273*0Sstevel@tonic-gate 	return (0);
274*0Sstevel@tonic-gate }
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate /*
277*0Sstevel@tonic-gate  * parse mddb.cf line
278*0Sstevel@tonic-gate  *
279*0Sstevel@tonic-gate  * Caller of this routine needs to free the device id string that
280*0Sstevel@tonic-gate  * is passed back during a successful return.
281*0Sstevel@tonic-gate  */
282*0Sstevel@tonic-gate static int
283*0Sstevel@tonic-gate confline(
284*0Sstevel@tonic-gate 	char		*line,		/* line in file */
285*0Sstevel@tonic-gate 	char		**driver,	/* returned driver name */
286*0Sstevel@tonic-gate 	minor_t		*mnump,		/* returned minor number */
287*0Sstevel@tonic-gate 	daddr_t		*block,		/* returned block offset */
288*0Sstevel@tonic-gate 	char		**devid_char_pp	/* returned device id string */
289*0Sstevel@tonic-gate )
290*0Sstevel@tonic-gate {
291*0Sstevel@tonic-gate 	char		*p = line;
292*0Sstevel@tonic-gate 	int		chksum = 0;
293*0Sstevel@tonic-gate 	int		i;
294*0Sstevel@tonic-gate 	uint_t		devid_size;
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	if (*p == '#') {
297*0Sstevel@tonic-gate 		return (-1);
298*0Sstevel@tonic-gate 	}
299*0Sstevel@tonic-gate 	*driver = p;
300*0Sstevel@tonic-gate 	while ((*p != ' ') && (*p != '\t'))
301*0Sstevel@tonic-gate 		chksum += *p++;
302*0Sstevel@tonic-gate 	if (*driver == p) {
303*0Sstevel@tonic-gate 		return (-1);
304*0Sstevel@tonic-gate 	}
305*0Sstevel@tonic-gate 	*p++ = '\0';
306*0Sstevel@tonic-gate 	*mnump = strtoul(p, &p, 10);
307*0Sstevel@tonic-gate 	chksum += *mnump;
308*0Sstevel@tonic-gate 	*block = strtol(p, &p, 10);
309*0Sstevel@tonic-gate 	chksum += *block;
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	/* parse out devid */
312*0Sstevel@tonic-gate 	while ((*p == ' ') || (*p == '\t')) {
313*0Sstevel@tonic-gate 		p++;
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate 	i = strcspn(p, " \t");
316*0Sstevel@tonic-gate 	*devid_char_pp = Malloc(i+1);
317*0Sstevel@tonic-gate 	(void) strncpy(*devid_char_pp, p, i);
318*0Sstevel@tonic-gate 	(*devid_char_pp)[i] = '\0';
319*0Sstevel@tonic-gate 	devid_size = i;
320*0Sstevel@tonic-gate 	p += devid_size;
321*0Sstevel@tonic-gate 	for (i = 0; i < devid_size; i++) {
322*0Sstevel@tonic-gate 		chksum += (*devid_char_pp)[i];
323*0Sstevel@tonic-gate 	}
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	chksum += strtol(p, &p, 10);
326*0Sstevel@tonic-gate 	if (chksum != 42) {
327*0Sstevel@tonic-gate 		Free (*devid_char_pp);
328*0Sstevel@tonic-gate 		devid_char_pp = NULL;
329*0Sstevel@tonic-gate 		return (-1);
330*0Sstevel@tonic-gate 	}
331*0Sstevel@tonic-gate 	return (0);
332*0Sstevel@tonic-gate }
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate /*
335*0Sstevel@tonic-gate  * append MDDB lines to system
336*0Sstevel@tonic-gate  */
337*0Sstevel@tonic-gate int
338*0Sstevel@tonic-gate meta_systemfile_append_mddb(
339*0Sstevel@tonic-gate 	char		*cname,		/* mddb.cf file name */
340*0Sstevel@tonic-gate 	char		*sname,		/* system file name */
341*0Sstevel@tonic-gate 	char		*tname,		/* temp file name */
342*0Sstevel@tonic-gate 	FILE		*tfp,		/* temp FILE */
343*0Sstevel@tonic-gate 	int		doit,		/* really patch file */
344*0Sstevel@tonic-gate 	int		verbose,	/* show what we're doing */
345*0Sstevel@tonic-gate 	md_error_t	*ep		/* returned error */
346*0Sstevel@tonic-gate )
347*0Sstevel@tonic-gate {
348*0Sstevel@tonic-gate 	FILE		*cfp = NULL;
349*0Sstevel@tonic-gate 	char		buf[1024];
350*0Sstevel@tonic-gate 	char		*p;
351*0Sstevel@tonic-gate 	int		i;
352*0Sstevel@tonic-gate 	char		*driver;
353*0Sstevel@tonic-gate 	minor_t		mnum;
354*0Sstevel@tonic-gate 	daddr_t		block;
355*0Sstevel@tonic-gate 	char		line[MDDB_BOOTLIST_MAX_LEN];
356*0Sstevel@tonic-gate 	char		entry[MDDB_BOOTLIST_MAX_LEN];
357*0Sstevel@tonic-gate 	char		*devid_char_p = NULL;
358*0Sstevel@tonic-gate 	struct stat	statbuf;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	/* check names */
361*0Sstevel@tonic-gate 	assert(cname != NULL);
362*0Sstevel@tonic-gate 	assert(sname != NULL);
363*0Sstevel@tonic-gate 	assert(tname != NULL);
364*0Sstevel@tonic-gate 	assert(!doit || tfp != NULL);
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	/* open database conf file */
367*0Sstevel@tonic-gate 	if ((cfp = fopen(cname, "r")) == NULL) {
368*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, cname);
369*0Sstevel@tonic-gate 		goto out;
370*0Sstevel@tonic-gate 	}
371*0Sstevel@tonic-gate 	/* Check that it is an ordinary file */
372*0Sstevel@tonic-gate 	if (stat(cname, &statbuf) != 0) {
373*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, cname);
374*0Sstevel@tonic-gate 		goto out;
375*0Sstevel@tonic-gate 	}
376*0Sstevel@tonic-gate 	if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
377*0Sstevel@tonic-gate 		(void) mderror(ep, MDE_MDDB_FILE, cname);
378*0Sstevel@tonic-gate 		goto out;
379*0Sstevel@tonic-gate 	}
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	/* add header */
382*0Sstevel@tonic-gate 	if (verbose) {
383*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
384*0Sstevel@tonic-gate 		    "Add the following lines to %s:\n\n"), sname);
385*0Sstevel@tonic-gate 		(void) printf("%s", BEGMDDBSTR);
386*0Sstevel@tonic-gate 	}
387*0Sstevel@tonic-gate 	if (doit) {
388*0Sstevel@tonic-gate 		if (fprintf(tfp, "%s", BEGMDDBSTR) == EOF) {
389*0Sstevel@tonic-gate 			(void) mdsyserror(ep, errno, tname);
390*0Sstevel@tonic-gate 			goto out;
391*0Sstevel@tonic-gate 		}
392*0Sstevel@tonic-gate 	}
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	/* append database lines */
395*0Sstevel@tonic-gate 	while (((p = fgets(buf, sizeof (buf), cfp)) != NULL) &&
396*0Sstevel@tonic-gate 	    (confline(buf, &driver, &mnum, &block, &devid_char_p) != 0))
397*0Sstevel@tonic-gate 		;
398*0Sstevel@tonic-gate 	for (i = 1; ((p != NULL) && (i <= MDDB_MAX_PATCH)); ++i) {
399*0Sstevel@tonic-gate 		(void) snprintf(line, sizeof (line),
400*0Sstevel@tonic-gate 		    "mddb_bootlist%d=\"%s:%lu:%ld:%s",
401*0Sstevel@tonic-gate 		    i, driver, mnum, block, devid_char_p);
402*0Sstevel@tonic-gate 		if (devid_char_p != NULL) {
403*0Sstevel@tonic-gate 			free(devid_char_p);
404*0Sstevel@tonic-gate 			devid_char_p = NULL;
405*0Sstevel@tonic-gate 		}
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 		while ((p = fgets(buf, sizeof (buf), cfp)) != NULL) {
408*0Sstevel@tonic-gate 			if (confline(buf, &driver, &mnum, &block,
409*0Sstevel@tonic-gate 			    &devid_char_p) != 0) {
410*0Sstevel@tonic-gate 				continue;
411*0Sstevel@tonic-gate 			}
412*0Sstevel@tonic-gate 			(void) snprintf(entry, sizeof (entry), " %s:%lu:%ld:%s",
413*0Sstevel@tonic-gate 			    driver, mnum, block, devid_char_p);
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 			if ((strlen(line) + strlen(entry) + 4) > sizeof (line))
416*0Sstevel@tonic-gate 				break;
417*0Sstevel@tonic-gate 			(void) strcat(line, entry);
418*0Sstevel@tonic-gate 			if (devid_char_p != NULL) {
419*0Sstevel@tonic-gate 				free(devid_char_p);
420*0Sstevel@tonic-gate 				devid_char_p = NULL;
421*0Sstevel@tonic-gate 			}
422*0Sstevel@tonic-gate 		}
423*0Sstevel@tonic-gate 		if (verbose)
424*0Sstevel@tonic-gate 			/* CSTYLED */
425*0Sstevel@tonic-gate 			(void) printf("%s\";\n", line);
426*0Sstevel@tonic-gate 		if (doit) {
427*0Sstevel@tonic-gate 			/* CSTYLED */
428*0Sstevel@tonic-gate 			if (fprintf(tfp, "%s\";\n", line) <= 0) {
429*0Sstevel@tonic-gate 				(void) mdsyserror(ep, errno, tname);
430*0Sstevel@tonic-gate 				goto out;
431*0Sstevel@tonic-gate 			}
432*0Sstevel@tonic-gate 		}
433*0Sstevel@tonic-gate 	}
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	if (devid_char_p != NULL) {
436*0Sstevel@tonic-gate 		free(devid_char_p);
437*0Sstevel@tonic-gate 		devid_char_p = NULL;
438*0Sstevel@tonic-gate 	}
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	/* add trailer */
441*0Sstevel@tonic-gate 	if (verbose)
442*0Sstevel@tonic-gate 		(void) printf("%s\n", ENDMDDBSTR);
443*0Sstevel@tonic-gate 	if (doit) {
444*0Sstevel@tonic-gate 		if (fprintf(tfp, "%s", ENDMDDBSTR) == EOF) {
445*0Sstevel@tonic-gate 			(void) mdsyserror(ep, errno, tname);
446*0Sstevel@tonic-gate 			goto out;
447*0Sstevel@tonic-gate 		}
448*0Sstevel@tonic-gate 	}
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	/* close database conf file */
451*0Sstevel@tonic-gate 	if (fclose(cfp) != 0) {
452*0Sstevel@tonic-gate 		cfp = NULL;
453*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, cname);
454*0Sstevel@tonic-gate 		goto out;
455*0Sstevel@tonic-gate 	}
456*0Sstevel@tonic-gate 	cfp = NULL;
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	/* flush stuff */
459*0Sstevel@tonic-gate 	if (doit) {
460*0Sstevel@tonic-gate 		if ((fflush(tfp) != 0) ||
461*0Sstevel@tonic-gate 		    (fsync(fileno(tfp)) != 0)) {
462*0Sstevel@tonic-gate 			(void) mdsyserror(ep, errno, tname);
463*0Sstevel@tonic-gate 			goto out;
464*0Sstevel@tonic-gate 		}
465*0Sstevel@tonic-gate 	}
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	/* return success */
468*0Sstevel@tonic-gate 	return (0);
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	/* cleanup, return error */
471*0Sstevel@tonic-gate out:
472*0Sstevel@tonic-gate 	if (cfp != NULL)
473*0Sstevel@tonic-gate 		(void) fclose(cfp);
474*0Sstevel@tonic-gate 	return (-1);
475*0Sstevel@tonic-gate }
476