Compare commits
38 Commits
fileutils_
...
table_0_03
Author | SHA1 | Date | |
---|---|---|---|
|
d145edb435 | ||
|
fc2d1f07c3 | ||
|
694ad7adb7 | ||
|
d8a7175820 | ||
|
fe56feb875 | ||
|
5e9d34c91a | ||
|
0e086aef25 | ||
|
540385da7e | ||
|
540cd68691 | ||
|
c41d6e5a77 | ||
|
74ca45f795 | ||
|
5f4131f248 | ||
|
4bfef8c254 | ||
|
f77eba3d57 | ||
|
f18952a9d8 | ||
|
16cb163bb0 | ||
|
f8bdfa9a43 | ||
|
61f887fc67 | ||
|
9fd8936e93 | ||
|
ef693a93bc | ||
|
aa04293fc3 | ||
|
345a657d2c | ||
|
da7d7ff116 | ||
|
c5263a881e | ||
|
49adb94af0 | ||
|
b991ecaf9a | ||
|
2c8ae09776 | ||
|
8ecb7f296e | ||
|
3477d30dc5 | ||
|
f30dfecaf7 | ||
|
8a666eb5a4 | ||
|
61071132bf | ||
|
b177c3930d | ||
|
eb8d28b694 | ||
|
0b4f757b2b | ||
|
2aa20e2060 | ||
|
7d8ff8f72e | ||
|
576dde394a |
@@ -24,3 +24,4 @@ stamp-h
|
||||
sun4
|
||||
sun4sol2
|
||||
support
|
||||
i386-freebsd
|
||||
|
145
ChangeLog
145
ChangeLog
@@ -1,3 +1,148 @@
|
||||
1998-07-18 Martin Baulig <martin@home-of-linux.org>
|
||||
|
||||
* lib/{init, open}.c: Added `GLIBTOP_METHOD_PIPE' again.
|
||||
|
||||
* src/server/main.c: Removed gettext stuff.
|
||||
|
||||
1998-07-17 Martin Baulig <baulig@Stud.Informatik.uni-trier.de>
|
||||
|
||||
* sysdeps/common/sysdeps.c (glibtop_get_sysdeps_r): Using
|
||||
library functions with '_l' prefix instead of directly calling
|
||||
sysdeps code with '_r' prefix. This is necessary for client/server
|
||||
mode.
|
||||
|
||||
* lib/lib.awk (glibtop_get_*): Now correctly using
|
||||
`(1 << GLIBTOP_SYSDEPS_*)' instead of `GLIBTOP_SYSDEPS_*'.
|
||||
|
||||
* sysdeps/sun4/proclist.c (glibtop_get_proclist_p): Added
|
||||
implementation of that feature.
|
||||
|
||||
* sysdeps/sun4/proc_{uid, state}.c: Now working quite well.
|
||||
|
||||
* sysdeps/sun4/proc_{mem, time, signal, kernel, segment}.c: Added
|
||||
some basic implementation; this isn't really working yet.
|
||||
|
||||
* sysdeps/linux/sem_limits.c: Applied patch from Albert K T Hui
|
||||
<avatar@deva.net> for glibc 2.1.
|
||||
|
||||
1998-07-15 Martin Baulig <martin@home-of-linux.org>
|
||||
|
||||
* sysdeps/sun4/loadavg.h: New file. Imported from top 3.4.
|
||||
|
||||
* sysdeps/sun4/uptime.c (glibtop_get_uptime_p): Added
|
||||
implementation of that function using glibtop_get_cpu ().
|
||||
|
||||
* sysdeps/sun4/loadavg.c (glibtop_get_loadavg_p): Added
|
||||
implementation of that feature.
|
||||
|
||||
* sysdeps/sun4/{shm_limits.c, msg_limits.c, shm_limits.c}:
|
||||
Added implementation of this features.
|
||||
|
||||
1998-07-14 Martin Baulig <baulig@Stud.Informatik.uni-trier.de>
|
||||
|
||||
* src/daemon/server_config.h.in: Added some comments.
|
||||
|
||||
* src/daemon/server_config.pl: New file. This is a script you can use
|
||||
to create `server_config.h'. It will query you for some configuration
|
||||
options.
|
||||
|
||||
* configure.in (AC_PROG_AWK): Replaced this test with explicit test
|
||||
for `gawk' and `awk' since `mawk' doesn't work.
|
||||
|
||||
1998-07-14 Martin Baulig <martin@home-of-linux.org>
|
||||
|
||||
* src/daemon/gnuserv.c: Doing correct server initialization
|
||||
using `glibtop_set_parameter_l' and `glibtop_init_r'.
|
||||
|
||||
* src/daemon/main.c: Removed call to `glibtop_init_r'.
|
||||
|
||||
* lib/open.c (glibtop_open_l): We now call the open function
|
||||
of the sysdeps directory (glibtop_open_r) for server method
|
||||
`GLIBTOP_METHOD_DIRECT'.
|
||||
|
||||
* sysdeps/{linux, sun4, stub}/open.c: No longer `memset'
|
||||
server to zero.
|
||||
|
||||
* src/daemon/slave.c: New file.
|
||||
|
||||
* src/daemon/*.c: Done some more work on the daemon.
|
||||
|
||||
* sysdeps/common/gnuslib.c: Removed IPC stuff.
|
||||
|
||||
* include/glibtop/gnuserv.h: Removed IPC stuff.
|
||||
|
||||
* include/glibtop/command.h (glibtop_response_unit): Added
|
||||
typedef for `struct _glibtop_response_unit'.
|
||||
|
||||
* lib/Makefile.am: Using `$(top_srcdir)/features.def'
|
||||
instead of `$(top_builddir)/features.def'.
|
||||
|
||||
* sysdeps/guile/Makefile.am: Using `$(top_srcdir)/features.def'
|
||||
instead of `$(top_builddir)/features.def'.
|
||||
|
||||
* sysdeps/guile/names/Makefile.am: Dito.
|
||||
|
||||
* sysdeps/stub/*.c: changed suffix of all functions
|
||||
from '_s' to '_r'; see also ChangeLog entry from Jun 6.
|
||||
|
||||
1998-07-13 Martin Baulig <baulig@merkur.uni-trier.de>
|
||||
|
||||
* src/daemon/server_config.h: Removed from CVS.
|
||||
This is a config file which needs to be edited.
|
||||
|
||||
* src/daemon/server_config.h.in: Added. This is just
|
||||
an example for `server_config.h'.
|
||||
|
||||
1998-07-13 Martin Baulig <martin@home-of-linux.org>
|
||||
|
||||
* glibtop.h: Fixed invocation of `glibtop_close_r'.
|
||||
|
||||
* sysdeps/linux/procstate.c: Added missing `fclose'.
|
||||
|
||||
* include/glibtop/gnuserv.h (UNIX_DOMAIN_SOCKETS): Defining.
|
||||
|
||||
* include/glibtop/open.h (GLIBTOP_METHOD_UNIX): Added.
|
||||
|
||||
* lib/init.c: Added new method `GLIBTOP_METHOD_UNIX'.
|
||||
|
||||
* lib/open.c: Added support for Unix Domain Sockets.
|
||||
|
||||
* lib/close.c: Now closing inet and unix connections.
|
||||
|
||||
* lib/parameter.c (glibtop_set_parameter_l): You can now
|
||||
set the `method' and `features' fields.
|
||||
|
||||
* src/daemon/server_config.h: New file.
|
||||
|
||||
* src/daemon/{gnuserv.c, main.c}: More work on the server.
|
||||
|
||||
1998-07-10 Martin Baulig <martin@home-of-linux.org>
|
||||
|
||||
* src/Makefile.am (SUBDIRS): Removed `proxy'. This directory
|
||||
is considered obsolete and will be removed soon.
|
||||
|
||||
1998-07-06 Martin Baulig <martin@home-of-linux.org>
|
||||
|
||||
* sysdeps/common/mountlist.c: using functions from `xmalloc.c'.
|
||||
|
||||
* sysdeps/common/error.c: all functions now accept NULL as
|
||||
`server' argument.
|
||||
|
||||
* acconfig.h (AFS, MOUNTED_FREAD, MOUNTED_FREAD_FSTYP,
|
||||
MOUNTED_GETFSSTAT, MOUNTED_GETMNT, MOUNTED_GETMNTENT1,
|
||||
MOUNTED_GETMNTENT2, MOUNTED_GETMNTINFO, MOUNTED_LISTMNTENT,
|
||||
MOUNTED_VMOUNT, STAT_STATFS3_OSF1, STAT_READ_FILSYS,
|
||||
STAT_STATFS2_BSIZE, STAT_STATFS2_FSIZE, STAT_STATFS2_FS_DATA,
|
||||
STAT_STATFS4, STAT_STATVFS, STATFS_TRUNCATES_BLOCK_COUNTS):
|
||||
New macros.
|
||||
|
||||
* configure.in: added GNOME_FILEUTILS_CHECKS.
|
||||
|
||||
* sysdeps/common/{fsusage, mountlist}.[ch]:
|
||||
Imported from GNU Fileutils 3.16.
|
||||
|
||||
* sysdeps/common/mountlist.c: using g_malloc, g_realloc and g_strdup.
|
||||
|
||||
1998-07-03 Martin baulig <martin@home-of-linux.org>
|
||||
|
||||
* macros/gnome-libgtop-sysdeps.m4: No longer use
|
||||
|
79
acconfig.h
79
acconfig.h
@@ -12,6 +12,85 @@
|
||||
|
||||
/* Do not remove this comments and the empty lines; they are needed */
|
||||
#undef HAVE_PROGRAM_INVOCATION_SHORT_NAME
|
||||
/* Define if you have the Andrew File System. */
|
||||
#undef AFS
|
||||
|
||||
/* Define one of the following to indicate how a program can
|
||||
get a list of mounted filesystems. */
|
||||
|
||||
/* Define if there is no specific function for reading the list of
|
||||
mounted filesystems. fread will be used to read /etc/mnttab. [SVR2] */
|
||||
#undef MOUNTED_FREAD
|
||||
|
||||
/* Define if (like SVR2) there is no specific function for reading the
|
||||
list of mounted filesystems, and your system has these header files:
|
||||
<sys/fstyp.h> and <sys/statfs.h>. [SVR3] */
|
||||
#undef MOUNTED_FREAD_FSTYP
|
||||
|
||||
/* Define if there is a function named getfsstat for reading the list
|
||||
of mounted filesystems. [DEC Alpha running OSF/1] */
|
||||
#undef MOUNTED_GETFSSTAT
|
||||
|
||||
/* Define if there is a function named getmnt for reading the list of
|
||||
mounted filesystems. [Ultrix] */
|
||||
#undef MOUNTED_GETMNT
|
||||
|
||||
/* Define if there is a function named getmntent for reading the list
|
||||
of mounted filesystems, and that function takes a single argument.
|
||||
[4.3BSD, SunOS, HP-UX, Dynix, Irix] */
|
||||
#undef MOUNTED_GETMNTENT1
|
||||
|
||||
/* Define if there is a function named getmntent for reading the list of
|
||||
mounted filesystems, and that function takes two arguments. [SVR4] */
|
||||
#undef MOUNTED_GETMNTENT2
|
||||
|
||||
/* Define if there is a function named getmntinfo for reading the list
|
||||
of mounted filesystems. [4.4BSD] */
|
||||
#undef MOUNTED_GETMNTINFO
|
||||
|
||||
/* Define if there is a function named listmntent that can be used to
|
||||
list all mounted filesystems. [UNICOS] */
|
||||
#undef MOUNTED_LISTMNTENT
|
||||
|
||||
/* Define if there is a function named mntctl that can be used to read
|
||||
the list of mounted filesystems, and there is a system header file
|
||||
that declares `struct vmount.' [AIX] */
|
||||
#undef MOUNTED_VMOUNT
|
||||
|
||||
/* Define one of the following to indicate how a program can obtain
|
||||
filesystems usage information. */
|
||||
|
||||
/* Define if statfs takes 3 args. [DEC Alpha running OSF/1] */
|
||||
#undef STAT_STATFS3_OSF1
|
||||
|
||||
/* Define if there is no specific function for reading filesystems usage
|
||||
information and you have the <sys/filsys.h> header file. [SVR2] */
|
||||
#undef STAT_READ_FILSYS
|
||||
|
||||
/* Define if statfs takes 2 args and struct statfs has a field named f_bsize.
|
||||
[4.3BSD, SunOS 4, HP-UX, AIX PS/2] */
|
||||
#undef STAT_STATFS2_BSIZE
|
||||
|
||||
/* Define if statfs takes 2 args and struct statfs has a field named f_fsize.
|
||||
[4.4BSD, NetBSD] */
|
||||
#undef STAT_STATFS2_FSIZE
|
||||
|
||||
/* Define if statfs takes 2 args and the second argument has
|
||||
type struct fs_data. [Ultrix] */
|
||||
#undef STAT_STATFS2_FS_DATA
|
||||
|
||||
/* Define if statfs takes 4 args. [SVR3, Dynix, Irix, Dolphin] */
|
||||
#undef STAT_STATFS4
|
||||
|
||||
/* Define if there is a function named statvfs. [SVR4] */
|
||||
#undef STAT_STATVFS
|
||||
|
||||
/* Define if the block counts reported by statfs may be truncated to 2GB
|
||||
and the correct values may be stored in the f_spare array.
|
||||
[SunOS 4.1.2, 4.1.3, and 4.1.3_U1 are reported to have this problem.
|
||||
SunOS 4.1.1 seems not to be affected.] */
|
||||
#undef STATFS_TRUNCATES_BLOCK_COUNTS
|
||||
|
||||
|
||||
/* to fix a bug in autoheader on DEC OSF1. */
|
||||
#undef HAVE_PROGRAM_INVOCATION_NAME
|
||||
|
@@ -15,7 +15,10 @@ AC_PROG_CC
|
||||
AC_STDC_HEADERS
|
||||
AC_ARG_PROGRAM
|
||||
|
||||
AC_PROG_AWK
|
||||
dnl We don't use `AC_PROG_AWK' since it checks for mawk first which
|
||||
dnl does not work for libgtop.
|
||||
AC_CHECK_PROGS(AWK, gawk awk, )
|
||||
test -z "$AWK" && AC_MSG_ERROR([Sorry, you need a working awk interpreter.])
|
||||
|
||||
AC_CHECK_TOOL(CC,gcc)
|
||||
AC_CHECK_TOOL(RANLIB,ranlib)
|
||||
@@ -125,6 +128,8 @@ if test "$with_xauth" = "yes"; then
|
||||
fi
|
||||
AC_SUBST(libs_xauth)
|
||||
|
||||
dnl For diskusage stuff
|
||||
GNOME_FILEUTILS_CHECKS
|
||||
|
||||
CFLAGS="$CFLAGS -D_IN_LIBGTOP"
|
||||
|
||||
@@ -248,5 +253,6 @@ src/proxy/Makefile
|
||||
src/daemon/Makefile
|
||||
lib/Makefile
|
||||
examples/Makefile
|
||||
perl/Makefile.PL
|
||||
support/Makefile
|
||||
macros/Makefile],[sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile])
|
||||
|
@@ -68,14 +68,14 @@ main (int argc, char *argv [])
|
||||
|
||||
printf ("Host = '%s' - %u\n\n", buffer, port);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_cpu (&data.cpu);
|
||||
|
||||
printf ("CPU (0x%08lx): %lu, %lu, %lu, %lu, %lu, %lu\n",
|
||||
data.cpu.flags, data.cpu.total, data.cpu.user, data.cpu.nice,
|
||||
data.cpu.sys, data.cpu.idle, data.cpu.frequency);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_mem (&data.mem);
|
||||
|
||||
printf ("Memory (0x%08lx): %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu\n",
|
||||
@@ -83,26 +83,26 @@ main (int argc, char *argv [])
|
||||
data.mem.shared, data.mem.buffer, data.mem.cached,
|
||||
data.mem.user, data.mem.locked);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_swap (&data.swap);
|
||||
|
||||
printf ("Swap (0x%08lx): %lu, %lu, %lu\n", data.swap.flags,
|
||||
data.swap.total, data.swap.used, data.swap.free);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_uptime (&data.uptime);
|
||||
|
||||
printf ("Uptime (0x%08lx): %f, %f\n", data.uptime.flags,
|
||||
data.uptime.uptime, data.uptime.idletime);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_loadavg (&data.loadavg);
|
||||
|
||||
printf ("Loadavg (0x%08lx): %f, %f, %f\n", data.loadavg.flags,
|
||||
data.loadavg.loadavg [0], data.loadavg.loadavg [1],
|
||||
data.loadavg.loadavg [2]);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_shm_limits (&data.shm_limits);
|
||||
|
||||
printf ("Shm Limits (0x%08lx): %ld, %ld, %ld, %ld, %ld\n",
|
||||
@@ -110,7 +110,7 @@ main (int argc, char *argv [])
|
||||
data.shm_limits.shmmin, data.shm_limits.shmmni,
|
||||
data.shm_limits.shmseg, data.shm_limits.shmall);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_msg_limits (&data.msg_limits);
|
||||
|
||||
printf ("Msg Limits (0x%08lx): %ld, %ld, %ld, %ld, %ld, %ld, %ld\n",
|
||||
@@ -119,7 +119,7 @@ main (int argc, char *argv [])
|
||||
data.msg_limits.msgmnb, data.msg_limits.msgmni,
|
||||
data.msg_limits.msgssz, data.msg_limits.msgtql);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_sem_limits (&data.sem_limits);
|
||||
|
||||
printf ("Sem Limits (0x%08lx): "
|
||||
@@ -167,7 +167,7 @@ main (int argc, char *argv [])
|
||||
|
||||
printf ("\n");
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_state (&data.proc_state, pid);
|
||||
|
||||
printf ("Proc_State PID %5u (0x%08lx): '%s', %c, %u, %u\n",
|
||||
@@ -175,7 +175,7 @@ main (int argc, char *argv [])
|
||||
data.proc_state.state, data.proc_state.uid,
|
||||
data.proc_state.gid);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_uid (&data.proc_uid, pid);
|
||||
|
||||
printf ("Proc_Uid PID %5u (0x%08lx): "
|
||||
@@ -188,7 +188,7 @@ main (int argc, char *argv [])
|
||||
data.proc_uid.tpgid, data.proc_uid.priority,
|
||||
data.proc_uid.nice);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_mem (&data.proc_mem, pid);
|
||||
|
||||
printf ("Proc_Mem PID %5u (0x%08lx): "
|
||||
@@ -197,7 +197,7 @@ main (int argc, char *argv [])
|
||||
data.proc_mem.resident, data.proc_mem.share,
|
||||
data.proc_mem.rss, data.proc_mem.rss_rlim);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_time (&data.proc_time, pid);
|
||||
|
||||
printf ("Proc_Time PID %5u (0x%08lx): "
|
||||
@@ -207,7 +207,7 @@ main (int argc, char *argv [])
|
||||
data.proc_time.cstime, data.proc_time.timeout,
|
||||
data.proc_time.it_real_value);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_signal (&data.proc_signal, pid);
|
||||
|
||||
printf ("Proc_Signal PID %5u (0x%08lx): "
|
||||
@@ -215,7 +215,7 @@ main (int argc, char *argv [])
|
||||
data.proc_signal.signal, data.proc_signal.blocked,
|
||||
data.proc_signal.sigignore, data.proc_signal.sigcatch);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_kernel (&data.proc_kernel, pid);
|
||||
|
||||
printf ("Proc_Kernel PID %5u (0x%08lx): "
|
||||
@@ -226,7 +226,7 @@ main (int argc, char *argv [])
|
||||
data.proc_kernel.kstk_esp, data.proc_kernel.kstk_eip,
|
||||
data.proc_kernel.wchan);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_segment (&data.proc_segment, pid);
|
||||
|
||||
printf ("Proc_Segment PID %5u (0x%08lx): "
|
||||
@@ -238,7 +238,7 @@ main (int argc, char *argv [])
|
||||
|
||||
printf ("\n");
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_state (&data.proc_state, ppid);
|
||||
|
||||
printf ("Proc_State PPID %5u (0x%08lx): '%s', %c, %u, %u\n",
|
||||
@@ -246,7 +246,7 @@ main (int argc, char *argv [])
|
||||
data.proc_state.state, data.proc_state.uid,
|
||||
data.proc_state.gid);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_uid (&data.proc_uid, ppid);
|
||||
|
||||
printf ("Proc_Uid PPID %5u (0x%08lx): "
|
||||
@@ -259,7 +259,7 @@ main (int argc, char *argv [])
|
||||
data.proc_uid.tpgid, data.proc_uid.priority,
|
||||
data.proc_uid.nice);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_mem (&data.proc_mem, ppid);
|
||||
|
||||
printf ("Proc_Mem PPID %5u (0x%08lx): "
|
||||
@@ -268,7 +268,7 @@ main (int argc, char *argv [])
|
||||
data.proc_mem.resident, data.proc_mem.share,
|
||||
data.proc_mem.rss, data.proc_mem.rss_rlim);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_time (&data.proc_time, ppid);
|
||||
|
||||
printf ("Proc_Time PPID %5u (0x%08lx): "
|
||||
@@ -278,7 +278,7 @@ main (int argc, char *argv [])
|
||||
data.proc_time.cstime, data.proc_time.timeout,
|
||||
data.proc_time.it_real_value);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_signal (&data.proc_signal, ppid);
|
||||
|
||||
printf ("Proc_Signal PPID %5u (0x%08lx): "
|
||||
@@ -286,7 +286,7 @@ main (int argc, char *argv [])
|
||||
data.proc_signal.signal, data.proc_signal.blocked,
|
||||
data.proc_signal.sigignore, data.proc_signal.sigcatch);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_kernel (&data.proc_kernel, ppid);
|
||||
|
||||
printf ("Proc_Kernel PPID %5u (0x%08lx): "
|
||||
@@ -297,7 +297,7 @@ main (int argc, char *argv [])
|
||||
data.proc_kernel.kstk_esp, data.proc_kernel.kstk_eip,
|
||||
data.proc_kernel.wchan);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_segment (&data.proc_segment, ppid);
|
||||
|
||||
printf ("Proc_Segment PPID %5u (0x%08lx): "
|
||||
@@ -309,7 +309,7 @@ main (int argc, char *argv [])
|
||||
|
||||
printf ("\n");
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_state (&data.proc_state, 1);
|
||||
|
||||
printf ("Proc_State INIT %5u (0x%08lx): '%s', %c, %u, %u\n",
|
||||
@@ -317,7 +317,7 @@ main (int argc, char *argv [])
|
||||
data.proc_state.state, data.proc_state.uid,
|
||||
data.proc_state.gid);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_uid (&data.proc_uid, 1);
|
||||
|
||||
printf ("Proc_Uid INIT %5u (0x%08lx): "
|
||||
@@ -330,7 +330,7 @@ main (int argc, char *argv [])
|
||||
data.proc_uid.tpgid, data.proc_uid.priority,
|
||||
data.proc_uid.nice);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_mem (&data.proc_mem, 1);
|
||||
|
||||
printf ("Proc_Mem INIT %5u (0x%08lx): "
|
||||
@@ -339,7 +339,7 @@ main (int argc, char *argv [])
|
||||
data.proc_mem.resident, data.proc_mem.share,
|
||||
data.proc_mem.rss, data.proc_mem.rss_rlim);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_time (&data.proc_time, 1);
|
||||
|
||||
printf ("Proc_Time INIT %5u (0x%08lx): "
|
||||
@@ -349,7 +349,7 @@ main (int argc, char *argv [])
|
||||
data.proc_time.cstime, data.proc_time.timeout,
|
||||
data.proc_time.it_real_value);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_signal (&data.proc_signal, 1);
|
||||
|
||||
printf ("Proc_Signal INIT %5u (0x%08lx): "
|
||||
@@ -357,7 +357,7 @@ main (int argc, char *argv [])
|
||||
data.proc_signal.signal, data.proc_signal.blocked,
|
||||
data.proc_signal.sigignore, data.proc_signal.sigcatch);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_kernel (&data.proc_kernel, 1);
|
||||
|
||||
printf ("Proc_Kernel INIT %5u (0x%08lx): "
|
||||
@@ -368,7 +368,7 @@ main (int argc, char *argv [])
|
||||
data.proc_kernel.kstk_esp, data.proc_kernel.kstk_eip,
|
||||
data.proc_kernel.wchan);
|
||||
|
||||
for (c = 0; c < count; c++)
|
||||
for (c = 0; c < PROFILE_COUNT; c++)
|
||||
glibtop_get_proc_segment (&data.proc_segment, 1);
|
||||
|
||||
printf ("Proc_Segment INIT %5u (0x%08lx): "
|
||||
@@ -378,5 +378,7 @@ main (int argc, char *argv [])
|
||||
data.proc_segment.start_code, data.proc_segment.end_code,
|
||||
data.proc_segment.start_stack);
|
||||
|
||||
glibtop_close ();
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
@@ -60,7 +60,7 @@ extern const unsigned long glibtop_server_features;
|
||||
|
||||
#define glibtop_init() glibtop_init_r(&glibtop_global_server, 0, 0);
|
||||
|
||||
#define glibtop_close() glibtop_close_r(&glibtop_global_server);
|
||||
#define glibtop_close() glibtop_close_r(glibtop_global_server);
|
||||
|
||||
extern glibtop *glibtop_init_r __P((glibtop **, const unsigned long, const unsigned));
|
||||
|
||||
|
@@ -53,7 +53,9 @@ __BEGIN_DECLS
|
||||
#define _GLIBTOP_PARAM_SIZE 16
|
||||
|
||||
typedef struct _glibtop_command glibtop_command;
|
||||
|
||||
typedef struct _glibtop_response glibtop_response;
|
||||
typedef union _glibtop_response_union glibtop_response_union;
|
||||
|
||||
struct _glibtop_command
|
||||
{
|
||||
@@ -73,7 +75,7 @@ struct _glibtop_response
|
||||
{
|
||||
off_t offset;
|
||||
size_t size, data_size;
|
||||
union _glibtop_response_union u;
|
||||
glibtop_response_union u;
|
||||
};
|
||||
|
||||
#define glibtop_call(p1, p2, p3, p4) glibtop_call_r(glibtop_global_server, p1, p2, p3, p4)
|
||||
|
@@ -54,10 +54,8 @@ static char header_rcsid [] = "!Header: gnuserv.h,v 2.4 95/02/16 11:58:11 arup a
|
||||
* sockets with sysv ipc
|
||||
*/
|
||||
|
||||
|
||||
#define INTERNET_DOMAIN_SOCKETS
|
||||
// #define UNIX_DOMAIN_SOCKETS
|
||||
// #define SYSV_IPC
|
||||
#define UNIX_DOMAIN_SOCKETS
|
||||
|
||||
/*
|
||||
* Define additional authentication protocols to be used. These methods will
|
||||
@@ -91,15 +89,13 @@ static char header_rcsid [] = "!Header: gnuserv.h,v 2.4 95/02/16 11:58:11 arup a
|
||||
* Pick a default communication scheme, if none was specified.
|
||||
*/
|
||||
|
||||
#if !defined(SYSV_IPC) && !defined(UNIX_DOMAIN_SOCKETS) && !defined(INTERNET_DOMAIN_SOCKETS)
|
||||
#if !defined(UNIX_DOMAIN_SOCKETS) && !defined(INTERNET_DOMAIN_SOCKETS)
|
||||
|
||||
#ifdef HAVE_SYSVIPC
|
||||
#define SYSV_IPC /* SYSV systems use SYSV IPC by default */
|
||||
#endif /* HAVE_SYSVIPC */
|
||||
/* BSD systems use Unix Domain sockets by default */
|
||||
|
||||
#ifdef BSD
|
||||
#define UNIX_DOMAIN_SOCKETS /* BSD systems use Unix Domain sockets by default */
|
||||
#endif /* BSD */
|
||||
#define UNIX_DOMAIN_SOCKETS
|
||||
#endif
|
||||
|
||||
#endif /* No communication method pre-defined */
|
||||
|
||||
@@ -111,24 +107,6 @@ static char header_rcsid [] = "!Header: gnuserv.h,v 2.4 95/02/16 11:58:11 arup a
|
||||
* what you want.
|
||||
*/
|
||||
|
||||
# define GSERV_BUFSZ BUFSIZ
|
||||
|
||||
|
||||
#ifdef SYSV_IPC
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
#define send_string(s,str) \
|
||||
if (strlen(msgp->mtext) + strlen(str) < GSERV_BUFSZ) \
|
||||
strcat(msgp->mtext,str); \
|
||||
else \
|
||||
{ \
|
||||
fprintf(stderr,"%s: not enough message buffer space\n",progname); \
|
||||
exit(1); \
|
||||
} \
|
||||
|
||||
#endif /* SYSV_IPC */
|
||||
|
||||
#if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS)
|
||||
#include <sys/socket.h>
|
||||
#endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */
|
||||
@@ -155,9 +133,6 @@ static char header_rcsid [] = "!Header: gnuserv.h,v 2.4 95/02/16 11:58:11 arup a
|
||||
#undef TRUE
|
||||
#define TRUE 1
|
||||
|
||||
// extern char *optarg;
|
||||
// extern int optind;
|
||||
|
||||
/* The casts shut Sun's compiler up and are safe in the context these
|
||||
are actually used. */
|
||||
#define max2(x,y) (((int) (x) > (int) (y)) ? (x) : (y))
|
||||
@@ -178,16 +153,6 @@ static char header_rcsid [] = "!Header: gnuserv.h,v 2.4 95/02/16 11:58:11 arup a
|
||||
/* function declarations */
|
||||
extern int glibtop_make_connection __P((const char *, int, int *));
|
||||
|
||||
#ifdef SYSV_IPC
|
||||
void disconnect_from_ipc_server();
|
||||
#endif
|
||||
|
||||
#if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS)
|
||||
// void send_string (int s, const char *msg);
|
||||
// void disconnect_from_server (int s, int echo);
|
||||
// int read_line (int s, char *dest);
|
||||
#endif
|
||||
|
||||
#ifdef INTERNET_DOMAIN_SOCKETS
|
||||
extern long glibtop_internet_addr __P((const char *));
|
||||
#endif
|
||||
|
@@ -38,6 +38,7 @@ __BEGIN_DECLS
|
||||
#define GLIBTOP_METHOD_DIRECT 1
|
||||
#define GLIBTOP_METHOD_PIPE 2
|
||||
#define GLIBTOP_METHOD_INET 3
|
||||
#define GLIBTOP_METHOD_UNIX 4
|
||||
|
||||
extern void glibtop_open_l __P((glibtop *, const char *, const unsigned long, const unsigned));
|
||||
|
||||
|
13
kernel/table20/Makefile
Normal file
13
kernel/table20/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# Makefile for the linux system information tables.
|
||||
#
|
||||
# Note! Dependencies are done automagically by 'make dep', which also
|
||||
# removes any old dependencies. DON'T put your own dependencies here
|
||||
# unless it's something special (ie not a .c file).
|
||||
#
|
||||
# Note 2! The CFLAGS definition is now in the main makefile...
|
||||
|
||||
O_TARGET := table.o
|
||||
O_OBJS := main.o
|
||||
|
||||
include $(TOPDIR)/Rules.make
|
21
kernel/table20/README
Normal file
21
kernel/table20/README
Normal file
@@ -0,0 +1,21 @@
|
||||
This is a new system call `table ()' for the Linux table. It is faster
|
||||
than reading from /proc and can be used to fetch all information required
|
||||
for libgtop until whe have some other function (extended sysctl, ...) in
|
||||
standard kernels.
|
||||
|
||||
I didn't want to change sysctl or some other function myself cause this may
|
||||
cause other applications relying upon those function to fail. This is
|
||||
something for the ``real'' kernel gurus ...
|
||||
|
||||
To use this new system call for libgtop, do the following:
|
||||
|
||||
* Copy this directory to /usr/src/linux/table
|
||||
* Make /usr/src/linux/include/linux/table.h symlink to /usr/src/linux/table/table.h
|
||||
* Apply the patch `kernel.patch' to the kernel, compile, install and reboot
|
||||
* Recompile libgtop (remove `config.cache' and run the `autogen.sh' again).
|
||||
|
||||
If you want to change and/or add something - feel free to do so !
|
||||
|
||||
Have fun,
|
||||
|
||||
Martin
|
49
kernel/table20/kernel.patch
Normal file
49
kernel/table20/kernel.patch
Normal file
@@ -0,0 +1,49 @@
|
||||
diff -ur linux-2.0.32/Makefile linux-hacked/Makefile
|
||||
--- linux-2.0.32/Makefile Fri Nov 7 19:51:05 1997
|
||||
+++ linux-hacked/Makefile Thu Jun 11 20:41:12 1998
|
||||
@@ -87,7 +87,7 @@
|
||||
# standard CFLAGS
|
||||
#
|
||||
|
||||
-CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce
|
||||
+CFLAGS = -Wall -Wstrict-prototypes -g -O2 -fomit-frame-pointer -fno-strength-reduce
|
||||
|
||||
ifdef CONFIG_CPP
|
||||
CFLAGS := $(CFLAGS) -x c++
|
||||
@@ -113,12 +113,12 @@
|
||||
# Include the make variables (CC, etc...)
|
||||
#
|
||||
|
||||
-ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o net/network.a
|
||||
+ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o net/network.a table/table.o
|
||||
FILESYSTEMS =fs/filesystems.a
|
||||
DRIVERS =drivers/block/block.a \
|
||||
drivers/char/char.a
|
||||
LIBS =$(TOPDIR)/lib/lib.a
|
||||
-SUBDIRS =kernel drivers mm fs net ipc lib
|
||||
+SUBDIRS =kernel drivers mm fs net ipc lib table
|
||||
|
||||
ifeq ($(CONFIG_ISDN),y)
|
||||
DRIVERS := $(DRIVERS) drivers/isdn/isdn.a
|
||||
diff -ur linux-2.0.32/arch/i386/kernel/entry.S linux-hacked/arch/i386/kernel/entry.S
|
||||
--- linux-2.0.32/arch/i386/kernel/entry.S Tue Sep 16 23:42:45 1997
|
||||
+++ linux-hacked/arch/i386/kernel/entry.S Thu Jun 11 21:37:20 1998
|
||||
@@ -699,4 +699,6 @@
|
||||
.long SYMBOL_NAME(sys_mremap)
|
||||
.long 0,0
|
||||
.long SYMBOL_NAME(sys_vm86)
|
||||
- .space (NR_syscalls-166)*4
|
||||
+ .long 0
|
||||
+ .long SYMBOL_NAME(sys_table)
|
||||
+ .space (NR_syscalls-168)*4
|
||||
diff -ur linux-2.0.32/include/asm-i386/unistd.h linux-hacked/include/asm-i386/unistd.h
|
||||
--- linux-2.0.32/include/asm-i386/unistd.h Fri Mar 22 07:34:02 1996
|
||||
+++ linux-hacked/include/asm-i386/unistd.h Thu Jun 11 21:37:03 1998
|
||||
@@ -169,6 +169,7 @@
|
||||
#define __NR_sched_rr_get_interval 161
|
||||
#define __NR_nanosleep 162
|
||||
#define __NR_mremap 163
|
||||
+#define __NR_table 168
|
||||
|
||||
/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
|
||||
#define _syscall0(type,name) \
|
437
kernel/table20/main.c
Normal file
437
kernel/table20/main.c
Normal file
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* linux/table/table_impl.c
|
||||
* Copyright (C) 1998 Martin Baulig
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/a.out.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/swap.h>
|
||||
|
||||
#include <asm/segment.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <linux/table.h>
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#if defined(__i386__)
|
||||
# define KSTK_EIP(tsk) (((unsigned long *)tsk->kernel_stack_page)[1019])
|
||||
# define KSTK_ESP(tsk) (((unsigned long *)tsk->kernel_stack_page)[1022])
|
||||
#elif defined(__alpha__)
|
||||
/*
|
||||
* See arch/alpha/kernel/ptrace.c for details.
|
||||
*/
|
||||
# define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \
|
||||
+ (long)&((struct pt_regs *)0)->reg)
|
||||
# define KSTK_EIP(tsk) (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc)))
|
||||
# define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
|
||||
#elif defined(__sparc__)
|
||||
# define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \
|
||||
+ (long)&((struct pt_regs *)0)->reg)
|
||||
# define KSTK_EIP(tsk) (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc)))
|
||||
# define KSTK_ESP(tsk) (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(u_regs[UREG_FP])))
|
||||
#endif
|
||||
|
||||
static struct task_struct *
|
||||
get_task (pid_t pid)
|
||||
{
|
||||
struct task_struct ** p;
|
||||
|
||||
p = task;
|
||||
while (++p < task+NR_TASKS) {
|
||||
if (*p && (*p)->pid == pid)
|
||||
return *p;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
|
||||
int * pages, int * shared, int * dirty, int * total)
|
||||
{
|
||||
pte_t * pte;
|
||||
unsigned long end;
|
||||
|
||||
if (pmd_none(*pmd))
|
||||
return;
|
||||
if (pmd_bad(*pmd)) {
|
||||
printk("statm_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
|
||||
pmd_clear(pmd);
|
||||
return;
|
||||
}
|
||||
pte = pte_offset(pmd, address);
|
||||
address &= ~PMD_MASK;
|
||||
end = address + size;
|
||||
if (end > PMD_SIZE)
|
||||
end = PMD_SIZE;
|
||||
do {
|
||||
pte_t page = *pte;
|
||||
|
||||
address += PAGE_SIZE;
|
||||
pte++;
|
||||
if (pte_none(page))
|
||||
continue;
|
||||
++*total;
|
||||
if (!pte_present(page))
|
||||
continue;
|
||||
++*pages;
|
||||
if (pte_dirty(page))
|
||||
++*dirty;
|
||||
if (pte_page(page) >= high_memory)
|
||||
continue;
|
||||
if (mem_map[MAP_NR(pte_page(page))].count > 1)
|
||||
++*shared;
|
||||
} while (address < end);
|
||||
}
|
||||
|
||||
static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size,
|
||||
int * pages, int * shared, int * dirty, int * total)
|
||||
{
|
||||
pmd_t * pmd;
|
||||
unsigned long end;
|
||||
|
||||
if (pgd_none(*pgd))
|
||||
return;
|
||||
if (pgd_bad(*pgd)) {
|
||||
printk("statm_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
|
||||
pgd_clear(pgd);
|
||||
return;
|
||||
}
|
||||
pmd = pmd_offset(pgd, address);
|
||||
address &= ~PGDIR_MASK;
|
||||
end = address + size;
|
||||
if (end > PGDIR_SIZE)
|
||||
end = PGDIR_SIZE;
|
||||
do {
|
||||
statm_pte_range(pmd, address, end - address, pages, shared, dirty, total);
|
||||
address = (address + PMD_SIZE) & PMD_MASK;
|
||||
pmd++;
|
||||
} while (address < end);
|
||||
}
|
||||
|
||||
static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end,
|
||||
int * pages, int * shared, int * dirty, int * total)
|
||||
{
|
||||
while (address < end) {
|
||||
statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total);
|
||||
address = (address + PGDIR_SIZE) & PGDIR_MASK;
|
||||
pgd++;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
get_wchan (struct task_struct *p)
|
||||
{
|
||||
if (!p || p == current || p->state == TASK_RUNNING)
|
||||
return 0;
|
||||
#if defined(__i386__)
|
||||
{
|
||||
unsigned long ebp, eip;
|
||||
unsigned long stack_page;
|
||||
int count = 0;
|
||||
|
||||
stack_page = p->kernel_stack_page;
|
||||
if (!stack_page)
|
||||
return 0;
|
||||
ebp = p->tss.ebp;
|
||||
do {
|
||||
if (ebp < stack_page || ebp >= 4092+stack_page)
|
||||
return 0;
|
||||
eip = *(unsigned long *) (ebp+4);
|
||||
if (eip < (unsigned long) interruptible_sleep_on
|
||||
|| eip >= (unsigned long) add_timer)
|
||||
return eip;
|
||||
ebp = *(unsigned long *) ebp;
|
||||
} while (count++ < 16);
|
||||
}
|
||||
#elif defined(__alpha__)
|
||||
/*
|
||||
* This one depends on the frame size of schedule(). Do a
|
||||
* "disass schedule" in gdb to find the frame size. Also, the
|
||||
* code assumes that sleep_on() follows immediately after
|
||||
* interruptible_sleep_on() and that add_timer() follows
|
||||
* immediately after interruptible_sleep(). Ugly, isn't it?
|
||||
* Maybe adding a wchan field to task_struct would be better,
|
||||
* after all...
|
||||
*/
|
||||
{
|
||||
unsigned long schedule_frame;
|
||||
unsigned long pc;
|
||||
|
||||
pc = thread_saved_pc(&p->tss);
|
||||
if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) {
|
||||
schedule_frame = ((unsigned long *)p->tss.ksp)[6];
|
||||
return ((unsigned long *)schedule_frame)[12];
|
||||
}
|
||||
return pc;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
asmlinkage int
|
||||
sys_table (int type, union table *buf, const void *param)
|
||||
{
|
||||
union table tbl;
|
||||
struct sysinfo i;
|
||||
struct task_struct *tsk = NULL;
|
||||
int index, err;
|
||||
pid_t pid;
|
||||
|
||||
if (type == TABLE_VERSION)
|
||||
return _TABLE_VERSION;
|
||||
|
||||
if (!buf)
|
||||
return -EFAULT;
|
||||
|
||||
memset (&tbl, 0, sizeof (union table));
|
||||
|
||||
/* For TABLE_PROC_*, read pid and get task_struct */
|
||||
|
||||
switch (type) {
|
||||
case TABLE_PROC_UID:
|
||||
case TABLE_PROC_MEM:
|
||||
case TABLE_PROC_SEGMENT:
|
||||
case TABLE_PROC_TIME:
|
||||
case TABLE_PROC_STATE:
|
||||
case TABLE_PROC_SIGNAL:
|
||||
case TABLE_PROC_KERNEL:
|
||||
err = verify_area (VERIFY_READ, param, sizeof (pid_t));
|
||||
if (err)
|
||||
return err;
|
||||
memcpy_fromfs (&pid, param, sizeof (pid_t));
|
||||
|
||||
tsk = get_task (pid);
|
||||
if (tsk == NULL)
|
||||
return -ESRCH;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Main function dispatcher */
|
||||
|
||||
switch (type) {
|
||||
case TABLE_PROCLIST:
|
||||
tsk = task [0];
|
||||
for (index = 0; index < nr_tasks; index++) {
|
||||
tbl.proclist.pids [index] = tsk->pid;
|
||||
tsk = tsk->next_task;
|
||||
}
|
||||
tbl.proclist.nr_running = nr_running;
|
||||
tbl.proclist.nr_tasks = nr_tasks;
|
||||
tbl.proclist.last_pid = last_pid;
|
||||
break;
|
||||
case TABLE_CPU:
|
||||
tbl.cpu.total = jiffies;
|
||||
tbl.cpu.user = kstat.cpu_user;
|
||||
tbl.cpu.nice = kstat.cpu_nice;
|
||||
tbl.cpu.sys = kstat.cpu_system;
|
||||
tbl.cpu.idle = tbl.cpu.total -
|
||||
(tbl.cpu.user + tbl.cpu.nice + tbl.cpu.sys);
|
||||
tbl.cpu.frequency = HZ;
|
||||
break;
|
||||
case TABLE_MEM:
|
||||
si_meminfo (&i);
|
||||
tbl.mem.total = i.totalram;
|
||||
tbl.mem.used = i.totalram - i.freeram;
|
||||
tbl.mem.free = i.freeram;
|
||||
tbl.mem.shared = i.sharedram;
|
||||
tbl.mem.buffer = i.bufferram;
|
||||
tbl.mem.cached = page_cache_size << PAGE_SHIFT;
|
||||
break;
|
||||
case TABLE_SWAP:
|
||||
si_swapinfo (&i);
|
||||
tbl.swap.total = i.totalswap;
|
||||
tbl.swap.used = i.totalswap - i.freeswap;
|
||||
tbl.swap.free = i.freeswap;
|
||||
break;
|
||||
case TABLE_LOADAVG:
|
||||
tbl.loadavg.loadavg [0] = (double) avenrun [0] / (1 << FSHIFT);
|
||||
tbl.loadavg.loadavg [1] = (double) avenrun [1] / (1 << FSHIFT);
|
||||
tbl.loadavg.loadavg [2] = (double) avenrun [2] / (1 << FSHIFT);
|
||||
tbl.loadavg.nr_running = nr_running;
|
||||
tbl.loadavg.nr_tasks = nr_tasks;
|
||||
tbl.loadavg.last_pid = last_pid;
|
||||
break;
|
||||
case TABLE_UPTIME:
|
||||
tbl.uptime.uptime = jiffies;
|
||||
tbl.uptime.idle = task[0]->utime + task[0]->stime;
|
||||
break;
|
||||
case TABLE_PROC_STATE:
|
||||
tbl.proc_state.state = tsk->state;
|
||||
tbl.proc_state.flags = tsk->flags;
|
||||
memcpy (tbl.proc_state.comm, tsk->comm,
|
||||
sizeof (tbl.proc_state.comm));
|
||||
break;
|
||||
case TABLE_PROC_UID:
|
||||
tbl.proc_uid.uid = tsk->uid;
|
||||
tbl.proc_uid.euid = tsk->euid;
|
||||
tbl.proc_uid.suid = tsk->suid;
|
||||
tbl.proc_uid.fsuid = tsk->fsuid;
|
||||
|
||||
tbl.proc_uid.gid = tsk->gid;
|
||||
tbl.proc_uid.egid = tsk->egid;
|
||||
tbl.proc_uid.sgid = tsk->sgid;
|
||||
tbl.proc_uid.fsgid = tsk->fsgid;
|
||||
|
||||
tbl.proc_uid.pid = tsk->pid;
|
||||
tbl.proc_uid.pgrp = tsk->pgrp;
|
||||
tbl.proc_uid.ppid = tsk->p_pptr->pid;
|
||||
|
||||
tbl.proc_uid.session = tsk->session;
|
||||
tbl.proc_uid.tty = tsk->tty ?
|
||||
kdev_t_to_nr (tsk->tty->device) : 0;
|
||||
tbl.proc_uid.tpgid = tsk->tty ? tsk->tty->pgrp : -1;
|
||||
|
||||
tbl.proc_uid.priority = tsk->priority;
|
||||
tbl.proc_uid.counter = tsk->counter;
|
||||
tbl.proc_uid.def_priority = DEF_PRIORITY;
|
||||
break;
|
||||
case TABLE_PROC_SIGNAL:
|
||||
tbl.proc_signal.signal = tsk->signal;
|
||||
tbl.proc_signal.blocked = tsk->blocked;
|
||||
|
||||
if (tsk->sig) {
|
||||
struct sigaction * action = tsk->sig->action;
|
||||
unsigned long sig_ign = 0, sig_caught = 0;
|
||||
unsigned long bit = 1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
switch((unsigned long) action->sa_handler) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
sig_ign |= bit;
|
||||
break;
|
||||
default:
|
||||
sig_caught |= bit;
|
||||
}
|
||||
bit <<= 1;
|
||||
action++;
|
||||
}
|
||||
|
||||
tbl.proc_signal.ignored = sig_ign;
|
||||
tbl.proc_signal.caught = sig_caught;
|
||||
} else {
|
||||
tbl.proc_signal.ignored = 0;
|
||||
tbl.proc_signal.caught = 0;
|
||||
}
|
||||
break;
|
||||
case TABLE_PROC_MEM:
|
||||
if (tsk->mm && tsk->mm != &init_mm) {
|
||||
tbl.proc_mem.context = tsk->mm->context;
|
||||
tbl.proc_mem.start_code = tsk->mm->start_code;
|
||||
tbl.proc_mem.end_code = tsk->mm->end_code;
|
||||
tbl.proc_mem.start_data = tsk->mm-> start_data;
|
||||
tbl.proc_mem.end_data = tsk->mm->end_data;
|
||||
tbl.proc_mem.start_brk = tsk->mm->start_brk;
|
||||
tbl.proc_mem.brk = tsk->mm->brk;
|
||||
tbl.proc_mem.start_stack = tsk->mm->start_stack;
|
||||
tbl.proc_mem.start_mmap = tsk->mm->start_mmap;
|
||||
tbl.proc_mem.arg_start = tsk->mm->arg_start;
|
||||
tbl.proc_mem.arg_end = tsk->mm->arg_end;
|
||||
tbl.proc_mem.env_start = tsk->mm->env_start;
|
||||
tbl.proc_mem.env_end = tsk->mm->env_end;
|
||||
tbl.proc_mem.rss = tsk->mm->rss;
|
||||
tbl.proc_mem.total_vm = tsk->mm->total_vm;
|
||||
tbl.proc_mem.locked_vm = tsk->mm->locked_vm;
|
||||
}
|
||||
tbl.proc_mem.rlim = tsk->rlim ?
|
||||
tsk->rlim[RLIMIT_RSS].rlim_cur : 0;
|
||||
break;
|
||||
case TABLE_PROC_SEGMENT:
|
||||
if (tsk->mm && tsk->mm != &init_mm) {
|
||||
unsigned long vsize = 0;
|
||||
int size = 0, resident = 0, share = 0;
|
||||
int trs = 0, lrs = 0, drs = 0, dt = 0;
|
||||
struct vm_area_struct * vma = tsk->mm->mmap;
|
||||
|
||||
while (vma) {
|
||||
pgd_t *pgd = pgd_offset(tsk->mm, vma->vm_start);
|
||||
int pages = 0, shared = 0, dirty = 0, total = 0;
|
||||
|
||||
vsize += vma->vm_end - vma->vm_start;
|
||||
|
||||
statm_pgd_range (pgd, vma->vm_start, vma->vm_end,
|
||||
&pages, &shared, &dirty, &total);
|
||||
resident += pages;
|
||||
share += shared;
|
||||
dt += dirty;
|
||||
size += total;
|
||||
if (vma->vm_flags & VM_EXECUTABLE)
|
||||
trs += pages; /* text */
|
||||
else if (vma->vm_flags & VM_GROWSDOWN)
|
||||
drs += pages; /* stack */
|
||||
else if (vma->vm_end > 0x60000000)
|
||||
lrs += pages; /* library */
|
||||
else
|
||||
drs += pages;
|
||||
vma = vma->vm_next;
|
||||
}
|
||||
|
||||
tbl.proc_segment.vsize = vsize;
|
||||
tbl.proc_segment.size = size;
|
||||
tbl.proc_segment.resident = resident;
|
||||
tbl.proc_segment.shared = share;
|
||||
tbl.proc_segment.trs = trs;
|
||||
tbl.proc_segment.lrs = lrs;
|
||||
tbl.proc_segment.dt = dt;
|
||||
}
|
||||
break;
|
||||
case TABLE_PROC_TIME:
|
||||
tbl.proc_time.utime = tsk->utime;
|
||||
tbl.proc_time.stime = tsk->stime;
|
||||
tbl.proc_time.cutime = tsk->cutime;
|
||||
tbl.proc_time.cstime = tsk->cstime;
|
||||
|
||||
tbl.proc_time.start_time = tsk->start_time;
|
||||
tbl.proc_time.timeout = tsk->timeout;
|
||||
tbl.proc_time.policy = tsk->policy;
|
||||
tbl.proc_time.rt_priority = tsk->rt_priority;
|
||||
|
||||
tbl.proc_time.it_real_value = tsk->it_real_value;
|
||||
tbl.proc_time.it_prof_value = tsk->it_prof_value;
|
||||
tbl.proc_time.it_virt_value = tsk->it_virt_value;
|
||||
tbl.proc_time.it_real_incr = tsk->it_real_incr;
|
||||
tbl.proc_time.it_prof_incr = tsk->it_prof_incr;
|
||||
tbl.proc_time.it_virt_incr = tsk->it_virt_incr;
|
||||
break;
|
||||
case TABLE_PROC_KERNEL:
|
||||
tbl.proc_kernel.min_flt = tsk->min_flt;
|
||||
tbl.proc_kernel.cmin_flt = tsk->cmin_flt;
|
||||
tbl.proc_kernel.maj_flt = tsk->maj_flt;
|
||||
tbl.proc_kernel.cmaj_flt = tsk->cmaj_flt;
|
||||
|
||||
tbl.proc_kernel.kesp = tsk->kernel_stack_page ? KSTK_EIP(tsk) : 0;
|
||||
tbl.proc_kernel.keip = tsk->kernel_stack_page ? KSTK_ESP(tsk) : 0;
|
||||
|
||||
tbl.proc_kernel.nswap = tsk->nswap;
|
||||
tbl.proc_kernel.cnswap = tsk->cnswap;
|
||||
|
||||
tbl.proc_kernel.wchan = get_wchan (tsk);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = verify_area (VERIFY_WRITE, buf, sizeof (struct table));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memcpy_tofs (buf, &tbl, sizeof (union table));
|
||||
return 0;
|
||||
}
|
166
kernel/table20/table.h
Normal file
166
kernel/table20/table.h
Normal file
@@ -0,0 +1,166 @@
|
||||
#ifndef _LINUX_TABLE_H
|
||||
#define _LINUX_TABLE_H
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <linux/types.h>
|
||||
#else
|
||||
#define NR_TASKS 512
|
||||
#endif
|
||||
|
||||
#define TABLE_VERSION 0
|
||||
#define TABLE_CPU 1
|
||||
#define TABLE_MEM 2
|
||||
#define TABLE_SWAP 3
|
||||
#define TABLE_LOADAVG 4
|
||||
#define TABLE_UPTIME 5
|
||||
#define TABLE_PROCLIST 6
|
||||
#define TABLE_PROC_UID 7
|
||||
#define TABLE_PROC_MEM 8
|
||||
#define TABLE_PROC_SEGMENT 9
|
||||
#define TABLE_PROC_TIME 10
|
||||
#define TABLE_PROC_STATE 11
|
||||
#define TABLE_PROC_SIGNAL 12
|
||||
#define TABLE_PROC_KERNEL 13
|
||||
|
||||
/* CPU Usage (in jiffies = 1/100th seconds) */
|
||||
|
||||
struct table_cpu
|
||||
{
|
||||
unsigned long total; /* Total CPU Time */
|
||||
unsigned long user; /* CPU Time in User Mode */
|
||||
unsigned long nice; /* CPU Time in User Mode (nice) */
|
||||
unsigned long sys; /* CPU Time in System Mode */
|
||||
unsigned long idle; /* CPU Time in the Idle Task */
|
||||
unsigned long frequency; /* Tick frequency */
|
||||
};
|
||||
|
||||
/* Memory Usage (in bytes) */
|
||||
|
||||
struct table_mem
|
||||
{
|
||||
unsigned long total; /* Total physical memory */
|
||||
unsigned long used; /* Used memory size */
|
||||
unsigned long free; /* Free memory size */
|
||||
unsigned long shared; /* Shared memory size */
|
||||
unsigned long buffer; /* Size of buffers */
|
||||
unsigned long cached; /* Size of cached memory */
|
||||
};
|
||||
|
||||
/* Swap Space (in bytes) */
|
||||
|
||||
struct table_swap
|
||||
{
|
||||
unsigned long total; /* Total swap space */
|
||||
unsigned long used; /* Used swap space */
|
||||
unsigned long free; /* Free swap space */
|
||||
};
|
||||
|
||||
/* Load average */
|
||||
|
||||
struct table_loadavg
|
||||
{
|
||||
double loadavg [3];
|
||||
unsigned nr_running;
|
||||
unsigned nr_tasks;
|
||||
unsigned last_pid;
|
||||
};
|
||||
|
||||
/* Uptime */
|
||||
|
||||
struct table_uptime
|
||||
{
|
||||
unsigned long uptime;
|
||||
unsigned long idle;
|
||||
};
|
||||
|
||||
/* Process list. */
|
||||
|
||||
struct table_proclist
|
||||
{
|
||||
int nr_running, nr_tasks, last_pid;
|
||||
unsigned pids [NR_TASKS];
|
||||
};
|
||||
|
||||
/* Information about processes. */
|
||||
|
||||
struct table_proc_state
|
||||
{
|
||||
long state;
|
||||
unsigned long flags;
|
||||
char comm[16];
|
||||
};
|
||||
|
||||
struct table_proc_uid
|
||||
{
|
||||
int uid, euid, suid, fsuid;
|
||||
int gid, egid, sgid, fsgid;
|
||||
int pid, pgrp, ppid;
|
||||
int session;
|
||||
unsigned int tty;
|
||||
int tpgid;
|
||||
long priority;
|
||||
long counter;
|
||||
long def_priority;
|
||||
};
|
||||
|
||||
struct table_proc_mem
|
||||
{
|
||||
unsigned long context;
|
||||
unsigned long start_code, end_code, start_data, end_data;
|
||||
unsigned long start_brk, brk, start_stack, start_mmap;
|
||||
unsigned long arg_start, arg_end, env_start, env_end;
|
||||
unsigned long rss, rlim, total_vm, locked_vm;
|
||||
};
|
||||
|
||||
struct table_proc_segment
|
||||
{
|
||||
unsigned long vsize;
|
||||
int size, resident, shared;
|
||||
int trs, lrs, drs, dt;
|
||||
};
|
||||
|
||||
struct table_proc_time
|
||||
{
|
||||
long utime, stime, cutime, cstime, start_time;
|
||||
unsigned long timeout, policy, rt_priority;
|
||||
unsigned long it_real_value, it_prof_value, it_virt_value;
|
||||
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
|
||||
};
|
||||
|
||||
struct table_proc_signal
|
||||
{
|
||||
sigset_t signal;
|
||||
sigset_t blocked; /* bitmap of masked signals */
|
||||
sigset_t ignored; /* mask of ignored signals */
|
||||
sigset_t caught; /* mask of caught signals */
|
||||
};
|
||||
|
||||
struct table_proc_kernel
|
||||
{
|
||||
unsigned long keip, kesp, wchan;
|
||||
unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
|
||||
unsigned long nswap, cnswap;
|
||||
};
|
||||
|
||||
/* Union */
|
||||
|
||||
union table
|
||||
{
|
||||
struct table_cpu cpu;
|
||||
struct table_mem mem;
|
||||
struct table_swap swap;
|
||||
struct table_loadavg loadavg;
|
||||
struct table_uptime uptime;
|
||||
struct table_proclist proclist;
|
||||
struct table_proc_uid proc_uid;
|
||||
struct table_proc_mem proc_mem;
|
||||
struct table_proc_segment proc_segment;
|
||||
struct table_proc_time proc_time;
|
||||
struct table_proc_state proc_state;
|
||||
struct table_proc_signal proc_signal;
|
||||
struct table_proc_kernel proc_kernel;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_IPC_H */
|
||||
|
||||
|
1
kernel/table20/version.h
Normal file
1
kernel/table20/version.h
Normal file
@@ -0,0 +1 @@
|
||||
#define _TABLE_VERSION 1
|
16
kernel/table21/Makefile
Normal file
16
kernel/table21/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# Makefile for the linux system information tables.
|
||||
#
|
||||
# Note! Dependencies are done automagically by 'make dep', which also
|
||||
# removes any old dependencies. DON'T put your own dependencies here
|
||||
# unless it's something special (ie not a .c file).
|
||||
#
|
||||
# Note 2! The CFLAGS definition is now in the main makefile...
|
||||
|
||||
O_TARGET := table.o
|
||||
OX_OBJS := main.o
|
||||
|
||||
M_TARGET := module.o
|
||||
MX_OBJS := module.o
|
||||
|
||||
include $(TOPDIR)/Rules.make
|
21
kernel/table21/README
Normal file
21
kernel/table21/README
Normal file
@@ -0,0 +1,21 @@
|
||||
This is a new system call `table ()' for the Linux table. It is faster
|
||||
than reading from /proc and can be used to fetch all information required
|
||||
for libgtop until whe have some other function (extended sysctl, ...) in
|
||||
standard kernels.
|
||||
|
||||
I didn't want to change sysctl or some other function myself cause this may
|
||||
cause other applications relying upon those function to fail. This is
|
||||
something for the ``real'' kernel gurus ...
|
||||
|
||||
To use this new system call for libgtop, do the following:
|
||||
|
||||
* Copy this directory to /usr/src/linux/table
|
||||
* Make /usr/src/linux/include/linux/table.h symlink to /usr/src/linux/table/table.h
|
||||
* Apply the patch `kernel.patch' to the kernel, compile, install and reboot
|
||||
* Recompile libgtop (remove `config.cache' and run the `autogen.sh' again).
|
||||
|
||||
If you want to change and/or add something - feel free to do so !
|
||||
|
||||
Have fun,
|
||||
|
||||
Martin
|
61
kernel/table21/main.c
Normal file
61
kernel/table21/main.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* linux/table/table_impl.c
|
||||
* Copyright (C) 1998 Martin Baulig
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/a.out.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/signal.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/table.h>
|
||||
|
||||
#include "version.h"
|
||||
|
||||
extern void scheduling_functions_start_here(void);
|
||||
extern void scheduling_functions_end_here(void);
|
||||
|
||||
int (*table_function_ptr) (int, union table *, const void *) = 0;
|
||||
|
||||
EXPORT_SYMBOL(table_function_ptr);
|
||||
|
||||
EXPORT_SYMBOL(nr_running);
|
||||
EXPORT_SYMBOL(pidhash);
|
||||
EXPORT_SYMBOL(task);
|
||||
EXPORT_SYMBOL(si_swapinfo);
|
||||
EXPORT_SYMBOL(scheduling_functions_start_here);
|
||||
EXPORT_SYMBOL(scheduling_functions_end_here);
|
||||
EXPORT_SYMBOL(avenrun);
|
||||
EXPORT_SYMBOL(nr_tasks);
|
||||
EXPORT_SYMBOL(last_pid);
|
||||
EXPORT_SYMBOL(page_cache_size);
|
||||
EXPORT_SYMBOL(init_mm);
|
||||
|
||||
asmlinkage int
|
||||
sys_table (int type, union table *buf, const void *param)
|
||||
{
|
||||
if (table_function_ptr == 0)
|
||||
return -ENOSYS;
|
||||
|
||||
return (*table_function_ptr) (type, buf, param);
|
||||
}
|
524
kernel/table21/module.c
Normal file
524
kernel/table21/module.c
Normal file
@@ -0,0 +1,524 @@
|
||||
/*
|
||||
* linux/table/table_impl.c
|
||||
* Copyright (C) 1998 Martin Baulig
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/a.out.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/signal.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/table.h>
|
||||
|
||||
#include "version.h"
|
||||
|
||||
extern int (*table_function_ptr) (int, union table *, const void *);
|
||||
|
||||
int table_fkt (int, union table *, const void *);
|
||||
|
||||
EXPORT_NO_SYMBOLS;
|
||||
|
||||
int
|
||||
init_module(void)
|
||||
{
|
||||
printk ("init_module () = %p\n", table_fkt);
|
||||
table_function_ptr = table_fkt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
cleanup_module(void)
|
||||
{
|
||||
table_function_ptr = 0;
|
||||
}
|
||||
|
||||
#define LOAD_INT(x) ((x) >> FSHIFT)
|
||||
#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
|
||||
|
||||
#ifdef CONFIG_DEBUG_MALLOC
|
||||
int get_malloc(char * buffer);
|
||||
#endif
|
||||
|
||||
static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
|
||||
sigset_t *catch)
|
||||
{
|
||||
struct k_sigaction *k;
|
||||
int i;
|
||||
|
||||
sigemptyset(ign);
|
||||
sigemptyset(catch);
|
||||
|
||||
if (p->sig) {
|
||||
k = p->sig->action;
|
||||
for (i = 1; i <= _NSIG; ++i, ++k) {
|
||||
if (k->sa.sa_handler == SIG_IGN)
|
||||
sigaddset(ign, i);
|
||||
else if (k->sa.sa_handler != SIG_DFL)
|
||||
sigaddset(catch, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* These bracket the sleeping functions..
|
||||
*/
|
||||
extern void scheduling_functions_start_here(void);
|
||||
extern void scheduling_functions_end_here(void);
|
||||
#define first_sched ((unsigned long) scheduling_functions_start_here)
|
||||
#define last_sched ((unsigned long) scheduling_functions_end_here)
|
||||
|
||||
static unsigned long get_wchan(struct task_struct *p)
|
||||
{
|
||||
if (!p || p == current || p->state == TASK_RUNNING)
|
||||
return 0;
|
||||
#if defined(__i386__)
|
||||
{
|
||||
unsigned long ebp, eip;
|
||||
unsigned long stack_page;
|
||||
int count = 0;
|
||||
|
||||
stack_page = 4096 + (unsigned long)p;
|
||||
if (!stack_page)
|
||||
return 0;
|
||||
ebp = p->tss.ebp;
|
||||
do {
|
||||
if (ebp < stack_page || ebp >= 4092+stack_page)
|
||||
return 0;
|
||||
eip = *(unsigned long *) (ebp+4);
|
||||
if (eip < first_sched || eip >= last_sched)
|
||||
return eip;
|
||||
ebp = *(unsigned long *) ebp;
|
||||
} while (count++ < 16);
|
||||
}
|
||||
#elif defined(__alpha__)
|
||||
/*
|
||||
* This one depends on the frame size of schedule(). Do a
|
||||
* "disass schedule" in gdb to find the frame size. Also, the
|
||||
* code assumes that sleep_on() follows immediately after
|
||||
* interruptible_sleep_on() and that add_timer() follows
|
||||
* immediately after interruptible_sleep(). Ugly, isn't it?
|
||||
* Maybe adding a wchan field to task_struct would be better,
|
||||
* after all...
|
||||
*/
|
||||
{
|
||||
unsigned long schedule_frame;
|
||||
unsigned long pc;
|
||||
|
||||
pc = thread_saved_pc(&p->tss);
|
||||
if (pc >= first_sched && pc < last_sched) {
|
||||
schedule_frame = ((unsigned long *)p->tss.ksp)[6];
|
||||
return ((unsigned long *)schedule_frame)[12];
|
||||
}
|
||||
return pc;
|
||||
}
|
||||
#elif defined(__mc68000__)
|
||||
{
|
||||
unsigned long fp, pc;
|
||||
unsigned long stack_page;
|
||||
int count = 0;
|
||||
extern int sys_pause (void);
|
||||
|
||||
stack_page = p->kernel_stack_page;
|
||||
if (!stack_page)
|
||||
return 0;
|
||||
fp = ((struct switch_stack *)p->tss.ksp)->a6;
|
||||
do {
|
||||
if (fp < stack_page || fp >= 4088+stack_page)
|
||||
return 0;
|
||||
pc = ((unsigned long *)fp)[1];
|
||||
/* FIXME: This depends on the order of these functions. */
|
||||
if (pc < first_sched || pc >= last_sched)
|
||||
return pc;
|
||||
fp = *(unsigned long *) fp;
|
||||
} while (count++ < 16);
|
||||
}
|
||||
#elif defined(__powerpc__)
|
||||
return (p->tss.wchan);
|
||||
#elif defined (CONFIG_ARM)
|
||||
{
|
||||
unsigned long fp, lr;
|
||||
unsigned long stack_page;
|
||||
int count = 0;
|
||||
|
||||
stack_page = 4096 + (unsigned long)p;
|
||||
fp = get_css_fp (&p->tss);
|
||||
do {
|
||||
if (fp < stack_page || fp > 4092+stack_page)
|
||||
return 0;
|
||||
lr = pc_pointer (((unsigned long *)fp)[-1]);
|
||||
if (lr < first_sched || lr > last_sched)
|
||||
return lr;
|
||||
fp = *(unsigned long *) (fp - 12);
|
||||
} while (count ++ < 16);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019])
|
||||
# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
|
||||
#elif defined(__alpha__)
|
||||
/*
|
||||
* See arch/alpha/kernel/ptrace.c for details.
|
||||
*/
|
||||
# define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \
|
||||
+ (long)&((struct pt_regs *)0)->reg)
|
||||
# define KSTK_EIP(tsk) \
|
||||
(*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk)))
|
||||
# define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
|
||||
#elif defined(CONFIG_ARM)
|
||||
# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
|
||||
# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
|
||||
#elif defined(__mc68000__)
|
||||
#define KSTK_EIP(tsk) \
|
||||
({ \
|
||||
unsigned long eip = 0; \
|
||||
if ((tsk)->tss.esp0 > PAGE_SIZE && \
|
||||
MAP_NR((tsk)->tss.esp0) < max_mapnr) \
|
||||
eip = ((struct pt_regs *) (tsk)->tss.esp0)->pc; \
|
||||
eip; })
|
||||
#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
|
||||
#elif defined(__powerpc__)
|
||||
#define KSTK_EIP(tsk) ((tsk)->tss.regs->nip)
|
||||
#define KSTK_ESP(tsk) ((tsk)->tss.regs->gpr[1])
|
||||
#elif defined (__sparc_v9__)
|
||||
# define KSTK_EIP(tsk) ((tsk)->tss.kregs->tpc)
|
||||
# define KSTK_ESP(tsk) ((tsk)->tss.kregs->u_regs[UREG_FP])
|
||||
#elif defined(__sparc__)
|
||||
# define KSTK_EIP(tsk) ((tsk)->tss.kregs->pc)
|
||||
# define KSTK_ESP(tsk) ((tsk)->tss.kregs->u_regs[UREG_FP])
|
||||
#endif
|
||||
|
||||
/* Gcc optimizes away "strlen(x)" for constant x */
|
||||
#define ADDBUF(buffer, string) \
|
||||
do { memcpy(buffer, string, strlen(string)); \
|
||||
buffer += strlen(string); } while (0)
|
||||
|
||||
static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
|
||||
int * pages, int * shared, int * dirty, int * total)
|
||||
{
|
||||
pte_t * pte;
|
||||
unsigned long end;
|
||||
|
||||
if (pmd_none(*pmd))
|
||||
return;
|
||||
if (pmd_bad(*pmd)) {
|
||||
printk("statm_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
|
||||
pmd_clear(pmd);
|
||||
return;
|
||||
}
|
||||
pte = pte_offset(pmd, address);
|
||||
address &= ~PMD_MASK;
|
||||
end = address + size;
|
||||
if (end > PMD_SIZE)
|
||||
end = PMD_SIZE;
|
||||
do {
|
||||
pte_t page = *pte;
|
||||
|
||||
address += PAGE_SIZE;
|
||||
pte++;
|
||||
if (pte_none(page))
|
||||
continue;
|
||||
++*total;
|
||||
if (!pte_present(page))
|
||||
continue;
|
||||
++*pages;
|
||||
if (pte_dirty(page))
|
||||
++*dirty;
|
||||
if (MAP_NR(pte_page(page)) >= max_mapnr)
|
||||
continue;
|
||||
if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) > 1)
|
||||
++*shared;
|
||||
} while (address < end);
|
||||
}
|
||||
|
||||
static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size,
|
||||
int * pages, int * shared, int * dirty, int * total)
|
||||
{
|
||||
pmd_t * pmd;
|
||||
unsigned long end;
|
||||
|
||||
if (pgd_none(*pgd))
|
||||
return;
|
||||
if (pgd_bad(*pgd)) {
|
||||
printk("statm_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
|
||||
pgd_clear(pgd);
|
||||
return;
|
||||
}
|
||||
pmd = pmd_offset(pgd, address);
|
||||
address &= ~PGDIR_MASK;
|
||||
end = address + size;
|
||||
if (end > PGDIR_SIZE)
|
||||
end = PGDIR_SIZE;
|
||||
do {
|
||||
statm_pte_range(pmd, address, end - address, pages, shared, dirty, total);
|
||||
address = (address + PMD_SIZE) & PMD_MASK;
|
||||
pmd++;
|
||||
} while (address < end);
|
||||
}
|
||||
|
||||
static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end,
|
||||
int * pages, int * shared, int * dirty, int * total)
|
||||
{
|
||||
while (address < end) {
|
||||
statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total);
|
||||
address = (address + PGDIR_SIZE) & PGDIR_MASK;
|
||||
pgd++;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
table_fkt (int type, union table *buf, const void *param)
|
||||
{
|
||||
union table tbl;
|
||||
struct sysinfo i;
|
||||
struct task_struct *tsk = NULL;
|
||||
int index, err;
|
||||
pid_t pid;
|
||||
|
||||
if (type == TABLE_VERSION)
|
||||
return _TABLE_VERSION;
|
||||
|
||||
if (!buf)
|
||||
return -EFAULT;
|
||||
|
||||
memset (&tbl, 0, sizeof (union table));
|
||||
|
||||
/* For TABLE_PROC_*, read pid and get task_struct */
|
||||
|
||||
switch (type) {
|
||||
case TABLE_PROC_UID:
|
||||
case TABLE_PROC_MEM:
|
||||
case TABLE_PROC_SEGMENT:
|
||||
case TABLE_PROC_TIME:
|
||||
case TABLE_PROC_STATE:
|
||||
case TABLE_PROC_SIGNAL:
|
||||
case TABLE_PROC_KERNEL:
|
||||
err = verify_area (VERIFY_READ, param, sizeof (pid_t));
|
||||
if (err)
|
||||
return err;
|
||||
copy_from_user (&pid, param, sizeof (pid_t));
|
||||
|
||||
read_lock (&tasklist_lock);
|
||||
tsk = find_task_by_pid (pid);
|
||||
/* FIXME!! This should be done after the last use */
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
if (tsk == NULL)
|
||||
return -ESRCH;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Main function dispatcher */
|
||||
|
||||
switch (type) {
|
||||
case TABLE_PROCLIST:
|
||||
tsk = task [0];
|
||||
for (index = 0; index < nr_tasks; index++) {
|
||||
tbl.proclist.pids [index] = tsk->pid;
|
||||
tsk = tsk->next_task;
|
||||
}
|
||||
tbl.proclist.nr_running = nr_running;
|
||||
tbl.proclist.nr_tasks = nr_tasks;
|
||||
tbl.proclist.last_pid = last_pid;
|
||||
break;
|
||||
case TABLE_CPU:
|
||||
tbl.cpu.total = jiffies;
|
||||
tbl.cpu.user = kstat.cpu_user;
|
||||
tbl.cpu.nice = kstat.cpu_nice;
|
||||
tbl.cpu.sys = kstat.cpu_system;
|
||||
tbl.cpu.idle = tbl.cpu.total -
|
||||
(tbl.cpu.user + tbl.cpu.nice + tbl.cpu.sys);
|
||||
tbl.cpu.frequency = HZ;
|
||||
break;
|
||||
case TABLE_MEM:
|
||||
si_meminfo (&i);
|
||||
tbl.mem.total = i.totalram;
|
||||
tbl.mem.used = i.totalram - i.freeram;
|
||||
tbl.mem.free = i.freeram;
|
||||
tbl.mem.shared = i.sharedram;
|
||||
tbl.mem.buffer = i.bufferram;
|
||||
tbl.mem.cached = page_cache_size << PAGE_SHIFT;
|
||||
break;
|
||||
case TABLE_SWAP:
|
||||
si_swapinfo (&i);
|
||||
tbl.swap.total = i.totalswap;
|
||||
tbl.swap.used = i.totalswap - i.freeswap;
|
||||
tbl.swap.free = i.freeswap;
|
||||
break;
|
||||
case TABLE_LOADAVG:
|
||||
tbl.loadavg.loadavg [0] = (double) avenrun [0] / (1 << FSHIFT);
|
||||
tbl.loadavg.loadavg [1] = (double) avenrun [1] / (1 << FSHIFT);
|
||||
tbl.loadavg.loadavg [2] = (double) avenrun [2] / (1 << FSHIFT);
|
||||
tbl.loadavg.nr_running = nr_running;
|
||||
tbl.loadavg.nr_tasks = nr_tasks;
|
||||
tbl.loadavg.last_pid = last_pid;
|
||||
break;
|
||||
case TABLE_UPTIME:
|
||||
tbl.uptime.uptime = jiffies;
|
||||
tbl.uptime.idle = task[0]->times.tms_utime +
|
||||
task[0]->times.tms_stime;
|
||||
break;
|
||||
case TABLE_PROC_STATE:
|
||||
tbl.proc_state.state = tsk->state;
|
||||
tbl.proc_state.flags = tsk->flags;
|
||||
memcpy (tbl.proc_state.comm, tsk->comm,
|
||||
sizeof (tbl.proc_state.comm));
|
||||
break;
|
||||
case TABLE_PROC_UID:
|
||||
tbl.proc_uid.uid = tsk->uid;
|
||||
tbl.proc_uid.euid = tsk->euid;
|
||||
tbl.proc_uid.suid = tsk->suid;
|
||||
tbl.proc_uid.fsuid = tsk->fsuid;
|
||||
|
||||
tbl.proc_uid.gid = tsk->gid;
|
||||
tbl.proc_uid.egid = tsk->egid;
|
||||
tbl.proc_uid.sgid = tsk->sgid;
|
||||
tbl.proc_uid.fsgid = tsk->fsgid;
|
||||
|
||||
tbl.proc_uid.pid = tsk->pid;
|
||||
tbl.proc_uid.pgrp = tsk->pgrp;
|
||||
tbl.proc_uid.ppid = tsk->p_pptr->pid;
|
||||
|
||||
tbl.proc_uid.session = tsk->session;
|
||||
tbl.proc_uid.tty = tsk->tty ?
|
||||
kdev_t_to_nr (tsk->tty->device) : 0;
|
||||
tbl.proc_uid.tpgid = tsk->tty ? tsk->tty->pgrp : -1;
|
||||
|
||||
tbl.proc_uid.priority = tsk->priority;
|
||||
tbl.proc_uid.counter = tsk->counter;
|
||||
tbl.proc_uid.def_priority = DEF_PRIORITY;
|
||||
break;
|
||||
case TABLE_PROC_SIGNAL:
|
||||
tbl.proc_signal.signal = tsk->signal;
|
||||
tbl.proc_signal.blocked = tsk->blocked;
|
||||
|
||||
collect_sigign_sigcatch (tsk, &tbl.proc_signal.ignored,
|
||||
&tbl.proc_signal.caught);
|
||||
break;
|
||||
case TABLE_PROC_MEM:
|
||||
if (tsk->mm && tsk->mm != &init_mm) {
|
||||
tbl.proc_mem.context = tsk->mm->context;
|
||||
tbl.proc_mem.start_code = tsk->mm->start_code;
|
||||
tbl.proc_mem.end_code = tsk->mm->end_code;
|
||||
tbl.proc_mem.start_data = tsk->mm-> start_data;
|
||||
tbl.proc_mem.end_data = tsk->mm->end_data;
|
||||
tbl.proc_mem.start_brk = tsk->mm->start_brk;
|
||||
tbl.proc_mem.brk = tsk->mm->brk;
|
||||
tbl.proc_mem.start_stack = tsk->mm->start_stack;
|
||||
tbl.proc_mem.start_mmap = tsk->mm->mmap ?
|
||||
tsk->mm->mmap->vm_start : 0;
|
||||
tbl.proc_mem.arg_start = tsk->mm->arg_start;
|
||||
tbl.proc_mem.arg_end = tsk->mm->arg_end;
|
||||
tbl.proc_mem.env_start = tsk->mm->env_start;
|
||||
tbl.proc_mem.env_end = tsk->mm->env_end;
|
||||
tbl.proc_mem.rss = tsk->mm->rss;
|
||||
tbl.proc_mem.total_vm = tsk->mm->total_vm;
|
||||
tbl.proc_mem.locked_vm = tsk->mm->locked_vm;
|
||||
}
|
||||
tbl.proc_mem.rlim = tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0;
|
||||
break;
|
||||
case TABLE_PROC_SEGMENT:
|
||||
if (tsk->mm && tsk->mm != &init_mm) {
|
||||
unsigned long vsize = 0;
|
||||
int size = 0, resident = 0, share = 0;
|
||||
int trs = 0, lrs = 0, drs = 0, dt = 0;
|
||||
struct vm_area_struct * vma = tsk->mm->mmap;
|
||||
|
||||
while (vma) {
|
||||
pgd_t *pgd = pgd_offset(tsk->mm, vma->vm_start);
|
||||
int pages = 0, shared = 0, dirty = 0, total = 0;
|
||||
|
||||
vsize += vma->vm_end - vma->vm_start;
|
||||
|
||||
statm_pgd_range (pgd, vma->vm_start, vma->vm_end,
|
||||
&pages, &shared, &dirty, &total);
|
||||
resident += pages;
|
||||
share += shared;
|
||||
dt += dirty;
|
||||
size += total;
|
||||
if (vma->vm_flags & VM_EXECUTABLE)
|
||||
trs += pages; /* text */
|
||||
else if (vma->vm_flags & VM_GROWSDOWN)
|
||||
drs += pages; /* stack */
|
||||
else if (vma->vm_end > 0x60000000)
|
||||
lrs += pages; /* library */
|
||||
else
|
||||
drs += pages;
|
||||
vma = vma->vm_next;
|
||||
}
|
||||
|
||||
tbl.proc_segment.vsize = vsize;
|
||||
tbl.proc_segment.size = size;
|
||||
tbl.proc_segment.resident = resident;
|
||||
tbl.proc_segment.shared = share;
|
||||
tbl.proc_segment.trs = trs;
|
||||
tbl.proc_segment.lrs = lrs;
|
||||
tbl.proc_segment.dt = dt;
|
||||
}
|
||||
break;
|
||||
case TABLE_PROC_TIME:
|
||||
tbl.proc_time.utime = tsk->times.tms_utime;
|
||||
tbl.proc_time.stime = tsk->times.tms_stime;
|
||||
tbl.proc_time.cutime = tsk->times.tms_cutime;
|
||||
tbl.proc_time.cstime = tsk->times.tms_cstime;
|
||||
|
||||
tbl.proc_time.start_time = tsk->start_time;
|
||||
tbl.proc_time.timeout = tsk->timeout;
|
||||
tbl.proc_time.policy = tsk->policy;
|
||||
tbl.proc_time.rt_priority = tsk->rt_priority;
|
||||
|
||||
tbl.proc_time.it_real_value = tsk->it_real_value;
|
||||
tbl.proc_time.it_prof_value = tsk->it_prof_value;
|
||||
tbl.proc_time.it_virt_value = tsk->it_virt_value;
|
||||
tbl.proc_time.it_real_incr = tsk->it_real_incr;
|
||||
tbl.proc_time.it_prof_incr = tsk->it_prof_incr;
|
||||
tbl.proc_time.it_virt_incr = tsk->it_virt_incr;
|
||||
break;
|
||||
case TABLE_PROC_KERNEL:
|
||||
tbl.proc_kernel.min_flt = tsk->min_flt;
|
||||
tbl.proc_kernel.cmin_flt = tsk->cmin_flt;
|
||||
tbl.proc_kernel.maj_flt = tsk->maj_flt;
|
||||
tbl.proc_kernel.cmaj_flt = tsk->cmaj_flt;
|
||||
|
||||
tbl.proc_kernel.kesp = KSTK_EIP(tsk);
|
||||
tbl.proc_kernel.keip = KSTK_ESP(tsk);
|
||||
|
||||
tbl.proc_kernel.nswap = tsk->nswap;
|
||||
tbl.proc_kernel.cnswap = tsk->cnswap;
|
||||
|
||||
tbl.proc_kernel.wchan = get_wchan (tsk);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = verify_area (VERIFY_WRITE, buf, sizeof (struct table));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
copy_to_user (buf, &tbl, sizeof (union table));
|
||||
|
||||
return 0;
|
||||
}
|
166
kernel/table21/table.h
Normal file
166
kernel/table21/table.h
Normal file
@@ -0,0 +1,166 @@
|
||||
#ifndef _LINUX_TABLE_H
|
||||
#define _LINUX_TABLE_H
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <linux/types.h>
|
||||
#else
|
||||
#define NR_TASKS 512
|
||||
#endif
|
||||
|
||||
#define TABLE_VERSION 0
|
||||
#define TABLE_CPU 1
|
||||
#define TABLE_MEM 2
|
||||
#define TABLE_SWAP 3
|
||||
#define TABLE_LOADAVG 4
|
||||
#define TABLE_UPTIME 5
|
||||
#define TABLE_PROCLIST 6
|
||||
#define TABLE_PROC_UID 7
|
||||
#define TABLE_PROC_MEM 8
|
||||
#define TABLE_PROC_SEGMENT 9
|
||||
#define TABLE_PROC_TIME 10
|
||||
#define TABLE_PROC_STATE 11
|
||||
#define TABLE_PROC_SIGNAL 12
|
||||
#define TABLE_PROC_KERNEL 13
|
||||
|
||||
/* CPU Usage (in jiffies = 1/100th seconds) */
|
||||
|
||||
struct table_cpu
|
||||
{
|
||||
unsigned long total; /* Total CPU Time */
|
||||
unsigned long user; /* CPU Time in User Mode */
|
||||
unsigned long nice; /* CPU Time in User Mode (nice) */
|
||||
unsigned long sys; /* CPU Time in System Mode */
|
||||
unsigned long idle; /* CPU Time in the Idle Task */
|
||||
unsigned long frequency; /* Tick frequency */
|
||||
};
|
||||
|
||||
/* Memory Usage (in bytes) */
|
||||
|
||||
struct table_mem
|
||||
{
|
||||
unsigned long total; /* Total physical memory */
|
||||
unsigned long used; /* Used memory size */
|
||||
unsigned long free; /* Free memory size */
|
||||
unsigned long shared; /* Shared memory size */
|
||||
unsigned long buffer; /* Size of buffers */
|
||||
unsigned long cached; /* Size of cached memory */
|
||||
};
|
||||
|
||||
/* Swap Space (in bytes) */
|
||||
|
||||
struct table_swap
|
||||
{
|
||||
unsigned long total; /* Total swap space */
|
||||
unsigned long used; /* Used swap space */
|
||||
unsigned long free; /* Free swap space */
|
||||
};
|
||||
|
||||
/* Load average */
|
||||
|
||||
struct table_loadavg
|
||||
{
|
||||
double loadavg [3];
|
||||
unsigned nr_running;
|
||||
unsigned nr_tasks;
|
||||
unsigned last_pid;
|
||||
};
|
||||
|
||||
/* Uptime */
|
||||
|
||||
struct table_uptime
|
||||
{
|
||||
unsigned long uptime;
|
||||
unsigned long idle;
|
||||
};
|
||||
|
||||
/* Process list. */
|
||||
|
||||
struct table_proclist
|
||||
{
|
||||
int nr_running, nr_tasks, last_pid;
|
||||
unsigned pids [NR_TASKS];
|
||||
};
|
||||
|
||||
/* Information about processes. */
|
||||
|
||||
struct table_proc_state
|
||||
{
|
||||
long state;
|
||||
unsigned long flags;
|
||||
char comm[16];
|
||||
};
|
||||
|
||||
struct table_proc_uid
|
||||
{
|
||||
int uid, euid, suid, fsuid;
|
||||
int gid, egid, sgid, fsgid;
|
||||
int pid, pgrp, ppid;
|
||||
int session;
|
||||
unsigned int tty;
|
||||
int tpgid;
|
||||
long priority;
|
||||
long counter;
|
||||
long def_priority;
|
||||
};
|
||||
|
||||
struct table_proc_mem
|
||||
{
|
||||
unsigned long context;
|
||||
unsigned long start_code, end_code, start_data, end_data;
|
||||
unsigned long start_brk, brk, start_stack, start_mmap;
|
||||
unsigned long arg_start, arg_end, env_start, env_end;
|
||||
unsigned long rss, rlim, total_vm, locked_vm;
|
||||
};
|
||||
|
||||
struct table_proc_segment
|
||||
{
|
||||
unsigned long vsize;
|
||||
int size, resident, shared;
|
||||
int trs, lrs, drs, dt;
|
||||
};
|
||||
|
||||
struct table_proc_time
|
||||
{
|
||||
long utime, stime, cutime, cstime, start_time;
|
||||
unsigned long timeout, policy, rt_priority;
|
||||
unsigned long it_real_value, it_prof_value, it_virt_value;
|
||||
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
|
||||
};
|
||||
|
||||
struct table_proc_signal
|
||||
{
|
||||
sigset_t signal;
|
||||
sigset_t blocked; /* bitmap of masked signals */
|
||||
sigset_t ignored; /* mask of ignored signals */
|
||||
sigset_t caught; /* mask of caught signals */
|
||||
};
|
||||
|
||||
struct table_proc_kernel
|
||||
{
|
||||
unsigned long keip, kesp, wchan;
|
||||
unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
|
||||
unsigned long nswap, cnswap;
|
||||
};
|
||||
|
||||
/* Union */
|
||||
|
||||
union table
|
||||
{
|
||||
struct table_cpu cpu;
|
||||
struct table_mem mem;
|
||||
struct table_swap swap;
|
||||
struct table_loadavg loadavg;
|
||||
struct table_uptime uptime;
|
||||
struct table_proclist proclist;
|
||||
struct table_proc_uid proc_uid;
|
||||
struct table_proc_mem proc_mem;
|
||||
struct table_proc_segment proc_segment;
|
||||
struct table_proc_time proc_time;
|
||||
struct table_proc_state proc_state;
|
||||
struct table_proc_signal proc_signal;
|
||||
struct table_proc_kernel proc_kernel;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_IPC_H */
|
||||
|
||||
|
1
kernel/table21/version.h
Normal file
1
kernel/table21/version.h
Normal file
@@ -0,0 +1 @@
|
||||
#define _TABLE_VERSION 1
|
@@ -4,7 +4,7 @@ INCLUDES = -I$(top_builddir) -I$(top_srcdir) @machine_incs@ \
|
||||
-I$(top_srcdir)/include -I$(top_srcdir)/intl @GUILE_INCS@ \
|
||||
-DGTOPLOCALEDIR=\"$(datadir)/locale\" -D_GNU_SOURCE
|
||||
|
||||
CFLAGS = -Wall -W @CFLAGS@ -DGTOP_SERVER=\""@LIBGTOP_SERVER@"\" -DDEBUG
|
||||
CFLAGS = -Wall -W @CFLAGS@ -DGTOP_SERVER=\""@LIBGTOP_SERVER@"\"
|
||||
|
||||
lib_LTLIBRARIES = libgtop.la
|
||||
|
||||
@@ -13,8 +13,8 @@ libgtop_la_SOURCES = init.c open.c close.c command.c read.c read_data.c \
|
||||
|
||||
BUILT_SOURCES = lib.c
|
||||
|
||||
lib.c: lib.awk $(top_builddir)/config.h $(top_builddir)/features.def
|
||||
$(AWK) -f $(srcdir)/lib.awk < $(top_builddir)/features.def > lib-t
|
||||
lib.c: lib.awk $(top_builddir)/config.h $(top_srcdir)/features.def
|
||||
$(AWK) -f $(srcdir)/lib.awk < $(top_srcdir)/features.def > lib-t
|
||||
mv lib-t lib.c
|
||||
|
||||
EXTRA_DIST = lib.awk
|
||||
|
24
lib/close.c
24
lib/close.c
@@ -19,14 +19,30 @@
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <glibtop.h>
|
||||
#include <glibtop/open.h>
|
||||
#include <glibtop/close.h>
|
||||
#include <glibtop/command.h>
|
||||
|
||||
/* Closes pipe to gtop server. */
|
||||
/* Closes server. */
|
||||
|
||||
void
|
||||
glibtop_close_r (glibtop *server)
|
||||
{
|
||||
kill (server->pid, SIGKILL);
|
||||
close (server->input [0]);
|
||||
close (server->output [1]);
|
||||
switch (server->method) {
|
||||
case GLIBTOP_METHOD_UNIX:
|
||||
case GLIBTOP_METHOD_INET:
|
||||
glibtop_call_l (server, GLIBTOP_CMND_QUIT,
|
||||
0, NULL, 0, NULL);
|
||||
|
||||
if (close (server->socket))
|
||||
glibtop_warn_io ("close");
|
||||
|
||||
break;
|
||||
case GLIBTOP_METHOD_PIPE:
|
||||
kill (server->pid, SIGKILL);
|
||||
close (server->input [0]);
|
||||
close (server->output [1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -27,8 +27,8 @@
|
||||
#include <glibtop/xmalloc.h>
|
||||
|
||||
void *
|
||||
glibtop_call_l (glibtop *server, unsigned command, size_t send_size, void *send_buf,
|
||||
size_t recv_size, void *recv_buf)
|
||||
glibtop_call_l (glibtop *server, unsigned command, size_t send_size,
|
||||
void *send_buf, size_t recv_size, void *recv_buf)
|
||||
{
|
||||
glibtop_command cmnd;
|
||||
glibtop_response response;
|
||||
@@ -45,11 +45,6 @@ glibtop_call_l (glibtop *server, unsigned command, size_t send_size, void *send_
|
||||
* send it together with command, so we only need one system call instead
|
||||
* of two. */
|
||||
|
||||
#ifdef DEBUG
|
||||
// fprintf (stderr, "COMMAND: send_size = %d; command = %d; sizeof (cmnd) = %d\n",
|
||||
// send_size, command, sizeof (glibtop_command));
|
||||
#endif
|
||||
|
||||
if (send_size <= _GLIBTOP_PARAM_SIZE) {
|
||||
memcpy (cmnd.parameter, send_buf, send_size);
|
||||
cmnd.size = send_size;
|
||||
@@ -58,14 +53,17 @@ glibtop_call_l (glibtop *server, unsigned command, size_t send_size, void *send_
|
||||
}
|
||||
|
||||
glibtop_write_l (server, sizeof (glibtop_command), &cmnd);
|
||||
// glibtop_write_l (server, cmnd.data_size, send_buf);
|
||||
|
||||
glibtop_read_l (server, sizeof (glibtop_response), &response);
|
||||
|
||||
fprintf (stderr, "RESPONSE: %d - %d\n", response.offset, response.data_size);
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "RESPONSE: %lu - %d\n",
|
||||
response.offset, response.data_size);
|
||||
#endif
|
||||
|
||||
if (recv_buf)
|
||||
memcpy (recv_buf, ((char *) &response) + response.offset, recv_size);
|
||||
memcpy (recv_buf, ((char *) &response) + response.offset,
|
||||
recv_size);
|
||||
|
||||
if (response.data_size) {
|
||||
void *ptr = glibtop_malloc_r (server, response.data_size);
|
||||
|
36
lib/init.c
36
lib/init.c
@@ -63,16 +63,11 @@ _init_server (glibtop *server, const unsigned features)
|
||||
|
||||
if (server->server_command [0] != ':') {
|
||||
if (features & glibtop_server_features) {
|
||||
|
||||
/* We really need the server. */
|
||||
|
||||
server->method = GLIBTOP_METHOD_PIPE;
|
||||
|
||||
} else {
|
||||
|
||||
/* Fine. No server is needed, so we call the
|
||||
* sysdeps functions directly. */
|
||||
|
||||
server->method = GLIBTOP_METHOD_DIRECT;
|
||||
}
|
||||
|
||||
@@ -92,21 +87,19 @@ _init_server (glibtop *server, const unsigned features)
|
||||
/* Dispatch method. */
|
||||
|
||||
if (!strcmp (command, "direct")) {
|
||||
|
||||
/* Use sysdeps dir instead of connecting to server
|
||||
* even if using the server would be required on
|
||||
* the current system. */
|
||||
|
||||
/* Use sysdeps dir instead of connecting to server
|
||||
* even if using the server would be required on
|
||||
* the current system. */
|
||||
server->method = GLIBTOP_METHOD_DIRECT;
|
||||
|
||||
|
||||
} else if (!strcmp (command, "inet")) {
|
||||
|
||||
server->method = GLIBTOP_METHOD_INET;
|
||||
|
||||
/* Connect to internet server. */
|
||||
/* Connect to internet server. */
|
||||
|
||||
if (temp == NULL) {
|
||||
/* If no value was set, we use 'localhost'. */
|
||||
/* If no value was set, we use 'localhost'. */
|
||||
if (server->server_host == NULL)
|
||||
server->server_host = glibtop_strdup_r
|
||||
(server, "localhost");
|
||||
@@ -114,7 +107,7 @@ _init_server (glibtop *server, const unsigned features)
|
||||
char *temp2 = strstr (temp+1, ":");
|
||||
if (temp2) *temp2 = 0;
|
||||
|
||||
/* Override default. */
|
||||
/* Override default. */
|
||||
if (server->server_host)
|
||||
glibtop_free_r (server, (char *) server->server_host);
|
||||
|
||||
@@ -125,7 +118,7 @@ _init_server (glibtop *server, const unsigned features)
|
||||
}
|
||||
|
||||
if (temp == NULL) {
|
||||
/* If no value was set, we use DEFAULT_PORT. */
|
||||
/* If no value was set, we use DEFAULT_PORT. */
|
||||
if (server->server_port == 0)
|
||||
server->server_port = DEFAULT_PORT;
|
||||
} else {
|
||||
@@ -137,9 +130,22 @@ _init_server (glibtop *server, const unsigned features)
|
||||
|
||||
temp = temp2 ? temp2 + 1 : temp2;
|
||||
}
|
||||
|
||||
} else if (!strcmp (command, "unix")) {
|
||||
|
||||
/* Connect to unix domain socket. */
|
||||
server->method = GLIBTOP_METHOD_UNIX;
|
||||
|
||||
} else if (!strcmp (command, "pipe")) {
|
||||
|
||||
/* Open pipe to server. */
|
||||
server->method = GLIBTOP_METHOD_PIPE;
|
||||
|
||||
} else {
|
||||
|
||||
glibtop_error_r (server, "Unknown server method '%s'",
|
||||
server->server_command+1);
|
||||
|
||||
}
|
||||
|
||||
glibtop_free_r (server, command);
|
||||
|
@@ -31,7 +31,7 @@ function output(feature) {
|
||||
print "\tglibtop_init_r (&server, GLIBTOP_SYSDEPS_"toupper(feature)", 0);";
|
||||
print "";
|
||||
print "\tif ((server->flags & _GLIBTOP_INIT_STATE_SERVER) &&";
|
||||
print "\t (server->features & GLIBTOP_SYSDEPS_"toupper(feature)"))";
|
||||
print "\t (server->features & (1 << GLIBTOP_SYSDEPS_"toupper(feature)")))";
|
||||
print "\t{";
|
||||
|
||||
if (feature ~ /^proc_/) {
|
||||
|
81
lib/open.c
81
lib/open.c
@@ -33,6 +33,10 @@ void
|
||||
glibtop_open_l (glibtop *server, const char *program_name,
|
||||
const unsigned long features, const unsigned flags)
|
||||
{
|
||||
char version [BUFSIZ], buffer [BUFSIZ];
|
||||
int connect_type;
|
||||
unsigned nbytes;
|
||||
|
||||
server->name = program_name;
|
||||
|
||||
/* It is important to set _GLIBTOP_INIT_STATE_OPEN here when we
|
||||
@@ -40,19 +44,85 @@ glibtop_open_l (glibtop *server, const char *program_name,
|
||||
|
||||
server->flags |= _GLIBTOP_INIT_STATE_OPEN;
|
||||
|
||||
if (server->method == GLIBTOP_METHOD_INET) {
|
||||
int connect_type;
|
||||
switch (server->method) {
|
||||
case GLIBTOP_METHOD_DIRECT:
|
||||
fprintf (stderr, "Calling sysdeps open function.\n");
|
||||
|
||||
fprintf (stderr, "Connecting to '%s' port %d.\n",
|
||||
glibtop_open_r (server, program_name, features, flags);
|
||||
|
||||
break;
|
||||
case GLIBTOP_METHOD_INET:
|
||||
fprintf (stderr, "Connecting to '%s' port %ld.\n",
|
||||
server->server_host, server->server_port);
|
||||
|
||||
connect_type = glibtop_make_connection
|
||||
(server->server_host, server->server_port,
|
||||
&server->socket);
|
||||
|
||||
fprintf (stderr, "Connect Type is %d.\n", connect_type);
|
||||
|
||||
server->flags |= _GLIBTOP_INIT_STATE_SERVER;
|
||||
|
||||
server->features = -1;
|
||||
break;
|
||||
case GLIBTOP_METHOD_UNIX:
|
||||
fprintf (stderr, "Connecting to Unix Domain Socket.\n");
|
||||
|
||||
return;
|
||||
connect_type = glibtop_make_connection
|
||||
("unix", 0, &server->socket);
|
||||
|
||||
fprintf (stderr, "Connect Type is %d.\n", connect_type);
|
||||
|
||||
server->flags |= _GLIBTOP_INIT_STATE_SERVER;
|
||||
|
||||
server->features = -1;
|
||||
break;
|
||||
case GLIBTOP_METHOD_PIPE:
|
||||
fprintf (stderr, "Opening pipe to server (%s).\n",
|
||||
GTOP_SERVER);
|
||||
|
||||
#if 0
|
||||
if (socketpair (AF_UNIX, SOCK_STREAM, 0, server->input))
|
||||
glibtop_error_io_r (server, "socketpair");
|
||||
|
||||
if (socketpair (AF_UNIX, SOCK_STREAM, 0, server->output))
|
||||
glibtop_error_io_r (server, "socketpair");
|
||||
#endif
|
||||
|
||||
if (pipe (server->input) || pipe (server->output))
|
||||
glibtop_error_io_r (server, "cannot make a pipe");
|
||||
|
||||
server->pid = fork ();
|
||||
|
||||
if (server->pid < 0) {
|
||||
glibtop_error_io_r (server, "fork failed");
|
||||
} else if (server->pid == 0) {
|
||||
close (0); close (1);
|
||||
close (server->input [0]); close (server->output [1]);
|
||||
dup2 (server->input [1], 1);
|
||||
dup2 (server->output [0], 0);
|
||||
execl (GTOP_SERVER, NULL);
|
||||
glibtop_error_io_r (server, "execl %s", GTOP_SERVER);
|
||||
_exit (2);
|
||||
}
|
||||
|
||||
close (server->input [1]);
|
||||
close (server->output [0]);
|
||||
|
||||
sprintf (version, "%s server %s ready.\n", PACKAGE, VERSION);
|
||||
|
||||
glibtop_read_l (server, sizeof (nbytes), &nbytes);
|
||||
|
||||
if (nbytes != strlen (version))
|
||||
glibtop_error_r (server, "Requested %u bytes but got %u",
|
||||
strlen (version), nbytes);
|
||||
|
||||
glibtop_read_l (server, nbytes, buffer);
|
||||
|
||||
if (memcmp (version, buffer, strlen (version)))
|
||||
glibtop_error_r (server, "server version is not %s",
|
||||
VERSION);
|
||||
break;
|
||||
}
|
||||
|
||||
/* If the server has been started, ask it for its features. */
|
||||
@@ -64,5 +134,8 @@ glibtop_open_l (glibtop *server, const char *program_name,
|
||||
sizeof (glibtop_sysdeps), &sysdeps);
|
||||
|
||||
server->features = sysdeps.features;
|
||||
|
||||
fprintf (stderr, "Server features are %lu.\n",
|
||||
server->features);
|
||||
}
|
||||
}
|
||||
|
@@ -28,6 +28,14 @@
|
||||
memcpy (data_ptr, ptr, size); \
|
||||
return size;
|
||||
|
||||
#define _check_data(size) \
|
||||
if ((data_ptr == NULL) || (data_size != size)) { \
|
||||
glibtop_error_r (server, "glibtop_set_parameter (%d): " \
|
||||
"Expected %lu bytes but got %lu.", \
|
||||
parameter, size, data_size); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define _strlen(ptr) (ptr ? strlen (ptr) : 0)
|
||||
|
||||
size_t
|
||||
@@ -59,4 +67,14 @@ void
|
||||
glibtop_set_parameter_l (glibtop *server, const unsigned parameter,
|
||||
const void *data_ptr, size_t data_size)
|
||||
{
|
||||
switch (parameter) {
|
||||
case GLIBTOP_PARAM_METHOD:
|
||||
_check_data (sizeof (server->method));
|
||||
memcpy (&server->method, data_ptr, data_size);
|
||||
break;
|
||||
case GLIBTOP_PARAM_FEATURES:
|
||||
_check_data (sizeof (server->features));
|
||||
memcpy (&server->features, data_ptr, data_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
111
libproc/Makefile
Normal file
111
libproc/Makefile
Normal file
@@ -0,0 +1,111 @@
|
||||
# Auto-adaptive C library Makefile adapted for libproc, Chuck Blake.
|
||||
# Assumptions are basically that all the .c files in the CWD are modules
|
||||
# for the library and that all .h files are the interface to the library.
|
||||
|
||||
# PROJECT SPECIFIC MACROS
|
||||
NAME = proc
|
||||
|
||||
# INSTALLATION OPTIONS
|
||||
TOPDIR = /usr
|
||||
HDRDIR = $(TOPDIR)/include/$(NAME)# where to put .h files
|
||||
LIBDIR = $(TOPDIR)/lib# where to put library files
|
||||
SHLIBDIR = /lib# where to put shared library files
|
||||
HDROWN = -o root -g root # owner of header files
|
||||
LIBOWN = -o root -g root # owner of library files
|
||||
INSTALL = install
|
||||
|
||||
# COMPILATION OPTIONS
|
||||
CC = gcc -O2 -D_GNU_SOURCE #-ggdb # easy to command-line override
|
||||
CFLAGS = -I.. -Wall
|
||||
|
||||
# ----------------------------------------------------------------#
|
||||
# The rest is the auto-magic section -- highly GNU make dependent #
|
||||
# You should never need to edit this. #
|
||||
# ----------------------------------------------------------------#
|
||||
|
||||
VC_SUF = ,v
|
||||
VC_PFX = RCS/
|
||||
RCSFILES = $(patsubst $(VC_PFX)%$(VC_SUF),%,$(wildcard $(VC_PFX)*$(VC_SUF)))
|
||||
|
||||
# We take the union of RCS files and other files in CWD so that new files do
|
||||
# not need to alter this makefile. 'sort' removes duplicates. This allows the
|
||||
# convenience of compiling and testing new files before the initial check-in.
|
||||
|
||||
SRC = $(sort $(wildcard *.c) $(filter %.c,$(RCSFILES)))
|
||||
HDR = $(sort $(wildcard *.h) $(filter %.h,$(RCSFILES)))
|
||||
|
||||
OBJ = $(SRC:.c=.o)
|
||||
SONAME = lib$(NAME).so.$(LIBVERSION)
|
||||
|
||||
ifeq ($(SHARED),1)
|
||||
CFLAGS += -fpic
|
||||
all: lib$(NAME).a $(SONAME)
|
||||
else
|
||||
all: lib$(NAME).a
|
||||
endif
|
||||
|
||||
lib$(NAME).a: $(OBJ)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
$(SONAME): $(OBJ)
|
||||
gcc -Wl,-shared -Wl,-soname,$(SONAME) -o $@ $^ -lc
|
||||
ln -sf $(SONAME) lib$(NAME).so
|
||||
|
||||
# AUTOMATIC DEPENDENCY GENERATION -- GCC AND GNUMAKE DEPENDENT
|
||||
|
||||
.depend:
|
||||
$(strip $(CC) $(CFLAGS) -MM -MG $(SRC) > .depend)
|
||||
include .depend
|
||||
|
||||
# INSTALLATION
|
||||
|
||||
install: all
|
||||
if ! [ -d $(HDRDIR) ] ; then mkdir $(HDRDIR) ; fi
|
||||
$(INSTALL) $(HDROWN) $(HDR) $(TOPDIR)/include/$(NAME)
|
||||
$(INSTALL) $(LIBOWN) lib$(NAME).a $(LIBDIR)
|
||||
ifeq ($(SHARED),1)
|
||||
$(INSTALL) $(LIBOWN) $(SONAME) $(SHLIBDIR)
|
||||
ln -sf $(SHLIBDIR)/$(SONAME) $(SHLIBDIR)/lib$(NAME).so
|
||||
ldconfig
|
||||
endif
|
||||
|
||||
# VARIOUS SHORT CUT TARGETS
|
||||
.PHONY: all install dep clean distclean checkout checkclean
|
||||
|
||||
dep: .depend
|
||||
|
||||
clean:
|
||||
$(RM) lib$(NAME).* *.o
|
||||
|
||||
distclean: clean
|
||||
$(RM) .depend signames.h
|
||||
|
||||
checkout:
|
||||
$(CO) $(RCSFILES)
|
||||
|
||||
checkclean:
|
||||
$(RM) $(RCSFILES)
|
||||
|
||||
# CUSTOM c -> o rule so that command-line has minimal whitespace
|
||||
|
||||
%.o : %.c
|
||||
$(strip $(CC) $(CFLAGS) -c $<)
|
||||
|
||||
# PROJECT SPECIFIC DEPENDENCIES/BUILD RULES
|
||||
|
||||
|
||||
version.o: version.c version.h
|
||||
ifdef MINORVERSION
|
||||
$(strip $(CC) $(CFLAGS) -DVERSION=\"$(VERSION)\" -DSUBVERSION=\"$(SUBVERSION)\" -DMINORVERSION=\"$(MINORVERSION)\" -c version.c)
|
||||
else
|
||||
$(strip $(CC) $(CFLAGS) -DVERSION=\"$(VERSION)\" -DSUBVERSION=\"$(SUBVERSION)\" -c version.c)
|
||||
endif
|
||||
|
||||
signals.o : signames.h
|
||||
|
||||
signames.h ../proc/signames.h : /usr/include/signal.h
|
||||
/lib/cpp -dM </usr/include/signal.h | \
|
||||
tr -s '\t ' ' ' | sort -n +2 | sed \
|
||||
's:#define SIG\([A-Z]\+[0-9]*\) \([0-9]\+\) *\(\|/\*.*\)$$:{\
|
||||
\2,"\1" },:p;d' > signames.h
|
||||
|
49
libproc/alloc.c
Normal file
49
libproc/alloc.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/***********************************************************************\
|
||||
* Copyright (C) 1992 by Michael K. Johnson, johnsonm@sunsite.unc.edu *
|
||||
* *
|
||||
* This file is placed under the conditions of the GNU public *
|
||||
* license, version 2, or any later version. See file COPYING *
|
||||
* for information on distribution conditions. *
|
||||
\***********************************************************************/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void *xcalloc(void *pointer, int size) {
|
||||
void * ret;
|
||||
if (pointer)
|
||||
free(pointer);
|
||||
if (!(ret = calloc(1, size))) {
|
||||
fprintf(stderr, "xcalloc: allocation error, size = %d\n", size);
|
||||
exit(1);
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void *xmalloc(unsigned int size) {
|
||||
void *p;
|
||||
|
||||
if (size == 0)
|
||||
++size;
|
||||
p = malloc(size);
|
||||
if (!p) {
|
||||
fprintf(stderr, "xmalloc: malloc(%d) failed", size);
|
||||
perror(NULL);
|
||||
exit(1);
|
||||
}
|
||||
return(p);
|
||||
}
|
||||
|
||||
void *xrealloc(void *oldp, unsigned int size) {
|
||||
void *p;
|
||||
|
||||
if (size == 0)
|
||||
++size;
|
||||
p = realloc(oldp, size);
|
||||
if (!p) {
|
||||
fprintf(stderr, "xrealloc: realloc(%d) failed", size);
|
||||
perror(NULL);
|
||||
exit(1);
|
||||
}
|
||||
return(p);
|
||||
}
|
307
libproc/compare.c
Normal file
307
libproc/compare.c
Normal file
@@ -0,0 +1,307 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 1994 Charles Blake and Michael K. Johnson
|
||||
* This file is a part of procps, which is distributable
|
||||
* under the conditions of the GNU Public License. See the
|
||||
* file COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h> /* for strcmp */
|
||||
#include <stdio.h> /* for parse error output */
|
||||
#include "proc/readproc.h" /* for proc_t */
|
||||
#include "proc/tree.h" /* for struct tree_node */
|
||||
|
||||
/*
|
||||
This module was written by Charles Blake for procps.
|
||||
|
||||
mult_lvl_cmp:
|
||||
slick general purpose multi-level compare function I invented.
|
||||
sort_depth:
|
||||
the number of levels of functions *to use*. This means many more levels
|
||||
can be defined than mult_lvl_cmp tres out. If this is 1 then mult_lvl_cmp
|
||||
is just a trivial wrapper around (*sort_function[0]).
|
||||
sort_direction:
|
||||
multiplicative factor for the output of cmp_whatever.
|
||||
1 ==> default order, -1 ==> reverse order, 0 ==> forced equality
|
||||
The 0 bit is the neat part. Since a value of zero is the code for equality
|
||||
multiplying the output of cmp_foo(a,b) forces a==b to be true. This is a
|
||||
convenient way to turn sorting off in middle levels of a multi-level sort.
|
||||
If time is a problem, reforming the whole sort_function array to not include
|
||||
these unsorted middle levels will be faster since then cmp_foo won't even
|
||||
be called. It might simplify some code depending upon how you organize it.
|
||||
sort_function[]:
|
||||
array of function pointers that points to our family of comparison functions
|
||||
(I have named them cmp_* but mult_lvl_cmp doesn't care what they're named).
|
||||
This may be declared and initialized like so:
|
||||
int (*sort_function[])(void* a, void* b)={&cmp_foo, &cmp_bar, &cmp_hiho};
|
||||
You could also use my command line '-O' parser below.
|
||||
|
||||
Note that we only descend levels until the order is determined. If we descend
|
||||
all levels, that means that the items are equal at all levels, so we return 0.
|
||||
Otherwise we return whatever the level's cmp_foo function would have returned.
|
||||
This allows whatever default behavior you want for cmp_foo. sort_direction[]
|
||||
reverses this default behavior, but mult_lvl_cmp doesn't decide that ascending
|
||||
or descending is the default. That is the job of your cmp_foo's.
|
||||
*/
|
||||
|
||||
/* the only reason these are global is because qsort(3) likes it that way.
|
||||
It's also a little more efficient if mult_lvl_cmp() is called many times.
|
||||
*/
|
||||
|
||||
typedef int (*cmp_t)(void*,void*); /* for function pointer casts */
|
||||
|
||||
int sort_depth = 0;
|
||||
int sort_direction[10]; /* storage for 10 levels, but 4 would be plenty!*/
|
||||
int (*sort_function[10])(void* a, void* b);
|
||||
|
||||
int mult_lvl_cmp(void* a, void* b) {
|
||||
int i, cmp_val;
|
||||
for(i = 0; i < sort_depth; i++) {
|
||||
cmp_val = sort_direction[i] * (*sort_function[i])(a,b);
|
||||
if (cmp_val != 0)
|
||||
return cmp_val;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int node_mult_lvl_cmp(void* a, void* b) {
|
||||
int i, cmp_val;
|
||||
for(i = 0; i < sort_depth; i++) {
|
||||
cmp_val = sort_direction[i] * (*sort_function[i])(&(((struct tree_node *)a)->proc),&(((struct tree_node *)b)->proc));
|
||||
if (cmp_val != 0)
|
||||
return cmp_val;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* qsort(3) compliant comparison functions for all members of the ps_proc
|
||||
structure (in the same order in which they appear in the proc_t declaration)
|
||||
return is {-1,0,1} as {a<b, a==b, a>b}
|
||||
default ordering is ascending for all members. (flip 1,-1 to reverse)
|
||||
*/
|
||||
/* pre-processor macros to cut down on source size (and typing!)
|
||||
Note the use of the string concatenation operator ##
|
||||
*/
|
||||
#define CMP_STR(NAME) \
|
||||
int cmp_ ## NAME(proc_t** P, proc_t** Q) { \
|
||||
return strcmp((*P)-> ## NAME, (*Q)-> ## NAME); \
|
||||
}
|
||||
|
||||
#define CMP_INT(NAME) \
|
||||
int cmp_ ## NAME (proc_t** P, proc_t** Q) { \
|
||||
if ((*P)-> ## NAME < (*Q)-> ## NAME) return -1; \
|
||||
if ((*P)-> ## NAME > (*Q)-> ## NAME) return 1; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
/* Define the (46!) cmp_ functions with the above macros for every element
|
||||
of proc_t. If the binary gets too big, we could nuke inessentials.
|
||||
*/
|
||||
|
||||
/* CMP_STR(cmdline) */
|
||||
CMP_STR(user)
|
||||
CMP_STR(cmd)
|
||||
/* CMP_INT(state) */
|
||||
/* CMP_STR(ttyc) */
|
||||
CMP_INT(uid)
|
||||
CMP_INT(pid)
|
||||
CMP_INT(ppid)
|
||||
CMP_INT(pgrp)
|
||||
CMP_INT(session)
|
||||
CMP_INT(tty)
|
||||
CMP_INT(tpgid)
|
||||
CMP_INT(utime)
|
||||
CMP_INT(stime)
|
||||
CMP_INT(cutime)
|
||||
CMP_INT(cstime)
|
||||
/* CMP_INT(priority) */
|
||||
CMP_INT(nice)
|
||||
CMP_INT(start_time)
|
||||
/* CMP_INT(signal) */
|
||||
/* CMP_INT(blocked) */
|
||||
/* CMP_INT(sigignore) */
|
||||
/* CMP_INT(sigcatch) */
|
||||
CMP_INT(flags)
|
||||
CMP_INT(min_flt)
|
||||
CMP_INT(cmin_flt)
|
||||
CMP_INT(maj_flt)
|
||||
CMP_INT(cmaj_flt)
|
||||
/* CMP_INT(timeout) */
|
||||
CMP_INT(vsize)
|
||||
CMP_INT(rss)
|
||||
/* CMP_INT(rss_rlim) */
|
||||
/* CMP_INT(start_code) */
|
||||
/* CMP_INT(end_code) */
|
||||
/* CMP_INT(start_stack) */
|
||||
/* CMP_INT(kstk_esp) */
|
||||
/* CMP_INT(kstk_eip) */
|
||||
/* CMP_INT(wchan) */
|
||||
CMP_INT(pcpu)
|
||||
CMP_INT(size)
|
||||
CMP_INT(resident)
|
||||
CMP_INT(share)
|
||||
/* CMP_INT(trs) */
|
||||
/* CMP_INT(lrs) */
|
||||
/* CMP_INT(drs) */
|
||||
/* CMP_INT(dt) */
|
||||
|
||||
/* define user interface to sort keys. Fairly self-explanatory. */
|
||||
|
||||
struct cmp_fun_struct {
|
||||
char letter; /* single option-letter for key */
|
||||
char name[15]; /* long option name for key */
|
||||
int (*fun)(proc_t**, proc_t**); /* pointer to cmp_key */
|
||||
} cmp[] = {
|
||||
/* { '?', "cmdline", &cmp_cmdline }, */
|
||||
{ 'u', "user", &cmp_user },
|
||||
{ 'c', "cmd", &cmp_cmd },
|
||||
/* { '?', "state", &cmp_state }, */
|
||||
/* { '?', "ttyc", &cmp_ttyc }, */
|
||||
{ 'U', "uid", &cmp_uid },
|
||||
{ 'p', "pid", &cmp_pid },
|
||||
{ 'P', "ppid", &cmp_ppid },
|
||||
{ 'g', "pgrp", &cmp_pgrp },
|
||||
{ 'o', "session", &cmp_session },
|
||||
{ 't', "tty", &cmp_tty },
|
||||
{ 'G', "tpgid", &cmp_tpgid },
|
||||
{ 'k', "utime", &cmp_utime },
|
||||
{ 'K', "stime", &cmp_stime },
|
||||
{ 'j', "cutime", &cmp_cutime },
|
||||
{ 'J', "cstime", &cmp_cstime },
|
||||
/* { '?', "counter", &cmp_counter }, */
|
||||
{ 'y', "priority", &cmp_nice },
|
||||
{ 'T', "start_time", &cmp_start_time },
|
||||
/* { '?', "signal", &cmp_signal }, */
|
||||
/* { '?', "blocked", &cmp_blocked }, */
|
||||
/* { '?', "sigignore", &cmp_sigignore }, */
|
||||
/* { '?', "sigcatch", &cmp_sigcatch }, */
|
||||
{ 'f', "flags", &cmp_flags },
|
||||
{ 'm', "min_flt", &cmp_min_flt },
|
||||
{ 'n', "cmin_flt", &cmp_cmin_flt },
|
||||
{ 'M', "maj_flt", &cmp_maj_flt },
|
||||
{ 'N', "cmaj_flt", &cmp_cmaj_flt },
|
||||
/* { 'C', "timeout", &cmp_timeout }, */
|
||||
{ 'v', "vsize", &cmp_vsize },
|
||||
{ 'r', "rss", &cmp_rss },
|
||||
/* { '?', "rss_rlim", &cmp_rss_rlim }, */
|
||||
/* { '?', "start_code", &cmp_start_code }, */
|
||||
/* { '?', "end_code", &cmp_end_code }, */
|
||||
/* { '?', "start_stack", &cmp_start_stack }, */
|
||||
/* { '?', "kstk_esp", &cmp_kstk_esp }, */
|
||||
/* { '?', "kstk_eip", &cmp_kstk_eip }, */
|
||||
/* { '?', "wchan", &cmp_wchan }, */
|
||||
{ 'C', "pcpu", &cmp_pcpu },
|
||||
{ 's', "size", &cmp_size },
|
||||
{ 'R', "resident", &cmp_resident },
|
||||
{ 'S', "share", &cmp_share },
|
||||
/* { '?', "trs", &cmp_trs }, */
|
||||
/* { '?', "lrs", &cmp_lrs }, */
|
||||
/* { '?', "drs", &cmp_drs }, */
|
||||
/* { '?', "dt", &cmp_dt }, */
|
||||
{ '\0',"terminator", NULL }
|
||||
};
|
||||
|
||||
void dump_keys(void) {
|
||||
int i;
|
||||
for(i=0; cmp[i].letter; i++)
|
||||
fprintf(stderr, "%s-O%c , --sort:%-15.15s%s",
|
||||
i%2?"":" ",
|
||||
cmp[i].letter, cmp[i].name,
|
||||
i%2?"\n":"");
|
||||
if (i%2)
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/* command line option parsing. Assign sort_{depth,direction[],function[]}
|
||||
based upon a string of the form:
|
||||
[+-]a[+-]b[+-]c...
|
||||
with a,b,c,... being letter flags corresponding to a particular sort
|
||||
key and the optional '-' specifying a reverse sort on that key. + doesn't
|
||||
mean anything, but it keeps things looking balanced...
|
||||
*/
|
||||
int parse_sort_opt(char* opt) {
|
||||
int i, next_dir=1;
|
||||
for(; *opt ; ++opt) {
|
||||
if (*opt == '-' || *opt == '+') {
|
||||
if (*opt == '-')
|
||||
next_dir = -1;
|
||||
opt++;
|
||||
continue;
|
||||
}
|
||||
for (i = 0; cmp[i].letter; i++)
|
||||
if (*opt == cmp[i].letter)
|
||||
break;
|
||||
if (!cmp[i].letter) {
|
||||
fprintf(stderr,
|
||||
"ps: no such sort key -- %c. Possibilities are:\n", *opt);
|
||||
dump_keys();
|
||||
return -1;
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,
|
||||
"sort level %d: key %s, direction % d\n",
|
||||
sort_depth, cmp[i].name, next_dir);
|
||||
#endif
|
||||
sort_function[sort_depth] = (cmp_t)cmp[i].fun;
|
||||
sort_direction[sort_depth++] = next_dir;
|
||||
next_dir = 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_long_sort(char* opt) {
|
||||
char* comma;
|
||||
int i, more_keys, next_dir=1;
|
||||
do {
|
||||
if (*opt == '-' || *opt == '+') {
|
||||
if (*opt == '-')
|
||||
next_dir = -1;
|
||||
more_keys = 1;
|
||||
opt++;
|
||||
continue;
|
||||
}
|
||||
more_keys = ((comma=index(opt,',')) != NULL);
|
||||
/* keys are ',' delimited */
|
||||
if (more_keys)
|
||||
*comma='\0'; /* terminate for strcmp() */
|
||||
for(i = 0; cmp[i].letter; ++i)
|
||||
if (strcmp(opt, cmp[i].name) == 0)
|
||||
break;
|
||||
if (!cmp[i].letter) {
|
||||
fprintf(stderr,
|
||||
"ps: no such sort key -- %s. Possibilities are:\n", opt);
|
||||
dump_keys();
|
||||
return -1;
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,
|
||||
"sort level %d: key %s, direction % d\n",
|
||||
sort_depth, cmp[i].name, next_dir);
|
||||
#endif
|
||||
sort_function[sort_depth] = (cmp_t)cmp[i].fun;
|
||||
sort_direction[sort_depth++] = next_dir;
|
||||
next_dir = 1;
|
||||
}
|
||||
opt = comma + 1; /* do next loop on next key, if more keys, else done*/
|
||||
} while (more_keys);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reset_sort_options (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
sort_depth=0;
|
||||
for (i=0;i<10;i++){
|
||||
sort_direction[i]=0;
|
||||
sort_function[i]=(cmp_t)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void register_sort_function (int dir, cmp_t func)
|
||||
{
|
||||
sort_function[sort_depth] = func;
|
||||
sort_direction[sort_depth++] = dir;
|
||||
}
|
269
libproc/devname.c
Normal file
269
libproc/devname.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/* device name <-> number map system optimized for rapid, constant time lookup.
|
||||
Copyright Charles Blake, 1996, see COPYING for details.
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define __KERNEL__
|
||||
#include <linux/kdev_t.h>
|
||||
#undef __KERNEL__
|
||||
|
||||
#define DEVDIR "/dev"
|
||||
#define DEVTAB "psdevtab"
|
||||
static char *devtab_paths[] = {
|
||||
"/etc/" DEVTAB,
|
||||
"%s/." DEVTAB,
|
||||
NULL
|
||||
};
|
||||
#define DEVINITIALMODE 0664
|
||||
#define DEV_MAX_PATH (5+256)
|
||||
#define DEV_NAME_MAX 8
|
||||
|
||||
static dev_t major[] = { 2, 3, 4, 5, 19, 20, 22, 23, 24, 25, 32, 33,
|
||||
46, 47, 48, 49 };
|
||||
#define Nminor 256
|
||||
#define Nmajor (sizeof(major)/sizeof(dev_t))
|
||||
#define Ndev (Nmajor*Nminor)
|
||||
#define Ndevtab (Ndev*DEV_NAME_MAX)
|
||||
|
||||
static char* devtab; /* the memory buffer holding all the name strings */
|
||||
|
||||
/* This macro evaluates to the address into the table of the string of
|
||||
DEV_NAME_MAX chars for the device with major m, minor n. */
|
||||
#define TAB(m,n) (devtab + (m)*(Nminor*DEV_NAME_MAX) + (n)*DEV_NAME_MAX)
|
||||
|
||||
static int devtab_initialized = 0;
|
||||
|
||||
static char* name_to_path(char* name); /* forward declarations */
|
||||
static int init_devtab (void);
|
||||
|
||||
/* Device Name -> Number Map
|
||||
many-to-one: -1 on failed match.
|
||||
*/
|
||||
dev_t name_to_dev(char* name) {
|
||||
static struct stat sbuf;
|
||||
return (stat(name_to_path(name), &sbuf) < 0) ? -1 : sbuf.st_rdev;
|
||||
}
|
||||
|
||||
/* find m in a[] assuming a is sorted into ascending order */
|
||||
/* in-line linear search placeholder until more majors warrant binary search */
|
||||
static __inline__ int lookup(dev_t m, dev_t* a, int n) {
|
||||
int k;
|
||||
for(k=0; k < n && a[k] != m; k++)
|
||||
;
|
||||
return (k < n) ? k : -1;
|
||||
}
|
||||
|
||||
/* Device Number -> Name Map
|
||||
one-to-many: first directory order match in DEVDIR, "" on failed match.
|
||||
*/
|
||||
char* dev_to_name(dev_t num) {
|
||||
static char rval[DEV_NAME_MAX+1];
|
||||
dev_t m = MAJOR(num), n = MINOR(num), tmp;
|
||||
if (!devtab_initialized && !init_devtab())
|
||||
return "";
|
||||
if ((tmp = lookup(m, major, Nmajor)) == (dev_t)-1)
|
||||
return "";
|
||||
strncpy(rval, TAB(tmp,n), DEV_NAME_MAX);
|
||||
rval[DEV_NAME_MAX] = '\0';
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int dev_to_devtab(int);
|
||||
|
||||
static int init_devtab(void) {
|
||||
static struct stat sbuf, lbuf;
|
||||
static int fd;
|
||||
char **fmt, path[64], *HOME = getenv("HOME") ? getenv("HOME") : "";
|
||||
for (fmt = devtab_paths; *fmt; fmt++) {
|
||||
snprintf(path, sizeof path, *fmt, HOME);
|
||||
lbuf.st_ino = 0; /* initialize for test later */
|
||||
if (lstat(path, &lbuf) >= 0 && S_ISLNK(lbuf.st_mode))
|
||||
/* don't follow symlinks */
|
||||
continue;
|
||||
if ( (fd = open(path, O_RDONLY)) < 0 /* open DEVTAB file */
|
||||
|| fstat(fd, &sbuf) < 0 /* fstat it */
|
||||
|| (lbuf.st_ino && (sbuf.st_ino != lbuf.st_ino)) /* race */
|
||||
|| sbuf.st_nlink > 1 /* hardlink attack */
|
||||
|| sbuf.st_size != Ndevtab /* make sure it's the right size */
|
||||
|| (devtab = mmap(0, Ndevtab, PROT_READ, MAP_SHARED, fd, 0)) == (caddr_t) -1
|
||||
|| close(fd) == -1)
|
||||
{ /* could not open for read, attempt to fix/create */
|
||||
int oumsk = umask(0);
|
||||
if (devtab)
|
||||
munmap(devtab, Ndevtab);
|
||||
if (((fd = open(path, O_RDWR|O_TRUNC|O_CREAT, DEVINITIALMODE)) == -1 &&
|
||||
(unlink(path), fd = open(path, O_RDWR|O_TRUNC|O_CREAT, DEVINITIALMODE)) == -1)
|
||||
|| !dev_to_devtab(fd)) {
|
||||
close(fd); /* either both opens failed or the constructor failed */
|
||||
unlink(path); /* in case we created but could not fill a file */
|
||||
umask(oumsk);
|
||||
continue;
|
||||
} else {
|
||||
devtab_initialized = 1;
|
||||
close(fd);
|
||||
umask(oumsk);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
return devtab_initialized = 1;
|
||||
}
|
||||
return devtab_initialized;
|
||||
}
|
||||
|
||||
/* stat every file in DEVDIR saving its basename in devtab[] if it has
|
||||
a MAJOR(st_rdev) in our list of majors. return 0 on error otherwise 1. */
|
||||
static int dev_to_devtab(int fd) {
|
||||
static struct stat sbuf;
|
||||
int i;
|
||||
dev_t m;
|
||||
struct dirent* ent;
|
||||
DIR* dev;
|
||||
|
||||
if (!(dev = opendir(DEVDIR))) {
|
||||
fprintf(stderr, "%s: %s\nCannot generate device number -> name mapping.\n",
|
||||
DEVDIR, sys_errlist[errno]);
|
||||
return 0;
|
||||
}
|
||||
if (!(devtab = malloc(Ndevtab))) {
|
||||
fprintf(stderr, "%s: could not allocate memory\n", sys_errlist[errno]);
|
||||
return 0;
|
||||
}
|
||||
memset((void*)devtab, 0, Ndevtab);
|
||||
while ((ent = readdir(dev))) { /* loop over all dirents in DEVDIR */
|
||||
if (lstat(name_to_path(ent->d_name), &sbuf) < 0
|
||||
|| !S_ISCHR(sbuf.st_mode)) /* only look for char special devs */
|
||||
continue; /* due to overloading of majors */
|
||||
m = MAJOR(sbuf.st_rdev); /* copy name to appropriate spot */
|
||||
if ((i = lookup(m, major, Nmajor)) != -1)
|
||||
strncpy(TAB(i,MINOR(sbuf.st_rdev)), ent->d_name, DEV_NAME_MAX);
|
||||
}
|
||||
closedir(dev);
|
||||
if (write(fd, devtab, Ndevtab) != Ndevtab) /* probably no disk space */
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char path[DEV_MAX_PATH];
|
||||
|
||||
static char* name_to_path(char* name) {
|
||||
static char* Path;
|
||||
if (!Path) {
|
||||
strcpy(path, DEVDIR); /* copy DEVDIR */
|
||||
path[sizeof(DEVDIR) - 1] = '/'; /* change NUL to '/' */
|
||||
Path = path + sizeof(DEVDIR); /* put Path at start of basename */
|
||||
}
|
||||
strncpy(Path, name, DEV_MAX_PATH - sizeof(DEVDIR));
|
||||
return path;
|
||||
}
|
||||
|
||||
#ifdef TEST_DEVNAME
|
||||
int main(int argc, char** argv) { /* usage: cmd [<major> <minor>|<name>] */
|
||||
dev_t tmp;
|
||||
if (argc < 2) {
|
||||
printf("%s: [ maj min... | name ... ]\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
if (argv[1][0] >= '0' && argv[1][0] <= '9')
|
||||
for(argv++ ; argv[0] && argv[1] ; argv+=2)
|
||||
printf("%s\n", dev_to_name(MKDEV( atoi(argv[0]), atoi(argv[1]) )));
|
||||
else
|
||||
for(argv++ ; *argv ; argv++) {
|
||||
tmp = name_to_dev(*argv);
|
||||
printf("%d, %d\n", MAJOR(tmp), MINOR(tmp));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
Using this program on over 700 files in /dev to perform number->name resolution
|
||||
took well under 300 microsecs per device number pair on a Pentium 90. It is
|
||||
somewhat tough to time because once the 3 pages have been mapped in, the time is
|
||||
almost zero. For things like top, this method may even be faster in the long
|
||||
run. Those interested can gprof it for me. This system has the virtue of being
|
||||
nearly perfectly adaptable to individual systems, self updating when /dev
|
||||
changes and pretty darn fast when it hasn't. It will be slow for users without
|
||||
perms to change the psdevtab file, though. So this is what I decided was
|
||||
reasonable. If the process does not have perms to create or update
|
||||
/etc/psdevtab and it is out of date, we try /tmp/psdevtab. If /tmp/psdevtab is
|
||||
either out of date or unreadable (malicious user creates it and chmods it),
|
||||
$HOME/.psdevtab is used. This secondarily allows for per-user naming of ttys,
|
||||
but is really so that at most one user sees only a single delay per /dev
|
||||
modification.
|
||||
|
||||
To do the timings I did something like this with zsh:
|
||||
a=(`ls -l *(%^@/) | awk '{print $5 $6}' | sed 's/,/ /'`);
|
||||
time ./test $a
|
||||
|
||||
Finally, for lack of a better file for these to be in, I have collected the
|
||||
old algorithmic device number <-> device name mappings.
|
||||
Let m = major device number and n = minor device number satisfy:
|
||||
devno = m<<8 + n , m = devno>>8 , n = devno && 0x00FF, and let
|
||||
char L[32]="pqrstuvwxyzABCDEFGHIJKLMNOPQRSTU", H[16]="01234567890abcdef";
|
||||
DEVICE NUMBERS SPECIAL FILE NAMES
|
||||
OLD SYSTEM (64 pseudoterminal devices):
|
||||
m=4:
|
||||
n=0..63: tty + itoa_dec(n+1)
|
||||
n=128..191: pty + L[(n-128)/16] + H[(n-128)%16]
|
||||
n=192..255: tty + L[(n-192)/16] + H[(n-192)%16]
|
||||
NEW SYSTEM (256/512 pseudoterminal devices):
|
||||
m=2, n: pty + L[n/16] + H[n%16]
|
||||
m=3, n: tty + L[n/16] + H[n%16]
|
||||
m=4, n: tty + itoa_dec(n+1)
|
||||
m=49, n: pty + L[16+n/16] + H[n%16]
|
||||
m=50, n: tty + L[16+n/16] + H[n%16]
|
||||
(THE SAME IN EITHER SYSTEM)
|
||||
CALL-UNIX AND CONTROLLING TERMINAL DEVICES
|
||||
m=5:
|
||||
n=0: tty
|
||||
n=64..128: cua + {'0' + (n-64)}
|
||||
CYCLADES MULTIPORT:
|
||||
m=19, n: ttyC + itoa_hex(n)
|
||||
m=20, n: cub + itoa_hex(n) */
|
||||
|
||||
/* Re-implementation of old interface with the new generic functions. */
|
||||
|
||||
/* This does exactly the same thing as name_to_dev only now a full "ttyXX"
|
||||
specification will work as well.
|
||||
*/
|
||||
int tty_to_dev(char *tty) {
|
||||
static char pref_name_1[32] = "tty", *pnam1 = pref_name_1 + 3,
|
||||
pref_name_2[32] = "cu", *pnam2 = pref_name_2 + 2;
|
||||
dev_t num;
|
||||
if ((num = name_to_dev(tty)) != (dev_t) -1) /* try tty straight up */
|
||||
return num;
|
||||
strncpy(pnam1, tty, 32 - 3); /* try with "tty" prepended */
|
||||
if ((num = name_to_dev(pref_name_1)) != (dev_t) -1)
|
||||
return num;
|
||||
strncpy(pnam2, tty, 32 - 2); /* try with "cu" prepended */
|
||||
if ((num = name_to_dev(pref_name_2)) != (dev_t) -1)
|
||||
return num;
|
||||
return -1; /* no match */
|
||||
}
|
||||
|
||||
/* new abstraction that can maybe be generalized a little better. */
|
||||
char* abbrev_of_tty(char *tty) {
|
||||
static char temp[32]; /* return buf: good only until next call */
|
||||
char *pos = strpbrk(tty, "yu"); /* end of (presumed) prefices: tty*, cu* */
|
||||
temp[0] = 0;
|
||||
if (tty && tty[0] && pos && pos[0] && pos[1])
|
||||
sprintf(temp, "%*.*s", 3, 3, pos + 1);
|
||||
else
|
||||
strncpy(temp, " ? ", 31);
|
||||
return temp;
|
||||
}
|
||||
|
||||
/* Do in-place modification of the 4-buffer `tty' based upon `dev' */
|
||||
void dev_to_tty(char *tty, int dev) {
|
||||
char* new = abbrev_of_tty(dev_to_name(dev));
|
||||
strncpy(tty, new, 4);
|
||||
}
|
10
libproc/devname.h
Normal file
10
libproc/devname.h
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
dev_t name_to_dev(char* name);
|
||||
char* dev_to_name(dev_t num);
|
||||
|
||||
dev_t tty_to_dev(char *tty);
|
||||
void dev_to_tty(char *tty, int dev);
|
||||
|
||||
char* abbrev_of_tty(char *tty);
|
252
libproc/ksym.c
Normal file
252
libproc/ksym.c
Normal file
@@ -0,0 +1,252 @@
|
||||
/* kernel address -> symbol with next lower address. Charles Blake, 1996.
|
||||
* Written to obviate the need for psdatabase initialization based upon kernel
|
||||
* binary formats, etc.
|
||||
*
|
||||
* The basic algorithm is an approximate (intervals split vaguely 50-50) binary
|
||||
* search taking advantage of the fact the System.map is already sorted in
|
||||
* ascending order by the kernel makefile. It needs to assume an average symbol
|
||||
* record length to avoid scanning the entire symbol table, but in practice the
|
||||
* search time does not seem to be especially sensitive to this choice.
|
||||
*
|
||||
* The search could be an exact binary search if the lines of System.map were
|
||||
* padded with blanks to the right. awk '{printf "%8s%2s %-21.21s\n",$1,$2,$3}'
|
||||
* would do the trick for this but either makes the file large or truncates
|
||||
* symbols. The approximate method seems to be plenty fast enough, costing
|
||||
* only about as much as one extra fstat() or so per process.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/utsname.h>
|
||||
#include "proc/psdata.h"
|
||||
#include "proc/ps.h"
|
||||
#include "proc/version.h"
|
||||
|
||||
#define MAX_ADDR_SZ 32
|
||||
static char *sysmap, *sysmap_last, sysmap_fmt[10];
|
||||
static int sysmap_len, sysmap_mean = 32, sysmap_addrsz;
|
||||
|
||||
/* scan backward in a string no further than address beg looking for c */
|
||||
static char *strchrrev(char *a, char *beg, char c) {
|
||||
if (a)
|
||||
while (--a > beg && *a != c) ;
|
||||
return a;
|
||||
}
|
||||
|
||||
/* return ptr to the beg of approximately the i-th record */
|
||||
static char *addr_str(int i) {
|
||||
char *guess = sysmap + sysmap_mean * i;
|
||||
if (!i) return sysmap;
|
||||
if (guess - sysmap > sysmap_len - 2) guess = sysmap + sysmap_len - 2;
|
||||
for ( ; *guess != '\n' && guess > sysmap; guess--)
|
||||
;
|
||||
return guess + 1;
|
||||
|
||||
}
|
||||
|
||||
/* return ptr to symbol string (\n terminated) given beg of record ptr */
|
||||
static char *sym_put(char *buf, int len, char *addrptr) {
|
||||
char *s;
|
||||
while (*addrptr++ != ' ') ;
|
||||
while (*addrptr++ != ' ') ;
|
||||
strncpy(buf, addrptr, len);
|
||||
for (s = buf; s < buf + len; s++)
|
||||
if (*s == '\n')
|
||||
*s = '\0';
|
||||
buf[len - 1] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Try to open and mmap a single symbol table file and initialize globals */
|
||||
int sysmap_mmap(char *path) {
|
||||
int fd;
|
||||
struct stat sbuf;
|
||||
char *p;
|
||||
if (sysmap) /* do nothing if already mapped */
|
||||
return 1;
|
||||
if ((fd = open(path, O_RDONLY)) < 0
|
||||
|| fstat(fd, &sbuf) < 0
|
||||
|| (sysmap = mmap(0, sbuf.st_size,
|
||||
PROT_READ, MAP_SHARED,
|
||||
fd, 0)) == (caddr_t) -1)
|
||||
{
|
||||
close(fd);
|
||||
sysmap = NULL;
|
||||
return 0;
|
||||
}
|
||||
sysmap_len = sbuf.st_size;
|
||||
sysmap_last = strchrrev(sysmap + sysmap_len - 2, sysmap, '\n') + 1;
|
||||
|
||||
/* Now check first line of sysmap for hex numbers in first column. Note:
|
||||
0x/0X prefixes are disallowed, but easily addable. Capitalization is
|
||||
irrelevant because strncasecmp(3) is used below instead of strncmp. */
|
||||
for (p = sysmap; *p != ' '
|
||||
&& ((*p >= '0' && *p <= '9') ||
|
||||
(*p >= 'A' && *p <= 'F') ||
|
||||
(*p >= 'a' && *p <= 'f'))
|
||||
&& p < sysmap + MAX_ADDR_SZ;
|
||||
p++) /* no-op */ ;
|
||||
if (*p != ' ') { /* uh-oh: cannot understand format */
|
||||
fprintf(stderr, "warning: %s not parseable as a System.map.\n", path);
|
||||
munmap(sysmap, sysmap_len);
|
||||
sysmap = NULL;
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
sysmap_addrsz = p - sysmap;
|
||||
snprintf(sysmap_fmt, sizeof sysmap_fmt, "%%0%dlx", sysmap_addrsz);
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* kernel address -> name resolver.
|
||||
returned value is only good until the next call to the function.
|
||||
*/
|
||||
char *sysmap_symbol(unsigned long address) {
|
||||
static char rval[128], *pc, addr[MAX_ADDR_SZ];
|
||||
int i, p, n = sysmap_len / (double)sysmap_mean;
|
||||
|
||||
sprintf(addr, sysmap_fmt, address);
|
||||
p = 0; pc = sysmap;
|
||||
while (n) {
|
||||
i = p + (n >> 1);
|
||||
if (strncasecmp(addr, pc = addr_str(i), sysmap_addrsz) > 0)
|
||||
p = i + 1;
|
||||
n >>= 1;
|
||||
}
|
||||
if (pc == sysmap_last) /* scan forward but not past end */
|
||||
return sym_put(rval, sizeof rval, pc);
|
||||
while (strncasecmp(addr, pc, sysmap_addrsz) > 0)
|
||||
pc = strchr(pc, '\n') + 1;
|
||||
if (pc == sysmap) /* scan backward but not past beg */
|
||||
return sym_put(rval, sizeof rval, pc);
|
||||
while (strncasecmp(addr, pc, sysmap_addrsz) < 0)
|
||||
pc = strchrrev(pc - 1, sysmap, '\n') + 1;
|
||||
return sym_put(rval, sizeof rval, pc);
|
||||
}
|
||||
|
||||
/* extern struct nlist *namelist; */
|
||||
struct tbl_s vars, fncs;
|
||||
struct psdb_hdr db_hdr;
|
||||
int psdb = -1;
|
||||
|
||||
int open_psdb(void) {
|
||||
static char *sysmap_paths[] = {
|
||||
"/boot/System.map-%s",
|
||||
"/boot/System.map",
|
||||
"/lib/modules/%s/System.map",
|
||||
NULL
|
||||
};
|
||||
static char *psdb_paths[] = {
|
||||
"/etc/psdatabase",
|
||||
"/boot/psdatabase-%s",
|
||||
"/boot/psdatabase",
|
||||
"/lib/modules/%s/psdatabase",
|
||||
NULL
|
||||
};
|
||||
char **fmt, *env, path[64];
|
||||
struct utsname uts;
|
||||
uname(&uts);
|
||||
if ((env = getenv("PS_SYSMAP")) && sysmap_mmap(env))
|
||||
return 0;
|
||||
for (fmt = sysmap_paths; *fmt; fmt++) {
|
||||
snprintf(path, sizeof path, *fmt, uts.release);
|
||||
if (sysmap_mmap(path))
|
||||
return 0;
|
||||
}
|
||||
for (fmt = psdb_paths; *fmt; fmt++) {
|
||||
snprintf(path, sizeof path, *fmt, uts.release);
|
||||
if ((psdb = open(path, O_RDONLY)) != -1 &&
|
||||
read(psdb, (char*)&db_hdr, sizeof db_hdr) == sizeof db_hdr &&
|
||||
strncmp(db_hdr.magic, procps_version, sizeof(db_hdr.magic)) == 0)
|
||||
/* && version_cmp(kernel,psdatabase) */
|
||||
return 0;
|
||||
if (psdb != -1)
|
||||
fprintf(stderr,
|
||||
"psdatabase has magic no. %*s instead of %*s\n",
|
||||
(int) sizeof db_hdr.magic, db_hdr.magic,
|
||||
(int) sizeof db_hdr.magic, procps_version);
|
||||
close(psdb);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void close_psdb(void) {
|
||||
if (sysmap)
|
||||
munmap(sysmap, sysmap_len);
|
||||
else if (psdb != -1)
|
||||
close(psdb);
|
||||
psdb = -1;
|
||||
sysmap = NULL;
|
||||
}
|
||||
|
||||
int read_tbl(struct dbtbl_s *dbtbl, struct tbl_s *tbl) {
|
||||
lseek(psdb, dbtbl->off, SEEK_SET);
|
||||
tbl->tbl = (struct sym_s *) xmalloc(dbtbl->size);
|
||||
if (read(psdb, (char *) tbl->tbl, dbtbl->size) != dbtbl->size) {
|
||||
perror(PSDATABASE);
|
||||
exit(1);
|
||||
}
|
||||
tbl->nsym = dbtbl->nsym;
|
||||
tbl->strings = (char *) (tbl->tbl + tbl->nsym);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char * find_func(unsigned long address) {
|
||||
int n;
|
||||
struct sym_s *p;
|
||||
char *s;
|
||||
|
||||
if (sysmap)
|
||||
return sysmap_symbol(address);
|
||||
if (psdb == -1)
|
||||
return "(no psdb)";
|
||||
if (fncs.tbl == NULL)
|
||||
read_tbl(&db_hdr.fncs, &fncs);
|
||||
p = fncs.tbl;
|
||||
n = fncs.nsym;
|
||||
while (n) {
|
||||
int i = n / 2;
|
||||
if (p[i].addr < address) {
|
||||
p = &p[i+1];
|
||||
if (p->addr > address) {
|
||||
--p;
|
||||
break;
|
||||
}
|
||||
--n;
|
||||
}
|
||||
n /= 2;
|
||||
}
|
||||
s = p->name + fncs.strings;
|
||||
return *s=='_' ? s+1 : s;
|
||||
}
|
||||
|
||||
char * wchan(unsigned long address) {
|
||||
static char zero = 0;
|
||||
char *p;
|
||||
|
||||
if (address) {
|
||||
p = find_func(address);
|
||||
if (strncmp(p, "sys_", 4) == 0)
|
||||
p += 4;
|
||||
while (*p == '_' && *p)
|
||||
++p;
|
||||
} else /* 0 address means not in kernel space */
|
||||
p = &zero;
|
||||
return p;
|
||||
}
|
||||
|
||||
#ifdef SYSMAP_TEST
|
||||
int main(int ac, char** av) {
|
||||
if (ac < 3) {printf("%s System.map lines hexaddr ...\n",av[0]); return 1;}
|
||||
if (!sysmap_mmap(av[1])) return 1;
|
||||
if ((sysmap_mean = atoi(av[2])) <= 0) return 1;
|
||||
for (av += 3; *av; av++)
|
||||
printf("%s %s\n", *av, sysmap_symbol(strtoul(*av, NULL, 16)));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
52
libproc/output.c
Normal file
52
libproc/output.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Some output conversion routines for libproc
|
||||
Copyright (C) 1996, Charles Blake. See COPYING for details.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
/* output a string, converting unprintables to octal as we go, and stopping after
|
||||
processing max chars of output (accounting for expansion due to octal rep).
|
||||
*/
|
||||
unsigned print_str(FILE* file, char *s, unsigned max) {
|
||||
int i;
|
||||
for (i=0; s[i] && i < max; i++)
|
||||
if (isprint(s[i]) || s[i] == ' ')
|
||||
fputc(s[i], file);
|
||||
else {
|
||||
if (max - i > 3) {
|
||||
fprintf(file, "\\%03o", s[i]);
|
||||
i += 3; /* 4 printed, but i counts one */
|
||||
} else
|
||||
return max - i;
|
||||
}
|
||||
return max - i;
|
||||
}
|
||||
|
||||
/* output an argv style NULL-terminated string list, converting unprintables
|
||||
to octal as we go, separating items of the list by 'sep' and stopping after
|
||||
processing max chars of output (accounting for expansion due to octal rep).
|
||||
*/
|
||||
unsigned print_strlist(FILE* file, char **strs, char* sep, unsigned max) {
|
||||
int i, n, seplen = strlen(sep);
|
||||
for (n=0; *strs && n < max; strs++) {
|
||||
for (i=0; strs[0][i] && n+i < max; i++)
|
||||
if (isprint(strs[0][i]) || strs[0][i] == ' ')
|
||||
fputc(strs[0][i], file);
|
||||
else {
|
||||
if (max-(n+i) > 3) {
|
||||
fprintf(file, "\\%03o", strs[0][i]);
|
||||
n += 3; /* 4 printed, but i counts one */
|
||||
} else
|
||||
return max - n;
|
||||
}
|
||||
n += i;
|
||||
if (n + seplen < max) {
|
||||
fputs(sep, file);
|
||||
n += seplen;
|
||||
} else
|
||||
return max - n;
|
||||
}
|
||||
return max - n;
|
||||
}
|
30
libproc/ps.h
Normal file
30
libproc/ps.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* The shadow of the original with only common prototypes now. */
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* get definition of HZ */
|
||||
#include <asm/param.h>
|
||||
|
||||
/* get page info */
|
||||
#include <asm/page.h>
|
||||
|
||||
char *wchan(unsigned long);
|
||||
char *find_func(unsigned long address);
|
||||
void *xcalloc(void *pointer, int size);
|
||||
void *xmalloc(unsigned int size);
|
||||
void *xrealloc(void *oldp, unsigned int size);
|
||||
|
||||
int mult_lvl_cmp(void* a, void* b);
|
||||
int node_mult_lvl_cmp(void* a, void* b);
|
||||
void dump_keys(void);
|
||||
|
||||
char *user_from_uid(int uid);
|
||||
|
||||
int open_sysmap(void);
|
||||
int open_psdb(void);
|
||||
void close_psdb(void);
|
||||
void make_fnctbl(void);
|
||||
|
||||
unsigned print_str (FILE* file, char *s, unsigned max);
|
||||
unsigned print_strlist(FILE* file, char **strs, char* sep, unsigned max);
|
||||
unsigned snprint_strlist(char *buf, int max, char **strs, char *sep);
|
103
libproc/psdata.h
Normal file
103
libproc/psdata.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* psdata.h
|
||||
*
|
||||
* Jeffrey A. Uphoff <juphoff@nrao.edu>, 1995, 1996.
|
||||
* Michael K. Johnson.
|
||||
* Bruno Lankester.
|
||||
* (And others I'm sure...)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Capabilities are for reading system images and producing maps for
|
||||
* WCHAN output.
|
||||
*
|
||||
* AOUT_CAPABLE and ELF_CAPABLE may have 32-bit word size limitations
|
||||
* and have only been tested by the maintainer on Intel systems. They
|
||||
* are retained in the source tree in case they are useful; they are
|
||||
* intended to be generally deprecated.
|
||||
*
|
||||
* BFD_CAPABLE should work on any system with BFD.
|
||||
*
|
||||
* Set the capabilities in the top-level Makefile.
|
||||
*/
|
||||
|
||||
#if defined(ELF_CAPABLE)
|
||||
# define ELF_OBJECT 1
|
||||
# define ELF_FUNC 2
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <linux/utsname.h>
|
||||
|
||||
#define PSDATABASE "/etc/psdatabase"
|
||||
|
||||
struct dbtbl_s {
|
||||
off_t off; /* offset in psdatabase */
|
||||
int nsym; /* # symbols */
|
||||
int size; /* size of array + strings */
|
||||
};
|
||||
|
||||
/*
|
||||
* header of psdatabase
|
||||
*/
|
||||
struct psdb_hdr {
|
||||
/* Current procps package version goes here. kmemps doesn't like this. */
|
||||
char magic[32];
|
||||
/*
|
||||
* These are not functional--they only reside in the database for
|
||||
* informational purposes (i.e. if you want to look at the raw
|
||||
* database and see what kernel it's for).
|
||||
*/
|
||||
char uts_release[__NEW_UTS_LEN];
|
||||
char uts_version[__NEW_UTS_LEN];
|
||||
/*
|
||||
* Again, this is not functional, it's just there for information: it
|
||||
* shows the path to the uncompressed kernel image that was used to
|
||||
* generate this database.
|
||||
*/
|
||||
char sys_path[128];
|
||||
/* List of all functions. */
|
||||
struct dbtbl_s fncs;
|
||||
/*
|
||||
* This is currently only used to look up system_utsname while
|
||||
* psupdate is building the database--it really should be phased out!
|
||||
*/
|
||||
/* List of all bss and data symbols. */
|
||||
struct dbtbl_s vars;
|
||||
/*
|
||||
* The list of tty names that kmemps likes/uses in no longer present
|
||||
* in the procps psdatabase--it was never being built by procps'
|
||||
* psupdate anyway, so I removed the entry from the database header.
|
||||
*/
|
||||
};
|
||||
|
||||
struct sym_s {
|
||||
unsigned long addr; /* core address in kernel */
|
||||
int name; /* offset from strings ptr */
|
||||
};
|
||||
|
||||
struct tbl_s {
|
||||
struct sym_s *tbl;
|
||||
int nsym;
|
||||
char *strings; /* ptr to start of strings */
|
||||
};
|
||||
|
||||
extern struct psdb_hdr db_hdr;
|
||||
extern struct tbl_s fncs, vars;
|
||||
|
||||
int read_tbl (struct dbtbl_s *, struct tbl_s *);
|
||||
void *xmalloc (unsigned int);
|
||||
void *xrealloc (void *, unsigned int);
|
||||
|
||||
#define MLSEEK(FD, WHERE, WHENCE, ERROR)\
|
||||
if (lseek ((FD), (WHERE), (WHENCE)) == -1) {\
|
||||
perror ((ERROR));\
|
||||
exit (errno);\
|
||||
}
|
||||
|
||||
#define MREAD(FD, WHAT, SIZE, ERROR)\
|
||||
if (read ((FD), (WHAT), (SIZE)) != (SIZE)) {\
|
||||
perror ((ERROR));\
|
||||
exit (errno);\
|
||||
}
|
37
libproc/pwcache.c
Normal file
37
libproc/pwcache.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pwd.h>
|
||||
#include "proc/ps.h"
|
||||
|
||||
#define HASHSIZE 16 /* power of 2 */
|
||||
#define HASH(x) ((x) & (HASHSIZE - 1))
|
||||
|
||||
|
||||
static struct pwbuf {
|
||||
int uid;
|
||||
char name[12];
|
||||
struct pwbuf *next;
|
||||
} *pwhash[HASHSIZE];
|
||||
|
||||
char *user_from_uid(int uid)
|
||||
{
|
||||
struct pwbuf **p;
|
||||
struct passwd *pw;
|
||||
|
||||
p = &pwhash[HASH(uid)];
|
||||
while (*p) {
|
||||
if ((*p)->uid == uid)
|
||||
return((*p)->name);
|
||||
p = &(*p)->next;
|
||||
}
|
||||
*p = (struct pwbuf *) xmalloc(sizeof(struct pwbuf));
|
||||
(*p)->uid = uid;
|
||||
if ((pw = getpwuid(uid)) == NULL)
|
||||
sprintf((*p)->name, "#%d", uid);
|
||||
else
|
||||
sprintf((*p)->name, "%-.8s", pw->pw_name);
|
||||
(*p)->next = NULL;
|
||||
return((*p)->name);
|
||||
}
|
||||
|
||||
void bad_user_access_length() { }
|
395
libproc/readproc.c
Normal file
395
libproc/readproc.c
Normal file
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* New Interface to Process Table -- PROCTAB Stream (a la Directory streams)
|
||||
* Copyright(C) 1996. Charles L. Blake.
|
||||
*/
|
||||
#include "proc/version.h"
|
||||
#include "proc/readproc.h"
|
||||
#include "proc/devname.h"
|
||||
#include "proc/ps.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define Do(x) (flags & PROC_ ## x) /* convenient shorthand */
|
||||
|
||||
/* initiate a process table scan
|
||||
*/
|
||||
PROCTAB* openproc(int flags, ...) {
|
||||
va_list ap;
|
||||
PROCTAB* PT = xmalloc(sizeof(PROCTAB));
|
||||
|
||||
if (!Do(PID) && !(PT->procfs = opendir("/proc")))
|
||||
return NULL;
|
||||
PT->flags = flags;
|
||||
va_start(ap, flags); /* Init args list */
|
||||
if (Do(PID))
|
||||
PT->pids = va_arg(ap, pid_t*);
|
||||
else if (Do(TTY))
|
||||
PT->ttys = va_arg(ap, dev_t*);
|
||||
else if (Do(UID)) {
|
||||
PT->uids = va_arg(ap, uid_t*);
|
||||
PT->nuid = va_arg(ap, int);
|
||||
} else if (Do(STAT))
|
||||
PT->stats = va_arg(ap, char*);
|
||||
va_end(ap); /* Clean up args list */
|
||||
if (Do(ANYTTY) && Do(TTY))
|
||||
PT->flags = PT->flags & ~PROC_TTY; /* turn off TTY flag */
|
||||
return PT;
|
||||
}
|
||||
|
||||
/* terminate a process table scan
|
||||
*/
|
||||
void closeproc(PROCTAB* PT) {
|
||||
if (PT->procfs) closedir(PT->procfs);
|
||||
if (PT) free(PT);
|
||||
}
|
||||
|
||||
/* deallocate the space allocated by readproc if the passed rbuf was NULL
|
||||
*/
|
||||
void freeproc(proc_t* p) {
|
||||
if (!p) /* in case p is NULL */
|
||||
return;
|
||||
/* ptrs are after strings to avoid copying memory when building them. */
|
||||
/* so free is called on the address of the address of strvec[0]. */
|
||||
if (p->cmdline)
|
||||
free((void*)*p->cmdline);
|
||||
if (p->environ)
|
||||
free((void*)*p->environ);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/* stat2proc() makes sure it can handle arbitrary executable file basenames
|
||||
for `cmd', i.e. those with embedded whitespace or embedded ')'s. Such names
|
||||
confuse %s (see scanf(3)), so the string is split and %39c is used instead.
|
||||
(except for embedded ')' "(%[^)]c)" would work.
|
||||
*/
|
||||
void stat2proc(char* S, proc_t* P) {
|
||||
char* tmp = strrchr(S, ')'); /* split into "PID (cmd" and "<rest>" */
|
||||
*tmp = '\0'; /* replace trailing ')' with NUL */
|
||||
/* parse these two strings separately, skipping the leading "(". */
|
||||
memset(P->cmd, 0, sizeof P->cmd); /* clear even though *P xcalloc'd ?! */
|
||||
sscanf(S, "%d (%39c", &P->pid, P->cmd);
|
||||
sscanf(tmp + 2, /* skip space after ')' too */
|
||||
"%c %d %d %d %d %d %lu %lu %lu %lu %lu %ld %ld %ld %ld %d "
|
||||
"%d %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %LX %LX %LX %LX %lu",
|
||||
&P->state, &P->ppid, &P->pgrp, &P->session, &P->tty, &P->tpgid,
|
||||
&P->flags, &P->min_flt, &P->cmin_flt, &P->maj_flt, &P->cmaj_flt,
|
||||
&P->utime, &P->stime, &P->cutime, &P->cstime, &P->priority, &P->nice,
|
||||
&P->timeout, &P->it_real_value, &P->start_time, &P->vsize, &P->rss,
|
||||
&P->rss_rlim, &P->start_code, &P->end_code, &P->start_stack,
|
||||
&P->kstk_esp, &P->kstk_eip, &P->signal, &P->blocked, &P->sigignore,
|
||||
&P->sigcatch, &P->wchan);
|
||||
if (P->tty == 0)
|
||||
P->tty = -1; /* the old notty val, update elsewhere bef. moving to 0 */
|
||||
if (linux_version_code < LINUX_VERSION(1,3,39)) {
|
||||
P->priority = 2*15 - P->priority; /* map old meanings to new */
|
||||
P->nice = 15 - P->nice;
|
||||
}
|
||||
if (linux_version_code < LINUX_VERSION(1,1,30) && P->tty != -1)
|
||||
P->tty = 4*0x100 + P->tty; /* when tty wasn't full devno */
|
||||
}
|
||||
|
||||
void statm2proc(char* s, proc_t* P) {
|
||||
sscanf(s, "%ld %ld %ld %ld %ld %ld %ld",
|
||||
&P->size, &P->resident, &P->share,
|
||||
&P->trs, &P->lrs, &P->drs, &P->dt);
|
||||
}
|
||||
|
||||
void nulls2sep(char* str, int len, char sep) {
|
||||
int i;
|
||||
for (i = 0; i < len; i++)
|
||||
if (str[i] == 0)
|
||||
str[i] = sep;
|
||||
}
|
||||
|
||||
int file2str(char *directory, char *what, char *ret, int cap) {
|
||||
static char filename[80];
|
||||
int fd, num_read;
|
||||
|
||||
sprintf(filename, "%s/%s", directory, what);
|
||||
if ( (fd = open(filename, O_RDONLY, 0)) == -1 ) return -1;
|
||||
if ( (num_read = read(fd, ret, cap - 1)) <= 0 ) return -1;
|
||||
ret[num_read] = 0;
|
||||
close(fd);
|
||||
return num_read;
|
||||
}
|
||||
|
||||
char** file2strvec(char* directory, char* what) {
|
||||
char buf[2048]; /* read buf bytes at a time */
|
||||
char *p, *rbuf = 0, *endbuf, **q, **ret;
|
||||
int fd, tot = 0, n, c, end_of_file = 0;
|
||||
int align;
|
||||
|
||||
sprintf(buf, "%s/%s", directory, what);
|
||||
if ( (fd = open(buf, O_RDONLY, 0) ) == -1 ) return NULL;
|
||||
|
||||
/* read whole file into a memory buffer, allocating as we go */
|
||||
while ((n = read(fd, buf, sizeof buf - 1)) > 0) {
|
||||
if (n < sizeof buf - 1)
|
||||
end_of_file = 1;
|
||||
if (n == 0 && rbuf == 0)
|
||||
return NULL; /* process died between our open and read */
|
||||
if (n < 0) {
|
||||
if (rbuf)
|
||||
free(rbuf);
|
||||
return NULL; /* read error */
|
||||
}
|
||||
if (end_of_file && buf[n-1]) /* last read char not null */
|
||||
buf[n++] = '\0'; /* so append null-terminator */
|
||||
rbuf = xrealloc(rbuf, tot + n); /* allocate more memory */
|
||||
memcpy(rbuf + tot, buf, n); /* copy buffer into it */
|
||||
tot += n; /* increment total byte ctr */
|
||||
if (end_of_file)
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
if (n <= 0 && !end_of_file) {
|
||||
if (rbuf) free(rbuf);
|
||||
return NULL; /* read error */
|
||||
}
|
||||
endbuf = rbuf + tot; /* count space for pointers */
|
||||
align = (sizeof(char*)-1) - ((tot + sizeof(char*)-1) & (sizeof(char*)-1));
|
||||
for (c = 0, p = rbuf; p < endbuf; p++)
|
||||
if (!*p)
|
||||
c += sizeof(char*);
|
||||
c += sizeof(char*); /* one extra for NULL term */
|
||||
|
||||
rbuf = xrealloc(rbuf, tot + c + align); /* make room for ptrs AT END */
|
||||
endbuf = rbuf + tot; /* addr just past data buf */
|
||||
q = ret = (char**) (endbuf+align); /* ==> free(*ret) to dealloc */
|
||||
*q++ = p = rbuf; /* point ptrs to the strings */
|
||||
endbuf--; /* do not traverse final NUL */
|
||||
while (++p < endbuf)
|
||||
if (!*p) /* NUL char implies that */
|
||||
*q++ = p+1; /* next string -> next char */
|
||||
|
||||
*q = 0; /* null ptr list terminator */
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* These are some nice GNU C expression subscope "inline" functions.
|
||||
The can be used with arbitrary types and evaluate their arguments
|
||||
exactly once.
|
||||
*/
|
||||
|
||||
/* Test if item X of type T is present in the 0 terminated list L */
|
||||
# define XinL(T, X, L) ( { \
|
||||
T x = (X), *l = (L); \
|
||||
while (*l && *l != x) l++; \
|
||||
*l == x; \
|
||||
} )
|
||||
|
||||
/* Test if item X of type T is present in the list L of length N */
|
||||
# define XinLN(T, X, L, N) ( { \
|
||||
T x = (X), *l = (L); \
|
||||
int i = 0, n = (N); \
|
||||
while (i < n && l[i] != x) i++; \
|
||||
i < n && l[i] == x; \
|
||||
} )
|
||||
|
||||
/* readproc: return a pointer to a proc_t filled with requested info about the
|
||||
* next process available matching the restriction set. If no more such
|
||||
* processes are available, return a null pointer (boolean false). Use the
|
||||
* passed buffer instead of allocating space if it is non-NULL. */
|
||||
|
||||
/* This is optimized so that if a PID list is given, only those files are
|
||||
* searched for in /proc. If other lists are given in addition to the PID list,
|
||||
* the same logic can follow through as for the no-PID list case. This is
|
||||
* fairly complex, but it does try to not to do any unnecessary work.
|
||||
* Unfortunately, the reverse filtering option in which any PID *except* the
|
||||
* ones listed is pursued.
|
||||
*/
|
||||
#define flags (PT->flags)
|
||||
proc_t* readproc(PROCTAB* PT, proc_t* rbuf) {
|
||||
static struct direct *ent; /* dirent handle */
|
||||
static struct stat sb; /* stat buffer */
|
||||
static char path[32], sbuf[256]; /* bufs for stat,statm */
|
||||
int allocated = 0, matched = 0; /* flags */
|
||||
proc_t *p = NULL;
|
||||
|
||||
/* loop until a proc matching restrictions is found or no more processes */
|
||||
/* I know this could be a while loop -- this way is easier to indent ;-) */
|
||||
next_proc: /* get next PID for consideration */
|
||||
if (Do(PID)) {
|
||||
if (!*PT->pids) /* set to next item in pids */
|
||||
return NULL;
|
||||
sprintf(path, "/proc/%d", *(PT->pids)++);
|
||||
matched = 1;
|
||||
} else { /* get next numeric /proc ent */
|
||||
while ((ent = readdir(PT->procfs)) &&
|
||||
(*ent->d_name < '0' || *ent->d_name > '9'))
|
||||
;
|
||||
if (!ent || !ent->d_name)
|
||||
return NULL;
|
||||
sprintf(path, "/proc/%s", ent->d_name);
|
||||
}
|
||||
if (stat(path, &sb) == -1) /* no such dirent (anymore) */
|
||||
goto next_proc;
|
||||
if (Do(UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid))
|
||||
goto next_proc; /* not one of the requested uids */
|
||||
|
||||
if (!allocated) { /* assign mem for return buf */
|
||||
p = rbuf ? rbuf : xcalloc(p, sizeof *p); /* passed buf or alloced mem */
|
||||
allocated = 1; /* remember space is set up */
|
||||
}
|
||||
p->uid = sb.st_uid; /* need a way to get real uid */
|
||||
|
||||
if ((file2str(path, "stat", sbuf, sizeof sbuf)) == -1)
|
||||
goto next_proc; /* error reading /proc/#/stat */
|
||||
stat2proc(sbuf, p); /* parse /proc/#/stat */
|
||||
|
||||
if (!matched && Do(TTY) && !XinL(dev_t, p->tty, PT->ttys))
|
||||
goto next_proc; /* not one of the requested ttys */
|
||||
|
||||
if (!matched && Do(ANYTTY) && p->tty == -1)
|
||||
goto next_proc; /* no controlling terminal */
|
||||
|
||||
if (!matched && Do(STAT) && !strchr(PT->stats,p->state))
|
||||
goto next_proc; /* not one of the requested states */
|
||||
|
||||
if (Do(FILLMEM)) { /* read, parse /proc/#/statm */
|
||||
if ((file2str(path, "statm", sbuf, sizeof sbuf)) != -1 )
|
||||
statm2proc(sbuf, p); /* ignore statm errors here */
|
||||
} /* statm fields just zero */
|
||||
|
||||
/* some number->text resolving which is time consuming */
|
||||
if (Do(FILLTTY))
|
||||
dev_to_tty(p->ttyc, p->tty);
|
||||
if (Do(FILLUSR))
|
||||
strncpy(p->user, user_from_uid(p->uid), sizeof p->user);
|
||||
|
||||
if (Do(FILLCMD)) /* read+parse /proc/#/cmdline */
|
||||
p->cmdline = file2strvec(path, "cmdline");
|
||||
if (Do(FILLENV)) /* read+parse /proc/#/environ */
|
||||
p->environ = file2strvec(path, "environ");
|
||||
|
||||
if (p->state == 'Z') /* fixup cmd for zombies */
|
||||
strncat(p->cmd," <zombie>", sizeof p->cmd);
|
||||
|
||||
return p;
|
||||
}
|
||||
#undef flags
|
||||
|
||||
/* Convenient wrapper around openproc and readproc to slurp in the whole process
|
||||
* tree subset satisfying the constraints of flags and the optional PID list.
|
||||
* Free allocated memory with freeproctree(). The tree structure is a classic
|
||||
* left-list children + right-list siblings. The algorithm is a two-pass of the
|
||||
* process table. Since most process trees will have children with strictly
|
||||
* increasing PIDs, most of the structure will be picked up in the first pass.
|
||||
* The second loop then cleans up any nodes which turn out to have preceeded
|
||||
* their parent in /proc order.
|
||||
*/
|
||||
|
||||
/* Traverse tree 't' breadth-first looking for a process with pid p */
|
||||
proc_t* LookupPID(proc_t* t, pid_t p) {
|
||||
proc_t* tmp = NULL;
|
||||
if (!t)
|
||||
return NULL;
|
||||
if (t->pid == p) /* look here/terminate recursion */
|
||||
return t;
|
||||
if ((tmp = LookupPID(t->l, p))) /* recurse over children */
|
||||
return tmp;
|
||||
for (; t; t=t->r) /* recurse over siblings */
|
||||
if ((tmp = LookupPID(tmp, p)))
|
||||
return tmp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
proc_t* readproctree(int flags, ...) {
|
||||
static proc_t tree;
|
||||
PROCTAB* PT = NULL;
|
||||
proc_t *node, *tmp=NULL, *tmp2=NULL;
|
||||
va_list ap;
|
||||
|
||||
/* pass through apropriate arguments to openproc */
|
||||
va_start(ap, flags);
|
||||
if (Do(UID)) {
|
||||
/* temporary variables to ensure that va_arg() instances
|
||||
* are called in the right order
|
||||
*/
|
||||
uid_t* u;
|
||||
int i;
|
||||
|
||||
u = va_arg(ap, uid_t*);
|
||||
i = va_arg(ap, int);
|
||||
PT = openproc(flags, u, i);
|
||||
}
|
||||
else if (Do(PID) || Do(TTY) || Do(STAT))
|
||||
PT = openproc(flags, va_arg(ap, void*));
|
||||
else
|
||||
PT = openproc(flags);
|
||||
va_end(ap);
|
||||
|
||||
/* first pass: build tree, putting orphans on the first level */
|
||||
tree.l = tree.r = NULL;
|
||||
while ((node = readproc(PT,0)))
|
||||
if ((tmp = LookupPID(&tree, node->ppid))) {
|
||||
node->r = tmp->l->r; /* node --> left list of parent */
|
||||
tmp->l->r = node;
|
||||
} else {
|
||||
node->r = tree.r; /* node --> right list of 'tree' */
|
||||
tree.r = node;
|
||||
}
|
||||
/* second pass: scan tree for PPIDs of level-1 nodes moving links as necessary */
|
||||
for (node = &tree; node; node = node->r)
|
||||
if ((tmp = LookupPID(&tree, node->r->ppid))) {
|
||||
tmp2 = node->r; /* unlink from right list of 'tree' */
|
||||
node->r = node->r->r;
|
||||
tmp2->r = tmp->l->r; /* insert as child of found node */
|
||||
tmp->l->r = node;
|
||||
}
|
||||
closeproc(PT);
|
||||
return &tree;
|
||||
}
|
||||
|
||||
/* Convenient wrapper around openproc and readproc to slurp in the whole process
|
||||
* table subset satisfying the constraints of flags and the optional PID list.
|
||||
* Free allocated memory with freeproctab(). Access via tab[N]->member. The
|
||||
* pointer list is NULL terminated.
|
||||
*/
|
||||
proc_t** readproctab(int flags, ...) {
|
||||
PROCTAB* PT = NULL;
|
||||
proc_t** tab = NULL;
|
||||
int n = 0;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, flags); /* pass through args to openproc */
|
||||
if (Do(UID)) {
|
||||
/* temporary variables to ensure that va_arg() instances
|
||||
* are called in the right order
|
||||
*/
|
||||
uid_t* u;
|
||||
int i;
|
||||
|
||||
u = va_arg(ap, uid_t*);
|
||||
i = va_arg(ap, int);
|
||||
PT = openproc(flags, u, i);
|
||||
}
|
||||
else if (Do(PID) || Do(TTY) || Do(STAT))
|
||||
PT = openproc(flags, va_arg(ap, void*)); /* assume ptr sizes same */
|
||||
else
|
||||
PT = openproc(flags);
|
||||
va_end(ap);
|
||||
do { /* read table: */
|
||||
tab = xrealloc(tab, (n+1)*sizeof(proc_t*));/* realloc as we go, using */
|
||||
tab[n] = readproc(PT, NULL); /* final null to terminate */
|
||||
} while (tab[n++]); /* stop when NULL reached */
|
||||
closeproc(PT);
|
||||
return tab;
|
||||
}
|
||||
|
||||
/* deallocate a table of pointers to proc structures
|
||||
*/
|
||||
void freeproctab(proc_t** tab) {
|
||||
proc_t** p;
|
||||
for(p = tab; *p; p++)
|
||||
freeproc(*p);
|
||||
free(tab);
|
||||
}
|
168
libproc/readproc.h
Normal file
168
libproc/readproc.h
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* New Interface to Process Table -- PROCTAB Stream (a la Directory streams)
|
||||
* Copyright(C) 1996. Charles L. Blake.
|
||||
*/
|
||||
|
||||
/* Basic data structure which holds all information we can get about a process.
|
||||
* (unless otherwise specified, fields are read from /proc/#/stat)
|
||||
*/
|
||||
typedef struct proc_s {
|
||||
char
|
||||
user[10], /* user name corresponding to owner of process */
|
||||
cmd[40], /* basename of executable file in call to exec(2) */
|
||||
state, /* single-char code for process state (S=sleeping) */
|
||||
ttyc[5], /* string representation of controlling tty device */
|
||||
**environ, /* environment string vector (/proc/#/environ) */
|
||||
**cmdline; /* command line string vector (/proc/#/cmdline) */
|
||||
int
|
||||
uid, /* user id */
|
||||
pid, /* process id */
|
||||
ppid, /* pid of parent process */
|
||||
pgrp, /* process group id */
|
||||
session, /* session id */
|
||||
tty, /* full device number of controlling terminal */
|
||||
tpgid, /* terminal process group id */
|
||||
priority, /* kernel scheduling priority */
|
||||
nice; /* standard unix nice level of process */
|
||||
long long
|
||||
signal, /* mask of pending signals */
|
||||
blocked, /* mask of blocked signals */
|
||||
sigignore, /* mask of ignored signals */
|
||||
sigcatch; /* mask of caught signals */
|
||||
long
|
||||
start_time, /* start time of process -- seconds since 1-1-70 */
|
||||
utime, /* user-mode CPU time accumulated by process */
|
||||
stime, /* kernel-mode CPU time accumulated by process */
|
||||
cutime, /* cumulative utime of process and reaped children */
|
||||
cstime, /* cumulative stime of process and reaped children */
|
||||
/* the next 7 members come from /proc/#/statm */
|
||||
size, /* total # of pages of memory */
|
||||
resident, /* number of resident set (non-swapped) pages (4k) */
|
||||
share, /* number of pages of shared (mmap'd) memory */
|
||||
trs, /* text resident set size */
|
||||
lrs, /* shared-lib resident set size */
|
||||
drs, /* data resident set size */
|
||||
dt; /* dirty pages */
|
||||
unsigned
|
||||
pcpu; /* %CPU usage (is not filled in by readproc!!!) */
|
||||
unsigned long
|
||||
vsize, /* number of pages of virtual memory ... */
|
||||
rss, /* resident set size from /proc/#/stat */
|
||||
rss_rlim, /* resident set size ... ? */
|
||||
timeout, /* ? */
|
||||
it_real_value, /* ? */
|
||||
flags, /* kernel flags for the process */
|
||||
min_flt, /* number of minor page faults since process start */
|
||||
maj_flt, /* number of major page faults since process start */
|
||||
cmin_flt, /* cumulative min_flt of process and child processes */
|
||||
cmaj_flt, /* cumulative maj_flt of process and child processes */
|
||||
start_code, /* address of beginning of code segment */
|
||||
end_code, /* address of end of code segment */
|
||||
start_stack, /* address of the bottom of stack for the process */
|
||||
kstk_esp, /* kernel stack pointer */
|
||||
kstk_eip, /* kernel stack pointer */
|
||||
wchan; /* address of kernel wait channel proc is sleeping in */
|
||||
struct proc_s *l, /* ptrs for building arbitrary linked structs */
|
||||
*r; /* (i.e. singly/doubly-linked lists and trees */
|
||||
} proc_t;
|
||||
|
||||
/* PROCTAB: data structure holding the persistent information readproc needs
|
||||
* from openproc(). The setup is intentionally similar to the dirent interface
|
||||
* and other system table interfaces (utmp+wtmp come to mind).
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
typedef struct {
|
||||
DIR* procfs;
|
||||
int flags;
|
||||
pid_t* pids; /* pids of the procs */
|
||||
dev_t* ttys; /* devnos of the cttys */
|
||||
uid_t* uids; /* uids of procs */
|
||||
int nuid; /* cannot really sentinel-terminate unsigned short[] */
|
||||
char* stats; /* status chars (actually output into /proc//stat) */
|
||||
} PROCTAB;
|
||||
|
||||
/* initialize a PROCTAB structure holding needed call-to-call persistent data
|
||||
*/
|
||||
PROCTAB* openproc(int flags, ... /* pid_t*|uid_t*|dev_t*|char* [, int n] */ );
|
||||
|
||||
/* Convenient wrapper around openproc and readproc to slurp in the whole process
|
||||
* table subset satisfying the constraints of flags and the optional PID list.
|
||||
* Free allocated memory with freeproctab(). Access via tab[N]->member. The
|
||||
* pointer list is NULL terminated.
|
||||
*/
|
||||
proc_t** readproctab(int flags, ... /* same as openproc */ );
|
||||
|
||||
/* Convenient wrapper around openproc and readproc to slurp in the whole process
|
||||
* tree subset satisfying the constraints of flags and the optional PID list.
|
||||
*/
|
||||
proc_t* readproctree(int flags, ... /* same as openproc */ );
|
||||
|
||||
/* clean-up open files, etc from the openproc()
|
||||
*/
|
||||
void closeproc(PROCTAB* PT);
|
||||
|
||||
/* retrieve the next process matching the criteria set by the openproc()
|
||||
*/
|
||||
proc_t* readproc(PROCTAB* PT, proc_t* return_buf);
|
||||
|
||||
/* deallocate space allocated by readproc
|
||||
*/
|
||||
void freeproc(proc_t* p);
|
||||
|
||||
/* deallocate space allocated by readproctab
|
||||
*/
|
||||
void freeproctab(proc_t** p);
|
||||
|
||||
/* openproc/readproctab:
|
||||
*
|
||||
* Return PROCTAB* / *proc_t[] or NULL on error ((probably) "/proc" cannot be
|
||||
* opened.) By default readproc will consider all processes as valid to parse
|
||||
* and return, but not actually fill in the cmdline, environ, and /proc/#/statm
|
||||
* derived memory fields.
|
||||
*
|
||||
* `flags' (a bitwise-or of PROC_* below) modifies the default behavior. The
|
||||
* "fill" options will cause more of the proc_t to be filled in. The "filter"
|
||||
* options all use the second argument as the pointer to a list of objects:
|
||||
* process status', process id's, user id's, and tty device numbers. The third
|
||||
* argument is the length of the list (currently only used for lists of user
|
||||
* id's since unsigned short[] supports no convenient termination sentinel.)
|
||||
*/
|
||||
#define PROC_FILLMEM 0x1 /* read statm into the appropriate proc_t entries */
|
||||
#define PROC_FILLCMD 0x2 /* alloc and fill in `cmdline' part of proc_t */
|
||||
#define PROC_FILLENV 0x4 /* alloc and fill in `environ' part of proc_t */
|
||||
#define PROC_FILLTTY 0x8 /* resolve device number -> tty name via psdevtab */
|
||||
#define PROC_FILLUSR 0x10 /* resolve user id number -> user name via passwd */
|
||||
/* consider only processes with one of the passed: */
|
||||
#define PROC_PID 0x100 /* process id numbers ( 0 terminated) */
|
||||
#define PROC_TTY 0x200 /* ctty device nos. ( 0 terminated) */
|
||||
#define PROC_UID 0x400 /* user id numbers ( length needed ) */
|
||||
#define PROC_STAT 0x800 /* status fields ('\0' terminated) */
|
||||
#define PROC_ANYTTY 0x1000 /* proc must have a controlling terminal */
|
||||
|
||||
/* utility functions which may be of general interest: */
|
||||
|
||||
/* slurp /proc/DIR/FILE into a single large string into the passed
|
||||
buffer. return the number of bytes actually used. used for stat,statm
|
||||
*/
|
||||
int file2str(char *dir, char *file, char *buf, int buf_size);
|
||||
|
||||
/* convert a file of null terminated strings into an argv-style string vector
|
||||
* which may be de-allocated with a single free() on a dereference of the return
|
||||
* value, e.g. free(*ret). used for cmdline, environ.
|
||||
*/
|
||||
char** file2strvec(char* directory, char* what);
|
||||
|
||||
/* parse /proc/#/stat entries in string s into a proc_t
|
||||
*/
|
||||
void stat2proc(char* S, proc_t*);
|
||||
|
||||
/* parse /proc/#/statm entries in string s into a proc_t
|
||||
*/
|
||||
void statm2proc(char* s, proc_t*);
|
||||
|
||||
/* convert a memory buffer with nulls into a single string,
|
||||
replacing the nulls with sep. No longer used.
|
||||
*/
|
||||
void nulls2sep(char* str, int len, char sep);
|
65
libproc/signals.c
Normal file
65
libproc/signals.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/* signals.c - signal name handling */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "proc/signals.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
int number;
|
||||
char *name;
|
||||
} SIGNAME;
|
||||
|
||||
|
||||
static SIGNAME signals[] = {
|
||||
#include "signames.h" /* should be in same dir as this file */
|
||||
{ 0,NULL }};
|
||||
|
||||
|
||||
void list_signals(void)
|
||||
{
|
||||
SIGNAME *walk;
|
||||
int col;
|
||||
|
||||
col = 0;
|
||||
for (walk = signals; walk->name; walk++) {
|
||||
if (col+strlen(walk->name)+1 > 80) {
|
||||
putchar('\n');
|
||||
col = 0;
|
||||
}
|
||||
printf("%s%s",col ? " " : "",walk->name);
|
||||
col += strlen(walk->name)+1;
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
|
||||
int get_signal(char *name,char *cmd)
|
||||
{
|
||||
SIGNAME *walk;
|
||||
|
||||
if (isdigit(*name))
|
||||
return atoi(name);
|
||||
for (walk = signals; walk->name; walk++)
|
||||
if (!strcmp(walk->name,name)) break;
|
||||
if (walk->name) return walk->number;
|
||||
fprintf(stderr,"%s: unknown signal; %s -l lists signals.\n",name,cmd);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* get_signal2 is by Michael Shields. 1994/04/25. */
|
||||
int get_signal2(char *name)
|
||||
{
|
||||
SIGNAME *walk;
|
||||
|
||||
if (!name)
|
||||
return(-1);
|
||||
if (isdigit(*name))
|
||||
return atoi(name);
|
||||
for (walk = signals; walk->name; walk++)
|
||||
if (!strcmp(walk->name,name))
|
||||
return(walk->number);
|
||||
return(-1);
|
||||
}
|
12
libproc/signals.h
Normal file
12
libproc/signals.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/* signals.h - signal name handling */
|
||||
|
||||
void list_signals(void);
|
||||
|
||||
/* Lists all known signal names on standard output. */
|
||||
|
||||
int get_signal(char *name,char *cmd);
|
||||
int get_signal2(char *name);
|
||||
|
||||
/* Returns the signal number of NAME. If no such signal exists, an error
|
||||
message is displayed and the program is terminated. CMD is the name of the
|
||||
application. */
|
32
libproc/signames.h
Normal file
32
libproc/signames.h
Normal file
@@ -0,0 +1,32 @@
|
||||
{ 1,"HUP" },
|
||||
{ 2,"INT" },
|
||||
{ 3,"QUIT" },
|
||||
{ 4,"ILL" },
|
||||
{ 5,"TRAP" },
|
||||
{ 6,"ABRT" },
|
||||
{ 6,"IOT" },
|
||||
{ 7,"BUS" },
|
||||
{ 8,"FPE" },
|
||||
{ 9,"KILL" },
|
||||
{ 10,"USR1" },
|
||||
{ 11,"SEGV" },
|
||||
{ 12,"USR2" },
|
||||
{ 13,"PIPE" },
|
||||
{ 14,"ALRM" },
|
||||
{ 15,"TERM" },
|
||||
{ 16,"STKFLT" },
|
||||
{ 17,"CHLD" },
|
||||
{ 18,"CONT" },
|
||||
{ 19,"STOP" },
|
||||
{ 20,"TSTP" },
|
||||
{ 21,"TTIN" },
|
||||
{ 22,"TTOU" },
|
||||
{ 23,"URG" },
|
||||
{ 24,"XCPU" },
|
||||
{ 25,"XFSZ" },
|
||||
{ 26,"VTALRM" },
|
||||
{ 27,"PROF" },
|
||||
{ 28,"WINCH" },
|
||||
{ 29,"IO" },
|
||||
{ 30,"PWR" },
|
||||
{ 31,"UNUSED" },
|
20
libproc/status.c
Normal file
20
libproc/status.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "proc/ps.h"
|
||||
#include "proc/readproc.h"
|
||||
|
||||
char * status(proc_t* task) {
|
||||
static char buf[4] = " ";
|
||||
|
||||
buf[0] = task->state;
|
||||
if (task->rss == 0 && task->state != 'Z')
|
||||
buf[1] = 'W';
|
||||
else
|
||||
buf[1] = ' ';
|
||||
if (task->nice < 0)
|
||||
buf[2] = '<';
|
||||
else if (task->nice > 0)
|
||||
buf[2] = 'N';
|
||||
else
|
||||
buf[2] = ' ';
|
||||
|
||||
return(buf);
|
||||
}
|
176
libproc/sysinfo.c
Normal file
176
libproc/sysinfo.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/* File for parsing top-level /proc entities. */
|
||||
#include "proc/sysinfo.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "proc/version.h"
|
||||
|
||||
#define BAD_OPEN_MESSAGE \
|
||||
"Error: /proc must be mounted\n" \
|
||||
" To mount /proc at boot you need an /etc/fstab line like:\n" \
|
||||
" /proc /proc proc defaults\n" \
|
||||
" In the meantime, mount /proc /proc -t proc\n"
|
||||
|
||||
#define UPTIME_FILE "/proc/uptime"
|
||||
#define LOADAVG_FILE "/proc/loadavg"
|
||||
#define MEMINFO_FILE "/proc/meminfo"
|
||||
|
||||
static char buf[1024];
|
||||
|
||||
/* This macro opens FILE only if necessary and seeks to 0 so that successive
|
||||
calls to the functions are more efficient. It also reads the current
|
||||
contents of the file into the global buf.
|
||||
*/
|
||||
#define FILE_TO_BUF(FILE) { \
|
||||
static int n, fd = -1; \
|
||||
if (fd == -1 && (fd = open(FILE, O_RDONLY)) == -1) { \
|
||||
fprintf(stderr, BAD_OPEN_MESSAGE); \
|
||||
close(fd); \
|
||||
return 0; \
|
||||
} \
|
||||
lseek(fd, 0L, SEEK_SET); \
|
||||
if ((n = read(fd, buf, sizeof buf - 1)) < 0) { \
|
||||
perror(FILE); \
|
||||
close(fd); \
|
||||
fd = -1; \
|
||||
return 0; \
|
||||
} \
|
||||
buf[n] = '\0'; \
|
||||
}
|
||||
|
||||
#define SET_IF_DESIRED(x,y) if (x) *(x) = (y) /* evals 'x' twice */
|
||||
|
||||
int uptime(double *uptime_secs, double *idle_secs) {
|
||||
double up=0, idle=0;
|
||||
|
||||
FILE_TO_BUF(UPTIME_FILE)
|
||||
if (sscanf(buf, "%lf %lf", &up, &idle) < 2) {
|
||||
fprintf(stderr, "bad data in " UPTIME_FILE "\n");
|
||||
return 0;
|
||||
}
|
||||
SET_IF_DESIRED(uptime_secs, up);
|
||||
SET_IF_DESIRED(idle_secs, idle);
|
||||
return up; /* assume never be zero seconds in practice */
|
||||
}
|
||||
|
||||
int loadavg(double *av1, double *av5, double *av15) {
|
||||
double avg_1=0, avg_5=0, avg_15=0;
|
||||
|
||||
FILE_TO_BUF(LOADAVG_FILE)
|
||||
if (sscanf(buf, "%lf %lf %lf", &avg_1, &avg_5, &avg_15) < 3) {
|
||||
fprintf(stderr, "bad data in " LOADAVG_FILE "\n");
|
||||
exit(1);
|
||||
}
|
||||
SET_IF_DESIRED(av1, avg_1);
|
||||
SET_IF_DESIRED(av5, avg_5);
|
||||
SET_IF_DESIRED(av15, avg_15);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The following /proc/meminfo parsing routine assumes the following format:
|
||||
[ <label> ... ] # header lines
|
||||
[ <label> ] <num> [ <num> ... ] # table rows
|
||||
[ repeats of above line ]
|
||||
|
||||
Any lines with fewer <num>s than <label>s get trailing <num>s set to zero.
|
||||
The return value is a NULL terminated unsigned** which is the table of
|
||||
numbers without labels. Convenient enumeration constants for the major and
|
||||
minor dimensions are available in the header file. Note that this version
|
||||
requires that labels do not contain digits. It is readily extensible to
|
||||
labels which do not *begin* with digits, though.
|
||||
*/
|
||||
|
||||
#define MAX_ROW 3 /* these are a little liberal for flexibility */
|
||||
#define MAX_COL 7
|
||||
|
||||
unsigned** meminfo(void) {
|
||||
static unsigned *row[MAX_ROW + 1]; /* row pointers */
|
||||
static unsigned num[MAX_ROW * MAX_COL]; /* number storage */
|
||||
char *p;
|
||||
char fieldbuf[12]; /* bigger than any field name or size in kb */
|
||||
int i, j, k, l;
|
||||
|
||||
set_linux_version();
|
||||
FILE_TO_BUF(MEMINFO_FILE)
|
||||
if (!row[0]) /* init ptrs 1st time through */
|
||||
for (i=0; i < MAX_ROW; i++) /* std column major order: */
|
||||
row[i] = num + MAX_COL*i; /* A[i][j] = A + COLS*i + j */
|
||||
p = buf;
|
||||
for (i=0; i < MAX_ROW; i++) /* zero unassigned fields */
|
||||
for (j=0; j < MAX_COL; j++)
|
||||
row[i][j] = 0;
|
||||
if (linux_version_code < LINUX_VERSION(2,0,0)) {
|
||||
for (i=0; i < MAX_ROW && *p; i++) { /* loop over rows */
|
||||
while(*p && !isdigit(*p)) p++; /* skip chars until a digit */
|
||||
for (j=0; j < MAX_COL && *p; j++) { /* scanf column-by-column */
|
||||
l = sscanf(p, "%u%n", row[i] + j, &k);
|
||||
p += k; /* step over used buffer */
|
||||
if (*p == '\n' || l < 1) /* end of line/buffer */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
while(*p) {
|
||||
sscanf(p,"%11s%n",fieldbuf,&k);
|
||||
if(!strcmp(fieldbuf,"MemTotal:")) {
|
||||
p+=k;
|
||||
sscanf(p," %d",&(row[meminfo_main][meminfo_total]));
|
||||
row[meminfo_main][meminfo_total]<<=10;
|
||||
while(*p++ != '\n');
|
||||
}
|
||||
else if(!strcmp(fieldbuf,"MemFree:")) {
|
||||
p+=k;
|
||||
sscanf(p," %d",&(row[meminfo_main][meminfo_free]));
|
||||
row[meminfo_main][meminfo_free]<<=10;
|
||||
while(*p++ != '\n');
|
||||
}
|
||||
else if(!strcmp(fieldbuf,"MemShared:")) {
|
||||
p+=k;
|
||||
sscanf(p," %d",&(row[meminfo_main][meminfo_shared]));
|
||||
row[meminfo_main][meminfo_shared]<<=10;
|
||||
while(*p++ != '\n');
|
||||
}
|
||||
else if(!strcmp(fieldbuf,"Buffers:")) {
|
||||
p+=k;
|
||||
sscanf(p," %d",&(row[meminfo_main][meminfo_buffers]));
|
||||
row[meminfo_main][meminfo_buffers]<<=10;
|
||||
while(*p++ != '\n');
|
||||
}
|
||||
else if(!strcmp(fieldbuf,"Cached:")) {
|
||||
p+=k;
|
||||
sscanf(p," %d",&(row[meminfo_main][meminfo_cached]));
|
||||
row[meminfo_main][meminfo_cached]<<=10;
|
||||
while(*p++ != '\n');
|
||||
}
|
||||
else if(!strcmp(fieldbuf,"SwapTotal:")) {
|
||||
p+=k;
|
||||
sscanf(p," %d",&(row[meminfo_swap][meminfo_total]));
|
||||
row[meminfo_swap][meminfo_total]<<=10;
|
||||
while(*p++ != '\n');
|
||||
}
|
||||
else if(!strcmp(fieldbuf,"SwapFree:")) {
|
||||
p+=k;
|
||||
sscanf(p," %d",&(row[meminfo_swap][meminfo_free]));
|
||||
row[meminfo_swap][meminfo_free]<<=10;
|
||||
while(*p++ != '\n');
|
||||
}
|
||||
else
|
||||
while(*p++ != '\n'); /* ignore lines we don't understand */
|
||||
}
|
||||
row[meminfo_swap][meminfo_used]=row[meminfo_swap][meminfo_total]-row[meminfo_swap][meminfo_free];
|
||||
row[meminfo_main][meminfo_used]=row[meminfo_main][meminfo_total]-row[meminfo_main][meminfo_free];
|
||||
}
|
||||
return row; /* NULL return ==> error */
|
||||
}
|
||||
|
||||
/* shorthand for read_table("/proc/meminfo")[meminfo_main][meminfo_total] */
|
||||
unsigned read_total_main(void) {
|
||||
unsigned** mem;
|
||||
return (mem = meminfo()) ? mem[meminfo_main][meminfo_total] : -1;
|
||||
}
|
17
libproc/sysinfo.h
Normal file
17
libproc/sysinfo.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef SYSINFO_H
|
||||
#define SYSINFO_H
|
||||
|
||||
int loadavg(double *av1, double *av5, double *av15);
|
||||
int uptime (double *uptime_secs, double *idle_secs);
|
||||
unsigned** meminfo(void);
|
||||
|
||||
enum meminfo_row { meminfo_main = 0,
|
||||
meminfo_swap };
|
||||
|
||||
enum meminfo_col { meminfo_total = 0, meminfo_used, meminfo_free,
|
||||
meminfo_shared, meminfo_buffers, meminfo_cached
|
||||
};
|
||||
|
||||
unsigned read_total_main(void);
|
||||
|
||||
#endif /* SYSINFO_H */
|
14
libproc/tree.h
Normal file
14
libproc/tree.h
Normal file
@@ -0,0 +1,14 @@
|
||||
struct tree_node {
|
||||
proc_t *proc;
|
||||
pid_t pid;
|
||||
pid_t ppid;
|
||||
char *line;
|
||||
char *cmd;
|
||||
char **cmdline;
|
||||
char **environ;
|
||||
int children;
|
||||
int maxchildren;
|
||||
int *child;
|
||||
int have_parent;
|
||||
};
|
||||
|
39
libproc/version.c
Normal file
39
libproc/version.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* Suite version information for procps utilities
|
||||
* Copyright (c) 1995 Martin Schulze <joey@infodrom.north.de>
|
||||
* Ammended by cblake to only export the function symbol.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef MINORVERSION
|
||||
char procps_version[] = "procps version " VERSION "." SUBVERSION "." MINORVERSION;
|
||||
#else
|
||||
char procps_version[] = "procps version " VERSION "." SUBVERSION;
|
||||
#endif
|
||||
|
||||
void display_version(void) {
|
||||
fprintf(stdout, "%s\n", procps_version);
|
||||
}
|
||||
|
||||
/* Linux kernel version information for procps utilities
|
||||
* Copyright (c) 1996 Charles Blake <cblake@bbn.com>
|
||||
*/
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#define LINUX_VERSION(x,y,z) (0x10000*(x) + 0x100*(y) + z)
|
||||
|
||||
int linux_version_code = 0;
|
||||
|
||||
void set_linux_version(void) {
|
||||
static struct utsname uts;
|
||||
int x = 0, y = 0, z = 0; /* cleared in case sscanf() < 3 */
|
||||
|
||||
if (linux_version_code) return;
|
||||
if (uname(&uts) == -1) /* failure most likely implies impending death */
|
||||
exit(1);
|
||||
if (sscanf(uts.release, "%d.%d.%d", &x, &y, &z) < 3)
|
||||
fprintf(stderr, /* *very* unlikely to happen by accident */
|
||||
"Non-standard uts for running kernel:\n"
|
||||
"release %s=%d.%d.%d gives version code %d\n",
|
||||
uts.release, x, y, z, LINUX_VERSION(x,y,z));
|
||||
linux_version_code = LINUX_VERSION(x, y, z);
|
||||
}
|
24
libproc/version.h
Normal file
24
libproc/version.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef PROC_VERSION_H
|
||||
#define PROC_VERSION_H
|
||||
|
||||
/* Suite version information for procps utilities
|
||||
* Copyright (c) 1995 Martin Schulze <joey@infodrom.north.de>
|
||||
* Linux kernel version information for procps utilities
|
||||
* Copyright (c) 1996 Charles Blake <cblake@bbn.com>
|
||||
*/
|
||||
|
||||
extern void display_version(void); /* display suite version */
|
||||
extern char procps_version[]; /* global buf for suite version */
|
||||
|
||||
extern int linux_version_code; /* runtime version of LINUX_VERSION_CODE
|
||||
in /usr/include/linux/version.h */
|
||||
extern void set_linux_version(void); /* set linux_version_code */
|
||||
|
||||
|
||||
/* Convenience macros for composing/decomposing version codes */
|
||||
#define LINUX_VERSION(x,y,z) (0x10000*(x) + 0x100*(y) + z)
|
||||
#define LINUX_VERSION_MAJOR(x) ((x) & 0xFF0000) /* Dare we hope for a */
|
||||
#define LINUX_VERSION_MINOR(x) ((x) & 0x00FF00) /* Linux 256.0.0? ;-) */
|
||||
#define LINUX_VERSION_PATCH(x) ((x) & 0x0000FF)
|
||||
|
||||
#endif /* PROC_VERSION_H */
|
89
libproc/whattime.c
Normal file
89
libproc/whattime.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/* This is a trivial uptime program. I hereby release this program
|
||||
* into the public domain. I disclaim any responsibility for this
|
||||
* program --- use it at your own risk. (as if there were any.. ;-)
|
||||
* -michaelkjohnson (johnsonm@sunsite.unc.edu)
|
||||
*
|
||||
* Modified by Larry Greenfield to give a more traditional output,
|
||||
* count users, etc. (greenfie@gauss.rutgers.edu)
|
||||
*
|
||||
* Modified by mkj again to fix a few tiny buglies.
|
||||
*
|
||||
* Modified by J. Cowley to add printing the uptime message to a
|
||||
* string (for top) and to optimize file handling. 19 Mar 1993.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <utmp.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "proc/whattime.h"
|
||||
#include "proc/sysinfo.h"
|
||||
|
||||
static char buf[128];
|
||||
double av[3];
|
||||
|
||||
char *sprint_uptime(void) {
|
||||
struct utmp *utmpstruct;
|
||||
int upminutes, uphours, updays;
|
||||
int pos;
|
||||
struct tm *realtime;
|
||||
time_t realseconds;
|
||||
int numuser;
|
||||
double uptime_secs, idle_secs;
|
||||
|
||||
/* first get the current time */
|
||||
|
||||
time(&realseconds);
|
||||
realtime = localtime(&realseconds);
|
||||
pos = sprintf(buf, " %2d:%02d%s ",
|
||||
realtime->tm_hour%12 ? realtime->tm_hour%12 : 12,
|
||||
realtime->tm_min, realtime->tm_hour > 11 ? "pm" : "am");
|
||||
|
||||
/* read and calculate the amount of uptime */
|
||||
|
||||
uptime(&uptime_secs, &idle_secs);
|
||||
|
||||
updays = (int) uptime_secs / (60*60*24);
|
||||
strcat (buf, "up ");
|
||||
pos += 3;
|
||||
if (updays)
|
||||
pos += sprintf(buf + pos, "%d day%s, ", updays, (updays != 1) ? "s" : "");
|
||||
upminutes = (int) uptime_secs / 60;
|
||||
uphours = upminutes / 60;
|
||||
uphours = uphours % 24;
|
||||
upminutes = upminutes % 60;
|
||||
if(uphours)
|
||||
pos += sprintf(buf + pos, "%2d:%02d, ", uphours, upminutes);
|
||||
else
|
||||
pos += sprintf(buf + pos, "%d min, ", upminutes);
|
||||
|
||||
/* count the number of users */
|
||||
|
||||
numuser = 0;
|
||||
setutent();
|
||||
while ((utmpstruct = getutent())) {
|
||||
if ((utmpstruct->ut_type == USER_PROCESS) &&
|
||||
(utmpstruct->ut_name[0] != '\0'))
|
||||
numuser++;
|
||||
}
|
||||
endutent();
|
||||
|
||||
pos += sprintf(buf + pos, "%2d user%s, ", numuser, numuser == 1 ? "" : "s");
|
||||
|
||||
loadavg(&av[0], &av[1], &av[2]);
|
||||
|
||||
pos += sprintf(buf + pos, " load average: %.2f, %.2f, %.2f",
|
||||
av[0], av[1], av[2]);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void print_uptime(void)
|
||||
{
|
||||
printf("%s\n", sprint_uptime());
|
||||
}
|
9
libproc/whattime.h
Normal file
9
libproc/whattime.h
Normal file
@@ -0,0 +1,9 @@
|
||||
/* whattime.h --- see whattime.c for explanation */
|
||||
|
||||
#ifndef __WHATTIME_H
|
||||
#define __WHATTIME_H
|
||||
|
||||
void print_uptime(void);
|
||||
char *sprint_uptime(void);
|
||||
|
||||
#endif
|
@@ -1 +1 @@
|
||||
SUBDIRS = server proxy daemon
|
||||
SUBDIRS = server daemon
|
||||
|
@@ -1,3 +1,4 @@
|
||||
Makefile.in
|
||||
Makefile
|
||||
gnuserv
|
||||
server_config.h
|
||||
|
@@ -10,7 +10,7 @@ bin_PROGRAMS = gnuserv
|
||||
|
||||
EXTRA_PROGRAMS = gtop_daemon
|
||||
|
||||
gnuserv_SOURCES = gnuserv.c main.c
|
||||
gnuserv_SOURCES = gnuserv.c main.c slave.c
|
||||
gnuserv_LDADD = $(top_builddir)/lib/libgtop.la \
|
||||
$(top_builddir)/sysdeps/common/libgtop_common.la \
|
||||
$(top_builddir)/sysdeps/@sysdeps_dir@/libgtop_sysdeps.la \
|
||||
|
1210
src/daemon/gnuserv.c
1210
src/daemon/gnuserv.c
File diff suppressed because it is too large
Load Diff
@@ -21,15 +21,22 @@
|
||||
|
||||
#include <glibtop/gnuserv.h>
|
||||
|
||||
#include <glibtop/command.h>
|
||||
#include <glibtop/version.h>
|
||||
#include <glibtop/xmalloc.h>
|
||||
#include <glibtop/union.h>
|
||||
#include <glibtop/open.h>
|
||||
#include <glibtop/union.h>
|
||||
#include <glibtop/xmalloc.h>
|
||||
#include <glibtop/version.h>
|
||||
#include <glibtop/command.h>
|
||||
#include <glibtop/parameter.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <locale.h>
|
||||
|
||||
#undef REAL_DEBUG
|
||||
#define PARENT_DEBUG
|
||||
|
||||
#define MSG_BUFSZ sizeof (struct _glibtop_ipc_message)
|
||||
#define MSG_MSGSZ (MSG_BUFSZ - sizeof (long))
|
||||
|
||||
#if defined(HAVE_GETDTABLESIZE)
|
||||
#define GET_MAX_FDS() getdtablesize()
|
||||
#else
|
||||
@@ -38,180 +45,266 @@
|
||||
#define GET_MAX_FDS() 256
|
||||
#endif
|
||||
|
||||
#define _offset_union(p) ((char *) &response.u.p - (char *) &response)
|
||||
extern void handle_slave_command __P((glibtop_command *, glibtop_response *, const void *));
|
||||
|
||||
#define _offset_union(p) ((char *) &resp->u.p - (char *) resp)
|
||||
#define _offset_data(p) _offset_union (data.p)
|
||||
|
||||
static void do_output __P((int, glibtop_response *, off_t, size_t, const void *));
|
||||
static int do_read __P((int, void *, size_t));
|
||||
|
||||
static void
|
||||
do_output (int s, glibtop_response *response, off_t offset,
|
||||
do_output (int s, glibtop_response *resp, off_t offset,
|
||||
size_t data_size, const void *data)
|
||||
{
|
||||
#ifdef REAL_DEBUG
|
||||
fprintf (stderr, "Really writing %d bytes at offset %d.\n",
|
||||
fprintf (stderr, "Really writing %d bytes at offset %lu.\n",
|
||||
sizeof (glibtop_response), offset);
|
||||
#endif
|
||||
|
||||
response->offset = offset;
|
||||
response->data_size = data_size;
|
||||
resp->offset = offset;
|
||||
resp->data_size = data_size;
|
||||
|
||||
if (send (s, response, sizeof (glibtop_response), 0) < 0)
|
||||
if (send (s, resp, sizeof (glibtop_response), 0) < 0)
|
||||
glibtop_warn_io ("send");
|
||||
|
||||
if (response->data_size) {
|
||||
if (resp->data_size) {
|
||||
#ifdef REAL_DEBUG
|
||||
fprintf (stderr, "Writing %d bytes of data.\n", response->data_size);
|
||||
fprintf (stderr, "Writing %d bytes of data.\n", resp->data_size);
|
||||
#endif
|
||||
|
||||
if (send (s, data, response->data_size, 0) , 0)
|
||||
if (send (s, data, resp->data_size, 0) , 0)
|
||||
glibtop_warn_io ("send");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
do_read (int s, void *ptr, size_t total_size)
|
||||
{
|
||||
int nread;
|
||||
size_t already_read = 0, remaining = total_size;
|
||||
|
||||
while (already_read < total_size) {
|
||||
nread = recv (s, ptr, remaining, 0);
|
||||
if (s)
|
||||
nread = recv (s, ptr, remaining, 0);
|
||||
else
|
||||
nread = read (0, ptr, remaining);
|
||||
|
||||
if ((already_read == 0) && (nread == 0)) {
|
||||
glibtop_warn ("pid %d received eof.", getpid ());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nread <= 0) {
|
||||
glibtop_error_io ("recv");
|
||||
return;
|
||||
glibtop_warn_io ("recv");
|
||||
return 0;
|
||||
}
|
||||
|
||||
already_read += nread;
|
||||
remaining -= nread;
|
||||
(char *) ptr += nread;
|
||||
|
||||
#ifdef REAL_DEBUG
|
||||
fprintf (stderr, "READ (%d): %d - %d - %d\n",
|
||||
nread, already_read, remaining, total_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
return already_read;
|
||||
}
|
||||
|
||||
void
|
||||
handle_socket_connection (glibtop *server, int s)
|
||||
handle_parent_connection (int s)
|
||||
{
|
||||
pid_t pid;
|
||||
glibtop *server = glibtop_global_server;
|
||||
glibtop_response _resp, *resp = &_resp;
|
||||
glibtop_command _cmnd, *cmnd = &_cmnd;
|
||||
char parameter [BUFSIZ];
|
||||
struct timeval tv;
|
||||
glibtop_response response;
|
||||
glibtop_command cmnd;
|
||||
pid_t pid;
|
||||
void *ptr;
|
||||
|
||||
tv.tv_sec = 5;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
while(1) {
|
||||
do_read (s, &cmnd, sizeof (glibtop_command));
|
||||
fprintf (stderr, "Parent features = %lu\n", glibtop_server_features);
|
||||
|
||||
#ifdef REAL_DEBUG
|
||||
fprintf (stderr, "Received command %d from client.\n", cmnd.command);
|
||||
while (do_read (s, &cmnd, sizeof (glibtop_command))) {
|
||||
#ifdef PARENT_DEBUG
|
||||
fprintf (stderr, "Parent (%d) received command %d from client.\n",
|
||||
getpid (), cmnd->command);
|
||||
#endif
|
||||
|
||||
if (cmnd.data_size >= BUFSIZ) {
|
||||
glibtop_warn ("Client sent %d bytes, but buffer is %d", cmnd.size, BUFSIZ);
|
||||
if (cmnd->data_size >= BUFSIZ) {
|
||||
glibtop_warn ("Client sent %d bytes, but buffer is %d", cmnd->size, BUFSIZ);
|
||||
return;
|
||||
}
|
||||
|
||||
memset (parameter, 0, sizeof (parameter));
|
||||
|
||||
if (cmnd.data_size) {
|
||||
#ifdef REAL_DEBUG
|
||||
fprintf (stderr, "Client has %d bytes of data.\n", cmnd.data_size);
|
||||
if (cmnd->data_size) {
|
||||
#ifdef PARENT_DEBUG
|
||||
fprintf (stderr, "Client has %d bytes of data.\n", cmnd->data_size);
|
||||
#endif
|
||||
|
||||
do_read (s, parameter, cmnd.data_size);
|
||||
do_read (s, parameter, cmnd->data_size);
|
||||
|
||||
} else if (cmnd.size) {
|
||||
memcpy (parameter, cmnd.parameter, cmnd.size);
|
||||
} else if (cmnd->size) {
|
||||
memcpy (parameter, cmnd->parameter, cmnd->size);
|
||||
}
|
||||
|
||||
switch (cmnd.command) {
|
||||
|
||||
switch (cmnd->command) {
|
||||
case GLIBTOP_CMND_QUIT:
|
||||
do_output (s, resp, 0, 0, NULL);
|
||||
|
||||
fprintf (stderr, "Sending QUIT command (%d).\n",
|
||||
server->socket);
|
||||
|
||||
glibtop_call_l (server, GLIBTOP_CMND_QUIT,
|
||||
0, NULL, 0, NULL);
|
||||
|
||||
fprintf (stderr, "Done sending QUIT command (%d).\n",
|
||||
server->socket);
|
||||
|
||||
close (server->socket);
|
||||
return;
|
||||
case GLIBTOP_CMND_SYSDEPS:
|
||||
response.u.sysdeps.features = GLIBTOP_SYSDEPS_ALL;
|
||||
do_output (s, &response, _offset_union (sysdeps), 0, NULL);
|
||||
resp->u.sysdeps.features = GLIBTOP_SYSDEPS_ALL;
|
||||
do_output (s, resp, _offset_union (sysdeps), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_CPU:
|
||||
glibtop_get_cpu_l (server, &response.u.data.cpu);
|
||||
do_output (s, &response, _offset_data (cpu), 0, NULL);
|
||||
glibtop_get_cpu_l (server, &resp->u.data.cpu);
|
||||
do_output (s, resp, _offset_data (cpu), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_MEM:
|
||||
glibtop_get_mem_l (server, &response.u.data.mem);
|
||||
do_output (s, &response, _offset_data (mem), 0, NULL);
|
||||
glibtop_get_mem_l (server, &resp->u.data.mem);
|
||||
do_output (s, resp, _offset_data (mem), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_SWAP:
|
||||
glibtop_get_swap_l (server, &response.u.data.swap);
|
||||
do_output (s, &response, _offset_data (swap), 0, NULL);
|
||||
glibtop_get_swap_l (server, &resp->u.data.swap);
|
||||
do_output (s, resp, _offset_data (swap), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_UPTIME:
|
||||
glibtop_get_uptime_l (server, &response.u.data.uptime);
|
||||
do_output (s, &response, _offset_data (uptime), 0, NULL);
|
||||
glibtop_get_uptime_l (server, &resp->u.data.uptime);
|
||||
do_output (s, resp, _offset_data (uptime), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_LOADAVG:
|
||||
glibtop_get_loadavg_l (server, &response.u.data.loadavg);
|
||||
do_output (s, &response, _offset_data (loadavg), 0, NULL);
|
||||
glibtop_get_loadavg_l (server, &resp->u.data.loadavg);
|
||||
do_output (s, resp, _offset_data (loadavg), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_SHM_LIMITS:
|
||||
glibtop_get_shm_limits_l (server, &response.u.data.shm_limits);
|
||||
do_output (s, &response, _offset_data (shm_limits), 0, NULL);
|
||||
glibtop_get_shm_limits_l (server, &resp->u.data.shm_limits);
|
||||
do_output (s, resp, _offset_data (shm_limits), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_MSG_LIMITS:
|
||||
glibtop_get_msg_limits_l (server, &response.u.data.msg_limits);
|
||||
do_output (s, &response, _offset_data (msg_limits), 0, NULL);
|
||||
glibtop_get_msg_limits_l (server, &resp->u.data.msg_limits);
|
||||
do_output (s, resp, _offset_data (msg_limits), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_SEM_LIMITS:
|
||||
glibtop_get_sem_limits_l (server, &response.u.data.sem_limits);
|
||||
do_output (s, &response, _offset_data (sem_limits), 0, NULL);
|
||||
glibtop_get_sem_limits_l (server, &resp->u.data.sem_limits);
|
||||
do_output (s, resp, _offset_data (sem_limits), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_PROCLIST:
|
||||
ptr = glibtop_get_proclist_l (server, &response.u.data.proclist);
|
||||
do_output (s, &response, _offset_data (proclist),
|
||||
response.u.data.proclist.total, ptr);
|
||||
ptr = glibtop_get_proclist_l (server, &resp->u.data.proclist);
|
||||
do_output (s, resp, _offset_data (proclist),
|
||||
resp->u.data.proclist.total, ptr);
|
||||
glibtop_free_r (server, ptr);
|
||||
break;
|
||||
case GLIBTOP_CMND_PROC_STATE:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_state_l
|
||||
(server, &response.u.data.proc_state, pid);
|
||||
do_output (s, &response, _offset_data (proc_state), 0, NULL);
|
||||
(server, &resp->u.data.proc_state, pid);
|
||||
do_output (s, resp, _offset_data (proc_state), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_PROC_UID:
|
||||
pid = 1;
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_uid_l
|
||||
(server, &response.u.data.proc_uid, pid);
|
||||
do_output (s, &response, _offset_data (proc_uid), 0, NULL);
|
||||
(server, &resp->u.data.proc_uid, pid);
|
||||
do_output (s, resp, _offset_data (proc_uid), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_PROC_MEM:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_mem_l
|
||||
(server, &response.u.data.proc_mem, pid);
|
||||
do_output (s, &response, _offset_data (proc_mem), 0, NULL);
|
||||
(server, &resp->u.data.proc_mem, pid);
|
||||
do_output (s, resp, _offset_data (proc_mem), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_PROC_TIME:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_time_l
|
||||
(server, &response.u.data.proc_time, pid);
|
||||
do_output (s, &response, _offset_data (proc_time), 0, NULL);
|
||||
(server, &resp->u.data.proc_time, pid);
|
||||
do_output (s, resp, _offset_data (proc_time), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_PROC_SIGNAL:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_signal_l
|
||||
(server, &response.u.data.proc_signal, pid);
|
||||
do_output (s, &response, _offset_data (proc_signal), 0, NULL);
|
||||
(server, &resp->u.data.proc_signal, pid);
|
||||
do_output (s, resp, _offset_data (proc_signal), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_PROC_KERNEL:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_kernel_l
|
||||
(server, &response.u.data.proc_kernel, pid);
|
||||
do_output (s, &response, _offset_data (proc_kernel), 0, NULL);
|
||||
(server, &resp->u.data.proc_kernel, pid);
|
||||
do_output (s, resp, _offset_data (proc_kernel), 0, NULL);
|
||||
break;
|
||||
case GLIBTOP_CMND_PROC_SEGMENT:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_segment_l
|
||||
(server, &response.u.data.proc_segment, pid);
|
||||
do_output (s, &response, _offset_data (proc_segment), 0, NULL);
|
||||
(server, &resp->u.data.proc_segment, pid);
|
||||
do_output (s, resp, _offset_data (proc_segment), 0, NULL);
|
||||
break;
|
||||
default:
|
||||
glibtop_warn ("Parent received unknown command %u",
|
||||
cmnd->command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handle_child_connection (int s)
|
||||
{
|
||||
glibtop *server = glibtop_global_server;
|
||||
glibtop_response _resp, *resp = &_resp;
|
||||
glibtop_command _cmnd, *cmnd = &_cmnd;
|
||||
char parameter [BUFSIZ];
|
||||
void *ptr;
|
||||
|
||||
while (do_read (s, cmnd, sizeof (glibtop_command))) {
|
||||
#ifdef CHILD_DEBUG
|
||||
fprintf (stderr, "Child (%d - %d) received command "
|
||||
"%d from client.\n", getpid (), s, cmnd->command);
|
||||
#endif
|
||||
|
||||
if (cmnd->data_size >= BUFSIZ) {
|
||||
glibtop_warn ("Client sent %d bytes, but buffer is %d", cmnd->size, BUFSIZ);
|
||||
return;
|
||||
}
|
||||
|
||||
memset (parameter, 0, sizeof (parameter));
|
||||
|
||||
if (cmnd->data_size) {
|
||||
#ifdef CHILD_DEBUG
|
||||
fprintf (stderr, "Client has %d bytes of data.\n", cmnd->data_size);
|
||||
#endif
|
||||
|
||||
do_read (s, parameter, cmnd->data_size);
|
||||
|
||||
} else if (cmnd->size) {
|
||||
memcpy (parameter, cmnd->parameter, cmnd->size);
|
||||
}
|
||||
|
||||
switch (cmnd->command) {
|
||||
case GLIBTOP_CMND_QUIT:
|
||||
do_output (s, resp, 0, 0, NULL);
|
||||
return;
|
||||
#if GLIBTOP_SUID_PROCLIST
|
||||
case GLIBTOP_CMND_PROCLIST:
|
||||
ptr = glibtop_get_proclist_p
|
||||
(server, &resp->u.data.proclist);
|
||||
do_output (s, resp, _offset_data (proclist),
|
||||
resp->u.data.proclist.total, ptr);
|
||||
glibtop_free_r (server, ptr);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
handle_slave_command (cmnd, resp, parameter);
|
||||
do_output (s, resp, resp->offset, 0, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
40
src/daemon/server_config.h.in
Normal file
40
src/daemon/server_config.h.in
Normal file
@@ -0,0 +1,40 @@
|
||||
/* This is a sample config file.
|
||||
*
|
||||
* Copy this file to 'server_config.h' and edit it to fix your needs !
|
||||
*
|
||||
* You can also use the 'server_config.pl' script to create 'server_config.h'.
|
||||
*
|
||||
/
|
||||
|
||||
#define SERVER_PORT 42800 /* Port the server should listen on. */
|
||||
|
||||
/* NOTE: On RedHat 5.1 nobody is UID 99 and GID 99.
|
||||
*
|
||||
* The 'server_config.pl' script will use the real UID and GID of 'nobody'
|
||||
* on your system as default.
|
||||
*
|
||||
* NOTE: This only works if the server is started as root or SUID to root.
|
||||
*/
|
||||
|
||||
#define SERVER_UID 99 /* User ID the server should run as. */
|
||||
#define SERVER_GID 99 /* Group ID the server should run as. */
|
||||
|
||||
#define HOST_TABLE_ENTRIES 1 /* Number of entries in the host table. */
|
||||
|
||||
/* List of hosts that should be authorized to connect to the server.
|
||||
*
|
||||
* SECURITY WARNING:
|
||||
* Enabling access for a particular hosts means the ALL USERS on this host will
|
||||
* be allowed to connect to the server !
|
||||
*
|
||||
* If you want security, let this table empty and use the 'xauth' method instead.
|
||||
* Look at the manpage of gnuserv (1) as shipped with GNU Emacs for more details
|
||||
* about security. The server uses the same security mechanisms like gnuserv from
|
||||
* XEmacs 20.3.
|
||||
*/
|
||||
|
||||
const char *permitted_host_names [HOST_TABLE_ENTRIES] =
|
||||
{ "localhost" };
|
||||
|
||||
unsigned long permitted_hosts [HOST_TABLE_ENTRIES];
|
||||
|
111
src/daemon/server_config.pl
Executable file
111
src/daemon/server_config.pl
Executable file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
require 5.004;
|
||||
use strict;
|
||||
|
||||
print "Enter port the server should listen on [42800]: ";
|
||||
|
||||
my $port = <stdin>; chop $port;
|
||||
$port = 42800 unless $port =~ /^\d+$/;
|
||||
|
||||
print "\nUser name or UID to run as [nobody]: ";
|
||||
|
||||
my $user = <stdin>; chop $user; $user = 'nobody' if $user eq '';
|
||||
|
||||
my ($login, $pass, $uid, $gid);
|
||||
|
||||
unless ($user =~ /^\d+$/) {
|
||||
($login, $pass, $uid, $gid) = getpwnam ($user) or
|
||||
die "User '$user' not in passwd file.";
|
||||
}
|
||||
|
||||
my $g_default = (defined $gid) ? $gid : 'nogroup';
|
||||
|
||||
print "Group name or GID to run as [$g_default]: ";
|
||||
|
||||
my $group = <stdin>; chop $group; $group = $g_default if $group eq '';
|
||||
|
||||
unless ($group =~ /^\d+$/) {
|
||||
$gid = getgrnam ($group) or
|
||||
die "Group '$group' not in group file.";
|
||||
}
|
||||
|
||||
print "\nEnter list of hosts which should be authorized to";
|
||||
print "\nconnect to the server (terminate with a blank line):\n\n";
|
||||
|
||||
print "SECURITY WARNING:\n";
|
||||
print " Enabling access for a particular hosts means the ALL USERS on this host will\n";
|
||||
print " be allowed to connect to the server !\n\n";
|
||||
|
||||
print " If you want security, let this table empty and use the 'xauth' method instead.\n";
|
||||
print " Look at the manpage of gnuserv (1) as shipped with GNU Emacs for more details\n";
|
||||
print " about security. The server uses the same security mechanisms like gnuserv from\n";
|
||||
print " XEmacs 20.3\n\n";
|
||||
|
||||
my @hosts = ();
|
||||
my @host_addrs = ();
|
||||
my @host_names = ();
|
||||
|
||||
while (1) {
|
||||
print "Host: ";
|
||||
|
||||
my $host = <stdin>; chop $host;
|
||||
last if $host eq '';
|
||||
|
||||
my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname ($host) or
|
||||
die "gethostbyname (): Can't resolve '$host'";
|
||||
|
||||
my ($a,$b,$c,$d) = unpack('C4',$addrs[0]);
|
||||
|
||||
push @hosts, sprintf ("0x%02X%02X%02X%02X", $d, $c, $b, $a);
|
||||
push @host_addrs, sprintf ("%d.%d.%d.%d", $a, $b, $c, $d);
|
||||
push @host_names, $name;
|
||||
};
|
||||
|
||||
print "\n";
|
||||
print "This is your config:\n";
|
||||
print "====================\n\n";
|
||||
|
||||
printf qq[%-30s: %d\n\n], 'Port', $port;
|
||||
printf qq[%-30s: %d\n], 'UID', $uid;
|
||||
printf qq[%-30s: %d\n\n], 'GID', $gid;
|
||||
|
||||
foreach (0..$#hosts) {
|
||||
printf qq[%-30s (%s - %s)\n], $host_names[$_], $hosts[$_], $host_addrs [$_];
|
||||
}
|
||||
|
||||
print "\n";
|
||||
|
||||
print "Accept? (yes/no) ";
|
||||
|
||||
my $accept = <stdin>; chop $accept;
|
||||
|
||||
exit unless $accept eq 'yes';
|
||||
|
||||
print "\n";
|
||||
|
||||
open CONFIG, "> server_config.h" or
|
||||
die "open (server_config.h): $!";
|
||||
select CONFIG;
|
||||
|
||||
printf qq[\#define SERVER_PORT\t\t%d\n\n], $port;
|
||||
|
||||
printf qq[\#define SERVER_UID\t\t%d\n], $uid;
|
||||
printf qq[\#define SERVER_GID\t\t%d\n\n], $gid;
|
||||
|
||||
printf qq[\#define HOST_TABLE_ENTRIES\t%d\n\n], $#hosts + 1;
|
||||
|
||||
foreach (@host_names) {
|
||||
$_ = qq["$_"];
|
||||
}
|
||||
|
||||
printf qq[const char *permitted_host_names [HOST_TABLE_ENTRIES] = \n];
|
||||
printf qq[{ %s };\n\n], join (', ', @host_names);
|
||||
|
||||
printf qq[unsigned long permitted_hosts [HOST_TABLE_ENTRIES];\n];
|
||||
|
||||
close CONFIG;
|
||||
|
||||
select STDOUT;
|
||||
|
||||
print "Your config has successfully been written to 'server_config.h'.\n";
|
155
src/daemon/slave.c
Normal file
155
src/daemon/slave.c
Normal file
@@ -0,0 +1,155 @@
|
||||
/* $Id$ */
|
||||
|
||||
/* Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
|
||||
This file is part of the Gnome Top Library.
|
||||
Contributed by Martin Baulig <martin@home-of-linux.org>, April 1998.
|
||||
|
||||
The Gnome Top Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The Gnome Top Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <glibtop.h>
|
||||
#include <glibtop/gnuserv.h>
|
||||
|
||||
#include <glibtop/open.h>
|
||||
#include <glibtop/union.h>
|
||||
|
||||
#include <glibtop/command.h>
|
||||
#include <glibtop/parameter.h>
|
||||
|
||||
#define _offset_union(p) ((char *) &resp->u.p - (char *) resp)
|
||||
#define _offset_data(p) _offset_union (data.p)
|
||||
|
||||
void
|
||||
handle_slave_command (glibtop_command *cmnd, glibtop_response *resp,
|
||||
const void *parameter)
|
||||
{
|
||||
glibtop *server = glibtop_global_server;
|
||||
pid_t pid;
|
||||
|
||||
switch (cmnd->command) {
|
||||
case GLIBTOP_CMND_SYSDEPS:
|
||||
resp->u.sysdeps.features = glibtop_server_features;
|
||||
resp->offset = _offset_union (sysdeps);
|
||||
break;
|
||||
#if GLIBTOP_SUID_CPU
|
||||
case GLIBTOP_CMND_CPU:
|
||||
glibtop_get_cpu_p (server, &resp->u.data.cpu);
|
||||
resp->offset = _offset_data (cpu);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_MEM
|
||||
case GLIBTOP_CMND_MEM:
|
||||
glibtop_get_mem_p (server, &resp->u.data.mem);
|
||||
resp->offset = _offset_data (mem);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_SWAP
|
||||
case GLIBTOP_CMND_SWAP:
|
||||
glibtop_get_swap_p (server, &resp->u.data.swap);
|
||||
resp->offset = _offset_data (swap);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_UPTIME
|
||||
case GLIBTOP_CMND_UPTIME:
|
||||
glibtop_get_uptime_p (server, &resp->u.data.uptime);
|
||||
resp->offset = _offset_data (uptime);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_LOADAVG
|
||||
case GLIBTOP_CMND_LOADAVG:
|
||||
glibtop_get_loadavg_p (server, &resp->u.data.loadavg);
|
||||
resp->offset = _offset_data (loadavg);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_SHM_LIMITS
|
||||
case GLIBTOP_CMND_SHM_LIMITS:
|
||||
glibtop_get_shm_limits_p (server, &resp->u.data.shm_limits);
|
||||
resp->offset = _offset_data (shm_limits);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_MSG_LIMITS
|
||||
case GLIBTOP_CMND_MSG_LIMITS:
|
||||
glibtop_get_msg_limits_p (server, &resp->u.data.msg_limits);
|
||||
resp->offset = _offset_data (msg_limits);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_SEM_LIMITS
|
||||
case GLIBTOP_CMND_SEM_LIMITS:
|
||||
glibtop_get_sem_limits_p (server, &resp->u.data.sem_limits);
|
||||
resp->offset = _offset_data (sem_limits);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_PROC_STATE
|
||||
case GLIBTOP_CMND_PROC_STATE:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_state_p
|
||||
(server, &resp->u.data.proc_state, pid);
|
||||
resp->offset = _offset_data (proc_state);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_PROC_UID
|
||||
case GLIBTOP_CMND_PROC_UID:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_uid_p
|
||||
(server, &resp->u.data.proc_uid, pid);
|
||||
resp->offset = _offset_data (proc_uid);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_PROC_MEM
|
||||
case GLIBTOP_CMND_PROC_MEM:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_mem_p
|
||||
(server, &resp->u.data.proc_mem, pid);
|
||||
resp->offset = _offset_data (proc_mem);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_PROC_TIME
|
||||
case GLIBTOP_CMND_PROC_TIME:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_time_p
|
||||
(server, &resp->u.data.proc_time, pid);
|
||||
resp->offset = _offset_data (proc_time);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_PROC_SIGNAL
|
||||
case GLIBTOP_CMND_PROC_SIGNAL:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_signal_p
|
||||
(server, &resp->u.data.proc_signal, pid);
|
||||
resp->offset = _offset_data (proc_signal);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_PROC_KERNEL
|
||||
case GLIBTOP_CMND_PROC_KERNEL:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_kernel_p
|
||||
(server, &resp->u.data.proc_kernel, pid);
|
||||
resp->offset = _offset_data (proc_kernel);
|
||||
break;
|
||||
#endif
|
||||
#if GLIBTOP_SUID_PROC_SEGMENT
|
||||
case GLIBTOP_CMND_PROC_SEGMENT:
|
||||
memcpy (&pid, parameter, sizeof (pid_t));
|
||||
glibtop_get_proc_segment_p
|
||||
(server, &resp->u.data.proc_segment, pid);
|
||||
resp->offset = _offset_data (proc_segment);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
glibtop_error ("Child received unknown command %u",
|
||||
cmnd->command);
|
||||
break;
|
||||
}
|
||||
}
|
@@ -55,25 +55,8 @@ int main(int argc, char *argv[])
|
||||
uid = getuid (); euid = geteuid ();
|
||||
gid = getgid (); egid = getegid ();
|
||||
|
||||
if (setreuid (euid, uid)) _exit (1);
|
||||
|
||||
if (setregid (egid, gid)) _exit (1);
|
||||
|
||||
/* !!! END OF SUID ROOT PART !!! */
|
||||
|
||||
/* For security reasons, we temporarily drop our priviledges
|
||||
* before doing the gettext stuff. */
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, GTOPLOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
glibtop_version ();
|
||||
|
||||
/* !!! WE ARE ROOT HERE - CHANGE WITH CAUTION !!! */
|
||||
|
||||
setreuid (uid, euid); setregid (gid, egid);
|
||||
|
||||
glibtop_open_r (&server, argv [0], 0, 0);
|
||||
|
||||
if (setreuid (euid, uid)) _exit (1);
|
||||
@@ -89,7 +72,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
while(1) {
|
||||
/* block on read from client */
|
||||
/* fprintf (stderr, "waiting for input ...\n"); */
|
||||
nread = read (0, &size, sizeof (size_t));
|
||||
|
||||
/* will return 0 if parent exits. */
|
||||
|
@@ -21,6 +21,8 @@
|
||||
|
||||
#include <glibtop/error.h>
|
||||
|
||||
#define DEFAULT_NAME "ERROR"
|
||||
|
||||
/* Prints error message and exits. */
|
||||
|
||||
void
|
||||
@@ -30,7 +32,7 @@ glibtop_error_r (glibtop *server, char *format, ...)
|
||||
|
||||
va_start (ap, format);
|
||||
|
||||
fprintf (stderr, "%s: ", server->name);
|
||||
fprintf (stderr, "%s: ", server ? server->name : DEFAULT_NAME);
|
||||
vfprintf (stderr, format, ap);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
@@ -45,7 +47,7 @@ glibtop_error_io_r (glibtop *server, char *format, ...)
|
||||
|
||||
va_start (ap, format);
|
||||
|
||||
fprintf (stderr, "%s: ", server->name);
|
||||
fprintf (stderr, "%s: ", server ? server->name : DEFAULT_NAME);
|
||||
vfprintf (stderr, format, ap);
|
||||
fprintf (stderr, ": %s\n", strerror (errno));
|
||||
|
||||
@@ -60,7 +62,7 @@ glibtop_warn_r (glibtop *server, char *format, ...)
|
||||
|
||||
va_start (ap, format);
|
||||
|
||||
fprintf (stderr, "%s: ", server->name);
|
||||
fprintf (stderr, "%s: ", server ? server->name : DEFAULT_NAME);
|
||||
vfprintf (stderr, format, ap);
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
@@ -74,7 +76,7 @@ glibtop_warn_io_r (glibtop *server, char *format, ...)
|
||||
|
||||
va_start (ap, format);
|
||||
|
||||
fprintf (stderr, "%s: ", server->name);
|
||||
fprintf (stderr, "%s: ", server ? server->name : DEFAULT_NAME);
|
||||
vfprintf (stderr, format, ap);
|
||||
fprintf (stderr, ": %s\n", strerror (errno));
|
||||
|
||||
|
@@ -1,22 +1,22 @@
|
||||
/* -*-C-*-
|
||||
Common library code for the GNU Emacs server and client.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
Copying is permitted under those conditions described by the GNU
|
||||
General Public License.
|
||||
|
||||
Copyright (C) 1989 Free Software Foundation, Inc.
|
||||
|
||||
Author: Andy Norman (ange@hplb.hpl.hp.com), based on
|
||||
'etc/server.c' and 'etc/emacsclient.c' from the 18.52 GNU
|
||||
Emacs distribution.
|
||||
|
||||
Please mail bugs and suggestions to the author at the above address.
|
||||
*/
|
||||
* Common library code for the GNU Emacs server and client.
|
||||
*
|
||||
* This file is part of GNU Emacs.
|
||||
*
|
||||
* Copying is permitted under those conditions described by the GNU
|
||||
* General Public License.
|
||||
*
|
||||
* Copyright (C) 1989 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Andy Norman (ange@hplb.hpl.hp.com), based on
|
||||
* 'etc/server.c' and 'etc/emacsclient.c' from the 18.52 GNU
|
||||
* Emacs distribution.
|
||||
*
|
||||
* Please mail bugs and suggestions to the author at the above address.
|
||||
*/
|
||||
|
||||
/* HISTORY
|
||||
* 11-Nov-1990 bristor@simba
|
||||
* 11-Nov-1990 bristor@simba
|
||||
* Added EOT stuff.
|
||||
*/
|
||||
|
||||
@@ -29,35 +29,30 @@
|
||||
* ../etc/gnuserv.README relative to the directory containing this file)
|
||||
*/
|
||||
|
||||
#if 0
|
||||
static char rcsid [] = "!Header: gnuslib.c,v 2.4 95/02/16 11:57:37 arup alpha !";
|
||||
#endif
|
||||
|
||||
#include <glibtop.h>
|
||||
#include <glibtop/gnuserv.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef SYSV_IPC
|
||||
static int connect_to_ipc_server (void);
|
||||
#endif
|
||||
#ifdef UNIX_DOMAIN_SOCKETS
|
||||
static int connect_to_unix_server (void);
|
||||
static int connect_to_unix_server __P((void));
|
||||
#endif
|
||||
|
||||
#ifdef INTERNET_DOMAIN_SOCKETS
|
||||
static int connect_to_internet_server (const char *serverhost, u_short port);
|
||||
static int connect_to_internet_server __P((const char *, u_short));
|
||||
#endif
|
||||
|
||||
/* On some systems, e.g. DGUX, inet_addr returns a 'struct in_addr'. */
|
||||
#ifdef HAVE_BROKEN_INET_ADDR
|
||||
# define IN_ADDR struct in_addr
|
||||
# define NUMERIC_ADDR_ERROR (numeric_addr.s_addr == -1)
|
||||
#define IN_ADDR struct in_addr
|
||||
#define NUMERIC_ADDR_ERROR (numeric_addr.s_addr == -1)
|
||||
#else
|
||||
# if (LONGBITS > 32)
|
||||
# define IN_ADDR unsigned int
|
||||
# else
|
||||
# define IN_ADDR unsigned long
|
||||
# endif
|
||||
# define NUMERIC_ADDR_ERROR (numeric_addr == (IN_ADDR) -1)
|
||||
#if (LONGBITS > 32)
|
||||
#define IN_ADDR unsigned int
|
||||
#else
|
||||
#define IN_ADDR unsigned long
|
||||
#endif
|
||||
#define NUMERIC_ADDR_ERROR (numeric_addr == (IN_ADDR) -1)
|
||||
#endif
|
||||
|
||||
#include <arpa/inet.h>
|
||||
@@ -69,365 +64,309 @@ glibtop_make_connection (hostarg, portarg, s)
|
||||
int *s;
|
||||
{
|
||||
#ifdef INTERNET_DOMAIN_SOCKETS
|
||||
char *ptr;
|
||||
if (hostarg == NULL)
|
||||
hostarg = getenv ("LIBGTOP_HOST");
|
||||
if (portarg == 0 && (ptr = getenv("LIBGTOP_PORT")) != NULL)
|
||||
portarg = atoi (ptr);
|
||||
char *ptr;
|
||||
|
||||
if (hostarg == NULL)
|
||||
hostarg = getenv ("LIBGTOP_HOST");
|
||||
if (portarg == 0 && (ptr = getenv ("LIBGTOP_PORT")) != NULL)
|
||||
portarg = atoi (ptr);
|
||||
#endif
|
||||
|
||||
if (hostarg != NULL) {
|
||||
/* hostname was given explicitly, via cmd line arg or LIBGTOP_HOST,
|
||||
* so obey it. */
|
||||
if (hostarg != NULL) {
|
||||
/* hostname was given explicitly, via cmd line arg or
|
||||
* LIBGTOP_HOST, * so obey it. */
|
||||
#ifdef UNIX_DOMAIN_SOCKETS
|
||||
if (!strcmp (hostarg, "unix")) {
|
||||
*s = connect_to_unix_server ();
|
||||
return (int) CONN_UNIX;
|
||||
}
|
||||
if (!strcmp (hostarg, "unix")) {
|
||||
*s = connect_to_unix_server ();
|
||||
return (int) CONN_UNIX;
|
||||
}
|
||||
#endif /* UNIX_DOMAIN_SOCKETS */
|
||||
#ifdef INTERNET_DOMAIN_SOCKETS
|
||||
*s = connect_to_internet_server (hostarg, portarg);
|
||||
return (int) CONN_INTERNET;
|
||||
*s = connect_to_internet_server (hostarg, portarg);
|
||||
return (int) CONN_INTERNET;
|
||||
#endif
|
||||
#ifdef SYSV_IPC
|
||||
return -1; /* hostarg should always be NULL for SYSV_IPC */
|
||||
#endif
|
||||
} else {
|
||||
/* no hostname given. Use unix-domain/sysv-ipc, or
|
||||
* internet-domain connection to local host if they're not available. */
|
||||
} else {
|
||||
/* no hostname given. Use unix-domain/sysv-ipc, or *
|
||||
* internet-domain connection to local host if they're not
|
||||
* available. */
|
||||
#if defined(UNIX_DOMAIN_SOCKETS)
|
||||
*s = connect_to_unix_server ();
|
||||
return (int) CONN_UNIX;
|
||||
#elif defined(SYSV_IPC)
|
||||
*s = connect_to_ipc_server ();
|
||||
return (int) CONN_IPC;
|
||||
*s = connect_to_unix_server ();
|
||||
return (int) CONN_UNIX;
|
||||
#elif defined(INTERNET_DOMAIN_SOCKETS)
|
||||
{
|
||||
char localhost [HOSTNAMSZ];
|
||||
gethostname (localhost, HOSTNAMSZ); /* use this host by default */
|
||||
*s = connect_to_internet_server (localhost, portarg);
|
||||
return (int) CONN_INTERNET;
|
||||
}
|
||||
{
|
||||
char localhost[HOSTNAMSZ];
|
||||
|
||||
gethostname (localhost, HOSTNAMSZ); /* use this
|
||||
* host by
|
||||
* default */
|
||||
*s = connect_to_internet_server (localhost, portarg);
|
||||
return (int) CONN_INTERNET;
|
||||
}
|
||||
#endif /* IPC type */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SYSV_IPC
|
||||
/*
|
||||
connect_to_ipc_server -- establish connection with server process via SYSV IPC
|
||||
Returns msqid for server if successful.
|
||||
*/
|
||||
static int
|
||||
connect_to_ipc_server (void)
|
||||
{
|
||||
int s; /* connected msqid */
|
||||
key_t key; /* message key */
|
||||
char buf [GSERV_BUFSZ+1]; /* buffer for filename */
|
||||
|
||||
sprintf (buf, "/tmp/lgtd%d", (int)geteuid());
|
||||
creat (buf, 0600);
|
||||
if ((key = ftok (buf, 1)) == -1)
|
||||
glibtop_error_io ("unable to get ipc key from %s", buf);
|
||||
|
||||
if ((s = msgget (key, 0600)) == -1)
|
||||
glibtop_error_io ("unable to access msg queue");
|
||||
|
||||
return(s);
|
||||
|
||||
} /* connect_to_ipc_server */
|
||||
|
||||
|
||||
/*
|
||||
disconnect_from_ipc_server -- inform the server that sending has finished,
|
||||
and wait for its reply.
|
||||
*/
|
||||
void disconnect_from_ipc_server(s,msgp,echo)
|
||||
int s;
|
||||
struct msgbuf *msgp;
|
||||
int echo;
|
||||
{
|
||||
int len; /* length of received message */
|
||||
|
||||
send_string(s,EOT_STR); /* EOT terminates this message */
|
||||
msgp->mtype = 1;
|
||||
|
||||
if(msgsnd(s,msgp,strlen(msgp->mtext)+1,0) < 0) {
|
||||
perror(progname);
|
||||
fprintf(stderr,"%s: unable to send message to server\n",progname);
|
||||
exit(1);
|
||||
}; /* if */
|
||||
|
||||
if((len = msgrcv(s,msgp,GSERV_BUFSZ,getpid(),0)) < 0) {
|
||||
perror(progname);
|
||||
fprintf(stderr,"%s: unable to receive message from server\n",progname);
|
||||
exit(1);
|
||||
}; /* if */
|
||||
|
||||
if (echo) {
|
||||
msgp->mtext[len] = '\0'; /* string terminate message */
|
||||
fputs(msgp->mtext, stdout);
|
||||
if (msgp->mtext[len-1] != '\n') putchar ('\n');
|
||||
}; /* if */
|
||||
|
||||
} /* disconnect_from_ipc_server */
|
||||
#endif /* SYSV_IPC */
|
||||
|
||||
|
||||
#if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS)
|
||||
/*
|
||||
send_string -- send string to socket.
|
||||
*/
|
||||
* send_string -- send string to socket.
|
||||
*/
|
||||
#if 0
|
||||
static void
|
||||
send_string(s,msg)
|
||||
send_string (s, msg)
|
||||
int s;
|
||||
const char *msg;
|
||||
{
|
||||
#if 0
|
||||
if (send(s,msg,strlen(msg),0) < 0) {
|
||||
perror(progname);
|
||||
fprintf(stderr,"%s: unable to send\n",progname);
|
||||
exit(1);
|
||||
}; /* if */
|
||||
#else
|
||||
int len, left=strlen(msg);
|
||||
while (left > 0) {
|
||||
if ((len=write(s,msg,min2(left,GSERV_BUFSZ))) < 0) {
|
||||
/* XEmacs addition: robertl@arnet.com */
|
||||
if (errno == EPIPE) {
|
||||
return ;
|
||||
}
|
||||
perror(progname);
|
||||
fprintf(stderr,"%s: unable to send\n",progname);
|
||||
exit(1);
|
||||
}; /* if */
|
||||
left -= len;
|
||||
msg += len;
|
||||
}; /* while */
|
||||
if (send (s, msg, strlen (msg), 0) < 0) {
|
||||
perror (progname);
|
||||
fprintf (stderr, "%s: unable to send\n", progname);
|
||||
exit (1);
|
||||
}; /* if */
|
||||
#else
|
||||
int len, left = strlen (msg);
|
||||
|
||||
while (left > 0) {
|
||||
if ((len = write (s, msg, min2 (left, GSERV_BUFSZ))) < 0) {
|
||||
/* XEmacs addition: robertl@arnet.com */
|
||||
if (errno == EPIPE) {
|
||||
return;
|
||||
}
|
||||
perror (progname);
|
||||
fprintf (stderr, "%s: unable to send\n", progname);
|
||||
exit (1);
|
||||
}; /* if */
|
||||
left -= len;
|
||||
msg += len;
|
||||
}; /* while */
|
||||
#endif
|
||||
} /* send_string */
|
||||
} /* send_string */
|
||||
|
||||
/*
|
||||
read_line -- read a \n terminated line from a socket
|
||||
*/
|
||||
* read_line -- read a \n terminated line from a socket
|
||||
*/
|
||||
static int
|
||||
read_line(int s, char *dest)
|
||||
read_line (int s, char *dest)
|
||||
{
|
||||
int length;
|
||||
int offset=0;
|
||||
char buffer[GSERV_BUFSZ+1];
|
||||
int length;
|
||||
int offset = 0;
|
||||
char buffer[GSERV_BUFSZ + 1];
|
||||
|
||||
while ((length=read(s,buffer+offset,1)>0) && buffer[offset]!='\n'
|
||||
&& buffer[offset] != EOT_CHR) {
|
||||
offset += length;
|
||||
if (offset >= GSERV_BUFSZ)
|
||||
break;
|
||||
}
|
||||
buffer[offset] = '\0';
|
||||
strcpy(dest,buffer);
|
||||
return 1;
|
||||
} /* read_line */
|
||||
while ((length = read (s, buffer + offset, 1) > 0) && buffer[offset] != '\n'
|
||||
&& buffer[offset] != EOT_CHR) {
|
||||
offset += length;
|
||||
if (offset >= GSERV_BUFSZ)
|
||||
break;
|
||||
}
|
||||
buffer[offset] = '\0';
|
||||
strcpy (dest, buffer);
|
||||
return 1;
|
||||
} /* read_line */
|
||||
#endif
|
||||
#endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */
|
||||
|
||||
|
||||
#ifdef UNIX_DOMAIN_SOCKETS
|
||||
/*
|
||||
connect_to_unix_server -- establish connection with server process via a unix-
|
||||
domain socket. Returns socket descriptor for server
|
||||
if successful.
|
||||
*/
|
||||
* connect_to_unix_server -- establish connection with server process via a unix-
|
||||
* domain socket. Returns socket descriptor for server
|
||||
* if successful.
|
||||
*/
|
||||
static int
|
||||
connect_to_unix_server (void)
|
||||
{
|
||||
int s; /* connected socket descriptor */
|
||||
struct sockaddr_un server; /* for unix connections */
|
||||
int s; /* connected socket descriptor */
|
||||
struct sockaddr_un server; /* for unix connections */
|
||||
|
||||
if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
glibtop_error_io ("unable to create socket");
|
||||
|
||||
server.sun_family = AF_UNIX;
|
||||
if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
glibtop_error_io ("unable to create socket");
|
||||
|
||||
server.sun_family = AF_UNIX;
|
||||
#ifdef HIDE_UNIX_SOCKET
|
||||
sprintf(server.sun_path, "/tmp/lgtddir%d/lgtd", (int)geteuid());
|
||||
#else /* HIDE_UNIX_SOCKET */
|
||||
sprintf(server.sun_path, "/tmp/lgtd%d", (int)geteuid());
|
||||
sprintf (server.sun_path, "/tmp/lgtddir%d/lgtd", (int) geteuid ());
|
||||
#else /* HIDE_UNIX_SOCKET */
|
||||
sprintf (server.sun_path, "/tmp/lgtd%d", (int) geteuid ());
|
||||
#endif /* HIDE_UNIX_SOCKET */
|
||||
if (connect (s, (struct sockaddr *)&server, strlen(server.sun_path)+2) < 0)
|
||||
glibtop_error_io ("unable to connect to local");
|
||||
if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2) < 0)
|
||||
glibtop_error_io ("unable to connect to local");
|
||||
|
||||
return(s);
|
||||
return (s);
|
||||
|
||||
} /* connect_to_unix_server */
|
||||
} /* connect_to_unix_server */
|
||||
#endif /* UNIX_DOMAIN_SOCKETS */
|
||||
|
||||
|
||||
#ifdef INTERNET_DOMAIN_SOCKETS
|
||||
/*
|
||||
internet_addr -- return the internet addr of the hostname or
|
||||
internet address passed. Return -1 on error.
|
||||
*/
|
||||
long glibtop_internet_addr (host)
|
||||
* internet_addr -- return the internet addr of the hostname or
|
||||
* internet address passed. Return -1 on error.
|
||||
*/
|
||||
long
|
||||
glibtop_internet_addr (host)
|
||||
const char *host;
|
||||
{
|
||||
struct hostent *hp; /* pointer to host info for remote host */
|
||||
IN_ADDR numeric_addr; /* host address */
|
||||
struct hostent *hp; /* pointer to host info for remote host */
|
||||
IN_ADDR numeric_addr; /* host address */
|
||||
|
||||
numeric_addr = inet_addr (host);
|
||||
if (!NUMERIC_ADDR_ERROR)
|
||||
return numeric_addr;
|
||||
else if ((hp = gethostbyname (host)) != NULL)
|
||||
return ((struct in_addr *)(hp->h_addr))->s_addr;
|
||||
else {
|
||||
glibtop_warn_io ("gethostbyname (%s)", host);
|
||||
return -1;
|
||||
}
|
||||
numeric_addr = inet_addr (host);
|
||||
if (!NUMERIC_ADDR_ERROR)
|
||||
return numeric_addr;
|
||||
else if ((hp = gethostbyname (host)) != NULL)
|
||||
return ((struct in_addr *) (hp->h_addr))->s_addr;
|
||||
else {
|
||||
glibtop_warn_io ("gethostbyname (%s)", host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} /* glibtop_internet_addr */
|
||||
} /* glibtop_internet_addr */
|
||||
|
||||
#ifdef AUTH_MAGIC_COOKIE
|
||||
# include <X11/X.h>
|
||||
# include <X11/Xauth.h>
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xauth.h>
|
||||
|
||||
static Xauth *server_xauth = NULL;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
connect_to_internet_server -- establish connection with server process via
|
||||
an internet domain socket. Returns socket
|
||||
descriptor for server if successful.
|
||||
*/
|
||||
* connect_to_internet_server -- establish connection with server process via
|
||||
* an internet domain socket. Returns socket
|
||||
* descriptor for server if successful.
|
||||
*/
|
||||
static int
|
||||
connect_to_internet_server (const char *serverhost, u_short port)
|
||||
{
|
||||
int s; /* connected socket descriptor */
|
||||
struct servent *sp; /* pointer to service information */
|
||||
struct sockaddr_in peeraddr_in; /* for peer socket address */
|
||||
char buf[512]; /* temporary buffer */
|
||||
int s; /* connected socket descriptor */
|
||||
struct servent *sp; /* pointer to service information */
|
||||
struct sockaddr_in peeraddr_in; /* for peer socket address */
|
||||
char buf[512]; /* temporary buffer */
|
||||
|
||||
/* clear out address structures */
|
||||
memset((char *)&peeraddr_in, 0, sizeof(struct sockaddr_in));
|
||||
|
||||
/* Set up the peer address to which we will connect. */
|
||||
peeraddr_in.sin_family = AF_INET;
|
||||
/* clear out address structures */
|
||||
memset ((char *) &peeraddr_in, 0, sizeof (struct sockaddr_in));
|
||||
|
||||
/* look up the server host's internet address */
|
||||
if (((long) peeraddr_in.sin_addr.s_addr = glibtop_internet_addr (serverhost)) == -1)
|
||||
glibtop_error ("unable to find %s in /etc/hosts or from YP", serverhost);
|
||||
|
||||
if (port == 0) {
|
||||
if ((sp = getservbyname ("gtopd","tcp")) == NULL)
|
||||
peeraddr_in.sin_port = htons (DEFAULT_PORT+getuid());
|
||||
else
|
||||
peeraddr_in.sin_port = sp->s_port;
|
||||
} /* if */
|
||||
else
|
||||
peeraddr_in.sin_port = htons (port);
|
||||
|
||||
/* Create the socket. */
|
||||
if ((s = socket (AF_INET, SOCK_STREAM, 0))== -1)
|
||||
glibtop_error_io ("unable to create socket");
|
||||
|
||||
/* Try to connect to the remote server at the address
|
||||
* which was just built into peeraddr.
|
||||
*/
|
||||
if (connect(s, (struct sockaddr *)&peeraddr_in,
|
||||
sizeof(struct sockaddr_in)) == -1)
|
||||
glibtop_error_io ("unable to connect to remote");
|
||||
/* Set up the peer address to which we will connect. */
|
||||
peeraddr_in.sin_family = AF_INET;
|
||||
|
||||
/* look up the server host's internet address */
|
||||
if (((long) peeraddr_in.sin_addr.s_addr = glibtop_internet_addr (serverhost)) == -1)
|
||||
glibtop_error ("unable to find %s in /etc/hosts or from YP", serverhost);
|
||||
|
||||
if (port == 0) {
|
||||
if ((sp = getservbyname ("gtopd", "tcp")) == NULL)
|
||||
peeraddr_in.sin_port = htons (DEFAULT_PORT + getuid ());
|
||||
else
|
||||
peeraddr_in.sin_port = sp->s_port;
|
||||
}
|
||||
/* if */
|
||||
else
|
||||
peeraddr_in.sin_port = htons (port);
|
||||
|
||||
/* Create the socket. */
|
||||
if ((s = socket (AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
glibtop_error_io ("unable to create socket");
|
||||
|
||||
/* Try to connect to the remote server at the address * which was
|
||||
* just built into peeraddr. */
|
||||
if (connect (s, (struct sockaddr *) &peeraddr_in,
|
||||
sizeof (struct sockaddr_in)) == -1)
|
||||
glibtop_error_io ("unable to connect to remote");
|
||||
|
||||
#ifdef AUTH_MAGIC_COOKIE
|
||||
|
||||
/* send credentials using MIT-MAGIC-COOKIE-1 protocol */
|
||||
|
||||
server_xauth =
|
||||
XauGetAuthByAddr(FamilyInternet,
|
||||
sizeof(peeraddr_in.sin_addr.s_addr),
|
||||
(char *) &peeraddr_in.sin_addr.s_addr,
|
||||
strlen(MCOOKIE_SCREEN), MCOOKIE_SCREEN,
|
||||
strlen(MCOOKIE_X_NAME), MCOOKIE_X_NAME);
|
||||
/* send credentials using MIT-MAGIC-COOKIE-1 protocol */
|
||||
|
||||
if (server_xauth && server_xauth->data) {
|
||||
sprintf(buf, "%s\n%d\n", MCOOKIE_NAME, server_xauth->data_length);
|
||||
write (s, buf, strlen(buf));
|
||||
write (s, server_xauth->data, server_xauth->data_length);
|
||||
|
||||
return (s);
|
||||
}
|
||||
server_xauth =
|
||||
XauGetAuthByAddr (FamilyInternet,
|
||||
sizeof (peeraddr_in.sin_addr.s_addr),
|
||||
(char *) &peeraddr_in.sin_addr.s_addr,
|
||||
strlen (MCOOKIE_SCREEN), MCOOKIE_SCREEN,
|
||||
strlen (MCOOKIE_X_NAME), MCOOKIE_X_NAME);
|
||||
|
||||
if (server_xauth && server_xauth->data) {
|
||||
sprintf (buf, "%s\n%d\n", MCOOKIE_NAME, server_xauth->data_length);
|
||||
write (s, buf, strlen (buf));
|
||||
write (s, server_xauth->data, server_xauth->data_length);
|
||||
|
||||
return (s);
|
||||
}
|
||||
#endif /* AUTH_MAGIC_COOKIE */
|
||||
|
||||
sprintf (buf, "%s\n", DEFAUTH_NAME);
|
||||
write (s, buf, strlen(buf));
|
||||
sprintf (buf, "%s\n", DEFAUTH_NAME);
|
||||
write (s, buf, strlen (buf));
|
||||
|
||||
return(s);
|
||||
return (s);
|
||||
|
||||
} /* connect_to_internet_server */
|
||||
} /* connect_to_internet_server */
|
||||
#endif /* INTERNET_DOMAIN_SOCKETS */
|
||||
|
||||
|
||||
#if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS)
|
||||
/*
|
||||
disconnect_from_server -- inform the server that sending has finished, and wait for
|
||||
its reply.
|
||||
*/
|
||||
* disconnect_from_server -- inform the server that sending has finished, and wait for
|
||||
* its reply.
|
||||
*/
|
||||
#if 0
|
||||
static void
|
||||
disconnect_from_server(s,echo)
|
||||
disconnect_from_server (s, echo)
|
||||
int s;
|
||||
int echo;
|
||||
{
|
||||
#if 0
|
||||
char buffer[REPLYSIZ+1];
|
||||
char buffer[REPLYSIZ + 1];
|
||||
|
||||
#else
|
||||
char buffer[GSERV_BUFSZ+1];
|
||||
char buffer[GSERV_BUFSZ + 1];
|
||||
|
||||
#endif
|
||||
int add_newline = 1;
|
||||
int length;
|
||||
int add_newline = 1;
|
||||
int length;
|
||||
|
||||
send_string(s,EOT_STR); /* make sure server gets string */
|
||||
send_string (s, EOT_STR); /* make sure server gets string */
|
||||
|
||||
#if !defined (linux) && !defined (_SCO_DS)
|
||||
/*
|
||||
* shutdown is completely hozed under linux. If s is a unix domain socket,
|
||||
* you'll get EOPNOTSUPP back from it. If s is an internet socket, you get
|
||||
* a broken pipe when you try to read a bit later. The latter
|
||||
* problem is fixed for linux versions >= 1.1.46, but the problem
|
||||
* with unix sockets persists. Sigh.
|
||||
*/
|
||||
#if !defined (linux) && !defined (_SCO_DS)
|
||||
/*
|
||||
* shutdown is completely hozed under linux. If s is a unix domain socket,
|
||||
* you'll get EOPNOTSUPP back from it. If s is an internet socket, you get
|
||||
* a broken pipe when you try to read a bit later. The latter
|
||||
* problem is fixed for linux versions >= 1.1.46, but the problem
|
||||
* with unix sockets persists. Sigh.
|
||||
*/
|
||||
|
||||
if (shutdown(s,1) == -1) {
|
||||
perror(progname);
|
||||
fprintf(stderr, "%s: unable to shutdown socket\n",progname);
|
||||
exit(1);
|
||||
}; /* if */
|
||||
if (shutdown (s, 1) == -1) {
|
||||
perror (progname);
|
||||
fprintf (stderr, "%s: unable to shutdown socket\n", progname);
|
||||
exit (1);
|
||||
}; /* if */
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
while((length = recv(s,buffer,REPLYSIZ,0)) > 0) {
|
||||
buffer[length] = '\0';
|
||||
if (echo) fputs(buffer,stdout);
|
||||
add_newline = (buffer[length-1] != '\n');
|
||||
}; /* while */
|
||||
while ((length = recv (s, buffer, REPLYSIZ, 0)) > 0) {
|
||||
buffer[length] = '\0';
|
||||
if (echo)
|
||||
fputs (buffer, stdout);
|
||||
add_newline = (buffer[length - 1] != '\n');
|
||||
}; /* while */
|
||||
#else
|
||||
while ((length = read(s,buffer,GSERV_BUFSZ)) > 0 ||
|
||||
(length == -1 && errno == EINTR)) {
|
||||
if (length) {
|
||||
buffer[length] = '\0';
|
||||
if (echo) {
|
||||
fputs(buffer,stdout);
|
||||
add_newline = (buffer[length-1] != '\n');
|
||||
}; /* if */
|
||||
}; /* if */
|
||||
}; /* while */
|
||||
while ((length = read (s, buffer, GSERV_BUFSZ)) > 0 ||
|
||||
(length == -1 && errno == EINTR)) {
|
||||
if (length) {
|
||||
buffer[length] = '\0';
|
||||
if (echo) {
|
||||
fputs (buffer, stdout);
|
||||
add_newline = (buffer[length - 1] != '\n');
|
||||
}; /* if */
|
||||
}; /* if */
|
||||
}; /* while */
|
||||
#endif
|
||||
|
||||
if (echo && add_newline) putchar('\n');
|
||||
|
||||
if(length < 0) {
|
||||
perror(progname);
|
||||
fprintf(stderr,"%s: unable to read the reply from the server\n",progname);
|
||||
exit(1);
|
||||
}; /* if */
|
||||
if (echo && add_newline)
|
||||
putchar ('\n');
|
||||
|
||||
} /* disconnect_from_server */
|
||||
if (length < 0) {
|
||||
perror (progname);
|
||||
fprintf (stderr, "%s: unable to read the reply from the server\n", progname);
|
||||
exit (1);
|
||||
}; /* if */
|
||||
|
||||
} /* disconnect_from_server */
|
||||
#endif
|
||||
#endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */
|
||||
|
@@ -34,10 +34,19 @@ void free ();
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include <glibtop.h>
|
||||
#include <glibtop/xmalloc.h>
|
||||
|
||||
#undef xmalloc
|
||||
#undef xrealloc
|
||||
#undef xstrdup
|
||||
|
||||
#define xmalloc(p1) glibtop_malloc_r (NULL, p1)
|
||||
#define xrealloc(p1,p2) glibtop_realloc_r (NULL, p1, p2)
|
||||
#define xstrdup(p1) glibtop_strdup_r (NULL, p1)
|
||||
#define xfree(p1) glibtop_free_r (NULL, p1)
|
||||
|
||||
char *strstr ();
|
||||
char *xmalloc ();
|
||||
char *xrealloc ();
|
||||
char *xstrdup ();
|
||||
void error ();
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
|
@@ -53,48 +53,48 @@ glibtop_get_sysdeps_r (glibtop *server, glibtop_sysdeps *buf)
|
||||
/* Call all system dependent functions to check which values
|
||||
* they return. */
|
||||
|
||||
glibtop_get_cpu_r (server, &data.cpu);
|
||||
glibtop_get_cpu_l (server, &data.cpu);
|
||||
buf->cpu = data.cpu.flags;
|
||||
|
||||
glibtop_get_mem_r (server, &data.mem);
|
||||
glibtop_get_mem_l (server, &data.mem);
|
||||
buf->mem = data.mem.flags;
|
||||
|
||||
glibtop_get_swap_r (server, &data.swap);
|
||||
glibtop_get_swap_l (server, &data.swap);
|
||||
buf->swap = data.swap.flags;
|
||||
|
||||
glibtop_get_uptime_r (server, &data.uptime);
|
||||
glibtop_get_uptime_l (server, &data.uptime);
|
||||
buf->uptime = data.uptime.flags;
|
||||
|
||||
glibtop_get_loadavg_r (server, &data.loadavg);
|
||||
glibtop_get_loadavg_l (server, &data.loadavg);
|
||||
buf->loadavg = data.loadavg.flags;
|
||||
|
||||
glibtop_get_shm_limits_r (server, &data.shm_limits);
|
||||
glibtop_get_shm_limits_l (server, &data.shm_limits);
|
||||
buf->shm_limits = data.shm_limits.flags;
|
||||
|
||||
glibtop_get_msg_limits_r (server, &data.msg_limits);
|
||||
glibtop_get_msg_limits_l (server, &data.msg_limits);
|
||||
buf->msg_limits = data.msg_limits.flags;
|
||||
|
||||
glibtop_get_sem_limits_r (server, &data.sem_limits);
|
||||
glibtop_get_sem_limits_l (server, &data.sem_limits);
|
||||
buf->sem_limits = data.sem_limits.flags;
|
||||
|
||||
glibtop_get_proclist_r (server, &data.proclist);
|
||||
glibtop_get_proclist_l (server, &data.proclist);
|
||||
buf->proclist = data.proclist.flags;
|
||||
|
||||
glibtop_get_proc_state_r (server, &data.proc_state, 0);
|
||||
glibtop_get_proc_state_l (server, &data.proc_state, 0);
|
||||
buf->proc_state = data.proc_state.flags;
|
||||
|
||||
glibtop_get_proc_uid_r (server, &data.proc_uid, 0);
|
||||
glibtop_get_proc_uid_l (server, &data.proc_uid, 0);
|
||||
buf->proc_uid = data.proc_uid.flags;
|
||||
|
||||
glibtop_get_proc_mem_r (server, &data.proc_mem, 0);
|
||||
glibtop_get_proc_mem_l (server, &data.proc_mem, 0);
|
||||
buf->proc_mem = data.proc_mem.flags;
|
||||
|
||||
glibtop_get_proc_time_r (server, &data.proc_time, 0);
|
||||
glibtop_get_proc_time_l (server, &data.proc_time, 0);
|
||||
buf->proc_time = data.proc_time.flags;
|
||||
|
||||
glibtop_get_proc_kernel_r (server, &data.proc_kernel, 0);
|
||||
glibtop_get_proc_kernel_l (server, &data.proc_kernel, 0);
|
||||
buf->proc_kernel = data.proc_kernel.flags;
|
||||
|
||||
glibtop_get_proc_segment_r (server, &data.proc_segment, 0);
|
||||
glibtop_get_proc_segment_l (server, &data.proc_segment, 0);
|
||||
buf->proc_segment = data.proc_segment.flags;
|
||||
}
|
||||
|
@@ -18,8 +18,8 @@ libgtop_guile_la_SOURCES = guile.c
|
||||
|
||||
BUILT_SOURCES = guile.c
|
||||
|
||||
guile.c: guile.awk $(top_builddir)/config.h $(top_builddir)/features.def
|
||||
$(AWK) -f $(srcdir)/guile.awk < $(top_builddir)/features.def > gnc-t
|
||||
guile.c: guile.awk $(top_builddir)/config.h $(top_srcdir)/features.def
|
||||
$(AWK) -f $(srcdir)/guile.awk < $(top_srcdir)/features.def > gnc-t
|
||||
mv gnc-t guile.c
|
||||
|
||||
EXTRA_DIST = guile.awk
|
||||
|
@@ -12,8 +12,8 @@ libgtop_guile_names_la_SOURCES = guile-names.c
|
||||
|
||||
BUILT_SOURCES = guile-names.c
|
||||
|
||||
guile-names.c: guile-names.awk $(top_builddir)/config.h $(top_builddir)/features.def
|
||||
$(AWK) -f $(srcdir)/guile-names.awk < $(top_builddir)/features.def > gnc-t
|
||||
guile-names.c: guile-names.awk $(top_builddir)/config.h $(top_srcdir)/features.def
|
||||
$(AWK) -f $(srcdir)/guile-names.awk < $(top_srcdir)/features.def > gnc-t
|
||||
mv gnc-t guile-names.c
|
||||
|
||||
EXTRA_DIST = guile-names.awk
|
||||
|
@@ -27,7 +27,7 @@ glibtop *glibtop_global_server = NULL;
|
||||
|
||||
glibtop *
|
||||
glibtop_init_r (glibtop **server, const unsigned long features,
|
||||
const unsigned flags)
|
||||
const unsigned flags)
|
||||
{
|
||||
if (*server != NULL)
|
||||
return *server;
|
||||
@@ -37,7 +37,7 @@ glibtop_init_r (glibtop **server, const unsigned long features,
|
||||
if (glibtop_global_server == NULL) {
|
||||
glibtop_global_server = &_glibtop_global_server;
|
||||
glibtop_open_r (glibtop_global_server, "glibtop",
|
||||
features, flags);
|
||||
features, flags);
|
||||
}
|
||||
|
||||
return *server = glibtop_global_server;
|
||||
|
@@ -48,7 +48,8 @@ glibtop_get_mem_s (glibtop *server, glibtop_mem *buf)
|
||||
if (!f) return;
|
||||
|
||||
fscanf (f, "%*[^\n]\nMem: %lu %lu %lu %lu %lu %lu\n",
|
||||
&buf->total, &buf->used, &buf->free, &buf->shared, &buf->buffer, &buf->cached);
|
||||
&buf->total, &buf->used, &buf->free, &buf->shared,
|
||||
&buf->buffer, &buf->cached);
|
||||
|
||||
buf->user = buf->total - buf->free - buf->shared - buf->buffer;
|
||||
|
||||
|
@@ -52,9 +52,8 @@ static void set_linux_version(void) {
|
||||
|
||||
void
|
||||
glibtop_open_r (glibtop *server, const char *program_name,
|
||||
const unsigned long features, const unsigned flags)
|
||||
const unsigned long features, const unsigned flags)
|
||||
{
|
||||
memset (server, 0, sizeof (glibtop));
|
||||
server->name = program_name;
|
||||
|
||||
set_linux_version ();
|
||||
|
@@ -73,8 +73,10 @@ glibtop_get_proc_state_s (glibtop *server, glibtop_proc_state *buf, pid_t pid)
|
||||
return;
|
||||
}
|
||||
|
||||
input [nread] = 0;
|
||||
fclose (f);
|
||||
|
||||
input [nread] = 0;
|
||||
|
||||
/* This is from guile-utils/gtop/proc/readproc.c */
|
||||
|
||||
/* split into "PID (cmd" and "<rest>" */
|
||||
|
@@ -24,6 +24,16 @@
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/sem.h>
|
||||
|
||||
#ifdef _SEM_SEMUN_UNDEFINED
|
||||
union semun
|
||||
{
|
||||
int val;
|
||||
struct semid_ds *buf;
|
||||
unsigned short int *array;
|
||||
struct seminfo *__buf;
|
||||
};
|
||||
#endif
|
||||
|
||||
static unsigned long _glibtop_sysdeps_sem_limits =
|
||||
(1 << GLIBTOP_IPC_SEMMAP) + (1 << GLIBTOP_IPC_SEMMNI) +
|
||||
(1 << GLIBTOP_IPC_SEMMNS) + (1 << GLIBTOP_IPC_SEMMNU) +
|
||||
|
@@ -24,5 +24,5 @@
|
||||
/* Closes pipe to gtop server. */
|
||||
|
||||
void
|
||||
glibtop_close (glibtop *server)
|
||||
glibtop_close_l (glibtop *server)
|
||||
{ }
|
||||
|
@@ -25,7 +25,7 @@
|
||||
/* Provides information about cpu usage. */
|
||||
|
||||
void
|
||||
glibtop_get_cpu_r (glibtop *server, glibtop_cpu *buf)
|
||||
glibtop_get_cpu_s (glibtop *server, glibtop_cpu *buf)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_cpu));
|
||||
}
|
||||
|
46
sysdeps/stub/glibtop_server.h
Normal file
46
sysdeps/stub/glibtop_server.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* $Id$ */
|
||||
|
||||
/* Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
|
||||
This file is part of the Gnome Top Library.
|
||||
Contributed by Martin Baulig <martin@home-of-linux.org>, April 1998.
|
||||
|
||||
The Gnome Top Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The Gnome Top Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef __GLIBTOP_SERVER_H__
|
||||
#define __GLIBTOP_SERVER_H__
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define GLIBTOP_SUID_CPU 0
|
||||
#define GLIBTOP_SUID_MEM 0
|
||||
#define GLIBTOP_SUID_SWAP 0
|
||||
#define GLIBTOP_SUID_UPTIME 0
|
||||
#define GLIBTOP_SUID_LOADAVG 0
|
||||
#define GLIBTOP_SUID_SHM_LIMITS 0
|
||||
#define GLIBTOP_SUID_MSG_LIMITS 0
|
||||
#define GLIBTOP_SUID_SEM_LIMITS 0
|
||||
#define GLIBTOP_SUID_PROCLIST 0
|
||||
#define GLIBTOP_SUID_PROC_STATE 0
|
||||
#define GLIBTOP_SUID_PROC_UID 0
|
||||
#define GLIBTOP_SUID_PROC_MEM 0
|
||||
#define GLIBTOP_SUID_PROC_TIME 0
|
||||
#define GLIBTOP_SUID_PROC_SIGNAL 0
|
||||
#define GLIBTOP_SUID_PROC_KERNEL 0
|
||||
#define GLIBTOP_SUID_PROC_SEGMENT 0
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
@@ -26,14 +26,16 @@ static glibtop _glibtop_global_server;
|
||||
glibtop *glibtop_global_server = NULL;
|
||||
|
||||
glibtop *
|
||||
glibtop_init_r (glibtop **server)
|
||||
glibtop_init_r (glibtop **server, const unsigned long features,
|
||||
const unsigned flags)
|
||||
{
|
||||
if (*server != NULL)
|
||||
return *server;
|
||||
|
||||
if (glibtop_global_server == NULL) {
|
||||
glibtop_global_server = &_glibtop_global_server;
|
||||
glibtop_open (glibtop_global_server, "glibtop");
|
||||
glibtop_open_r (glibtop_global_server, "glibtop",
|
||||
features, flags);
|
||||
}
|
||||
|
||||
return *server = glibtop_global_server;
|
||||
|
@@ -25,7 +25,7 @@
|
||||
/* Provides load averange. */
|
||||
|
||||
void
|
||||
glibtop_get_loadavg_r (glibtop *server, glibtop_loadavg *buf)
|
||||
glibtop_get_loadavg_s (glibtop *server, glibtop_loadavg *buf)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_loadavg));
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@
|
||||
/* Provides information about memory usage. */
|
||||
|
||||
void
|
||||
glibtop_get_mem_r (glibtop *server, glibtop_mem *buf)
|
||||
glibtop_get_mem_s (glibtop *server, glibtop_mem *buf)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_mem));
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@
|
||||
/* Provides information about sysv ipc limits. */
|
||||
|
||||
void
|
||||
glibtop_get_msg_limits_r (glibtop *server, glibtop_msg_limits *buf)
|
||||
glibtop_get_msg_limits_s (glibtop *server, glibtop_msg_limits *buf)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_msg_limits));
|
||||
}
|
||||
|
@@ -24,8 +24,8 @@
|
||||
/* Opens pipe to gtop server. Returns 0 on success and -1 on error. */
|
||||
|
||||
void
|
||||
glibtop_open (glibtop *server, const char *program_name)
|
||||
glibtop_open_r (glibtop *server, const char *program_name,
|
||||
const unsigned long features, const unsigned flags)
|
||||
{
|
||||
memset (server, 0, sizeof (glibtop));
|
||||
server->name = program_name;
|
||||
}
|
||||
|
@@ -25,8 +25,8 @@
|
||||
/* Provides detailed information about a process. */
|
||||
|
||||
void
|
||||
glibtop_get_proc_kernel_r (glibtop *server, glibtop_proc_kernel *buf,
|
||||
pid_t pid)
|
||||
glibtop_get_proc_kernel_s (glibtop *server, glibtop_proc_kernel *buf,
|
||||
pid_t pid)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_proc_kernel));
|
||||
}
|
||||
|
@@ -32,7 +32,7 @@
|
||||
* each buf->size big. The total size is stored in buf->total. */
|
||||
|
||||
unsigned *
|
||||
glibtop_get_proclist_r (glibtop *server, glibtop_proclist *buf)
|
||||
glibtop_get_proclist_s (glibtop *server, glibtop_proclist *buf)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_proclist));
|
||||
return NULL;
|
||||
|
@@ -25,8 +25,8 @@
|
||||
/* Provides detailed information about a process. */
|
||||
|
||||
void
|
||||
glibtop_get_proc_mem_r (glibtop *server, glibtop_proc_mem *buf,
|
||||
pid_t pid)
|
||||
glibtop_get_proc_mem_s (glibtop *server, glibtop_proc_mem *buf,
|
||||
pid_t pid)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_proc_mem));
|
||||
}
|
||||
|
@@ -25,8 +25,8 @@
|
||||
/* Provides detailed information about a process. */
|
||||
|
||||
void
|
||||
glibtop_get_proc_segment_r (glibtop *server, glibtop_proc_segment *buf,
|
||||
pid_t pid)
|
||||
glibtop_get_proc_segment_s (glibtop *server, glibtop_proc_segment *buf,
|
||||
pid_t pid)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_proc_segment));
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@
|
||||
/* Provides detailed information about a process. */
|
||||
|
||||
void
|
||||
glibtop_get_proc_signal_r (glibtop *server, glibtop_proc_signal *buf,
|
||||
glibtop_get_proc_signal_s (glibtop *server, glibtop_proc_signal *buf,
|
||||
pid_t pid)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_proc_signal));
|
||||
|
@@ -25,8 +25,8 @@
|
||||
/* Provides detailed information about a process. */
|
||||
|
||||
void
|
||||
glibtop_get_proc_state_r (glibtop *server, glibtop_proc_state *buf,
|
||||
pid_t pid)
|
||||
glibtop_get_proc_state_s (glibtop *server, glibtop_proc_state *buf,
|
||||
pid_t pid)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_proc_state));
|
||||
}
|
||||
|
@@ -25,8 +25,8 @@
|
||||
/* Provides detailed information about a process. */
|
||||
|
||||
void
|
||||
glibtop_get_proc_time_r (glibtop *server, glibtop_proc_time *buf,
|
||||
pid_t pid)
|
||||
glibtop_get_proc_time_s (glibtop *server, glibtop_proc_time *buf,
|
||||
pid_t pid)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_proc_time));
|
||||
}
|
||||
|
@@ -25,8 +25,8 @@
|
||||
/* Provides detailed information about a process. */
|
||||
|
||||
void
|
||||
glibtop_get_proc_uid_r (glibtop *server, glibtop_proc_uid *buf,
|
||||
pid_t pid)
|
||||
glibtop_get_proc_uid_s (glibtop *server, glibtop_proc_uid *buf,
|
||||
pid_t pid)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_proc_uid));
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@
|
||||
/* Provides information about sysv sem limits. */
|
||||
|
||||
void
|
||||
glibtop_get_sem_limits_r (glibtop *server, glibtop_sem_limits *buf)
|
||||
glibtop_get_sem_limits_s (glibtop *server, glibtop_sem_limits *buf)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_sem_limits));
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@
|
||||
/* Provides information about sysv ipc limits. */
|
||||
|
||||
void
|
||||
glibtop_get_shm_limits_r (glibtop *server, glibtop_shm_limits *buf)
|
||||
glibtop_get_shm_limits_s (glibtop *server, glibtop_shm_limits *buf)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_shm_limits));
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@
|
||||
/* Provides information about swap usage. */
|
||||
|
||||
void
|
||||
glibtop_get_swap_r (glibtop *server, glibtop_swap *buf)
|
||||
glibtop_get_swap_s (glibtop *server, glibtop_swap *buf)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_swap));
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@
|
||||
/* Provides uptime and idle time. */
|
||||
|
||||
void
|
||||
glibtop_get_uptime_r (glibtop *server, glibtop_uptime *buf)
|
||||
glibtop_get_uptime_s (glibtop *server, glibtop_uptime *buf)
|
||||
{
|
||||
memset (buf, 0, sizeof (glibtop_uptime));
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <config.h>
|
||||
#include <glibtop.h>
|
||||
#include <glibtop/cpu.h>
|
||||
|
||||
static const unsigned long _glibtop_sysdeps_cpu =
|
||||
|
@@ -44,6 +44,8 @@
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#include "loadavg.h"
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* Older versions of SunOS don't have a typedef for pid_t.
|
||||
@@ -63,10 +65,13 @@ typedef int pid_t;
|
||||
#define X_CP_TIME 6
|
||||
#define X_PAGES 7
|
||||
#define X_EPAGES 8
|
||||
#define X_SHMINFO 9
|
||||
#define X_MSGINFO 10
|
||||
#define X_SEMINFO 11
|
||||
|
||||
#ifdef MULTIPROCESSOR
|
||||
#define X_NCPU 9
|
||||
#define X_MP_TIME 10
|
||||
#define X_NCPU 12
|
||||
#define X_MP_TIME 13
|
||||
#endif
|
||||
|
||||
/* Log base 2 of 1024 is 10 (2^10 == 1024) */
|
||||
@@ -80,6 +85,10 @@ struct _glibtop_machine
|
||||
gid_t gid, egid; /* Real and effective group id */
|
||||
int nlist_count; /* Number of symbols in the nlist */
|
||||
int ncpu; /* Number of CPUs we have */
|
||||
int nproc; /* Number of entries in the process array */
|
||||
size_t ptable_size; /* Size of process array. */
|
||||
unsigned long ptable_offset; /* Offset of process array in kernel. */
|
||||
struct proc *proc_table; /* Process array. */
|
||||
unsigned long pages, epages;
|
||||
struct page *physpage;
|
||||
int bytesize, count;
|
||||
@@ -97,6 +106,10 @@ extern int _glibtop_check_nlist __P((void *, register struct nlist *));
|
||||
|
||||
extern int _glibtop_getkval __P((void *, unsigned long, int *, int, char *));
|
||||
|
||||
extern void _glibtop_read_proc_table __P((void *));
|
||||
|
||||
extern struct proc *_glibtop_find_pid __P((void *, pid_t));
|
||||
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
|
@@ -27,7 +27,7 @@ glibtop *glibtop_global_server = NULL;
|
||||
|
||||
glibtop *
|
||||
glibtop_init_r (glibtop **server, const unsigned long features,
|
||||
const unsigned flags)
|
||||
const unsigned flags)
|
||||
{
|
||||
if (*server != NULL)
|
||||
return *server;
|
||||
@@ -35,7 +35,7 @@ glibtop_init_r (glibtop **server, const unsigned long features,
|
||||
if (glibtop_global_server == NULL) {
|
||||
glibtop_global_server = &_glibtop_global_server;
|
||||
glibtop_open_r (glibtop_global_server, "glibtop",
|
||||
features, flags);
|
||||
features, flags);
|
||||
}
|
||||
|
||||
return *server = glibtop_global_server;
|
||||
|
@@ -19,15 +19,45 @@
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <config.h>
|
||||
#include <glibtop.h>
|
||||
#include <glibtop/loadavg.h>
|
||||
|
||||
static const unsigned long _glibtop_sysdeps_loadavg =
|
||||
(1 << GLIBTOP_LOADAVG_LOADAVG);
|
||||
|
||||
/* Provides load averange. */
|
||||
|
||||
void
|
||||
glibtop_get_loadavg_p (glibtop *server, glibtop_loadavg *buf)
|
||||
{
|
||||
load_avg avenrun [3];
|
||||
int i;
|
||||
|
||||
glibtop_init_r (&server, 0, 0);
|
||||
|
||||
memset (buf, 0, sizeof (glibtop_loadavg));
|
||||
|
||||
/* !!! THE FOLLOWING CODE RUNS SGID KMEM - CHANGE WITH CAUTION !!! */
|
||||
|
||||
setregid (server->machine.gid, server->machine.egid);
|
||||
|
||||
/* get the load average array */
|
||||
|
||||
(void) _glibtop_getkval (server, _glibtop_nlist [X_AVENRUN].n_value,
|
||||
(int *) avenrun, sizeof (avenrun),
|
||||
_glibtop_nlist [X_AVENRUN].n_name);
|
||||
|
||||
if (setregid (server->machine.egid, server->machine.gid))
|
||||
_exit (1);
|
||||
|
||||
/* !!! END OF SGID KMEM PART !!! */
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* Calculate loadavg values from avenrun. */
|
||||
buf->loadavg [i] = loaddouble (avenrun [i]);
|
||||
}
|
||||
|
||||
/* Now we can set the flags. */
|
||||
|
||||
buf->flags = _glibtop_sysdeps_loadavg;
|
||||
}
|
||||
|
57
sysdeps/sun4/loadavg.h
Normal file
57
sysdeps/sun4/loadavg.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Top - a top users display for Berkeley Unix
|
||||
*
|
||||
* Defines required to access load average figures.
|
||||
*
|
||||
* This include file sets up everything we need to access the load average
|
||||
* values in the kernel in a machine independent way. First, it sets the
|
||||
* typedef "load_avg" to be either double or long (depending on what is
|
||||
* needed), then it defines these macros appropriately:
|
||||
*
|
||||
* loaddouble(la) - convert load_avg to double.
|
||||
* intload(i) - convert integer to load_avg.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We assume that if FSCALE is defined, then avenrun and ccpu are type long.
|
||||
* If your machine is an exception (mips, perhaps?) then make adjustments
|
||||
* here.
|
||||
*
|
||||
* Defined types: load_avg for load averages, pctcpu for cpu percentages.
|
||||
*/
|
||||
#if defined(mips) && !defined(NetBSD)
|
||||
# include <sys/fixpoint.h>
|
||||
# if defined(FBITS) && !defined(FSCALE)
|
||||
# define FSCALE (1 << FBITS) /* mips */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef FSCALE
|
||||
# define FIXED_LOADAVG FSCALE
|
||||
# define FIXED_PCTCPU FSCALE
|
||||
#endif
|
||||
|
||||
#ifdef ibm032
|
||||
# undef FIXED_LOADAVG
|
||||
# undef FIXED_PCTCPU
|
||||
# define FIXED_PCTCPU PCT_SCALE
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef FIXED_PCTCPU
|
||||
typedef long pctcpu;
|
||||
# define pctdouble(p) ((double)(p) / FIXED_PCTCPU)
|
||||
#else
|
||||
typedef double pctcpu;
|
||||
# define pctdouble(p) (p)
|
||||
#endif
|
||||
|
||||
#ifdef FIXED_LOADAVG
|
||||
typedef long load_avg;
|
||||
# define loaddouble(la) ((double)(la) / FIXED_LOADAVG)
|
||||
# define intload(i) ((int)((i) * FIXED_LOADAVG))
|
||||
#else
|
||||
typedef double load_avg;
|
||||
# define loaddouble(la) (la)
|
||||
# define intload(i) ((double)(i))
|
||||
#endif
|
@@ -19,7 +19,7 @@
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <config.h>
|
||||
#include <glibtop.h>
|
||||
#include <glibtop/mem.h>
|
||||
|
||||
static const unsigned long _glibtop_sysdeps_mem =
|
||||
|
@@ -19,14 +19,53 @@
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <glibtop.h>
|
||||
#include <glibtop/msg_limits.h>
|
||||
|
||||
/* #define KERNEL to get declaration of `struct msginfo'. */
|
||||
|
||||
#define KERNEL
|
||||
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
static const unsigned long _glibtop_sysdeps_msg_limits =
|
||||
(1 << GLIBTOP_IPC_MSGMAP) + (1 << GLIBTOP_IPC_MSGMAX) +
|
||||
(1 << GLIBTOP_IPC_MSGMNB) + (1 << GLIBTOP_IPC_MSGMNI) +
|
||||
(1 << GLIBTOP_IPC_MSGSSZ) + (1 << GLIBTOP_IPC_MSGTQL);
|
||||
|
||||
/* Provides information about sysv ipc limits. */
|
||||
|
||||
void
|
||||
glibtop_get_msg_limits_p (glibtop *server, glibtop_msg_limits *buf)
|
||||
{
|
||||
struct msginfo msginfo;
|
||||
|
||||
glibtop_init_r (&server, 0, 0);
|
||||
|
||||
memset (buf, 0, sizeof (glibtop_msg_limits));
|
||||
|
||||
/* !!! THE FOLLOWING CODE RUNS SGID KMEM - CHANGE WITH CAUTION !!! */
|
||||
|
||||
setregid (server->machine.gid, server->machine.egid);
|
||||
|
||||
/* get the load average array */
|
||||
|
||||
(void) _glibtop_getkval (server, _glibtop_nlist [X_MSGINFO].n_value,
|
||||
(int *) &msginfo, sizeof (msginfo),
|
||||
_glibtop_nlist [X_MSGINFO].n_name);
|
||||
|
||||
if (setregid (server->machine.egid, server->machine.gid))
|
||||
_exit (1);
|
||||
|
||||
/* !!! END OF SGID KMEM PART !!! */
|
||||
|
||||
buf->msgmap = msginfo.msgmap;
|
||||
buf->msgmax = msginfo.msgmax;
|
||||
buf->msgmnb = msginfo.msgmnb;
|
||||
buf->msgmni = msginfo.msgmni;
|
||||
buf->msgssz = msginfo.msgssz;
|
||||
buf->msgtql = msginfo.msgtql;
|
||||
|
||||
buf->flags = _glibtop_sysdeps_msg_limits;
|
||||
}
|
||||
|
@@ -34,6 +34,9 @@ struct nlist _glibtop_nlist[] = {
|
||||
{ "cp_time" }, /* 6 */
|
||||
{ "pages" }, /* 7 */
|
||||
{ "epages" }, /* 8 */
|
||||
{ "shminfo" }, /* 9 */
|
||||
{ "msginfo" }, /* 10 */
|
||||
{ "seminfo" }, /* 11 */
|
||||
#else
|
||||
{ "_avenrun" }, /* 0 */
|
||||
{ "_ccpu" }, /* 1 */
|
||||
@@ -44,6 +47,9 @@ struct nlist _glibtop_nlist[] = {
|
||||
{ "_cp_time" }, /* 6 */
|
||||
{ "_pages" }, /* 7 */
|
||||
{ "_epages" }, /* 8 */
|
||||
{ "_shminfo" }, /* 9 */
|
||||
{ "_msginfo" }, /* 10 */
|
||||
{ "_seminfo" }, /* 11 */
|
||||
#ifdef MULTIPROCESSOR
|
||||
{ "_ncpu" },
|
||||
{ "_mp_time" },
|
||||
@@ -64,7 +70,6 @@ glibtop_open_r (glibtop *server, const char *program_name,
|
||||
|
||||
/* !!! WE ARE ROOT HERE - CHANGE WITH CAUTION !!! */
|
||||
|
||||
memset (server, 0, sizeof (glibtop));
|
||||
server->name = program_name;
|
||||
|
||||
server->machine.uid = getuid ();
|
||||
@@ -113,6 +118,24 @@ glibtop_open_r (glibtop *server, const char *program_name,
|
||||
(_glibtop_check_nlist (server, _glibtop_nlist) > 0))
|
||||
_exit (1);
|
||||
|
||||
/* Get process array stuff. */
|
||||
|
||||
(void) _glibtop_getkval (server, _glibtop_nlist[X_NPROC].n_value,
|
||||
(int *)(&server->machine.nproc),
|
||||
sizeof (server->machine.nproc),
|
||||
_glibtop_nlist[X_NPROC].n_name);
|
||||
|
||||
(void) _glibtop_getkval (server, _glibtop_nlist[X_PROC].n_value,
|
||||
(int *)(&server->machine.ptable_offset),
|
||||
sizeof (server->machine.ptable_offset),
|
||||
_glibtop_nlist[X_PROC].n_name);
|
||||
|
||||
server->machine.ptable_size = (unsigned long) server->machine.nproc *
|
||||
(unsigned long) sizeof (struct proc);
|
||||
|
||||
server->machine.proc_table = glibtop_malloc_r
|
||||
(server, server->machine.ptable_size);
|
||||
|
||||
/* This are for the memory statistics. */
|
||||
|
||||
(void) _glibtop_getkval (server, _glibtop_nlist[X_PAGES].n_value,
|
||||
@@ -216,3 +239,46 @@ _glibtop_getkval (void *void_server, unsigned long offset, int *ptr, int size, c
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Used internally. Reads process table from kernel. */
|
||||
|
||||
void
|
||||
_glibtop_read_proc_table (void *void_server)
|
||||
{
|
||||
glibtop *server = (glibtop *) void_server;
|
||||
|
||||
/* !!! THE FOLLOWING CODE RUNS SGID KMEM - CHANGE WITH CAUTION !!! */
|
||||
|
||||
setregid (server->machine.gid, server->machine.egid);
|
||||
|
||||
/* Read process table from kernel. */
|
||||
|
||||
(void) _glibtop_getkval (server, server->machine.ptable_offset,
|
||||
(int *) server->machine.proc_table,
|
||||
(size_t) server->machine.ptable_size,
|
||||
_glibtop_nlist[X_PROC].n_name);
|
||||
|
||||
if (setregid (server->machine.egid, server->machine.gid))
|
||||
_exit (1);
|
||||
|
||||
/* !!! END OF SGID KMEM PART !!! */
|
||||
}
|
||||
|
||||
/* Used internally. Finds pid in process table. */
|
||||
|
||||
struct proc *
|
||||
_glibtop_find_pid (void *void_server, pid_t pid)
|
||||
{
|
||||
register struct proc *pp;
|
||||
register int i;
|
||||
|
||||
glibtop *server = (glibtop *) void_server;
|
||||
|
||||
for (pp = server->machine.proc_table, i = 0;
|
||||
i < server->machine.nproc; pp++, i++) {
|
||||
if ((pp->p_stat != 0) && (pp->p_pid == pid))
|
||||
return pp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -19,16 +19,38 @@
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <config.h>
|
||||
#include <glibtop.h>
|
||||
#include <glibtop/prockernel.h>
|
||||
|
||||
static const unsigned long _glibtop_sysdeps_proc_kernel =
|
||||
(1 << GLIBTOP_PROC_KERNEL_K_FLAGS) + (1 << GLIBTOP_PROC_KERNEL_WCHAN);
|
||||
|
||||
/* Provides detailed information about a process. */
|
||||
|
||||
void
|
||||
glibtop_get_proc_kernel_p (glibtop *server, glibtop_proc_kernel *buf,
|
||||
pid_t pid)
|
||||
pid_t pid)
|
||||
{
|
||||
struct proc *pp;
|
||||
|
||||
glibtop_init_r (&server, 0, 0);
|
||||
|
||||
memset (buf, 0, sizeof (glibtop_proc_kernel));
|
||||
|
||||
/* Read process table from kernel. */
|
||||
|
||||
_glibtop_read_proc_table (server);
|
||||
|
||||
/* Find the pid in the process table. */
|
||||
|
||||
pp = _glibtop_find_pid (server, pid);
|
||||
|
||||
if (pp == NULL) return;
|
||||
|
||||
/* Fill in data fields. */
|
||||
|
||||
buf->k_flags = pp->p_flag;
|
||||
buf->wchan = pp->p_wchan;
|
||||
|
||||
buf->flags = _glibtop_sysdeps_proc_kernel;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user