xref: /illumos-gate/usr/src/cmd/sysdef/sysdef.c (revision b3385a702fe5f8caba5ad4c451836514efff0bfa)
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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 	/*
31 	 * This command can now print the value of data items
32 	 * from [1] /dev/kmem is the default, and [2] a named
33 	 * file passed with the -n argument.  If the read is from
34 	 * /dev/kmem, we also print the value of BSS symbols.
35 	 * The logic to support this is: if read is from file,
36 	 * [1] find the section number of .bss, [2] look through
37 	 * nlist for symbols that are in .bss section and zero
38 	 * the n_value field.  At print time, if the n_value field
39 	 * is non-zero, print the info.
40 	 *
41 	 * This protects us from trying to read a bss symbol from
42 	 * the file and, possibly, dropping core.
43 	 *
44 	 * When reading from /dev/kmem, the n_value field is the
45 	 * seek address, and the contents are read from that address.
46 	 *
47 	 * NOTE: when reading from /dev/kmem, the actual, incore
48 	 * values will be printed, for example: the current nodename
49 	 * will be printed, etc.
50 	 *
51 	 * the cmn line usage is: sysdef -i -n namelist -h -d -D
52 	 * (-i for incore, though this is now the default, the option
53 	 * is left in place for SVID compatibility)
54 	 */
55 #include	<stdio.h>
56 #include	<nlist.h>
57 #include	<string.h>
58 #include	<sys/types.h>
59 #include	<sys/sysmacros.h>
60 #include	<sys/var.h>
61 #include	<sys/tuneable.h>
62 #include	<sys/modctl.h>
63 #include	<sys/fcntl.h>
64 #include	<sys/utsname.h>
65 #include	<sys/resource.h>
66 #include	<sys/conf.h>
67 #include	<sys/stat.h>
68 #include	<sys/signal.h>
69 #include	<sys/priocntl.h>
70 #include	<sys/procset.h>
71 #include	<sys/systeminfo.h>
72 #include	<sys/machelf.h>
73 #include	<dirent.h>
74 #include	<ctype.h>
75 #include	<stdlib.h>
76 #include	<time.h>
77 #include	<unistd.h>
78 #include	<fcntl.h>
79 
80 #include	<libelf.h>
81 
82 extern void sysdef_devinfo(void);
83 
84 static gid_t egid;
85 
86 #define	SYM_VALUE(sym)	(nl[(sym)].n_value)
87 #define	MEMSEEK(sym)	memseek(sym)
88 #define	MEMREAD(var)	fread((char *)&var, sizeof (var), 1, \
89 				(incore ? memfile : sysfile))
90 
91 struct	var	v;
92 struct  tune	tune;
93 
94 int incore = 1;		/* The default is "incore" */
95 int bss;		/* if read from file, don't read bss symbols */
96 int hostidf = 0;	/* 0 == print hostid with other info, */
97 			/* 1 == print just the hostid */
98 int devflag = 0;	/* SunOS4.x devinfo compatible output */
99 int drvname_flag = 0;	/* print the driver name as well as the node */
100 int nflag = 0;
101 char	*os = "/dev/ksyms";	/* Wont always have a /kernel/unix */
102 				/* This wont fully replace it funtionally */
103 				/* but is a reasonable default/placeholder */
104 
105 char	*mem = "/dev/kmem";
106 
107 int	nstrpush;
108 ssize_t	strmsgsz, strctlsz;
109 short	ts_maxupri;
110 char 	sys_name[10];
111 int	nlsize, lnsize;
112 FILE	*sysfile, *memfile;
113 
114 void	setln(char *, int, int, int);
115 void	getnlist(void);
116 void	memseek(int);
117 void	devices(void);
118 void	sysdev(void);
119 int	setup(char *);
120 void	modules(void);
121 
122 struct nlist	*nl, *nlptr;
123 int vs, tu, utsnm, bdev, pnstrpush,
124     pstrmsgsz, pstrctlsz, endnm,
125     pts_maxupri, psys_name, fd_cur, fd_max;
126 
127 #define	MAXI	300
128 #define	MAXL	MAXI/11+10
129 #define	EXPAND	99
130 
131 struct	link {
132 	char	*l_cfnm;	/* config name from master table */
133 	int l_funcidx;		/* index into name list structure */
134 	unsigned int l_soft :1;	/* software driver flag from master table */
135 	unsigned int l_dtype:1;	/* set if block device */
136 	unsigned int l_used :1;	/* set when device entry is printed */
137 } *ln, *lnptr, *majsrch();
138 
139 	/* ELF Items */
140 Elf *elfd = NULL;
141 Ehdr *ehdr = NULL;
142 
143 #ifdef _ELF64
144 #define	elf_getehdr elf64_getehdr
145 #define	elf_getshdr elf64_getshdr
146 #else
147 #define	elf_getehdr elf32_getehdr
148 #define	elf_getshdr elf32_getshdr
149 #endif
150 
151 /* This procedure checks if module "name" is currently loaded */
152 
153 int
154 loaded_mod(const char *name)
155 {
156 	struct modinfo modinfo;
157 
158 	/* mi_nextid of -1 means we're getting info on all modules */
159 	modinfo.mi_id = modinfo.mi_nextid = -1;
160 	modinfo.mi_info = MI_INFO_ALL;
161 
162 	while (modctl(MODINFO, modinfo.mi_id, &modinfo) >= 0)
163 		if (strcmp(modinfo.mi_name, name) == 0)
164 			return (1);
165 
166 	return (0);
167 }
168 
169 const char *sysv_transition =
170 	"*\n* IPC %s\n*\n"
171 	"* The IPC %s module no longer has system-wide limits.\n"
172 	"* Please see the \"Solaris Tunable Parameters Reference Manual\" for\n"
173 	"* information on how the old limits map to resource controls and\n"
174 	"* the prctl(1) and getrctl(2) manual pages for information on\n"
175 	"* observing the new limits.\n*\n";
176 
177 const char *sysv_notloaded =
178 	"*\n* IPC %s module is not loaded\n*\n";
179 
180 /*
181  * Emit a message pointing script writers to the new source for
182  * System V IPC information.
183  */
184 void
185 sysvipc(const char *module, const char *name)
186 {
187 	if (loaded_mod(module))
188 		(void) printf(sysv_transition, name, name);
189 	else
190 		(void) printf(sysv_notloaded, name);
191 }
192 
193 int
194 main(int argc, char *argv[])
195 {
196 	struct	utsname utsname;
197 	Elf_Scn *scn;
198 	Shdr *shdr;
199 	char *name;
200 	int ndx;
201 	int i;
202 	char hostid[256], *end;
203 	unsigned long hostval;
204 	uint_t	rlim_fd_cur, rlim_fd_max;
205 
206 	egid = getegid();
207 	setegid(getgid());
208 
209 	while ((i = getopt(argc, argv, "dihDn:?")) != EOF) {
210 		switch (i) {
211 		case 'D':
212 			drvname_flag++;
213 			break;
214 		case 'd':
215 			devflag++;
216 			break;
217 		case 'h':
218 			hostidf++;
219 			break;
220 		case 'i':
221 			incore++;	/* In case "-i and -n" passed */
222 			break;		/* Not logical, but not disallowed */
223 		case 'n':
224 			nflag = 1;
225 			incore--;	/* Not incore, use specified file */
226 			os = optarg;
227 			break;
228 		default:
229 			fprintf(stderr,
230 				"usage: %s [-D -d -i -h -n namelist]\n",
231 					argv[0]);
232 			return (1);
233 		}
234 	}
235 
236 	/*
237 	 * Prints hostid of machine.
238 	 */
239 	if (sysinfo(SI_HW_SERIAL, hostid, sizeof (hostid)) == -1) {
240 		fprintf(stderr, "hostid: sysinfo failed\n");
241 		return (1);
242 	}
243 	hostval = strtoul(hostid, &end, 10);
244 	if (hostval == 0 && end == hostid) {
245 		fprintf(stderr, "hostid: hostid string returned by "
246 		    "sysinfo not numeric: \"%s\"\n", hostid);
247 		return (1);
248 	}
249 	if (!devflag)
250 		fprintf(stdout, "*\n* Hostid\n*\n  %8.8x\n", hostval);
251 
252 	if (hostidf)
253 		return (0);
254 
255 	if (((sysfile = fopen(os, "r")) == NULL) && nflag) {
256 		fprintf(stderr, "cannot open %s\n", os);
257 		return (1);
258 	}
259 
260 	if (sysfile) {
261 		if (incore) {
262 			int memfd;
263 
264 			setegid(egid);
265 			if ((memfile = fopen(mem, "r")) == NULL) {
266 				fprintf(stderr, "cannot open %s\n", mem);
267 				return (1);
268 			}
269 			setegid(getgid());
270 
271 			memfd = fileno(memfile);
272 			fcntl(memfd, F_SETFD,
273 			    fcntl(memfd, F_GETFD, 0) | FD_CLOEXEC);
274 		}
275 
276 		/*
277 		 *	Use libelf to read both COFF and ELF namelists
278 		 */
279 
280 		if ((elf_version(EV_CURRENT)) == EV_NONE) {
281 			fprintf(stderr, "ELF Access Library out of date\n");
282 			return (1);
283 		}
284 
285 		if ((elfd = elf_begin(fileno(sysfile), ELF_C_READ,
286 		    NULL)) == NULL) {
287 			fprintf(stderr, "Unable to elf begin %s (%s)\n",
288 				os, elf_errmsg(-1));
289 			return (1);
290 		}
291 
292 		if ((ehdr = elf_getehdr(elfd)) == NULL) {
293 			fprintf(stderr, "%s: Can't read Exec header (%s)\n",
294 				os, elf_errmsg(-1));
295 			return (1);
296 		}
297 
298 		if ((((elf_kind(elfd)) != ELF_K_ELF) &&
299 		    ((elf_kind(elfd)) != ELF_K_COFF)) ||
300 		    (ehdr->e_type != ET_EXEC)) {
301 			fprintf(stderr, "%s: invalid file\n", os);
302 			elf_end(elfd);
303 			return (1);
304 		}
305 
306 		/*
307 		 *	If this is a file read, look for .bss section
308 		 */
309 
310 		if (!incore) {
311 			ndx = 1;
312 			scn = NULL;
313 			while ((scn = elf_nextscn(elfd, scn)) != NULL) {
314 				if ((shdr = elf_getshdr(scn)) == NULL) {
315 					fprintf(stderr,
316 					    "%s: Error reading Shdr (%s)\n",
317 					    os, elf_errmsg(-1));
318 					return (1);
319 				}
320 				name = elf_strptr(elfd, ehdr->e_shstrndx,
321 				    (size_t)shdr->sh_name);
322 				if ((name) && ((strcmp(name, ".bss")) == 0)) {
323 					bss = ndx;
324 				}
325 				ndx++;
326 			}
327 		} /* (!incore) */
328 	}
329 
330 	uname(&utsname);
331 	if (!devflag)
332 		printf("*\n* %s Configuration\n*\n", utsname.machine);
333 
334 	if (sysfile) {
335 		nlsize = MAXI;
336 		lnsize = MAXL;
337 		nl = (struct nlist *)calloc(nlsize, sizeof (struct nlist));
338 		ln = (struct link *)calloc(lnsize, sizeof (struct link));
339 		nlptr = nl;
340 		lnptr = ln;
341 
342 		bdev = setup("bdevsw");
343 		setup("");
344 
345 		getnlist();
346 
347 		if (!devflag)
348 			printf("*\n* Devices\n*\n");
349 		devices();
350 		if (devflag)
351 			return (0);
352 
353 		printf("*\n* Loadable Objects\n");
354 
355 		modules();
356 	}
357 
358 	printf("*\n* System Configuration\n*\n");
359 
360 	sysdev();
361 
362 	if (sysfile) {
363 		/* easy stuff */
364 		printf("*\n* Tunable Parameters\n*\n");
365 		nlptr = nl;
366 		vs = setup("v");
367 		tu = setup("tune");
368 		utsnm = setup("utsname");
369 		pnstrpush = setup("nstrpush");
370 		pstrmsgsz = setup("strmsgsz");
371 		pstrctlsz = setup("strctlsz");
372 		pts_maxupri = setup("ts_maxupri");
373 		psys_name = setup("sys_name");
374 		fd_cur = setup("rlim_fd_cur");
375 		fd_max = setup("rlim_fd_max");
376 
377 		/*
378 		 * This assignment to endnm must follow all calls to setup().
379 		 */
380 		endnm = setup("");
381 
382 		getnlist();
383 
384 		for (nlptr = &nl[vs]; nlptr != &nl[endnm]; nlptr++) {
385 			if (nlptr->n_value == 0 &&
386 			    (incore || nlptr->n_scnum != bss)) {
387 				fprintf(stderr, "namelist error on <%s>\n",
388 				    nlptr->n_name);
389 				/* return (1); */
390 			}
391 		}
392 		if (SYM_VALUE(vs)) {
393 			MEMSEEK(vs);
394 			MEMREAD(v);
395 		}
396 		printf("%8d	maximum memory allowed in buffer cache "
397 		    "(bufhwm)\n", v.v_bufhwm * 1024);
398 		printf("%8d	maximum number of processes (v.v_proc)\n",
399 		    v.v_proc);
400 		printf("%8d	maximum global priority in sys class "
401 		    "(MAXCLSYSPRI)\n", v.v_maxsyspri);
402 		printf("%8d	maximum processes per user id (v.v_maxup)\n",
403 		    v.v_maxup);
404 		printf("%8d	auto update time limit in seconds (NAUTOUP)\n",
405 		    v.v_autoup);
406 		if (SYM_VALUE(tu)) {
407 			MEMSEEK(tu);
408 			MEMREAD(tune);
409 		}
410 		printf("%8d	page stealing low water mark (GPGSLO)\n",
411 		    tune.t_gpgslo);
412 		printf("%8d	fsflush run rate (FSFLUSHR)\n",
413 		    tune.t_fsflushr);
414 		printf("%8d	minimum resident memory for avoiding "
415 		    "deadlock (MINARMEM)\n", tune.t_minarmem);
416 		printf("%8d	minimum swapable memory for avoiding deadlock "
417 		    "(MINASMEM)\n", tune.t_minasmem);
418 	}
419 
420 	printf("*\n* Utsname Tunables\n*\n");
421 	if (sysfile && SYM_VALUE(utsnm)) {
422 		MEMSEEK(utsnm);
423 		MEMREAD(utsname);
424 	}
425 	printf("%8s  release (REL)\n", utsname.release);
426 	printf("%8s  node name (NODE)\n", utsname.nodename);
427 	printf("%8s  system name (SYS)\n", utsname.sysname);
428 	printf("%8s  version (VER)\n", utsname.version);
429 
430 	if (sysfile) {
431 		printf("*\n* Process Resource Limit Tunables "
432 		    "(Current:Maximum)\n*\n");
433 		if (SYM_VALUE(fd_cur)) {
434 			MEMSEEK(fd_cur);
435 			MEMREAD(rlim_fd_cur);
436 		}
437 		if (SYM_VALUE(fd_max)) {
438 			MEMSEEK(fd_max);
439 			MEMREAD(rlim_fd_max);
440 		}
441 
442 		printf("0x%16.16x:", rlim_fd_cur);
443 		printf("0x%16.16x", rlim_fd_max);
444 		printf("\tfile descriptors\n");
445 
446 		printf("*\n* Streams Tunables\n*\n");
447 		if (SYM_VALUE(pnstrpush)) {
448 			MEMSEEK(pnstrpush);	MEMREAD(nstrpush);
449 			printf("%6d	maximum number of pushes allowed "
450 			    "(NSTRPUSH)\n", nstrpush);
451 		}
452 		if (SYM_VALUE(pstrmsgsz)) {
453 			MEMSEEK(pstrmsgsz);	MEMREAD(strmsgsz);
454 			printf("%6ld	maximum stream message size "
455 			    "(STRMSGSZ)\n", strmsgsz);
456 		}
457 		if (SYM_VALUE(pstrctlsz)) {
458 			MEMSEEK(pstrctlsz);	MEMREAD(strctlsz);
459 			printf("%6ld	max size of ctl part of message "
460 			    "(STRCTLSZ)\n", strctlsz);
461 		}
462 	}
463 
464 	sysvipc("msgsys", "Messages");
465 	sysvipc("semsys", "Semaphores");
466 	sysvipc("shmsys", "Shared Memory");
467 
468 	if (sysfile) {
469 		if (SYM_VALUE(pts_maxupri)) {
470 			printf("*\n* Time Sharing Scheduler Tunables\n*\n");
471 			MEMSEEK(pts_maxupri);	MEMREAD(ts_maxupri);
472 			printf("%d	maximum time sharing user "
473 			    "priority (TSMAXUPRI)\n", ts_maxupri);
474 		}
475 
476 		if (SYM_VALUE(psys_name)) {
477 			MEMSEEK(psys_name);	MEMREAD(sys_name);
478 			printf("%s	system class name (SYS_NAME)\n",
479 			    sys_name);
480 		}
481 
482 		if (elfd)
483 			elf_end(elfd);
484 	}
485 	return (0);
486 }
487 
488 /*
489  * setup - add an entry to a namelist structure array
490  */
491 int
492 setup(char *nam)
493 {
494 	int idx;
495 
496 	if (nlptr >= &nl[nlsize]) {
497 		if ((nl = (struct nlist *)realloc(nl,
498 		    (nlsize + EXPAND) * sizeof (struct nlist))) == NULL) {
499 			fprintf(stderr, "Namelist space allocation failed\n");
500 			exit(1);
501 		}
502 		nlptr = &nl[nlsize];
503 		nlsize += EXPAND;
504 	}
505 
506 	nlptr->n_name = malloc(strlen(nam) + 1); /* pointer to next string */
507 	strcpy(nlptr->n_name, nam);	/* move name into string table */
508 	nlptr->n_type = 0;
509 	nlptr->n_value = 0;
510 	idx = nlptr++ - nl;
511 	return (idx);
512 }
513 
514 /*
515  * Handle the configured devices
516  */
517 void
518 devices(void)
519 {
520 	setegid(egid);
521 	sysdef_devinfo();
522 	setegid(getgid());
523 }
524 
525 char	*LS_MODULES = "/bin/ls -R -p -i -1 ";
526 char	*MODULES_TMPFILE = "/tmp/sysdef.sort.XXXXXX";
527 
528 void
529 modules()
530 {
531 	int i;
532 	int n_dirs = 0;
533 	ino_t *inodes;
534 	char *curr, *next;
535 	char **dirs;
536 	char *modpath, *ls_cmd;
537 	char *tmpf;
538 	int curr_len, modpathlen;
539 	int ls_cmd_len = strlen(LS_MODULES);
540 	int sfd;
541 
542 	if ((modctl(MODGETPATHLEN, NULL, &modpathlen)) != 0) {
543 		fprintf(stderr, "sysdef: fail to get module path length\n");
544 		exit(1);
545 	}
546 	if ((modpath = malloc(modpathlen + 1)) == NULL) {
547 		fprintf(stderr, "sysdef: malloc failed\n");
548 		exit(1);
549 	}
550 	if (modctl(MODGETPATH, NULL, modpath) != 0) {
551 		fprintf(stderr, "sysdef: fail to get module path\n");
552 		exit(1);
553 	}
554 
555 	/*
556 	 * Figure out number of directory entries in modpath.
557 	 * Module paths are stored in a space separated string
558 	 */
559 	curr = modpath;
560 	while (curr) {
561 		n_dirs++;
562 		curr = strchr(curr + 1, ' ');
563 	}
564 
565 	if (((inodes = (ino_t *)malloc(n_dirs * sizeof (ino_t))) == NULL) ||
566 	    ((dirs = (char **)malloc(n_dirs * sizeof (char *))) == NULL)) {
567 		fprintf(stderr, "sysdef: malloc failed\n");
568 		exit(1);
569 	}
570 
571 	if ((tmpf = malloc(strlen(MODULES_TMPFILE) + 1)) == NULL) {
572 		fprintf(stderr, "sysdef: malloc failed\n");
573 		exit(1);
574 	}
575 
576 	curr = modpath;
577 	for (i = 0; i < n_dirs; i++) {
578 		int j, len, inode, ino;
579 		char line[100], path[100], *pathptr = "";
580 		char srtbuf[100], *sorted_fname;
581 		FILE *lspipe, *srtpipe, *fp;
582 		struct stat stat_buf;
583 
584 		if (next = strchr(curr, ' ')) {
585 			*next = '\0';
586 		}
587 
588 		/*
589 		 * Make sure the module path is present.
590 		 */
591 		if (stat(curr, &stat_buf) == -1) {
592 			curr = next ? next + 1 : NULL;
593 			inodes[i] = (ino_t)-1;
594 			continue;
595 		}
596 
597 		/*
598 		 * On sparcs, /platform/SUNW,... can be symbolic link to
599 		 * /platform/sun4x. We check the inode number of directory
600 		 * and skip any duplication.
601 		 */
602 		dirs[i] = curr;
603 		inodes[i] = stat_buf.st_ino;
604 
605 		for (j = 0; inodes[i] != inodes[j]; j++)
606 			;
607 		if (j != i) {
608 			curr = next ? next + 1 : NULL;
609 			continue;
610 		}
611 
612 		printf("*\n* Loadable Object Path = %s\n*\n", curr);
613 
614 		curr_len = strlen(curr);
615 		if ((ls_cmd = malloc(ls_cmd_len + curr_len + 1)) == NULL) {
616 			fprintf(stderr, "sysdef: malloc failed\n");
617 			exit(1);
618 		}
619 
620 		(void) sprintf(ls_cmd, "%s%s", LS_MODULES, curr);
621 
622 		/*
623 		 * List the loadable objects in the directory tree, sorting
624 		 * them by inode so as to note any hard links.  A temporary
625 		 * file in /tmp  is used to store output from sort before
626 		 * listing.
627 		 */
628 		if ((lspipe = popen(ls_cmd, "r")) == NULL) {
629 			fprintf(stderr, "sysdef: cannot open ls pipe\n");
630 			exit(1);
631 		}
632 		free(ls_cmd);
633 
634 		(void) strcpy(tmpf, MODULES_TMPFILE);
635 		if ((sorted_fname = mktemp(tmpf)) == NULL ||
636 		    (strcmp(sorted_fname, "") == 0)) {
637 			fprintf(stderr,
638 			    "sysdef: cannot create unique tmp file name\n");
639 			exit(1);
640 		}
641 
642 		if ((sfd = open(sorted_fname, O_RDWR|O_CREAT|O_EXCL,
643 		    0600)) == -1) {
644 			fprintf(stderr, "sysdef: cannot open %s\n",
645 			    sorted_fname);
646 			exit(1);
647 		}
648 
649 		sprintf(srtbuf, "/bin/sort - > %s", sorted_fname);
650 		if ((srtpipe = popen(srtbuf, "w")) == NULL) {
651 			fprintf(stderr, "sysdef: cannot open sort pipe\n");
652 			exit(1);
653 		}
654 
655 		while (fgets(line, 99, lspipe) != NULL) {
656 			char *tmp;
657 			/*
658 			 * 'line' has <cr>, skip blank lines & dir entries
659 			 */
660 			if (((len = strlen(line)) <= 1) ||
661 			    (line[len-2] == '/'))
662 				continue;
663 
664 			/* remember path of each subdirectory */
665 
666 			if (line[0] == '/') {
667 				(void) strcpy(path, &line[curr_len]);
668 				tmp = strtok(&path[1], ":");
669 				if ((tmp == NULL) || (tmp[0] == '\n')) {
670 					continue;
671 				}
672 				pathptr = &path[1];
673 				(void) strcat(pathptr, "/");
674 				continue;
675 			} else {
676 				char *tmp1 = strtok(line, " ");
677 				tmp = strtok(NULL, "\n");
678 				/*
679 				 * eliminate .conf file
680 				 */
681 				if (strstr(tmp, ".conf")) {
682 					continue;
683 				}
684 				/*
685 				 * Printing the (inode, path, module)
686 				 * ripple.
687 				 */
688 				fprintf(srtpipe, "%s %s%s\n",
689 				    tmp1, pathptr, tmp);
690 			}
691 		}
692 		(void) pclose(lspipe);
693 		(void) pclose(srtpipe);
694 
695 		/*
696 		 * A note on data synchronization. We opened sfd above,
697 		 * before calling popen, to ensure that the tempfile
698 		 * was created exclusively to prevent a malicious user
699 		 * from creating a link in /tmp to make us overwrite
700 		 * another file. We have never read from sfd, there
701 		 * can be no stale data cached anywhere.
702 		 */
703 		if ((fp = fdopen(sfd, "r")) == NULL) {
704 			fprintf(stderr, "sysdef: cannot open sorted file: %s",
705 			    sorted_fname);
706 			exit(1);
707 		}
708 		inode = -1;
709 		while (fgets(line, 99, fp) != NULL) {
710 
711 			sscanf(line, "%d %s",  &ino, path);
712 			if (ino == inode)
713 				printf("\thard link:  ");
714 			printf("%s\n", path);
715 			inode = ino;
716 		}
717 		(void) fclose(fp);
718 		(void) unlink(sorted_fname);
719 		curr = next ? next + 1 : NULL;
720 	}
721 	free(tmpf);
722 	free(modpath);
723 }
724 
725 void
726 sysdev(void)
727 {
728 	printf("  swap files\n");
729 	fflush(stdout);
730 	if (system("/usr/sbin/swap -l") < 0)
731 		fprintf(stderr, "unknown swap file(s)\n");
732 }
733 
734 void
735 memseek(int sym)
736 {
737 	Elf_Scn *scn;
738 	Shdr *eshdr;
739 	long eoff;
740 
741 	if (incore) {
742 		if ((fseek(memfile, nl[sym].n_value, 0)) != 0) {
743 			fprintf(stderr, "%s: fseek error (in memseek)\n", mem);
744 			exit(1);
745 		}
746 	} else {
747 		if ((scn = elf_getscn(elfd, nl[sym].n_scnum)) == NULL) {
748 			fprintf(stderr, "%s: Error reading Scn %d (%s)\n",
749 				os, nl[sym].n_scnum, elf_errmsg(-1));
750 			exit(1);
751 		}
752 
753 		if ((eshdr = elf_getshdr(scn)) == NULL) {
754 			fprintf(stderr, "%s: Error reading Shdr %d (%s)\n",
755 				os, nl[sym].n_scnum, elf_errmsg(-1));
756 			exit(1);
757 		}
758 
759 		eoff = (long)(nl[sym].n_value - eshdr->sh_addr +
760 		    eshdr->sh_offset);
761 
762 		if ((fseek(sysfile, eoff, 0)) != 0) {
763 			fprintf(stderr, "%s: fseek error (in memseek)\n", os);
764 			exit(1);
765 		}
766 	}
767 }
768 
769 /*
770  * filter out bss symbols if the reads are from the file
771  */
772 void
773 getnlist(void)
774 {
775 	struct nlist *p;
776 
777 	nlist(os, nl);
778 
779 	/*
780 	 * The nlist is done. If any symbol is a bss
781 	 * and we are not reading from incore, zero
782 	 * the n_value field. (Won't be printed if
783 	 * n_value == 0.)
784 	 */
785 	if (!incore) {
786 		for (p = nl; p->n_name && p->n_name[0]; p++) {
787 			if (p->n_scnum == bss) {
788 				p->n_value = 0;
789 			}
790 		}
791 	}
792 }
793