View previous topic :: View next topic |
Author |
Message |
gtbX Tux's lil' helper

Joined: 11 Oct 2003 Posts: 126
|
Posted: Tue Mar 20, 2007 2:22 am Post subject: embedded + automounting |
|
|
I'm trying to build a digital picture frame out of an old laptop (Thinkpad 390: Pentium2 233, 32MB ram). It's for my grandparents, so it must be set-and-forget simple: the only UI should be a screen, an on switch and memory card slots. The hard disk should shut down after boot to keep the noise down.
I've started with Tiny Gentoo, but set it up to use udev instead of a static /dev. I couldn't install udev from portage, as it requires a full install of baselayout, sysvinit, and bash among other things that would just be taking up space. Instead I installed udev from source here: http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html. (Perhaps a udev-lite or udev-embedded ebuild is in order?)
The laptop connects to a USB card reader that works flawlessly on my other linux boxen, but these have a full udev-dbus-hal-pmount chain. Due to the limited memory of this machine, I don't think that will all fit. This thread has a way of automounting usb devices through udev alone, but it doesn't deal with card change events. It seems hal continuously polls the card reader for insert/removal events, and signals udev to add/remove the device file. I can force card partitions to be recognized by doing
Code: | dd if=/dev/sdX of=/dev/null count=1 |
but that doesn't seem right, and it doesn't help card removals
Ideas?
Here's my /init
Code: |
cat /initrd/init
#!/bin/ash
echo
echo
echo " Welcome to TinyGentoo."
echo
echo
echo " * Setting umask.."
umask 022
echo " * Mounting /proc.."
mount -t proc none /proc
echo " * Mounting /sys.."
mount -t sysfs none /sys
echo " * Starting udev.."
echo " * Using netlink for hotplug events.."
echo "" > /proc/sys/kernel/hotplug
echo " * Starting udevd.."
udevd --daemon
echo " * Populating /dev with existing devices through uevents"
touch /dev/.udev_populate
/sbin/udevtrigger --attr-match=dev
echo " * Letting udev process events"
/sbin/udevsettle --timeout=60
rm /dev/.udev_populate
echo " * Shutting down hard disk.."
hdparm -S 1 /dev/hda
hdparm -Y /dev/hda
#echo " * Starting init.."
#exec <dev/console >dev/console 2>&1
#exec chroot . /sbin/init
#echo " *** Starting init failed! ***"
#echo " * Trying to start a shell.."
exec /bin/ash
|
|
|
Back to top |
|
 |
gtbX Tux's lil' helper

