Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
embedded + automounting
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Gentoo on Alternative Architectures
View previous topic :: View next topic  
Author Message
gtbX
Tux's lil' helper
Tux's lil' helper


Joined: 11 Oct 2003
Posts: 99

PostPosted: Tue Mar 20, 2007 2:22 am    Post subject: embedded + automounting Reply with quote

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
View user's profile Send private message
gtbX
Tux's lil' helper
Tux's lil' helper


Joined: 11 Oct 2003
Posts: 99

PostPosted: Sat Mar 24, 2007 4:02 am    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Gentoo on Alternative Architectures All times are GMT
Page 1 of 1

 
Jump to:  
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