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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
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.
43 * This protects us from trying to read a bss symbol from
44 * the file and, possibly, dropping core.
46 * When reading from /dev/kmem, the n_value field is the
47 * seek address, and the contents are read from that address.
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.
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)
60 #include <sys/types.h>
61 #include <sys/sysmacros.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>
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>
84 extern void sysdef_devinfo(void);
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))
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 */
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 */
107 char *mem
= "/dev/kmem";
110 ssize_t strmsgsz
, strctlsz
;
114 FILE *sysfile
, *memfile
;
116 void setln(char *, int, int, int);
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
;
130 #define MAXL MAXI/11+10
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();
146 #define elf_getehdr elf64_getehdr
147 #define elf_getshdr elf64_getshdr
149 #define elf_getehdr elf32_getehdr
150 #define elf_getshdr elf32_getshdr
153 /* This procedure checks if module "name" is currently loaded */
156 loaded_mod(const char *name
)
158 struct modinfo modinfo
;
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
;
164 while (modctl(MODINFO
, modinfo
.mi_id
, &modinfo
) >= 0)
165 if (strcmp(modinfo
.mi_name
, name
) == 0)
171 const char *sysv_transition
=
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";
179 const char *sysv_notloaded
=
180 "*\n* IPC %s module is not loaded\n*\n";
183 * Emit a message pointing script writers to the new source for
184 * System V IPC information.
187 sysvipc(const char *module
, const char *name
)
189 if (loaded_mod(module
))
190 (void) printf(sysv_transition
, name
, name
);
192 (void) printf(sysv_notloaded
, name
);
196 main(int argc
, char *argv
[])
198 struct utsname utsname
;
204 char hostid
[256], *end
;
205 unsigned long hostval
;
206 uint_t rlim_fd_cur
, rlim_fd_max
;
211 while ((i
= getopt(argc
, argv
, "dihDn:?")) != EOF
) {
223 incore
++; /* In case "-i and -n" passed */
224 break; /* Not logical, but not disallowed */
227 incore
--; /* Not incore, use specified file */
232 "usage: %s [-D -d -i -h -n namelist]\n",
239 * Prints hostid of machine.
241 if (sysinfo(SI_HW_SERIAL
, hostid
, sizeof (hostid
)) == -1) {
242 fprintf(stderr
, "hostid: sysinfo failed\n");
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
);
252 fprintf(stdout
, "*\n* Hostid\n*\n %8.8x\n", hostval
);
257 if (((sysfile
= fopen(os
, "r")) == NULL
) && nflag
) {
258 fprintf(stderr
, "cannot open %s\n", os
);
267 if ((memfile
= fopen(mem
, "r")) == NULL
) {
268 fprintf(stderr
, "cannot open %s\n", mem
);
273 memfd
= fileno(memfile
);
274 fcntl(memfd
, F_SETFD
,
275 fcntl(memfd
, F_GETFD
, 0) | FD_CLOEXEC
);
279 * Use libelf to read both COFF and ELF namelists
282 if ((elf_version(EV_CURRENT
)) == EV_NONE
) {
283 fprintf(stderr
, "ELF Access Library out of date\n");
287 if ((elfd
= elf_begin(fileno(sysfile
), ELF_C_READ
,
289 fprintf(stderr
, "Unable to elf begin %s (%s)\n",
294 if ((ehdr
= elf_getehdr(elfd
)) == NULL
) {
295 fprintf(stderr
, "%s: Can't read Exec header (%s)\n",
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
);
309 * If this is a file read, look for .bss section
315 while ((scn
= elf_nextscn(elfd
, scn
)) != NULL
) {
316 if ((shdr
= elf_getshdr(scn
)) == NULL
) {
318 "%s: Error reading Shdr (%s)\n",
322 name
= elf_strptr(elfd
, ehdr
->e_shstrndx
,
323 (size_t)shdr
->sh_name
);
324 if ((name
) && ((strcmp(name
, ".bss")) == 0)) {
334 printf("*\n* %s Configuration\n*\n", utsname
.machine
);
339 nl
= (struct nlist
*)calloc(nlsize
, sizeof (struct nlist
));
340 ln
= (struct link
*)calloc(lnsize
, sizeof (struct link
));
344 bdev
= setup("bdevsw");
350 printf("*\n* Devices\n*\n");
355 printf("*\n* Loadable Objects\n");
360 printf("*\n* System Configuration\n*\n");
366 printf("*\n* Tunable Parameters\n*\n");
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");
380 * This assignment to endnm must follow all calls to setup().
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",
398 printf("%10ld maximum memory allowed in buffer cache "
399 "(bufhwm)\n", v
.v_bufhwm
* 1024);
400 printf("%10d maximum number of processes (v.v_proc)\n",
402 printf("%10d maximum global priority in sys class "
403 "(MAXCLSYSPRI)\n", v
.v_maxsyspri
);
404 printf("%10d maximum processes per user id (v.v_maxup)\n",
406 printf("%10d auto update time limit in seconds (NAUTOUP)\n",
412 printf("%10d page stealing low water mark (GPGSLO)\n",
414 printf("%10d fsflush run rate (FSFLUSHR)\n",
416 printf("%10d minimum resident memory for avoiding "
417 "deadlock (MINARMEM)\n", tune
.t_minarmem
);
418 printf("%10d minimum swapable memory for avoiding deadlock "
419 "(MINASMEM)\n", tune
.t_minasmem
);
422 printf("*\n* Utsname Tunables\n*\n");
423 if (sysfile
&& SYM_VALUE(utsnm
)) {
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
);
433 printf("*\n* Process Resource Limit Tunables "
434 "(Current:Maximum)\n*\n");
435 if (SYM_VALUE(fd_cur
)) {
437 MEMREAD(rlim_fd_cur
);
439 if (SYM_VALUE(fd_max
)) {
441 MEMREAD(rlim_fd_max
);
444 printf("0x%16.16x:", rlim_fd_cur
);
445 printf("0x%16.16x", rlim_fd_max
);
446 printf("\tfile descriptors\n");
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
);
454 if (SYM_VALUE(pstrmsgsz
)) {
455 MEMSEEK(pstrmsgsz
); MEMREAD(strmsgsz
);
456 printf("%6ld maximum stream message size "
457 "(STRMSGSZ)\n", strmsgsz
);
459 if (SYM_VALUE(pstrctlsz
)) {
460 MEMSEEK(pstrctlsz
); MEMREAD(strctlsz
);
461 printf("%6ld max size of ctl part of message "
462 "(STRCTLSZ)\n", strctlsz
);
466 sysvipc("msgsys", "Messages");
467 sysvipc("semsys", "Semaphores");
468 sysvipc("shmsys", "Shared Memory");
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
);
478 if (SYM_VALUE(psys_name
)) {
479 MEMSEEK(psys_name
); MEMREAD(sys_name
);
480 printf("%s system class name (SYS_NAME)\n",
491 * setup - add an entry to a namelist structure array
498 if (nlptr
>= &nl
[nlsize
]) {
499 if ((nl
= reallocarray(nl
, nlsize
+ EXPAND
,
500 sizeof (struct nlist
))) == NULL
) {
501 fprintf(stderr
, "Namelist space allocation failed\n");
508 nlptr
->n_name
= malloc(strlen(nam
) + 1); /* pointer to next string */
509 strcpy(nlptr
->n_name
, nam
); /* move name into string table */
517 * Handle the configured devices
527 char *LS_MODULES
= "/bin/ls -R -p -i -1 ";
528 char *MODULES_TMPFILE
= "/tmp/sysdef.sort.XXXXXX";
538 char *modpath
, *ls_cmd
;
540 int curr_len
, modpathlen
;
541 int ls_cmd_len
= strlen(LS_MODULES
);
544 if ((modctl(MODGETPATHLEN
, NULL
, &modpathlen
)) != 0) {
545 fprintf(stderr
, "sysdef: fail to get module path length\n");
548 if ((modpath
= malloc(modpathlen
+ 1)) == NULL
) {
549 fprintf(stderr
, "sysdef: malloc failed\n");
552 if (modctl(MODGETPATH
, NULL
, modpath
) != 0) {
553 fprintf(stderr
, "sysdef: fail to get module path\n");
558 * Figure out number of directory entries in modpath.
559 * Module paths are stored in a space separated string
564 curr
= strchr(curr
+ 1, ' ');
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");
573 if ((tmpf
= malloc(strlen(MODULES_TMPFILE
) + 1)) == NULL
) {
574 fprintf(stderr
, "sysdef: malloc failed\n");
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
;
586 if (next
= strchr(curr
, ' ')) {
591 * Make sure the module path is present.
593 if (stat(curr
, &stat_buf
) == -1) {
594 curr
= next
? next
+ 1 : NULL
;
595 inodes
[i
] = (ino_t
)-1;
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.
605 inodes
[i
] = stat_buf
.st_ino
;
607 for (j
= 0; inodes
[i
] != inodes
[j
]; j
++)
610 curr
= next
? next
+ 1 : NULL
;
614 printf("*\n* Loadable Object Path = %s\n*\n", curr
);
616 curr_len
= strlen(curr
);
617 if ((ls_cmd
= malloc(ls_cmd_len
+ curr_len
+ 1)) == NULL
) {
618 fprintf(stderr
, "sysdef: malloc failed\n");
622 (void) sprintf(ls_cmd
, "%s%s", LS_MODULES
, curr
);
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
630 if ((lspipe
= popen(ls_cmd
, "r")) == NULL
) {
631 fprintf(stderr
, "sysdef: cannot open ls pipe\n");
636 (void) strcpy(tmpf
, MODULES_TMPFILE
);
637 if ((sorted_fname
= mktemp(tmpf
)) == NULL
||
638 (strcmp(sorted_fname
, "") == 0)) {
640 "sysdef: cannot create unique tmp file name\n");
644 if ((sfd
= open(sorted_fname
, O_RDWR
|O_CREAT
|O_EXCL
,
646 fprintf(stderr
, "sysdef: cannot open %s\n",
651 sprintf(srtbuf
, "/bin/sort - > %s", sorted_fname
);
652 if ((srtpipe
= popen(srtbuf
, "w")) == NULL
) {
653 fprintf(stderr
, "sysdef: cannot open sort pipe\n");
657 while (fgets(line
, 99, lspipe
) != NULL
) {
660 * 'line' has <cr>, skip blank lines & dir entries
662 if (((len
= strlen(line
)) <= 1) ||
663 (line
[len
-2] == '/'))
666 /* remember path of each subdirectory */
668 if (line
[0] == '/') {
669 (void) strcpy(path
, &line
[curr_len
]);
670 tmp
= strtok(&path
[1], ":");
671 if ((tmp
== NULL
) || (tmp
[0] == '\n')) {
675 (void) strcat(pathptr
, "/");
678 char *tmp1
= strtok(line
, " ");
679 tmp
= strtok(NULL
, "\n");
681 * eliminate .conf file
683 if (strstr(tmp
, ".conf")) {
687 * Printing the (inode, path, module)
690 fprintf(srtpipe
, "%s %s%s\n",
694 (void) pclose(lspipe
);
695 (void) pclose(srtpipe
);
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.
705 if ((fp
= fdopen(sfd
, "r")) == NULL
) {
706 fprintf(stderr
, "sysdef: cannot open sorted file: %s",
711 while (fgets(line
, 99, fp
) != NULL
) {
713 sscanf(line
, "%d %s", &ino
, path
);
715 printf("\thard link: ");
716 printf("%s\n", path
);
720 (void) unlink(sorted_fname
);
721 curr
= next
? next
+ 1 : NULL
;
730 printf(" swap files\n");
732 if (system("/usr/sbin/swap -l") < 0)
733 fprintf(stderr
, "unknown swap file(s)\n");
744 if ((fseek(memfile
, nl
[sym
].n_value
, 0)) != 0) {
745 fprintf(stderr
, "%s: fseek error (in memseek)\n", mem
);
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));
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));
761 eoff
= (long)(nl
[sym
].n_value
- eshdr
->sh_addr
+
764 if ((fseek(sysfile
, eoff
, 0)) != 0) {
765 fprintf(stderr
, "%s: fseek error (in memseek)\n", os
);
772 * filter out bss symbols if the reads are from the file
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
788 for (p
= nl
; p
->n_name
&& p
->n_name
[0]; p
++) {
789 if (p
->n_scnum
== bss
) {