binstats-1.08.orig/ 0040755 0001750 0000144 00000000000 07231561214 013260 5 ustar mvela users binstats-1.08.orig/README 0100644 0001750 0000144 00000013505 07231561206 014142 0 ustar mvela users Introduction
------------
This is binstats 1.08 - an administration utility for tracking down the
various types of binary formats for Linux executables and their dynamic
library dependencies and also executable scripts and man pages.
Features include:
1) tally of a.out (Linux/i386), ELF and ECOFF (new!) binaries, dynamically
and statically linked, unstripped and setuid
2) tally of Java bytecode binaries (if you run file-3.20+)
3) tally of text files distinguishing between Bourne, bash and [T]C shells,
awk, perl, python & tcl scripts, other interpreted scripts & unidentified
texts
4) tally of duplicated executable names
5) tally of binaries with missing dynamic libraries
6) tally of DLL and ELF dynamic libraries, used and unused
7) tally of man pages and duplicated manual names (new!)
8) a log of all the above tallies plus listing a.out binaries, statically
linked binaries, unstripped binaries, setuid binaries, duplicated
executables, missing library binaries, all unidentified text files,
all used and unused dynamic libraries, duplicated manuals
9) a C program that dereferences symbolic links
10) a command line interface
It was inspired by "execount" written by Murple (murple@clark.net)
. Originally, when binstats
was created in 1996 it was useful during the a.out to ELF transition for
pruning a system of a.out executables.
Now in 2001, times have changed with fancy package management systems being
common on Linux distributions. This makes binstats much less needed. But the
hurdle of creating binary packages suffices that people still compile stuff
from tar balls of source code - I know I do. Of course, with the ravages of
time, after many compilations and installations your system gets into a
rather untidy state: forgotten binaries that once used libc5 populated
/usr/local/bin; multiple versions of dynamically linked libraries lie
forlorn; various man pages are scattered across your file hierarchy. All
because you were enjoying the vicarious pleasure of trying the latest and
greatest version of rapidly changing open sources. Thus binstats is a last
resort to restore order to the chaos that this ad-hoc approach to software
installation brings.
Go on, try it. You know you want to: it's the latest version...
Technical details
-----------------
Binstats has been written as a bash script utilising the following common
unix tools: echo, tr, cat, xargs, cut, dirname, sed, find, sort, uniq, grep,
file, ldd, awk, col, diff, wc, uname, date. [As usual, a Linux distribution
is indebted to the GNU project for most of these tools.]
This latest version has been tested on Redhat 6.2 which contains GNU
bash 1.14.7, GNU sh-utils 2.0, GNU findutils 4.1, GNU textutils 2.0e, GNU
grep 2.4, file 3.28, ld.so 1.9.5, Gnu libc 2.1.3, Gnu Awk (gawk) 3.0.4,
util-linux 2.10f and GNU diffutils 2.7.
Also binstats (1.0.7) had been tested on Redhat 5.1 which contains GNU bash
1.14.7, GNU sh-utils 1.16, GNU findutils 4.1, GNU textutils 1.22, GNU grep
2.0, file 3.24, ld.so 1.9.5, Gnu libc 2.0.7, Gnu Awk (gawk) 3.0.3,
util-linux 2.7 and GNU diffutils 2.7.
Finally versions up to 1.05 have been tested on Redhat 4.2 which contains
GNU bash 1.14.7, GNU sh-utils 1.16, GNU findutils 4.1, GNU textutils 1.22,
GNU grep 2.0, file 3.22, ld.so 1.7.14, Gnu Awk (gawk) 3.0.2 and GNU
diffutils 2.7.
Historical bugs
---------------
Of the numerous commands used by binstats, some old versions of two
utilities have slight problems.
file: For ELF 'not stripped' support, pick up "file 3.15-grr1" plus the
patch from Mitch D'Souza .
Compile and install accordingly to instructions.
There is a bug in the magic of file-3.15: in Magdir/commands, the six lines
from 40-45 inclusive should be moved to the end.
file-3.20 has ELF 'not stripped' support and Java bytecode support.
ldd: ldd has at least one bug (in ld.so 1.7.14) and one inconsistency (or
feature) which binstats has to be cope with. The latter problem is still
present in the version that comes with Red Hat 5.1 - when only a single name
is passed to ldd, it does not print the name of the file. The solutions to
these problems are controlled by switches in the script.
Running
-------
Edit the Makefile to suit your setup. Compile derefsymlink, install the
executables and man pages. Read the notes in the script before using
binstats.
Now you have three options:
1) leave binstats as is and it will use your PATH and ld.so.conf
2) edit the variables to fit your system
or 3) use the command line interface
./binstats [-b[inaries]="list of executable directories"] [-d[ebug]]
[-f[ile]=bstats.log] [-h[elp]]
[-l[ibraries]="list of library directories"]
[-m[anuals]="list of manual directories"]
[-p[ath]="usual path for binstats"]
[-t[emp]=/tmp] [-v[ersion]]
For example, if you have a minimal system then try
./binstats -b="/bin /sbin /usr/bin /usr/sbin"
if you only have the four specified directories.
If you don't run it as root then any executable without world readable
status (especially setuid binaries) will register in the tallies or log as
"can't read setuid".
Acknowledgements
----------------
Thanks goes to the people who have provided feedback. Special thanks goes to
Matej Vela who contributed the man pages.
Bugs, etc
---------
Please send any bug reports, patches, etc to me. The latest version can be
found at . The
distribution is also archived at
.
To do
-----
Maybe it's better use Perl or Python [when I read up on it] for all this.
Peter Chang
18th January 2001
PS binstats is released under the GPL and as such the usual licence
conditions and lack of warranty apply.
binstats-1.08.orig/Makefile 0100644 0001750 0000144 00000001362 07023010045 014705 0 ustar mvela users # -*- sh -*-
# Makefile for derefsymlink compilation and installation
#
# Edit the following to suit your system and type "make install"
CC= gcc
CFLAGS= -Wall -O6
LDFLAGS= -s
# This sets the prefix for the executable and manual page directories
# during installation
PREFIX= /usr/local
# If you want to install derefsymlink in some place other than
# /usr/local/bin then make sure PATH is set accordingly in binstats
DESTBIN= $(PREFIX)/bin
DESTMAN= $(PREFIX)/man/man1
derefsymlink: derefsymlink.o
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) derefsymlink.o
install:: derefsymlink
install -m 755 derefsymlink $(DESTBIN)
install -m 755 binstats $(DESTBIN)
install -m 644 binstats.1 derefsymlink.1 $(DESTMAN)
clean:
rm -f derefsymlink derefsymlink.o
binstats-1.08.orig/derefsymlink.c 0100644 0001750 0000144 00000015520 06447524331 016127 0 ustar mvela users /*
* derefsymlink - a program to dereference symbolic links
*
* Copyright (c) 1996 by Peter Chang
* Peter.Chang@nottingham.ac.uk
*
* It takes in pathnames and spits them out fully dereference.
* If any of the components of the pathnames do not exist or
* contain circular symlinks, the program stays silent or
* prints a message to stderr.
* [Some of the error checking is rather paranoid but it's better
* to be safe than sorry.]
*
* Revision 0.1 created on 1996/8/21
* made skeleton program which processes options and filenames
* correctly, derefname() just echos back at the moment
* Revision 0.2 written on 1996/8/23
* filled in rest of program, including derefname() and striprel()
* added verbose flag
* Revision 0.3 debugged on 1997/12/22
* the last test in derefname() did not cope with a single link to
* a top directory
*/
#include
#include
#include
#include
#include
#define IN_USE_ARGV 0
#define IN_USE_FILE 1
#define IN_USE_STDIN 2
#define OUT_USE_STDOUT 0
#define OUT_USE_FILE 1
#define DEPTH_LIMIT 25 /* max directory depth */
int in_method = IN_USE_ARGV;
int out_method = OUT_USE_STDOUT;
int verbose = 0;
int main(int argc, char *argv[])
{
static char iname[FILENAME_MAX], oname[FILENAME_MAX],
cname[FILENAME_MAX];
int al, i;
FILE *fi, *fo;
int pcl(int , char **, char *, char *);
int derefname(char *, int );
/* look for options */
al = pcl(argc, argv, iname, oname);
/* set up output */
if (out_method == OUT_USE_FILE) {
if ((fo = fopen(oname, "w")) == NULL) {
if (verbose) fprintf(stderr, "can't open output file %s", oname);
exit(EXIT_FAILURE);
}
} else fo = stdout;
/* if there is a list from a file or stdin
* then go through this first */
if (in_method != IN_USE_ARGV) {
if (in_method == IN_USE_FILE) {
if ((fi = fopen(iname, "r")) == NULL) {
if (verbose) fprintf(stderr, "can't open input file %s", iname);
exit(EXIT_FAILURE);
}
} else fi = stdin;
while ((i = fscanf(fi, "%s", cname)) != EOF) {
if (derefname(cname, 0) >= 0) fprintf(fo, "%s\n", cname);
}
}
/* now finish off the remaining arguments */
while (al < argc) {
strncpy(cname, argv[al++], FILENAME_MAX-1);
if (derefname(cname, 0) >= 0) fprintf(fo, "%s\n", cname);
}
if (out_method == OUT_USE_FILE) fclose(fo);
return EXIT_SUCCESS;
}
static char curdir[FILENAME_MAX];
/* do the real work here */
int derefname(char *name, int depth)
{
char tempa[FILENAME_MAX], cname[FILENAME_MAX];
struct stat sbuf;
int len, sc;
char *ptra;
int striprel(char *);
/* check if we are bombing out */
if (depth < 0) return depth;
if (depth > DEPTH_LIMIT) {
/* recursion limit to prevent circular reference */
if (verbose) fprintf(stderr, "circular symbolic link: %s\n", name);
return -1;
}
strncpy(cname, name, FILENAME_MAX-1);
if (name[0] != '/') { /* is name absolute */
if (curdir[0] == '\0') { /* initialise current directory */
getcwd(curdir, FILENAME_MAX-1);
strncat(curdir, "/", FILENAME_MAX-1);
}
/* append cwd to local name */
strncpy(cname, curdir, FILENAME_MAX-1);
strncat(cname, name, FILENAME_MAX-1);
}
if (striprel(cname) != 0) return -1;
if (lstat(cname, &sbuf) != 0) {
if (verbose) fprintf(stderr, "%s does not exist\n", cname);
return -1;
}
sc = 0;
while (S_ISLNK(sbuf.st_mode)) { /* check for symlink and deref it */
if (sc > DEPTH_LIMIT) {
/* recursion limit to prevent circular reference */
if (verbose) fprintf(stderr, "circular symbolic link: %s\n", cname);
return -1;
}
len = readlink(cname, tempa, FILENAME_MAX-1);
tempa[len] = '\0';
if (tempa[0] != '/') {
if ((ptra = strrchr(cname, '/')) == NULL) {
if (verbose) fprintf(stderr, "Error in stripping link\n");
return -1;
}
*(ptra+1) = '\0';
strncat(cname, tempa, FILENAME_MAX-1);
} else {
strncpy(cname, tempa, FILENAME_MAX-1);
}
if (striprel(cname) != 0) return -1;
if (lstat(cname, &sbuf) != 0) {
if (verbose) fprintf(stderr, "%s does not exist\n", cname);
return -1;
}
sc++;
}
/* strip last name */
if ((ptra = strrchr(cname, '/')) == NULL) {
if (verbose) fprintf(stderr, "Error in stripping name\n");
return -1;
}
if (ptra != cname) {
strncpy(tempa, ptra, FILENAME_MAX-1);
*ptra = '\0';
/* dereference rest of path */
depth = derefname(cname, depth+1);
strncpy(name, cname, FILENAME_MAX-1);
strncat(name, tempa, FILENAME_MAX-1);
} else strncpy(name, cname, FILENAME_MAX-1);
return depth;
}
/* remove all "/../" and "/./" in pathnames */
int striprel(char *name)
{
static char tempa[FILENAME_MAX], tempb[FILENAME_MAX];
char *ptra, *ptrb;
strncpy(tempa, name, FILENAME_MAX-1);
while ((ptra = strstr(tempa, "/../")) != NULL) {
*ptra = '\0';
if ((ptrb = strrchr(tempa, '/')) == NULL) {
if (verbose) fprintf(stderr, "Error in stripping '..'\n");
return -1;
}
*(ptrb+1) = '\0';
strncpy(tempb, ptra+4, FILENAME_MAX-1);
strncat(tempa, tempb, FILENAME_MAX-1);
}
while ((ptra = strstr(tempa, "/./")) != NULL) {
*ptra = '\0';
strncpy(tempb, ptra+2, FILENAME_MAX-1);
strncat(tempa, tempb, FILENAME_MAX-1);
}
strncpy(name, tempa, FILENAME_MAX-1);
return 0;
}
/*
* Parse the command line set the filename and the appropriate flags
*/
int pcl(int argc, char **argv, char *iname, char *oname)
{
static const char *options[] = {
"help print this message",
"file use a list of filenames",
"output use file instead of stdout",
"stdin use stdin as input",
"verbose print error messages",
NULL
};
static const char usage0[] = "usage: derefsymlink [options] [filename] ...",
usage1[] = " try derefsymlink -help for a list of options";
int i, optno, olen;
const char **sptr;
for (i = 1; i < argc; i++) {
olen = strlen(argv[i])-1;
if (argv[i][0] == '-') {
for (sptr = options, optno = 0; *sptr != NULL; sptr++, optno++)
if (strncmp(argv[i]+1, *sptr, olen) == 0) break;
switch(optno) {
case 0:
printf("%s\n", usage0);
printf("Options:\n");
for (sptr = options; *sptr != NULL; sptr++)
printf(" -%s\n", *sptr);
printf("\n");
exit(EXIT_SUCCESS);
break;
case 1:
in_method = IN_USE_FILE;
strcpy(iname, argv[++i]);
break;
case 2:
out_method = OUT_USE_FILE;
strcpy(oname, argv[++i]);
break;
case 3:
in_method = IN_USE_STDIN;
break;
case 4:
verbose = 1;
break;
default:
fprintf(stderr, "%s\n%s\n", usage0, usage1);
exit(EXIT_FAILURE);
break;
}
} else return i;
}
return i;
}
binstats-1.08.orig/derefsymlink.1 0100644 0001750 0000144 00000001531 07023010250 016017 0 ustar mvela users .TH DEREFSYMLINK 1 "October 31, 1999" "Debian Project" "Debian Manual"
.SH NAME
derefsymlink \- dereference symbolic links
.SH SYNOPSIS
.B derefsymlink
.RB [ -f [ ile ]\c
.I input-file
|
.RB -s [ tdin ]
.RB [ -o [ utput ]\c
.IR output-file ]
.RB [ -v [ erbose ]]
.RI [ symbolic-link ...]
.PP
.B derefsymlink
.BR -h [ elp ]
.SH OPTIONS
.TP
.BI -file " input-file"
Dereference whitespace delimited symbolic links read from
.IR input-file .
.TP
.B -help
Display a usage summary and exit.
.TP
.BI -output " output-file"
Output resulting filenames to
.I output-file
instead of standard output.
.TP
.B -stdin
Dereference whitespace delimited symbolic links read from standard input.
.TP
.B -verbose
Display verbose error messages.
.SH AUTHOR
Peter Chang .
.BR
This manual page was originally written by Matej Vela .
binstats-1.08.orig/binstats.lsm 0100644 0001750 0000144 00000002330 07231561177 015627 0 ustar mvela users Begin4
Title: binstats
Version: 1.08
Entered-date: 2001-01-18
Description: An admin utility to aid the tidying up of binaries,
interpreted scripts, dynamic libraries and man pages. It can
find the number and identity of a.out, ELF & ECOFF binaries,
plus their debugging symbols status, setuid status and
dynamic library dependence. It can count the number of Java
bytecode programs. It can tally up the main types of scripts
and look for unidentified executable text files. Also it is
able to look for any duplicated executable and manual page
names, unused libraries, binaries with missing libraries and
statically linked binaries. Also includes a C program to
dereference symbolic links.
Keywords: aout elf binary dynamic library symbolic link
Author: Peter.Chang@nottingham.ac.uk (Peter Chang)
Maintained-by: Peter.Chang@nottingham.ac.uk (Peter Chang)
Primary-site: metalab.unc.edu /pub/Linux/utils/scripts
12k binstats-1.08.tar.gz
Alternate-site: http://www.nottingham.ac.uk/~etzpc/binstats.html
Original-site:
Platforms: Linux, bash script needs lots of unix (or GNU) tools,
the Linux (or Gnu libc) ldd and gcc (for compiling
derefsymlink)
Copying-policy: GPL
End
binstats-1.08.orig/binstats.1 0100644 0001750 0000144 00000003004 07023010224 015150 0 ustar mvela users .TH BINSTATS 1 "October 31, 1999" "Debian Project" "Debian Manual"
.SH NAME
binstats \- display statistics about programs and libraries
.SH SYNOPSIS
.B binstats
.RB [ -b [ inaries ]\c
.RI = bindirs ]
.RB [ -d [ ebug ]]
.RB [ -f [ ile ]\c
.RI = logfile ]
.RB [ -l [ ibraries ]\c
.RI = libdirs ]
.RB [ -m [ anuals ]\c
.RI = mandirs ]
.RB [ -p [ ath ]\c
.RI = path ]
.RB [ -t [ emp ]\c
.RI = tmpdir ]
.PP
.B binstats
.BR -h [ elp ]
.PP
.B binstats
.BR -v [ ersion ]
.SH OPTIONS
.TP
.BI -binaries " bindirs"
.I bindirs
is a quoted list of whitespace delimited directories where programs should
be searched for.
.TP
.B -debug
Store temporary files in the current directory and do not remove them when
finished.
.TP
.BI -file " logfile"
Output report to
.I logfile
instead of standard output.
.TP
.B -help
Display a usage summary and exit.
.TP
.BI -libraries " libdirs"
.I libdirs
is a quoted list of whitespace delimited directories where libraries should
be searched for.
.TP
.BI -manuals " mandirs"
.I mandirs
is a quoted list of whitespace delimited directories where manpages should
be searched for.
.TP
.BI -path " path"
Use the specified
.I path
instead of the value of the environment variable
.BR PATH .
.TP
.BI -temp " tmpdir"
Store temporary files in
.IR tmpdir
instead of the value of the environment variable
.BR TMPDIR ,
if defined, or
.IR /tmp .
.TP
.B -version
Output version information and exit.
.SH AUTHOR
Peter Chang .
.BR
This manual page was originally written by Matej Vela .
binstats-1.08.orig/binstats 0100755 0001750 0000144 00000057046 07231561052 015046 0 ustar mvela users #!/bin/bash
# -*- sh -*-
# binstats - a Linux utility to find the number and identity of i386 a.out
# 1.08 ELF and ECOFF binaries, plus their debugging symbols status,
# setuid status and dynamic library dependence. The number of shell,
# awk, perl, python & tcl scripts are counted. Also it looks for
# any duplicated executable name, unused libraries, binaries with
# missing libraries and statically linked binaries. Finally it
# counts man pages and looks for duplicated names.
# version number of binstats
BSVER="1.08"
# Make sure 1) the PATH, EXEDIR, DLIBDIR & MANDIR variables are correct.
# If you want to use the current PATH for the executables search
# then set USEPATH to 1. If you want to use /etc/ld.so.conf for
# dynamic library search then set USELDSOCONF to 1.
# Alternatively you can set these via the command line.
# 2) there is enough room in TMPDIR (<300k);
# 3) that the C program 'derefsymlink' has been built and
# installed in /usr/local/bin (or where PATH points to)
# if USECDS is set to 1.
# Then run it (if you are not root then any executable without world
# readable status [especially setuid binaries] will register in the
# tallies or log as "can't read setuid"). After a while, a summary will
# appear on screen and a log of more information is recorded in BSLOG
# (bstats.log).
# Copyright (c) 1996, 1997, 1999 & 2000 by (Peter.Chang@nottingham.ac.uk)
# Inspired by "execount"
# written by Murple (murple@clark.net)
# Version History:
# 0.5 - Created on 1996/7/19
# 0.7 - Modified output format on 1996/7/23
# 0.9 - Added unused dynamic library hunt, logging to file
# and duplicate executable search on 1996/7/25
# 0.91 - TMPDIR introduced and added search for binaries
# with missing libraries on 1996/7/26
# 0.92 - Derefenced symbolic links that ldd (1.7.14) gives
# which confused the list of unused libraries on 1996/8/9
# 0.93 - Put in un-stripped binaries counting (relies on ELF patch to
# file), make sure we only count executables and include NMAGIC
# type on 1996/8/12
# 0.94 - Improved the symbolic link dereferencing to cope with some
# types of relative links on 1996/8/20
# 0.95 - Wrote a C program to do dereferencing, added setuid counting
# and beautified output on 1996/8/23
# 0.96 - (Thanks to Preston.F.Crow@Dartmouth.EDU for his feedback and
# suggestions.) Stopped "find" recursing down directories in
# EXEDIR, fixed ldd inconsistency, added support for using PATH
# and script counting on 1996/9/3
# 0.97 - Added automatic dynamic library directories detection using the
# contents of /etc/ld.so.conf on 1996/9/9
# 0.98 - Tightened search for dynamic libraries, used derefsymlink for
# libraries, checked for derefsymlink and
# generalized grep for [sS]hell on 1997/3/28
# 0.99 - Added Java bytecode detection (need magic support) on 1997/3/29
# 1.00 - Added command line interface on 1997/4/1
# 1.01 - Fixed for new version of ldd (1.9.1+), courtesy of
# Markus Rex ,
# on 1997/9/23
# 1.02 - (Thanks to Matej Vela for passing on the
# following fixes.) Fixed shared library filename patterns (from
# Laurent Bonnaud ), added use of
# environment variable TMPDIR and added -follow to find binaries
# that are symlinked on 1999/11/11
# 1.03 - Removed shell function deref_symlink and fullpath. Added
# OMAGIC, ECOFF support and man page checking (the latter
# item was suggested in a Debian bug report by Adam P. Harris
# ) on 1999/11/12
# 1.04 - The man page code didn't cope with the double colons in many
# perl man pages. It is now fixed thanks to Matej Vela
# on 1999/11/15
# 1.05 - Included count of awk scripts as noticed by Arnaud
# Launay on 1999/11/30
# 1.06 - Included fixes and counts of python and tcl scripts from Osamu Aoki
# , generalized some matches and tweaked
# on 2000/6/13
# 1.07 - Yet another attempt to fix the vagaries of shell and subshell
# expansions on 2000/6/14
# 1.08 - Included some more fixes to the scripts counting as pointed out by
# Osamu Aoki , added some more directories
# to defaults and made binstat immune to "symlinks in tmp" attacks
# from patches by Matej Vela on 2001/1/16
# save old path
OLDPATH=$PATH
#---------Customise the variables below or use the command line----------
# to use your PATH for a list of binary directories instead of setting
# EXEDIR separately, set to 1 [beware of having . in your PATH if you only
# want to see "official" binaries.]
# otherwise set to 0 and edit EXEDIR
USEPATH=1
# the list of directories where your executables reside (change to suit
# your system or ignore if USEPATH=1)
EXEDIR="/bin /usr/bin /usr/local/bin /sbin /usr/sbin /usr/local/sbin /usr/X11R6/bin /usr/games"
# the list of directories where your man pages reside
MANDIR="/usr/man /usr/share/man /usr/X11R6/man /usr/local/man"
# to use /etc/ld.so.conf to fill in DLIBDIR, set to 1
USELDSOCONF=1
# otherwise set to 0 and edit DLIBDIR
# the list of dynamic library directories (change to suit your system
# or ignore if USELDSOCONF=1)
DLIBDIR="/lib /usr/lib /usr/local/lib /usr/X11R6/lib"
# the path needed by binstats
# for echo, sed, tr, cat, xargs, cut, dirname, find, sort, awk, uniq, grep,
# file, ldd, col, diff, wc, uname, date, col & derefsymlink (assumed to be
# in /usr/local/bin)
PATH=/bin:/usr/bin:/usr/local/bin
#---------nothing further to edit below (unless you're hacking)----------
# name of log file
BSLOG=bstats.log
# temporary storage directory, use environment variable if defined
TMPDIR=${TMPDIR-/tmp}
# ldd has at least one bug (in 1.7.14) and one inconsistency (or feature) which
# have to be worked around, see comments in code below for more details
LDDBA=0 # garbage output
LDDBB=0 # executable name missing for single name
# when these are fixed or changed then the following variables to 1
# debugging option, set to 1 to retain files
DEBUG=0
# another debugging option, set to 0 to reuse old temp files
FILEOPS=1
#----------process command line arguments---------------
CLI_USAGE=\
"Usage: ./binstats [-b[inaries]=\"/bin /usr/bin\"] [-d[ebug]]
[-f[ile]=bstats.log] [-h[elp]]
[-l[ibraries]=\"/lib /usr/lib\"]
[-m[anuals]=\"/usr/man /usr/local/man\"]
[-p[ath]=\"/bin:/usr/bin:/usr/local/bin\"]
[-t[emp]=/tmp] [-v[ersion]]"
for CLI_OPT
do
case "$CLI_OPT" in
-*=*) CLI_ARG=`echo "$CLI_OPT" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
*) CLI_ARG= ;;
esac
case "$CLI_OPT" in
-b*=*) USEPATH=0
EXEDIR="$CLI_ARG" ;;
-d*) DEBUG=1 ;;
-f*=*) BSLOG="$CLI_ARG" ;;
-h*) echo "$CLI_USAGE"
exit 0 ;;
-l*=*) USELDSOCONF=0
DLIBDIR="$CLI_ARG" ;;
-m*=*) MANDIR="$CLI_ARG" ;;
-p*=*) PATH="$CLI_ARG" ;;
-t*=*) TMPDIR="$CLI_ARG" ;;
-v*) echo "binstats-$BSVER"
exit 0 ;;
*) echo "$CLI_USAGE"
exit 1 ;;
esac
done
#----------define variables and functions---------------
if [ $USEPATH -eq 1 ]; then
# use old PATH (not sure if the substitution is needed)
EXEDIR=`echo $OLDPATH | tr : ' ' | sed s:\~:$HOME:g`
fi
if [ $USELDSOCONF -eq 1 ]; then
# use /etc/ld.so.conf plus the two "trusted" locations
LDSOCONF=`cat /etc/ld.so.conf | grep -v '^#' | xargs echo`
DLIBDIR="/lib /usr/lib $LDSOCONF"
fi
# ID number
PIDNO=$$
# name of temp log
BSLOGTMP=$BSLOG.$PIDNO
if [ $DEBUG -gt 0 ]; then
TMPDIR=.
PIDNO=00
else
TMPDIR=$TMPDIR/binstats.$PIDNO
mkdir -m 700 $TMPDIR || exit 1
fi
# list of executables
EXELIST=$TMPDIR/exelist.$PIDNO
# list of dynamic libraries
DLIBLIST=$TMPDIR/dliblist.$PIDNO
# list of man pages
MANLIST=$TMPDIR/manlist.$PIDNO
# executable types
EXEFILE=$TMPDIR/exefile.$PIDNO
# list of dependent (used) libraries
EXELIB=$TMPDIR/exelib.$PIDNO
# list of unused libraries
DLIBUN=$TMPDIR/dlibun.$PIDNO
# temporary storage
DTEMPA=$TMPDIR/dtempa.$PIDNO # all dynamic libs in $DLIBDIR
DTEMPB=$TMPDIR/dtempb.$PIDNO # missing dynamic libs in $EXELIB
DTEMPC=$TMPDIR/dtempc.$PIDNO # dereferenced list of $DTEMPA
ETEMPA=$TMPDIR/etempa.$PIDNO # all files in $EXEDIR
ETEMPB=$TMPDIR/etempb.$PIDNO # output of ldd on files in $EXEFILE
ETEMPC=$TMPDIR/etempc.$PIDNO # statically linked binaries in $ETEMPB
ETEMPD=$TMPDIR/etempd.$PIDNO # duplicate executable names in $ETEMPA
ETEMPE=$TMPDIR/etempe.$PIDNO # 'not stripped' binaries in $EXEFILE
ETEMPF=$TMPDIR/etempf.$PIDNO # setuid binaries in $EXEFILE
MTEMPA=$TMPDIR/mtempa.$PIDNO # all files in $MANDIR
MTEMPB=$TMPDIR/mtempb.$PIDNO # duplicate executable names in $MTEMPA
#----------begin program---------------
if [ $FILEOPS -gt 0 ]; then
echo "Look in $EXEDIR for executables"
find $EXEDIR -perm +111 -maxdepth 1 -type f -follow -print | \
derefsymlink -s | sort | uniq | \
awk -F '/' '{ printf "%s:%s\n", $NF, $0 }' > $ETEMPA
echo "Find duplicated executable names"
# use an awk script instead of whereis later (as suggested by Preston Crow)
# R=repetition, N=name, P=path
sort -t ':' $ETEMPA | awk -F ':' \
'BEGIN { R=0;N="";P="" }
{
if ($1==N) { printf("%s ",P); R=1 }
else { if (R==1) { printf("%s\n",P); R=0 } };
N=$1; P=$2
}
END { if (R==1) {printf("%s\n",P)} }' \
> $ETEMPD
echo "Sort out list by alphabetical order"
sort -t ':' $ETEMPA | cut -d ':' -f 2- > $EXELIST
echo "Find executable type (this will take a long time)"
cat $EXELIST | xargs file > $EXEFILE
echo "Look for dynamic library dependence (this will take an even longer time)"
# hmm, ldd (1.7.14) seems to output some unprintable character when it
# encounters a static a.out image
# And ldd (1.9.2) prints some hex numbers after library name in parentheses
if [ $LDDBA -eq 0 ]; then
grep 'executable' $EXEFILE | cut -d ':' -f 1 | \
xargs ldd | col -b | cut -d '(' -f 1 >& $ETEMPB
else
grep 'executable' $EXEFILE | cut -d ':' -f 1 | \
xargs ldd | awk cut -d '(' -f 1 >& $ETEMPB
fi
echo "List the used dynamic libraries"
grep 'lib[^:]*\.so' $ETEMPB | sort -b | uniq -c > $EXELIB
grep 'statically linked' $ETEMPB > $ETEMPC
echo "Hunt down binaries that depend on missing libraries"
awk \
'/^\// { CURPROG = $0; NEW = 1 }
/not found/ { if (NEW == 1) print CURPROG; NEW = 0 }' \
$ETEMPB > $DTEMPB
echo "Look in $DLIBDIR for dynamic libraries"
find $DLIBDIR -maxdepth 1 -type f -name 'lib*.so*' | \
derefsymlink -s | sort | uniq > $DLIBLIST
echo "Search for unused dynamic libraries"
grep -v 'not found' $EXELIB | cut -d '/' -f 2- | cut -d ' ' -f 1 | \
sort | uniq | sed 's,^,/,g' > $DTEMPA
derefsymlink -f $DTEMPA | sort | uniq > $DTEMPC
diff -du $DLIBLIST $DTEMPC | grep '^-/' | cut -b 2- > $DLIBUN
echo "Find un-stripped binaries"
grep 'not stripped' $EXEFILE | sort > $ETEMPE
echo "Find setuid binaries"
grep 'setuid' $EXEFILE | sort > $ETEMPF
fi
echo "Look in $MANDIR for man pages"
find $MANDIR -maxdepth 2 -type f -follow -name '*.*' -print | \
derefsymlink -s | sort | uniq | \
awk -F '/' '{ printf "%s;%s\n", $NF, $0 }' > $MTEMPA
echo "Find duplicated man page names"
sort -t ';' $MTEMPA | awk -F ';' \
'BEGIN { R=0;N="";P="" }
{
if ($1==N) { printf("%s ",P); R=1 }
else { if (R==1) { printf("%s\n",P); R=0 } };
N=$1; P=$2
}
END { if (R==1) {printf("%s\n",P)} }' \
> $MTEMPB
# finish messing around with files and lists of files
# now work out some numbers
echo "Gather statistics"
AOUTC=`grep 'Linux/i386.*executable' $EXEFILE | wc -l`
OMAGIC=`grep 'OMAGIC' $EXEFILE | wc -l`
NMAGIC=`grep 'NMAGIC' $EXEFILE | wc -l`
QMAGIC=`grep 'QMAGIC' $EXEFILE | wc -l`
ZMAGIC=`grep 'ZMAGIC' $EXEFILE | wc -l`
ELFC=`grep 'ELF.*executable' $EXEFILE | wc -l`
ECOFFC=`grep 'ECOFF.*executable' $EXEFILE | wc -l`
JAVAC=`grep 'Java bytecode' $EXEFILE | wc -l`
LIBC=`cat $EXELIB | wc -l`
UNLIBC=`cat $DLIBUN | wc -l`
DLLIBC=`grep 'DLL' $EXELIB | wc -l`
SELFC=`grep 'ELF' $ETEMPC | wc -l`
SECOFFC=`grep 'ECOFF' $ETEMPC | wc -l`
#SAOUTC=`grep -v 'ELF' $ETEMPC | wc -l`
SAOUTC=`grep 'Linux/i386' $ETEMPC | wc -l`
DUPC=`cat $ETEMPD | wc -l`
MISSC=`cat $DTEMPB | wc -l`
ELFUNSTR=`grep 'ELF.*executable' $ETEMPE | wc -l`
ECOFFUNSTR=`grep 'ECOFF.*executable' $ETEMPE | wc -l`
AOUTUNSTR=`grep 'Linux/i386.*executable' $ETEMPE | wc -l`
ELFSETUID=`grep 'ELF.*executable' $ETEMPF | wc -l`
ECOFFSETUID=`grep 'ECOFF.*executable' $ETEMPF | wc -l`
AOUTSETUID=`grep 'Linux/i386.*executable' $ETEMPF | wc -l`
UNSETUID=`grep "can\'t" $ETEMPF | wc -l`
TEXTC=`grep ':.* text' $EXEFILE | wc -l`
ALLSCRIPTC=`grep -e ':.* script' -e ':.* commands' $EXEFILE | wc -l`
SHC=`grep 'Bourne [sS]hell' $EXEFILE | wc -l`
BASHC=`grep 'Bourne-Again' $EXEFILE | wc -l`
CSHC=`grep '[^x] C [sS]hell' $EXEFILE | wc -l`
TCSHC=`grep 'Tenex C' $EXEFILE | wc -l`
AWKC=`grep ':.*awk' $EXEFILE | wc -l`
PERLC=`grep ':.*perl' $EXEFILE | wc -l`
PYTHONC=`grep ':.*python' $EXEFILE | wc -l`
TCLC=`grep -e ':.*tcl' -e ':.*wish ' $EXEFILE | wc -l`
OTHERC=$[($ALLSCRIPTC)-($SHC+$BASHC+$CSHC+$TCSHC+$AWKC+$PERLC+$PYTHONC+$TCLC)]
UNIDTC=$[($TEXTC-($ALLSCRIPTC))]
MANC=`cat $MTEMPA | wc -l`
MANDUPC=`cat $MTEMPB | wc -l`
MACHNAME=`uname -n`
DATESTAMP=`date +'%Y/%m/%d %T %Z'`
#----------log all info---------------
echo "binstats-$BSVER output from $MACHNAME on $DATESTAMP" > $BSLOGTMP
echo "" >> $BSLOGTMP
echo "Binaries: $[($AOUTC+$ELFC+$ECOFFC)]" >> $BSLOGTMP
echo " OMAGIC Demand Paged: $OMAGIC" >> $BSLOGTMP
echo " NMAGIC Demand Paged: $NMAGIC" >> $BSLOGTMP
echo " QMAGIC Demand Paged: $QMAGIC" >> $BSLOGTMP
echo " ZMAGIC Demand Paged: $ZMAGIC" >> $BSLOGTMP
echo " statically linked: $SAOUTC" >> $BSLOGTMP
echo " not stripped: $AOUTUNSTR" >> $BSLOGTMP
echo " setuid: $AOUTSETUID" >> $BSLOGTMP
echo " ELF: $ELFC" >> $BSLOGTMP
echo " statically linked: $SELFC" >> $BSLOGTMP
echo " not stripped: $ELFUNSTR" >> $BSLOGTMP
echo " setuid: $ELFSETUID" >> $BSLOGTMP
echo " ECOFF: $ECOFFC" >> $BSLOGTMP
echo " statically linked: $SECOFFC" >> $BSLOGTMP
echo " not stripped: $ECOFFUNSTR" >> $BSLOGTMP
echo " setuid: $ECOFFSETUID" >> $BSLOGTMP
echo " Java: $JAVAC" >> $BSLOGTMP
if [ $UNSETUID -gt 0 ]; then
echo " Can't read setuid: $UNSETUID" >> $BSLOGTMP
fi
echo " Duplicate names: $DUPC" >> $BSLOGTMP
echo " Missing libraries: $MISSC" >> $BSLOGTMP
echo "Text: $TEXTC" >> $BSLOGTMP
echo " Bourne shell: $SHC" >> $BSLOGTMP
echo " Bourne-Again shell: $BASHC" >> $BSLOGTMP
echo " C shell: $CSHC" >> $BSLOGTMP
echo " Tenex C shell: $TCSHC" >> $BSLOGTMP
echo " Awk: $AWKC" >> $BSLOGTMP
echo " Perl: $PERLC" >> $BSLOGTMP
echo " Python: $PYTHONC" >> $BSLOGTMP
echo " Tcl: $TCLC" >> $BSLOGTMP
if [ $OTHERC -gt 9 ]; then
echo " Other interpreted: $OTHERC" >> $BSLOGTMP
else
echo " Other interpreted: $OTHERC" >> $BSLOGTMP
fi
if [ $UNIDTC -gt 9 ]; then
echo " Unidentified: $UNIDTC" >> $BSLOGTMP
else
echo " Unidentified: $UNIDTC" >> $BSLOGTMP
fi
echo "Used libraries: $LIBC" >> $BSLOGTMP
echo " DLL: $DLLIBC" >> $BSLOGTMP
echo "Unused libs: $UNLIBC" >> $BSLOGTMP
echo "Man pages: $MANC" >> $BSLOGTMP
echo " Duplicate names: $MANDUPC" >> $BSLOGTMP
DOTLINE=0
echo "==============================================================" >> $BSLOGTMP
if [ $OMAGIC -gt 0 ]; then
DOTLINE=1
echo "OMAGIC binaries:" >> $BSLOGTMP
grep 'OMAGIC' $EXEFILE | cut -d ':' -f 1 | sort >> $BSLOGTMP
fi
if [ $NMAGIC -gt 0 ]; then
if [ $DOTLINE -gt 0 ]; then
echo "--------------------------------------------------------------" >> $BSLOGTMP
fi
DOTLINE=1
echo "NMAGIC binaries:" >> $BSLOGTMP
grep 'NMAGIC' $EXEFILE | cut -d ':' -f 1 | sort >> $BSLOGTMP
fi
if [ $QMAGIC -gt 0 ]; then
if [ $DOTLINE -gt 0 ]; then
echo "--------------------------------------------------------------" >> $BSLOGTMP
fi
DOTLINE=1
echo "QMAGIC binaries:" >> $BSLOGTMP
grep 'QMAGIC' $EXEFILE | cut -d ':' -f 1 | sort >> $BSLOGTMP
fi
if [ $ZMAGIC -gt 0 ]; then
if [ $DOTLINE -gt 0 ]; then
echo "--------------------------------------------------------------" >> $BSLOGTMP
fi
DOTLINE=1
echo "ZMAGIC binaries:" >> $BSLOGTMP
grep 'ZMAGIC' $EXEFILE | cut -d ':' -f 1 | sort >> $BSLOGTMP
fi
if [ $SAOUTC -gt 0 ]; then
if [ $DOTLINE -gt 0 ]; then
echo "--------------------------------------------------------------" >> $BSLOGTMP
fi
DOTLINE=1
echo "statically linked (a.out):" >> $BSLOGTMP
grep -B 1 'statically linked$' $ETEMPB | \
grep '^/' | cut -d ':' -f 1 >> $BSLOGTMP
fi
if [ $AOUTUNSTR -gt 0 ]; then
if [ $DOTLINE -gt 0 ]; then
echo "--------------------------------------------------------------" >> $BSLOGTMP
fi
DOTLINE=1
echo "not stripped (a.out):" >> $BSLOGTMP
grep 'Linux/i386.*executable' $ETEMPE | cut -d ':' -f 1 >> $BSLOGTMP
fi
if [ $AOUTSETUID -gt 0 ]; then
if [ $DOTLINE -gt 0 ]; then
echo "--------------------------------------------------------------" >> $BSLOGTMP
fi
DOTLINE=1
echo "setuid (a.out):" >> $BSLOGTMP
grep 'Linux/i386.*executable' $ETEMPF | cut -d ':' -f 1 >> $BSLOGTMP
fi
if [ $DOTLINE -gt 0 ]; then
echo "==============================================================" >> $BSLOGTMP
fi
DOTLINE=0
if [ $SELFC -gt 0 ]; then
echo "statically linked (ELF):" >> $BSLOGTMP
grep -B 1 'statically linked (ELF)' $ETEMPB | grep '^/' | \
cut -d ':' -f 1 >> $BSLOGTMP
DOTLINE=1
fi
if [ $ELFUNSTR -gt 0 ]; then
if [ $DOTLINE -gt 0 ]; then
echo "--------------------------------------------------------------" >> $BSLOGTMP
fi
DOTLINE=1
echo "not stripped (ELF):" >> $BSLOGTMP
grep 'ELF.*executable' $ETEMPE | cut -d ':' -f 1 >> $BSLOGTMP
fi
if [ $ELFSETUID -gt 0 ]; then
if [ $DOTLINE -gt 0 ]; then
echo "--------------------------------------------------------------" >> $BSLOGTMP
fi
DOTLINE=1
echo "setuid (ELF):" >> $BSLOGTMP
grep 'ELF.*executable' $ETEMPF | cut -d ':' -f 1 >> $BSLOGTMP
fi
if [ $DOTLINE -gt 0 ]; then
echo "==============================================================" >> $BSLOGTMP
fi
DOTLINE=0
if [ $SECOFFC -gt 0 ]; then
echo "statically linked (ECOFF):" >> $BSLOGTMP
grep -B 1 'statically linked (ECOFF)' $ETEMPB | grep '^/' | \
cut -d ':' -f 1 >> $BSLOGTMP
DOTLINE=1
fi
if [ $ECOFFUNSTR -gt 0 ]; then
if [ $DOTLINE -gt 0 ]; then
echo "--------------------------------------------------------------" >> $BSLOGTMP
fi
DOTLINE=1
echo "not stripped (ECOFF):" >> $BSLOGTMP
grep 'ECOFF.*executable' $ETEMPE | cut -d ':' -f 1 >> $BSLOGTMP
fi
if [ $ECOFFSETUID -gt 0 ]; then
if [ $DOTLINE -gt 0 ]; then
echo "--------------------------------------------------------------" >> $BSLOGTMP
fi
DOTLINE=1
echo "setuid (ECOFF):" >> $BSLOGTMP
grep 'ECOFF.*executable' $ETEMPF | cut -d ':' -f 1 >> $BSLOGTMP
fi
if [ $DOTLINE -gt 0 ]; then
echo "==============================================================" >> $BSLOGTMP
fi
if [ $UNSETUID -gt 0 ]; then
echo "can't read setuid:" >> $BSLOGTMP
grep "can\'t" $ETEMPF | cut -d ':' -f 1 >> $BSLOGTMP
echo "==============================================================" >> $BSLOGTMP
fi
if [ $DUPC -gt 0 ]; then
echo "duplicated executable names:" >> $BSLOGTMP
cat $ETEMPD >> $BSLOGTMP
echo "==============================================================" >> $BSLOGTMP
fi
if [ $MISSC -gt 0 ]; then
echo "binaries with missing libraries:" >> $BSLOGTMP
# work around ldd inconsistency (1.7.14)
if [ $LDDBB -eq 0 ]; then
if [ $MISSC -eq 1 ]; then
cat $DTEMPB >> $BSLOGTMP
fi
fi
cut -d ':' -f 1 $DTEMPB | xargs ldd | cut -d '(' -f 1 >> $BSLOGTMP
echo "==============================================================" >> $BSLOGTMP
fi
if [ $OTHERC -gt 0 ]; then
echo "other interpreted files:" >> $BSLOGTMP
grep -e ':.* script' -e ':.* commands' $EXEFILE | \
grep -v 'Bourne [sS]hell' | \
grep -v 'Bourne-Again' | \
grep -v '[^x] C [sS]hell' | \
grep -v 'Tenex C' | \
grep -v ':.*awk' | \
grep -v ':.*perl' | \
grep -v ':.*python' | \
grep -v -e ':.*tcl' -e ':.*wish ' >> $BSLOGTMP
echo "==============================================================" >> $BSLOGTMP
fi
if [ $UNIDTC -gt 0 ]; then
echo "unidentified text files:" >> $BSLOGTMP
grep ':.* text' $EXEFILE | grep -v ':.* script' | grep -v ':.*perl' | \
cut -d ':' -f 1 | sort >> $BSLOGTMP
echo "==============================================================" >> $BSLOGTMP
fi
echo " usage count | dynamic library" >> $BSLOGTMP
echo "--------------------------------------------------------------" >> $BSLOGTMP
if [ $DLLIBC -gt 0 ]; then
echo "DLL:" >> $BSLOGTMP
grep 'DLL' $EXELIB >> $BSLOGTMP
echo "--------------------------------------------------------------" >> $BSLOGTMP
fi
echo "ELF:" >> $BSLOGTMP
grep -v 'DLL' $EXELIB >> $BSLOGTMP
if [ $UNLIBC -gt 0 ]; then
echo "--------------------------------------------------------------" >> $BSLOGTMP
echo "unused:" >> $BSLOGTMP
cat $DLIBUN >> $BSLOGTMP
fi
echo "==============================================================" >> $BSLOGTMP
if [ $MANDUPC -gt 0 ]; then
echo "duplicated man page names:" >> $BSLOGTMP
cat $MTEMPB >> $BSLOGTMP
echo "==============================================================" >> $BSLOGTMP
fi
# backup old log file
if [ -f $BSLOG ]; then mv -f $BSLOG $BSLOG~; fi
# filter through sed to beautify (note the embedded TAB)
sed -e 's,^/\(.*[^:]\)$, /\1,g' $BSLOGTMP > $BSLOG
rm -f $BSLOGTMP
# begin on-screen summary
echo ""
echo ""
echo "binstats-$BSVER output from $MACHNAME on $DATESTAMP"
echo ""
echo "Binaries: $[($AOUTC+$ELFC+$ECOFFC)]"
echo " OMAGIC Demand Paged: $OMAGIC"
echo " NMAGIC Demand Paged: $NMAGIC"
echo " QMAGIC Demand Paged: $QMAGIC"
echo " ZMAGIC Demand Paged: $ZMAGIC"
echo " statically linked: $SAOUTC"
echo " not stripped: $AOUTUNSTR"
echo " setuid: $AOUTSETUID"
echo " ELF: $ELFC"
echo " statically linked: $SELFC"
echo " not stripped: $ELFUNSTR"
echo " setuid: $ELFSETUID"
echo " ECOFF: $ECOFFC"
echo " statically linked: $SECOFFC"
echo " not stripped: $ECOFFUNSTR"
echo " setuid: $ECOFFSETUID"
echo " Java: $JAVAC"
if [ $UNSETUID -gt 0 ]; then
echo " Can't read setuid: $UNSETUID"
fi
echo " Duplicate names: $DUPC"
echo " Missing libraries: $MISSC"
echo "Text: $TEXTC"
echo " Bourne shell: $SHC"
echo " Bourne-Again shell: $BASHC"
echo " C shell: $CSHC"
echo " Tenex C shell: $TCSHC"
echo " Awk: $AWKC"
echo " Perl: $PERLC"
echo " Python: $PYTHONC"
echo " Tcl: $TCLC"
if [ $OTHERC -gt 9 ]; then
echo " Other interpreted: $OTHERC"
else
echo " Other interpreted: $OTHERC"
fi
if [ $UNIDTC -gt 9 ]; then
echo " Unidentified: $UNIDTC"
else
echo " Unidentified: $UNIDTC"
fi
echo "Used libraries: $LIBC"
echo " DLL: $DLLIBC"
echo "Unused libs: $UNLIBC"
echo "Man pages: $MANC"
echo " Duplicate names: $MANDUPC"
# tidy up
if [ $DEBUG -eq 0 ]; then
rm -rf $TMPDIR
fi
echo "=============================================================="
echo "More detailed information can be obtained in $BSLOG"
# end of script