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 #ifndef SGS_PRE_UNIFIED_PROCESS
142 path = MSG_ORIG(MSG_PTH_NEWDLP_64);
143 #else
144 path = MSG_ORIG(MSG_PTH_OLDDLP_64);
145 #endif
146 #else
147 #ifndef SGS_PRE_UNIFIED_PROCESS
148 path = MSG_ORIG(MSG_PTH_NEWDLP);
149 #else
150 path = MSG_ORIG(MSG_PTH_OLDDLP);
151 #endif
152 #endif
153 list = &crle->c_edlibpath;
154 break;
155
156 case CRLE_ESLIB:
157 #if M_CLASS == ELFCLASS64
158 #ifndef SGS_PRE_UNIFIED_PROCESS
159 path = MSG_ORIG(MSG_PTH_NEWTD_64);
160 #else
161 path = MSG_ORIG(MSG_PTH_OLDTD_64);
162 #endif
163 #else
164 #ifndef SGS_PRE_UNIFIED_PROCESS
165 path = MSG_ORIG(MSG_PTH_NEWTD);
166 #else
167 path = MSG_ORIG(MSG_PTH_OLDTD);
168 #endif
169 #endif
170 list = &crle->c_eslibpath;
171 break;
172
173 case CRLE_ADLIB:
174 path = MSG_ORIG(MSG_PTH_AOUTDLP);
175 list = &crle->c_adlibpath;
176 break;
177
178 case CRLE_ASLIB:
179 #ifndef SGS_PRE_UNIFIED_PROCESS
180 path = MSG_ORIG(MSG_PTH_NEWTD);
181 #else
182 path = MSG_ORIG(MSG_PTH_OLDTD);
183 #endif
184 list = &crle->c_aslibpath;
185 break;
186
187 default:
188 return (1);
189 }
190
191 return (addlib(crle, list, path));
192 }
193
194 /*
195 * Establish the flags required to generate the associated object. Actually
196 * the flags are already part of the object being inspected from the present
197 * configuration file, but instead of using them all, which can cause some
198 * unsuspected propagation down the inspect() family, only use those flags that
199 * would have been contributed from crle()'s calls to inspect.
200 */
201 static Half
getflags(Half flags)202 getflags(Half flags)
203 {
204 flags &=
205 (RTC_OBJ_ALTER | RTC_OBJ_DUMP | RTC_OBJ_GROUP | RTC_OBJ_OPTINAL);
206 return (flags | RTC_OBJ_CMDLINE);
207 }
208
209 /*
210 * Dump a configuration files information. This routine is very close to the
211 * scanconfig() in libcrle.
212 */
213 /*ARGSUSED2*/
214 static INSCFG_RET
scanconfig(Crle_desc * crle,Addr addr,int c_class)215 scanconfig(Crle_desc * crle, Addr addr, int c_class)
216 {
217 Conv_inv_buf_t inv_buf1, inv_buf2, inv_buf3, inv_buf4;
218 Conv_dl_flag_buf_t dl_flag_buf;
219 Rtc_id *id;
220 Rtc_head *head;
221 Rtc_dir *dirtbl;
222 Rtc_file *filetbl;
223 Rtc_obj *objtbl, *obj;
224 Word *hash, *chain;
225 const char *strtbl;
226 int ndx, bkts;
227 APlist *cmdline = NULL;
228 char _cmd[PATH_MAX], *cmd;
229 char _objdir[PATH_MAX], *objdir = NULL;
230
231 /*
232 * If there is an Rtc_id present, the Rtc_head follows it.
233 * Otherwise, it is at the top.
234 */
235 if (RTC_ID_TEST(addr)) {
236 id = (Rtc_id *) addr;
237 addr += sizeof (*id); /* Rtc_head follows */
238 } else {
239 id = NULL;
240 /*
241 * When updating an existing config file that is lacking
242 * the Rtc_id block, don't put one into the resulting file.
243 */
244 crle->c_flags &= ~CRLE_ADDID;
245 }
246 head = (Rtc_head *) addr;
247
248
249 /*
250 * The rest of the configuration file can only be examined by
251 * a program of the same ELFCLASS, byte order, and hardware
252 * architecture as the one that created it.
253 */
254 #ifdef _ELF64
255 /* 64-bit program with an existing 32-bit file? Abort. */
256 if (!(head->ch_cnflags & RTC_HDR_64)) {
257 (void) fprintf(stderr, MSG_INTL(MSG_ARG_CLASS),
258 crle->c_name, crle->c_confil);
259 return (INSCFG_RET_FAIL);
260 }
261 #else
262 /* 32-bit program with an existing 64-bit file? Restart. */
263 if (head->ch_cnflags & RTC_HDR_64)
264 return (INSCFG_RET_NEED64);
265
266 /*
267 * 32-bit program with an existing 32-bit file, but the
268 * user specified the -64 option? Abort
269 */
270 if (c_class != ELFCLASS32) {
271 (void) fprintf(stderr, MSG_INTL(MSG_ARG_CLASS),
272 crle->c_name, crle->c_confil);
273 return (INSCFG_RET_FAIL);
274 }
275 #endif
276 /*
277 * Now that the ELFCLASS has been settled, ensure that the
278 * byte order and hardware match. Unlike ELFCLASS, where restarting
279 * the other version is an option, we cannot work around a mismatch
280 * of these attributes.
281 */
282 if (id) { /* Rtc_id is present */
283 /*
284 * Was the file produced by compatible hardware?
285 * ELFCLASS doesn't matter here, because we can
286 * adjust for that, but byte order and machine type do.
287 */
288 if ((id->id_data != M_DATA) || (id->id_machine != M_MACH)) {
289 (void) fprintf(stderr, MSG_INTL(MSG_ARG_WRONGARCH),
290 crle->c_name, crle->c_confil,
291 conv_ehdr_data(id->id_data, CONV_FMT_ALT_FILE,
292 &inv_buf1),
293 conv_ehdr_mach(id->id_machine, CONV_FMT_ALT_FILE,
294 &inv_buf2),
295 conv_ehdr_data(M_DATA, CONV_FMT_ALT_FILE,
296 &inv_buf3),
297 conv_ehdr_mach(M_MACH, CONV_FMT_ALT_FILE,
298 &inv_buf4));
299 return (INSCFG_RET_FAIL);
300 }
301 }
302
303
304 /* LINTED */
305 objtbl = (Rtc_obj *)(CAST_PTRINT(char *, head->ch_obj) + addr);
306 strtbl = (const char *)(CAST_PTRINT(char *, head->ch_str) + addr);
307
308 /*
309 * If the configuration file has a version higher than we
310 * recognise, we face two issues:
311 * (1) Updates are not possible because we have no
312 * way to recognise or propagate the new features.
313 * This has to be a fatal error.
314 * (2) Printing has the risk that we may have been
315 * handed something other than a real config file, as
316 * well as the fact that we can't display the information
317 * for the new features. So, we print a warning, but
318 * continue on to do the best we can with it.
319 */
320 if (head->ch_version > RTC_VER_CURRENT) {
321 if (crle->c_flags & CRLE_UPDATE) {
322 (void) fprintf(stderr, MSG_INTL(MSG_ARG_UPDATEVER),
323 crle->c_name, crle->c_confil,
324 (int)head->ch_version, RTC_VER_CURRENT);
325 return (INSCFG_RET_FAIL);
326 } else {
327 (void) fprintf(stderr, MSG_INTL(MSG_ARG_PRINTVER),
328 crle->c_name, crle->c_confil,
329 (int)head->ch_version, RTC_VER_CURRENT);
330 }
331 }
332
333 /*
334 * If this is a version 1 configuration file we can't generate accurate
335 * update information, or the command-line used to create the file.
336 */
337 if (head->ch_version == RTC_VER_ONE) {
338 (void) printf(MSG_INTL(MSG_ARG_UPDATE), crle->c_name,
339 crle->c_confil, (int)head->ch_version);
340 }
341
342
343 if (!(crle->c_flags & CRLE_UPDATE) && (head->ch_cnflags & RTC_HDR_64)) {
344 /*
345 * Construct the original command line argument.
346 */
347 cmd = strdupa(MSG_ORIG(MSG_CMD_64));
348 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
349 return (INSCFG_RET_FAIL);
350 }
351
352
353 /*
354 * Start analyzing the configuration files header information.
355 */
356 if ((crle->c_flags & CRLE_UPDATE) == 0) {
357 const char *fmt;
358
359 if (head->ch_dlflags)
360 fmt = conv_dl_flag(head->ch_dlflags, 0, &dl_flag_buf);
361 else
362 fmt = MSG_ORIG(MSG_STR_EMPTY);
363
364 (void) printf(MSG_INTL(MSG_DMP_HEAD), (int)head->ch_version,
365 crle->c_confil, fmt);
366
367 /*
368 * If the file has an id block, show the information
369 */
370 if (id)
371 (void) printf(MSG_INTL(MSG_DMP_PLATFORM),
372 conv_ehdr_class(id->id_class, CONV_FMT_ALT_FILE,
373 &inv_buf1),
374 conv_ehdr_data(id->id_data, CONV_FMT_ALT_FILE,
375 &inv_buf2),
376 conv_ehdr_mach(id->id_machine, CONV_FMT_ALT_FILE,
377 &inv_buf3));
378
379 /*
380 * Construct the original command line argument.
381 */
382 (void) snprintf(_cmd, PATH_MAX, MSG_ORIG(MSG_CMD_CONF),
383 crle->c_confil);
384 cmd = strdupa(_cmd);
385 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
386 return (INSCFG_RET_FAIL);
387
388 /*
389 * Construct any -f usage.
390 */
391 if (head->ch_dlflags &&
392 (head->ch_dlflags != RTLD_REL_RELATIVE)) {
393 (void) snprintf(_cmd, PATH_MAX, MSG_ORIG(MSG_CMD_FLAGS),
394 conv_dl_flag(head->ch_dlflags, CONV_FMT_ALT_CRLE,
395 &dl_flag_buf));
396 cmd = strdupa(_cmd);
397 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
398 return (INSCFG_RET_FAIL);
399 }
400 } else {
401 /*
402 * Establish any -f usage.
403 */
404 if (head->ch_dlflags &&
405 (head->ch_dlflags != RTLD_REL_RELATIVE))
406 crle->c_dlflags = head->ch_dlflags;
407 }
408
409
410 /*
411 * Determine if this configuration file is only applicable to a specific
412 * application.
413 */
414 if (head->ch_app) {
415 char *alter;
416
417 obj = (Rtc_obj *)(head->ch_app + addr);
418
419 /*
420 * Determine the output directory for the files
421 * alternative name.
422 */
423 alter = (char *)(strtbl + obj->co_alter);
424 (void) strcpy(_objdir, alter);
425 alter = strrchr(_objdir, '/');
426 *alter = '\0';
427
428 crle->c_objdir = objdir = _objdir;
429
430 if (crle->c_flags & CRLE_UPDATE) {
431 if (inspect(crle, (strtbl + obj->co_name),
432 (RTC_OBJ_DUMP | RTC_OBJ_ALTER |
433 RTC_OBJ_GROUP | RTC_OBJ_CMDLINE)) != 0)
434 return (INSCFG_RET_FAIL);
435 } else {
436 (void) printf(MSG_INTL(MSG_DMP_APP),
437 (strtbl + obj->co_alter), (strtbl + obj->co_name));
438
439 /*
440 * Construct the original command line arguments.
441 */
442 (void) snprintf(_cmd, PATH_MAX,
443 MSG_ORIG(MSG_CMD_OUTPUT), crle->c_objdir);
444 cmd = strdupa(_cmd);
445 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
446 return (INSCFG_RET_FAIL);
447
448 (void) snprintf(_cmd, PATH_MAX,
449 MSG_ORIG(MSG_CMD_DUMPGRP), (strtbl + obj->co_name));
450 cmd = strdupa(_cmd);
451 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
452 return (INSCFG_RET_FAIL);
453 }
454 }
455
456 /*
457 * Analyze any alternative library path and trusted directory entries.
458 */
459 if (head->ch_edlibpath) {
460 const char *str;
461
462 str = (const char *)(head->ch_edlibpath + addr);
463
464 if (crle->c_flags & CRLE_UPDATE) {
465 crle->c_flags &= ~CRLE_AOUT;
466
467 #ifndef SGS_PRE_UNIFIED_PROCESS
468 if ((head->ch_cnflags & RTC_HDR_UPM) == 0) {
469 if (head->ch_cnflags & RTC_HDR_64)
470 str = conv_config_upm(str,
471 MSG_ORIG(MSG_PTH_OLDDLP_64),
472 MSG_ORIG(MSG_PTH_UPDLP_64),
473 MSG_PTH_UPDLP_64_SIZE);
474 else
475 str = conv_config_upm(str,
476 MSG_ORIG(MSG_PTH_OLDDLP),
477 MSG_ORIG(MSG_PTH_UPDLP),
478 MSG_PTH_UPDLP_SIZE);
479 }
480 #endif
481 if (addlib(crle, &crle->c_edlibpath, str) != 0)
482 return (INSCFG_RET_FAIL);
483 } else {
484 (void) printf(MSG_INTL(MSG_DMP_DLIBPTH),
485 MSG_ORIG(MSG_STR_ELF), str);
486
487 (void) snprintf(_cmd, PATH_MAX,
488 MSG_ORIG(MSG_CMD_EDLIB), str);
489 cmd = strdupa(_cmd);
490 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
491 return (INSCFG_RET_FAIL);
492 }
493 } else {
494 if (crle->c_flags & CRLE_UPDATE) {
495 if (crle->c_flags & CRLE_EDLIB) {
496 /*
497 * If we've been asked to update a configuration
498 * file, and no existing default ELF search
499 * path exists, but the user is going to add new
500 * entries, fabricate the system defaults so
501 * that the users get added to them.
502 */
503 if (fablib(crle, CRLE_EDLIB) != 0)
504 return (INSCFG_RET_FAIL);
505 }
506 } else {
507 /*
508 * Indicate any system default.
509 */
510 #if M_CLASS == ELFCLASS64
511 #ifndef SGS_PRE_UNIFIED_PROCESS
512 (void) printf(MSG_INTL(MSG_DEF_NEWDLP_64));
513 #else
514 (void) printf(MSG_INTL(MSG_DEF_OLDDLP_64));
515 #endif
516 #else
517 #ifndef SGS_PRE_UNIFIED_PROCESS
518 (void) printf(MSG_INTL(MSG_DEF_NEWDLP));
519 #else
520 (void) printf(MSG_INTL(MSG_DEF_OLDDLP));
521 #endif
522 #endif
523 }
524 }
525
526 if (head->ch_eslibpath) {
527 const char *str;
528
529 str = (const char *)(head->ch_eslibpath + addr);
530
531 if (crle->c_flags & CRLE_UPDATE) {
532 crle->c_flags &= ~CRLE_AOUT;
533
534 #ifndef SGS_PRE_UNIFIED_PROCESS
535 if ((head->ch_cnflags & RTC_HDR_UPM) == 0) {
536 if (head->ch_cnflags & RTC_HDR_64)
537 str = conv_config_upm(str,
538 MSG_ORIG(MSG_PTH_OLDTD_64),
539 MSG_ORIG(MSG_PTH_UPTD_64),
540 MSG_PTH_UPTD_64_SIZE);
541 else
542 str = conv_config_upm(str,
543 MSG_ORIG(MSG_PTH_OLDTD),
544 MSG_ORIG(MSG_PTH_UPTD),
545 MSG_PTH_UPTD_SIZE);
546 }
547 #endif
548 if (addlib(crle, &crle->c_eslibpath, str) != 0)
549 return (INSCFG_RET_FAIL);
550 } else {
551 (void) printf(MSG_INTL(MSG_DMP_TLIBPTH),
552 MSG_ORIG(MSG_STR_ELF), str);
553
554 (void) snprintf(_cmd, PATH_MAX,
555 MSG_ORIG(MSG_CMD_ESLIB), str);
556 cmd = strdupa(_cmd);
557 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
558 return (INSCFG_RET_FAIL);
559 }
560 } else {
561 if (crle->c_flags & CRLE_UPDATE) {
562 if (crle->c_flags & CRLE_ESLIB) {
563 /*
564 * If we've been asked to update a configuration
565 * file, and no existing default ELF secure
566 * path exists, but the user is going to add new
567 * entries, fabricate the system defaults so
568 * that the users get added to them.
569 */
570 if (fablib(crle, CRLE_ESLIB) != 0)
571 return (INSCFG_RET_FAIL);
572 }
573 } else {
574 /*
575 * Indicate any system default.
576 */
577 #if M_CLASS == ELFCLASS64
578 #ifndef SGS_PRE_UNIFIED_PROCESS
579 (void) printf(MSG_INTL(MSG_DEF_NEWTD_64));
580 #else
581 (void) printf(MSG_INTL(MSG_DEF_OLDTD_64));
582 #endif
583 #else
584 #ifndef SGS_PRE_UNIFIED_PROCESS
585 (void) printf(MSG_INTL(MSG_DEF_NEWTD));
586 #else
587 (void) printf(MSG_INTL(MSG_DEF_OLDTD));
588 #endif
589 #endif
590 }
591 }
592
593 if (head->ch_adlibpath) {
594 const char *str;
595
596 str = (const char *)(head->ch_adlibpath + addr);
597
598 if (crle->c_flags & CRLE_UPDATE) {
599 crle->c_flags |= CRLE_AOUT;
600 if (addlib(crle, &crle->c_adlibpath, str) != 0)
601 return (INSCFG_RET_FAIL);
602 } else {
603 (void) printf(MSG_INTL(MSG_DMP_DLIBPTH),
604 MSG_ORIG(MSG_STR_AOUT), str);
605
606 (void) snprintf(_cmd, PATH_MAX,
607 MSG_ORIG(MSG_CMD_ADLIB), str);
608 cmd = strdupa(_cmd);
609 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
610 return (INSCFG_RET_FAIL);
611 }
612 } else {
613 if (crle->c_flags & CRLE_UPDATE) {
614 if (crle->c_flags & CRLE_ADLIB) {
615 /*
616 * If we've been asked to update a configuration
617 * file, and no existing default AOUT search
618 * path exists, but the user is going to add new
619 * entries, fabricate the system defaults so
620 * that the users get added to them.
621 */
622 if (fablib(crle, CRLE_ADLIB) != 0)
623 return (INSCFG_RET_FAIL);
624 }
625 } else if (crle->c_flags & CRLE_AOUT) {
626 /*
627 * Indicate any system default.
628 */
629 (void) printf(MSG_INTL(MSG_DEF_AOUTDLP));
630 }
631 }
632
633 if (head->ch_aslibpath) {
634 const char *str;
635
636 str = (const char *)(head->ch_aslibpath + addr);
637
638 if (crle->c_flags & CRLE_UPDATE) {
639 crle->c_flags |= CRLE_AOUT;
640 if (addlib(crle, &crle->c_aslibpath, str) != 0)
641 return (INSCFG_RET_FAIL);
642 } else {
643 (void) printf(MSG_INTL(MSG_DMP_TLIBPTH),
644 MSG_ORIG(MSG_STR_AOUT), str);
645
646 (void) snprintf(_cmd, PATH_MAX,
647 MSG_ORIG(MSG_CMD_ASLIB), str);
648 cmd = strdupa(_cmd);
649 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL)
650 return (INSCFG_RET_FAIL);
651 }
652 } else {
653 if (crle->c_flags & CRLE_UPDATE) {
654 if (crle->c_flags & CRLE_ASLIB) {
655 /*
656 * If we've been asked to update a configuration
657 * file, and no existing default AOUT secure
658 * path exists, but the user is going to add new
659 * entries, fabricate the system defaults so
660 * that the users get added to them.
661 */
662 if (fablib(crle, CRLE_ASLIB) != 0)
663 return (INSCFG_RET_FAIL);
664 }
665 } else if (crle->c_flags & CRLE_AOUT) {
666 /*
667 * Indicate any system default.
668 */
669 #ifndef SGS_PRE_UNIFIED_PROCESS
670 (void) printf(MSG_INTL(MSG_DEF_AOUTNEWTD));
671 #else
672 (void) printf(MSG_INTL(MSG_DEF_AOUTOLDTD));
673 #endif
674 }
675 }
676
677 /*
678 * Display any environment variables.
679 */
680 if ((head->ch_version >= RTC_VER_THREE) && head->ch_env) {
681 Rtc_env *envtbl;
682
683 if ((crle->c_flags & CRLE_UPDATE) == 0)
684 (void) printf(MSG_INTL(MSG_ENV_TITLE));
685
686 for (envtbl = (Rtc_env *)(head->ch_env + addr);
687 envtbl->env_str; envtbl++) {
688 const char *str;
689
690 str = (const char *)(envtbl->env_str + addr);
691
692 if (crle->c_flags & CRLE_UPDATE) {
693 if (addenv(crle, str,
694 (envtbl->env_flags | RTC_ENV_CONFIG)) == 0)
695 return (INSCFG_RET_FAIL);
696 } else {
697 const char *pfmt, *sfmt;
698
699 if (envtbl->env_flags & RTC_ENV_PERMANT) {
700 pfmt = MSG_INTL(MSG_ENV_PRM);
701 sfmt = MSG_ORIG(MSG_CMD_PRMENV);
702 } else {
703 pfmt = MSG_INTL(MSG_ENV_RPL);
704 sfmt = MSG_ORIG(MSG_CMD_RPLENV);
705 }
706 (void) printf(pfmt, str);
707 (void) snprintf(_cmd, PATH_MAX, sfmt, str);
708 cmd = strdupa(_cmd);
709 if (aplist_append(&cmdline, cmd,
710 AL_CNT_CRLE) == NULL)
711 return (INSCFG_RET_FAIL);
712 }
713 }
714 }
715
716 /*
717 * Display any filter/filtee associations.
718 */
719 if ((head->ch_version >= RTC_VER_FOUR) && head->ch_fltr) {
720 if ((crle->c_flags & CRLE_UPDATE) == 0) {
721 Rtc_fltr *fltrtbl;
722 Rtc_flte *fltetbl;
723
724 /* LINTED */
725 fltrtbl = (Rtc_fltr *)
726 (CAST_PTRINT(char *, head->ch_fltr) + addr);
727 /* LINTED */
728 fltetbl = (Rtc_flte *)
729 (CAST_PTRINT(char *, head->ch_flte) + addr);
730
731 (void) printf(MSG_INTL(MSG_FLT_TITLE));
732
733 while (fltrtbl->fr_filter) {
734 Rtc_flte *_fltetbl;
735
736 /*
737 * Print the filter and filtee string pair.
738 */
739 (void) printf(MSG_INTL(MSG_FLT_FILTER),
740 (strtbl + fltrtbl->fr_filter),
741 (strtbl + fltrtbl->fr_string));
742
743 /*
744 * Print each filtee.
745 */
746 /* LINTED */
747 for (_fltetbl = (Rtc_flte *)((char *)fltetbl +
748 fltrtbl->fr_filtee); _fltetbl->fe_filtee;
749 _fltetbl++) {
750 (void) printf(MSG_INTL(MSG_FLT_FILTEE),
751 (strtbl + _fltetbl->fe_filtee));
752 }
753 fltrtbl++;
754 }
755 }
756 }
757
758 /*
759 * Display any memory reservations required for any alternative
760 * objects.
761 */
762 if (head->ch_resbgn && ((crle->c_flags & CRLE_UPDATE) == 0))
763 (void) printf(MSG_INTL(MSG_DMP_RESV),
764 (u_longlong_t)head->ch_resbgn,
765 (u_longlong_t)head->ch_resend,
766 (u_longlong_t)(head->ch_resend - head->ch_resbgn));
767
768 /*
769 * If there's no hash table there's nothing else to process.
770 */
771 if (head->ch_hash == 0) {
772 if ((crle->c_flags & CRLE_UPDATE) == 0)
773 printcmd(crle, head, cmdline);
774 return (INSCFG_RET_OK);
775 }
776
777 /*
778 * Traverse the directory and filename arrays.
779 */
780 for (dirtbl = (Rtc_dir *)(head->ch_dir + addr);
781 dirtbl->cd_obj; dirtbl++) {
782 struct stat status;
783 Rtc_obj *dobj;
784 const char *str;
785
786 dobj = (Rtc_obj *)(dirtbl->cd_obj + addr);
787 filetbl = (Rtc_file *)(dirtbl->cd_file + addr);
788 str = strtbl + dobj->co_name;
789
790 /*
791 * Simplify recreation by using any command-line directories.
792 * If we're dealing with a version 1 configuration file use
793 * every directory.
794 */
795 if ((dobj->co_flags & RTC_OBJ_CMDLINE) ||
796 (head->ch_version == RTC_VER_ONE)) {
797 if (crle->c_flags & CRLE_UPDATE) {
798 if (inspect(crle, str,
799 getflags(dobj->co_flags)) != 0)
800 return (INSCFG_RET_FAIL);
801 if ((dobj->co_flags &
802 (RTC_OBJ_NOEXIST | RTC_OBJ_ALTER)) ==
803 RTC_OBJ_NOEXIST)
804 continue;
805 } else {
806 /* LINTED */
807 (void) snprintf(_cmd, PATH_MAX,
808 getformat(dobj->co_flags), str);
809 cmd = strdupa(_cmd);
810 if (aplist_append(&cmdline, cmd,
811 AL_CNT_CRLE) == NULL)
812 return (INSCFG_RET_FAIL);
813 }
814 }
815
816 /*
817 * If this isn't an update print the directory name. If the
818 * directory has no entries (possible if the directory is a
819 * symlink to another directory, in which case we record the
820 * real path also), don't bother printing it unless we're in
821 * verbose mode.
822 */
823 if ((crle->c_flags & CRLE_UPDATE) == 0) {
824 if ((dobj->co_flags &
825 (RTC_OBJ_NOEXIST | RTC_OBJ_ALTER)) ==
826 RTC_OBJ_NOEXIST) {
827 (void) printf(MSG_INTL(MSG_DMP_DIR_2), str);
828 continue;
829 } else if (filetbl->cf_obj ||
830 (crle->c_flags & CRLE_VERBOSE))
831 (void) printf(MSG_INTL(MSG_DMP_DIR_1), str);
832 }
833
834 /*
835 * Under verbose mode validate any real directory entry - the
836 * same test will be carried out by ld.so.1.
837 */
838 if (((crle->c_flags & CRLE_UPDATE) == 0) &&
839 (crle->c_flags & CRLE_VERBOSE) &&
840 (dobj->co_flags & RTC_OBJ_REALPTH)) {
841 if (stat(str, &status) != 0) {
842 int err = errno;
843 (void) printf(MSG_INTL(MSG_DMP_STAT), str,
844 strerror(err));
845 } else if (status.st_mtime != dobj->co_info) {
846 (void) printf(MSG_INTL(MSG_DMP_DCMP), str);
847 }
848 }
849
850 for (; filetbl->cf_obj; filetbl++) {
851 Rtc_obj *fobj;
852 Half flags;
853
854 fobj = (Rtc_obj *)(filetbl->cf_obj + addr);
855 str = strtbl + fobj->co_name;
856 flags = fobj->co_flags;
857
858 /*
859 * Only update individual files that were originally
860 * specified on the command-line. Or, if this is a
861 * version 1 configuration file use every file that
862 * isn't part of an all-entries directory.
863 */
864 if (((flags & RTC_OBJ_CMDLINE) &&
865 ((fobj->co_flags & RTC_OBJ_APP) == 0)) ||
866 ((head->ch_version == RTC_VER_ONE) &&
867 ((dobj->co_flags & RTC_OBJ_ALLENTS) == 0))) {
868 char *alter = NULL, altdir[PATH_MAX];
869
870 /*
871 * Determine whether this file requires an
872 * alternative, and if so, and we haven't
873 * already an alternative in affect, create one.
874 */
875 if (fobj->co_flags & RTC_OBJ_ALTER) {
876 alter = (char *)(strtbl +
877 fobj->co_alter);
878 (void) strcpy(altdir, alter);
879 alter = strrchr(altdir, '/');
880 *alter = '\0';
881
882 if ((objdir == NULL) ||
883 (strcmp(objdir, altdir) != 0)) {
884 (void) strcpy(_objdir, altdir);
885 crle->c_objdir = alter =
886 objdir = _objdir;
887 } else
888 alter = NULL;
889 }
890
891 if (crle->c_flags & CRLE_UPDATE) {
892 if (inspect(crle, str,
893 getflags(flags)) != 0)
894 return (INSCFG_RET_FAIL);
895 continue;
896 }
897
898 if (alter) {
899 (void) snprintf(_cmd, PATH_MAX,
900 MSG_ORIG(MSG_CMD_OUTPUT),
901 crle->c_objdir);
902 cmd = strdupa(_cmd);
903 if (aplist_append(&cmdline, cmd,
904 AL_CNT_CRLE) == NULL)
905 return (INSCFG_RET_FAIL);
906 }
907
908 /* LINTED */
909 (void) snprintf(_cmd, PATH_MAX,
910 getformat(flags), str);
911 cmd = strdupa(_cmd);
912 if (aplist_append(&cmdline, cmd,
913 AL_CNT_CRLE) == NULL)
914 return (INSCFG_RET_FAIL);
915 }
916
917 if (crle->c_flags & CRLE_UPDATE)
918 continue;
919
920 /*
921 * Although we record both full pathnames and their
922 * simple filenames (basename), only print the simple
923 * names unless we're under verbose mode.
924 */
925 if ((strchr(str, '/') == 0) ||
926 (crle->c_flags & CRLE_VERBOSE)) {
927 if (fobj->co_flags & RTC_OBJ_ALTER)
928 (void) printf(MSG_INTL(MSG_DMP_FILE_2),
929 str, (strtbl + fobj->co_alter));
930 else
931 (void) printf(MSG_INTL(MSG_DMP_FILE_1),
932 str);
933 }
934
935 /*
936 * Under verbose mode validate any real file entry - the
937 * same test will be carried out by ld.so.1.
938 */
939 if ((crle->c_flags & CRLE_VERBOSE) &&
940 (fobj->co_flags & RTC_OBJ_REALPTH)) {
941 if (stat(str, &status) != 0) {
942 int err = errno;
943 (void) printf(MSG_INTL(MSG_DMP_STAT),
944 str, strerror(err));
945 } else if (status.st_size != fobj->co_info) {
946 (void) printf(MSG_INTL(MSG_DMP_FCMP),
947 str);
948 }
949 }
950 }
951 }
952
953 if ((crle->c_flags & CRLE_UPDATE) == 0)
954 printcmd(crle, head, cmdline);
955
956 if ((crle->c_flags & CRLE_VERBOSE) == 0)
957 return (INSCFG_RET_OK);
958
959 /*
960 * If we've in verbose mode scan the hash list.
961 */
962 /* LINTED */
963 hash = (Word *)(CAST_PTRINT(char *, head->ch_hash) + addr);
964 bkts = hash[0];
965 chain = &hash[2 + bkts];
966 hash += 2;
967
968 (void) printf(MSG_INTL(MSG_DMP_HASH));
969
970 /*
971 * Scan the hash buckets looking for valid entries.
972 */
973 for (ndx = 0; ndx < bkts; ndx++, hash++) {
974 Conv_config_obj_buf_t config_obj_buf;
975 Rtc_obj *obj;
976 const char *str;
977 Word _ndx;
978
979 if (*hash == NULL)
980 continue;
981
982 obj = objtbl + *hash;
983 str = strtbl + obj->co_name;
984
985 (void) printf(MSG_INTL(MSG_DMP_HASHENT_1), obj->co_id, ndx,
986 str, conv_config_obj(obj->co_flags, &config_obj_buf));
987
988 /*
989 * Determine whether there are other objects chained to this
990 * bucket.
991 */
992 for (_ndx = chain[*hash]; _ndx; _ndx = chain[_ndx]) {
993 obj = objtbl + _ndx;
994 str = strtbl + obj->co_name;
995
996 (void) printf(MSG_INTL(MSG_DMP_HASHENT_2), obj->co_id,
997 str, conv_config_obj(obj->co_flags,
998 &config_obj_buf));
999 }
1000 }
1001 (void) printf(MSG_ORIG(MSG_STR_NL));
1002
1003 return (INSCFG_RET_OK);
1004 }
1005
1006
1007 INSCFG_RET
inspectconfig(Crle_desc * crle,int c_class)1008 inspectconfig(Crle_desc * crle, int c_class)
1009 {
1010 INSCFG_RET error;
1011 int fd;
1012 Addr addr;
1013 struct stat status;
1014 const char *caller = crle->c_name, *file = crle->c_confil;
1015 Conv_inv_buf_t inv_buf1, inv_buf2, inv_buf3;
1016
1017 /*
1018 * Open the configuration file, determine its size and map it in.
1019 */
1020 if ((fd = open(file, O_RDONLY, 0)) == -1) {
1021 int err = errno;
1022
1023 if (err == ENOENT) {
1024 #ifndef _ELF64
1025 /* Must restart if user requested a 64-bit file */
1026 if (c_class == ELFCLASS64)
1027 return (INSCFG_RET_NEED64);
1028 #endif
1029
1030 /*
1031 * To allow an update (-u) from scratch, fabricate any
1032 * default search and secure paths that the user
1033 * intends to add to.
1034 */
1035 if (crle->c_flags & CRLE_UPDATE) {
1036 if (crle->c_flags & CRLE_EDLIB) {
1037 if (fablib(crle, CRLE_EDLIB))
1038 return (INSCFG_RET_FAIL);
1039 }
1040 if (crle->c_flags & CRLE_ESLIB) {
1041 if (fablib(crle, CRLE_ESLIB))
1042 return (INSCFG_RET_FAIL);
1043 }
1044 if (crle->c_flags & CRLE_ADLIB) {
1045 if (fablib(crle, CRLE_ADLIB))
1046 return (INSCFG_RET_FAIL);
1047 }
1048 if (crle->c_flags & CRLE_ASLIB) {
1049 if (fablib(crle, CRLE_ASLIB))
1050 return (INSCFG_RET_FAIL);
1051 }
1052 return (INSCFG_RET_OK);
1053
1054 } else if (crle->c_flags & CRLE_CONFDEF) {
1055 const char *fmt1, *fmt2;
1056
1057 /*
1058 * Otherwise if the user is inspecting a default
1059 * configuration file that doesn't exist inform
1060 * them and display the ELF defaults.
1061 */
1062 (void) printf(MSG_INTL(MSG_DEF_NOCONF), file);
1063 (void) printf(MSG_INTL(MSG_DMP_PLATFORM),
1064 conv_ehdr_class(M_CLASS,
1065 CONV_FMT_ALT_FILE, &inv_buf1),
1066 conv_ehdr_data(M_DATA,
1067 CONV_FMT_ALT_FILE, &inv_buf2),
1068 conv_ehdr_mach(M_MACH,
1069 CONV_FMT_ALT_FILE, &inv_buf3));
1070
1071
1072 if (crle->c_flags & CRLE_AOUT) {
1073 fmt1 = MSG_INTL(MSG_DEF_AOUTDLP);
1074 #ifndef SGS_PRE_UNIFIED_PROCESS
1075 fmt2 = MSG_INTL(MSG_DEF_AOUTNEWTD);
1076 #else
1077 fmt2 = MSG_INTL(MSG_DEF_AOUTOLDTD);
1078 #endif
1079 } else {
1080 #if M_CLASS == ELFCLASS64
1081 #ifndef SGS_PRE_UNIFIED_PROCESS
1082 fmt1 = MSG_INTL(MSG_DEF_NEWDLP_64);
1083 fmt2 = MSG_INTL(MSG_DEF_NEWTD_64);
1084 #else
1085 fmt1 = MSG_INTL(MSG_DEF_OLDDLP_64);
1086 fmt2 = MSG_INTL(MSG_DEF_OLDTD_64);
1087 #endif
1088 #else
1089 #ifndef SGS_PRE_UNIFIED_PROCESS
1090 fmt1 = MSG_INTL(MSG_DEF_NEWDLP);
1091 fmt2 = MSG_INTL(MSG_DEF_NEWTD);
1092 #else
1093 fmt1 = MSG_INTL(MSG_DEF_OLDDLP);
1094 fmt2 = MSG_INTL(MSG_DEF_OLDTD);
1095 #endif
1096 #endif
1097 }
1098 (void) printf(fmt1);
1099 (void) printf(fmt2);
1100
1101 return (INSCFG_RET_OK);
1102 }
1103 }
1104
1105 /*
1106 * Otherwise there's an error condition in accessing the file.
1107 */
1108 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), caller, file,
1109 strerror(err));
1110
1111 return (INSCFG_RET_FAIL);
1112 }
1113
1114 (void) fstat(fd, &status);
1115 if (status.st_size < sizeof (Rtc_head)) {
1116 (void) close(fd);
1117 (void) fprintf(stderr, MSG_INTL(MSG_COR_TRUNC), caller, file);
1118 return (INSCFG_RET_FAIL);
1119 }
1120 if ((addr = (Addr)mmap(0, status.st_size, PROT_READ, MAP_SHARED,
1121 fd, 0)) == (Addr)MAP_FAILED) {
1122 int err = errno;
1123 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP), caller, file,
1124 strerror(err));
1125 (void) close(fd);
1126 return (INSCFG_RET_FAIL);
1127 }
1128 (void) close(fd);
1129
1130 /*
1131 * Print the contents of the configuration file.
1132 */
1133 error = scanconfig(crle, addr, c_class);
1134
1135 (void) munmap((void *)addr, status.st_size);
1136 return (error);
1137 }
1138