Joined: 11 Oct 2003 Posts: 126
|
Posted: Sat Mar 24, 2007 4:02 am Post subject: |
|
|
Ok, here's what I did:
Without HAL continuously polling removable devices, they never get recognized by the kernel. Therefore, I needed something to mimic this functionality of hal: a C program to poll the card slot devices, and a short ash script to take care of the cleanup.
cardd.c:
Code: | /* cardd - card slot monitor daemon
*
* This program is designed to monitor USB flash memory card reader slots,
* and cause device events when cards are inserted or removed. Each slot
* in a x-in-1 card reader should be represented by its own device in /dev
*
* When a card is inserted, simply opening the device file should cause the
* kernel to read the card's partition table, which in turn causes udev to
* create device files for the partitions. Udev, or another program, is
* responsible for mounting these partitions.
*
* When a card is removed, opening the device will cause an I/O error. The
* filesystems inside any partitions on the device must then be unmounted.
* Ideally, this program should signal udev somehow that a device has been
* removed and the appropriate cleanup should happen.
*
* The list of devices to watch is kept in an internal list. Devices may be
* added to the list by writing the device name and a newline to the fifo
* /var/cardslots. If a device file no longer exists, it is automatically
* removed from the list. Device names are limited to MAX_DEVNAME
* (default 256) chars.
*
* Note this has nothing to do with PCMCIA/CardBus card slots.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#define MAX_DEVNAME 256
#define FIFO_NAME "/var/cardslots"
struct card_slot_s {
char device[MAX_DEVNAME];
int card_present;
struct card_slot_s *next;
};
typedef struct card_slot_s card_slot;
int run;
struct sigaction handler;
void handle_SIGINT()
{
run = 0;
}
void unmount_parts( const char *device )
{
int pid;
if( ( pid = fork() ) == 0 ) {
// inside child process. execute unmount script
execl( "/bin/ash", "/bin/ash", "/sbin/unmount_parts.sh",
device, (char *)NULL );
perror( "exec" );
exit( EXIT_FAILURE );
}
// wait for child to terminate
waitpid( pid, NULL, 0 );
}
card_slot *add_card_slot( card_slot *slot, const char *device_name )
{
if( strlen( device_name ) == 0 ) return slot;
if( slot == NULL ) {
slot = malloc( sizeof( card_slot ) );
if( slot == NULL ) {
perror( "malloc" );
exit( EXIT_FAILURE );
}
strcpy( slot->device, device_name );
slot->card_present = 0;
slot->next = NULL;
} else {
slot->next = add_card_slot( slot->next, device_name );
}
return slot;
}
void cleanup_slot_list( card_slot *slot )
{
if( slot == NULL ) return;
if( slot->next != NULL )
cleanup_slot_list( slot->next );
free( slot );
}
card_slot *check_slot_list( card_slot *slot )
{
int dev;
if( slot != NULL ) {
slot->next = check_slot_list( slot->next );
dev = open( slot->device, O_RDONLY );
if( dev < 0 ) {
// remove this device from the list for all errors except ENOMEDIUM
if( errno != ENOMEDIUM ) {
card_slot *tmp;
perror( "open" );
tmp = slot->next;
free( slot );
slot = tmp;
} else {
if( slot->card_present ) {
// unmount all partitions
unmount_parts( slot->device );
}
slot->card_present = 0;
}
} else {
slot->card_present = 1;
if( close( dev ) != 0 )
perror( "close" );
}
}
return slot;
}
void read_devices( int fd, card_slot **first )
{
char buf[MAX_DEVNAME];
int i;
while( 1 )
for( i = 0; i < MAX_DEVNAME; i++ ) {
if( ( read( fd, buf + i, 1 ) ) < 1 ) return;
if( buf[i] == '\n' || buf[i] == '\r' ) {
buf[i] = '\0';
*first = add_card_slot( *first, buf );
break;
}
}
}
int main( int argc, char *argv[] )
{
int fifo;
card_slot *first_slot = NULL;
run = 1;
// initialize the signal handler
handler.sa_handler = handle_SIGINT;
sigaction( SIGINT, &handler, NULL );
// first make the fifo to accept input on
if( mkfifo( FIFO_NAME, 0600 ) < 0 ) {
perror( "mkfifo" );
exit( EXIT_FAILURE );
}
// open the fifo to read input
if( ( fifo = open( FIFO_NAME, O_RDONLY | O_NONBLOCK ) ) < 0 ) {
perror( "open" );
exit( EXIT_FAILURE );
}
// main loop
while( run ) {
// check if new card slots were added
read_devices( fifo, &first_slot );
// check all known slots for media change
first_slot = check_slot_list( first_slot );
sleep( 5 );
}
// close and clean up
cleanup_slot_list( first_slot );
if( close( fifo ) != 0 )
perror( "close" );
if( unlink( FIFO_NAME ) != 0 )
perror( "unlink" );
return EXIT_SUCCESS;
} |
and its companion script, unmount_parts.sh
Code: | #!/bin/ash
if [ "$@" == "" ]
then
exit
fi
echo "Unmounting filesystems on $@"
for f in `ls $@?*`
do
umount -l $f
rmdir /mnt/`basename $f`
rm $f
done
|
cardd was started just before udev so that udev could pass card slot detection events to cardd:
/init
Code: | #!/bin/ash
echo
echo
echo " Welcome to TinyGentoo."
echo
echo
echo " * Setting umask.."
umask 022
echo " * Mounting /proc.."
mount -t proc none /proc
echo " * Mounting /sys.."
mount -t sysfs none /sys
echo " * Starting flash card daemon.."
cardd &
echo " * Starting udev.."
echo " * Using netlink for hotplug events.."
echo "" > /proc/sys/kernel/hotplug
echo " * Starting udevd.."
udevd --daemon
echo " * Populating /dev with existing devices through uevents"
touch /dev/.udev_populate
/sbin/udevtrigger --attr-match=dev
echo " * Letting udev process events"
/sbin/udevsettle --timeout=60
rm /dev/.udev_populate
echo " * Shutting down hard disk.."
hdparm -S 1 /dev/hda
hdparm -Y /dev/hda
exec <dev/console >dev/console 2>&1
echo " * Starting ash.."
exec /bin/ash |
/etc/dev.d/block/usb.dev
Code: | #!/bin/ash
base=$(basename $DEVNAME)
#Check to see if the device is a sdXn device (disk partition)
if [[ `expr $base : "sd[a-z][1-9]"` == 4 ]]
then
#Do this when adding the plugged device
if [ "$ACTION" == "add" ]
then
#Create mount point and mount the device to it with proper access
mkdir -p /mnt/$base
mount -o ro /dev/$base /mnt/$base
#Do this when the device is unplugged
elif [ "$ACTION" == "remove" ]
then
umount -l /mnt/$base
rmdir /mnt/$base
fi
#check if the device is sdX (whole-disk block device)
elif [[ `expr $base : "sd[a-z]"` == 3 ]]
then
if [ "$ACTION" == "add" ]
then
if [ -e /var/cardslots ]
then
echo "$DEVNAME" > /var/cardslots
fi
fi
fi |
There. a system that can autodetect and mount memory cards in 32MB combined ram/disk space. granted, there are probably some security problems with it, but I'm not too concerned since its going in an isolated system.
Now all I need is a framebuffer picture viewer that will automatically display any pictures found under /mnt/ (and can deal with the filesystem changing on the fly). |
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|