mirror of https://github.com/CIRCL/Circlean
commit
52ee749a45
|
@ -0,0 +1,50 @@
|
|||
Building the project
|
||||
====================
|
||||
|
||||
To get started contributing to Circlean, first, fork the project and `git clone`
|
||||
your fork. Then, follow the instructions in [README_setup.md](README_setup.md)
|
||||
to build an image.
|
||||
|
||||
The issue tracker
|
||||
=================
|
||||
|
||||
If you find a bug or see a problem with PyCIRCLean, please open an issue in the Github
|
||||
repo. We'll do our best to respond as quickly as possible. Also, feel free to contribute a solution
|
||||
to any of the open issues - we'll do our best to review your pull request in a timely manner.
|
||||
This project is in active development, so any contributions are welcome!
|
||||
|
||||
Running the tests
|
||||
=================
|
||||
|
||||
To emulate the Raspberry Pi hardware for testing, we'll be using
|
||||
[Qemu](http://wiki.qemu.org/Main_Page), an open source machine emulator.
|
||||
The "qemu" package available for Ubuntu/Debian includes all of the required
|
||||
packages (including qemu-system-arm) except for qemu-user-static, which must
|
||||
be installed separately.
|
||||
|
||||
```
|
||||
sudo apt-get install qemu qemu-user-static expect
|
||||
```
|
||||
|
||||
* Get the qemu kernel for the image you are using:
|
||||
|
||||
```
|
||||
pushd tests; wget https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/kernel-qemu; popd
|
||||
```
|
||||
|
||||
* Put some test data from tests/testFiles into tests/content_img_vfat_norm
|
||||
|
||||
* Comment out the other tests in tests/run.sh or populate those directories as
|
||||
well
|
||||
|
||||
* Make sure to set the filename of the image and the kernel in `tests/run.sh`
|
||||
|
||||
* Run the tests:
|
||||
|
||||
```
|
||||
sudo ./run_tests.sh
|
||||
```
|
||||
|
||||
* If the image run processed images correctly but doesn't exit and unmount the
|
||||
images cleanly, look at tests/run.exp and make sure it's waiting for the
|
||||
string your qemu and kernel actually produce.
|
98
README.md
98
README.md
|
@ -6,83 +6,81 @@ CIRCLean
|
|||
How To
|
||||
======
|
||||
|
||||
[Graphical how-to and pre-build image](http://circl.lu/projects/CIRCLean/).
|
||||
[Graphical how-to and pre-built image](http://circl.lu/projects/CIRCLean/).
|
||||
|
||||
To prepare the SD card on Windows, you can use [Win32DiskImager] (http://sourceforge.net/projects/win32diskimager/).
|
||||
To prepare the SD card on Windows, you can use [Win32DiskImager](http://sourceforge.net/projects/win32diskimager/).
|
||||
|
||||
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
|
||||
[contributing](CONTRIBUTING.md) and the [setup readme](README_setup.md).
|
||||
|
||||
Why/What
|
||||
========
|
||||
|
||||
This project aims to be used in case you got an USB key you do not know what is
|
||||
contains but still want to have a look.
|
||||
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
|
||||
main computer directly.
|
||||
|
||||
Work in progress, contributions welcome:
|
||||
This is a work in progress - contributions are welcome:
|
||||
|
||||
The content of the first key will be copyed or/and converted to the second key
|
||||
following theses rules (based on the mime type):
|
||||
- direct copy of plain text files (mime type: text/*)
|
||||
- direct copy of audio files (mime type: audio/*)
|
||||
- direct copy of image files (mime type: image/*)
|
||||
- direct copy of video files (mime type: video/*)
|
||||
- direct copy of example files (mime type: example/*)
|
||||
- direct copy of message files (mime type: message/*)
|
||||
- direct copy of model files (mime type: model/*)
|
||||
- direct copy of multipart files (mime type: multipart/*)
|
||||
- Copying or converting the application files this way (mime type: application/*):
|
||||
- pdf => HTML
|
||||
- msword|vnd.openxmlformats-officedocument.*|vnd.ms-*|vnd.oasis.opendocument* => pdf => html
|
||||
- *xml* => copy as a text file
|
||||
- x-dosexec (executable) => prepend and append DANGEROUS to the filename
|
||||
- x-gzip|x-tar|x-7z-compressed => compressed file
|
||||
- octet-stream => direct copy
|
||||
|
||||
Compressed files (zip|x-rar|x-bzip2|x-lzip|x-lzma|x-lzop|x-xz|x-compress|x-gzip|x-tar|*compressed):
|
||||
- Unpacking of archives
|
||||
- Recursively run the rules on the unpacked files
|
||||
The content of the first key will be copied or/and converted to the second key
|
||||
following these rules (based on the mime type, as determined by libmagic):
|
||||
- Direct copy of:
|
||||
- Plain text files (mime type: text/*)
|
||||
- Audio files (mime type: audio/*)
|
||||
- Video files (mime type: video/*)
|
||||
- Example files (mime type: example/*)
|
||||
- Multipart files (mime type: multipart/*)
|
||||
- *xml* files, after being converted to text files
|
||||
- Octet-stream files
|
||||
- Copied after verification:
|
||||
- Image files after verifying that they are not compression bombs (mime type: image/*)
|
||||
- PDF files, after marking as dangerous if they contain malicious content
|
||||
- msword|vnd.openxmlformats-officedocument.*|vnd.ms-*|vnd.oasis.opendocument*, after
|
||||
parsing with oletools/olefile and marking as dangerous if the parsing fails.
|
||||
- Copied but marked as dangerous (DANGEROUS_filename_DANGEROUS)
|
||||
- Message files (mime type: message/*)
|
||||
- Model files (mime type: model/*)
|
||||
- x-dosexec (executable)
|
||||
- Compressed files (zip|x-rar|x-bzip2|x-lzip|x-lzma|x-lzop|x-xz|x-compress|x-gzip|x-tar|*compressed):
|
||||
- Archives are unpacked, with the unpacking process stopped after 2 levels of archives
|
||||
to prevent archive bombs.
|
||||
- The above rules are applied recursively to the unpacked files.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
0. Power off the device
|
||||
1. Plug the untrusted key in the top usb slot of the Raspberry Pi
|
||||
2. Plug your own key in the bottom usb slot
|
||||
0. Power off the device and unplug all connections.
|
||||
1. Plug the untrusted key in the top USB slot of the Raspberry Pi.
|
||||
2. Plug your own key in the bottom USB slot (or use any of the other slots if
|
||||
there are more than 2).
|
||||
|
||||
*Note*: This key should be bigger than the original one because the archives
|
||||
will be copyed
|
||||
*Note*: This key should be bigger than the original one because any archives
|
||||
present on the source key will be expanded and copied.
|
||||
|
||||
3. Optional: connect the HDMI cable to a screen to see what happen
|
||||
4. Connect the power to the micro USB
|
||||
3. Optional: connect the HDMI cable to a screen to monitor the process.
|
||||
4. Connect the power to the micro USB port.
|
||||
|
||||
*Note*: 5V, 700mA regulated power supply
|
||||
*Note*: Use a 5V, 700mA+ regulated power supply
|
||||
|
||||
5. Wait until you do not see any blinking green light on the board, or if you
|
||||
connected the HDMI cable, check the screen
|
||||
it's slow and can take 30-60 minutes depending on how many document
|
||||
conversions take place
|
||||
6. Power off the device and disconnect the drives
|
||||
connected the HDMI cable, check the screen. The process is slow and can take
|
||||
30-60 minutes depending on how many document conversions take place.
|
||||
6. Power off the device and disconnect the drives.
|
||||
|
||||
Helper scripts
|
||||
==============
|
||||
|
||||
You should use them as example when you are creating a new image and probably not
|
||||
run them blindly as you will most probably have to change constraints accordingly to
|
||||
You should use them as examples when you are creating a new image and probably not
|
||||
run them blindly as you will most probably have to change parameters accordingly to
|
||||
your configuration.
|
||||
|
||||
IN ALL CASES, PLEASE READ THE COMMENTS IN THE SCRIPTS AT LEAST ONCE.
|
||||
|
||||
* proper_chroot.sh: uses qemu to chroot into a raspbian instance (.img or SD Card)
|
||||
* prepare_rPI_builder.sh: update the system, add the repositories and install all
|
||||
the dependencies needed to compile poppler and pdf2htmlEX on a rPi
|
||||
* update_builder.sh: compile the latest version of poppler from debian experimental,
|
||||
pull and compile the latest version of pdf2htmlEX from the git repository
|
||||
* prepare_rPI.sh: update the system, install the dependencies of poppler and pdf2htmlEX,
|
||||
install poppler and pdf2htmlEX (the deb packages compiled in the builder)
|
||||
* prepare_rPI.sh: update the system, some configuration
|
||||
* create_user.sh: create the user who will run the scripts, assign the proper sudo rights.
|
||||
* copy_to_final.sh: populate the content of the directory fs/ in the image,
|
||||
contains a sample of dd command to write the image on the SD card.
|
||||
*TAKE CARE NOT USING THE WRONG DESTINATION*
|
||||
|
||||
|
||||
|
||||
NOTE: TAKE CARE NOT TO USE THE WRONG DESTINATION
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
Install Qemu and Expect
|
||||
============
|
||||
|
||||
Install the necessary packages:
|
||||
|
||||
```
|
||||
sudo apt-get install qemu qemu-user-static expect
|
||||
```
|
||||
|
||||
|
||||
Create a new image from scratch
|
||||
===============================
|
||||
|
||||
* Download the most recent version of Raspbian Jessie lite:
|
||||
https://downloads.raspberrypi.org/raspbian_lite_latest
|
||||
|
||||
* Unpack it:
|
||||
|
||||
```
|
||||
unzip 2016-03-18-raspbian-jessie-lite.zip
|
||||
```
|
||||
|
||||
|
||||
Prepare the image
|
||||
=================
|
||||
|
||||
It will be used for the build environment and the final image.
|
||||
|
||||
* [Add empty space to the image](resize_img.md)
|
||||
|
||||
* Chroot in the image
|
||||
|
||||
```
|
||||
sudo ./proper_chroot.sh
|
||||
```
|
||||
|
||||
* Change your user to root (your global variables may be broken)
|
||||
|
||||
```
|
||||
su root
|
||||
```
|
||||
|
||||
* The locales may be broken, fix it (remove `en_GB.UTF-8 UTF-8`, set `en_US.UTF-8 UTF-8`):
|
||||
|
||||
```
|
||||
dpkg-reconfigure locales
|
||||
```
|
||||
|
||||
* In the image, make sure everything is up-to-date, and remove the old packages
|
||||
|
||||
```
|
||||
apt-get update
|
||||
apt-get dist-upgrade
|
||||
apt-get autoremove
|
||||
apt-get install timidity git p7zip-full python-dev python-pip python-lxml pmount libjpeg-dev libtiff-dev libwebp-dev liblcms2-dev tcl-dev tk-dev python-tk libxml2-dev libxslt1-dev
|
||||
```
|
||||
|
||||
* Install python requirements
|
||||
|
||||
```
|
||||
pip install oletools olefile exifread Pillow
|
||||
pip install git+https://github.com/Rafiot/officedissector.git
|
||||
pip install git+https://github.com/CIRCL/PyCIRCLean.git
|
||||
```
|
||||
|
||||
* Create the user and mtab for a RO filesystem
|
||||
|
||||
```
|
||||
useradd -m kitten
|
||||
chown -R kitten:kitten /home/kitten
|
||||
ln -s /proc/mounts /etc/mtab
|
||||
```
|
||||
|
||||
* Copy the files
|
||||
|
||||
```
|
||||
sudo ./copy_to_final.sh /mnt/arm_rPi/
|
||||
```
|
||||
|
||||
* Enable rc.local
|
||||
|
||||
```
|
||||
systemctl enable rc-local.service
|
||||
```
|
||||
|
|
@ -1,232 +0,0 @@
|
|||
Install Qemu and Expect
|
||||
============
|
||||
|
||||
Install the necessary packages:
|
||||
|
||||
```
|
||||
sudo apt-get install qemu qemu-user-static expect
|
||||
```
|
||||
|
||||
Create a new image from scratch
|
||||
===============================
|
||||
|
||||
* Download the most recent version of Raspbian Jessie lite:
|
||||
https://downloads.raspberrypi.org/raspbian_lite_latest
|
||||
|
||||
* Unpack it:
|
||||
|
||||
```
|
||||
unzip 2016-03-18-raspbian-jessie-lite.zip
|
||||
```
|
||||
|
||||
Prepare the base image
|
||||
======================
|
||||
|
||||
It will be used for the build environment and the final image.
|
||||
|
||||
* [Add empty space to the image](resize_img.md)
|
||||
|
||||
* Chroot in the image
|
||||
|
||||
```
|
||||
sudo ./proper_chroot.sh
|
||||
```
|
||||
|
||||
* Change your user to root (your global variables may be broken)
|
||||
|
||||
```
|
||||
su root
|
||||
```
|
||||
|
||||
* The locales may be broken, fix it (remove `en_GB.UTF-8 UTF-8`, set `en_US.UTF-8 UTF-8`):
|
||||
|
||||
```
|
||||
dpkg-reconfigure locales
|
||||
```
|
||||
|
||||
* In the image, make sure everything is up-to-date, and remove the old packages
|
||||
|
||||
```
|
||||
apt-get update
|
||||
apt-get dist-upgrade
|
||||
apt-get autoremove
|
||||
```
|
||||
|
||||
Setup two images
|
||||
================
|
||||
|
||||
* Create two separate images: one will be used to build the deb packages that are not available in wheezy
|
||||
|
||||
```
|
||||
mv raspbian-wheezy.img BUILDENV-raspbian-wheezy.img
|
||||
cp BUILDENV-raspbian-wheezy.img FINAL-raspbian-wheezy.img
|
||||
```
|
||||
|
||||
Build environment specifics
|
||||
===========================
|
||||
|
||||
* Create a symlink to the build image
|
||||
|
||||
```
|
||||
ln -s BUILDENV-raspbian-wheezy.img raspbian-wheezy.img
|
||||
```
|
||||
|
||||
* Chroot in the image
|
||||
|
||||
```
|
||||
sudo ./proper_chroot.sh
|
||||
```
|
||||
|
||||
* Change your user to root (your global variables may be broken)
|
||||
|
||||
```
|
||||
su root
|
||||
```
|
||||
|
||||
* Add Wheezy backports source packages to build a poppler version compatible with pdf2htmlEX
|
||||
|
||||
```
|
||||
echo 'deb-src http://ftp.debian.org/debian/ wheezy-backports main' >> /etc/apt/sources.list
|
||||
apt-get instal debian-keyring debian-archive-keyring
|
||||
apt-get update
|
||||
```
|
||||
|
||||
* Get the required build dependencies and the sources
|
||||
|
||||
```
|
||||
apt-get build-dep poppler
|
||||
apt-get source poppler
|
||||
```
|
||||
|
||||
* Compile the package
|
||||
|
||||
```
|
||||
cd poppler-<VERSION>/
|
||||
dpkg-buildpackage
|
||||
```
|
||||
At least on Debian 8, you may receive an error about libpoppler-glib-dev missing the gir1.2-poppler requirement; you can ignore it.
|
||||
|
||||
|
||||
* Install the packages required by pdf2htmlEX
|
||||
|
||||
```
|
||||
apt-get install cmake libfontforge-dev libspiro-dev python-dev default-jre-headless
|
||||
cd ..
|
||||
dpkg -i libpoppler-dev* libpoppler* libpoppler-private-dev*
|
||||
```
|
||||
|
||||
* Download the sources of pdf2htmlEX (we cannot use anything newer than v0.11 because fontforge>=2.0 is not available)
|
||||
|
||||
```
|
||||
wget https://github.com/Rafiot/pdf2htmlEX/archive/KittenGroomer.zip
|
||||
unzip KittenGroomer.zip
|
||||
```
|
||||
|
||||
* Compile the package
|
||||
|
||||
```
|
||||
cd pdf2htmlEX-KittenGroomer/
|
||||
dpkg-buildpackage -uc -b
|
||||
```
|
||||
|
||||
* Get the packages out of the building image (run it outside of the chroot)
|
||||
|
||||
```
|
||||
cp /mnt/arm_rPi/libpoppler46_* /mnt/arm_rPi/pdf2htmlex_* deb/
|
||||
```
|
||||
|
||||
Final image specifics
|
||||
=====================
|
||||
|
||||
* Change the link to the image
|
||||
|
||||
```
|
||||
rm raspbian-wheezy.img
|
||||
ln -s FINAL-raspbian-wheezy.img -raspbian-wheezy.img
|
||||
```
|
||||
|
||||
* Chroot in the image
|
||||
|
||||
```
|
||||
sudo ./proper_chroot.sh
|
||||
```
|
||||
|
||||
* Change your user to root (your global variables may be broken)
|
||||
|
||||
```
|
||||
su root
|
||||
```
|
||||
|
||||
* Copy the debian packages into the chroot (run it outside of the chroot)
|
||||
|
||||
```
|
||||
cp deb/*.deb /mnt/arm_rPi/
|
||||
```
|
||||
|
||||
* Install repencencies required by the project
|
||||
|
||||
```
|
||||
apt-get install libreoffice p7zip-full libfontforge1 timidity freepats pmount ntfs-3g unoconv python-pip
|
||||
dpkg -i *.deb
|
||||
pip install twiggy python-magic
|
||||
```
|
||||
|
||||
* Create the user, make Libreoffice and mtab working on a RO filesystem
|
||||
|
||||
```
|
||||
useradd -m kitten
|
||||
pushd /home/kitten
|
||||
ln -s /tmp/libreoffice
|
||||
mkdir .config/
|
||||
ln -s /tmp/libreoffice_config .config/libreoffice
|
||||
popd
|
||||
chown -R kitten:kitten /home/kitten
|
||||
ln -s /proc/mounts /etc/mtab
|
||||
```
|
||||
|
||||
* Copy the script to the image
|
||||
|
||||
```
|
||||
sudo ./copy_to_final.sh
|
||||
```
|
||||
|
||||
* Get the PyCIRCLean modules
|
||||
```
|
||||
pip install git+https://github.com/CIRCL/PyCIRCLean
|
||||
```
|
||||
|
||||
|
||||
* Exit the chroot
|
||||
|
||||
Write the image on a SD card
|
||||
============================
|
||||
|
||||
*WARNING*: Make sure you write on the right filesystem
|
||||
|
||||
```
|
||||
sudo dd bs=4M if=FINAL-raspbian-wheezy.img of=/dev/<FILESYSTEM>
|
||||
```
|
||||
|
||||
Run the tests
|
||||
=============
|
||||
|
||||
* Get the qemu kernel:
|
||||
```
|
||||
pushd tests; wget https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/kernel-qemu; popd
|
||||
```
|
||||
|
||||
* Put some test data from tests/testFiles into tests/content_img_vfat_norm
|
||||
|
||||
* Comment out the other tests in tests/run.sh or populate those directories as
|
||||
well
|
||||
|
||||
* Make sure to set the filename of the image and the kernel in `tests/run.sh`
|
||||
|
||||
* Run the tests:
|
||||
```
|
||||
sudo ./run_tests.sh
|
||||
```
|
||||
|
||||
* If the image run processed images correctly but doesn't exit and unmount the
|
||||
images cleanly, look at tests/run.exp and make sure it's waiting for the
|
||||
string your qemu and kernel actually produce.
|
|
@ -0,0 +1,196 @@
|
|||
Building the image from scratch
|
||||
===============================
|
||||
|
||||
There is always a prebuilt image available for download and installation as
|
||||
described in the [README](README.md). If you'd like to build the project yourself,
|
||||
there are several steps involved:
|
||||
|
||||
* Downloading a generic Raspbian Lite image
|
||||
* Adding space to the image
|
||||
* Downloading and building the dependencies
|
||||
* Copying the project filesystem into the image
|
||||
|
||||
This procedure will only work on Ubuntu or Debian Linux. If you use MacOS or
|
||||
Windows, the best option is to install Linux in a virtual machine using
|
||||
something like VirtualBox.
|
||||
|
||||
Downloading the Raspbian image
|
||||
==============================
|
||||
|
||||
* Get the most recent version of Raspbian Jessie Lite:
|
||||
|
||||
```
|
||||
wget https://downloads.raspberrypi.org/raspbian_lite_latest
|
||||
```
|
||||
|
||||
* Unpack it:
|
||||
|
||||
```
|
||||
unzip XXXX-XX-XX-raspbian-jessie-lite.zip
|
||||
```
|
||||
|
||||
Adding space to the image
|
||||
=========================
|
||||
|
||||
* Use dd to add 2GB (2048 blocks at 1024k each). Using /dev/zero as the input
|
||||
file yields an unlimited number of "0x00" bytes.
|
||||
|
||||
```
|
||||
> dd if=/dev/zero bs=1024k count=2048 >> XXXX-XX-XX-raspbian-jessie-lite.img
|
||||
```
|
||||
|
||||
* Grow the root partition using fdisk. The "p" command prints the current partition
|
||||
table. The first partition listed is the boot partition, which shouldn't be changed.
|
||||
The "d" command, when given the parameter "2", deletes the current root partition.
|
||||
The "n" command then makes a new partition. It can take the default for "type"
|
||||
and "number". The "First sector" should be the value that was the "start" sector of the root
|
||||
partition (131072 in the example below, but this varies depending on the version of the
|
||||
Raspbian image). The "Last sector" should be the default, and it should be significantly
|
||||
larger than it was before (6852607 vs. 2658303 in the example).
|
||||
|
||||
|
||||
```
|
||||
> fdisk XXXX-XX-XX-raspbian-jessie-lite.img
|
||||
|
||||
Command (m for help): *p*
|
||||
Disk XXXX-XX-XX-raspbian-jessie-lite.img: 3.3 GiB, 3508535296 bytes, 6852608 sectors
|
||||
Units: sectors of 1 * 512 = 512 bytes
|
||||
Sector size (logical/physical): 512 bytes / 512 bytes
|
||||
I/O size (minimum/optimal): 512 bytes / 512 bytes
|
||||
Disklabel type: dos
|
||||
Disk identifier: 0x6f92008e
|
||||
|
||||
Device Boot Start End Sectors Size Id Type
|
||||
XXXX-XX-XX-raspbian-jessie-lite.img1 8192 131071 122880 60M c W95 FAT32 (LBA)
|
||||
XXXX-XX-XX-raspbian-jessie-lite.img2 131072 2658303 2527232 1.2G 83 Linux
|
||||
|
||||
Command (m for help): *d*
|
||||
Partition number (1,2, default 2): *2*
|
||||
|
||||
Partition 2 has been deleted.
|
||||
|
||||
Command (m for help): *n*
|
||||
Partition type
|
||||
p primary (1 primary, 0 extended, 3 free)
|
||||
e extended (container for logical partitions)
|
||||
Select (default p):
|
||||
|
||||
Using default response p.
|
||||
Partition number (2-4, default 2):
|
||||
First sector (2048-6852607, default 2048): *131072*
|
||||
Last sector, +sectors or +size{K,M,G,T,P} (131072-6852607, default 6852607):
|
||||
|
||||
Created a new partition 2 of type 'Linux' and of size 3.2 GiB.
|
||||
|
||||
Command (m for help): *w*
|
||||
The partition table has been altered.
|
||||
Syncing disks.
|
||||
```
|
||||
|
||||
* Mount the image in loop mode: first, edit /mount_image.sh to use the proper values
|
||||
for $OFFSET_BOOT and $OFFSET_ROOTFS, which you can obtain using fdisk and "p" as
|
||||
shown above. You must also change $IMAGE to the correct path. Then run:
|
||||
|
||||
```
|
||||
sudo ./proper_chroot.sh
|
||||
```
|
||||
|
||||
* After mounting the image, the above script will chroot into the mounted image.
|
||||
While in a chroot, the / directory of the image appears as the system / directory
|
||||
(thus the name, change root). To exit the chroot, run "exit" in the root directory.
|
||||
Then, verify the path to the mounted partitions, and resize the filesystem
|
||||
to fill the new larger partition using resize2fs:
|
||||
|
||||
```
|
||||
> df | grep /mnt/arm
|
||||
|
||||
/dev/loop0 3927752 1955672 1794172 53% /mnt/arm_rPi
|
||||
/dev/loop1 57288 18960 38328 34% /mnt/arm_rPi/boot
|
||||
|
||||
> sudo resize2fs /dev/loop0
|
||||
```
|
||||
|
||||
Installing the dependencies
|
||||
===========================
|
||||
|
||||
* To install the dependencies, you'll have to reenter the chroot again:
|
||||
|
||||
```
|
||||
sudo chroot /mnt/arm_rPi
|
||||
```
|
||||
|
||||
* Change your user to root (your global variables may be broken as a result):
|
||||
|
||||
```
|
||||
su root
|
||||
```
|
||||
|
||||
* Change the locales (remove "en_GB.UTF-8 UTF-8", add "en_US.UTF-8 UTF-8"). The
|
||||
arrow keys move the cursor, spacebar selects/deselects a locale, tab moves the cursor
|
||||
to a different context, and enter lets you select "ok":
|
||||
|
||||
```
|
||||
dpkg-reconfigure locales
|
||||
```
|
||||
|
||||
* In the image, make sure everything is up-to-date and remove the old packages:
|
||||
|
||||
```
|
||||
apt-get update
|
||||
apt-get dist-upgrade
|
||||
apt-get autoremove
|
||||
apt-get install timidity git p7zip-full python-dev python-pip python-lxml pmount libjpeg-dev libtiff-dev libwebp-dev liblcms2-dev tcl-dev tk-dev python-tk libxml2-dev libxslt1-dev
|
||||
```
|
||||
|
||||
* Install the Python dependencies for PyCIRCLean. Currently, PyCIRCLean is
|
||||
Python 2.7 and 3.3+ compatible, but Python 2 support might be dropped at some point.
|
||||
|
||||
```
|
||||
pip install oletools olefile exifread Pillow
|
||||
pip install git+https://github.com/Rafiot/officedissector.git
|
||||
pip install git+https://github.com/CIRCL/PyCIRCLean.git
|
||||
```
|
||||
|
||||
* Create a new user and make mounting work with a read-only filesystem.
|
||||
|
||||
```
|
||||
useradd -m kitten
|
||||
chown -R kitten:kitten /home/kitten
|
||||
ln -s /proc/mounts /etc/mtab
|
||||
```
|
||||
|
||||
* Enable rc.local, which ensures that the code in /etc/rc.local is run on boot.
|
||||
This is what triggers CIRCLean to run.
|
||||
|
||||
```
|
||||
systemctl enable rc-local.service
|
||||
```
|
||||
|
||||
* Exit the chroot again, and copy the files from your repository into the mounted
|
||||
image.
|
||||
|
||||
```
|
||||
sudo ./copy_to_final.sh /mnt/arm_rPi/
|
||||
```
|
||||
|
||||
Write the image on a SD card
|
||||
============================
|
||||
|
||||
* Plug your SD card into the computer. Then, find where it is mounted using df:
|
||||
|
||||
```
|
||||
df -h
|
||||
```
|
||||
|
||||
* If it has been automatically mounted, unmount the SD card (use the path you
|
||||
found in the previous step):
|
||||
|
||||
```
|
||||
umount $PATH_TO_YOUR_SD
|
||||
```
|
||||
|
||||
* Write the image to the card:
|
||||
|
||||
```
|
||||
sudo dd bs=4M if=$PATH_TO_YOUR_IMAGE of=$PATH_TO_YOUR_SD
|
||||
```
|
|
@ -1,6 +0,0 @@
|
|||
proc /proc proc defaults 0 0
|
||||
/dev/mmcblk0p1 /boot vfat ro,defaults 0 0
|
||||
/dev/mmcblk0p2 / ext4 ro,defaults,noatime 0 0
|
||||
tmpfs /tmp tmpfs rw,size=64M,noexec,nodev,nosuid,mode=1777 0 0
|
||||
tmpfs /media tmpfs rw,size=64M,noexec,nodev,nosuid,mode=1777 0 0
|
||||
# a swapfile is not a swap partition, so no using swapon|off from here on, use dphys-swapfile swap[on|off] for that
|
54
fs/etc/group
54
fs/etc/group
|
@ -1,54 +0,0 @@
|
|||
root:x:0:
|
||||
daemon:x:1:
|
||||
bin:x:2:
|
||||
sys:x:3:
|
||||
adm:x:4:pi
|
||||
tty:x:5:
|
||||
disk:x:6:
|
||||
lp:x:7:
|
||||
mail:x:8:
|
||||
news:x:9:
|
||||
uucp:x:10:
|
||||
man:x:12:
|
||||
proxy:x:13:
|
||||
kmem:x:15:
|
||||
dialout:x:20:pi
|
||||
fax:x:21:
|
||||
voice:x:22:
|
||||
cdrom:x:24:pi
|
||||
floppy:x:25:
|
||||
tape:x:26:
|
||||
sudo:x:27:pi
|
||||
audio:x:29:pi
|
||||
dip:x:30:
|
||||
www-data:x:33:
|
||||
backup:x:34:
|
||||
operator:x:37:
|
||||
list:x:38:
|
||||
irc:x:39:
|
||||
src:x:40:
|
||||
gnats:x:41:
|
||||
shadow:x:42:
|
||||
utmp:x:43:
|
||||
video:x:44:pi
|
||||
sasl:x:45:
|
||||
plugdev:x:46:pi,kitten
|
||||
staff:x:50:
|
||||
games:x:60:pi
|
||||
users:x:100:pi
|
||||
nogroup:x:65534:
|
||||
libuuid:x:101:
|
||||
crontab:x:102:
|
||||
pi:x:1000:
|
||||
ssh:x:103:
|
||||
ntp:x:104:
|
||||
netdev:x:105:pi
|
||||
input:x:999:pi
|
||||
messagebus:x:106:
|
||||
lpadmin:x:107:
|
||||
fuse:x:108:
|
||||
lightdm:x:109:
|
||||
indiecity:x:1001:root
|
||||
spi:x:1002:pi
|
||||
gpio:x:1003:pi
|
||||
kitten:x:1004:
|
|
@ -1,5 +0,0 @@
|
|||
# /etc/pmount.allow
|
||||
# pmount will allow users to additionally mount all devices that are
|
||||
# listed here.
|
||||
/dev/sdb1
|
||||
/dev/sda*
|
|
@ -1,19 +0,0 @@
|
|||
#!/bin/sh
|
||||
# Part of raspi-config http://github.com/asb/raspi-config
|
||||
#
|
||||
# See LICENSE file for copyright and license details
|
||||
|
||||
# Should be installed to /etc/profile.d/raspi-config.sh to force raspi-config
|
||||
# to run at initial login
|
||||
|
||||
# You may also want to set automatic login in /etc/inittab on tty1 by adding a
|
||||
# line such as:
|
||||
# 1:2345:respawn:/bin/login -f root tty1 </dev/tty1 >/dev/tty1 2>&1 # RPICFG_TO_DISABLE
|
||||
|
||||
if [ $(id -u) -ne 0 ]; then
|
||||
printf "\nNOTICE: the software on this Raspberry Pi has not been fully configured. Please run 'sudo raspi-config'\n\n"
|
||||
else
|
||||
# Disable raspi-config at the first run.
|
||||
# raspi-config
|
||||
exec login -f pi
|
||||
fi
|
|
@ -1,36 +0,0 @@
|
|||
#!/bin/sh -e
|
||||
#
|
||||
# rc.local
|
||||
#
|
||||
# This script is executed at the end of each multiuser runlevel.
|
||||
# Make sure that the script will "exit 0" on success or any other
|
||||
# value on error.
|
||||
#
|
||||
# In order to enable or disable this script just change the execution
|
||||
# bits.
|
||||
#
|
||||
# By default this script does nothing.
|
||||
|
||||
clean(){
|
||||
echo 'Rc Local done, quit.'
|
||||
/sbin/shutdown -P -h now
|
||||
}
|
||||
|
||||
# Print the IP address
|
||||
_IP=$(hostname -I) || true
|
||||
if [ "$_IP" ]; then
|
||||
printf "My IP address is %s\n" "$_IP"
|
||||
fi
|
||||
|
||||
if [ -e /dev/sda ]; then
|
||||
if [ -e /dev/sdb ]; then
|
||||
# avoid possible misuse
|
||||
/sbin/ifconfig eth0 down
|
||||
trap clean EXIT TERM INT
|
||||
cd /opt/groomer
|
||||
/usr/sbin/led &
|
||||
./init.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
|
@ -1 +0,0 @@
|
|||
kitten hard priority -20
|
|
@ -1,28 +0,0 @@
|
|||
#
|
||||
# This file MUST be edited with the 'visudo' command as root.
|
||||
#
|
||||
# Please consider adding local content in /etc/sudoers.d/ instead of
|
||||
# directly modifying this file.
|
||||
#
|
||||
# See the man page for details on how to write a sudoers file.
|
||||
#
|
||||
Defaults env_reset
|
||||
Defaults mail_badpass
|
||||
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
||||
# Host alias specification
|
||||
|
||||
# User alias specification
|
||||
|
||||
# Cmnd alias specification
|
||||
|
||||
# User privilege specification
|
||||
#root ALL=(ALL:ALL) ALL
|
||||
|
||||
# Allow members of group sudo to execute any command
|
||||
#%sudo ALL=(ALL:ALL) ALL
|
||||
|
||||
# See sudoers(5) for more information on "#include" directives:
|
||||
|
||||
#includedir /etc/sudoers.d
|
||||
#pi ALL=(ALL) NOPASSWD: ALL
|
|
@ -1 +0,0 @@
|
|||
SUBSYSTEM=="hidraw", DRIVERS=="usbhid", RUN+="/bin/bash -c 'cd /sys/devices/platform/bcm2708_usb/usb1/1-1 ; for d in $(ls -d 1-1.[2-5]); do if [ $(ls -lR $d | grep -c usbhid) -gt 0 ] ; then echo 0 > $d/authorized ; fi ; done'"
|
|
@ -1,2 +0,0 @@
|
|||
KERNEL=="sdc", SYMLINK+="mmcblk0"
|
||||
KERNEL=="sdc?", SYMLINK+="mmcblk0p%n",
|
|
@ -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,4 +0,0 @@
|
|||
# Paths to the commands used to convert the files
|
||||
PDF="/usr/bin/pdf2htmlEX"
|
||||
LO="/usr/bin/libreoffice"
|
||||
UNPACKER="/usr/bin/7z"
|
|
@ -1,332 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import magic
|
||||
import os
|
||||
import mimetypes
|
||||
import shlex
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
from helpers import FileBase, KittenGroomerBase, main
|
||||
|
||||
UNOCONV = '/usr/bin/unoconv'
|
||||
LIBREOFFICE = '/usr/bin/libreoffice'
|
||||
GS = '/usr/bin/gs'
|
||||
PDF2HTMLEX = '/usr/bin/pdf2htmlEX'
|
||||
SEVENZ = '/usr/bin/7z'
|
||||
|
||||
|
||||
# Prepare application/<subtype>
|
||||
mimes_office = ['msword', 'vnd.openxmlformats-officedocument.', 'vnd.ms-',
|
||||
'vnd.oasis.opendocument']
|
||||
mimes_pdf = ['pdf']
|
||||
mimes_xml = ['xml']
|
||||
mimes_ms = ['x-dosexec']
|
||||
mimes_compressed = ['zip', 'x-rar', 'x-bzip2', 'x-lzip', 'x-lzma', 'x-lzop',
|
||||
'x-xz', 'x-compress', 'x-gzip', 'x-tar', 'compressed']
|
||||
mimes_data = ['octet-stream']
|
||||
|
||||
|
||||
class File(FileBase):
|
||||
|
||||
def __init__(self, src_path, dst_path):
|
||||
''' Init file object, set the mimetype '''
|
||||
super(File, self).__init__(src_path, dst_path)
|
||||
mimetype = magic.from_file(src_path, mime=True)
|
||||
self.main_type, self.sub_type = mimetype.split('/')
|
||||
self.log_details.update({'maintype': self.main_type, 'subtype': self.sub_type})
|
||||
self.expected_mimetype, self.expected_extensions = self.crosscheck_mime()
|
||||
self.is_recursive = False
|
||||
|
||||
def crosscheck_mime(self):
|
||||
'''
|
||||
Set the expected mime and extension variables based on mime type.
|
||||
'''
|
||||
# /usr/share/mime has interesting stuff
|
||||
|
||||
# guess_type uses the extension to get a mime type
|
||||
expected_mimetype, encoding = mimetypes.guess_type(self.src_path, strict=False)
|
||||
if expected_mimetype is not None:
|
||||
expected_extensions = mimetypes.guess_all_extensions(expected_mimetype,
|
||||
strict=False)
|
||||
else:
|
||||
# the extension is unknown...
|
||||
expected_extensions = None
|
||||
|
||||
return expected_mimetype, expected_extensions
|
||||
|
||||
def verify_extension(self):
|
||||
'''Check if the extension is the one we expect'''
|
||||
if self.expected_extensions is None:
|
||||
return None
|
||||
path, actual_extension = os.path.splitext(self.src_path)
|
||||
return actual_extension in self.expected_extensions
|
||||
|
||||
def verify_mime(self):
|
||||
'''Check if the mime is the one we expect'''
|
||||
if self.expected_mimetype is None:
|
||||
return None
|
||||
actual_mimetype = '{}/{}'.format(self.main_type, self.sub_type)
|
||||
return actual_mimetype == self.expected_mimetype
|
||||
|
||||
|
||||
class KittenGroomer(KittenGroomerBase):
|
||||
|
||||
def __init__(self, root_src=None, root_dst=None, max_recursive=5):
|
||||
'''
|
||||
Initialize the basics of the conversion process
|
||||
'''
|
||||
if root_src is None:
|
||||
root_src = os.path.join(os.sep, 'media', 'src')
|
||||
if root_dst is None:
|
||||
root_dst = os.path.join(os.sep, 'media', 'dst')
|
||||
super(KittenGroomer, self).__init__(root_src, root_dst)
|
||||
|
||||
self.recursive = 0
|
||||
self.max_recursive = max_recursive
|
||||
|
||||
subtypes_apps = [
|
||||
(mimes_office, self._office_related),
|
||||
(mimes_pdf, self._pdf),
|
||||
(mimes_xml, self._office_related),
|
||||
(mimes_ms, self._executables),
|
||||
(mimes_compressed, self._archive),
|
||||
(mimes_data, self._binary_app),
|
||||
]
|
||||
self.subtypes_application = self._init_subtypes_application(subtypes_apps)
|
||||
|
||||
self.mime_processing_options = {
|
||||
'text': self.text,
|
||||
'audio': self.audio,
|
||||
'image': self.image,
|
||||
'video': self.video,
|
||||
'application': self.application,
|
||||
'example': self.example,
|
||||
'message': self.message,
|
||||
'model': self.model,
|
||||
'multipart': self.multipart,
|
||||
'inode': self.inode,
|
||||
}
|
||||
|
||||
# Dirty trick to run libreoffice at least once and avoid unoconv to crash...
|
||||
self._run_process(LIBREOFFICE, 5)
|
||||
|
||||
# ##### Helpers #####
|
||||
def _init_subtypes_application(self, subtypes_application):
|
||||
'''
|
||||
Create the Dict to pick the right function based on the sub mime type
|
||||
'''
|
||||
to_return = {}
|
||||
for list_subtypes, fct in subtypes_application:
|
||||
for st in list_subtypes:
|
||||
to_return[st] = fct
|
||||
return to_return
|
||||
|
||||
def _print_log(self):
|
||||
'''
|
||||
Print the logs related to the current file being processed
|
||||
'''
|
||||
tmp_log = self.log_name.fields(**self.cur_file.log_details)
|
||||
if self.cur_file.log_details.get('dangerous'):
|
||||
tmp_log.warning(self.cur_file.log_string)
|
||||
elif self.cur_file.log_details.get('unknown') or self.cur_file.log_details.get('binary'):
|
||||
tmp_log.info(self.cur_file.log_string)
|
||||
else:
|
||||
tmp_log.debug(self.cur_file.log_string)
|
||||
|
||||
def _run_process(self, command_line, timeout=0):
|
||||
'''Run subprocess, wait until it finishes'''
|
||||
if timeout != 0:
|
||||
deadline = time.time() + timeout
|
||||
else:
|
||||
deadline = None
|
||||
args = shlex.split(command_line)
|
||||
p = subprocess.Popen(args)
|
||||
while True:
|
||||
code = p.poll()
|
||||
if code is not None:
|
||||
break
|
||||
if deadline is not None and time.time() > deadline:
|
||||
p.kill()
|
||||
break
|
||||
time.sleep(1)
|
||||
return True
|
||||
|
||||
#######################
|
||||
|
||||
# ##### Discarded mime types, reason in the comments ######
|
||||
def inode(self):
|
||||
''' Usually empty file. No reason (?) to copy it on the dest key'''
|
||||
self.cur_file.log_string += 'Inode file'
|
||||
|
||||
def unknown(self):
|
||||
''' This main type is unknown, that should not happen '''
|
||||
self.cur_file.log_string += 'Unknown file'
|
||||
|
||||
# ##### Threated as malicious, no reason to have it on a USB key ######
|
||||
def example(self):
|
||||
'''Way to process example file'''
|
||||
self.cur_file.log_string += 'Example file'
|
||||
self.cur_file.make_dangerous()
|
||||
self._safe_copy()
|
||||
|
||||
def message(self):
|
||||
'''Way to process message file'''
|
||||
self.cur_file.log_string += 'Message file'
|
||||
self.cur_file.make_dangerous()
|
||||
self._safe_copy()
|
||||
|
||||
def model(self):
|
||||
'''Way to process model file'''
|
||||
self.cur_file.log_string += 'Model file'
|
||||
self.cur_file.make_dangerous()
|
||||
self._safe_copy()
|
||||
|
||||
def multipart(self):
|
||||
'''Way to process multipart file'''
|
||||
self.cur_file.log_string += 'Multipart file'
|
||||
self.cur_file.make_dangerous()
|
||||
self._safe_copy()
|
||||
|
||||
#######################
|
||||
|
||||
# ##### Converted ######
|
||||
def text(self):
|
||||
''' LibreOffice should be able to open all the files '''
|
||||
self.cur_file.log_string += 'Text file'
|
||||
self._office_related()
|
||||
|
||||
def application(self):
|
||||
''' Everything can be there, using the subtype to decide '''
|
||||
for subtype, fct in list(self.subtypes_application.items()):
|
||||
if subtype in self.cur_file.sub_type:
|
||||
fct()
|
||||
self.cur_file.log_string += 'Application file'
|
||||
return
|
||||
self.cur_file.log_string += 'Unknown Application file'
|
||||
self._unknown_app()
|
||||
|
||||
def _executables(self):
|
||||
'''Way to process executable file'''
|
||||
self.cur_file.add_log_details('processing_type', 'executable')
|
||||
self.cur_file.make_dangerous()
|
||||
self._safe_copy()
|
||||
|
||||
def _office_related(self):
|
||||
'''Way to process all the files LibreOffice can handle'''
|
||||
self.cur_file.add_log_details('processing_type', 'office')
|
||||
dst_dir, filename = os.path.split(self.cur_file.dst_path)
|
||||
tmpdir = os.path.join(dst_dir, 'temp')
|
||||
name, ext = os.path.splitext(filename)
|
||||
tmppath = os.path.join(tmpdir, name + '.pdf')
|
||||
self._safe_mkdir(tmpdir)
|
||||
lo_command = '{} --format pdf -eSelectPdfVersion=1 --output {} {}'.format(
|
||||
UNOCONV, tmppath, self.cur_file.src_path)
|
||||
self._run_process(lo_command)
|
||||
self._pdfa(tmppath)
|
||||
self._safe_rmtree(tmpdir)
|
||||
|
||||
def _pdfa(self, tmpsrcpath):
|
||||
'''Way to process PDF/A file'''
|
||||
pdf_command = '{} --dest-dir / {} {}'.format(PDF2HTMLEX, tmpsrcpath,
|
||||
self.cur_file.dst_path + '.html')
|
||||
self._run_process(pdf_command)
|
||||
|
||||
def _pdf(self):
|
||||
'''Way to process PDF file'''
|
||||
self.cur_file.add_log_details('processing_type', 'pdf')
|
||||
dst_dir, filename = os.path.split(self.cur_file.dst_path)
|
||||
tmpdir = os.path.join(dst_dir, 'temp')
|
||||
tmppath = os.path.join(tmpdir, filename)
|
||||
self._safe_mkdir(tmpdir)
|
||||
gs_command = '{} -dPDFA -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile={} {}'.format(
|
||||
GS, tmppath, self.cur_file.src_path)
|
||||
self._run_process(gs_command)
|
||||
self._pdfa(tmppath)
|
||||
self._safe_rmtree(tmpdir)
|
||||
|
||||
def _archive(self):
|
||||
'''Way to process Archive'''
|
||||
self.cur_file.add_log_details('processing_type', 'archive')
|
||||
self.cur_file.is_recursive = True
|
||||
self.cur_file.log_string += 'Archive extracted, processing content.'
|
||||
tmpdir = self.cur_file.dst_path + '_temp'
|
||||
self._safe_mkdir(tmpdir)
|
||||
extract_command = '{} -p1 x {} -o{} -bd'.format(SEVENZ, self.cur_file.src_path, tmpdir)
|
||||
self._run_process(extract_command)
|
||||
self.recursive += 1
|
||||
self.processdir(tmpdir, self.cur_file.dst_path)
|
||||
self.recursive -= 1
|
||||
self._safe_rmtree(tmpdir)
|
||||
|
||||
def _unknown_app(self):
|
||||
'''Way to process an unknown file'''
|
||||
self.cur_file.make_unknown()
|
||||
self._safe_copy()
|
||||
|
||||
def _binary_app(self):
|
||||
'''Way to process an unknown binary file'''
|
||||
self.cur_file.make_binary()
|
||||
self._safe_copy()
|
||||
|
||||
#######################
|
||||
|
||||
# ##### Not converted, checking the mime type ######
|
||||
def audio(self):
|
||||
'''Way to process an audio file'''
|
||||
self.cur_file.log_string += 'Audio file'
|
||||
self._media_processing()
|
||||
|
||||
def image(self):
|
||||
'''Way to process an image'''
|
||||
self.cur_file.log_string += 'Image file'
|
||||
self._media_processing()
|
||||
|
||||
def video(self):
|
||||
'''Way to process a video'''
|
||||
self.cur_file.log_string += 'Video file'
|
||||
self._media_processing()
|
||||
|
||||
def _media_processing(self):
|
||||
'''Generic way to process all the media files'''
|
||||
self.cur_log.fields(processing_type='media')
|
||||
if not self.cur_file.verify_mime() or not self.cur_file.verify_extension():
|
||||
# The extension is unknown or doesn't match the mime type => suspicious
|
||||
# TODO: write details in the logfile
|
||||
self.cur_file.make_dangerous()
|
||||
self._safe_copy()
|
||||
|
||||
#######################
|
||||
|
||||
def processdir(self, src_dir=None, dst_dir=None):
|
||||
'''
|
||||
Main function doing the processing
|
||||
'''
|
||||
if src_dir is None:
|
||||
src_dir = self.src_root_dir
|
||||
if dst_dir is None:
|
||||
dst_dir = self.dst_root_dir
|
||||
|
||||
if self.recursive > 0:
|
||||
self._print_log()
|
||||
|
||||
if self.recursive >= self.max_recursive:
|
||||
self.cur_log.warning('ARCHIVE BOMB.')
|
||||
self.cur_log.warning('The content of the archive contains recursively other archives.')
|
||||
self.cur_log.warning('This is a bad sign so the archive is not extracted to the destination key.')
|
||||
self._safe_rmtree(src_dir)
|
||||
if src_dir.endswith('_temp'):
|
||||
archbomb_path = src_dir[:-len('_temp')]
|
||||
self._safe_remove(archbomb_path)
|
||||
|
||||
for srcpath in self._list_all_files(src_dir):
|
||||
self.cur_file = File(srcpath, srcpath.replace(src_dir, dst_dir))
|
||||
|
||||
self.log_name.info('Processing {} ({}/{})', srcpath.replace(src_dir + '/', ''),
|
||||
self.cur_file.main_type, self.cur_file.sub_type)
|
||||
self.mime_processing_options.get(self.cur_file.main_type, self.unknown)()
|
||||
if not self.cur_file.is_recursive:
|
||||
self._print_log()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(KittenGroomer)
|
|
@ -1,221 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
source ./constraint.sh
|
||||
source ./constraint_conv.sh
|
||||
|
||||
RECURSIVE_ARCHIVE_MAX=3
|
||||
RECURSIVE_ARCHIVE_CURRENT=0
|
||||
ARCHIVE_BOMB=0
|
||||
LOGFILE="${LOGS}/processing.txt"
|
||||
|
||||
# Something went wrong.
|
||||
error_handler(){
|
||||
echo "FAILED." >> ${LOGFILE}
|
||||
echo -e "\tSomething went wrong during the duplication of the last file." >> ${LOGFILE}
|
||||
echo -e "\tPlease open a bug on https://www.github.com/Rafiot/KittenGroomer" >> ${LOGFILE}
|
||||
continue
|
||||
}
|
||||
|
||||
trap error_handler ERR TERM INT
|
||||
|
||||
office_n_txt(){
|
||||
src_file=${1}
|
||||
dst_file=${2}${1##$CURRENT_SRC}.html
|
||||
temp=${2}/temp
|
||||
${LO} --headless --convert-to pdf --outdir "${temp}" "${src_file}"
|
||||
${PDF} --dest-dir=/ ${temp}/*.pdf ${dst_file}
|
||||
rm -rf "${temp}"
|
||||
}
|
||||
|
||||
copy(){
|
||||
src_file=${1}
|
||||
dst_file=${2}
|
||||
mkdir -p `dirname "${dst_file}"`
|
||||
cp "${src_file}" "${dst_file}"
|
||||
}
|
||||
|
||||
# Plain text
|
||||
text(){
|
||||
echo Text file ${1}
|
||||
office_n_txt ${1} ${2}
|
||||
}
|
||||
|
||||
# Multimedia
|
||||
## WARNING: They are assumed safe.
|
||||
audio(){
|
||||
echo Audio file ${1}
|
||||
copy ${1} ${2}${1##$CURRENT_SRC}
|
||||
}
|
||||
|
||||
image(){
|
||||
echo Image file ${1}
|
||||
copy ${1} ${2}${1##$CURRENT_SRC}
|
||||
}
|
||||
|
||||
video(){
|
||||
echo Video file ${1}
|
||||
copy ${1} ${2}${1##$CURRENT_SRC}
|
||||
}
|
||||
|
||||
# Random - Used
|
||||
|
||||
archive(){
|
||||
echo Archive file ${1}
|
||||
if [ ${ARCHIVE_BOMB} -eq 0 ]; then
|
||||
temp_extract_dir=${2}_temp
|
||||
mkdir -p "${temp_extract_dir}"
|
||||
${UNPACKER} -p1 x "${1}" -o"${temp_extract_dir}" -bd
|
||||
main ${2} ${RECURSIVE_ARCHIVE_CURRENT} ${temp_extract_dir} || true
|
||||
rm -rf "${temp_extract_dir}"
|
||||
fi
|
||||
if [ ${ARCHIVE_BOMB} -eq 1 ]; then
|
||||
rm -rf "${2}"
|
||||
rm -rf "${2}_temp"
|
||||
fi
|
||||
CURRENT_SRC="/media/${SRC}"
|
||||
}
|
||||
|
||||
|
||||
application(){
|
||||
echo App file ${1}
|
||||
src_file=${1}
|
||||
dst_file=${2}${1##$CURRENT_SRC}
|
||||
mime_details=${3}
|
||||
case ${mime_details} in
|
||||
pdf)
|
||||
echo "Got a pdf"
|
||||
${PDF} --dest-dir "${2}" "${src_file}"
|
||||
;;
|
||||
msword|vnd.openxmlformats-officedocument.*|vnd.ms-*|vnd.oasis.opendocument*)
|
||||
# https://blogs.msdn.com/b/vsofficedeveloper/archive/2008/05/08/office-2007-open-xml-mime-types.aspx
|
||||
# http://plan-b-for-openoffice.org/glossary/term/mime-type
|
||||
echo "MS Office or ODF document"
|
||||
office_n_txt ${src_file} ${2}
|
||||
;;
|
||||
*xml*)
|
||||
echo "Got an XML"
|
||||
office_n_txt ${src_file} ${2}
|
||||
;;
|
||||
x-dosexec)
|
||||
echo "Win executable"
|
||||
copy ${src_file} ${2}/DANGEROUS_${1##$CURRENT_SRC/}_DANGEROUS
|
||||
;;
|
||||
zip|x-rar|x-bzip2|x-lzip|x-lzma|x-lzop|x-xz|x-compress|x-gzip|x-tar|*compressed)
|
||||
echo "Compressed file"
|
||||
archive ${src_file} ${dst_file}
|
||||
;;
|
||||
octet-stream)
|
||||
echo "Unknown type."
|
||||
copy ${src_file} ${dst_file}.bin
|
||||
;;
|
||||
*)
|
||||
echo "Unhandled type"
|
||||
copy ${src_file} ${dst_file}
|
||||
;;
|
||||
esac
|
||||
|
||||
}
|
||||
|
||||
# Random - Unused?
|
||||
## WARNING: They are assumed safe.
|
||||
|
||||
example(){
|
||||
echo Example file ${1}
|
||||
copy ${1} ${2}${1##$CURRENT_SRC}
|
||||
}
|
||||
|
||||
message(){
|
||||
echo Message file ${1}
|
||||
copy ${1} ${2}${1##$CURRENT_SRC}
|
||||
}
|
||||
|
||||
model(){
|
||||
echo Model file ${1}
|
||||
copy ${1} ${2}${1##$CURRENT_SRC}
|
||||
}
|
||||
|
||||
multipart(){
|
||||
echo Multipart file ${1}
|
||||
copy ${1} ${2}${1##$CURRENT_SRC}
|
||||
}
|
||||
|
||||
main(){
|
||||
if [ -z ${1} ]; then
|
||||
echo "Please specify the destination directory."
|
||||
exit
|
||||
fi
|
||||
set -e
|
||||
set -x
|
||||
|
||||
if [ -z ${2} ]; then
|
||||
CURRENT_SRC="/media/${SRC}"
|
||||
RECURSIVE_ARCHIVE_CURRENT=0
|
||||
ARCHIVE_BOMB=0
|
||||
else
|
||||
RECURSIVE_ARCHIVE_CURRENT=${2}
|
||||
CURRENT_SRC=${3}
|
||||
if [ ${RECURSIVE_ARCHIVE_CURRENT} -gt ${RECURSIVE_ARCHIVE_MAX} ]; then
|
||||
echo Archive bomb.
|
||||
ARCHIVE_BOMB=1
|
||||
echo "ARCHIVE BOMB." >> ${LOGFILE}
|
||||
echo "The content of the archive contains recursively other archives." >> ${LOGFILE}
|
||||
echo "This is a bad sign so the archive is not extracted to the destination key." >> ${LOGFILE}
|
||||
return
|
||||
else
|
||||
RECURSIVE_ARCHIVE_CURRENT=`expr ${RECURSIVE_ARCHIVE_CURRENT} + 1`
|
||||
fi
|
||||
fi
|
||||
|
||||
FILE_LIST=`find ${CURRENT_SRC} -type f`
|
||||
SAVEIFS=$IFS
|
||||
IFS=$(echo -en "\n\b")
|
||||
for file in ${FILE_LIST}; do
|
||||
# first param is the destination dir
|
||||
dest=${1}
|
||||
|
||||
mime=`file -b --mime-type "${file}"`
|
||||
echo ${mime}
|
||||
main_mime=`echo ${mime} | cut -f1 -d/`
|
||||
details=`echo ${mime} | cut -f2 -d/`
|
||||
echo -n "Processing ${file} (${mime})... " >> ${LOGFILE}
|
||||
case "${main_mime}" in
|
||||
"text")
|
||||
text ${file} ${dest} || error_handler
|
||||
;;
|
||||
"audio")
|
||||
audio ${file} ${dest} || error_handler
|
||||
;;
|
||||
"image")
|
||||
image ${file} ${dest} || error_handler
|
||||
;;
|
||||
"video")
|
||||
video ${file} ${dest} || error_handler
|
||||
;;
|
||||
"application")
|
||||
application ${file} ${dest} ${details} || error_handler
|
||||
;;
|
||||
"example")
|
||||
example ${file} ${dest} || error_handler
|
||||
;;
|
||||
"message")
|
||||
message ${file} ${dest} || error_handler
|
||||
;;
|
||||
"model")
|
||||
model ${file} ${dest} || error_handler
|
||||
;;
|
||||
"multipart")
|
||||
multipart ${file} ${dest} || error_handler
|
||||
;;
|
||||
*)
|
||||
echo "This should never happen... :]"
|
||||
echo $mime $main_mime $details
|
||||
;;
|
||||
esac
|
||||
echo "done." >> ${LOGFILE}
|
||||
done
|
||||
IFS=$SAVEIFS
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
|
||||
from helpers import FileBase, KittenGroomerBase, main
|
||||
|
||||
|
||||
printers = ['.STL', '.obj']
|
||||
cnc = ['.nc', '.tap', '.gcode', '.dxf', '.stl', '.obj', '.iges', '.igs',
|
||||
'.vrml', '.vrl', '.thing', '.step', '.stp', '.x3d']
|
||||
shopbot = ['.ai', '.svg', '.dxf', '.dwg', '.eps']
|
||||
omax = ['.ai', '.svg', '.dxf', '.dwg', '.eps', '.omx', '.obj']
|
||||
epilog_laser = ['.ai', '.svg', '.dxf', '.dwg', '.eps']
|
||||
metabeam = ['.dxf']
|
||||
up = ['.upp', '.up3', '.stl', '.obj']
|
||||
|
||||
|
||||
class FilePier9(FileBase):
|
||||
|
||||
def __init__(self, src_path, dst_path):
|
||||
''' Init file object, set the extension '''
|
||||
super(FilePier9, self).__init__(src_path, dst_path)
|
||||
a, self.extension = os.path.splitext(self.src_path)
|
||||
|
||||
|
||||
class KittenGroomerPier9(KittenGroomerBase):
|
||||
|
||||
def __init__(self, root_src=None, root_dst=None):
|
||||
'''
|
||||
Initialize the basics of the copy
|
||||
'''
|
||||
if root_src is None:
|
||||
root_src = os.path.join(os.sep, 'media', 'src')
|
||||
if root_dst is None:
|
||||
root_dst = os.path.join(os.sep, 'media', 'dst')
|
||||
super(KittenGroomerPier9, self).__init__(root_src, root_dst)
|
||||
|
||||
# The initial version will accept all the file extension for all the machines.
|
||||
self.authorized_extensions = printers + cnc + shopbot + omax + epilog_laser + metabeam + up
|
||||
|
||||
def _print_log(self):
|
||||
'''
|
||||
Print the logs related to the current file being processed
|
||||
'''
|
||||
tmp_log = self.log_name.fields(**self.cur_file.log_details)
|
||||
if not self.cur_file.log_details.get('valid'):
|
||||
tmp_log.warning(self.cur_file.log_string)
|
||||
else:
|
||||
tmp_log.debug(self.cur_file.log_string)
|
||||
|
||||
def processdir(self):
|
||||
'''
|
||||
Main function doing the processing
|
||||
'''
|
||||
for srcpath in self._list_all_files(self.src_root_dir):
|
||||
self.log_name.info('Processing {}', srcpath.replace(self.src_root_dir + '/', ''))
|
||||
self.cur_file = FilePier9(srcpath, srcpath.replace(self.src_root_dir, self.dst_root_dir))
|
||||
if self.cur_file.extension in self.authorized_extensions:
|
||||
self.cur_file.add_log_details('valid', True)
|
||||
self.cur_file.log_string = 'Expected extension: ' + self.cur_file.extension
|
||||
self._safe_copy()
|
||||
else:
|
||||
self.cur_file.log_string = 'Bad extension: ' + self.cur_file.extension
|
||||
self._print_log()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(KittenGroomerPier9)
|
|
@ -1,122 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
# To make debugging easier
|
||||
echo "KittenGroomer: in groomer.sh" 1>&2
|
||||
|
||||
source ./constraint.sh
|
||||
if ! [ "${ID}" -ge "1000" ]; then
|
||||
echo "This script cannot run as root."
|
||||
exit
|
||||
fi
|
||||
|
||||
source ./functions.sh
|
||||
|
||||
clean(){
|
||||
echo Cleaning.
|
||||
${SYNC}
|
||||
|
||||
# Cleanup source
|
||||
pumount ${SRC}
|
||||
|
||||
# Cleanup destination
|
||||
rm -rf ${TEMP}
|
||||
rm -rf ${ZIPTEMP}
|
||||
pumount ${DST}
|
||||
|
||||
exit
|
||||
}
|
||||
|
||||
trap clean EXIT TERM INT
|
||||
|
||||
# De we have a source device
|
||||
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`
|
||||
if [ -z "${DEV_PARTITIONS}" ]; then
|
||||
echo "${DEV_SRC} does not have any partitions."
|
||||
exit
|
||||
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
|
||||
for partition in ${DEV_PARTITIONS}
|
||||
do
|
||||
# Processing a partition
|
||||
echo "Processing partition: ${partition}"
|
||||
if [ `${MOUNT} | grep -c ${SRC}` -ne 0 ]; then
|
||||
${PUMOUNT} ${SRC}
|
||||
fi
|
||||
|
||||
${PMOUNT} -w ${partition} ${SRC}
|
||||
ls "/media/${SRC}" | grep -i autorun.inf | xargs -I {} mv "/media/${SRC}"/{} "/media/${SRC}"/DANGEROUS_{}_DANGEROUS || true
|
||||
${PUMOUNT} ${SRC}
|
||||
${PMOUNT} -r ${partition} ${SRC}
|
||||
if [ ${?} -ne 0 ]; then
|
||||
echo "Unable to mount ${partition} on /media/${SRC}"
|
||||
else
|
||||
echo "${partition} mounted at /media/${SRC}"
|
||||
|
||||
# Print the filenames on the current partition in a logfile
|
||||
find "/media/${SRC}" -fls "${LOGS}/Content_partition_${PARTCOUNT}.txt"
|
||||
|
||||
# create a directory on ${DST} named PARTION_$PARTCOUNT
|
||||
target_dir="/media/${DST}/FROM_PARTITION_${PARTCOUNT}"
|
||||
echo "copying to: ${target_dir}"
|
||||
mkdir -p "${target_dir}"
|
||||
LOGFILE="${LOGS}/processing.txt"
|
||||
|
||||
echo "==== Starting processing of /media/${SRC} to ${target_dir}. ====" 1>&2
|
||||
echo "==== Starting processing of /media/${SRC} to ${target_dir}. ====" >> ${LOGFILE}
|
||||
generic.py --source /media/${SRC} --destination ${target_dir} || true
|
||||
echo "==== Done with /media/${SRC} to ${target_dir}. ====" 1>&2
|
||||
echo "==== Done with /media/${SRC} to ${target_dir}. ====" >> ${LOGFILE}
|
||||
|
||||
ls -lR "${target_dir}"
|
||||
fi
|
||||
let PARTCOUNT=`expr $PARTCOUNT + 1`
|
||||
done
|
||||
|
||||
# To make debugging easier
|
||||
echo "KittenGroomer: done with groomer.sh" 1>&2
|
||||
|
||||
# The cleanup is automatically done in the function clean called when
|
||||
# the program quits
|
|
@ -1,149 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import shutil
|
||||
from twiggy import quickSetup, log
|
||||
import argparse
|
||||
|
||||
class KittenGroomerError(Exception):
|
||||
def __init__(self, message):
|
||||
'''
|
||||
Base KittenGroomer exception handler.
|
||||
'''
|
||||
super(KittenGroomerError, self).__init__(message)
|
||||
self.message = message
|
||||
|
||||
|
||||
class ImplementationRequired(KittenGroomerError):
|
||||
'''
|
||||
Implementation required error
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class FileBase(object):
|
||||
|
||||
def __init__(self, src_path, dst_path):
|
||||
'''
|
||||
Contains base information for a file on the source USB key,
|
||||
initialised with expected src and dest path
|
||||
'''
|
||||
self.src_path = src_path
|
||||
self.dst_path = dst_path
|
||||
self.log_details = {'filepath': self.src_path}
|
||||
self.log_string = ''
|
||||
|
||||
def add_log_details(self, key, value):
|
||||
'''
|
||||
Add an entry in the log dictionary
|
||||
'''
|
||||
self.log_details[key] = value
|
||||
|
||||
def make_dangerous(self):
|
||||
'''
|
||||
This file should be considered as dangerous and never run.
|
||||
Prepending and appending DANGEROUS to the destination
|
||||
file name avoid double-click of death
|
||||
'''
|
||||
self.log_details['dangerous'] = True
|
||||
path, filename = os.path.split(self.dst_path)
|
||||
self.dst_path = os.path.join(path, 'DANGEROUS_{}_DANGEROUS'.format(filename))
|
||||
|
||||
def make_unknown(self):
|
||||
'''
|
||||
This file has an unknown type and it was not possible to take
|
||||
a decision. Theuser will have to decide what to do.
|
||||
Prepending UNKNOWN
|
||||
'''
|
||||
self.log_details['unknown'] = True
|
||||
path, filename = os.path.split(self.dst_path)
|
||||
self.dst_path = os.path.join(path, 'UNKNOWN_{}'.format(filename))
|
||||
|
||||
def make_binary(self):
|
||||
'''
|
||||
This file is a binary, and should probably not be run.
|
||||
Appending .bin avoir double click of death but the user
|
||||
will have to decide by itself.
|
||||
'''
|
||||
self.log_details['binary'] = True
|
||||
path, filename = os.path.split(self.dst_path)
|
||||
self.dst_path = os.path.join(path, '{}.bin'.format(filename))
|
||||
|
||||
|
||||
class KittenGroomerBase(object):
|
||||
|
||||
def __init__(self, root_src, root_dst):
|
||||
'''
|
||||
Setup the base options of the copy/convert setup
|
||||
'''
|
||||
self.src_root_dir = root_src
|
||||
self.dst_root_dir = root_dst
|
||||
self.log_root_dir = os.path.join(self.dst_root_dir, 'logs')
|
||||
self.log_processing = os.path.join(self.log_root_dir, 'processing.log')
|
||||
|
||||
# quickSetup(file=self.log_processing)
|
||||
quickSetup()
|
||||
self.log_name = log.name('files')
|
||||
|
||||
self.cur_file = None
|
||||
|
||||
# ##### Helpers #####
|
||||
def _safe_rmtree(self, directory):
|
||||
'''Remove a directory tree if it exists'''
|
||||
if os.path.exists(directory):
|
||||
shutil.rmtree(directory)
|
||||
|
||||
def _safe_remove(self, filepath):
|
||||
'''Remove a file if it exists'''
|
||||
if os.path.exists(filepath):
|
||||
os.remove(filepath)
|
||||
|
||||
def _safe_mkdir(self, directory):
|
||||
'''Remove a directory if it exists'''
|
||||
if not os.path.exists(directory):
|
||||
os.makedirs(directory)
|
||||
|
||||
def _safe_copy(self):
|
||||
''' Copy a file and create directory if needed '''
|
||||
try:
|
||||
dst_path, filename = os.path.split(self.cur_file.dst_path)
|
||||
self._safe_mkdir(dst_path)
|
||||
shutil.copy(self.cur_file.src_path, self.cur_file.dst_path)
|
||||
return True
|
||||
except Exception as e:
|
||||
# TODO: Logfile
|
||||
print(e)
|
||||
return False
|
||||
|
||||
def _list_all_files(self, directory):
|
||||
''' Generate an iterator over all the files in a directory tree '''
|
||||
for root, dirs, files in os.walk(directory):
|
||||
for filename in files:
|
||||
filepath = os.path.join(root, filename)
|
||||
yield filepath
|
||||
|
||||
def _print_log(self):
|
||||
'''
|
||||
Print log, should be called after each file.
|
||||
|
||||
You probably want to reimplement it in the subclass
|
||||
'''
|
||||
tmp_log = self.log_name.fields(**self.cur_file.log_details)
|
||||
tmp_log.info('It did a thing.')
|
||||
|
||||
#######################
|
||||
|
||||
def processdir(self, src_dir=None, dst_dir=None):
|
||||
'''
|
||||
Main function doing the work, you have to implement it yourself.
|
||||
'''
|
||||
raise ImplementationRequired('You have to implement the result processdir.')
|
||||
|
||||
|
||||
def main(kg_implementation):
|
||||
parser = argparse.ArgumentParser(prog='KittenGroomer', description='Call the KittenGroomer implementation to do things on files present in the source directory to the destination directory')
|
||||
parser.add_argument('-s', '--source', type=str, help='Source directory')
|
||||
parser.add_argument('-d', '--destination', type=str, help='Destination directory')
|
||||
args = parser.parse_args()
|
||||
kg = kg_implementation(args.source, args.destination)
|
||||
kg.processdir()
|
|
@ -1,43 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
source ./constraint.sh
|
||||
|
||||
if [ ${ID} -ne 0 ]; then
|
||||
echo "This script has to be run as root."
|
||||
exit
|
||||
fi
|
||||
|
||||
clean(){
|
||||
echo Done, cleaning.
|
||||
${SYNC}
|
||||
kill -9 $(cat /tmp/music.pid)
|
||||
rm -f /tmp/music.pid
|
||||
}
|
||||
|
||||
trap clean EXIT TERM INT
|
||||
|
||||
./music.sh &
|
||||
echo $! > /tmp/music.pid
|
||||
|
||||
# Dumb libreoffice wants to write into ~/libreoffice or crash with
|
||||
# com::sun::star::uno::RuntimeException
|
||||
mkdir /tmp/libreoffice
|
||||
chown -R kitten:kitten /tmp/libreoffice
|
||||
# Avoid:
|
||||
# Failed to connect to /usr/lib/libreoffice/program/soffice.bin (pid=2455) in 6 seconds.
|
||||
# Connector : couldn't connect to socket (Success)
|
||||
# Error: Unable to connect or start own listener. Aborting.
|
||||
mkdir /tmp/libreoffice_config
|
||||
chown -R kitten:kitten /tmp/libreoffice_config
|
||||
|
||||
# Reject all network connexions.
|
||||
iptables -F
|
||||
iptables -A INPUT -j REJECT
|
||||
iptables -A OUTPUT -j REJECT
|
||||
iptables -A FORWARD -j REJECT
|
||||
|
||||
su ${USERNAME} -c ./groomer.sh
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
#set -x
|
||||
|
||||
source ./constraint.sh
|
||||
|
||||
killed(){
|
||||
echo 'Music stopped.'
|
||||
}
|
||||
|
||||
trap killed EXIT TERM INT
|
||||
|
||||
# Force output on analog
|
||||
amixer cset numid=3 1
|
||||
|
||||
files=(${MUSIC}*)
|
||||
|
||||
while true; do
|
||||
$TIMIDITY ${files[RANDOM % ${#files[@]}]}
|
||||
done
|
|
@ -10,6 +10,9 @@
|
|||
# bits.
|
||||
#
|
||||
# By default this script does nothing.
|
||||
#
|
||||
# The above are the default comments for rc.local. For Circlean, rc.local has
|
||||
# been modified to start the grooming process on boot.
|
||||
|
||||
clean(){
|
||||
echo 'Rc Local done, quit.'
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from RPi import GPIO
|
||||
import time
|
||||
|
||||
|
||||
# blinking function
|
||||
def blink(pin):
|
||||
GPIO.output(pin, GPIO.HIGH)
|
||||
time.sleep(.1)
|
||||
GPIO.output(pin, GPIO.LOW)
|
||||
time.sleep(.1)
|
||||
return
|
||||
|
||||
|
||||
def test_leds():
|
||||
# to use Raspberry Pi board pin numbers
|
||||
GPIO.setmode(GPIO.BOARD)
|
||||
pins = [11, 12, 15]
|
||||
# set up GPIO output channel
|
||||
for pin in pins:
|
||||
GPIO.setup(pin, GPIO.OUT)
|
||||
|
||||
# blink GPIO17 50 times
|
||||
for i in range(0, 50):
|
||||
for pin in pins:
|
||||
blink(pin)
|
||||
|
||||
|
||||
def test_button():
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
|
||||
button = 23
|
||||
GPIO.setup(button, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
while True:
|
||||
GPIO.wait_for_edge(button, GPIO.RISING)
|
||||
|
||||
print("Button Pressed")
|
||||
|
||||
GPIO.wait_for_edge(button, GPIO.FALLING)
|
||||
|
||||
print("Button Released")
|
||||
|
||||
|
||||
test_button()
|
||||
|
||||
GPIO.cleanup()
|
|
@ -1,13 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script will mount a given image or sd card in loop mode.
|
||||
# Make sure to change the path and offsets for the image you use. You can get
|
||||
# the correct offsets using `file $PATH_TO_IMAGE` or fdisk.
|
||||
# If you want to mount an SD card, unset $IMAGE.
|
||||
|
||||
# To make debugging easier
|
||||
echo "KittenGroomer: in mount_image.sh" 1>&2
|
||||
|
||||
# Notes:
|
||||
# - To chroot in an existing SD card, unset IMAGE. Change the paths to the partitions if needed.
|
||||
# - The offsets are thoses of 2013-02-09-wheezy-raspbian.img. It will change on an other image.
|
||||
# To get the offsets, use the "file" command.
|
||||
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
echo "This script must be run as root" 1>&2
|
||||
exit 1
|
||||
|
@ -33,21 +33,17 @@ PARTITION_BOOT='/dev/mmcblk0p1'
|
|||
#PARTITION_ROOTFS='/dev/sdd2'
|
||||
#PARTITION_BOOT='/dev/sdd1'
|
||||
|
||||
# If you use the img
|
||||
# If you use the img...
|
||||
# Double check the path and offsets as noted above!
|
||||
##### Debian
|
||||
IMAGE='2016-05-09_CIRCLean.img'
|
||||
OFFSET_ROOTFS=$((131072 * 512))
|
||||
OFFSET_BOOT=$((8192 * 512))
|
||||
##### Arch
|
||||
#IMAGE='archlinux-hf-2013-02-11.img'
|
||||
#OFFSET_ROOTFS=$((186368 * 512))
|
||||
#OFFSET_BOOT=$((2048 * 512))
|
||||
############
|
||||
OFFSET_ROOTFS=$((131072 * 512))
|
||||
|
||||
CHROOT_PATH='/mnt/arm_rPi'
|
||||
|
||||
clean(){
|
||||
mv ${CHROOT_PATH}/etc/ld.so.preload_bkp ${CHROOT_PATH}/etc/ld.so.preload
|
||||
mv ${CHROOT_PATH}/etc/ld.so.preload_backup ${CHROOT_PATH}/etc/ld.so.preload
|
||||
rm ${CHROOT_PATH}/etc/resolv.conf
|
||||
rm ${CHROOT_PATH}/usr/bin/qemu*arm*
|
||||
|
||||
|
@ -79,7 +75,7 @@ elif [ -a ${PARTITION_ROOTFS} ]; then
|
|||
mount ${PARTITION_ROOTFS} ${CHROOT_PATH}
|
||||
mount ${PARTITION_BOOT} ${CHROOT_PATH}/boot
|
||||
else
|
||||
print 'You need a SD card or an image'
|
||||
echo 'You need a SD card or an image'
|
||||
exit
|
||||
fi
|
||||
|
||||
|
@ -95,7 +91,7 @@ mount -o bind /tmp ${CHROOT_PATH}/tmp
|
|||
|
||||
cp -pf /etc/resolv.conf ${CHROOT_PATH}/etc
|
||||
|
||||
mv ${CHROOT_PATH}/etc/ld.so.preload ${CHROOT_PATH}/etc/ld.so.preload_bkp
|
||||
mv ${CHROOT_PATH}/etc/ld.so.preload ${CHROOT_PATH}/etc/ld.so.preload_backup
|
||||
|
||||
# To make debugging easier
|
||||
echo "KittenGroomer: Image mounted, executing command from mount_image.sh" 1>&2
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# change locales to en_US.UTF-8
|
||||
dpkg-reconfigure locales
|
||||
|
||||
# Increase size of image. See resize_img.md
|
||||
|
||||
apt-get update
|
||||
apt-get dist-upgrade
|
||||
apt-get autoremove
|
||||
|
||||
# build dependencies of pdf2htmlEX
|
||||
apt-get install cmake debhelper libpoppler-dev libjpeg-dev libfontforge-dev \
|
||||
libspiro-dev python-dev default-jre-headless libpoppler-private-dev
|
|
@ -10,16 +10,6 @@ apt-get autoremove
|
|||
apt-get install libreoffice p7zip-full libfontforge1 timidity freepats pmount
|
||||
dpkg -i pdf2htmlex*.deb
|
||||
|
||||
# Make Libreoffice usable on a RO filesystem
|
||||
useradd -m kitten
|
||||
pushd /home/kitten
|
||||
ln -s /tmp/libreoffice
|
||||
popd
|
||||
|
||||
chown -R kitten:kitten /home/kitten
|
||||
|
||||
ln -s /proc/mounts /etc/mtab
|
||||
|
||||
# Disable swap
|
||||
dphys-swapfile uninstall
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# We cannot use the version 0.12 because it requires fontforge 2.0
|
||||
# The fork use a saner list of dependencies and a patch that allows to build on debian jessie.
|
||||
|
||||
wget https://github.com/Rafiot/pdf2htmlEX/archive/KittenGroomer.zip
|
||||
unzip KittenGroomer.zip
|
||||
|
||||
cd pdf2htmlEX-KittenGroomer/
|
||||
|
||||
dpkg-buildpackage -uc -b
|
Loading…
Reference in New Issue