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
meta_systemfile_copy(char * sname,int doroot,int domddb,int doit,int verbose,char ** tname,FILE ** tfp,md_error_t * ep)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
meta_systemfile_append_mdroot(mdname_t * rootnp,char * sname,char * tname,FILE * tfp,int ismeta,int doit,int verbose,md_error_t * ep)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
confline(char * line,char ** driver,minor_t * mnump,daddr_t * block,char ** devid_char_pp)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
meta_systemfile_append_mddb(char * cname,char * sname,char * tname,FILE * tfp,int doit,int verbose,int check,md_error_t * ep)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