Posts Tagged ‘Arch Linux’

Holy crap. This “blog” is almost dead. Lemme give it some love.

While finishing up a rewrite of our database scripts at ArchAudio I had to figure out a solution to clear out old packages in the repositories. The way our stuff works is actually dependent solely on Subversion, and there is no SSH involved. You can guess that this means our binary packages are just SVN commits.

As such, without getting too hacky, you are not going to get a list of packages being “uploaded”. You are going to need to work with an arbitrary number of packages at a time, so fellow Arch Linux user Bluewind‘s script for his personal repositories is not going to cut it (note: this is false and is actually an excuse for my inability to read Perl). I also want to keep our scripts in Bash (aside from the mailer which is in Python and is just a copy-paste from a template) to allow potentially more people to contribute.

I figured I would just need something like Pacman‘s clean function, but for the makepkg cache instead. I thought something like that might already exist, but a search through the AUR, ArchWiki and Arch Forums turned up nothing. In not wanting to waste any more time, I figured reinventing the wheel wouldn’t be that great of a loss if I couldn’t find the wheel in the first place. So here it is:

#!/bin/bash

# Copyright (c) 2011 Ray Rashif  - GNU GPL

get_fext() {
	echo $1 | rev | awk -F "-" '{print $1}' | rev
}

get_pver() {
	echo $1 | rev | awk -F "-" '{print $2"-"$3}' | rev
}

get_pname() {
	local fext pver

	fext=$(get_fext $1)
	pver=$(get_pver $1)

	echo ${1/-$pver-$fext}
}

# clean package extensions first
echo -n "Getting rid of old package formats..."

