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