#!/bin/bash ## ## create configuration documentation for a server ## (c) Koen Noens ## ChangeLog: ## October 2008 added some additional statements, ## inspired by supportconfig - Jason Record ## (jrecord@novell.com), (c) Novell, Inc ## May 2008 version 0.1 ## ## http://users.telenet.be/mydotcom/howto/linux/autoinventory.htm ## http://users.telenet.be/mydotcom/howto/linux/automatic.htm ## ########################################################################## # 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 # # the Free Software Foundation; version 2 of the License # ########################################################################## ### Prerequisites ## Part of this script depends on the presense of /etc/timestamp ## Ideally, this file is created after the initial OS setup, so ## that changes to the default configuration get documented ### To DO ## create a package ## depends:dpkg,debconf-utils ## postinst: create /etc/timestamp ## create a cron job (daily?) ## create $SAVEASDIR ## ## rewrite this script so it can ## - use commandline options ## - read params from a config file ## ## possible options : ## - 'raw' or 'verbose' : generate unfiltered, raw output ## ## provide a mechanism to preserve history ## ## provide a mechanism to differentiate between static info (eg hardware) ## and info that might change over time (config, software) ## ## maybe create separate scripts for each operation so they can be ## called separately, and use this script as a container to call them all ## ## create restore procedure or proof-of-concept ### Params and Options ## general script options ## VERBOSE="y" CREATEINDEX="y" SAVEDIR="/var/log/sysdoc" #SAVEDIR=${SAVEDIR}_$(date +%Y%m%d) date-stamped output dir for history THIS="$0" THISDIR=$(dirname $THIS) ## output naming conventions: # lst_something : describes "something", eg lst_hardware_disks # cp_filename : copy of 'filename' - in subdir 'files' ## general logging options ## SAVE_INSTALLER_LOG="yes" ALWAYSCOLLECT=" /etc/passwd \ /etc/shadow \ /etc/group \ /etc/sudoers \ /etc/fstab \ /etc/inittab \ /etc/grub.conf \ /boot/grub/menu.lst \ /boot/grub/device.map \ " #don't remove this quote! ## Fileserver documentation ## DIRDEPTH=2 # how deep do we want to recurse for fileserver info (eg ACL's) ### Reality Check [ -d $SAVEDIR ] || mkdir -p $SAVEDIR [ -d $SAVEDIR/files ] || mkdir -p $SAVEDIR/files ### Functions ### Main ## system identity and general environment ## misc. system info OUTPUT=$SAVEDIR/lst_systeminfo ( hostname -f || hostname uname -a if [ -d /var/log/installer ]; then echo -n "installation date (installer log most recent inode change): " stat -c%z /var/log/installer/status echo -n "installation date installer log most recent modify/write): " stat -c%y /var/log/installer/status echo; cat /var/log/installer/lsb-release fi ) > $OUTPUT hostname >$SAVEDIR/host.name #for index ## network OUTPUT2="$OUTPUT-network" ( echo;echo NETWORK grep eth /etc/network/interfaces ;echo; route -n ; echo; INTERFACES=$(ifconfig |grep -o eth. ) for IF in $INTERFACES; do ifconfig $IF; echo; ethtool $IF; echo; echo ; done ) > $OUTPUT2 ## disks and partitions OUTPUT2="$OUTPUT-disks" ( echo "FSTAB" grep -v ^[\#\;] /etc/fstab ; echo;echo; mount; echo;echo; echo "DISKS" fdisk -l ; echo;echo; echo "PARTITIONS" cat /proc/partitions ; echo;echo; echo "LVM" which lvm && (for CMD in vgs lvs pvs ; do $CMD echo; done ) || echo "nothing to report" echo;echo; echo "RAID (mdadm - Linux Software Raid)" if [ -d /proc/mdstat ] ; then ## TODO : ## read devices from /proc/mdstat and ## for device in list ; do mdadm --query device ; done ## or something with mdadm --export or mdadm --export --detail true #placeholder else echo "nothing to report" fi echo;echo; )>$OUTPUT2 ## hardware OUTPUT2="$OUTPUT-hardware" ( echo "CPU" cat /proc/cpuinfo && echo echo "MEMORY" cat /proc/meminfo |grep "MemTotal" cat /proc/meminfo |grep "SwapTotal" echo echo "PCI DEVICES" lspci && echo ) > $OUTPUT2 OUTPUT2="$OUTPUT-hardware-modules" ( for MODULE in $(cat /proc/modules | cut -d' ' -f1 -); do mod_descr=$(modinfo -F description $MODULE ) echo "$MODULE $mod_descr" done ) > $OUTPUT2 OUTPUT2="$OUTPUT-hardware-installerlog" if [ -d /var/log/installer ]; then cp /var/log/installer/hardware_summary $OUTPUT2 ## keep a copy of the installer logs ? if [ "$SAVE_INSTALLER_LOG" = "yes" ] ; then [ -d $SAVEDIR/installer.log ] || \ mkdir -p $SAVEDIR/installer.log cp -r /var/log/installer/* $SAVEDIR/installer.log/ || true fi fi ## draft preseed content for this system OUTPUT="$SAVEDIR/preseed_draft" if which debconf-get-selections ; then ( echo "## created by autodoc - $HOSTNAME - $(date)" echo "### use this file to create a preseed file" debconf-get-selections ) > $OUTPUT OUTPUT="$OUTPUT-installer" ( echo "## created by autodoc - $HOSTNAME - $(date)" echo "### use this file to create a preseed file" debconf-get-selections --installer ) > $OUTPUT fi ## list installed software # -libs are excluded, they'll be pulled in as dependency anyway OUTPUT="$SAVEDIR/lst_packages" dpkg --get-selections | cut -f1 - | grep -v ^lib > $OUTPUT OUTPUT="$OUTPUT-full" dpkg -l > $OUTPUT ## task selection # -probably redundant, we can use dpkg selections in stead. OUTPUT="$SAVEDIR/lst_tasks" tasksel --list-tasks | grep ^i > $OUTPUT ## services OUTPUT="$SAVEDIR/lst_services" ( echo "runlevel: $(runlevel)" echo; echo "services (startup scripts) for this runlevel : " RUNLVL=$(runlevel | grep -o [0-9]) ls -1 /etc/rc$RUNLVL.d echo; echo " status of services" echo "if daemon doesn't support 'status' option, we check process ID's" echo "doesn't work for processes where daemon name != script name"; echo ls -1 /etc/rc$RUNLVL.d | while read F; do SERVICE=${F:3}; echo "Status of $SERVICE"; /etc/init.d/$SERVICE status || (ps -e | grep $SERVICE) || echo "not found"; echo ; done )> $OUTPUT ## list user accounts and group membership #-- assume extra users get UID gt or eq 1000 OUTPUT="$SAVEDIR/lst_users_groups" grep "x:[0-9]\{4\}" /etc/passwd | cut -d: -f1 - |while read USER; do groups $USER done > $OUTPUT #-- likewise, list system user accounts OUTPUT="$SAVEDIR/lst_users_groups_systemaccounts" cat /etc/passwd | cut -d: -f3 - | while read ID; do [ $ID -lt 1000 ] && groups $(grep :$ID: /etc/passwd |cut -d: -f1 - ); done > $OUTPUT ## collect changes to default file permissions #--- tricky. #--- assume that changes to inode data are most likely permission changes #-- but inode data will also change with the creation of hardlinks, a.o. #-- comparison is to _status_ of /etc/timestamp, assuming that will never change ## if we run this at regular intervals, we can use use these intervals with find ## -cnewer _file_ also finds files created after so we get too much data ## CAVEAT: don't overwrite the output file, always append to it ## we sort it with most recent changes on top OUTPUT="$SAVEDIR/lst_files_modified" find -cnewer /etc/timestamp | grep -v ^\/home | while read FILENAME; do stat -c %z\ %a\ %U:%G\ %n $FILENAME; echo ""; done >> $OUTPUT sort -iru -o $OUTPUT $OUTPUT ## if we're doing posix acl, we'll want to document it OUTPUT=$SAVEDIR/lst_filesystem_acl ( echo "filesystems with posix acl:" FSACL=$(grep acl /etc/fstab | awk '{print $2}') echo $FSACL ## directories and subdirectories (re DIRDEPTH) and their ACL echo "ACL for filesystems / top level directory" for ITM in $FSACL; do echo $ITM getfacl $ITM ; done echo "ACL for main subdirectories" for ITM in $FSACL; do find $ITM -type d -maxdepth $DIRDEPTH |while read D ; do getfacl $D ; done done ) >$OUTPUT ( echo "automatic system configuration documentation"; echo;echo; echo "this system configuration documentation is based on the assumption that we know the distribution's defaults, and document the changes by collecting config files that have been changed. The file /etc/timestamp serves as time reference : we collect config files modified after the creation of /etc.timestamp. This enables us to document _any_ service configuration, modification, cusy-tomization, ... without having to explicitly list all possible services and their config files or status commands" echo;echo; echo "if /etc/timestamp doesn't exist, we need to explicitely enumerate all files that might be interesting. See Novell's supportconfig for examples" echo;echo echo "this script creates/updates /etc/timestamp. If this script is run immediatly after the initial system setup, all customization will be documented. Every additional run of this script will collect changes made since the previous run. By modifying the output directory, you can create a change history of the system" )>$SAVEDIR/A_lst_config_README ## detect and document changes to the default config files ## outputfile here is based on original filename find /etc -type f -newer /etc/timestamp | while read FILE; do echo $FILE > $SAVEDIR/lst_modified-config-files grep -v ^[\#\;] $FILE | grep [a-z] > $SAVEDIR/files/cp_$(basename $FILE) done ## one time readout of interesting config files that may have been created ## before 'timestamp' and don't get updated for FILE in $ALWAYSCOLLECT ; do grep -v ^[\#\;] $FILE | grep [a-z] > $SAVEDIR/files/cp_$(basename $FILE) done ## update the timestamp so the next run only processes recent changes ##touch /etc/timestamp ## optionally create an html index page # FIXME ## needs work to pass correct directory if directory name has date in it ## [[ "$CREATEINDEX" = "y" ]] && sysdoc.index