BSD User Hacks

by Dru Lavigne

One of the things that really impressed me when I was researching and writing BSD Hacks is how resourceful and imaginative open source users really are. To be honest, it was hard to limit the book to 100 hacks--there's just so many useful ideas out there.

You can imagine how pleased I was to receive an email the other day from Patrick Tracanelli, one of the developers of the FreeBSD LiveCD Project (http://livecd.sourceforge.net. The email contained a dialog script, his "hack" of hack #82 from BSD Hacks. This particular hack demonstrates how to reap the benefits of the ports collection without having to install the entire ports tree.

I was excited for two reasons. One, here was a reader who had taken the spirit of the book to heart: to use the hacks as fuel to your own imagination to solve a particular problem using the tools you happen to have at hand. Second, I had wanted to include at least one hack on dialog, an extremely useful and easy way to add menus to a basic shell script. However, in the end, there just wasn't room in the book for a dialog hack.

With Patrick's permission, I've included his script. If you have a FreeBSD system without the ports collection, try using it to download the required skeletons needed to install a particular port. If you've already installed the ports collection, you can still try it as it will do its work in a temporary directory. I hope you enjoy the script as much as I do!

*****

#!/bin/sh -
#
# Patrick Tracanelli
#
# June 2004 - early Beta (or Alfa?) lines
#
# (Written while listening to Revoltz - banda da Mari)
#
#set -ex

set_anoncvsrvr() {

if [ -e $1 ]; then

# ANONCVSRVR="anoncvs.br.freebsd.org"
# (BRazil / Unicamp - Universidade de Campinas)
#
ANONCVSRVR="anoncvs.at.freebsd.org"
# (AusTria / Wirtschaftsuniversitaet Wien, ZID. Vienna)
#
# ANONCVSRVR="anoncvs.jp.freebsd.org"
# (Japan / GCTR-FREEBSD - Global Center IPv6 FreeBSD)
#
# ANONCVSRVR="anoncvs.de.freebsd.org"
# (Germany / Technische Universitaet Muenchen)
#
# ANONCVSRVR="anoncvs2.de.freebsd.org"
# (Germany / University of KaiserslauternKaiserslautern)
#
# ANONCVSRVR="anoncvs.freebsd.org"
# (US, California / FreeBSD Project)

else
ANONCVSRVR=$1
fi

}

checkuid() {
if [ `id -u` -ne 0 ]; then
message 5 "Sorry, you should be root!"
exit 0;
fi
}

get_defs() {
CTRLDIR="/var/tmp/ports.tempcontrol"

set_anoncvsrvr
export CVSROOT=:pserver:anoncvs:anoncvs@${ANONCVSRVR}/home/ncvs

if [ -r ${CTRLDIR}/PORTSB ]; then
PORTSB="`cat ${CTRLDIR}/PORTSB`"
else
first_run_msg
defportsb
fi
}

save_defs() {
case $1 in
"portsb")
echo ${PORTSB} > ${CTRLDIR}/PORTSB
;;
esac
}

defportsb() {
if [ -r ~/.cvspass ]; then
message 5 "=> Backing up ~/.cvspass to ~/.cvspass_"
mv -v ~/.cvspass ~/.cvspass_
message 5 "=> Touching an empty ~/.cvspass"
touch ~/.cvspass
fi
if [ -w /usr/ports ]; then
message 5 "=> /usr/ports exists, won't mess there..."
mkdir -p /usr/local/tmp_ports
PORTSB="/usr/local/tmp_ports"
message 5 "=> /usr/local/tmp_ports/ports will be our temporary working tree."
else
message 5 "=> /usr/ports does not exists, will be our temporary working tree."
PORTSB="/usr"
fi
mkdir -p ${CTRLDIR}
save_defs portsb
}

cvs_login() {
export CVSROOT=:pserver:anoncvs:anoncvs@${ANONCVSRVR}/home/ncvs

if [ -r ${CTRLDIR}/cvs_loggedin ]; then
message 5 "Already logged into ${ANONCVSRVR}."
else
cvs login
echo ${ANONCVSRVR} > ${CTRLDIR}/cvs_loggedin
fi
}

cvs_logout() {
cvs logout
rm -f ${CTRLDIR}/cvs_loggedin
message 5 "Logged out from ${ANONCVSRVR} CVS Server"
}

cvs_co_base() {
cvs_login
cd ${PORTSB}
cvs co -A -P -l ports/Mk
cvs co -A -P -l ports/Templates
cvs co -A -P -l ports/INDEX
message 5 "checkout of ports/Mk, ports/Templates and ports/INDEX is done!"
}


def_categories() {
# should ONLY be called by def_smallindex()
TMPLISTING="`mktemp -t portskel`"
cat ${PORTSB}/ports/INDEX | awk -F "|" '{print $7}' | cut -d " " -f 1 > ${TMPLISTING}
cat ${TMPLISTING} | uniq > ${CTRLDIR}/CATEGORIES
rm -f ${TMPLISTING}
# from now on, we dont need INDEX more...
rm -f ${PORTSB}/ports/INDEX
}