for pfile in *.pkg.tar.*; do
	# exit cleanly if nothing was found
	if [[ "$pfile" = '*.pkg.tar.*' ]]; then
		echo "none found"
		echo "No packages found, nothing to do."
		exit 0
	fi

	fext=$(get_fext $pfile)
	pver=$(get_pver $pfile)
	pname=${pfile/-$pver-$fext}
	parch=${fext/.*}

	# just edit the RE for more formats
	id=$pname-$pver-$parch.pkg.tar
	pext_matches=($(\ls -v $id.[gx]z))

	if [[ ${#pext_matches[@]} -gt 1 ]]; then
		for match in ${pext_matches[@]}; do
			[[ "$match" != "$id.xz" ]] && \
				rm -f $match && oldremoved=1
		done
	fi
done

[[ $oldremoved -eq 1 ]] && echo "done" || echo "none found"

# now clean the rest
for pfile in *.pkg.tar.*; do
	fext=$(get_fext $pfile)
	pver=$(get_pver $pfile)
	pname=${pfile/-$pver-$fext}
	parch=${fext/.*}

	matches=($(\ls -v $pname-*-$parch.*))

	# for cases like foo, foo-bar, prevent mixing them up
	for oldpkg in $(seq 0 $((${#matches[@]} - 1))); do
		oldname=$(get_pname ${matches[$oldpkg]})
		[[ "$oldname" != "$pname" ]] && unset matches[$oldpkg]
	done

	t_matches=${#matches[@]}

	# if only one match then obviously nothing to do
	[[ $t_matches -eq 1 ]] && continue

	# get oldest and newest versions
	oldest=$(get_pver ${matches[0]})
	newest=$(get_pver ${matches[$t_matches-1]})

	echo "Cleaning $pname [$oldest -> $newest] ($parch)"

	# WARNING: logic based on ls natural version sort order;
	#   some types of versioning may fail this order
	#   last item is assumed latest
	for oldpkg in $(seq 0 $(($t_matches - 2))); do
		rm -f ${matches[$oldpkg]} && pkgremoved=1
	done
done

[[ $pkgremoved -ne 1 ]] && echo "All clear, nothing to clean."

# vim:set ts=4 sw=4 noet:

Nicely highlighted here: http://paste.pocoo.org/show/416372/

It removes all but the latest one for every package found in the current directory. It also checks for and removes older package formats for eg. those in .gz instead of .xz. Caveats apply (read through the code), and it’s also not optimised for speed. For instance, getting the name of the package via a functon is really expensive. Sort order may be a problem if your locale is not a form of English, but I’m not sure. Just test it out in a copy of the directory you want manipulated.

Note: This is not really Arch-specific although I deal with Arch Linux files in this article; anyone can adapt it for their *NIX platform’s init process.

Quickstart
First, get your sound file ready. We are going to read it after the system has sourced our rc.conf MODULES array, so you are free to choose a player, format and location. To be safe, I have mine in boot, and use aplay instead of mplayer, so it is at /boot/audio.wav as (obviously) a WAVE instead of MP3 or OGG.

Edit /etc/rc.sysinit and look for the line:

# Load modules from the MODULES array defined in rc.conf

and then add:

# start some background audio
/usr/sbin/alsactl restore
/usr/bin/aplay /boot/audio.wav &

before the lines:

if [ -d /proc/acpi ]; then
  stat_busy "Loading standard ACPI modules"
  ACPI_MODULES="ac battery button fan processor thermal"

Or if you manually load modules (all or even a couple), then before:

# Wait for udev uevents

Else, as a last resort, before:

# bring up the loopback interface

Try from the earliest, and if you get low-level ALSA errors, it means the sound device didn’t initialise by the time you wanted it to run. In that case, try the other two positions. Any later than that, I don’t see a point. Also, remember to set a nice level beforehand with alsamixer and then alsactl store it. If you want a different set of levels separate from the post-boot system, simply use a different file with the –file option:

~# alsactl store -f /etc/asoundboot.state

Since this is still a little too late for my taste, I don’t kill it. Good for a non-invasive ambience track, especially if you run a login manager. If you’re very clever and into Rocket Science, you can also use a sound file which fits into the period of bootup from after modules have been loaded (Rocket Science Hint: time or bootchart). Or if you’re not very clever, you can just kill the process from somewhere, eg. /etc/rc.local:

killall -9 aplay

For what it’s worth, that is the earliest time we can play a sound file without modifying the system, and this is before any daemons are run. You can remove your alsa daemon from the system since we already restore the state during the above run (edit the alsactl line accordingly if you have made changes to /etc/conf.d/alsa). Like mentioned, the result is not good enough for me (and possibly a lot of others), because my bootup is 40 seconds til a fully-functional, action-ready and tiled KDE 4 desktop (30 to Awesome WM). Nevertheless, curiosity killed.

Warning: An update to initscripts will replace the sysinit file. Look for “NoUpgrade” in pacman.

Background
Sabayon Linux has been doing it ever since their LiveDVD releases of year 2006, and even though it’s not something everyone would like, the fact is that it gets the curious user excited no matter how nonsensical a purpose it serves. I used Sabayon from around late 2006 to early 2007, at which point I moved to Arch (and I never hopped again), so I can still remember that it had an option to “turn off” the music via the kernel line. Regardless of the on/off state, I never did hear the music. At one point of time, on Arch, I tried to implement something similar. I forgot what I did, whether it even worked, and lost the related prototype files if any at all (I do recall a custom daemon).

Anyway, someone on #archlinux asked about this yesterday, and it got me curious again. My stance is always the same:

There is no reason for any kind of “boot music” aside from when live media is used. Optical read speed is inherently slower than traditional disks or flash drives, and for LiveDVDs it equates to a significant amount of waiting time during the boot process. There, it makes ample sense. If you _are_ curious enough to try it nonetheless, on a sane, installed system, you have to ensure that the music does not start too early or too late, or else it becomes pointless to the extent I should have to punch you.

From this and this it appears Sabayon has something called a “Boot Music Infrastructure”, which is technically nothing more than an init script. The sound file itself is stored in /usr/share/sounds, and the script will read (i.e play) it while the rest of the daemons are being started. The following:

depend() {
  after modules
  before hostname
  before alsasound
}

Translates linguistically to:

Start only after all modules have loaded, before the hostname is set, and before alsa state is restored.

I have no idea why they’re creating their own values for the audio levels. Anyway, theoretically, it might be possible to start the sound subsystem even earlier. That would mean injecting the modules (along with dependencies) and binaries into the kernel image (see mkinitcpio), and reconstructing init itself.

Say..a low-level method to play music from POST onwards would be really nice.

Another Rocket Science Hint: iPod

=p