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