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