#!/bin/ash # #POSIXness v0.20 19990529 #GPL2 -- Dave 'Kill a Cop' Cinege # #Uses the fullest extent of ash, sed, and custom busybox functions #to provide many of the linux goodies that will not fit on boot #floppies. Helps give you that 'real machine' feel... # #Some of the sed code is stolen from various FAQ's, etc # #Some of these functions are LRP oddites, you probably can't use. # This script is dedicated to Phil Hands and Paul Russell # I hope to amaze and inspire people with the power of the bourne # shell the same way you guys did for me when I was just a lowly # scumbag neophyte begging for a clue. # Much thanks for your continuing help with LRP. OIFS=$IFS TAB=' ' SP=' ' CR=`echo -e -n "\r"` LF=' ' MASTCONF="/etc/lrp.conf" [ -f $MASTCONF ] && . $MASTCONF #FIX ME: very wasteful and error prone qt () { "$@" >/dev/null 2>&1 ; } source () { . $@; } basename () { #usr/bin local IFS='/' set -- $1 eval rc="\$$#" [ "$rc" = "" ] && eval rc="\$$(($# - 1))" echo "$rc" } dirname () { #usr/bin echo "$1" | sed '/^\/$/c\ / s/\/*$// s/[^/]*$// /./!c\ . s/\/$//' } free () { #usr/bin cat /proc/meminfo } grep () { #bin local pat pat="$1" shift sed "\'$pat'P" -n "$@" } cut () { #usr/bin #default tab delim=' ' while getopts b:c:d:f:s opt ; do case "$opt" in b|c) byte="$OPTARG" ;; d) delim="$OPTARG" ;; f) field="$OPTARG" ;; s) delimonly=1 ;; esac done #space not working! if [ "$delim" = "\s" ]; then delim=' ' #space -- IFS prevents specing a space fi # shift $(($OPTIND - 1)) if [ "$1" = "" ] || [ "$1" = "-" ]; then file='' else file=$1 fi if [ $byte ]; then #sed 's/./\1/1' $file eecho "byte and char not working yet" exit fi local IFS=' ' if [ $delimonly ]; then field=$(($field - 1)) fi if [ "$field" = 0 ]; then exit 0 fi for line in `cat $file`; do local IFS=$delim set -- $line if [ $delimonly ]; then shift eval necho $"$field" else [ $# -eq 1 ] && field=1 eval echo $"$field" fi done } head () { #usr/bin local num=10 if [ "$1" = "-n" ]; then num=$2 shift 2 fi sed "$num"q "$@" } tail () { #usr/bin local num=10 if [ "$1" = "-n" ]; then num=$2 shift 2 fi num=$(($num + 1)) sed -e :a -e '$q;N;'$num',$D;ba' "$@" } nl () { #usr/bin if [ "$1" = "-b" ]; then if [ "$2" = "a" ]; then sed = $3 | sed 'N; s/^/ /; s/ *\(.\{6,\}\)\n/\1 /' fi shift 2 else sed '/^$/b;=' $1 | sed '/./N; s/^/ /; s/ *\(.\{6,\}\)\n/\1 /' fi } uniq () { #usr/bin sed '$!N; /^\(.*\)\n\1$/!P; D' "$@" } sort () { #usr/bin echo 'sort: fix me!' } zgrep () { #usr/bin singlefilearg "$2" zcat "$2" | grep "$1" - } zmore () { #usr/bin singlefilearg "$1" zcat "$1" | more } reset () { #usr/bin echo 'c' stty sane } mail () { #usr/sbin usage () { cat <<- EOF Usage: $(basename) options to[,...] Options: [-s subject] [-c cc[,...]] [-b bcc[,...]] [-a attachment[,...]] [-d domain] [-h smtpserver] Mail settings are in /etc/lrp.conf -a attach text file(s) -d specify from FQDN, overriding lrp_MAIL_DOMAIN or local domain -h specify SMTP server, overriding the lrp_MAIL_SERVER setting EOF } rfcdate () { local IFS=" " set -- `date -R` case "$#" in 6) echo "$@" ;; 1) set -- `date` [ "$#" -eq 5 ] && echo "$1, $3 $2 $5 $4 +0000" ;; *) ;; esac } attach () { if [ -f "$1" ] ; then name=`echo $1 | sed 's/.*\///'` cat <<- EOF --$ContentBoundry Content-Type: application/octet-stream; name="$name" Content-Disposition: attatchment; filename="$name" EOF cat "$1" | sed 's/^\./\.\./' fi } abort () { eecho "Aborting due to $1" eecho " Killing child processes: $pidctrl $pidmnc" qt kill $pidctrl qt kill $pidmnc exit 1 } ctrl () { exit1 () { eecho "Error: Unknown response." eecho " $lastline" eecho " $state: $nrep $vrep" kill -12 $$ exit 1 } getresponse () { read nrep vrep # Skip over multi-line responses while : ; do case $nrep in ???-*) read nrep vrep ;; *) break ;; esac done x=${nrep%${nrep#?}} } local wait=yes trap "unset wait" 10 while [ "$wait" = "yes" ] ; do done { getresponse state=0 sentbody=no IFS=$LF for line in `cat $fdata` ; do IFS=$OIFS # Send heartbeat signal...prevents timout while active kill -10 $$ lastline="$line" case $x in "2") echo "$line$CR" [ $state -eq 4 ] && [ "$line" != "DATA" ] && state=$(($state - 1)) [ $state -ne 6 ] && state=$(($state + 1)) ;; "3") [ $state -ne 5 -a $state -ne 6 ] && exit1 [ $state -eq 5 ] && state=$(($state + 1)) if [ "$line" = "." ] ; then if [ "$sentbody" != "yes" ] ; then cat $fbody | sed 's/^\./\.\./' kill -10 $$ IFS="," for file in $att; do attach $file kill -10 $$ done IFS=$OIFS sentbody=yes else echo "$line$CR" state=$(($state + 1)) fi else echo "$line$CR" fi ;; *) exit1 ;; esac [ $state -ne 6 ] && getresponse # eecho "$state: $nrep $line" done } < $prx exit 0 } TIMEOUT=60 ContentBoundry="+++++LRP content boundry $$-`date +%s`+++++" ptx="/tmp/smtp.tx.$$" prx="/tmp/smtp.rx.$$" fdata="/tmp/smtp.data.$$" fbody="/tmp/smtp.body.$$" [ -e $prx ] && eecho "Bad in file" && exit 1 [ -e $ptx ] && eecho "Bad out file" && exit 1 [ -e $fdata ] && eecho "Bad temp file" && exit 1 [ -e $fbody ] && eecho "Bad temp file" && exit 1 mknod $ptx p; mknod $prx p; echo -e -n > $fdata echo -e -n > $fbody chmod 600 $ptx $prx $fdata $fbody fqdn=${lrp_MAIL_DOMAIN:-`hostname -f`} user=${USER:-$LOGNAME} smtpserv=${lrp_MAIL_SERVER:-mail} while getopts a:b:c:d:h:s: opt ; do case "$opt" in a) att="$OPTARG" ;; b) bcc="$OPTARG" ;; c) cc="$OPTARG" ;; d) fqdn="$OPTARG" ;; h) smtpserv="$OPTARG" ;; s) subject="$OPTARG" ;; esac done shift $(($OPTIND - 1)) [ $# -lt 1 ] && { usage ; exit 1 ; } cat >$fbody to="$@" IFS="," allto="$to,$cc,$bcc" envelopes="$( for str in $allto; do echo $str done | sed 's/^.*[< ]\(.*\)$/\1/;s/>$//' )" IFS=$OIFS { echo "RSET" echo "HELO $fqdn" echo "MAIL FROM:<$user@$fqdn>" for rcpt in $envelopes; do echo "RCPT TO:<$rcpt>" done echo "DATA" date=`rfcdate` [ -n "$date" ] && echo "Date: $date" echo "From: $user@$fqdn" echo "Subject: $subject" [ -n "$to" ] && echo "To: $to" [ -n "$cc" ] && echo "cc: $cc" [ -n "$bcc" ] && echo "bcc: " [ -n "$att" ] && { echo "Mime-Version: 1.0" echo "Content-Type: multipart/mixed; boundary=\"$ContentBoundry\"" echo "" echo "--$ContentBoundry" echo 'Content-Type: text/plain; charset="us-ascii"' } echo "" echo "." [ -n "$att" ] && { echo "" echo -n "--$ContentBoundry--" } echo -e "\n.\nQUIT" } >$fdata # Heartbeat signal from ctrl process trap "count=0" 10 # Abort signal from ctrl process trap "abort \"connection error\"" 12 # Remove files on exit trap "qt rm -f $ptx $prx $fdata $fbody" 0 # Trap software aborts & kill child processes trap "abort \"software signal\"" 1 2 6 9 15 trap "" 18 19 20 trap ":" 17 ctrl > $ptx & pidctrl=$! mnc $smtpserv $(getservbyname smtp) < $ptx > $prx & pidmnc=$! kill -10 $pidctrl count=0 while [ -n "`jobs`" ] ; do sleep 1 count=$(($count + 1)) [ $count -gt $TIMEOUT ] && abort "timeout" done exit 0 } finger () { #usr/bin #[ $# -ne 1 ] && echo "Usage: $(basename) user[@host.domain]" && exit 1 local IFS='@' set -- $1 user="$1" if [ "$2" != "" ]; then host="$2" else host="localhost" fi echo "$user"' ' | mnc $host $(getservbyname finger) [ $? -ne 0 ] && echo "Connection refused" && exit 1 } uname () { #bin local rc case $1 in -a|--all) rc="`cat /proc/sys/kernel/ostype` `cat /proc/sys/kernel/hostname` `cat /proc/sys/kernel/osrelease` `cat /proc/sys/kernel/version` i386 unknown" ;; -r|--release) rc="`cat /proc/sys/kernel/osrelease`" ;; -s|--sysname|*) rc="`cat /proc/sys/kernel/ostype`" ;; esac echo $rc } uptime () { #usr/bin local IFS='.' set -- `cat /proc/uptime` uph=$(($1 / 3600)) upd=$(($uph / 24)) local IFS=' ' set -- `date` str="$4" set -- `cat /proc/loadavg` str="$str up $upd Days ($uph"h"), load average: $1 $2 $3" echo " $str" } who () { #usr/bin local now=$(date +%s) echo "USER TTY PID TIMEON FROM" for f in $(dutmp /var/run/utmp |grep '^7|'); do #dutmp busybox function local IFS='|' set -- $f minon=$(( $(($now - $10)) / 60 )) #echo "$5 $3 $2 $minon $6" printf "%-8.8s %-8.8s %-8.8s %-8.8s %-8.8s\n" $5 $3 $2 $minon $6 done } last () { #usr/bin local now=$(date +%s) echo "USER TTY PID TIMEON FROM" for f in $(dutmp /var/log/wtmp |grep '^\(7\|2\)|'); do #dutmp busybox function local IFS='|' set -- $f minon=$(( $(($now - $10)) / 60 )) echo "$5 $3 $2 $minon $6" done } getservbyname () { #usr/sbin [ "$1" != "" ] && serv=$1 || \ { eecho "Usage: $prog service [type]"; exit 1; } proto=${2:-tcp} port="$(sed -n "s/^$serv[ |$TAB]*\([^/]*\)\/$proto.*$/\1/p" /etc/services)" echo "${port:-0}" return ${port:-0} } printenv () { #usr/bin if [ $# -gt 0 ]; then for v in $@; do eval V="\$"$v"" [ ! "$V" ] && continue echo "$V" done else for v in $(export); do eval echo "$v="\$"$v"; done fi } id () { #usr/bin IFS=':' set -- $(grep "^$USER:" /etc/passwd) uid=$3 gid=$4 set -- $(grep ":x:$gid:" /etc/group) gidn=$1 echo "uid=$uid($USER) gid=$gid($gidn)" } whoami () { #usr/bin echo "$USER" } w () { #usr/bin uptime who } expr () { #usr/bin exp "$@" #ash builtin } necho () { #usr/bin local E if [ "$1" = "-n" ]; then shift E="echo -n" else E="echo" fi #Do not echo if line is blank if [ ! "$1" = "" ]; then $E "$1" fi } eecho () { #usr/bin echo "$@" >/dev/null >&2 } pauseme () { #usr/bin echo -n " Press return...";read n;echo } lsmod () { #sbin echo "Module Pages Used by" cat /proc/modules } useradd () { #usr/sbin PW="/etc/passwd" SH="/etc/shadow" DAY="$(( $(date +%s) / 60 / 60 / 24 ))" eecho "FIX ME: $DAY" } userdel () { #usr/sbin PW="/etc/passwd" SH="/etc/shadow" [ $# -ne 1 ] && eecho "Usage: $prog username" && return 1 if [ "$(sed -n /^$1:/p $PW)" = "" ]; then eecho "$prog: user $1 does not exist" return 1 fi umask 077 cp $PW $PW-; cp $SH $SH- sed "/^$1:/d" $PW- > $PW sed "/^$1:/d" $SH- > $SH } usermod () { #usr/sbin eecho "FIX ME" } groupadd () { #usr/sbin eecho "FIX ME" } groupdel () { #usr/sbin GP="/etc/group" GS="/etc/gshadow" [ $# -ne 1 ] && eecho "usage: $prog group" && return 1 if [ "$(sed -n /^$1:/p $PW)" = "" ]; then eecho "$prog: group $1 does not exist" return 1 fi umask 077 cp $GP $GP-; cp $GS $GS- sed /^$1:/d $GP- > $GP sed /^$1:/d $GS- > $GS } groupmod () { #usr/sbin eecho "FIX ME" } #START LRP stuff lrpkg () { #usr/sbin lrpkgpath="/var/lib/lrpkg/" CD="$(pwd)" usage () { eecho "Usage: $(basename $0) [-l] [-i] []" eecho " -l: list List installed packages." eecho " -i: install Install package. (exclude .lrp)" eecho " If giving give full path /dev/..." } list () { echo "Name Version Description" echo "===============-==============-==============================================" PACKAGES="$(cat $lrpkgpath/packages)" for p in $PACKAGES; do ver="$(cat $lrpkgpath/$p.version)" desc="$(head -n 1 $lrpkgpath/$p.help)" printf "%-15.15s %-14.14s %-46.46s\n" "$p" "$ver" "$desc" done } install () { f="$1" local pk="`sed 's/.*PKGPATH=.*/PKGPATH/' /proc/cmdline`" local d="" if [ "$pk" = "PKGPATH" ]; then if [ -z "$2" ]; then local d="`sed 's/.*PKGPATH=/\1/; s/ .*//1; s/^.*,\(.*\)$/\1/' /proc/cmdline`" else local d="$2" fi fi cd / if [ -f "$CD/$f.lrp" ]; then echo -n "Installing $f... " qt gunzip < "$CD/$f.lrp" if [ $? -eq 0 ]; then gunzip < "$CD/$f.lrp" | qt untar echo "$f">>"$lrpkgpath/packages" #Update installed packages file [ -n "$d" ] &&\ echo "$f=-t `cat $lrpkgpath/boot.fstype` $d">>"$lrpkgpath/backdisk" echo "Done." else echo "Archive appears corrupted! Bailing..." fi else eecho "Archive '$f.lrp' not found." fi cd $CD } case "$1" in -l ) list "$2" ;; -i ) install "$2" "$3" ;; * ) usage ;; esac } update-rc.d () { #usr/sbin usage () { eecho "Usage: $(basename $0) [-f] [-a[-w]] " eecho " -f: force Force. ALL current links of are deleted." eecho " -a: all Process all files in /etc/init.d/. ignored." eecho " -w: wipe Wipe /etc/rc?.d/ directories (implies -f)" eecho " -v: verbose Be extra verbose." eecho "" eecho "This program uses 'RCDLINKS=' found in the /etc/init.d/ files." eecho "Comment out 'RCDLINKS=' if you want a file to be ignored." } while getopts fawv opt ; do case "$opt" in f) rcdforce="yes" ;; a) rcdall="yes" ;; w) rcdwipe="yes" ;; v) rcdvb="yes" ;; esac done shift $(($OPTIND - 1)) if [ "$rcdall" = "yes" ]; then if [ "$rcdwipe" = "yes" ]; then for d in /etc/rc?.d; do [ ! -d "$d" ] && continue qt rm $d/[KS][0-9][0-9]* done fi F=/etc/init.d/* else [ "$1" = "" ] && usage && exit 1 F=/etc/init.d/$1 if [ ! -x "$f" ]; then eecho "$f does not exist or is not executable." exit 1 fi fi errlvl=0 for f in $F; do [ ! -x "$f" ] && continue eval RCDLINKS=$(sed -n '1,/^RCDLINKS=/s/^RCDLINKS=\(.*\)/\1/p' $f 2>/dev/null) if [ "$RCDLINKS" != "" ]; then bf="$(basename $f)" qt ls /etc/rc?.d/[KS][0-9][0-9]$bf if [ $? -eq 0 ]; then if [ "$rcdforce" = "yes" ]; then qt rm /etc/rc?.d/[KS][0-9][0-9]$bf else eecho "System startup links for $f already exist." errlvl=2 continue fi fi for l in $RCDLINKS; do IFS=','; set -- $l; IFS=$OIFS [ ! -d "/etc/rc$1.d" ] && continue # Ignore bad dirs. [ "$rcdvb" ] && eecho "RCDLINKS=$RCDLINKS - $f" ln -sf "../init.d/$bf" "/etc/rc$1.d/$2$bf" 2>/dev/null done else [ "$rcdvb" ] && eecho "'^RCDLINKS=' not found in $f. File ignored." errlvl=3 fi done return $errlvl } help () { #usr/bin HF="$1" [ $# -eq 0 ] && HF="root" more "/var/lib/lrpkg/$HF.help" } svi () { #usr/sbin singlefilearg "/etc/init.d/$1" /etc/init.d/$@ } mount.boot () { #usr/sbin mount -t `cat /var/lib/lrpkg/boot.fstype` /dev/boot "$1" } mount.back () { dev = "" if [ -f /var/lib/lrpkg/backdisk ]; then dev="`grep ""^$1="" /var/lib/lrpkg/backdisk|sed 's/.*=//'`" fi if [ "$dev" = "" ]; then mount -t `cat /var/lib/lrpkg/boot.fstype` /dev/boot "$2" else mount $dev "$2" fi } #END LRP stuff singlefilearg () { if [ "$1" = "" ]; then eecho "Usage: $prog file" exit 1 fi if [ ! -f "$1" ]; then eecho "$1: No such file or directory" exit 1 fi } ## #main () #{ ## prog=$(basename $0) case $prog in basename|dirname|uname|grep|cut|free|expr|head|tail|nl|\ uniq|mail|finger|sort|help|svi|mount.boot|mount.back|necho|eecho|\ useradd|userdel|usermod|groupadd|groupdel|groupmod|\ update-rc.d|printenv|getservbyname|lrpkg|zmore|zgrep) $prog "$@" ;; uptime|who|id|whoami|w|pauseme|lsmod|last|reset) $prog ;; *) eecho "No function defined for '$prog'" exit 1 ;; esac exit $? ## #} ##