def_smallindex() {
if [ -r ${PORTSB}/ports/INDEX ]; then
cat ${PORTSB}/ports/INDEX | awk -F "|" '{print $2}' | \
awk -F "/" '{print $4"/"$5}' > ${CTRLDIR}/INDEX
def_categories
message 6 "Both ${CTRLDIR}/INDEX and ${CTRLDIR}/CATEGORIES were hopefully generated."
else
message 8 "${PORTSB}/ports/INDEX was not found! We need this file
once, to generate our smaller ports INDEX definition and find out
what are the most recent available categories. I suggest you to
CVS checkout the basic required files again (menu's option #2)."
fi
}

cvs_co_desired_portskel() {
cd ${PORTSB}
cvs co -A -P -l ports/$1
get_depends $1

}


get_depends() {
cd ${PORTSB}/ports/$1
PORTDEP=`cat Makefile | grep "LIB_DEPENDS" | awk -F "/" '{print $2"/"$3"/"}' | grep -v "//"`
for dep in ${PORTDEP}; do
message 5 "=> $1 depends on $dep, lets get it..."
cvs_co_desired_portskel $dep 2>&1 >> /tmp/log.log
done
}

select_port_bycat() {
CATEGORY=$1
CHOICE=`mktemp -t portskel`
# PORTS=`cat /var/tmp/ports.tempcontrol/INDEX | grep "${CATEGORY}/" | awk -F "/" '{print $1"/"$2" <="}'`
PORTS=`cat /var/tmp/ports.tempcontrol/INDEX | grep "${CATEGORY}/" | awk -F "/" '{print $2" <="}'`

dialog --menu "Under ${CATEGORY}/ category, choose the port you want skeleleton for." \
20 70 13 ${PORTS} 2> ${CHOICE}

if [ -r `cat ${CHOICE}` ]; then
select_category
else
CHOICE=`cat ${CHOICE}`
cvs_co_desired_portskel ${CATEGORY}/${CHOICE}
hopefully_done_msg
cvs_logout
exit 0;
fi
}

select_category() {
CHOICE=`mktemp -t portskel`
CATEGORIES=`cat ${CTRLDIR}/CATEGORIES | awk '{print $1" <="}'`

dialog --menu "Select the ports category." \
20 35 13 ${CATEGORIES} 2> ${CHOICE} && select_port_bycat `cat ${CHOICE}`

rm -f ${CHOICE}
}

hopefully_done_msg() {
MSGF="`mktemp -t portskel`"

cat >> ${MSGF} << EOF
Ports skeleton for ${CATEGORY}/${CHOICE} and all its dependencies
were hopefully retrieved. Now you should manually:

cd ${PORTSB}/ports/${CATEGORY}/${CHOICE}

read Makefile file to figure out all available compiling-time
options and:

make WITH_DESIRED_OPTIONS_READ_ON_MAKEFILE=yes install clean

And if disk space is a big big issue and you can't temporarily use
the space necessary by distfiles/, you may issue:

make distclean

This tool does not intend to install things for you, only retrieve
the necessary skeleton trees that allows you to use the amazing
FreeBSD Ports Collection without spending all ~500MB disk space
used by the complete ports collection skel.

If you do not use to set compile-time options nor modify CFLAGS,
you may also consider using pkg_add(1) with the -r switch.

Thank you for using this tool.
Hope it worked as you expected.
EOF
dialog --title "[ Skeleton retrieval done! ]" \
--textbox ${MSGF} 15 70
rm -f ${MSGF}
}

first_run_msg() {
MSG="It is the first time you are running this program!
\nWe need to set some default values that will be used
until the end of your ports skeleton retrieval, or 'til
you explicitly choose to update/redefine those values.
\nMost of the data we define here, will be used for the
next times you run this program. Press OK to go on."
dialog --title "First time run! Time to define defaults." --msgbox "${MSG}" 12 59
}

message() {
dialog --title "Please note:" --msgbox "$2" $1 70
}

go_retrieve() {
if [ -r ${CTRLDIR}/CATEGORIES ]; then
select_category
else
cvs_co_base
def_smallindex
go_retrieve # thats why we are here...
fi
}


main_menu() {
checkuid
get_defs

CHOICE="`mktemp -t portskel`"
dialog --menu "Ports Skeleton Retrieval Tool (June 2004)" 19 50 12 \
R "Retrieve a skeleton for a port." \
2 "CVS checkout the basic required files." \
3 "Create a smaller INDEX & CATEGORIES." \
4 "Delete defaults and exit." \
5 "Delete everything and exit." \
6 "Logout from CVS" \
Q "Quit" 2> ${CHOICE}
OP="`cat ${CHOICE}`"
rm -f ${CHOICE}

case ${OP} in
R)
go_retrieve
main_menu
;;
2)
cvs_co_base
main_menu
;;
3)
def_smallindex
main_menu
;;
Q)
cvs_logout
message 5 "bye bye!"
exit 0;
;;
4)
rm -rf ${CTRLDIR}
message 5 "${CTRLDIR} was removed!"
cvs_logout
exit 0;
;;
5)
rm -rf ${CTRLDIR}
rm -rf ${PORTSB}
rm -f /tmp/portskel.*
message 5 "Both ${CTRLDIR} and ${PORTSB} removed!"
cvs_logout
exit 0;
;;
6)
cvs_logout
main_menu
;;
*)
main_menu
;;

esac
}

####################################
main_menu







Have you hacked a BSD Hack? If so, drop me a line or post it for the benefit of other users.