mirror of https://github.com/CIRCL/Circlean
commit
216a9cf426
13
README.md
13
README.md
|
@ -14,18 +14,21 @@ And the linux way is in the command line, via dd (see in copy_to_final.sh)
|
||||||
|
|
||||||
If you'd like to contribute to the project or build the image yourself, see
|
If you'd like to contribute to the project or build the image yourself, see
|
||||||
[contributing](CONTRIBUTING.md) and the [setup readme](README_setup.md).
|
[contributing](CONTRIBUTING.md) and the [setup readme](README_setup.md).
|
||||||
|
This is a work in progress - contributions are welcome.
|
||||||
|
|
||||||
Why/What
|
Why/What
|
||||||
========
|
========
|
||||||
|
|
||||||
This project aims to be useful when you get/find a USB key that you can't trust,
|
This project aims to be useful when you get/find a USB key that you can't trust,
|
||||||
and you want to have a look at its contents without taking the risk of plugging it into your
|
and you want to look at its contents without taking the risk of plugging it into
|
||||||
main computer directly.
|
your computer directly.
|
||||||
|
|
||||||
This is a work in progress - contributions are welcome:
|
CIRCLean is currently tested to work with USB keys that have FAT32, NTFS, or
|
||||||
|
ext2/3/4 filesystems. Currently, exFAT is not supported due to lack of support for
|
||||||
|
this format in pmount. The vast majority of USB keys will be FAT32 or NTFS.
|
||||||
|
|
||||||
The content of the first key will be copied or/and converted to the second key
|
The content of the untrusted key will be copied or/and converted to the second
|
||||||
following these rules (based on the mime type, as determined by libmagic):
|
(blank) key following these rules (based on the mime type as determined bylibmagic):
|
||||||
- Direct copy of:
|
- Direct copy of:
|
||||||
- Plain text files (mime type: text/*)
|
- Plain text files (mime type: text/*)
|
||||||
- Audio files (mime type: audio/*)
|
- Audio files (mime type: audio/*)
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
led: led.c
|
|
||||||
gcc -ggdb -o led led.c
|
|
|
@ -1,81 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
/* GPIO registers address */
|
|
||||||
#define BCM2708_PERI_BASE 0x20000000
|
|
||||||
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
|
|
||||||
#define BLOCK_SIZE (256)
|
|
||||||
|
|
||||||
/* GPIO setup macros. Always use GPIO_IN(x) before using GPIO_OUT(x) or GPIO_ALT(x,y) */
|
|
||||||
#define GPIO_IN(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
|
|
||||||
#define GPIO_OUT(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
|
|
||||||
#define GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
|
|
||||||
|
|
||||||
#define GPIO_SET(g) *(gpio+7) = 1<<(g) /* sets bit which are 1, ignores bit which are 0 */
|
|
||||||
#define GPIO_CLR(g) *(gpio+10) = 1<<(g) /* clears bit which are 1, ignores bit which are 0 */
|
|
||||||
#define GPIO_LEV(g) (*(gpio+13) >> (g)) & 0x00000001
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define GPIO_4 4
|
|
||||||
|
|
||||||
int mem_fd;
|
|
||||||
void *gpio_map;
|
|
||||||
volatile uint32_t *gpio;
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int i;
|
|
||||||
/* open /dev/mem */
|
|
||||||
mem_fd = open("/dev/mem", O_RDWR|O_SYNC);
|
|
||||||
if (mem_fd == -1) {
|
|
||||||
perror("Cannot open /dev/mem");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* mmap GPIO */
|
|
||||||
gpio_map = mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, GPIO_BASE);
|
|
||||||
if (gpio_map == MAP_FAILED) {
|
|
||||||
perror("mmap() failed");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
/* Always use volatile pointer! */
|
|
||||||
gpio = (volatile uint32_t *)gpio_map;
|
|
||||||
|
|
||||||
|
|
||||||
GPIO_IN(GPIO_4); /* must use GPIO_IN before we can use GPIO_OUT */
|
|
||||||
GPIO_OUT(GPIO_4);
|
|
||||||
|
|
||||||
//Turn on led
|
|
||||||
while (1) {
|
|
||||||
//printf("Enable LED\n");
|
|
||||||
GPIO_SET(GPIO_4);
|
|
||||||
usleep(1000000);
|
|
||||||
//printf("Disable GPIO\n"); // Does not seem to work?
|
|
||||||
//GPIO_CLR(GPIO_4);
|
|
||||||
//usleep(1000000);
|
|
||||||
}
|
|
||||||
/* Free up ressources */
|
|
||||||
/* munmap GPIO */
|
|
||||||
ret = munmap(gpio_map, BLOCK_SIZE);
|
|
||||||
if (ret == -1) {
|
|
||||||
perror("munmap() failed");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
/* close /dev/mem */
|
|
||||||
ret = close(mem_fd);
|
|
||||||
if (ret == -1) {
|
|
||||||
perror("Cannot close /dev/mem");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
# /etc/pmount.allow
|
# /etc/pmount.allow
|
||||||
# pmount will allow users to additionally mount all devices that are
|
# pmount will allow users to additionally mount all devices that are
|
||||||
# listed here.
|
# listed here.
|
||||||
/dev/sdb1
|
/dev/sdb*
|
||||||
/dev/sda*
|
/dev/sda*
|
||||||
|
|
|
@ -11,27 +11,28 @@
|
||||||
#
|
#
|
||||||
# By default this script does nothing.
|
# By default this script does nothing.
|
||||||
#
|
#
|
||||||
# The above are the default comments for rc.local. For Circlean, rc.local has
|
## The above are the default comments for rc.local. For Circlean, rc.local has
|
||||||
# been modified to start the grooming process on boot.
|
## been modified to start the grooming process after booting.
|
||||||
|
|
||||||
clean(){
|
clean(){
|
||||||
echo 'Rc Local done, quit.'
|
echo "GROOMER: rc.local done, shutting down."
|
||||||
/sbin/shutdown -P -h now
|
/sbin/shutdown -P -h now
|
||||||
}
|
}
|
||||||
|
|
||||||
# Print the IP address
|
echo "GROOMER: end of boot, running rc.local."
|
||||||
_IP=$(hostname -I) || true
|
|
||||||
if [ "$_IP" ]; then
|
# Print the IP address (this doesn't work currently?)
|
||||||
printf "My IP address is %s\n" "$_IP"
|
# _IP=$(hostname -I) || true
|
||||||
fi
|
# if [ "$_IP" ]; then
|
||||||
|
# printf "My IP address is %s\n" "$_IP"
|
||||||
|
# fi
|
||||||
|
|
||||||
if [ -e /dev/sda ]; then
|
if [ -e /dev/sda ]; then
|
||||||
if [ -e /dev/sdb ]; then
|
if [ -e /dev/sdb ]; then
|
||||||
# avoid possible misuse
|
# Avoid possible misuse - turn off eth0 (ethernet port)
|
||||||
/sbin/ifconfig eth0 down
|
/sbin/ifconfig eth0 down
|
||||||
trap clean EXIT TERM INT
|
trap clean EXIT TERM INT
|
||||||
cd /opt/groomer
|
cd /opt/groomer
|
||||||
/usr/sbin/led &
|
|
||||||
./init.sh
|
./init.sh
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
# The purpose of this rules file is to ensure that the top left usb port and its partitions have a symlink to /dev/source_key[num], and the other ports to /dev/dest_key[num]
|
||||||
|
KERNEL=="sd*", KERNELS=="1-1.2", SUBSYSTEMS=="usb", SYMLINK+="source_key%n"
|
||||||
|
KERNEL=="sd*", KERNELS=="1-1.[3-5]", SUBSYSTEMS=="usb", SYMLINK+="dest_key%n"
|
|
@ -1,2 +1,5 @@
|
||||||
|
# This udev rule is designed to make the hardware appear more like the actual raspi hardware when emulating in Qemu. You might have to change sdc to sda or sdb depending on where the filesystem you are emulating is available from in /dev/.
|
||||||
|
# See http://pub.phyks.me/respawn/mypersonaldata/public/2014-05-20-11-08-01/ for more info.
|
||||||
KERNEL=="sdc", SYMLINK+="mmcblk0"
|
KERNEL=="sdc", SYMLINK+="mmcblk0"
|
||||||
KERNEL=="sdc?", SYMLINK+="mmcblk0p%n",
|
KERNEL=="sdc?", SYMLINK+="mmcblk0p%n",
|
||||||
|
#KERNEL=="sdc2", SYMLINK+="root"
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
USERNAME="kitten"
|
||||||
|
ID=`/usr/bin/id -u`
|
||||||
|
|
||||||
|
|
||||||
|
# Paths used in multiple scripts
|
||||||
|
SRC="src"
|
||||||
|
DEV_SRC="/dev/source_key"
|
||||||
|
SRC_MNT="/media/src"
|
||||||
|
|
||||||
|
DST="dst"
|
||||||
|
DEV_DST="/dev/dest_key"
|
||||||
|
DST_MNT="/media/dst"
|
||||||
|
|
||||||
|
TEMP="${DST_MNT}/temp"
|
||||||
|
ZIPTEMP="${DST_MNT}/ziptemp"
|
||||||
|
LOGS="${DST_MNT}/logs"
|
||||||
|
GROOM_LOG="/tmp/groom_log.txt"
|
||||||
|
MUSIC="/opt/midi/"
|
||||||
|
|
||||||
|
|
||||||
|
# Commands
|
||||||
|
SYNC="/bin/sync"
|
||||||
|
TIMIDITY="/usr/bin/timidity"
|
||||||
|
MOUNT="/bin/mount"
|
||||||
|
PMOUNT="/usr/bin/pmount -A -s"
|
||||||
|
PUMOUNT="/usr/bin/pumount"
|
|
@ -1,23 +0,0 @@
|
||||||
DEV_SRC='/dev/sda'
|
|
||||||
DEV_DST='sdb1'
|
|
||||||
|
|
||||||
# User allowed to do the following commands without password
|
|
||||||
USERNAME='kitten'
|
|
||||||
MUSIC="/opt/midi/"
|
|
||||||
|
|
||||||
ID=`/usr/bin/id -u`
|
|
||||||
|
|
||||||
# Paths used in multiple scripts
|
|
||||||
SRC="src"
|
|
||||||
DST="dst"
|
|
||||||
TEMP="/media/${DST}/temp"
|
|
||||||
ZIPTEMP="/media/${DST}/ziptemp"
|
|
||||||
LOGS="/media/${DST}/logs"
|
|
||||||
|
|
||||||
|
|
||||||
# commands
|
|
||||||
SYNC='/bin/sync'
|
|
||||||
TIMIDITY='/usr/bin/timidity'
|
|
||||||
MOUNT='/bin/mount'
|
|
||||||
PMOUNT='/usr/bin/pmount -A -s'
|
|
||||||
PUMOUNT='/usr/bin/pumount'
|
|
|
@ -1,112 +1,75 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# set -e (exit when a line returns non-0 status) and -x (xtrace) flags
|
||||||
set -e
|
set -e
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
source ./constraint.sh
|
# Import constants from config file
|
||||||
|
source ./config.sh
|
||||||
|
|
||||||
if ! [ "${ID}" -ge "1000" ]; then
|
if ! [ "${ID}" -ge "1000" ]; then
|
||||||
echo "This script cannot run as root."
|
echo "GROOMER: groomer.sh cannot run as root."
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
clean(){
|
clean(){
|
||||||
echo Cleaning.
|
# Write anything in memory to disk
|
||||||
${SYNC}
|
${SYNC}
|
||||||
|
|
||||||
# Cleanup source
|
# Remove temporary files from destination key
|
||||||
pumount ${SRC}
|
|
||||||
|
|
||||||
# Cleanup destination
|
|
||||||
rm -rf ${TEMP}
|
rm -rf ${TEMP}
|
||||||
rm -rf ${ZIPTEMP}
|
rm -rf ${ZIPTEMP}
|
||||||
pumount ${DST}
|
|
||||||
|
|
||||||
exit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trap clean EXIT TERM INT
|
trap clean EXIT TERM INT
|
||||||
|
|
||||||
# De we have a source device
|
# Find the partition names on the device available at /dev/source_key
|
||||||
if [ ! -b ${DEV_SRC} ]; then
|
|
||||||
echo "Source device (${DEV_SRC}) does not exists."
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
# Find the partition names on the source device
|
|
||||||
DEV_PARTITIONS=`ls "${DEV_SRC}"* | grep "${DEV_SRC}[1-9][0-6]*" || true`
|
DEV_PARTITIONS=`ls "${DEV_SRC}"* | grep "${DEV_SRC}[1-9][0-6]*" || true`
|
||||||
if [ -z "${DEV_PARTITIONS}" ]; then
|
if [ -z "${DEV_PARTITIONS}" ]; then
|
||||||
echo "${DEV_SRC} does not have any partitions."
|
echo "GROOMER: ${DEV_SRC} does not have any partitions."
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Do we have a destination device
|
|
||||||
if [ ! -b "/dev/${DEV_DST}" ]; then
|
|
||||||
echo "Destination device (/dev/${DEV_DST}) does not exists."
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# mount and prepare destination device
|
|
||||||
if ${MOUNT}|grep ${DST}; then
|
|
||||||
${PUMOUNT} ${DST} || true
|
|
||||||
fi
|
|
||||||
# uid= only works on a vfat FS. What should wedo if we get an ext* FS ?
|
|
||||||
${PMOUNT} -w ${DEV_DST} ${DST}
|
|
||||||
if [ ${?} -ne 0 ]; then
|
|
||||||
echo "Unable to mount /dev/${DEV_DST} on /media/${DST}"
|
|
||||||
exit
|
|
||||||
else
|
|
||||||
echo "Target USB device (/dev/${DEV_DST}) mounted at /media/${DST}"
|
|
||||||
rm -rf "/media/${DST}/FROM_PARTITION_"*
|
|
||||||
|
|
||||||
# prepare temp dirs and make sure it's empty
|
|
||||||
mkdir -p "${TEMP}"
|
|
||||||
mkdir -p "${ZIPTEMP}"
|
|
||||||
mkdir -p "${LOGS}"
|
|
||||||
|
|
||||||
rm -rf "${TEMP}/"*
|
|
||||||
rm -rf "${ZIPTEMP}/"*
|
|
||||||
rm -rf "${LOGS}/"*
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Groom da kitteh!
|
|
||||||
|
|
||||||
# Find the FS types
|
|
||||||
# lsblk -n -o name,fstype,mountpoint,label,uuid -r
|
|
||||||
|
|
||||||
PARTCOUNT=1
|
PARTCOUNT=1
|
||||||
for partition in ${DEV_PARTITIONS}
|
for partition in ${DEV_PARTITIONS}
|
||||||
do
|
do
|
||||||
# Processing a partition
|
echo "GROOMER: Processing partition ${partition}"
|
||||||
echo "Processing partition: ${partition}"
|
# Unmount anything that is mounted on /media/src
|
||||||
if [ `${MOUNT} | grep -c ${SRC}` -ne 0 ]; then
|
if [ `${MOUNT} | grep -c ${SRC}` -ne 0 ]; then
|
||||||
${PUMOUNT} ${SRC}
|
${PUMOUNT} ${SRC}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Mount the current partition in write mode
|
||||||
${PMOUNT} -w ${partition} ${SRC}
|
${PMOUNT} -w ${partition} ${SRC}
|
||||||
ls "/media/${SRC}" | grep -i autorun.inf | xargs -I {} mv "/media/${SRC}"/{} "/media/${SRC}"/DANGEROUS_{}_DANGEROUS || true
|
# Mark any autorun.inf files as dangerous on the source device
|
||||||
|
ls ${SRC_MNT} | grep -i autorun.inf | xargs -I {} mv "${SRC_MNT}"/{} "{SRC_MNT}"/DANGEROUS_{}_DANGEROUS || true
|
||||||
|
# Unmount and remount the current partition in read-only mode
|
||||||
${PUMOUNT} ${SRC}
|
${PUMOUNT} ${SRC}
|
||||||
${PMOUNT} -r ${partition} ${SRC}
|
${PMOUNT} -r ${partition} ${SRC}
|
||||||
if [ ${?} -ne 0 ]; then
|
if [ ${?} -ne 0 ]; then
|
||||||
echo "Unable to mount ${partition} on /media/${SRC}"
|
# Previous command (mounting current partition) failed
|
||||||
|
echo "GROOMER: Unable to mount ${partition} on /media/${SRC}"
|
||||||
else
|
else
|
||||||
echo "${partition} mounted at /media/${SRC}"
|
echo "GROOMER: ${partition} mounted at /media/${SRC}"
|
||||||
|
|
||||||
# Print the filenames on the current partition in a logfile
|
# Put the filenames from the current partition in a logfile
|
||||||
find "/media/${SRC}" -fls "${LOGS}/Content_partition_${PARTCOUNT}.txt"
|
find "/media/${SRC}" -fls "${LOGS}/contents_partition_${PARTCOUNT}.txt"
|
||||||
|
|
||||||
# create a directory on ${DST} named PARTION_$PARTCOUNT
|
# Create a directory on ${DST} named PARTION_$PARTCOUNT
|
||||||
target_dir="/media/${DST}/FROM_PARTITION_${PARTCOUNT}"
|
target_dir="/media/${DST}/FROM_PARTITION_${PARTCOUNT}"
|
||||||
echo "copying to: ${target_dir}"
|
|
||||||
mkdir -p "${target_dir}"
|
mkdir -p "${target_dir}"
|
||||||
LOGFILE="${LOGS}/processing.txt"
|
LOGFILE="${LOGS}/processing.txt"
|
||||||
|
|
||||||
|
# Run the current partition through filecheck.py
|
||||||
echo "==== Starting processing of /media/${SRC} to ${target_dir}. ====" >> ${LOGFILE}
|
echo "==== Starting processing of /media/${SRC} to ${target_dir}. ====" >> ${LOGFILE}
|
||||||
filecheck.py --source /media/${SRC} --destination ${target_dir} || true
|
filecheck.py --source /media/${SRC} --destination ${target_dir} || true
|
||||||
echo "==== Done with /media/${SRC} to ${target_dir}. ====" >> ${LOGFILE}
|
echo "==== Done with /media/${SRC} to ${target_dir}. ====" >> ${LOGFILE}
|
||||||
|
|
||||||
|
# List destination files (recursively) for debugging
|
||||||
ls -lR "${target_dir}"
|
ls -lR "${target_dir}"
|
||||||
fi
|
fi
|
||||||
let PARTCOUNT=`expr $PARTCOUNT + 1`
|
let PARTCOUNT=`expr $PARTCOUNT + 1`
|
||||||
done
|
done
|
||||||
|
|
||||||
# The cleanup is automatically done in the function clean called when
|
# The cleanup is automatically done in the function clean called when
|
||||||
# the program quits
|
# the program exits
|
||||||
|
|
|
@ -1,26 +1,36 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# set -e (exit when a line returns non-0 status) and -x (xtrace) flags
|
||||||
set -e
|
set -e
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
source ./constraint.sh
|
# Import constants from config file
|
||||||
|
source ./config.sh
|
||||||
|
|
||||||
if [ ${ID} -ne 0 ]; then
|
if [ ${ID} -ne 0 ]; then
|
||||||
echo "This script has to be run as root."
|
echo "GROOMER: This script has to be run as root."
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
clean(){
|
clean(){
|
||||||
echo Done, cleaning.
|
echo "GROOMER: cleaning up after init.sh."
|
||||||
${SYNC}
|
${SYNC}
|
||||||
|
# Stop the music from playing
|
||||||
kill -9 $(cat /tmp/music.pid)
|
kill -9 $(cat /tmp/music.pid)
|
||||||
rm -f /tmp/music.pid
|
rm -f /tmp/music.pid
|
||||||
}
|
}
|
||||||
|
|
||||||
trap clean EXIT TERM INT
|
trap clean EXIT TERM INT
|
||||||
|
|
||||||
|
# Stop hdmi display from sleeping after a period of time
|
||||||
|
setterm -powersave off -blank 0
|
||||||
|
|
||||||
|
# Start music
|
||||||
./music.sh &
|
./music.sh &
|
||||||
echo $! > /tmp/music.pid
|
echo $! > /tmp/music.pid
|
||||||
|
|
||||||
su ${USERNAME} -c ./groomer.sh
|
# List block storage devices for debugging
|
||||||
|
# Make sure to set tee in append (-a) mode below if you uncomment
|
||||||
|
# lsblk |& tee ${GROOM_LOG}
|
||||||
|
|
||||||
|
su ${USERNAME} -c ./mount_dest.sh |& tee ${GROOM_LOG}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# set -e (exit when a line returns non-0 status) and -x (xtrace) flags
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
# Import constants from config file
|
||||||
|
source ./config.sh
|
||||||
|
|
||||||
|
if ! [ "${ID}" -ge "1000" ]; then
|
||||||
|
echo "GROOMER: mount_keys.sh cannot run as root."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
clean(){
|
||||||
|
echo "GROOMER: Cleaning up in mount_keys.sh."
|
||||||
|
|
||||||
|
# Copy the temporary logfile to the destination key
|
||||||
|
cp ${GROOM_LOG} "${DST_MNT}/groomer_log_dst.txt"
|
||||||
|
|
||||||
|
# Write anything in memory to disk
|
||||||
|
${SYNC}
|
||||||
|
|
||||||
|
# Unmount source and destination
|
||||||
|
pumount ${SRC}
|
||||||
|
|
||||||
|
# Clean up and unmount destination
|
||||||
|
pumount ${DST}
|
||||||
|
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
trap clean EXIT TERM INT
|
||||||
|
|
||||||
|
# Check that a device is available on /dev/source_key (symlinked to /dev/sda or sdb)
|
||||||
|
if [ ! -b ${DEV_SRC} ]; then
|
||||||
|
echo "GROOMER: Source device (${DEV_SRC}) does not exist."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check that a device is available on /dev/dest_key (symlinked to /dev/sda or sdb)
|
||||||
|
if [ ! -b ${DEV_DST} ]; then
|
||||||
|
echo "GROOMER: Destination device (${DEV_DST}) does not exist."
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If there is already a device mounted on /media/dst, unmount it
|
||||||
|
if ${MOUNT}|grep ${DST}; then
|
||||||
|
${PUMOUNT} ${DST} || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# uid= only works on a vfat FS. What should wedo if we get an ext* FS ?
|
||||||
|
# What does this ^ comment mean?
|
||||||
|
|
||||||
|
# Mount the first partition of DST (/dev/dest_key1)
|
||||||
|
# pmount automatically mounts on /media/ (at /media/dst in this case).
|
||||||
|
${PMOUNT} -w "${DEV_DST}1" ${DST}
|
||||||
|
if [ ${?} -ne 0 ]; then
|
||||||
|
echo "GROOMER: Unable to mount ${DEV_DST}1 on ${DST_MNT}"
|
||||||
|
exit
|
||||||
|
else
|
||||||
|
echo "GROOMER: Destination USB device (${DEV_DST}1) mounted at ${DST_MNT}"
|
||||||
|
|
||||||
|
# Remove any existing "FROM_PARTITION_" directories
|
||||||
|
rm -rf "/media/${DST}/FROM_PARTITION_"*
|
||||||
|
|
||||||
|
# Prepare temp dirs and make sure they're empty if they already exist
|
||||||
|
mkdir -p "${TEMP}"
|
||||||
|
mkdir -p "${ZIPTEMP}"
|
||||||
|
mkdir -p "${LOGS}"
|
||||||
|
rm -rf "${TEMP}/"*
|
||||||
|
rm -rf "${ZIPTEMP}/"*
|
||||||
|
rm -rf "${LOGS}/"*
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Now that destination is mounted and prepared, run the groomer
|
||||||
|
./groomer.sh
|
|
@ -3,7 +3,7 @@
|
||||||
set -e
|
set -e
|
||||||
#set -x
|
#set -x
|
||||||
|
|
||||||
source ./constraint.sh
|
source ./config.sh
|
||||||
|
|
||||||
killed(){
|
killed(){
|
||||||
echo 'Music stopped.'
|
echo 'Music stopped.'
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
ledBtn: ledBtn.c
|
|
||||||
gcc -o ledBtn ledBtn.c
|
|
|
@ -1,282 +0,0 @@
|
||||||
/***************************************************************************************/
|
|
||||||
/* */
|
|
||||||
/* file : ledBtn.c */
|
|
||||||
/* */
|
|
||||||
/* synopsis : */
|
|
||||||
/* the compiled code should be ran with root privileges to allow for access to */
|
|
||||||
/* the GPIO pins through direct GPIO register manipulation in C-code. */
|
|
||||||
/* After initialization, the code update the LEDs status according to the commands */
|
|
||||||
/* passed on std input (using a pipe). */
|
|
||||||
/* It also monitors the push-button and triggers a reboot sequence */
|
|
||||||
/* when it is depressed. */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* This code is based on examples from */
|
|
||||||
/* http://elinux.org/RPi_Low-level_peripherals#C */
|
|
||||||
/* How to access GPIO registers from C-code on the Raspberry-Pi, Example program */
|
|
||||||
/* Dom and Gert, 15-January-2012, Revised: 15-Feb-2013 */
|
|
||||||
/* */
|
|
||||||
/* and from Raphael Vinot (CIRCL.lu) */
|
|
||||||
/* */
|
|
||||||
/* v 1.00 - 22/02/2015 - initial release (Marc Durvaux) */
|
|
||||||
/* v 1.10 - 27/02/2015 - added 'z' command for debugging, improved handling of */
|
|
||||||
/* concateneted command sequences */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/***************************************************************************************/
|
|
||||||
|
|
||||||
// Includes
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
// Constant for low-level access to GPIO
|
|
||||||
#define BCM2708_PERI_BASE 0x20000000
|
|
||||||
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
|
|
||||||
#define BLOCK_SIZE (4*1024)
|
|
||||||
|
|
||||||
// global variables related to GPIO
|
|
||||||
int mem_fd ;
|
|
||||||
void *gpio_map ;
|
|
||||||
volatile unsigned *gpio ; // I/O access
|
|
||||||
|
|
||||||
// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
|
|
||||||
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
|
|
||||||
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
|
|
||||||
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
|
|
||||||
|
|
||||||
#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0
|
|
||||||
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
|
|
||||||
|
|
||||||
#define GET_GPIO(g) (*(gpio+13)&(1<<g)) // 0 if LOW, (1<<g) if HIGH
|
|
||||||
|
|
||||||
#define GPIO_PULL *(gpio+37) // Pull up/pull down
|
|
||||||
#define GPIO_PULLCLK0 *(gpio+38) // Pull up/pull down clock
|
|
||||||
|
|
||||||
// LED and push-button GPIO pin mapping (from schematic)
|
|
||||||
#define GREEN_LED 17
|
|
||||||
#define YELLOW_LED 18
|
|
||||||
#define RED_LED 22
|
|
||||||
#define PUSHBUTTON 23
|
|
||||||
|
|
||||||
// Time tic (in nsec) for loops : 10 ms
|
|
||||||
#define TIME_TIC 10000000L
|
|
||||||
// Blink half-period in tics
|
|
||||||
#define MAX_COUNT 30
|
|
||||||
// Button long pression threshold
|
|
||||||
#define LONG_PUSH 300
|
|
||||||
|
|
||||||
|
|
||||||
// forward declaration of functions
|
|
||||||
void setup_io() ;
|
|
||||||
void do_reboot() ;
|
|
||||||
|
|
||||||
/***************************************************************************************/
|
|
||||||
//
|
|
||||||
// main
|
|
||||||
// input : path and name of the FIFO must be passed as 1st argument
|
|
||||||
//
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
int fd, nbytes ;
|
|
||||||
int state, count, repeat_count ;
|
|
||||||
int Btn_state, Btn_prev_state, Btn_press_count ;
|
|
||||||
char code ;
|
|
||||||
|
|
||||||
state = 0 ; // initialize state variable
|
|
||||||
count = 0 ; // initialize loop counter
|
|
||||||
repeat_count = 0 ;
|
|
||||||
code = 0 ;
|
|
||||||
|
|
||||||
setup_io() ; // initialize GPIO pointer and GPIO pins
|
|
||||||
Btn_state = GET_GPIO( PUSHBUTTON) ; // get push-button initial state
|
|
||||||
Btn_prev_state = Btn_state ;
|
|
||||||
Btn_press_count = 0 ;
|
|
||||||
|
|
||||||
fd = open(argv[1], O_RDONLY) ;
|
|
||||||
if (fd < 0) {
|
|
||||||
perror("open") ;
|
|
||||||
exit (2) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
Btn_state = GET_GPIO( PUSHBUTTON) ;
|
|
||||||
if (Btn_state != 0) { // button released
|
|
||||||
Btn_press_count = 0 ; // reset counter
|
|
||||||
} else { // button pressed
|
|
||||||
Btn_press_count++ ;
|
|
||||||
if (Btn_state != Btn_prev_state) {
|
|
||||||
//printf("Button pressed!\n");
|
|
||||||
if (state >= 4) { // final state, immediate reboot
|
|
||||||
close(fd) ;
|
|
||||||
do_reboot() ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Btn_press_count == LONG_PUSH) { // trigger forced reboot
|
|
||||||
state = 10 ; // LED animation before reboot
|
|
||||||
repeat_count = 0 ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Btn_prev_state = Btn_state ;
|
|
||||||
|
|
||||||
nbytes = read(fd, &code, 1) ;
|
|
||||||
if (nbytes < 0) {
|
|
||||||
perror("read") ;
|
|
||||||
exit (2) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbytes > 0) {
|
|
||||||
switch (code) { // codes evaluated at every tic
|
|
||||||
case 'z' : // clear without restart (for debugging)
|
|
||||||
GPIO_CLR = 1<<GREEN_LED ;
|
|
||||||
GPIO_CLR = 1<<YELLOW_LED ;
|
|
||||||
GPIO_CLR = 1<<RED_LED ;
|
|
||||||
state = 0 ;
|
|
||||||
break ;
|
|
||||||
case 'r' : // Ready
|
|
||||||
GPIO_SET = 1<<GREEN_LED ;
|
|
||||||
state = 1 ;
|
|
||||||
break ;
|
|
||||||
case 'p' : // Processing
|
|
||||||
GPIO_CLR = 1<<GREEN_LED ;
|
|
||||||
GPIO_SET = 1<<YELLOW_LED ;
|
|
||||||
state = 2 ;
|
|
||||||
break ;
|
|
||||||
case 'e' : // Error (process aborted)
|
|
||||||
GPIO_CLR = 1<<GREEN_LED ;
|
|
||||||
GPIO_CLR = 1<<YELLOW_LED ;
|
|
||||||
GPIO_SET = 1<<RED_LED ;
|
|
||||||
state = 6 ;
|
|
||||||
break ;
|
|
||||||
case 'c' : // task successfully completed
|
|
||||||
GPIO_CLR = 1<<YELLOW_LED ;
|
|
||||||
GPIO_SET = 1<<GREEN_LED ;
|
|
||||||
state = 4 ;
|
|
||||||
count = 0 ;
|
|
||||||
break ;
|
|
||||||
case 'f' : // file processing successfully completed
|
|
||||||
GPIO_SET = 1<<GREEN_LED ;
|
|
||||||
state = 3 ;
|
|
||||||
count = 0 ;
|
|
||||||
break ;
|
|
||||||
} // end switch
|
|
||||||
}
|
|
||||||
|
|
||||||
count++ ;
|
|
||||||
if (count >= MAX_COUNT) {
|
|
||||||
count = 0 ;
|
|
||||||
|
|
||||||
switch (state) { // states evaluated after MAX_COUNT tics
|
|
||||||
case 3 : // green LED flash OFF
|
|
||||||
GPIO_CLR = 1<<GREEN_LED ;
|
|
||||||
state = 2 ;
|
|
||||||
break ;
|
|
||||||
case 4 : // green LED blinks OFF
|
|
||||||
GPIO_CLR = 1<<GREEN_LED ;
|
|
||||||
state = 5 ;
|
|
||||||
break ;
|
|
||||||
case 5 : // green LED blinks ON
|
|
||||||
GPIO_SET = 1<<GREEN_LED ;
|
|
||||||
state = 4 ;
|
|
||||||
break ;
|
|
||||||
case 10 : // start LED animation before reboot
|
|
||||||
GPIO_SET = 1<<GREEN_LED ;
|
|
||||||
GPIO_SET = 1<<YELLOW_LED ;
|
|
||||||
GPIO_SET = 1<<RED_LED ;
|
|
||||||
state = 11 ;
|
|
||||||
break ;
|
|
||||||
case 11 : // LED animation before reboot
|
|
||||||
GPIO_CLR = 1<<GREEN_LED ;
|
|
||||||
GPIO_CLR = 1<<YELLOW_LED ;
|
|
||||||
GPIO_CLR = 1<<RED_LED ;
|
|
||||||
repeat_count++ ;
|
|
||||||
if (repeat_count > 5) {
|
|
||||||
state = 12 ;
|
|
||||||
} else {
|
|
||||||
state = 10 ;
|
|
||||||
}
|
|
||||||
break ;
|
|
||||||
case 12 : // proceed with reboot
|
|
||||||
close(fd) ;
|
|
||||||
do_reboot() ;
|
|
||||||
break ;
|
|
||||||
} // end switch
|
|
||||||
} // end if
|
|
||||||
|
|
||||||
// loop delay
|
|
||||||
nanosleep((struct timespec[]){{0, TIME_TIC}}, NULL) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0 ; // we should never come here!
|
|
||||||
} // main
|
|
||||||
|
|
||||||
/***************************************************************************************/
|
|
||||||
//
|
|
||||||
// Set up a memory region to access GPIO
|
|
||||||
//
|
|
||||||
void setup_io() {
|
|
||||||
/* open /dev/mem */
|
|
||||||
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
|
|
||||||
printf("can't open /dev/mem \n");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* mmap GPIO */
|
|
||||||
gpio_map = mmap(
|
|
||||||
NULL, //Any adddress in our space will do
|
|
||||||
BLOCK_SIZE, //Map length
|
|
||||||
PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
|
|
||||||
MAP_SHARED, //Shared with other processes
|
|
||||||
mem_fd, //File to map
|
|
||||||
GPIO_BASE //Offset to GPIO peripheral
|
|
||||||
);
|
|
||||||
|
|
||||||
close(mem_fd); //No need to keep mem_fd open after mmap
|
|
||||||
|
|
||||||
if (gpio_map == MAP_FAILED) {
|
|
||||||
printf("mmap error %d\n", (int)gpio_map);//errno also set!
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always use volatile pointer!
|
|
||||||
gpio = (volatile unsigned *)gpio_map ;
|
|
||||||
|
|
||||||
// initializes the LED and push-button pins
|
|
||||||
INP_GPIO( GREEN_LED) ; // must use INP_GPIO before we can use OUT_GPIO
|
|
||||||
OUT_GPIO( GREEN_LED) ;
|
|
||||||
INP_GPIO( YELLOW_LED) ;
|
|
||||||
OUT_GPIO( YELLOW_LED) ;
|
|
||||||
INP_GPIO( RED_LED) ;
|
|
||||||
OUT_GPIO( RED_LED) ;
|
|
||||||
INP_GPIO( PUSHBUTTON) ;
|
|
||||||
|
|
||||||
// initializes LEDs to OFF state
|
|
||||||
GPIO_CLR = 1<<GREEN_LED ;
|
|
||||||
GPIO_CLR = 1<<YELLOW_LED ;
|
|
||||||
GPIO_CLR = 1<<RED_LED ;
|
|
||||||
|
|
||||||
} // setup_io
|
|
||||||
|
|
||||||
/***************************************************************************************/
|
|
||||||
//
|
|
||||||
// Call system reboot
|
|
||||||
//
|
|
||||||
void do_reboot() {
|
|
||||||
static char *execArgv[5] ; /* define arguments for shutdown exec */
|
|
||||||
|
|
||||||
execArgv[0] = "shutdown" ;
|
|
||||||
execArgv[1] = "-r" ;
|
|
||||||
execArgv[2] = "now" ;
|
|
||||||
execArgv[3] = NULL ;
|
|
||||||
|
|
||||||
//printf("going to reboot!\n") ;
|
|
||||||
execv("/sbin/shutdown", execArgv) ;
|
|
||||||
} // do_reboot
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*** END OF FILE ***********************************************************************/
|
|
|
@ -1,27 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
FIFO="/tmp/ledBtnFIFO"
|
|
||||||
#mkfifo $FIFO
|
|
||||||
|
|
||||||
#sudo ./ledBtn $FIFO
|
|
||||||
|
|
||||||
# send command "READY"
|
|
||||||
echo "r" > $FIFO
|
|
||||||
#sleep 1
|
|
||||||
# send command "PROCESSING"
|
|
||||||
echo "p" > $FIFO
|
|
||||||
sleep 1
|
|
||||||
# send command "FILE processed"
|
|
||||||
echo "f" > $FIFO
|
|
||||||
sleep 3
|
|
||||||
# send command "FILE processed"
|
|
||||||
echo "f" > $FIFO
|
|
||||||
sleep 3
|
|
||||||
# send command "processing successfully COMPLETED"
|
|
||||||
echo "c" > $FIFO
|
|
||||||
sleep 2
|
|
||||||
# send command "ZERO (clear display and return state to 0)"
|
|
||||||
echo "z" > $FIFO
|
|
||||||
sleep 2
|
|
||||||
# send command "ERROR"
|
|
||||||
echo "e" > $FIFO
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -x
|
||||||
|
|
||||||
|
# cp /media/sf_ubuntu-shared/Circlean-Ubuntu/fs_filecheck/opt/groomer/init.sh /mnt/rpi/opt/groomer/init.sh
|
||||||
|
# cp /media/sf_ubuntu-shared/Circlean-Ubuntu/fs_filecheck/opt/groomer/groomer.sh /mnt/rpi/opt/groomer/groomer.sh
|
||||||
|
# cp /media/sf_ubuntu-shared/Circlean-Ubuntu/fs_filecheck/opt/groomer/config.sh /mnt/rpi/opt/groomer/config.sh
|
||||||
|
# cp /media/sf_ubuntu-shared/Circlean-Ubuntu/fs_filecheck/opt/groomer/mount_dest.sh /mnt/rpi/opt/groomer/mount_dest.sh
|
||||||
|
# cp /media/sf_ubuntu-shared/Circlean-Ubuntu/fs_filecheck/opt/groomer/music.sh /mnt/rpi/opt/groomer/music.sh
|
||||||
|
# cp /media/sf_ubuntu-shared/Circlean-Ubuntu/fs_filecheck/etc/rc.local /mnt/rpi/etc/rc.local
|
||||||
|
# cp /media/sf_ubuntu-shared/Circlean-Ubuntu/fs_filecheck/etc/pmount.allow /mnt/rpi/etc/pmount.allow
|
||||||
|
# cp /media/sf_ubuntu-shared/Circlean-Ubuntu/fs_filecheck/etc/udev/rules.d/10-usb.rules /mnt/rpi/etc/udev/rules.d/10-usb.rules
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
IMAGE='2016-05-12_CIRCLean.img'
|
||||||
|
OFFSET=$((512 * 131072))
|
||||||
|
|
||||||
|
mkdir /mnt/rpi
|
||||||
|
mount -v -o offset=${OFFSET} -t ext4 ${IMAGE} /mnt/rpi
|
Loading…
Reference in New Issue