From 317bcb1d9feec3c642aa3565fa5bb97fc208631b Mon Sep 17 00:00:00 2001 From: Dmitrijs Ledkovs Date: Wed, 28 Aug 2013 18:09:14 +0100 Subject: New upstream release. --- ChangeLog | 53 +++ Makefile.in | 2 +- NEWS | 16 + TODO | 4 +- aclocal.m4 | 6 +- config/depcomp | 3 +- config/ltmain.sh | 4 +- configure | 20 +- configure.ac | 2 +- debian/changelog | 14 + debian/control | 2 +- man/procenv.1 | 27 +- src/Makefile.am | 7 + src/Makefile.in | 9 +- src/procenv.c | 1121 +++++++++++++++++++++++++++++++++++++++++++++++++----- src/procenv.h | 123 +++++- 16 files changed, 1277 insertions(+), 136 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1c5ba68..35ff4d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,56 @@ +2013-08-23 James Hunt + + * TODO: + * man/procenv.1: + - Added -A/--arguments option. + - Updated --mount to include reference to statfs. + - Added -N/--network option. + - Updated SEE ALSO section. + * src/procenv.c: + - Added support for BSD/Hurd signals: SIGEMT, SIGINFO, SIGLOST. + - usage(): Use colon to separate output types from description for + consistency. + - is_console(): Enable for FreeBSD/kFreeBSD. + - append(): Allocate space if str points to NULL. + - appendf(): Allocate space if str points to NULL. + - appendva(): Allocate space if str points to NULL. + - dump(): + - Call show_network(). + - Call show_locale() *after* show_rlimits() for correct ordering. + - show_linux_mounts(): Add block and inode details (LP: #1212728). + - show_bsd_mounts(): Add block and inode details (LP: #1212728). + - show_compiler(): + - Added __FILE__, __BASE_FILE__ and __TIMESTAMP__. + - main(): + - Updates for -N/--network. + - New functions: + - show_arguments(). + - get_network_address(). + - decode_if_flags(). + - get_ipv6_scope_name() (unused). + - get_mtu(). + - get_mac_address(). + - decode_extended_if_flags(). + - get_net_family_name(). + - show_network_if(). + - show_network(). + +2013-07-19 James Hunt + + * src/man/procenv.1: Updated date and year. + * src/procenv.c: + - show_bsd_proc_branch(): Fix to work in BSD jails: these entities are + bizarre in that they have no init process, and a processes parent + may actually be a process running *outside* of the jail... and as a + result, all you can know about it is its PID. + - Various hacks to work in the decidedly un-bionic Android + environment. + * Android.mk: Makefile for Android. + +2013-07-04 James Hunt + + * man/procenv.1: Add a new --exec example. + 2013-06-28 James Hunt * configure.ac: Force old serial test behaviour (specifically diff --git a/Makefile.in b/Makefile.in index 3beaee7..fcd1a66 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.2 from Makefile.am. +# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. diff --git a/NEWS b/NEWS index 379f4eb..5644fe9 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,19 @@ +0.26 2013-08-27 + + * Check to determine if running on a console now works for + FreeBSD/kFreeBSD too. + * Added ability to show all arguments (-A/--arguments) + (useful when using --exec). + * Added ability to display network details (-N/--network). + * Added BSD/Hurd-specific signals. + * Corrected output sort order. + * Mount details now include block, inode and fsck details. + +0.25 2013-07-19 + + * Fixed bug where procenv would hang in a FreeBSD jail. + * Port to Android. + 0.24 2013-06-28 * Packaging update for automake-1.13 to ensure procenv output diff --git a/TODO b/TODO index cf7326e..ad8b543 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,8 @@ # TODO - networking details -- add statfs(2) + - IPv6 scope_id. + - gateway. - add to show_sizeof(): - intN_t group - i18n (gettext) @@ -18,6 +19,7 @@ - add process arguments to show_proc_branch()? - sort output of show_mounts(). - use CPUID instruction to detect XEN environments? + (http://libcpuid.sourceforge.net/) - use dlopen to probe for apparmor/selinux. This avoids having to depend on the existence of the appropriate libs, but still allows security context information to be queried on systems that provide them. diff --git a/aclocal.m4 b/aclocal.m4 index 05c1a54..a5d5503 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,4 +1,4 @@ -# generated automatically by aclocal 1.13.2 -*- Autoconf -*- +# generated automatically by aclocal 1.13.3 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. @@ -195,7 +195,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.13' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.13.2], [], +m4_if([$1], [1.13.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -211,7 +211,7 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.13.2])dnl +[AM_AUTOMAKE_VERSION([1.13.3])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) diff --git a/config/depcomp b/config/depcomp index 06b0882..4ebd5b3 100755 --- a/config/depcomp +++ b/config/depcomp @@ -1,7 +1,7 @@ #! /bin/sh # depcomp - compile a program generating dependencies as side-effects -scriptversion=2012-10-18.11; # UTC +scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. @@ -552,6 +552,7 @@ $ { G p }' >> "$depfile" + echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; diff --git a/config/ltmain.sh b/config/ltmain.sh index b9205ee..3825a2a 100644 --- a/config/ltmain.sh +++ b/config/ltmain.sh @@ -70,7 +70,7 @@ # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) -# $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.2ubuntu1 +# $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.3ubuntu1 # automake: $automake_version # autoconf: $autoconf_version # @@ -80,7 +80,7 @@ PROGRAM=libtool PACKAGE=libtool -VERSION="2.4.2 Debian-2.4.2-1.2ubuntu1" +VERSION="2.4.2 Debian-2.4.2-1.3ubuntu1" TIMESTAMP="" package_revision=1.3337 diff --git a/configure b/configure index be2ba31..b5bfdc1 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for procenv 0.24. +# Generated by GNU Autoconf 2.69 for procenv 0.26. # # Report bugs to . # @@ -583,8 +583,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='procenv' PACKAGE_TARNAME='procenv' -PACKAGE_VERSION='0.24' -PACKAGE_STRING='procenv 0.24' +PACKAGE_VERSION='0.26' +PACKAGE_STRING='procenv 0.26' PACKAGE_BUGREPORT='james.hunt@ubuntu.com' PACKAGE_URL='' @@ -1279,7 +1279,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures procenv 0.24 to adapt to many kinds of systems. +\`configure' configures procenv 0.26 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1345,7 +1345,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of procenv 0.24:";; + short | recursive ) echo "Configuration of procenv 0.26:";; esac cat <<\_ACEOF @@ -1441,7 +1441,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -procenv configure 0.24 +procenv configure 0.26 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1867,7 +1867,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by procenv $as_me 0.24, which was +It was created by procenv $as_me 0.26, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -5302,7 +5302,7 @@ fi # Define the identity of the package. PACKAGE='procenv' - VERSION='0.24' + VERSION='0.26' cat >>confdefs.h <<_ACEOF @@ -6022,7 +6022,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by procenv $as_me 0.24, which was +This file was extended by procenv $as_me 0.26, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -6088,7 +6088,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -procenv config.status 0.24 +procenv config.status 0.26 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index d1ac19b..1ef3c56 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.68]) -AC_INIT(procenv, 0.24, [james.hunt@ubuntu.com]) +AC_INIT(procenv, 0.26, [james.hunt@ubuntu.com]) AC_COPYRIGHT([Copyright (C) 2012-2013 James Hunt and Kees Cook ]) AC_CONFIG_SRCDIR([src/procenv.c]) diff --git a/debian/changelog b/debian/changelog index bc10bf4..4273dfb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,17 @@ +procenv (0.26-1) unstable; urgency=low + + * New upstream release. + + -- James Hunt Tue, 27 Aug 2013 23:09:03 +0100 + +procenv (0.25-1) unstable; urgency=low + + * debian/control: Add build-depends on automake >= 1.12 for + 'serial-tests' used in configure.ac + * New upstream release. + + -- James Hunt Fri, 19 Jul 2013 21:40:43 +0100 + procenv (0.24-1) unstable; urgency=low * New upstream release. diff --git a/debian/control b/debian/control index 280dd1c..5ff2264 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: procenv Section: utils Priority: optional Maintainer: James Hunt -Build-Depends: debhelper (>= 9.0.0), dh-autoreconf, libkvm-dev [kfreebsd-any], pkg-config +Build-Depends: debhelper (>= 9.0.0), dh-autoreconf, libkvm-dev [kfreebsd-any], pkg-config, automake (>= 1.12) Standards-Version: 3.9.4 Homepage: https://code.launchpad.net/procenv XS-Testsuite: autopkgtest diff --git a/man/procenv.1 b/man/procenv.1 index 99441ea..1027d76 100644 --- a/man/procenv.1 +++ b/man/procenv.1 @@ -1,4 +1,4 @@ -.TH PROCENV "1" "2012-11-29" "User Commands" +.TH PROCENV "1" "2013-07-16" "User Commands" .\" .SH NAME procenv \- display process environment details @@ -21,11 +21,16 @@ procenv \- display process environment details Display details of the process environment in a parseable format. .\" .SH OPTIONS +.\" .TP \fB\-a\fR, \fB\-\-meta\fR Display meta details. .\" .TP +\fB\-A\fR, \fB\-\-arguments\fR +Display program arguments. +.\" +.TP \fB\-b\fR, \fB\-\-libs\fR Display library details. See @@ -118,7 +123,7 @@ See \fB\-m\fR, \fB\-\-mount[s]\fR Display mount details. See -.BR getmntent (3) "" " (Linux) and " getmntinfo (3) "" " (BSD)." +.BR getmntent (3) "" " and " statfs (2) "" " (Linux), and " getmntinfo (3) "" " (BSD)." .PP .\" .TP @@ -129,6 +134,13 @@ See .PP .\" .TP +\fB\-N\fR, \fB\-\-network\fR +Display network details. +See +.BR getifaddrs (3) "" ", " getnameinfo (3) "" ", and " ioctl (2) " (Linux)" . +.PP +.\" +.TP \fB\-o\fR, \fB\-\-oom\fR Display out-of-memory manager details (Linux only). See @@ -308,9 +320,14 @@ specified. \& # Show limits \& procenv \-l \& -\& # Send compiler information to syslog (note the order of the options) +\& # Send compiler information to syslog (note the order of the options). \& procenv \-\-output=syslog \-\-compiler \& +\& # Run a command ('mycmd --arg1 --foo=bar') without creating a new +\& # process, but have procenv run first and log its output to a +\& # regular file. +\& exec procenv \-\-file=/tmp/procenv.log --exec -- mycmd --arg1 --foo=bar +\& \& # The following kernel command-line snippet will cause procenv to \& # write output to first serial tty device and then execute init(8) \& # in debug mode to allow early boot environment to be examined. @@ -332,7 +349,7 @@ Kees Cook .RB < kees@ubuntu.com > "" "." .\" .SH COPYRIGHT -Copyright \(co 2012 James Hunt +Copyright \(co 2012-2013 James Hunt .RB < james.hunt@ubuntu.com > and Kees Cook @@ -358,6 +375,8 @@ There is NO WARRANTY, to the extent permitted by law. .BR exec (P) "" , .BR getconf (1) "" , .BR groups (1) "" , +.BR ifconfig (8) "" , +.BR ip (9) "" , .BR kill (1) "" , .BR ldd (1) "" , .BR locale (1) "" , diff --git a/src/Makefile.am b/src/Makefile.am index ee388b0..c63a9ae 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,10 @@ +AM_CFLAGS = \ + -pedantic \ + -std=gnu99 + -Wall -O2 \ + -fstack-protector \ + -Wformat -Werror=format-security + bin_PROGRAMS = procenv procenv_SOURCES = procenv.c procenv.h procenv_LDADD = -lrt diff --git a/src/Makefile.in b/src/Makefile.in index 2fa86a1..8a87c00 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.13.2 from Makefile.am. +# Makefile.in generated by automake 1.13.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -267,6 +267,10 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ +AM_CFLAGS = \ + -pedantic \ + -std=gnu99 + procenv_SOURCES = procenv.c procenv.h procenv_LDADD = -lrt procenv_CPPFLAGS = $(am__append_1) $(am__append_2) @@ -686,6 +690,9 @@ uninstall-am: uninstall-binPROGRAMS ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS + -Wall -O2 \ + -fstack-protector \ + -Wformat -Werror=format-security # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/src/procenv.c b/src/procenv.c index 325c38d..a1c17cc 100644 --- a/src/procenv.c +++ b/src/procenv.c @@ -9,7 +9,7 @@ * Licence: GPLv3. See below... *-------------------------------------------------------------------- * - * Copyright © 2012 James Hunt. + * Copyright 2012-2013 James Hunt. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -70,7 +70,7 @@ int selected_option = 0; /** * indent: * - * Number of spaces to indent output + * Number of spaces to indent output. **/ int indent = 0; @@ -88,6 +88,12 @@ const char *program_name; **/ char **exec_args = NULL; +/** + * Copy of argv and argc used by show_arguments(). + **/ +char **argvp = NULL; +int argvc = 0; + struct procenv_user user; struct procenv_misc misc; struct procenv_priority priority; @@ -125,7 +131,7 @@ struct mntopt_map { { MNT_SYNCHRONOUS , "synchronous" }, { MNT_UNION , "union" }, - { 0, NULL }, + { 0, NULL } }; #endif @@ -134,7 +140,9 @@ struct procenv_map output_map[] = { { OUTPUT_STDERR , "stderr" }, { OUTPUT_STDOUT , "stdout" }, { OUTPUT_SYSLOG , "syslog" }, - { OUTPUT_TERM , "terminal" } + { OUTPUT_TERM , "terminal" }, + + { 0, NULL } }; struct baud_speed baud_speeds[] = { @@ -162,6 +170,67 @@ struct baud_speed baud_speeds[] = { { 0, NULL } }; +struct if_flag_map { + unsigned int flag; + char *name; +} if_flag_map[] = { + mk_map_entry (IFF_UP), + mk_map_entry (IFF_BROADCAST), + mk_map_entry (IFF_DEBUG), + mk_map_entry (IFF_LOOPBACK), + mk_map_entry (IFF_POINTOPOINT), + mk_map_entry (IFF_RUNNING), + mk_map_entry (IFF_NOARP), + mk_map_entry (IFF_PROMISC), + +#if defined (PROCENV_LINUX) + mk_map_entry (IFF_NOTRAILERS), +#endif + + mk_map_entry (IFF_ALLMULTI), + +#if defined (PROCENV_LINUX) + mk_map_entry (IFF_MASTER), + mk_map_entry (IFF_SLAVE), +#endif + +#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__) + mk_map_entry (IFF_SIMPLEX), +#endif + + mk_map_entry (IFF_MULTICAST), + +#if defined (PROCENV_LINUX) + mk_map_entry (IFF_PORTSEL), + mk_map_entry (IFF_AUTOMEDIA), + mk_map_entry (IFF_DYNAMIC), + mk_map_entry (IFF_LOWER_UP), + mk_map_entry (IFF_DORMANT), + mk_map_entry (IFF_ECHO), +#endif + + { 0, NULL } +}; + +#if defined (PROCENV_LINUX) +struct if_extended_flag_map { + unsigned int flag; + char *name; +} if_extended_flag_map[] = { + mk_map_entry (IFF_802_1Q_VLAN), + mk_map_entry (IFF_EBRIDGE), + mk_map_entry (IFF_SLAVE_INACTIVE), + mk_map_entry (IFF_MASTER_8023AD), + mk_map_entry (IFF_MASTER_ALB), + mk_map_entry (IFF_BONDING), + mk_map_entry (IFF_SLAVE_NEEDARP), + mk_map_entry (IFF_ISATAP), + + { 0, NULL } +}; +#endif + + /* Really, every single sysconf variable should be ifdef'ed since it * may not exist on a particular system, but that makes the code look * untidy. @@ -180,18 +249,22 @@ struct procenv_map sysconf_map[] = { mk_sysconf_map_entry (_SC_CLK_TCK), mk_posix_sysconf_map_entry (COLL_WEIGHTS_MAX), mk_posix_sysconf_map_entry (EXPR_NEST_MAX), +#if defined (_SC_HOST_NAME_MAX) mk_posix_sysconf_map_entry (HOST_NAME_MAX), +#endif mk_posix_sysconf_map_entry (LINE_MAX), mk_posix_sysconf_map_entry (LOGIN_NAME_MAX), mk_posix_sysconf_map_entry (OPEN_MAX), mk_posix_sysconf_map_entry (PAGESIZE), mk_posix_sysconf_map_entry (RE_DUP_MAX), mk_posix_sysconf_map_entry (STREAM_MAX), +#if defined (_SC_SYMLOOP_MAX) mk_posix_sysconf_map_entry (SYMLOOP_MAX), +#endif mk_posix_sysconf_map_entry (TTY_NAME_MAX), mk_posix_sysconf_map_entry (TZNAME_MAX), { _SC_VERSION, "_POSIX_VERSION(_SC_VERSION)" }, -#ifdef _SC_POSIX2_C_DEV +#if defined (_SC_POSIX2_C_DEV) mk_posix_sysconf_map_entry (POSIX2_C_DEV), #endif mk_posix_sysconf_map_entry (BC_BASE_MAX), @@ -215,15 +288,25 @@ struct procenv_map sysconf_map[] = { mk_sysconf_map_entry (_SC_NPROCESSORS_CONF), mk_sysconf_map_entry (_SC_NPROCESSORS_ONLN), +#if defined (_SC_ADVISORY_INFO) mk_posixopt_sysconf_map_entry (ADVISORY_INFO), +#endif mk_posixopt_sysconf_map_entry (ASYNCHRONOUS_IO), +#if defined (_SC_BARRIERS) mk_posixopt_sysconf_map_entry (BARRIERS), +#endif #if defined (_POSIX_CHOWN_RESTRICTED) mk_sysconf_map_entry (_POSIX_CHOWN_RESTRICTED), #endif +#if defined (_SC_CLOCK_SELECTION) mk_posixopt_sysconf_map_entry (CLOCK_SELECTION), +#endif +#if defined (_SC_CPUTIME) mk_posixopt_sysconf_map_entry (CPUTIME), +#endif +#if defined (_SC_FILE_LOCKING) mk_posixopt_sysconf_map_entry (FILE_LOCKING), +#endif mk_posixopt_sysconf_map_entry (FSYNC), mk_posixopt_sysconf_map_entry (JOB_CONTROL), mk_posixopt_sysconf_map_entry (MAPPED_FILES), @@ -231,43 +314,77 @@ struct procenv_map sysconf_map[] = { mk_posixopt_sysconf_map_entry (MEMLOCK_RANGE), mk_posixopt_sysconf_map_entry (MEMORY_PROTECTION), mk_posixopt_sysconf_map_entry (MESSAGE_PASSING), +#if defined (_SC_MONOTONIC_CLOCK) mk_posixopt_sysconf_map_entry (MONOTONIC_CLOCK), +#endif #ifdef _SC_MULTI_PROCESS mk_posixopt_sysconf_map_entry (MULTI_PROCESS), #endif mk_posixopt_sysconf_map_entry (PRIORITIZED_IO), mk_posixopt_sysconf_map_entry (PRIORITY_SCHEDULING), +#if defined (_POSIX_RAW_SOCKETS) mk_sysconf_map_entry (_POSIX_RAW_SOCKETS), +#endif +#if defined (_SC_READER_WRITER_LOCKS) mk_posixopt_sysconf_map_entry (READER_WRITER_LOCKS), +#endif mk_posixopt_sysconf_map_entry (REALTIME_SIGNALS), +#if defined (_SC_REGEXP) mk_posixopt_sysconf_map_entry (REGEXP), +#endif mk_posixopt_sysconf_map_entry (SAVED_IDS), mk_posixopt_sysconf_map_entry (SEMAPHORES), mk_posixopt_sysconf_map_entry (SHARED_MEMORY_OBJECTS), +#if defined (_SC_SHELL) mk_posixopt_sysconf_map_entry (SHELL), +#endif +#if defined (_SC_SPAWN) mk_posixopt_sysconf_map_entry (SPAWN), +#endif +#if defined (_SC_SPIN_LOCKS) mk_posixopt_sysconf_map_entry (SPIN_LOCKS), +#endif +#if defined (_SC_SPORADIC_SERVER) mk_posixopt_sysconf_map_entry (SPORADIC_SERVER), +#endif mk_posixopt_sysconf_map_entry (SYNCHRONIZED_IO), mk_posixopt_sysconf_map_entry (THREAD_ATTR_STACKSIZE), +#if defined (_SC_THREAD_CPUTIME) mk_posixopt_sysconf_map_entry (THREAD_CPUTIME), +#endif mk_posixopt_sysconf_map_entry (THREAD_PRIO_INHERIT), mk_posixopt_sysconf_map_entry (THREAD_PRIO_PROTECT), mk_posixopt_sysconf_map_entry (THREAD_PRIORITY_SCHEDULING), +#if defined (_SC_THREAD_PROCESS_SHARED) mk_posixopt_sysconf_map_entry (THREAD_PROCESS_SHARED), +#endif mk_posixopt_sysconf_map_entry (THREAD_SAFE_FUNCTIONS), +#if defined (_SC_THREAD_SPORADIC_SERVER) mk_posixopt_sysconf_map_entry (THREAD_SPORADIC_SERVER), +#endif mk_posixopt_sysconf_map_entry (THREADS), +#if defined (_SC_TIMEOUTS) mk_posixopt_sysconf_map_entry (TIMEOUTS), +#endif mk_posixopt_sysconf_map_entry (TIMERS), +#if defined (_SC_TRACE) mk_posixopt_sysconf_map_entry (TRACE), +#endif +#if defined (_SC_TRACE_EVENT_FILTER) mk_posixopt_sysconf_map_entry (TRACE_EVENT_FILTER), +#endif +#if defined (_SC_TRACE_INHERIT) mk_posixopt_sysconf_map_entry (TRACE_INHERIT), +#endif +#if defined (_SC_TRACE_LOG) mk_posixopt_sysconf_map_entry (TRACE_LOG), +#endif #ifdef _SC_TYPED_MEMORY_OBJECT mk_posixopt_sysconf_map_entry (TYPED_MEMORY_OBJECT), #endif +#if defined (_POSIX_VDISABLE) mk_sysconf_map_entry (_POSIX_VDISABLE), +#endif mk_sysconf_map_entry (_XOPEN_CRYPT), mk_sysconf_map_entry (_XOPEN_LEGACY), #if defined (_XOPEN_REALTIME) @@ -343,6 +460,15 @@ struct procenv_map signal_map[] = { mk_map_entry (SIGXCPU), mk_map_entry (SIGXFSZ), +#if defined (PROCENV_BSD) || defined (PROCENV_HURD) + mk_map_entry (SIGEMT), + mk_map_entry (SIGINFO), +#endif + +#if defined (PROCENV_HURD) + mk_map_entry (SIGLOST), +#endif + { 0, NULL }, }; @@ -382,7 +508,7 @@ struct procenv_map scheduler_map[] = { mk_map_entry (SCHED_OTHER), mk_map_entry (SCHED_FIFO), mk_map_entry (SCHED_RR), -#if defined (PROCENV_LINUX) +#if defined (PROCENV_LINUX) && ! defined (PROCENV_ANDROID) mk_map_entry (SCHED_BATCH), #ifdef SCHED_IDLE mk_map_entry (SCHED_IDLE), @@ -408,6 +534,7 @@ usage (void) show ("Options:"); show (""); show (" -a, --meta : Display meta details."); + show (" -A, --arguments : Display program arguments."); show (" -b, --libs : Display library details."); show (" -c, --cgroup[s] : Display cgroup details (Linux only)."); show (" -d, --compiler : Display compiler details."); @@ -424,14 +551,15 @@ usage (void) show (" -L, --locale : Display locale details."); show (" -m, --mount[s] : Display mount details."); show (" -n, --confstr : Display confstr details."); + show (" -N, --network : Display network details."); show (" -o, --oom : Display out-of-memory manager details (Linux only)"); - show (" --output= : Send output to alternative location. Type can be one of:"); + show (" --output= : Send output to alternative location. can be one of:"); show (""); - show (" file # send output to a file."); - show (" stderr # write to standard error."); - show (" stdout # write to standard output (default)."); - show (" syslog # write to the system log file."); - show (" terminal # write to terminal."); + show (" file : Send output to a file."); + show (" stderr : Write to standard error."); + show (" stdout : Write to standard output (default)."); + show (" syslog : Write to the system log file."); + show (" terminal : Write to terminal."); show (""); show (" -p, --proc[ess] : Display process details."); show (" -P, --platform : Display platform details."); @@ -510,9 +638,6 @@ _show (const char *prefix, int indent, const char *fmt, ...) assert (fmt); - buffer = strdup (""); - assert (buffer); - if (indent) appendf (&buffer, "%*s", indent, " "); @@ -544,7 +669,7 @@ _show (const char *prefix, int indent, const char *fmt, ...) ret = write (user.tty_fd, buffer, strlen (buffer)); if (ret < 0) { fprintf (stderr, "ERROR: failed to write to terminal\n"); - exit (EXIT_FAILURE); + goto error; } break; @@ -557,14 +682,14 @@ _show (const char *prefix, int indent, const char *fmt, ...) if (output_fd < 0) { fprintf (stderr, "ERROR: failed to open file '%s'\n", output_file); - exit (EXIT_FAILURE); + goto error; } } ret = write (output_fd, buffer, strlen (buffer)); if (ret < 0) { fprintf (stderr, "ERROR: failed to write to file '%s'\n", output_file); - exit (EXIT_FAILURE); + goto error; } break; @@ -703,6 +828,8 @@ show_signals (void) die ("failed to query signal mask"); for (i = 1; i <= NUM_SIGNALS; i++) { + const char *signal_name; + const char *signal_desc; blocked = 0; ignored = 0; @@ -723,9 +850,12 @@ show_signals (void) else if (rc) blocked = 1; + signal_name = get_signal_name (i); + signal_desc = strsignal (i); + show ("%s ('%s', %d): blocked=%s, ignored=%s", - get_signal_name (i), - strsignal (i), + signal_name ? signal_name : UNKNOWN_STR, + signal_desc ? signal_desc : UNKNOWN_STR, i, blocked ? YES_STR : NO_STR, ignored ? YES_STR : NO_STR); @@ -819,6 +949,7 @@ dump_sysconf (void) } } +#ifndef PROCENV_ANDROID void show_confstrs (void) { @@ -832,6 +963,7 @@ show_confstrs (void) #endif show_confstr (_CS_PATH); } +#endif void get_misc (void) @@ -848,6 +980,7 @@ get_misc (void) #endif } +#if !defined (PROCENV_HURD) /** * is_console: * @fd: open file descriptor. @@ -855,31 +988,27 @@ get_misc (void) * Check if specified file descriptor is attached to a _console_ * device (physical or virtual). * - * Note that ptys are NOT consoles :) + * Notes: + * - ptys are NOT consoles :) + * - running inside screen/tmux will report not running on console. * * Returns: TRUE if @fd is attached to a console, else FALSE. - * - * FIXME: how can this be determined for BSD? **/ int is_console (int fd) { -#if defined (PROCENV_LINUX) - struct vt_mode vt; - int ret; + struct vt_mode vt; + int ret; - ret = ioctl (0, VT_GETMODE, &vt); + ret = ioctl (fd, VT_GETMODE, &vt); return !ret; -#else - return FALSE; -#endif } +#endif void dump_user (void) { - header ("process"); show ("process id (pid): %d", user.pid); @@ -904,11 +1033,11 @@ dump_user (void) show ("has controlling terminal: %s", has_ctty () ? YES_STR : NO_STR); -#if defined (PROCENV_LINUX) +#if defined (PROCENV_HURD) + show ("on console: %s", UNKNOWN_STR); +#else show ("on console: %s", is_console (user.tty_fd) ? YES_STR : NO_STR); -#else - show ("on console: %s", UNKNOWN_STR); #endif show ("real user id (uid): %d ('%s')", @@ -937,11 +1066,21 @@ dump_user (void) show ("login name: '%s'", user.login ? user.login : ""); +#if defined (PROCENV_ANDROID) + /* No gecos on Android. In fact it doesn't actually use the + * passwd database, but meh. + */ + show ("passwd: name='%s', dir='%s', shell='%s'", + user.passwd.pw_name, + user.passwd.pw_dir, + user.passwd.pw_shell); +#else show ("passwd: name='%s', gecos='%s', dir='%s', shell='%s'", user.passwd.pw_name, user.passwd.pw_gecos, user.passwd.pw_dir, user.passwd.pw_shell); +#endif show_all_groups (); } @@ -979,8 +1118,6 @@ dump_misc (void) dump_priorities (); show ("memory page size: %d bytes", getpagesize ()); - - #if defined (PROCENV_LINUX) #ifdef LINUX_VERSION_CODE show ("kernel headers version: %u.%u.%u", @@ -1042,11 +1179,13 @@ dump_fds (void) for (fd = 0; fd < max; fd++) { if (fd_valid (fd)) { - int is_tty = isatty (fd); - char *name = NULL; + int is_tty = isatty (fd); + char *name = NULL; if (is_tty) { +#if ! defined (PROCENV_ANDROID) name = ttyname (fd); +#endif show ("fd %d: terminal=%s ('%s')", fd, is_tty ? YES_STR : NO_STR, name ? name : NA_STR); @@ -1055,6 +1194,7 @@ dump_fds (void) } } } + #if defined (PROCENV_LINUX) dump_linux_proc_fds (); #endif @@ -1135,7 +1275,11 @@ get_user_info (void) user.login = getlogin (); user.pgroup = getpgrp (); +#if defined (PROCENV_ANDROID) + sprintf (user.ctrl_terminal, "/dev/tty"); +#else ctermid (user.ctrl_terminal); +#endif /* Get a reference to the controlling terminal * in case all standard fds are redirected. @@ -1174,6 +1318,11 @@ append (char **str, const char *new) assert (str); assert (new); + if (! *str) + *str = strdup (""); + + assert (*str); + /* +1 for terminating nul */ total = strlen (*str) + 1; @@ -1197,6 +1346,11 @@ appendf (char **str, const char *fmt, ...) assert (str); assert (fmt); + if (! *str) + *str = strdup (""); + + assert (*str); + va_start (ap, fmt); if (vasprintf (&new, fmt, ap) < 0) { @@ -1218,6 +1372,11 @@ appendva (char **str, const char *fmt, va_list ap) assert (str); assert (fmt); + if (! *str) + *str = strdup (""); + + assert (*str); + if (vasprintf (&new, fmt, ap) < 0) { perror ("vasprintf"); exit (EXIT_FAILURE); @@ -1379,6 +1538,19 @@ dump_meta (void) PRIVILEGED_STR); } +void +show_arguments (void) +{ + int i; + + header ("arguments"); + + show ("count: %u", argvc); + + for (i = 0; i < argvc; i++) + show ("argv[%d]='%s'", i, argvp[i]); +} + void show_stat (void) { @@ -1445,18 +1617,18 @@ show_stat (void) show ("group id (gid): %d ('%s')", st.st_gid, get_group_name (st.st_uid)); show ("size: %lu bytes (%lu 512-byte blocks)", st.st_size, st.st_blocks); - if (! ctime_r (&st.st_atime, formatted_time)) + if (! ctime_r ((time_t *)&st.st_atime, formatted_time)) die ("failed to format atime"); formatted_time[ strlen (formatted_time)-1] = '\0'; show ("atime: %lu (%s)", st.st_atime, formatted_time); - if (! ctime_r (&st.st_mtime, formatted_time)) + if (! ctime_r ((time_t *)&st.st_mtime, formatted_time)) die ("failed to format mtime"); formatted_time[ strlen (formatted_time)-1] = '\0'; show ("mtime: %lu (%s)", st.st_mtime, formatted_time); - if (! ctime_r (&st.st_ctime, formatted_time)) + if (! ctime_r ((time_t *)&st.st_ctime, formatted_time)) die ("failed to format ctime"); formatted_time[ strlen (formatted_time)-1] = '\0'; show ("ctime: %lu (%s)", st.st_ctime, formatted_time); @@ -1465,7 +1637,7 @@ show_stat (void) long get_kernel_bits (void) { -#if defined (PROCENV_LINUX) +#if defined (PROCENV_LINUX) && ! defined (PROCENV_ANDROID) long value; errno = 0; @@ -1482,6 +1654,7 @@ void dump (void) { dump_meta (); + show_arguments (); #if defined (PROCENV_LINUX) show_capabilities (); @@ -1489,14 +1662,19 @@ dump (void) #endif show_clocks (); show_compiler (); +#ifndef PROCENV_ANDROID show_confstrs (); +#endif show_env (); dump_fds (); +#ifndef PROCENV_ANDROID show_libs (); - show_locale (); +#endif show_rlimits (); + show_locale (); dump_misc (); show_mounts (SHOW_ALL); + show_network (); #if defined (PROCENV_LINUX) show_oom (); #endif @@ -1519,14 +1697,223 @@ dump (void) show_tty_attrs (); dump_uname (); } +void +get_network_address (const struct sockaddr *address, int family, char *name) +{ + int ret; -#if defined (PROCENV_LINUX) + assert (address); + assert (name); + + memset (name, '\0', NI_MAXHOST); + + if (family == AF_INET || family == AF_INET6) { + ret = getnameinfo (address, + (family == AF_INET) + ? sizeof (struct sockaddr_in) + : sizeof (struct sockaddr_in6), + (char *)name, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if (ret) { + switch (ret) { + case EAI_NONAME: + case EAI_FAMILY: + sprintf ((char *)name, "%s", NA_STR); + break; + default: + sprintf ((char *)name, "%s", UNKNOWN_STR); + break; + } + } + } else { + sprintf ((char *)name, "%s", NA_STR); + } + + assert (name[NI_MAXHOST-1] == '\0'); +} + +char * +decode_if_flags (unsigned int flags) +{ + char *str = NULL; + struct if_flag_map *p; + int first = TRUE; + + for (p = if_flag_map; p && p->name; p++) { + if (flags & p->flag) { + appendf (&str, "%s%s", + first ? "" : ",", + p->name); + first = FALSE; + } + } + + return str; +} + +const char * +get_ipv6_scope_name (uint32_t scope) +{ + switch (scope) { + case 0x0: + case 0xf: + return "reserved"; + break; + + case 0x1: + return "interface-local"; + break; + + case 0x2: + return "link-local"; + break; + + case 0x4: + return "admin-local"; + break; + + case 0x5: + return "site-local"; + break; + + case 0x8: + return "organization-local"; + break; + + case 0xe: + return "global"; + break; + } + + return UNKNOWN_STR; +} + +int +get_mtu (const struct ifaddrs *ifaddr) +{ + int sock; + struct ifreq ifr; + int request = SIOCGIFMTU; + + assert (ifaddr); + + /* We need to create a socket to query an interfaces mac + * address. Don't ask me why... + */ + sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP); + + if (sock < 0) + return -1; + + memset (&ifr, 0, sizeof (struct ifreq)); + strncpy (ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ-1); + + if (ioctl (sock, request, &ifr) < 0) + goto out; +out: + close (sock); + + return ifr.ifr_mtu; +} + +/* + * + * Returns: IEEE-802 format MAC address, or NULL on error. + */ +char * +get_mac_address (const struct ifaddrs *ifaddr) +{ + char *data = NULL; + char *mac_address = NULL; + int i; + int valid = FALSE; +#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__) + struct sockaddr_dl *link_layer; +#else + struct ifreq ifr; + int sock = -1; +#endif + +#if defined (PROCENV_LINUX) || defined (PROCENV_HURD) + int request = SIOCGIFHWADDR; +#endif + + assert (ifaddr); + +#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__) + link_layer = (struct sockaddr_dl *)ifaddr->ifa_addr; +#else + + /* We need to create a socket to query an interfaces mac + * address. Don't ask me why... + */ + sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP); + + if (sock < 0) + return NULL; + + memset (&ifr, 0, sizeof (struct ifreq)); + strncpy (ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ-1); + + if (ioctl (sock, request, &ifr) < 0) + goto out; +#endif + +#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__) + data = LLADDR (link_layer); +#else + data = (char *)ifr.ifr_hwaddr.sa_data; +#endif + + if (data) { + for (i = 0; i < 6; i++) { + if (data[i]) { + valid = TRUE; + break; + } + } + } + + /* MAC comprised of all zeros cannot be valid */ + if (! valid) + goto out; + + /* An IEEE-802 formatted MAC address comprises 6x 2-byte groups, + * separated by 5 colons with an additional byte for the string + * terminator. + */ + mac_address = calloc ((6*2) + 5 + 1, sizeof (char)); + if (! mac_address) + goto out; + + sprintf (mac_address, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + (unsigned char)data[0], + (unsigned char)data[1], + (unsigned char)data[2], + (unsigned char)data[3], + (unsigned char)data[4], + (unsigned char)data[5]); + +out: + +#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__) + /* NOP */ +#else + close (sock); +#endif + return mac_address; +} + + +#if defined (PROCENV_LINUX) || defined (PROCENV_HURD) void show_linux_mounts (ShowMountType what) { - FILE *mtab; - struct mntent *mnt; - int major, minor; + FILE *mtab; + struct mntent *mnt; + struct statvfs fs; + unsigned int major = 0; + unsigned int minor = 0; + int have_stats; mtab = fopen (MOUNTS, "r"); @@ -1536,19 +1923,80 @@ show_linux_mounts (ShowMountType what) } while ((mnt = getmntent (mtab))) { + char *str = NULL; + have_stats = TRUE; + if (what == SHOW_ALL || what == SHOW_MOUNTS) { + unsigned multiplier = 0; + fsblkcnt_t blocks; + fsblkcnt_t bfree; + fsblkcnt_t bavail; + fsblkcnt_t used_blocks; + fsblkcnt_t used_files; + + if (statvfs (mnt->mnt_dir, &fs) < 0) { + have_stats = FALSE; + } else { + multiplier = fs.f_bsize / DF_BLOCK_SIZE; + + blocks = fs.f_blocks * multiplier; + bfree = fs.f_bfree * multiplier; + bavail = fs.f_bavail * multiplier; + used_blocks = blocks - bfree; + used_files = fs.f_files - fs.f_ffree; + } + get_major_minor (mnt->mnt_dir, &major, &minor); - show ("fsname='%s', dir='%s', type='%s', " - "opts='%s', " - "dev=(major:%d, minor:%d)", - mnt->mnt_fsname, - mnt->mnt_dir, - mnt->mnt_type, - mnt->mnt_opts, - major, - minor); + appendf (&str, + "fsname='%s', dir='%s', type='%s', " + "opts='%s', " + "dev=(major:%u, minor:%u), " + "dump_freq=%d, fsck_passno=%d, ", + mnt->mnt_fsname, + mnt->mnt_dir, + mnt->mnt_type, + mnt->mnt_opts, + major, minor, + mnt->mnt_freq, mnt->mnt_passno); + + if (have_stats) { + appendf (&str, + "fsid=%.*x, " + "optimal_block_size=%lu, " + "%d-byte blocks (total=%lu, used=%lu, free=%lu, available=%lu), " + "files/inodes (total=%lu, used=%lu, free=%lu)", + sizeof (fs.f_fsid), + fs.f_fsid, + fs.f_bsize, + DF_BLOCK_SIZE, + blocks, + used_blocks, + bfree, + bavail, + fs.f_files, + used_files, + fs.f_ffree); + } else { + appendf (&str, + "fsid=%s, " + "optimal_block_size=%s, " + "%d-byte blocks (total=%s, used=%s, free=%s, available=%s), " + "files/inodes (total=%s, free=%s)", + UNKNOWN_STR, + UNKNOWN_STR, + UNKNOWN_STR, + UNKNOWN_STR, + UNKNOWN_STR, + UNKNOWN_STR, + UNKNOWN_STR, + UNKNOWN_STR, + UNKNOWN_STR); + } + + show (str); + free (str); } if (what == SHOW_ALL || what == SHOW_PATHCONF) @@ -1557,6 +2005,50 @@ show_linux_mounts (ShowMountType what) fclose (mtab); } +#endif + +#if defined (PROCENV_LINUX) +char * +decode_extended_if_flags (const char *interface, unsigned short *flags) +{ + int sock; + struct ifreq ifr; + int first = TRUE; + char *str = NULL; + struct if_extended_flag_map *p; + + assert (interface); + assert (flags); + + /* We need to create a socket to query an interfaces mac + * address. Don't ask me why... + */ + sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP); + + if (sock < 0) + return NULL; + + memset (&ifr, 0, sizeof (struct ifreq)); + strncpy (ifr.ifr_name, interface, IFNAMSIZ-1); + + if (ioctl (sock, SIOCGIFPFLAGS, &ifr) < 0) + goto out; + + *flags = ifr.ifr_flags; + + for (p = if_extended_flag_map; p && p->name; p++) { + if (*flags & p->flag) { + appendf (&str, "%s%s", + first ? "" : ",", + p->name); + first = FALSE; + } + } +out: + close (sock); + return str; +} + /** * linux_kernel_version: @@ -1629,7 +2121,7 @@ show_mounts (ShowMountType what) { header ("mounts"); -#if defined (PROCENV_LINUX) +#if defined (PROCENV_LINUX) || defined (PROCENV_HURD) show_linux_mounts (what); #endif @@ -1638,6 +2130,275 @@ show_mounts (ShowMountType what) #endif } +const char * +get_net_family_name (sa_family_t family) +{ + switch (family) { +#if defined (PROCENV_LINUX) + case AF_PACKET: + return "AF_PACKET"; + break; +#endif + +#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__) + case AF_LINK: + return "AF_LINK"; + break; +#endif + + case AF_INET: + return "AF_INET"; + break; + + case AF_INET6: + return "AF_INET6"; + break; + } + + return UNKNOWN_STR; +} + +void +show_network_if (const struct ifaddrs *ifa, const char *mac_address) +{ + char *str = NULL; + char *flags = NULL; + char *extended_flags = NULL; + unsigned short ext_flags = 0; + sa_family_t family; + char address[NI_MAXHOST]; + int mtu = 0; + + assert (ifa); + + family = ifa->ifa_addr->sa_family; + + flags = decode_if_flags (ifa->ifa_flags); + +#if defined (PROCENV_LINUX) + extended_flags = decode_extended_if_flags (ifa->ifa_name, &ext_flags); +#endif + appendf (&str, "interface %s: family=%s (0x%x), " + "flags=0x%x (%s), extended_flags=0x%x (%s)", + ifa->ifa_name, + get_net_family_name (family), + family, + ifa->ifa_flags, + flags ? flags : UNKNOWN_STR, + ext_flags, + extended_flags ? extended_flags : NA_STR); + if (flags) + free (flags); + + if (extended_flags) + free (extended_flags); + + mtu = get_mtu (ifa); + +#if defined (PROCENV_HURD) + /* No AF_LINK/AF_PACKET on Hurd atm */ + appendf (&str, ", mac=%s", UNKNOWN_STR); +#else + appendf (&str, ", mac=%s", mac_address ? mac_address : NA_STR); +#endif + + if (mtu > 0) { + appendf (&str, ", mtu=%d", mtu); + } else { + appendf (&str, ", mtu=%s", UNKNOWN_STR); + } + + get_network_address (ifa->ifa_addr, family, address); + appendf (&str, ", address=%s", address); + + if (ifa->ifa_netmask) + get_network_address (ifa->ifa_netmask, family, address); + appendf (&str, ", netmask=%s", ifa->ifa_netmask ? address : NA_STR); + +#if !defined (PROCENV_HURD) + if (family != PROCENV_LINK_LEVEL_FAMILY) { + if ((ifa->ifa_flags & IFF_BROADCAST) && ifa->ifa_broadaddr) { + get_network_address (ifa->ifa_broadaddr, family, address); + + appendf (&str, ", broadcast=%s", ifa->ifa_broadaddr ? address : NA_STR); + } + } else { +#endif + appendf (&str, ", broadcast=%s", NA_STR); +#if !defined (PROCENV_HURD) + } +#endif + + if (ifa->ifa_flags & IFF_POINTOPOINT && ifa->ifa_dstaddr) { + + get_network_address (ifa->ifa_dstaddr, family, address); + + appendf (&str, ", point-to-point=%s", address); + } + + show (str); + free (str); +} + +/* + * BSD returns an additional AF_LINK ifaddrs containing the + * actual link-layer MAC address for each interface. + * + * Linux does the same but with one additional AF_PACKET family / interface. + * + * This is somewhat noisome since for BSD we need to cache the MAC addresses + * such that they can be retrieved when the _next_ ifaddrs structure + * appears for the *same* interface, but we only want to + * display the non-AF_LINK elements *unless* they refer + * to an interface with no associated address. + * + * The situation for Linux is similar but we only care + * about AF_PACKET entries for interfaces that have no + * associated address since we can extract the MAC + * address using an ioctl (rather than considering the + * AF_PACKET element). + * + * The strategy therefore is to: + * + * 1) Cache all AF_LINK/AF_PACKET elements. + * 2) Once an element arrives that matches an interface + * name found in the cache, use that as necessary (extra + * the MAC for BSD, NOP for Linux), then free that cache + * element. + * 3) Having processed all entries, if any entries are + * left in the cache, they must refer to interfaces that + * have no address, so display them. + * + * XXX: Note the implicit assumption that the AF_LINK/AF_PACKET entries + * will appear _before_ the corresponding entry containing address + * details for the interface in the output of getifaddrs(): observations + * suggests this _seems_ to be the case, but is not documented as being + * guaranteed. + */ +void +show_network (void) +{ + struct ifaddrs *if_addrs; + struct ifaddrs *ifa; + char *mac_address = NULL; + struct network_map *head = NULL; + struct network_map *node = NULL; + struct network_map *tmp = NULL; + + header ("network"); + + /* Query all network interfaces */ + if (getifaddrs (&if_addrs) < 0) { + show ("%s", UNKNOWN_STR); + return; + } + + /* Construct an initial node for the cache */ + head = calloc (1, sizeof (struct network_map)); + assert (head); + + /* Iterate over all network interfaces */ + for (ifa = if_addrs; ifa; ifa = ifa->ifa_next) { +#if !defined (PROCENV_HURD) + int family; +#endif + + if (! ifa->ifa_addr) + continue; + +#if !defined (PROCENV_HURD) + family = ifa->ifa_addr->sa_family; + + if (family == PROCENV_LINK_LEVEL_FAMILY) { + + /* Add link level interface details to the cache */ + mac_address = get_mac_address (ifa); + + node = calloc (1, sizeof (struct network_map)); + assert (node); + + /* Conveniently, an ifaddrs contains a bunch of + * pointers and some flags. + * + * Since all those pointers are valid until we + * call freeifaddrs(), all we need to do is copy + * the flags since the memcpy will copy the + * pointers addresses for us :) + */ + memcpy (&node->ifaddr, ifa, sizeof (struct ifaddrs)); + node->ifaddr.ifa_flags = ifa->ifa_flags; + + /* Since we've already formatted the MAC + * address, we'll cache that too. + */ + node->mac_address = mac_address; + mac_address = NULL; + + /* prepend */ + node->next = head->next; + if (head->next) + head->next->prev = node; + node->prev = head; + head->next = node; + + continue; + } +#endif + + /* From now on, we're only looking at interfaces with an + * address. + */ + + /* Search for an entry corresponding to the interface in the cache */ + for (node = head->next; node && node->ifaddr.ifa_name; node = node->next) { + if (! strcmp (node->ifaddr.ifa_name, ifa->ifa_name)) { + + /* Save */ + mac_address = node->mac_address + ? strdup (node->mac_address) + : NULL; + + /* Unlink existing node as it has now served its purpose */ + node->prev->next = node->next; + if (node->next) + node->next->prev = node->prev; + + /* Destroy */ + if (node->mac_address) + free (node->mac_address); + free (node); + + break; + } + } + + /* Display the interface (which must have an associated address) */ + show_network_if (ifa, mac_address); + if (mac_address) { + free (mac_address); + mac_address = NULL; + } + } + + /* Destroy the cache, displaying any interfaces not previously displayed. + * These by definition cannot have addresses assigned to them. + */ + for (node = head->next; node && node->ifaddr.ifa_name; node = tmp) { + + tmp = node->next; + + show_network_if (&node->ifaddr, node->mac_address); + + /* Destroy */ + if (node->mac_address) + free (node->mac_address); + free (node); + } + + free (head); + freeifaddrs (if_addrs); +} + #if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__) char * @@ -1645,7 +2406,6 @@ get_bsd_mount_opts (uint64_t flags) { struct mntopt_map *opt; char *str = NULL; - int first = TRUE; size_t len = 0; size_t total = 0; int count = 0; @@ -1694,10 +2454,17 @@ get_bsd_mount_opts (uint64_t flags) void show_bsd_mounts (ShowMountType what) { - int count; - struct statfs *mounts; - struct statfs *mnt; - int i; + int count; + struct statfs *mounts; + struct statfs *mnt; + unsigned int major = 0; + unsigned int minor = 0; + int i; + unsigned multiplier = 0; + statfs_int_type blocks; + statfs_int_type bfree; + statfs_int_type bavail; + statfs_int_type used; /* Note that returned memory cannot be freed (by us) */ count = getmntinfo (&mounts, MNT_WAIT); @@ -1716,12 +2483,47 @@ show_bsd_mounts (ShowMountType what) mnt->f_mntonname); if (what == SHOW_ALL || what == SHOW_MOUNTS) { - show ("fsname='%s', dir='%s', type='%s', opts='%s'", + + get_major_minor (mnt->f_mntonname, + &major, + &minor); + + multiplier = mnt->f_bsize / DF_BLOCK_SIZE; + blocks = mnt->f_blocks * multiplier; + bfree = mnt->f_bfree * multiplier; + bavail = mnt->f_bavail * multiplier; + used = blocks - bfree; + + show ("fsname='%s', dir='%s', type='%s', " + "opts='%s', " + "dev=(major:%u, minor:%u), " + "fsid=%.*x%.*x, " + "optimal_block_size=%" statfs_int_fmt ", " + "%d-byte blocks (total=%" statfs_int_fmt ", " + "used=%" statfs_int_fmt ", free=%" statfs_int_fmt ", available=%" statfs_int_fmt "), " + "files/inodes (total=%" statfs_int_fmt ", free=%" statfs_int_fmt ")", mnt->f_mntfromname, mnt->f_mntonname, mnt->f_fstypename, - opts); + opts, + major, minor, + + /* Always zero on BSD? */ + sizeof (mnt->f_fsid.val[0]), + mnt->f_fsid.val[0], + sizeof (mnt->f_fsid.val[1]), + mnt->f_fsid.val[1], + + mnt->f_bsize, + DF_BLOCK_SIZE, + blocks, + used, + bfree, + bavail, + mnt->f_files, + mnt->f_ffree); } + if (what == SHOW_ALL || what == SHOW_PATHCONF) show_pathconfs (what, mnt->f_mntonname); mnt++; @@ -1729,6 +2531,7 @@ show_bsd_mounts (ShowMountType what) free (opts); } } + #endif void @@ -1757,11 +2560,13 @@ const char * container_type (void) { struct stat statbuf; - dev_t expected; char buffer[1024]; FILE *f; +#if defined (PROCENV_LINUX) + dev_t expected; expected = makedev (5, 1); +#endif if (stat ("/dev/console", &statbuf) < 0) goto out; @@ -1883,6 +2688,7 @@ show_proc_branch (void) } #if defined (PROCENV_BSD) +/* Who would have thought handling PIDs was so tricky? */ void show_bsd_proc_branch (void) { @@ -1895,6 +2701,7 @@ show_bsd_proc_branch (void) pid_t self, current; int done = FALSE; char *str; + pid_t ultimate_parent = 0; str = strdup ("ancestry: "); assert (str); @@ -1909,21 +2716,89 @@ show_bsd_proc_branch (void) if (! procs) die ("failed to get process info"); + /* Calculate the lowest PID number which gives us the ultimate + * parent of all processes. + * + * On BSD sytems, normally PID 0 ('[kernel]') is the ultimate + * parent rather than PID 1 ('init'). + * + * However, this doesn't work in a BSD jail since in that + * environment: + * + * - there is no init process visible. + * - there is no kernel thread visible. + * - the ultimate parent PID will either by 1 (the "invisible" + * init process) or 'n' where 'n' is a PID>1 which is also + * "invisible" (since it lives outside the jail in the host + * environment). + * + * Confused yet? + */ + + p = &procs[0]; + ultimate_parent = p->ki_pid; + + for (i = 1; i < count; i++) { + p = &procs[i]; + if (p->ki_pid < ultimate_parent) + ultimate_parent = p->ki_pid; + } + while (! done) { - for (i = 0; i < count; i++) { + for (i = 0; i < count && !done; i++) { p = &procs[i]; if (p->ki_pid == current) { - if (current == 0) { - /* ultimate parent == PID 0 == '[kernel]' */ + if (misc.in_jail) { + struct kinfo_proc *p2; + int ppid_found = FALSE; + int j; + + /* Determine if the parent PID + * actually exists within the + * jail. + */ + for (j = 0; j < count; j++) { + p2 = &procs[j]; + + if (p2->ki_pid == p->ki_ppid) { + ppid_found = TRUE; + break; + } + } + + if (p->ki_ppid == 1 || (p->ki_ppid && ! ppid_found)) { + /* Found the "last" PID (whose parent is either + * the "invisible init" or which exists outside the jail) + * so record it and hop out. + */ + appendf (&str, "%d ('%s') %d (%s)", + (int)current, p->ki_comm, + p->ki_ppid, UNKNOWN_STR); + done = TRUE; + break; + } else { + /* Found a valid parent pid */ + appendf (&str, "%d ('%s'), ", + (int)current, p->ki_comm); + } + + } else if (! ultimate_parent && current == ultimate_parent) { + + /* Found the "last" PID so record it and hop out */ appendf (&str, "%d ('%s')", (int)current, p->ki_comm); done = TRUE; break; + } else { + + /* Found a valid parent pid */ appendf (&str, "%d ('%s'), ", (int)current, p->ki_comm); } + + /* Move on */ current = p->ki_ppid; } } @@ -2344,7 +3219,7 @@ show_tty_attrs (void) struct winsize size; int ret; int fds[4] = { -1, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO }; - int i; + size_t i; fds[0] = user.tty_fd; @@ -2365,7 +3240,6 @@ show_tty_attrs (void) } } -out_of_ideas: show ("%s", NA_STR); return; @@ -2710,6 +3584,7 @@ get_arch (void) return UNKNOWN_STR; } +#ifndef PROCENV_ANDROID int libs_callback (struct dl_phdr_info *info, size_t size, void *data) { @@ -2726,6 +3601,7 @@ show_libs (void) dl_iterate_phdr (libs_callback, NULL); } +#endif void show_clocks (void) @@ -2917,25 +3793,28 @@ show_ranges (void) void show_compiler (void) { - char *name; - char *version; + char *name = NULL; + char *version = NULL; -#if defined (__GNUC__) - name = "GCC"; - version = __VERSION__; -#elif defined (__clang__) - name = "LLVM"; - version = __clang_version__; -#elif defined (__INTEL_COMPILER) +#if defined (__INTEL_COMPILER) name = "Intel"; version = __ICC; +#elif defined (__clang__) + name = "Clang/LLVM"; + version = __clang_version__; +#elif defined (__GNUC__) + name = "GCC"; + version = __VERSION__; #endif header ("compiler"); - show ("name: %s", name); - show ("version: %s", version); - show ("compile date: %s", __DATE__); - show ("compile time: %s", __TIME__); + show ("name: %s", name ? name : UNKNOWN_STR); + show ("version: %s", version ? version : UNKNOWN_STR); + show ("compile date (__DATE__): %s", __DATE__); + show ("compile time (__TIME__): %s", __TIME__); + show ("translation unit (__FILE__): %s", __FILE__); + show ("base file (__BASE_FILE__): %s", __BASE_FILE__); + show ("timestamp (__TIMESTAMP__): %s", __TIMESTAMP__); #ifdef __STRICT_ANSI__ show ("__STRICT_ANSI__: %s", DEFINED_STR); @@ -3269,7 +4148,6 @@ dump_linux_proc_fds (void) char *prefix_path = "/proc/self/fd"; char path[MAXPATHLEN]; char link[MAXPATHLEN]; - int saved_errno; ssize_t len; header ("fds (linux/proc)"); @@ -3584,25 +4462,25 @@ check_envvars (void) } void -get_major_minor (const char *path, int *major, int *minor) +get_major_minor (const char *path, unsigned int *_major, unsigned int *_minor) { struct stat st; assert (path); - assert (major); - assert (minor); + assert (_major); + assert (_minor); if (stat (path, &st) < 0) { /* Don't fail as this query may be for a mount which the * user does not have permission to check. */ warn ("unable to stat path '%s'", path); - *major = *minor = -1; + *_major = *_minor = 0; return; } - *major = major (st.st_dev); - *minor = minor (st.st_dev); + *_major = major (st.st_dev); + *_minor = minor (st.st_dev); } /** @@ -3635,7 +4513,6 @@ get_path (const char *argv0) char cwd[PATH_MAX]; size_t bytes; size_t len; - int ret; memset (cwd, '\0', sizeof (cwd)); @@ -3706,7 +4583,12 @@ show_threads (void) show ("thread stack size: %lu bytes", (unsigned long int)stack_size); +#if defined (PROCENV_ANDROID) + ret = 0; + scope = pthread_attr_getscope (&attr); +#else ret = pthread_attr_getscope (&attr, &scope); +#endif show ("thread scope: %s", ret != 0 ? UNKNOWN_STR : scope == PTHREAD_SCOPE_SYSTEM ? "PTHREAD_SCOPE_SYSTEM" @@ -3731,6 +4613,7 @@ show_threads (void) else show ("thread scheduler priority: %d", param.sched_priority); +#ifndef PROCENV_ANDROID ret = pthread_attr_getinheritsched (&attr, &inherit_sched); show ("thread inherit scheduler: %s", ret != 0 ? UNKNOWN_STR : @@ -3739,6 +4622,7 @@ show_threads (void) : "PTHREAD_EXPLICIT_SCHED"); show ("thread concurrency: %d", pthread_getconcurrency ()); +#endif } char * @@ -3793,8 +4677,8 @@ show_data_model (void) #undef DATA_MODEL int -main (int argc, - char *argv[]) +main (int argc, + char *argv[]) { int option; int long_index; @@ -3802,6 +4686,7 @@ main (int argc, struct option long_options[] = { {"meta" , no_argument, NULL, 'a'}, + {"arguments" , no_argument, NULL, 'A'}, {"libs" , no_argument, NULL, 'b'}, {"cgroup" , no_argument, NULL, 'c'}, {"cgroups" , no_argument, NULL, 'c'}, @@ -3820,6 +4705,7 @@ main (int argc, {"mount" , no_argument, NULL, 'm'}, {"mounts" , no_argument, NULL, 'm'}, {"confstr" , no_argument, NULL, 'n'}, + {"network" , no_argument, NULL, 'N'}, {"oom" , no_argument, NULL, 'o'}, {"proc" , no_argument, NULL, 'p'}, {"process" , no_argument, NULL, 'p'}, @@ -3848,6 +4734,8 @@ main (int argc, }; program_name = argv[0]; + argvp = argv; + argvc = argc; /* Check before command-line options, since the latter * must take priority. @@ -3858,7 +4746,7 @@ main (int argc, while (TRUE) { option = getopt_long (argc, argv, - "abcdefghijklLmnopPqrstTuUvwxyz", + "aAbcdefghijklLmnNopPqrstTuUvwxyz", long_options, &long_index); if (option == -1) break; @@ -3893,8 +4781,14 @@ main (int argc, dump_meta (); break; + case 'A': + show_arguments (); + break; + case 'b': +#ifndef PROCENV_ANDROID show_libs (); +#endif break; case 'c': @@ -3951,7 +4845,13 @@ main (int argc, break; case 'n': +#ifndef PROCENV_ANDROID show_confstrs (); +#endif + break; + + case 'N': + show_network (); break; case 'o': @@ -3961,6 +4861,7 @@ main (int argc, break; case 'p': + get_misc (); dump_user (); break; @@ -4037,16 +4938,20 @@ main (int argc, if (reexec && ! exec_args && optind >= argc) die ("must specify atleast one argument with '--exec'"); - dump (); - - cleanup (); - + /* Prepare for re-exec */ if (reexec) { if (! exec_args) { argv += optind; exec_args = argv; } + } + dump (); + + cleanup (); + + /* Perform re-exec */ + if (reexec) { execvp (exec_args[0], exec_args); die ("failed to re-exec %s", exec_args[0]); } @@ -4054,3 +4959,23 @@ main (int argc, exit (EXIT_SUCCESS); } + +char * +get_user_name (uid_t uid) +{ + struct passwd *p; + + p = getpwuid (uid); + + return p ? p->pw_name : NULL; +} + +char * +get_group_name (gid_t gid) +{ + struct group *g; + + g = getgrgid (gid); + + return g ? g->gr_name : NULL; +} diff --git a/src/procenv.h b/src/procenv.h index c6d8c74..c531af0 100644 --- a/src/procenv.h +++ b/src/procenv.h @@ -42,6 +42,26 @@ #include #include #include +#include +#include +#include +#include + +/* FIXME: Android testing */ +#if 1 +#ifndef PACKAGE_NAME +#define PACKAGE_NAME "procenv" +#endif + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "0.24" +#endif + +#ifndef PACKAGE_STRING +#define PACKAGE_STRING PACKAGE_NAME +#endif + +#endif /* FIXME */ #if defined (__FreeBSD__) \ || defined (__NetBSD__) \ @@ -53,6 +73,10 @@ #define PROCENV_LINUX #endif +#if defined (PROCENV_LINUX) && defined (__BIONIC__) +#define PROCENV_ANDROID +#endif + #ifdef __GNU__ #define PROCENV_HURD #endif @@ -61,9 +85,20 @@ #define PROCENV_ARCH_X86 #endif -#if defined (PROCENV_LINUX) +#if defined PROCENV_ANDROID +/* major(3) / minor(3) */ +#include +#endif + +#if defined (PROCENV_LINUX) || defined (PROCENV_HURD) #include -#include +#include +#include +#endif + +#if defined (PROCENV_LINUX) +#include + #include #include @@ -151,6 +186,14 @@ #include #include #include +#include +#include +#include +#include +#endif + +#if defined (PROCENV_HURD) +#include #endif #if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__) @@ -177,6 +220,26 @@ #define FALSE (!TRUE) #endif +/* Network family for entries containing link-level interface + * details. These entries will be cached to allow MAC addresses + * to be extracted from them when displaying the corresponding + * higher-level network family entries for the interface in + * question. + */ +#if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__) +#define PROCENV_LINK_LEVEL_FAMILY AF_LINK +#elif defined (PROCENV_LINUX) +#define PROCENV_LINK_LEVEL_FAMILY AF_PACKET +#endif + +#if defined (PROCENV_BSD) +#define statfs_int_type uint64_t +#define statfs_int_fmt PRIu64 +#elif defined (__FreeBSD_kernel__) +#define statfs_int_type uint64_t +#define statfs_int_fmt "lu" +#endif + /* FIXME: gettext */ #define _(str) str @@ -199,6 +262,9 @@ #define NUM_SIGNALS 32 #endif +/* Size of blocks we will show the user (as df(1) does) */ +#define DF_BLOCK_SIZE 1024 + /* If an indent is required, use this many spaces */ #define INDENT 2 @@ -221,14 +287,6 @@ #define type_hex_width(type) \ (sizeof (type) * 2) -#define get_group_name(gid) \ -({struct group *g = getgrgid (gid); \ - g ? g->gr_name : NULL;}) - -#define get_user_name(uid) \ -({struct passwd *p = getpwuid (uid); \ - p ? p->pw_name : NULL;}) - #define show_clock_res(clock) \ { \ struct timespec res; \ @@ -415,8 +473,17 @@ struct procenv_priority { int user; }; +struct network_map { + struct ifaddrs ifaddr; + char *mac_address; + + struct network_map *next; + struct network_map *prev; +}; + void _show (const char *prefix, int indent, const char *fmt, ...); +void header (const char *fmt, ...); void init (void); void cleanup (void); bool in_chroot (void); @@ -433,7 +500,13 @@ void show_env (void); void show_rlimits (void); void show_rusage (void); void dump_sysconf (void); +char *get_user_name (gid_t gid); +char *get_group_name (gid_t gid); + +#ifndef PROCENV_ANDROID void show_confstrs (void); +#endif + void dump_priorities (void); void show_mounts (ShowMountType what); void get_user_info (void); @@ -445,12 +518,17 @@ void show_proc_branch (void); void show_tty_attrs (void); const char * get_speed (speed_t speed); const char * get_signal_name (int signum); +void show_arguments (void); void dump_meta (void); char *get_os (void); char *get_arch (void); void dump_platform (void); + +#ifndef PROCENV_ANDROID int libs_callback (struct dl_phdr_info *info, size_t size, void *data); void show_libs (void); +#endif + int get_indent (void); void show_clocks (void); void show_timezone (void); @@ -463,7 +541,11 @@ void show_compiler (void); void get_uname (void); void dump_uname (void); void show_all_groups (void); + +#if !defined (PROCENV_HURD) int is_console (int fd); +#endif + long get_kernel_bits (void); bool has_ctty (void); void show_cpu (void); @@ -476,15 +558,25 @@ int get_output_value (const char *name); void set_indent (void); void show_stat (void); void show_locale (void); -void get_major_minor (const char *path, int *major, int *minor); +void get_major_minor (const char *path, + unsigned int *_major, + unsigned int *_minor); bool uid_match (uid_t uid); char * get_path (const char *argv0); bool is_big_endian (void); char * get_thread_scheduler_name (int sched); int qsort_compar (const void *a, const void *b); void show_data_model (void); - +const char *get_net_family_name (sa_family_t family); +void show_network (void); +void show_network_if (const struct ifaddrs *ifa, const char *mac_address); +void get_network_name (const struct sockaddr *address, int family, char *name); +const char *get_ipv6_scope_name (uint32_t scope); +char *get_mac_address (const struct ifaddrs *ifaddr); +int get_mtu (const struct ifaddrs *ifaddr); +char *decode_if_flags (unsigned int flags); #if defined (PROCENV_LINUX) +char *decode_extended_if_flags (const char *interface, unsigned short *flags); void get_root (char *root, size_t len); void get_tty_locked_status (struct termios *lock_status); void dump_linux_proc_fds (void); @@ -493,7 +585,7 @@ void show_oom (void); void show_capabilities (void); void show_linux_security_module (void); void show_linux_security_module_context (void); -void show_linux_mounts (ShowMountType what); +void show_linux_network (void); void show_linux_proc_branch (void); void show_linux_prctl (void); void show_linux_cpu (void); @@ -502,9 +594,14 @@ void show_linux_scheduler (void); bool linux_kernel_version (int major, int minor, int revision); #endif /* PROCENV_LINUX */ +#if defined (PROCENV_LINUX) || defined (PROCENV_HURD) +void show_linux_mounts (ShowMountType what); +#endif + #if defined (PROCENV_BSD) || defined (__FreeBSD_kernel__) char * get_bsd_mount_opts (uint64_t flags); void show_bsd_mounts (ShowMountType what); +void show_bsd_network (void); void get_bsd_misc (void); void show_bsd_proc_branch (void); void show_bsd_cpu (void); -- cgit v1.2.3