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 /*
23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/mman.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <limits.h>
35 #include "sgs.h"
36 #include "rtc.h"
37 #include "conv.h"
38 #include "_crle.h"
39 #include "msg.h"
40
41
42 /*
43 * Display the command line required to regenerate the configuration file.
44 *
45 * Under normal mode the command is printed on one line to make it more
46 * available for grep(1) use. Under verbose mode the command is separated
47 * into each argument (a little more readable perhaps when the arguments are
48 * numerous of have long pathnames).
49 *
50 * Note that for version 1 configuration files we never used to generate any
51 * command-line information, and as the attempt to do so is only a best effort
52 * don't bother printing anything.
53 */
54 static void
printcmd(Crle_desc * crle,Rtc_head * head,APlist * cmdline)55 printcmd(Crle_desc *crle, Rtc_head * head, APlist *cmdline)
56 {
57 Aliste idx, lidx;
58 const char *fmto, *fmtb, *fmtm, *fmte;
59 char *cmd;
60 int output = 0;
61
62 if (crle->c_flags & CRLE_VERBOSE) {
63 fmto = MSG_INTL(MSG_DMP_CMD_ONE_V);
64 fmtb = MSG_INTL(MSG_DMP_CMD_BGN_V);
65 fmtm = MSG_INTL(MSG_DMP_CMD_MID_V);
66 fmte = MSG_INTL(MSG_DMP_CMD_END_V);
67
68 } else if (head->ch_version > RTC_VER_ONE) {
69 fmto = MSG_INTL(MSG_DMP_CMD_ONE);
70 fmtb = MSG_INTL(MSG_DMP_CMD_BGN);
71 fmtm = MSG_INTL(MSG_DMP_CMD_MID);
72 fmte = MSG_INTL(MSG_DMP_CMD_END);
73
74 } else {
75 (void) printf(MSG_ORIG(MSG_STR_NL));
76 return;
77 }
78
79 (void) printf(MSG_INTL(MSG_DMP_CMD_TITLE));
80
81 lidx = aplist_nitems(cmdline) - 1;
82 for (APLIST_TRAVERSE(cmdline, idx, cmd)) {
83 if (output++ == 0) {
84 if (idx < lidx)
85 (void) printf(fmtb, cmd);
86 else
87 (void) printf(fmto, cmd);
88 } else {
89 if (idx < lidx)
90 (void) printf(fmtm, cmd);
91 else
92 (void) printf(fmte, cmd);
93 }
94 }
95 }
96
97 /*
98 * Establish the argument required to generate the associated object.
99 */
100 static const char *
getformat(Half flags)101 getformat(Half flags)
102 {
103 if (flags & RTC_OBJ_ALTER) {
104 if (flags & RTC_OBJ_DUMP) {
105 if (flags & RTC_OBJ_GROUP)
106 return (MSG_ORIG(MSG_CMD_DUMPGRP));
107 else
108 return (MSG_ORIG(MSG_CMD_DUMPIND));
109 } else {
110 if (flags & RTC_OBJ_OPTINAL)
111 return (MSG_ORIG(MSG_CMD_OPTIONAL));
112 else
113 return (MSG_ORIG(MSG_CMD_ALTER));
114 }
115 } else {
116 if (flags & RTC_OBJ_GROUP)
117 return (MSG_ORIG(MSG_CMD_GRP));
118 else
119 return (MSG_ORIG(MSG_CMD_IND));
120 }
121 }
122
123 /*
124 * Fabricate a system default search path. If an update is requested, and
125 * new search paths are specified while no configuration file exists, or if a
126 * configuration file does exist but doesn't specify this particular search
127 * path, create any system defaults. The intent is to allow
128 * "crle -u -l/usr/local/lib" and have this append the search path to the
129 * system default, rather than have the user have to determine and specify
130 * this default themselves.
131 */
132 static int
fablib(Crle_desc * crle,int flag)133 fablib(Crle_desc * crle, int flag)
134 {
135 const char *path;
136 char **list;
137
138 switch (flag) {
139 case CRLE_EDLIB:
140 #if M_CLASS == ELFCLASS64
141 path = MSG_ORIG(MSG_PTH_NEWDLP_64);
142 #else
143 path = MSG_ORIG(MSG_PTH_NEWDLP);
144 #endif
145 list = &crle->c_edlibpath;
146 break;
147
148 case CRLE_ESLIB:
149 #if M_CLASS == ELFCLASS64
150 path = MSG_ORIG(MSG_PTH_NEWTD_64);
151 #else
152 path = MSG_ORIG(MSG_PTH_NEWTD);
153 #endif
154 list = &crle->c_eslibpath;
155 break;
156
157 default:
158 return (1);
159 }
160
161 return (addlib(crle, list, path));
162 }
163
164 /*
165 * Establish the flags required to generate the associated object. Actually
166 * the flags are already part of the object being inspected from the present
167 * configuration file, but instead of using them all, which can cause some
168 * unsuspected propagation down the inspect() family, only use those flags that
169 * would have been contributed from crle()'s calls to inspect.
170 */
171 static Half
getflags(Half flags)172 getflags(Half flags)
173 {
174 flags &=
175 (RTC_OBJ_ALTER | RTC_OBJ_DUMP | RTC_OBJ_GROUP | RTC_OBJ_OPTINAL);
176 return (flags | RTC_OBJ_CMDLINE);
177 }
178
179 /*
180 * Dump a configuration files information. This routine is very close to the
181 * scanconfig() in libcrle.
182 */
183 /*ARGSUSED2*/
184 static INSCFG_RET
scanconfig(Crle_desc * crle,Addr addr,int c_class)185 scanconfig(Crle_desc * crle, Addr addr, int c_class)
186 {
187 Conv_inv_buf_t inv_buf1, inv_buf2, inv_buf3, inv_buf4;
188 Conv_dl_flag_buf_t dl_flag_buf;
189 Rtc_id *id;
190 Rtc_head *head;
191 Rtc_dir *dirtbl;
192 Rtc_file *filetbl;
193 Rtc_obj *objtbl, *obj;
194 Word *hash, *chain;
195 const char *strtbl;
196 int ndx, bkts;
197 APlist *cmdline = NULL;
198 boolean_t cmdset = B_FALSE;
199 char _cmd[PATH_MAX], *cmd;
200 char _objdir[PATH_MAX], *objdir = NULL;
201
202 /*
203 * If there is an Rtc_id present, the Rtc_head follows it.
204 * Otherwise, it is at the top.
205 */
206 if (RTC_ID_TEST(addr)) {
207 id = (Rtc_id *) addr;
208 addr += sizeof (*id); /* Rtc_head follows */
209 } else {
210 id = NULL;
211 /*
212 * When updating an existing config file that is lacking
213 * the Rtc_id block, don't put one into the resulting file.
214 */
215 crle->c_flags &= ~CRLE_ADDID;
216 }
217 head = (Rtc_head *) addr;
218
219
220 /*
221 * The rest of the configuration file can only be examined by
222 * a program of the same ELFCLASS, byte order, and hardware
223 * architecture as the one that created it.
224 */
225 #ifdef _ELF64
226 /* 64-bit program with an existing 32-bit file? Abort. */
227 if (!(head->ch_cnflags & RTC_HDR_64)) {
228 (void) fprintf(stderr, MSG_INTL(MSG_ARG_CLASS),
229 crle->c_name, crle->c_confil);
230 return (INSCFG_RET_FAIL);
231 }
232 #else
233 /* 32-bit program with an existing 64-bit file? Restart. */
234 if (head->ch_cnflags & RTC_HDR_64)
235 return (INSCFG_RET_NEED64);
236
237 /*
238 * 32-bit program with an existing 32-bit file, but the
239 * user specified the -64 option? Abort
240 */
241 if (c_class != ELFCLASS32) {
242 (void) fprintf(stderr, MSG_INTL(MSG_ARG_CLASS),
243 crle->c_name, crle->c_confil);
244 return (INSCFG_RET_FAIL);
245 }
246 #endif
247 /*
248 * Now that the ELFCLASS has been settled, ensure that the
249 * byte order and hardware match. Unlike ELFCLASS, where restarting
250 * the other version is an option, we cannot work around a mismatch
251 * of these attributes.
252 */
253 if (id) { /* Rtc_id is present */
254 /*
255 * Was the file produced by compatible hardware?
256 * ELFCLASS doesn't matter here, because we can
257 * adjust for that, but byte order and machine type do.
258 */
259 if ((id->id_data != M_DATA) || (id->id_machine != M_MACH)) {
260 (void) fprintf(stderr, MSG_INTL(MSG_ARG_WRONGARCH),
261 crle->c_name, crle->c_confil,
262 conv_ehdr_data(id->id_data, CONV_FMT_ALT_FILE,
263 &inv_buf1),
264 conv_ehdr_mach(id->id_machine, CONV_FMT_ALT_FILE,
265 &inv_buf2),
266 conv_ehdr_data(M_DATA, CONV_FMT_ALT_FILE,
267 &inv_buf3),
268 conv_ehdr_mach(M_MACH, CONV_FMT_ALT_FILE,
269 &inv_buf4));
270 return (INSCFG_RET_FAIL);
271 }
272 }
273
274
275 /* LINTED */
276 objtbl = (Rtc_obj *)(CAST_PTRINT(char *, head->ch_obj) + addr);
277 strtbl = (const char *)(CAST_PTRINT(char *, head->ch_str) + addr);
278
279 /*
280 * If the configuration file has a version higher than we
281 * recognise, we face two issues:
282 * (1) Updates are not possible because we have no
283 * way to recognise or propagate the new features.
284 * This has to be a fatal error.
285 * (2) Printing has the risk that we may have been
286 * handed something other than a real config file, as
287 * well as the fact that we can't display the information
288 * for the new features. So, we print a warning, but
289 * continue on to do the best we can with it.
290 */
291 if (head->ch_version > RTC_VER_CURRENT) {
292 if (crle->c_flags & CRLE_UPDATE) {
293 (void) fprintf(stderr, MSG_INTL(MSG_ARG_UPDATEVER),
294 crle->c_name, crle->c_confil,
295 (int)head->ch_version, RTC_VER_CURRENT);
296 return (INSCFG_RET_FAIL);
297 } else {
298 (void) fprintf(stderr, MSG_INTL(MSG_ARG_PRINTVER),
299 crle->c_name, crle->c_confil,
300 (int)head->ch_version, RTC_VER_CURRENT);
301 }
302 }
303
304 /*
305 * If this is a version 1 configuration file we can't generate accurate
306 * update information, or the command-line used to create the file.
307 */
308 if (head->ch_version == RTC_VER_ONE) {
309 (void) printf(MSG_INTL(MSG_ARG_UPDATE), crle->c_name,
310 crle->c_confil, (int)head->ch_version);
311 }
312
313
314 if (!(crle->c_flags & CRLE_UPDATE) && (head->ch_cnflags & RTC_HDR_64)) {
315 /*
316 * Construct the original command line argument.
317 */
318 cmd = strdupa(MSG_ORIG(MSG_CMD_64));
319 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
320 return (INSCFG_RET_FAIL);
321 }
322
323
324 /*
325 * Start analyzing the configuration files header information.
326 */
327 if ((crle->c_flags & CRLE_UPDATE) == 0) {
328 const char *fmt;
329
330 if (head->ch_dlflags)
331 fmt = conv_dl_flag(head->ch_dlflags, 0, &dl_flag_buf);
332 else
333 fmt = MSG_ORIG(MSG_STR_EMPTY);
334
335 (void) printf(MSG_INTL(MSG_DMP_HEAD), (int)head->ch_version,
336 crle->c_confil, fmt);
337
338 /*
339 * If the file has an id block, show the information
340 */
341 if (id)
342 (void) printf(MSG_INTL(MSG_DMP_PLATFORM),
343 conv_ehdr_class(id->id_class, CONV_FMT_ALT_FILE,
344 &inv_buf1),
345 conv_ehdr_data(id->id_data, CONV_FMT_ALT_FILE,
346 &inv_buf2),
347 conv_ehdr_mach(id->id_machine, CONV_FMT_ALT_FILE,
348 &inv_buf3));
349
350 /*
351 * Construct the original command line argument.
352 */
353 (void) snprintf(_cmd, PATH_MAX, MSG_ORIG(MSG_CMD_CONF),
354 crle->c_confil);
355 cmd = strdupa(_cmd);
356 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
357 return (INSCFG_RET_FAIL);
358
359 /*
360 * Construct any -f usage.
361 */
362 if (head->ch_dlflags &&
363 (head->ch_dlflags != RTLD_REL_RELATIVE)) {
364 (void) snprintf(_cmd, PATH_MAX, MSG_ORIG(MSG_CMD_FLAGS),
365 conv_dl_flag(head->ch_dlflags, CONV_FMT_ALT_CRLE,
366 &dl_flag_buf));
367 cmd = strdupa(_cmd);
368 cmdset = B_TRUE;
369 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
370 return (INSCFG_RET_FAIL);
371 }
372 } else {
373 /*
374 * Establish any -f usage.
375 */
376 if (head->ch_dlflags &&
377 (head->ch_dlflags != RTLD_REL_RELATIVE))
378 crle->c_dlflags = head->ch_dlflags;
379 }
380
381
382 /*
383 * Determine if this configuration file is only applicable to a specific
384 * application.
385 */
386 if (head->ch_app) {
387 char *alter;
388
389 obj = (Rtc_obj *)(head->ch_app + addr);
390
391 /*
392 * Determine the output directory for the files
393 * alternative name.
394 */
395 alter = (char *)(strtbl + obj->co_alter);
396 (void) strcpy(_objdir, alter);
397 alter = strrchr(_objdir, '/');
398 *alter = '\0';
399
400 crle->c_objdir = objdir = _objdir;
401
402 if (crle->c_flags & CRLE_UPDATE) {
403 if (inspect(crle, (strtbl + obj->co_name),
404 (RTC_OBJ_DUMP | RTC_OBJ_ALTER |
405 RTC_OBJ_GROUP | RTC_OBJ_CMDLINE)) != 0)
406 return (INSCFG_RET_FAIL);
407 } else {
408 (void) printf(MSG_INTL(MSG_DMP_APP),
409 (strtbl + obj->co_alter), (strtbl + obj->co_name));
410
411 /*
412 * Construct the original command line arguments.
413 */
414 cmdset = B_TRUE;
415 (void) snprintf(_cmd, PATH_MAX,
416 MSG_ORIG(MSG_CMD_OUTPUT), crle->c_objdir);
417 cmd = strdupa(_cmd);
418 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
419 return (INSCFG_RET_FAIL);
420
421 (void) snprintf(_cmd, PATH_MAX,
422 MSG_ORIG(MSG_CMD_DUMPGRP), (strtbl + obj->co_name));
423 cmd = strdupa(_cmd);
424 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
425 return (INSCFG_RET_FAIL);
426 }
427 }
428
429 /*
430 * Analyze any alternative library path and trusted directory entries.
431 */
432 if (head->ch_edlibpath) {
433 const char *str;
434
435 str = (const char *)(head->ch_edlibpath + addr);
436
437 if (crle->c_flags & CRLE_UPDATE) {
438
439 if ((head->ch_cnflags & RTC_HDR_UPM) == 0) {
440 if (head->ch_cnflags & RTC_HDR_64)
441 str = conv_config_upm(str,
442 MSG_ORIG(MSG_PTH_OLDDLP_64),
443 MSG_ORIG(MSG_PTH_UPDLP_64),
444 MSG_PTH_UPDLP_64_SIZE);
445 else
446 str = conv_config_upm(str,
447 MSG_ORIG(MSG_PTH_OLDDLP),
448 MSG_ORIG(MSG_PTH_UPDLP),
449 MSG_PTH_UPDLP_SIZE);
450 }
451 if (addlib(crle, &crle->c_edlibpath, str) != 0)
452 return (INSCFG_RET_FAIL);
453 } else {
454 (void) printf(MSG_INTL(MSG_DMP_DLIBPTH),
455 MSG_ORIG(MSG_STR_ELF), str);
456
457 (void) snprintf(_cmd, PATH_MAX,
458 MSG_ORIG(MSG_CMD_EDLIB), str);
459 cmd = strdupa(_cmd);
460 cmdset = B_TRUE;
461 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
462 return (INSCFG_RET_FAIL);
463 }
464 } else {
465 if (crle->c_flags & CRLE_UPDATE) {
466 if (crle->c_flags & CRLE_EDLIB) {
467 /*
468 * If we've been asked to update a configuration
469 * file, and no existing default ELF search
470 * path exists, but the user is going to add new
471 * entries, fabricate the system defaults so
472 * that the users get added to them.
473 */
474 if (fablib(crle, CRLE_EDLIB) != 0)
475 return (INSCFG_RET_FAIL);
476 }
477 } else {
478 /*
479 * Indicate any system default.
480 */
481 #if M_CLASS == ELFCLASS64
482 (void) printf(MSG_INTL(MSG_DEF_NEWDLP_64));
483 #else
484 (void) printf(MSG_INTL(MSG_DEF_NEWDLP));
485 #endif
486 }
487 }
488
489 if (head->ch_eslibpath) {
490 const char *str;
491
492 str = (const char *)(head->ch_eslibpath + addr);
493
494 if (crle->c_flags & CRLE_UPDATE) {
495
496 if ((head->ch_cnflags & RTC_HDR_UPM) == 0) {
497 if (head->ch_cnflags & RTC_HDR_64)
498 str = conv_config_upm(str,
499 MSG_ORIG(MSG_PTH_OLDTD_64),
500 MSG_ORIG(MSG_PTH_UPTD_64),
501 MSG_PTH_UPTD_64_SIZE);
502 else
503 str = conv_config_upm(str,
504 MSG_ORIG(MSG_PTH_OLDTD),
505 MSG_ORIG(MSG_PTH_UPTD),
506 MSG_PTH_UPTD_SIZE);
507 }
508 if (addlib(crle, &crle->c_eslibpath, str) != 0)
509 return (INSCFG_RET_FAIL);
510 } else {
511 (void) printf(MSG_INTL(MSG_DMP_TLIBPTH),
512 MSG_ORIG(MSG_STR_ELF), str);
513
514 (void) snprintf(_cmd, PATH_MAX,
515 MSG_ORIG(MSG_CMD_ESLIB), str);
516 cmd = strdupa(_cmd);
517 cmdset = B_TRUE;
518 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
519 return (INSCFG_RET_FAIL);
520 }
521 } else {
522 if (crle->c_flags & CRLE_UPDATE) {
523 if (crle->c_flags & CRLE_ESLIB) {
524 /*
525 * If we've been asked to update a configuration
526 * file, and no existing default ELF secure
527 * path exists, but the user is going to add new
528 * entries, fabricate the system defaults so
529 * that the users get added to them.
530 */
531 if (fablib(crle, CRLE_ESLIB) != 0)
532 return (INSCFG_RET_FAIL);
533 }
534 } else {
535 /*
536 * Indicate any system default.
537 */
538 #if M_CLASS == ELFCLASS64
539 (void) printf(MSG_INTL(MSG_DEF_NEWTD_64));
540 #else
541 (void) printf(MSG_INTL(MSG_DEF_NEWTD));
542 #endif
543 }
544 }
545
546 /*
547 * Display any environment variables.
548 */
549 if ((head->ch_version >= RTC_VER_THREE) && head->ch_env) {
550 Rtc_env *envtbl;
551
552 if ((crle->c_flags & CRLE_UPDATE) == 0)
553 (void) printf(MSG_INTL(MSG_ENV_TITLE));
554
555 for (envtbl = (Rtc_env *)(head->ch_env + addr);
556 envtbl->env_str; envtbl++) {
557 const char *str;
558
559 str = (const char *)(envtbl->env_str + addr);
560
561 if (crle->c_flags & CRLE_UPDATE) {
562 if (addenv(crle, str,
563 (envtbl->env_flags | RTC_ENV_CONFIG)) == 0)
564 return (INSCFG_RET_FAIL);
565 } else {
566 const char *pfmt, *sfmt;
567
568 if (envtbl->env_flags & RTC_ENV_PERMANT) {
569 pfmt = MSG_INTL(MSG_ENV_PRM);
570 sfmt = MSG_ORIG(MSG_CMD_PRMENV);
571 } else {
572 pfmt = MSG_INTL(MSG_ENV_RPL);
573 sfmt = MSG_ORIG(MSG_CMD_RPLENV);
574 }
575 (void) printf(pfmt, str);
576 (void) snprintf(_cmd, PATH_MAX, sfmt, str);
577 cmd = strdupa(_cmd);
578 cmdset = B_TRUE;
579 if (aplist_append(&cmdline, cmd,
580 AL_CNT_CRLE) == NULL)
581 return (INSCFG_RET_FAIL);
582 }
583 }
584 }
585
586 /*
587 * Display any filter/filtee associations.
588 */
589 if ((head->ch_version >= RTC_VER_FOUR) && head->ch_fltr) {
590 if ((crle->c_flags & CRLE_UPDATE) == 0) {
591 Rtc_fltr *fltrtbl;
592 Rtc_flte *fltetbl;
593
594 /* LINTED */
595 fltrtbl = (Rtc_fltr *)
596 (CAST_PTRINT(char *, head->ch_fltr) + addr);
597 /* LINTED */
598 fltetbl = (Rtc_flte *)
599 (CAST_PTRINT(char *, head->ch_flte) + addr);
600
601 (void) printf(MSG_INTL(MSG_FLT_TITLE));
602
603 while (fltrtbl->fr_filter) {
604 Rtc_flte *_fltetbl;
605
606 /*
607 * Print the filter and filtee string pair.
608 */
609 (void) printf(MSG_INTL(MSG_FLT_FILTER),
610 (strtbl + fltrtbl->fr_filter),
611 (strtbl + fltrtbl->fr_string));
612
613 /*
614 * Print each filtee.
615 */
616 /* LINTED */
617 for (_fltetbl = (Rtc_flte *)((char *)fltetbl +
618 fltrtbl->fr_filtee); _fltetbl->fe_filtee;
619 _fltetbl++) {
620 (void) printf(MSG_INTL(MSG_FLT_FILTEE),
621 (strtbl + _fltetbl->fe_filtee));
622 }
623 fltrtbl++;
624 }
625 }
626 }
627
628 /*
629 * Display any memory reservations required for any alternative
630 * objects.
631 */
632 if (head->ch_resbgn && ((crle->c_flags & CRLE_UPDATE) == 0))
633 (void) printf(MSG_INTL(MSG_DMP_RESV),
634 (u_longlong_t)head->ch_resbgn,
635 (u_longlong_t)head->ch_resend,
636 (u_longlong_t)(head->ch_resend - head->ch_resbgn));
637
638 /*
639 * If there's no hash table there's nothing else to process.
640 */
641 if (head->ch_hash == 0) {
642 if (((crle->c_flags & CRLE_UPDATE) == 0) && cmdset)
643 printcmd(crle, head, cmdline);
644 return (INSCFG_RET_OK);
645 }
646
647 /*
648 * Traverse the directory and filename arrays.
649 */
650 for (dirtbl = (Rtc_dir *)(head->ch_dir + addr);
651 dirtbl->cd_obj; dirtbl++) {
652 struct stat status;
653 Rtc_obj *dobj;
654 const char *str;
655
656 dobj = (Rtc_obj *)(dirtbl->cd_obj + addr);
657 filetbl = (Rtc_file *)(dirtbl->cd_file + addr);
658 str = strtbl + dobj->co_name;
659
660 /*
661 * Simplify recreation by using any command-line directories.
662 * If we're dealing with a version 1 configuration file use
663 * every directory.
664 */
665 if ((dobj->co_flags & RTC_OBJ_CMDLINE) ||
666 (head->ch_version == RTC_VER_ONE)) {
667 if (crle->c_flags & CRLE_UPDATE) {
668 if (inspect(crle, str,
669 getflags(dobj->co_flags)) != 0)
670 return (INSCFG_RET_FAIL);
671 if ((dobj->co_flags &
672 (RTC_OBJ_NOEXIST | RTC_OBJ_ALTER)) ==
673 RTC_OBJ_NOEXIST)
674 continue;
675 } else {
676 /* LINTED */
677 (void) snprintf(_cmd, PATH_MAX,
678 getformat(dobj->co_flags), str);
679 cmd = strdupa(_cmd);
680 cmdset = B_TRUE;
681 if (aplist_append(&cmdline, cmd,
682 AL_CNT_CRLE) == NULL)
683 return (INSCFG_RET_FAIL);
684 }
685 }
686
687 /*
688 * If this isn't an update print the directory name. If the
689 * directory has no entries (possible if the directory is a
690 * symlink to another directory, in which case we record the
691 * real path also), don't bother printing it unless we're in
692 * verbose mode.
693 */
694 if ((crle->c_flags & CRLE_UPDATE) == 0) {
695 if ((dobj->co_flags &
696 (RTC_OBJ_NOEXIST | RTC_OBJ_ALTER)) ==
697 RTC_OBJ_NOEXIST) {
698 (void) printf(MSG_INTL(MSG_DMP_DIR_2), str);
699 continue;
700 } else if (filetbl->cf_obj ||
701 (crle->c_flags & CRLE_VERBOSE))
702 (void) printf(MSG_INTL(MSG_DMP_DIR_1), str);
703 }
704
705 /*
706 * Under verbose mode validate any real directory entry - the
707 * same test will be carried out by ld.so.1.
708 */
709 if (((crle->c_flags & CRLE_UPDATE) == 0) &&
710 (crle->c_flags & CRLE_VERBOSE) &&
711 (dobj->co_flags & RTC_OBJ_REALPTH)) {
712 if (stat(str, &status) != 0) {
713 int err = errno;
714 (void) printf(MSG_INTL(MSG_DMP_STAT), str,
715 strerror(err));
716 } else if (status.st_mtime != dobj->co_info) {
717 (void) printf(MSG_INTL(MSG_DMP_DCMP), str);
718 }
719 }
720
721 for (; filetbl->cf_obj; filetbl++) {
722 Rtc_obj *fobj;
723 Half flags;
724
725 fobj = (Rtc_obj *)(filetbl->cf_obj + addr);
726 str = strtbl + fobj->co_name;
727 flags = fobj->co_flags;
728
729 /*
730 * Only update individual files that were originally
731 * specified on the command-line. Or, if this is a
732 * version 1 configuration file use every file that
733 * isn't part of an all-entries directory.
734 */
735 if (((flags & RTC_OBJ_CMDLINE) &&
736 ((fobj->co_flags & RTC_OBJ_APP) == 0)) ||
737 ((head->ch_version == RTC_VER_ONE) &&
738 ((dobj->co_flags & RTC_OBJ_ALLENTS) == 0))) {
739 char *alter = NULL, altdir[PATH_MAX];
740
741 /*
742 * Determine whether this file requires an
743 * alternative, and if so, and we haven't
744 * already an alternative in affect, create one.
745 */
746 if (fobj->co_flags & RTC_OBJ_ALTER) {
747 alter = (char *)(strtbl +
748 fobj->co_alter);
749 (void) strcpy(altdir, alter);
750 alter = strrchr(altdir, '/');
751 *alter = '\0';
752
753 if ((objdir == NULL) ||
754 (strcmp(objdir, altdir) != 0)) {
755 (void) strcpy(_objdir, altdir);
756 crle->c_objdir = alter =
757 objdir = _objdir;
758 } else
759 alter = NULL;
760 }
761
762 if (crle->c_flags & CRLE_UPDATE) {
763 if (inspect(crle, str,
764 getflags(flags)) != 0)
765 return (INSCFG_RET_FAIL);
766 continue;
767 }
768
769 if (alter) {
770 (void) snprintf(_cmd, PATH_MAX,
771 MSG_ORIG(MSG_CMD_OUTPUT),
772 crle->c_objdir);
773 cmd = strdupa(_cmd);
774 cmdset = B_TRUE;
775 if (aplist_append(&cmdline, cmd,
776 AL_CNT_CRLE) == NULL)
777 return (INSCFG_RET_FAIL);
778 }
779
780 /* LINTED */
781 (void) snprintf(_cmd, PATH_MAX,
782 getformat(flags), str);
783 cmd = strdupa(_cmd);
784 cmdset = B_TRUE;
785 if (aplist_append(&cmdline, cmd,
786 AL_CNT_CRLE) == NULL)
787 return (INSCFG_RET_FAIL);
788 }
789
790 if (crle->c_flags & CRLE_UPDATE)
791 continue;
792
793 /*
794 * Although we record both full pathnames and their
795 * simple filenames (basename), only print the simple
796 * names unless we're under verbose mode.
797 */
798 if ((strchr(str, '/') == 0) ||
799 (crle->c_flags & CRLE_VERBOSE)) {
800 if (fobj->co_flags & RTC_OBJ_ALTER)
801 (void) printf(MSG_INTL(MSG_DMP_FILE_2),
802 str, (strtbl + fobj->co_alter));
803 else
804 (void) printf(MSG_INTL(MSG_DMP_FILE_1),
805 str);
806 }
807
808 /*
809 * Under verbose mode validate any real file entry - the
810 * same test will be carried out by ld.so.1.
811 */
812 if ((crle->c_flags & CRLE_VERBOSE) &&
813 (fobj->co_flags & RTC_OBJ_REALPTH)) {
814 if (stat(str, &status) != 0) {
815 int err = errno;
816 (void) printf(MSG_INTL(MSG_DMP_STAT),
817 str, strerror(err));
818 } else if (status.st_size != fobj->co_info) {
819 (void) printf(MSG_INTL(MSG_DMP_FCMP),
820 str);
821 }
822 }
823 }
824 }
825
826 if (((crle->c_flags & CRLE_UPDATE) == 0) && cmdset)
827 printcmd(crle, head, cmdline);
828
829 if ((crle->c_flags & CRLE_VERBOSE) == 0)
830 return (INSCFG_RET_OK);
831
832 /*
833 * If we've in verbose mode scan the hash list.
834 */
835 /* LINTED */
836 hash = (Word *)(CAST_PTRINT(char *, head->ch_hash) + addr);
837 bkts = hash[0];
838 chain = &hash[2 + bkts];
839 hash += 2;
840
841 (void) printf(MSG_INTL(MSG_DMP_HASH));
842
843 /*
844 * Scan the hash buckets looking for valid entries.
845 */
846 for (ndx = 0; ndx < bkts; ndx++, hash++) {
847 Conv_config_obj_buf_t config_obj_buf;
848 Rtc_obj *obj;
849 const char *str;
850 Word _ndx;
851
852 if (*hash == 0)
853 continue;
854
855 obj = objtbl + *hash;
856 str = strtbl + obj->co_name;
857
858 (void) printf(MSG_INTL(MSG_DMP_HASHENT_1), obj->co_id, ndx,
859 str, conv_config_obj(obj->co_flags, &config_obj_buf));
860
861 /*
862 * Determine whether there are other objects chained to this
863 * bucket.
864 */
865 for (_ndx = chain[*hash]; _ndx; _ndx = chain[_ndx]) {
866 obj = objtbl + _ndx;
867 str = strtbl + obj->co_name;
868
869 (void) printf(MSG_INTL(MSG_DMP_HASHENT_2), obj->co_id,
870 str, conv_config_obj(obj->co_flags,
871 &config_obj_buf));
872 }
873 }
874 (void) printf(MSG_ORIG(MSG_STR_NL));
875
876 return (INSCFG_RET_OK);
877 }
878
879
880 INSCFG_RET
inspectconfig(Crle_desc * crle,int c_class)881 inspectconfig(Crle_desc * crle, int c_class)
882 {
883 INSCFG_RET error;
884 int fd;
885 Addr addr;
886 struct stat status;
887 const char *caller = crle->c_name, *file = crle->c_confil;
888 Conv_inv_buf_t inv_buf1, inv_buf2, inv_buf3;
889
890 /*
891 * Open the configuration file, determine its size and map it in.
892 */
893 if ((fd = open(file, O_RDONLY, 0)) == -1) {
894 int err = errno;
895
896 if (err == ENOENT) {
897 #ifndef _ELF64
898 /* Must restart if user requested a 64-bit file */
899 if (c_class == ELFCLASS64)
900 return (INSCFG_RET_NEED64);
901 #endif
902
903 /*
904 * To allow an update (-u) from scratch, fabricate any
905 * default search and secure paths that the user
906 * intends to add to.
907 */
908 if (crle->c_flags & CRLE_UPDATE) {
909 if (crle->c_flags & CRLE_EDLIB) {
910 if (fablib(crle, CRLE_EDLIB))
911 return (INSCFG_RET_FAIL);
912 }
913 if (crle->c_flags & CRLE_ESLIB) {
914 if (fablib(crle, CRLE_ESLIB))
915 return (INSCFG_RET_FAIL);
916 }
917 return (INSCFG_RET_OK);
918
919 } else if (crle->c_flags & CRLE_CONFDEF) {
920 const char *fmt1, *fmt2;
921
922 /*
923 * Otherwise if the user is inspecting a default
924 * configuration file that doesn't exist inform
925 * them and display the ELF defaults.
926 */
927 (void) printf(MSG_INTL(MSG_DEF_NOCONF), file);
928 (void) printf(MSG_INTL(MSG_DMP_PLATFORM),
929 conv_ehdr_class(M_CLASS,
930 CONV_FMT_ALT_FILE, &inv_buf1),
931 conv_ehdr_data(M_DATA,
932 CONV_FMT_ALT_FILE, &inv_buf2),
933 conv_ehdr_mach(M_MACH,
934 CONV_FMT_ALT_FILE, &inv_buf3));
935
936
937 #if M_CLASS == ELFCLASS64
938 fmt1 = MSG_INTL(MSG_DEF_NEWDLP_64);
939 fmt2 = MSG_INTL(MSG_DEF_NEWTD_64);
940 #else
941 fmt1 = MSG_INTL(MSG_DEF_NEWDLP);
942 fmt2 = MSG_INTL(MSG_DEF_NEWTD);
943 #endif
944 (void) printf(fmt1);
945 (void) printf(fmt2);
946
947 return (INSCFG_RET_OK);
948 }
949 }
950
951 /*
952 * Otherwise there's an error condition in accessing the file.
953 */
954 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), caller, file,
955 strerror(err));
956
957 return (INSCFG_RET_FAIL);
958 }
959
960 (void) fstat(fd, &status);
961 if (status.st_size < sizeof (Rtc_head)) {
962 (void) close(fd);
963 (void) fprintf(stderr, MSG_INTL(MSG_COR_TRUNC), caller, file);
964 return (INSCFG_RET_FAIL);
965 }
966 if ((addr = (Addr)mmap(0, status.st_size, PROT_READ, MAP_SHARED,
967 fd, 0)) == (Addr)MAP_FAILED) {
968 int err = errno;
969 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP), caller, file,
970 strerror(err));
971 (void) close(fd);
972 return (INSCFG_RET_FAIL);
973 }
974 (void) close(fd);
975
976 /*
977 * Print the contents of the configuration file.
978 */
979 error = scanconfig(crle, addr, c_class);
980
981 (void) munmap((void *)addr, status.st_size);
982 return (error);
983 }
984