sstea備忘録

日々のPCライフのメモ、備忘録、及びそれに類推する何か。
記載内容に間違い等を発見された場合はコッソリ教えてください... → sstea<a>aol.jp (<a> を @ に変えてください)


Raspbian(2015-11-21)のLITE版と通常版の違い

◆2015-11-21リリース Raspbian

気が付いたら新しいRaspbian(2015-11-21-raspbian-jessie)がリリースされてました。
通常版に加えて、LITE版もありました。

LITE版は最小構成のようで、デスクトップ関連のパッケージは入っていません。
LITE版と通常版で、具体的にどのパッケージが違うのか(需要があるかは分かりませんが)知りたかったので調べてみました。

◆"df" 結果
使用サイズはLITE版は1GB程、通常版は3.5GB程です。
通常版でも4GBのmicroSDに何とか入ります。

  2015-11-21-raspbian-jessie-lite
$ df
Filesystem     1K-blocks   Used Available Use% Mounted on
/dev/root        1304692 952540    267828  79% /
devtmpfs          469748      0    469748   0% /dev
tmpfs             474052      0    474052   0% /dev/shm
tmpfs             474052   6276    467776   2% /run
tmpfs               5120      4      5116   1% /run/lock
tmpfs             474052      0    474052   0% /sys/fs/cgroup
/dev/mmcblk0p1     61384  20296     41088  34% /boot

  2015-11-21-raspbian-jessie
$ df
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/root        3651636 3346332    100096  98% /
devtmpfs          469748       0    469748   0% /dev
tmpfs             474052       0    474052   0% /dev/shm
tmpfs             474052    6384    467668   2% /run
tmpfs               5120       4      5116   1% /run/lock
tmpfs             474052       0    474052   0% /sys/fs/cgroup
/dev/mmcblk0p1     61384   20296     41088  34% /boot
tmpfs              94812       0     94812   0% /run/user/1000

◆"dpkg -l" 結果

それぞれのパッケージ一覧("dpkg -l" した結果)は、下記です。(別ファイルにしてあります)

  2015-11-21-raspbian-jessie-lite

  2015-11-21-raspbian-jessie


◆パッケージ差分
下記が 2015-11-21 Raspbian のLITE版と通常版のパッケージ差分になります。
下記ピンク色のパッケージがLITE版にはなく、通常版にのみ含まれているパッケージになります。
(黒色のパッケージはLITE版、通常版に共通で含まれているパッケージです。)

acl
adduser
adwaita-icon-theme
alacarte
alsa-base
alsa-utils
apt
apt-utils
aptitude
aptitude-common
aspell
aspell-en
avahi-daemon
base-files
base-passwd
bash
bash-completion
bind9-host
binutils
blt
bluej
bsdmainutils
bsdutils
build-essential
bzip2
ca-certificates
cifs-utils
claws-mail
claws-mail-i18n
coinor-libcbc3
coinor-libcgl1
coinor-libclp1
coinor-libcoinmp1:armhf
coinor-libcoinutils3
coinor-libosi1
console-setup
console-setup-linux
coreutils
cpio
cpp
cpp-4.9
crda
cron
cryptsetup-bin
cups-bsd
cups-client
cups-common
curl
dash
dbus
dbus-x11
dc
dconf-gsettings-backend:armhf
dconf-service
debconf
debconf-i18n
debconf-utils
debian-reference-common
debian-reference-en
debianutils
desktop-base
desktop-file-utils
dh-python
dhcpcd5
dictionaries-common
diffutils
dillo
dmidecode
dmsetup
dosfstools
dphys-swapfile
dpkg
dpkg-dev
e2fslibs:armhf
e2fsprogs
ed
eject
emacsen-common
epiphany-browser
epiphany-browser-data
esound-common
fake-hwclock
fakeroot
fbset
file
findutils
firmware-atheros
firmware-brcm80211
firmware-libertas
firmware-ralink
firmware-realtek
fontconfig
fontconfig-config
fonts-dejavu
fonts-dejavu-core
fonts-dejavu-extra
fonts-freefont-ttf
fonts-opensymbol
fonts-roboto
fonts-sil-gentium-basic
freepats
fuse
g++
g++-4.9
galculator
gcc
gcc-4.6-base:armhf
gcc-4.7-base:armhf
gcc-4.8-base:armhf
gcc-4.9
gcc-4.9-base:armhf
gconf-service
gconf2
gconf2-common

gdb
gdbserver
gdebi-core
geoip-database
gettext-base
giblib1:armhf
gir1.2-atk-1.0
gir1.2-freedesktop:armhf
gir1.2-gdkpixbuf-2.0
gir1.2-glib-2.0:armhf
gir1.2-gmenu-3.0
gir1.2-gtk-3.0:armhf
gir1.2-pango-1.0:armhf
git
git-core
git-man
gksu
glib-networking:armhf
glib-networking-common
glib-networking-services
gnome-desktop3-data
gnome-icon-theme
gnome-icon-theme-symbolic
gnome-menus
gnome-themes-standard:armhf
gnome-themes-standard-data

gnupg
gnupg-agent
gnupg2
gpgv
gpicview
greenfoot

grep
groff-base
gsettings-desktop-schemas
gsfonts
gsfonts-x11
gstreamer0.10-alsa:armhf
gstreamer0.10-plugins-base:armhf
gstreamer1.0-alsa:armhf
gstreamer1.0-libav:armhf
gstreamer1.0-omx
gstreamer1.0-plugins-bad:armhf
gstreamer1.0-plugins-base:armhf
gstreamer1.0-plugins-good:armhf
gstreamer1.0-x:armhf
gtk2-engines:armhf
gtk2-engines-clearlookspix:armhf
gtk2-engines-pixbuf:armhf
gvfs:armhf
gvfs-backends
gvfs-common
gvfs-daemons
gvfs-fuse
gvfs-libs:armhf

gzip
hardlink
hdparm
hicolor-icon-theme

hostname
idle
idle-python2.7
idle-python3.4
idle3

ifupdown
info
init
init-system-helpers
initramfs-tools
initscripts
insserv
install-info
iproute2
iptables
iputils-ping
isc-dhcp-client
isc-dhcp-common
iso-codes
iw
jackd
jackd2
java-common
javascript-common
kbd
keyboard-configuration
klibc-utils
kmod
krb5-locales
leafpad
less
libaa1:armhf
libabw-0.1-1

libacl1:armhf
libalgorithm-c3-perl
libalgorithm-diff-perl
libalgorithm-diff-xs-perl
libalgorithm-merge-perl
libapt-inst1.5:armhf
libapt-pkg4.12:armhf
libarchive-extract-perl
libarchive13:armhf
libasan1:armhf
libasn1-8-heimdal:armhf
libasound2:armhf
libasound2-data
libaspell15:armhf
libasprintf0c2:armhf
libass5:armhf
libassuan0:armhf
libasyncns0:armhf
libatasmart4:armhf
libatk-bridge2.0-0:armhf
libatk1.0-0:armhf
libatk1.0-data
libatlas3-base

libatomic1:armhf
libatspi2.0-0:armhf
libattr1:armhf
libaudio2:armhf
libaudiofile1:armhf

libaudit-common
libaudit1:armhf
libavahi-client3:armhf
libavahi-common-data:armhf
libavahi-common3:armhf
libavahi-core7:armhf
libavahi-glib1:armhf
libavahi-gobject0:armhf
libavc1394-0:armhf
libavcodec56:armhf
libavformat56:armhf
libavresample2:armhf
libavutil54:armhf

libbind9-90
libblas-common
libblas3

libblkid1:armhf
libbluetooth3:armhf
libbluray1:armhf
libboost-atomic1.55.0:armhf
libboost-date-time1.55.0:armhf
libboost-filesystem1.55.0:armhf

libboost-iostreams1.49.0
libboost-iostreams1.50.0
libboost-iostreams1.53.0
libboost-iostreams1.54.0:armhf
libboost-iostreams1.55.0:armhf
libboost-program-options1.55.0:armhf
libboost-regex1.55.0:armhf
libboost-system1.55.0:armhf
libboost-thread1.55.0:armhf

libbsd0:armhf
libbz2-1.0:armhf
libc-ares2:armhf
libc-bin
libc-dev-bin
libc6:armhf
libc6-dbg:armhf
libc6-dev:armhf
libcaca0:armhf
libcairo-gobject2:armhf
libcairo2:armhf
libcanberra-gtk3-0:armhf
libcanberra0:armhf

libcap-ng0:armhf
libcap2:armhf
libcap2-bin
libcdio-cdda1
libcdio-paranoia1
libcdio13
libcdparanoia0:armhf
libcdr-0.1-1

libcgi-fast-perl
libcgi-pm-perl
libchromaprint0:armhf
libclass-c3-perl
libclass-c3-xs-perl
libcloog-isl4:armhf
libclucene-contribs1:armhf
libclucene-core1:armhf
libcmis-0.4-4
libcolamd2.8.0:armhf
libcolord2:armhf

libcomerr2:armhf
libcompfaceg1
libcpan-meta-perl
libcroco3:armhf
libcryptsetup4:armhf
libcups2:armhf
libcupsfilters1:armhf
libcupsimage2:armhf

libcurl3:armhf
libcurl3-gnutls:armhf
libcwidget3:armhf
libcwiid1
libdaemon0:armhf
libdata-optlist-perl
libdata-section-perl
libdatrie1:armhf
libdb5.3:armhf
libdbus-1-3:armhf
libdbus-glib-1-2:armhf
libdc1394-22:armhf
libdca0:armhf
libdconf1:armhf

libdebconfclient0:armhf
libdevmapper-event1.02.1:armhf
libdevmapper1.02.1:armhf
libdirectfb-1.2-9:armhf
libdns-export100
libdns100
libdpkg-perl
libdrm-freedreno1:armhf
libdrm-nouveau2:armhf
libdrm-radeon1:armhf

libdrm2:armhf
libdv4:armhf
libdvdnav4:armhf
libdvdread4:armhf
libe-book-0.1-1

libedit2:armhf
libegl1-mesa:armhf
libelf1:armhf
libelfg0:armhf
libenca0:armhf
libenchant1c2a:armhf
libeot0
libepoxy0
liberror-perl
libesd0:armhf

libestr0
libetonyek-0.1-1
libetpan17:armhf
libevdev2

libevent-2.0-5:armhf
libexif12:armhf
libexpat1:armhf
libexpat1-dev:armhf
libexttextcat-2.0-0
libexttextcat-data
libfaad2:armhf

libfakeroot:armhf
libfcgi-perl
libffi5:armhf
libffi6:armhf
libfftw3-double3:armhf
libfftw3-single3:armhf

libfile-fcntllock-perl
libflac8:armhf
libflite1:armhf
libfltk1.3:armhf
libfluidsynth1:armhf
libfm-data
libfm-extra4:armhf
libfm-gtk-data
libfm-gtk4:armhf
libfm-modules:armhf
libfm4:armhf
libfontconfig1:armhf
libfontenc1:armhf
libfreehand-0.1-1

libfreetype6:armhf
libfreetype6-dev
libfribidi0:armhf
libfuse2:armhf
libgbm1:armhf

libgcc-4.9-dev:armhf
libgcc1:armhf
libgconf-2-4:armhf
libgcrypt20:armhf
libgd3:armhf
libgdbm3:armhf
libgdk-pixbuf2.0-0:armhf
libgdk-pixbuf2.0-common
libgeoclue0:armhf

libgeoip1:armhf
libgfortran3:armhf
libgif4:armhf
libgirepository-1.0-1:armhf
libgksu2-0
libgl1-mesa-glx:armhf
libglapi-mesa:armhf
libglew1.10:armhf

libglib2.0-0:armhf
libglib2.0-bin
libglib2.0-data
libgltf-0.0-0
libglu1-mesa:armhf
libgme0

libgmp10:armhf
libgnome-desktop-3-10
libgnome-keyring-common
libgnome-keyring0:armhf
libgnome-menu-3-0

libgnutls-deb0-28:armhf
libgnutls-openssl27:armhf
libgoa-1.0-0b:armhf
libgoa-1.0-common

libgomp1:armhf
libgpg-error0:armhf
libgpgme11:armhf
libgphoto2-6:armhf
libgphoto2-port10:armhf
libgpm2:armhf
libgraphite2-3:armhf
libgsm1:armhf

libgssapi-krb5-2:armhf
libgssapi3-heimdal:armhf
libgstreamer-plugins-bad1.0-0:armhf
libgstreamer-plugins-base0.10-0:armhf
libgstreamer-plugins-base1.0-0:armhf
libgstreamer0.10-0:armhf
libgstreamer1.0-0:armhf
libgtk-3-0:armhf
libgtk-3-bin
libgtk-3-common
libgtk2.0-0:armhf
libgtk2.0-bin
libgtk2.0-common
libgtkglext1
libgtop2-7
libgtop2-common
libgudev-1.0-0:armhf

libharfbuzz-icu0:armhf
libharfbuzz0b:armhf
libhcrypto4-heimdal:armhf
libheimbase1-heimdal:armhf
libheimntlm0-heimdal:armhf

libhogweed2:armhf
libhsqldb1.8.0-java
libhunspell-1.3-0:armhf
libhx509-5-heimdal:armhf
libhyphen0
libice6:armhf

libicu52:armhf
libid3tag0
libident
libidn11:armhf
libiec61883-0:armhf
libilmbase6:armhf
libimlib2
libimobiledevice4:armhf

libirs-export91
libisc-export95
libisc95
libisccc90
libisccfg-export90
libisccfg90
libisl10:armhfts
libiw30:armhf
libjack-jackd2-0:armhf
libjasper1:armhf
libjavascriptcoregtk-3.0-0:armhf
libjbig0:armhf

libjpeg62-turbo:armhf
libjpeg8:armhf
libjs-jquery
libjs-prettify

libjson-c2:armhf
libjson-glib-1.0-0:armhf
libjson-glib-1.0-common

libk5crypto3:armhf
libkate1
libkeyutils1:armhf
libklibc
libkmod2:armhf
libkrb5-26-heimdal:armhf
libkrb5-3:armhf
libkrb5support0:armhf
libksba8:armhf
liblangtag-common
liblangtag1
liblapack3
liblcms2-2:armhf

libldap-2.4-2:armhf
libldb1:armhf
liblightdm-gobject-1-0
libllvm3.5:armhf

liblocale-gettext-perl
liblockfile-bin
liblockfile1:armhf

liblog-message-perl
liblog-message-simple-perl
liblogging-stdlog0:armhf
liblognorm1:armhf
libltdl7:armhf
libluajit-5.1-common
liblvm2app2.2:armhf
liblwres90
liblzma5:armhf
liblzo2-2:armhf
libmad0:armhf

libmagic1:armhf
libmenu-cache-bin
libmenu-cache3:armhf
libmhash2:armhf
libmikmod3:armhf
libmimic0
libmjpegutils-2.1-0
libmms0:armhf
libmng1:armhf
libmodplug1

libmodule-build-perl
libmodule-pluggable-perl
libmodule-signature-perl
libmotif-common
libmount1:armhf
libmozjs185-1.0
libmp3lame0:armhf

libmpc3:armhf
libmpdec2:armhf
libmpeg2encpp-2.1-0

libmpfr4:armhf
libmpg123-0:armhf
libmplex2-2.1-0

libmro-compat-perl
libmspub-0.1-1
libmtdev1:armhf
libmtp-common
libmtp9:armhf
libmwaw-0.3-3
libmythes-1.2-0

libncurses5:armhf
libncursesw5:armhf
libneon27-gnutls
libnettle4:armhf
libnewt0.52:armhf
libnfnetlink0:armhf
libnfsidmap2:armhf
libnih-dbus1
libnih1
libnl-3-200:armhf
libnl-genl-3-200:armhf
libnotify4:armhf
libnspr4:armhf

libnss-mdns:armhf
libnss3:armhf
libntdb1:armhf
libobrender29
libobt2
libodfgen-0.1-1
libofa0
libogg0:armhf
libopenal-data
libopenal1:armhf
libopencv-calib3d2.4:armhf
libopencv-contrib2.4:armhf
libopencv-core2.4:armhf
libopencv-features2d2.4:armhf
libopencv-flann2.4:armhf
libopencv-highgui2.4:armhf
libopencv-imgproc2.4:armhf
libopencv-legacy2.4:armhf
libopencv-ml2.4:armhf
libopencv-objdetect2.4:armhf
libopencv-video2.4:armhf
libopenexr6:armhf
libopenjpeg5:armhf

libopts25:armhf
libopus0:armhf
liborc-0.4-0:armhf
liborcus-0.8-0

libp11-kit0:armhf
libpackage-constants-perl
libpackagekit-glib2-18:armhf
libpam-modules:armhf
libpam-modules-bin
libpam-runtime
libpam-systemd:armhf
libpam0g:armhf
libpango-1.0-0:armhf
libpango1.0-0:armhf
libpangocairo-1.0-0:armhf
libpangoft2-1.0-0:armhf
libpangox-1.0-0:armhf
libpangoxft-1.0-0:armhf

libparams-util-perl
libparted2:armhf
libpciaccess0:armhf
libpcre3:armhf
libpcsclite1:armhf
libpipeline1:armhf
libpisock9
libpixman-1-0:armhf
libplist2:armhf

libpng12-0:armhf
libpng12-dev:armhf
libpod-latex-perl
libpod-readme-perl
libpolkit-agent-1-0:armhf
libpolkit-backend-1-0:armhf
libpolkit-gobject-1-0:armhf
libpoppler46:armhf

libpopt0:armhf
libportaudio2:armhf
libportmidi0

libprocps3:armhf
libproxy1:armhf
libpsl0:armhf
libpth20:armhf
libpulse0:armhf

libpython-stdlib:armhf
libpython2.7:armhf
libpython2.7-minimal:armhf
libpython2.7-stdlib:armhf7)
libpython3-dev:armhf
libpython3-stdlib:armhf
libpython3.4:armhf
libpython3.4-dev:armhf
libpython3.4-minimal:armhf
libpython3.4-stdlib:armhf4)
libqscintilla2-11
libqscintilla2-l10n
libqt4-dbus:armhf
libqt4-network:armhf
libqt4-xml:armhf
libqt4-xmlpatterns:armhf
libqtcore4:armhf
libqtdbus4:armhf
libqtgui4:armhf
libqtwebkit4:armhf
libraptor2-0:armhf

libraspberrypi-bin
libraspberrypi-dev
libraspberrypi-doc
libraspberrypi0
librasqal3:armhf
libraw1394-11:armhf
librdf0:armhf

libreadline6:armhf
libregexp-common-perl
libreoffice
libreoffice-avmedia-backend-gstreamer
libreoffice-base
libreoffice-base-core
libreoffice-base-drivers
libreoffice-calc
libreoffice-common
libreoffice-core
libreoffice-draw
libreoffice-gtk
libreoffice-impress
libreoffice-java-common
libreoffice-math
libreoffice-report-builder-bin
libreoffice-sdbc-hsqldb
libreoffice-style-galaxy
libreoffice-writer

librest-0.7-0:armhf
librevenge-0.0-0
libroken18-heimdal:armhf
librsvg2-2:armhf
librsvg2-common:armhf
librtimulib-dev
librtimulib-utils
librtimulib7)

librtmp1:armhf
libruby1.9.1
libruby1.9.1-dbg
libruby2.1:armhf

libsamplerate0:armhf
libsasl2-2:armhf
libsasl2-modules:armhf
libsasl2-modules-db:armhf
libsbc1:armhf
libschroedinger-1.0-0:armhf
libscsynth1
libsdl-image1.2:armhf
libsdl-mixer1.2:armhf
libsdl-ttf2.0-0:armhf
libsdl1.2debian:armhf
libsecret-1-0:armhf
libsecret-common

libselinux1:armhf
libsemanage-common
libsemanage1:armhf
libsepol1:armhf
libservlet2.5-java
libsgutils2-2
libshout3:armhf

libsigc++-1.2-5c2
libsigc++-2.0-0c2a:armhf
libslang2:armhf
libsm6:armhf
libsmartcols1:armhf
libsmbclient:armhf
libsndfile1:armhf

libsoftware-license-perl
libsoundtouch0:armhf
libsoup-gnome2.4-1:armhf
libsoup2.4-1:armhf
libspandsp2:armhf
libspeex1:armhf

libsqlite3-0:armhf
libsrtp0
libss2:armhf
libssh-4:armhf
libssh2-1:armhf
libssl1.0.0:armhf
libstartup-notification0:armhf
libstdc++-4.9-dev:armhf
libstdc++6:armhf
libsub-exporter-perl
libsub-install-perl
libswscale3:armhf
libsysfs2:armhf
libsystemd0:armhf
libtag1-vanilla:armhf
libtag1c2a:armhf

libtalloc2:armhf
libtasn1-6:armhf
libtcl8.5:armhf
libtcl8.6:armhf
libtcltk-ruby1.9.1
libtdb1:armhf

libterm-ui-perl
libtevent0:armhf
libtext-charwidth-perl
libtext-iconv-perl
libtext-soundex-perl
libtext-template-perl
libtext-wrapi18n-perl
libthai-data
libthai0:armhf
libtheora0:armhf
libtiff5:armhf

libtimedate-perl
libtinfo5:armhf
libtirpc1:armhf
libtk8.5:armhf
libtk8.6:armhf

libubsan0:armhf
libudev0:armhf
libudev1:armhf
libudisks2-0:armhf
libusb-0.1-4:armhf
libusb-1.0-0:armhf
libusbmuxd2:armhf
libustr-1.0-1:armhf
libuuid1:armhf
libv4l-0:armhf
libv4l2rds0:armhf
libv4lconvert0:armhf
libv8-3.14.5
libva1:armhf
libvdpau1:armhf
libvisio-0.1-1
libvisual-0.4-0:armhf
libvisual-0.4-plugins:armhf
libvo-aacenc0:armhf
libvo-amrwbenc0:armhf
libvorbis0a:armhf

libvorbisenc2:armhf
libvorbisfile3:armhf
libvpx1:armhf
libvte-common
libvte9
libwavpack1:armhf
libwayland-client0:armhf
libwayland-cursor0:armhf
libwayland-server0:armhf

libwbclient0:armhf
libwebkitgtk-3.0-0:armhf
libwebkitgtk-3.0-common
libwebp5:armhf
libwebpdemux1:armhf
libwebpmux1:armhf
libwildmidi-config
libwildmidi1:armhf
libwind0-heimdal:armhf
libwnck-3-0:armhf
libwnck-3-common
libwnck-common
libwnck22
libwpd-0.10-10
libwpg-0.3-3
libwps-0.3-3

libwrap0:armhf
libx11-6:armhf
libx11-data
libx11-xcb1:armhf
libx264-142:armhf

libxapian22
libxau6:armhf
libxaw7:armhf
libxcb-dri2-0:armhf
libxcb-dri3-0:armhf
libxcb-glx0:armhf
libxcb-present0:armhf
libxcb-render0:armhf
libxcb-shape0:armhf
libxcb-shm0:armhf
libxcb-sync1:armhf
libxcb-util0:armhf
libxcb-xfixes0:armhf

libxcb1:armhf
libxcomposite1:armhf
libxcursor1:armhf
libxdamage1:armhf

libxdmcp6:armhf
libxext6:armhf
libxfce4ui-1-0
libxfce4util-bin
libxfce4util-common
libxfce4util6
libxfconf-0-2
libxfixes3:armhf
libxfont1:armhf
libxft2:armhf
libxi6:armhf
libxinerama1:armhf
libxkbcommon0:armhf
libxkbfile1:armhf
libxklavier16
libxm4:armhf

libxml2:armhf
libxmu6:armhf
libxmuu1:armhf
libxpm4:armhf
libxrandr2:armhf
libxrender1:armhf
libxres1:armhf
libxshmfence1:armhf
libxslt1.1:armhf
libxss1:armhf
libxt6:armhf
libxtables10
libxtst6:armhf
libxv1:armhf
libxvidcore4:armhf
libxxf86dga1:armhf
libxxf86vm1:armhf
libyajl2:armhf
libyaml-0-2:armhf
libzbar0
lightdm
lightdm-gtk-greeter

linux-libc-dev:armhf
locales
login
logrotate
lp-solve
lsb-base
lsb-release
lua5.1
luajit
lxappearance
lxappearance-obconf
lxde
lxde-common
lxde-core
lxde-icon-theme
lxinput
lxkeymap
lxmenu-data
lxpanel
lxpanel-data
lxrandr
lxsession
lxtask
lxterminal

make
makedev
man-db
manpages
manpages-dev
mawk
menu-xdg
mime-support
minecraft-pi
module-init-tools
mount
mountall
multiarch-support
nano
ncdu
ncurses-base
ncurses-bin
ncurses-term
net-tools
netbase
netcat-openbsd
netcat-traditional
netsurf-common
netsurf-gtk

nfs-common
nodejs
nodejs-legacy
nodered
ntfs-3g

ntp
nuscratch
omxplayer
openbox

openresolv
openssh-client
openssh-server
openssh-sftp-server
openssl
oracle-java8-jdk
packagekit

parted
passwd
patch
pcmanfm
penguinspuzzle

perl
perl-base
perl-modules
pi-package
pi-package-data
pi-package-session
pimixer
pinentry-gtk2
pipanel

pkg-config
plymouth
policykit-1
poppler-data
poppler-utils
powermgmt-base

procps
psmisc
pypy-setuptools
pypy-upstream
pypy-upstream-dev
pypy-upstream-doc

python
python-apt-common
python-cairo
python-chardet
python-colorama
python-dbus
python-dbus-dev
python-distlib
python-gi
python-gobject
python-gobject-2
python-gpiozero
python-gtk2
python-html5lib
python-minecraftpi

python-minimal
python-ndg-httpsclient
python-numpy
python-openssl
python-picamera
python-pifacecommon
python-pifacedigitalio
python-pil:armhf
python-pip
python-pkg-resources
python-pyasn1
python-pygame
python-requests

python-rpi.gpio
python-rtimulib
python-sense-hat
python-serial
python-setuptools
python-six
python-spidev
python-support
python-talloc
python-tk
python-urllib3
python-wheel
python-xklavier

python2.7
python2.7-minimal
python3
python3-apt
python3-chardet
python3-colorama
python3-debian
python3-dev
python3-distlib
python3-gpiozero

python3-html5lib
python3-minecraftpi
python3-minimal
python3-numpy
python3-pgzero
python3-picamera
python3-pifacecommon
python3-pifacedigital-scratch-handler
python3-pifacedigitalio
python3-pil:armhf
python3-pip
python3-pkg-resources
python3-pygame
python3-requests
python3-rpi.gpio

python3-rtimulib
python3-sense-hat
python3-serial
python3-setuptools
python3-six
python3-spidev
python3-tk
python3-uno
python3-urllib3
python3-wheel
python3.4
python3.4-dev
python3.4-minimal

qdbus
qjackctl
qtchooser
qtcore4-l10n
raspberrypi-artwork

raspberrypi-bootloader
raspberrypi-net-mods
raspberrypi-sys-mods
raspberrypi-ui-mods

raspbian-archive-keyring
raspi-config
raspi-copies-and-fills
rc-gui
readline-common
rename
ri1.9.1
rpcbind
rpi-update
rsync

rsyslog
ruby
ruby1.9.1
ruby1.9.1-dev
ruby1.9.1-examples
ruby1.9.1-full
ruby1.9.3
ruby2.1
rubygems-integration

samba-common
samba-libs:armhf
scratch
scrot

sed
sense-hat
sensible-utils
sgml-base
shared-mime-info
smartsim
sonic-pi
squeak-plugins-scratch
squeak-vm

ssh
startpar
strace
sudo
supercollider
supercollider-common
supercollider-ide
supercollider-language
supercollider-server
supercollider-supernova

systemd
systemd-sysv
sysv-rc
sysvinit-utils
tar
tasksel
tasksel-data
tcl8.5
tcpd
timidity
tk8.5
tk8.6-blt2.5

traceroute
tree
triggerhappy
tzdata
ucf
udev
udisks
udisks2
uno-libs3

unzip
ure
usbutils
util-linux
v4l-utils
va-driver-all:armhf
vdpau-va-driver:armhf

vim-common
vim-tiny
wget
whiptail
wireless-regdb
wireless-tools
wiringpi
wolfram-engine

wpasupplicant
x11-common
x11-utils
x11-xkb-utils
x11-xserver-utils
x2x
xarchiver

xauth
xdg-user-dirs
xdg-utils
xfce-keyboard-shortcuts
xfconf
xfonts-100dpi
xfonts-encodings
xfonts-utils
xinit

xkb-data
xml-core
xpdf
xserver-common
xserver-xorg
xserver-xorg-core
xserver-xorg-input-all
xserver-xorg-input-evdev
xserver-xorg-input-synaptics
xserver-xorg-video-fbdev
xserver-xorg-video-fbturbo

xz-utils
zenity
zenity-common

zlib1g:armhf
zlib1g-dev:armhf


VPN サーバー(SoftEther) のログ出力先を変更する


以前に Raspberry Pi 上で VPN サーバーを構築し、常時稼動させるようにしました。

特に問題なく安定稼動していたので、それ以後 VPN 関連の設定は弄ることなく放置していたのですが、久しぶりに眺めていて、/home/pi/local/vpnserver/ の中を見てみると、
・ backup.vpn_server.config/
・ server_log/
それぞれのディレクトリ以下に何かファイルがいっぱいできています。
自分は正直、ログとか見ないですし、ディスクイメージごとバックアップも取ってあり、これらファイルは不要です。

ログファイルとかは、どうせなら /var/log/ 以下に作って欲しいんですが。。。
/var/log/ 以下は既に tmpfs にしてありますのでリブートすればさっぱり綺麗になります。)

まずは正攻法でこれらログ出力の停止、出力先の変更を試みようと思います。

◆SoftEther でのログ出力設定
Windows マシンにインストールした「SoftEther VPN サーバー管理マネージャ」を立ち上げます。

[仮想 HUB の管理]から
[ログ保存設定]ボタンで、「セキュリティログ」「パケットログ」はチェックを外せば残さなくできます。

ss_softether_log

自分は既にチェック外していたので、packet_log/、security_log/ の中にログっぽいものはありませんでした。

一通り見てみましたが、上記以外にログ設定関連の項目はなさそうです。。。

◆VPNサーバーのログ出力先変更
ファイルいっぱいできるのは何か気持ち悪いので、ログの出力先を /var/log/ 以下に出力するようにしようと思います。

まず、vpnserver を停止させます。
$ sudo /etc/init.d/vpnserver stop

今あるログディレクトリ等を削除し、リンクを作成します。
$ export LOGDIR=/var/log/vpnserver
$ cd /home/pi/local/vpnserver/

$ sudo rm -rf backup.vpn_server.config
$ sudo rm -rf packet_log
$ sudo rm -rf security_log
$ sudo rm -rf server_log

$ sudo ln -s ${LOGDIR}/backup.vpn_server.config/ backup.vpn_server.config
$ sudo ln -s ${LOGDIR}/packet_log/ packet_log
$ sudo ln -s ${LOGDIR}/security_log/ security_log
$ sudo ln -s ${LOGDIR}/server_log/ server_log


◆initスクリプトの修正
起動時に、RAMディスクにVPNサーバーのログ用ディレクトリを作成するよう、以前に作ったスクリプトを修正します。

/etc/init.d/vpnserver
#!/bin/sh
### BEGIN INIT INFO
# Provides:       vpnserver
# Required-Start: $local_fs $network
# Required-Stop:  $local_fs $network
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# Description:    SoftEther VPN Server
### END INIT INFO

DAEMON=/home/pi/local/vpnserver/vpnserver
LOGDIR=/var/log/vpnserver
LOCK=/var/lock/vpnserver

vpn_start() {
    ${DAEMON} start
    sleep 2
    tap=`ip tuntap | cut -f1 -d:`
    brctl addif br0 ${tap}
}

vpn_stop() {
    ${DAEMON} stop
}

test -x ${DAEMON} || exit 0

mkdir -p ${LOGDIR}
mkdir -m 0700 -p ${LOGDIR}/backup.vpn_server.config
mkdir -m 0600 -p ${LOGDIR}/packet_log
mkdir -m 0600 -p ${LOGDIR}/security_log
mkdir -m 0600 -p ${LOGDIR}/server_log

        : (略)

上記修正を行なった part3 版が↓です。(上記修正を行なえば下記操作は不要です。)
$ curl http://sstea.blog.jp/raspi/script/vpnserver3 > vpnserver
$ chmod 755 vpnserver
$ sudo mv vpnserver /etc/init.d/


これで、VPNサーバーを再起動するか、リブートすればログファイルの出力先が変わっているはずです。
リブートする度にログは消えるので、蓄積していきません。(良いか悪いかは運用者の方針次第ですが。)
$ sudo /etc/init.d/vpnserver start

Raspberry Pi のメモリを効率よく使う

今回は Raspberry Pi で ZRAM 機能を有効にしようと思います。

現運用的には、メモリは全然足りています。
通常時では 100MB ほど使用しているだけです。
RAMディスク(厳密にはtmpfs)として使用している /tmp や /var/log の 64MB がフルに使用されても全然余裕です。
$ free
             total       used       free     shared    buffers     cached
Mem:        480852     126700     354152          0       8548      72460
-/+ buffers/cache:      45692     435160

ただ、ガチャガチャいろいろ動かした時には 300MB くらい行くときもありました。
なので、メモリ不足回避のための保険としてSWAPを有効にしようかとも思いましたが、SWAPを有効にすると
・スワップイン、スワップアウト発生時に遅くなる
・SWAP領域(SWAPファイル)分、ディスクスペースを消費する
というデメリットがあります。

特にほぼ使われないのが分かっているのにスワップファイルにディスク容量を取られるのが勿体無いです。
(4GB microSD を使っているので、ディスク空き容量は常に意識していないと。。。)

◆ZRAM機能
Linuxにはメモリの一部を圧縮スワップ領域として使用できるZRAMという機能があります。
簡単に言うと、ディスクスペースを一切消費することなく、500MB しかないメモリを 600MB くらいとして使えるということです。
(圧縮スワップ領域が使用される場合は多少のオーバーヘッドは発生します。)

256MB~512MB 要る、というのであれば、大人しくSWAP領域を確保してください。
今回は保険のために用意しておくだけなので、1, 2割増えれば十分ですので。

◆ZRAM が使用可能かの確認
ZRAM を使用するには、ZRAM 機能が使用可能な Linux カーネルである必要があります。
以下、使用可能かの確認方法をです。(別パターンの確認方法は↓おまけ1参照)

以下のデバイスファイルがあれば ZRAM 機能が使用可能です。
$ ls /dev/zram*
上記デバイスファイルがない場合は、下記ローダブルカーネルモジュールがあるか確認します。
あれば問題ありません。
$ ls /lib/modules/`uname -r`/kernel/drivers/block/zram/zram.ko
どちらも無い場合は、残念ながら ZRAM が使用できない Linux カーネルです。
↓を参考にカーネルコンフィグレーションを変更しカーネルをリビルドする必要があります。

◆ZRAM 機能を有効にするためのLinux カーネルコンフィグレーション
カーネルのビルド、差し替え方法はこちらをご覧ください

[1] CONFIG_ZSMALLOC を有効化(とりあえずローダブルカーネルモジュールにしておきます)
Kernel Features  --->
<M> Memory allocator for compressed pages

[2] CONFIG_ZRAM を有効化(ここもとりあえずローダブルカーネルモジュールにしておきます)
Device Drivers  --->
[*] Block devices  --->
<M>   Compressed RAM block device support
[*]     Enable LZ4 algorithm support
     CONFIG_ZRAM_LZ4_COMPRESS も有効化しておきます。ここはお好みで。
     (デフォルトは LZO 圧縮になります。
       一般的には LZ4 圧縮の方が圧縮率は劣りますが、圧縮、展開速度が高速です。)

# 今回、ZRAM の有効化に合わせて、Linux カーネルを 4.0.4 でリビルドしました。
# 使用したカーネルコンフィグをアップしておきます。

◆initスクリプトの作成

zram.sh
#!/bin/sh
### BEGIN INIT INFO
# Provides:       zram
# Required-Start:
# Required-Stop:
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
### END INIT INFO

case "$1" in
    start)
        modprobe zram

        echo lz4 > /sys/block/zram0/comp_algorithm
        echo 256M > /sys/block/zram0/disksize

        mkswap /dev/zram0
        swapon -p 5 /dev/zram0
        ;;
    stop)
        swapoff /dev/zram0
        sleep 1
        modprobe -r zram
        ;;
    *)
        echo "Usage $0 start | stop "
        ;;
esac
ZRAMをローダブルカーネルモジュールとしている場合は、まず modprobe コマンドでモジュールを組み込む必要があります。

CONFIG_ZRAM_LZ4_COMPRESS を有効にしているので、その後 LZ4 アルゴリズムに変更しています。
コンフィグを有効にしていても、/sys/block/zram0/comp_algorithm を変更しなければ LZO 圧縮のままとなります。("cat /sys/block/zram0/comp_algorithm" で確認できます。)

サイズはお好みで設定してください。(上記の場合は 256MBです。)
メモリサイズの半分を指定するのが一般的(?おまけ2↓参照)のようです。

◆ZRAMの有効化
$ curl -O http://sstea.blog.jp/raspi/script/zram.sh
$ chmod 755 zram.sh
$ sudo mv zram.sh /etc/init.d/
$ sudo chkconfig --add zram.sh
zram.sh を取得し、実行権限を付与し、init スクリプトとして登録します。

再起動するか、"sudo /etc/init.d/zram.sh start" とすると、ZRAM が有効になります。
$ cat /proc/swaps
Filename                                Type            Size    Used    Priority
/dev/zram0                              partition       131068  0       5

ちなみにスワップのし易さは /proc/sys/vm/swappiness に echo で値を書き込む事で設定できます。
(cat を使うと現在の設定値を取得できます。)
0から100の値を設定でき、値が大きいほうがスワップし易いです。

◆おまけ1
CONFIG_IKCONFIG_PROC  が有効になっている Linux カーネルであれば下記で確認可能です。
$ zcat /proc/config.gz | grep CONFIG_ZRAM
で、"CONFIG_ZRAM=y" または "CONFIG_ZRAM=m" と表示されれば、問題ありません。
"m" の場合はZRAMのローダブルカーネルモジュールがあるはずです。

◆おまけ2
Ubuntu 等の場合(勿論 Linux Mint も!!)は、
"sudo apt-get install zram-config" とするだけ(カーネルが対応しているのは前提ですが)で
ZRAM が使えるようになります。

その方法でインストールした場合の /etc/init/zram-config.conf を見ると、
ZRAM デバイスを CPU の数だけ作ります。
そして、一個あたりの ZRAM のサイズは全メモリサイズの半分のサイズをCPUの数で割ったサイズを指定しています。

メモリが1GBでCPUが4つの場合は、128MB(1GB / 2 / 4)の ZRAM を4つ作る(計512MB)という事です。

Raspberry Pi に起こしてもらう

今さらながらですが、Raspberry Pi をアラーム(目覚まし)として使おうと思います。
音も鳴るようにしましたし、VPN サーバーを構築して常時電源入れたまんまになったので。。。

◆アラームとして求める要件
"mpd play" を cron に登録、、、でアラームとしては最低限、機能するんですが、それだけだとおもしろくないので。
時間になったらお知らせしてくれるのは当然として、下記三点を満たすものを目指します。

・好きな音をアラーム音として指定可能。
・最初は控えめな音量で、徐々に音量が大きくなる。
・一定時間経てば勝手に鳴り止む。
(ひょっとしたら、その場にいないかもしれないですし。鳴りっぱなしだと、近所迷惑なので。)

◆mp3 ファイルの再生
アラーム音としては、一旦 mp3 ファイルのみを考えます。

まずは mp3 ファイルを再生するために必要なパッケージをインストールします。
$ sudo apt-get install mpg123

mpg123 コマンドは指定フレーム分だけ再生する、とかがオプション指定で出来るのでそれを利用します。
(↓おまけ1にて補足)
ただ、フレーム指定だと直感的に分かりにくいので、下記のようなラッパーのシェルを作りました。

mp3play.sh
#!/bin/bash

n_option=
k_option=

mp3_file=$1
time=$(($2))
offset=$(($3))

if [ ! -f "${mp3_file}" ]; then
    echo "no such file : ${mp3_file}"
    exit 1
fi

# 30s is about 1150frame
if [ ${time} -ne 0 ]; then
    n_option="-n $((${time} * 38))"
fi
if [ ${offset} -ne 0 ]; then
    k_option="-k $((${offset} * 38))"
fi

mpg123  ${n_option} ${k_option} "${mp3_file}" &> /dev/null

使用方法としては、
・第一引数にmp3 ファイル
・第二引数に再生時間(秒数指定、0 なら最後まで再生)※
・第三引数に再生オフセット(秒数指定、0 なら最初から再生)※
を指定する感じです。
※ 数字以外、または省略時は 0 と解釈されます。
→ "Usage: mp3play.sh mp3-file [time] [offset]"

再生オフセットを微調整することでいきなりサビの部分から再生が出来ます。

◆音量の変更

alarm.sh
#!/bin/bash

volume=$(($1))
period=$(($2))

prev_volume=`amixer get PCM | sed -n "s/.*\[\(.*\)%\].*/\1/gp" | head -n 1`

if [ ${volume} -ne 0 ]; then
    amixer set PCM ${volume}% > /dev/null
else
    volume=${prev_volume}
fi

shift 2
/home/pi/local/bin/mp3play.sh "$@" &

if [ ${period} -ne 0 ]; then
    while [ ${volume} -lt 100 ]; do
        sleep ${period}
        volume=$((${volume} + 5))
        amixer set PCM ${volume}% > /dev/null
    done
fi

wait

if [ ${volume} -ne ${prev_volume} ]; then
    amixer set PCM ${prev_volume}% > /dev/null
fi

音量を変更するので、実行前の音量を prev_volume に退避し、終了時に元に戻しています。
第三引数以降は、上記で作った mp3play.sh にそのまま渡して、実行します。
その後、一定秒数ごとに 5% ずつボリュームアップさせ、100% までアップさせたら mp3play.sh が終了するのを待ち合わせます。

使用方法としては、
・第一引数に音量(%指定、0 ならその時のシステム音量)※
・第二引数にボリュームアップ間隔(秒数指定、0 ならボリュームアップしない)※
・第三引数にmp3 ファイル
・第四引数に再生時間(秒数指定、0 なら最後まで再生)※
・第五引数に再生オフセット(秒数指定、0 なら最初から再生)※
※ 数字以外、または省略時は 0 と解釈されます。
を指定する感じです。
→ "Usage: alarm.sh volume period mp3-file [time] [offset]"

◆スケジューリング登録
$ cd /home/pi/local/bin/
$ curl -O http://sstea.blog.jp/raspi/script/mp3play.sh
$ curl -O http://sstea.blog.jp/raspi/script/alarm.sh
$ chmod 755 mp3play.sh alarm.sh
スクリプトを取得し、実行権限を付与します。

crontab コマンドで末尾に処理を追加します。
$ crontab -e
月曜日から金曜日の7時30分に実行させる設定が下記です。
ボリューム10%からスタートし、2秒ごとにボリュームアップ、60秒後に停止、という引数で alarm.sh を実行させます。hoge.mp3 は任意のファイルを指定してください。
    : (略)
30 7 * * 1-5 /home/pi/local/bin/alarm.sh 10 2 "/home/pi/hoge.mp3" 60 0

◆アラームの停止
現状、途中で止める方法がありません。(鳴り止むのを待つしかないです。)
どうしても止めたい場合は、
$ killall mpg123
とでもしてください。
(んな事しなくても、電源抜いたらさすがに止まりますけどね。)

◆おまけ1

mp3 ファイルの再生には mpg123 コマンドでもいいですが、mpg321 コマンドでも可能です。
どっちを使ってもやりたいことは可能と思います。オプションが微妙に違いますが。

自分の環境では mpg123 コマンドのインストールには 316kB 必要でした。
top コマンドでCPU使用率を見ていると大体 14% 程度といったところでした。

一方、mpg321 コマンドのインストールにはその他のパッケージのインストールも必要で合計 5025kB 必要でした。
top コマンドでCPU使用率を見ていると大体 9% 程度といったところでした。

自分はディスク容量を取り、mpg123 の方を使用する事にしました。
ちなみに mpd で再生した場合のtopコマンドでのCPU使用率も14%程度でした。参考までに。

Raspberry Pi を VPN サーバーにする、改

前回に引き続き、Raspberry Pi のVPN サーバーの設定を行ないます。

◆VPN 経由で Raspberry Pi 上の web サーバーにローカルアクセス出来ない問題

前回までで VPN 接続は出来るようになりましたが、前回環境ではなぜか VPN 経由では Raspberry Pi 上の web サーバーにローカルアクセスIPアドレスでアクセス出来ませんでした。

いろいろ Google 先生に問い合わせてみると、
「Linux および Solaris オペレーティングシステムでは、仮想 HUB (VPN) の内側からローカルブリッジ先のLANカードから LAN への通信は行うことが出来ますが、ローカルブリッジしている LAN カード自体に対して通信することはできません。これは Linux カーネルの制限事項です。」
という情報を Google 先生から頂きました。

つまり、Linux ではこれは仕様という事。。。
回避策は、、、物理的にLANカードもう一個挿す事。。。

何とか、ソフトだけで回避はできないのか!?
→ できるみたいです!!


何かブリッジの設定をすればいいっぽいみたいですが、すいません。正直、よく分かってないです。

http://www.petapico.biz/ラジ館petapicoshop/softether-vpnで外から-irmagician-を制御してエアコンをつける/

のページの情報が凄く役立ちました。先人の知恵に感謝です。


以下の手順で解決しました。

◆ローカルブリッジの設定

必要パッケージをインストールします。
$ sudo apt-get install bridge-utils

/etc/network/interfaces
を修正します。
auto eth0
iface eth0 inet manual


auto br0
iface br0 inet static
  address 192.168.0.100
  netmask 255.255.255.0
  network 192.168.0.0
  broadcast 192.168.0.255
  gateway 192.168.0.1
  bridge_ports eth0
  bridge_maxwait 10


前回作った /etc/init.d/vpnserver に下記を追加します。
        : (略)
vpn_start() {
    ${DAEMON} start
    sleep 2
    tap=`ip tuntap | cut -f1 -d:`
    brctl addif br0 ${tap}

}
        : (略)

上記を追加した part2 版が↓です。
$ curl -O http://sstea.blog.jp/raspi/script/vpnserver2 > vpnserver
$ chmod 755 vpnserver
$ sudo mv vpnserver /etc/init.d/

◆tapデバイスの設定

Windows 側で「SoftEther VPN サーバー管理マネージャ」を立ち上げます。
前回の (F-2)  ~ (F-4) の部分の設定を変えます。

メインウィンドウから「ローカルブリッジ設定」ボタンを押下し、「ローカルブリッジ設定」ウィンドウを出します。
「ローカルブリッジの削除」ボタンで前回追加した設定は一旦、削除します。

(F-2)' [新しいローカルブリッジの定義]->[仮想 HUB] を選択
(F-3)' [作成する種類] で「新しい tap デバイスとのブリッジ接続」を選択
(F-4)' [新しい tap デバイス名] を入力
(F-5)' 「ローカルブリッジを追加」ボタンを押下


これで、VPN 経由でも Raspberry Pi 上の web サーバーにアクセス出来るようになりました。

これからは Raspberry Pi を VPN サーバーとして常時稼動させようと思いますので、どれほどの省電力効果があるか分かりませんが、オーバークロック設定は None に戻しておこうと思います。

◆おまけ1
Xperia Z3 には以下のAndroidアプリを入れています。

・WOL用アプリ
Fing - Network Tools

LAN内のマシンを自動的に検出してくれるので、MACアドレスとか入力しなくてもよくてお手軽です。

・リモートデスクトップ用アプリ
Splashtop 2 Remote Desktop

リモートデスクトップでアクセスしたいマシンに Splashtop Streamer をインストールしておく必要はありますが、軽い動画くらいなら普通にリモートデスクトップ経由で見れるくらいのポテンシャルを持ってます。(音も鳴ります)

外出先から VPN 接続し、上記アプリを使用して PC の電源を入れてリモートデスクトップで操作、という事が普通にできてます。

◆おまけ2
Windowsマシンでの動画再生には VLC メディアプレイヤーを使ってるんですが、Splashtop のリモートデスクトップ経由で動画再生した時に、VLC のウィンドウ内が真っ黒で動画が見えないことがありました。

VLC の[ツール]->[設定]->[ビデオ]->[ディスプレイ]->[出力] を「Direct3Dビデオ出力」に設定することで、表示されるようになりました。

Raspberry Pi を VPN サーバーにする

今回は、外出先から家のPCにアクセスするために Raspberry Pi を VPN(Virtual Private Network) サーバーにしてみたいと思います。
SotfEther VPN というOSSのVPNソフトがありますので、それを今回は使用してみる事にします。

以下の要件を満たす事が可能な環境を構築する事を目指します。

・PCの電源が落ちていれば外出先から電源投入できる(Wake On LAN)。
・外出先からPCにスマホのリモートデスクトップアプリでアクセスできる。
・外出先から前回作ったwebブラウザで Raspberry Pi を操作できる。
・セキュリティとかあんまり詳しくないので、そのあたりは良きに計らってくれる。

◆VPN(SoftEther) サーバーソフトのインストール
https://ja.softether.org/4-docs/1-manual/7/7.3 を参考にインストールしました。

http://www.softether-download.com/ja.aspx から SoftEther VPN Server の ARM EABI 版をダンロードし、展開します。
(現時点の最新は v4.15-9546-beta-2015.04.05 でした)
$ wget http://jp.softether-download.com/files/softether/v4.15-9546-beta-2015.04.05-tree/Linux/SoftEther_VPN_Server/32bit_-_ARM_EABI/softether-vpnserver-v4.15-9546-beta-2015.04.05-linux-arm_eabi-32bit.tar.gz

$ tar xvzf softether-vpnserver-v4.15-9546-beta-2015.04.05-linux-arm_eabi-32bit.tar.gz
$ cd vpnserver/
$ make

後は、何回か「1」を押してもらえればいいです。。


公式のマニュアルでは vpnserver は /usr/local/vpnserver に移動させていますが、自分は /home/pi/local/vpnserver に移動しておきます。(個人的な趣味です。)

公式マニュアルに従って、root のみ実行可能なように権限変更を行なっておきます。
$ mv vpnserver /home/pi/local/vpnserver

$ cd /home/pi/local/vpnserver/
$ chmod 600 *
$ chmod 700 vpncmd vpnserver

$ cd ../
$ sudo chown -R root:root vpnserver/
vpncmd の check コマンドで動作チェックできます。
$ cd /home/pi/local/vpnserver/
$ sudo ./vpncmd

◆VPN のスタートアップスクリプトを登録

公式のスタートアップスクリプトやその他諸々を参考に書きました。

/etc/init.d/vpnserver
#!/bin/sh
### BEGIN INIT INFO
# Provides:       vpnserver
# Required-Start: $local_fs $network
# Required-Stop:  $local_fs $network
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# Description:    SoftEther VPN Server
### END INIT INFO

DAEMON=/home/pi/local/vpnserver/vpnserver
LOCK=/var/lock/vpnserver

vpn_start() {
    ${DAEMON} start
}

vpn_stop() {
    ${DAEMON} stop
}

test -x ${DAEMON} || exit 0

case "$1" in
start)
    vpn_start
    touch ${LOCK}
    ;;
stop)
    vpn_stop
    rm ${LOCK}
    ;;
restart)
    vpn_stop
    sleep 3
    vpn_start
    ;;
*)
    echo "Usage: $0 {start|stop|restart}"
    exit 1
esac

exit 0

上記を実行権限を与えて、 /etc/init.d/ 直下に移動し、ブート時に自動起動するように登録します。
$ curl -O http://sstea.blog.jp/raspi/script/vpnserver
$ chmod 755 vpnserver

$ sudo mv vpnserver /etc/init.d/
$ sudo chkconfig --add vpnserver

VPNサービスを開始します。再起動でもいいです。ブート時に自動起動するので。
$ sudo /etc/init.d/vpnserver start

◆VPNの設定
VPNの設定は Windows 側から行なえるので楽でした。

http://www.softether-download.com/ja.aspx から「SoftEther VPN Server Manager for Windows」をダンロードし、windows マシンにインストールし、管理ツールを実行します。

(A-1) 「新しい接続設定」ボタンを押下
(A-2) 「新しい接続設定の作成」ウィンドウが出るので、[接続設定名], [ホスト名] をそれぞれ入力し、[OK]
(A-3) 「接続」ボタンを押下
ss_softether01
ss_softether02
(B-1) メインのウィンドウ(「VPN サーバー管理マネージャ」)が出るので、「仮想 HUB の作成」ボタンを押下
(B-2) 「仮想 HUB の新規作成」ウィンドウが出るので、[仮想 HUB 名] を入力し、[OK]
ss_softether03
ss_softether04

(C-1) メインウィンドウに戻り、「仮想 HUB の管理」ボタンを押下
(C-2) 適宜「ログ保存設定」を設定(変更しなくても可)
(C-3) 「仮想 HUB の管理」ウィンドウが出るので、「ユーザーの管理」ボタンを押下
ss_softether05

(D-1) 「ユーザーの管理」ウィンドウが出るので、「新規作成」ボタンを押下
(D-2) [ユーザーの新規作成]ウィンドウが出るので、[ユーザー名], [パスワード] を入力し、[OK]
ss_softether06
ss_softether07

(E-1) メインウィンドウに戻り、「IPsec / L2TP 設定」ボタンを押下
(E-2) 「IPsec / L2TP / EtherIP / L2TPv3 設定」ウィンドウが出るので、[L2TP サーバー機能を有効にする(L2TP over IPsec)] をチェック
(E-3) [IPsec 共通設定]->[IPsec 事前共有鍵] を入力し、[OK]
ss_softether08

(F-1) メインウィンドウに戻り、「ローカルブリッジ設定」ボタンを押下
(F-2) 「ローカルブリッジ設定」ウィンドウが出るので、[新しいローカルブリッジの定義]->[仮想 HUB] を選択
(F-3) [作成する種類] で「物理的な既存の LAN カードとのブリッジ接続」を選択
(F-4) 「ローカルブリッジを追加」ボタンを押下
ss_softether09

(G-1) メインウィンドウに戻り、「ダイナミック DNS 設定」ボタンを押下
(G-2) 「ダイナミック DNS 設定」ウィンドウが出るので、[設定の変更]->[ダイナミック DNS ホスト名の変更] を入力
(G-3) 「上記の DNS ホスト名に変更する」ボタンを押下
ss_softether10

◆ルーターの設定
外出先から Raspberry Pi にアクセスするためには、ルーターのポートを開放しておく必要があります。
L2TP/IPSec を使用する場合、500(UDP) と4500(UDP) の2つのポートを開放する必要があります。

ルータによって「ポートフォワーディング」とか「ポートマッピング」とかで設定できるはずです。
ちなみに、うちにあるルーター(CG-WLR300NM)の場合は、[詳細設定] ->[バーチャル・サーバ(ポート開放)] で設定しました。

だいたいのルーターは設定後、ルーターを再起動させれば反映されると思います。

◆VPN接続テスト
スマホ側からVPN接続できるか確認してみます。
下記は Xperia Z3 の場合の設定例です。

(1) [設定]->[Wi-Fi] を OFF (同一LAN 内の場合)

(2) [設定]->[その他の設定]->[VPN] に移動

(3) [VPNプロフィールの追加]
     「名前」を適宜入力
     「タイプ」に [L2TP/IPSec PSK] を設定
     「サーバーアドレス」に (G-2) で入力したホスト名を入力
     「IPSec事前共有鍵」に (E-3) で入力した事前共有鍵を入力
ss_xperia_vpn01

(4) 追加したVPNプロフィールに接続
      「ユーザー名」、「パスワード」に (D-2) で入力したユーザー名、パスワードを入力し、接続


VPN接続が正常に行なえたなら、リモートデスクトップ、WOLもアプリ入れればローカルIPアドレスで可能と思います。
※ただし現段階では、VPN 経由での前回作ったwebブラウザ経由での Raspberry Pi 操作ができません。

ちょっと長くなってきたので、今回はここまでです。
次回、上記課題の解決を試みます。

Raspberry Pi をスマホで操作する

以前にジョイスティックで Raspberry Pi の操作を試みましたが、よく考えたら「スマホで操作できたらそれでいいんじゃない?」(半年前にXperia Z3を買ったので。)と思いましたので、今度はスマホでの Raspberry Pi の操作にチャレンジしたいと思います。

スマホ(Xperia Z3)からウェブブラウザ経由で Raspberry Pi のリブート等の操作ができる事を目指します。

ちなみに操作画面のイメージは↓こんな感じです。
(Xperia Z3からドルフィンブラウザでアクセス)
ss_xperia_cmd01

このあたりについては専門外なのでカッコいいUIの操作画面とかまで求められても、自分には無理です。
動くことをもって良しとしてください。

◆apache, php のインストール
まずは必要なパッケージをインストールします。
$ sudo apt-get install apache2 php5

以前に /var/log/ 以下はRAMディスクを使用するようにしていましたので、/etc/init.d/init-ramdisk に下記を追記しておきます。
mkdir -p /var/log/apache2/

◆Raspberry Pi 操作用 html & php

google 先生に訊きながらいろいろ参考にして作ってみましたが、正直、自分は素人なので、無駄な事や一般的でない事等、いろいろイケてない事とかしてるかもしれません。。。ご容赦を。

command.html
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <meta http-equiv="Content-Script-Type" content="text/javascript" />
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <script type="text/javascript">
//<![CDATA[
function createXMLHttpRequest() {
  if (window.XMLHttpRequest) {
    return new XMLHttpRequest();
  } else {
    return new ActiveXObject("Microsoft.XMLHTTP");
  }
}

function entryClickEvent(id, handler) {
  var obj = document.getElementById(id);
  if (window.addEventListener) {
    obj.addEventListener("click", handler, false);
  } else {
    obj.attachEvent("onclick", handler);
  }
}

function doCommand(command) {
  var request = createXMLHttpRequest();
  request.open("POST", "command.php", true);
  request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  request.send("cmd=" + encodeURIComponent(command));
}

function doCommandConfirm(command)
{
  ret = confirm("本当に実行してもよろしいですか?\n" + command);
  if (ret == true) {
    doCommand(command);
  }
}

function command1() {
  doCommand("mpc prev");
}
function command2() {
  doCommand("mpc toggle");
}
function command3() {
  doCommand("mpc next");
}
function command4() {
  doCommandConfirm("sudo shutdown -r now");
}
function command5() {
  doCommandConfirm("sudo shutdown -h now");
}

window.onload = function() {
  entryClickEvent('btn1', command1);
  entryClickEvent('btn2', command2);
  entryClickEvent('btn3', command3);
  entryClickEvent('btn4', command4);
  entryClickEvent('btn5', command5);
}
//]]>
  </script>
  <title>command</title>
</head>
<body>
  <center>
  <input type="button" id="btn1" value="<<" style="width:30%; height:50%; font-size:35px" />
  <input type="button" id="btn2" value="mpc" style="width:30%; height:50%; font-size:35px" />
  <input type="button" id="btn3" value=">>" style="width:30%; height:50%; font-size:35px" />
  <input type="button" id="btn4" value="reboot" style="width:45%; height:20%; font-size:40px" />
  <input type="button" id="btn5" value="shutdown" style="width:45%; height:20%; font-size:40px" />
</body>
</html>

command.php
<?php
$command = filter_input(INPUT_POST, "cmd");
if ($command) {
  shell_exec($command);
}
?>
php スクリプトで html から渡された文字列をシェルコマンドとして実行します。
html ファイルのシェルコマンドの部分を他のコマンドに置き換える事で、簡単に改造できると思います。

※外部に公開するwebサーバーでは導入しないでください

$ curl -O http://sstea.blog.jp/raspi/web/command.html
$ curl -O http://sstea.blog.jp/raspi/web/command.php
$ sudo mv command.html /var/www/
$ sudo mv command.php /var/www/


http://192.168.0.100/command.html にブラウザでアクセスし、ちゃんと動くかテストしてみてください。
PCからでも、スマホからでもいけると思います。
(reboot と shutdown はまだ出来ません。)

# ↑IPアドレス部分は raspberry pi のIPアドレスを指定して下さい。

自分の Xperia Z3 では上記アドレスをブックマークに登録し、ホーム画面にショートカットを作る事で、ワンタッチですぐにアクセス可能にしています。

◆php から sudo コマンドを実行できるようにする
今のままでは、sudo を含むシェルコマンドは実行できませんので、reboot, shutdown が出来ません。
これを実行できるようにします。

$ sudo visudo
 で /etc/sudoers の末尾に以下を追記しておきます。一応、実行可能なコマンドを絞っておきます。
www-data ALL=(ALL) NOPASSWD: /sbin/shutdown
(実行可能コマンドはコンマで区切ることで、複数コマンドを指定可能です。)

これで Raspberry Pi の再起動、シャットダウンもスマホから可能になりました。
ただし、現状は LAN 内からしか操作はできません。
VPN(Virtual Private Network) を構築すれば、LAN 外からでも Raspberry Pi を操作可能になります。


◆おまけ1
以前に作った talk.sh を html ファイルのシェルコマンドの部分に指定して、ボタンを押したら喋るようにしようと思ったのですが、最初はうまく動きませんでした。

sudo 付ければちゃんと喋ってくれましたので、権限関連の問題かと思っていろいろ試していたところ、www-data に権限を追加することで、sudo 無しでも無事に喋ってくれるようになりました。
$ sudo usermod -G audio -a www-data

Raspberry Pi のカーネルカバレッジ情報を取得する

◆GCOVカーネル
Linux にはカバレッジ計測する gcov コマンドというものがあります。
しかし、一般的な gcov でカバレッジ計測が可能なのはユーザー空間のプログラムです。
(厳密には gcov コマンド自体は、
  カバレッジ計測用のコンパイルオプションでコンパイルされたプログラムの
  実行結果を収集、可視化するためのものですが。)

Linux カーネルはユーザー空間のプログラムではないので、
一般的な gcov コマンド等ではカバレッジ計測できないのですが、
それを行なってしまうのがGCOVカーネルなのです。

元々は LTP (Linux Test Project) のサイトからGCOVカーネル用のパッチをダウンロードして適用する必要があったのですが、いつのまにか本家の Linux に取り込み済みのようです。

# 3.18 以降なら ARM にも対応しています。
# (3.17 以前でも本質的には対応されてます。 Kconfig メニュー上表示されませんが。)

◆カーネルカバレッジデータのサンプル
どんな感じのデータが取得できるのかは、まずは見てもらった方が早いと思います。
下記は自分が raspberry pi でGCOVカーネル(3.19.3) を実際に動かして取得したデータです。

  GCOVカーネルカバレッジデータの出力サンプル


arch/arm/lib/uaccess_with_memcpy.c の __copy_to_user_memcpy() の部分を
↓下記に抽出しました。
if 文などの分岐単位でカバレッジ計測されます。 
左にその行の実行回数が表示されています。

ss_rpi_gcov01

◆GCOVカーネルのビルド
では実際のGCOVカーネルのビルド方法です。

"make menuconfig" により、
CONFIG_GCOV_KERNEL と CONFIG_GCOV_PROFILE_ALL を有効にし、
Linux カーネルをビルドします。(Linux カーネルのビルド方法詳細はここを参照)
    General setup  --->
      GCOV-based kernel profiling  --->
      [*] Enable gcov-based kernel profiling
      [*] Profile entire Kernel

           Specify GCOV format (Autodetect)  --->
# CONFIG_GCOV_KERNEL のメニューは CONFIG_DEBUG_FS を有効にしないと表示されません。

参考までに、本家 LTP の説明ページ。
http://ltp.sourceforge.net/coverage/gcov.php

(実際動かしてみると、結構重くなってましたので、あくまでプロファイリング用のカーネルと割り切りましょう。)

◆lcov コマンドのインストール
GCOVカーネルで取得したカバレッジデータを
上記サンプルのように html 化して出力してくれる lcov というツール(?)があります。

ホスト環境に lcov コマンドをインストールしておきます。
(Linux カーネルをクロスビルドしているホスト側です。構築方法詳細はここを参照)

$ git clone https://github.com/linux-test-project/lcov.git
$ cd lcov/
$ sudo make install
で、lcov 1.11 がインストールできると思います。

または、下記でもいいです。
$ curl -L -O http://downloads.sourceforge.net/ltp/lcov-1.11.tar.gz
$ tar xvzf lcov-1.11.tar.gz
$ cd lcov-1.11/
$ sudo make install

いつもの apt-get でもインストールされたんですが、
バージョンが最新(1.11)ではなく1.10でしたので、
上記のどちらかを推奨します。
$ sudo apt-get install lcov

◆カーネルカバレッジデータの取得

GCOVカーネルをビルドしたなら、そのカーネルでRaspberry Pi を実際に動かしてみます。

/sys/kernel/debug/gcov/ 以下にカバレッジデータが蓄積されていますので、
そのデータを取得し、ホスト環境に持って行きます。
$ sudo mount -t debugfs nodev /sys/kernel/debug/
$ sudo cp -a /sys/kernel/debug/gcov/home/mint/raspi/linux-3.19.y ./gcov-data
$ sudo tar cvjf gcov.tar.bz2 gcov-data/
※ピンク色の部分はクロスビルドした環境によって異なります。

◆カーネルカバレッジデータのhtml化

ところ変わって、こちらはホスト環境側になります。
KERNEL_DIR はクロスビルドした Linux カーネルのディレクトリです。
$ export KERNEL_DIR=/home/mint/raspi/linux-3.19.y
$ export CROSS_COMPILE=arm-linux-gnueabihf-
Raspberry Pi 上で取得した gcov.tar.bz2 を適当なディレクトリに展開します。
$ mkdir gcov-tmp/
$ cd gcov-tmp/
$ tar xvjf gcov.tar.bz2


クロス環境での lcov の使い方がいまいちよく分からなかったので、
この辺りは自分がトライ&エラーで試した結果になります。
なのでもっとスマートな方法があるかもしれないです。

カバレッジデータとソースコードを同ディレクトリに置くために、取得データをカーネルツリーにコピーします。
(lcov のオプションで別ディレクトリのままでもいけそうな気もするのですが。)
$ cp -a gcov-data/* ${KERNEL_DIR}/

クロス用の gcov を指定し、lcovコマンドを叩きます。output-file、output-directory の名前は何でもいいです。
$ lcov --capture --directory ${KERNEL_DIR}/ --output-file coverage.info --gcov-tool ${CROSS_COMPILE}gcov
$ genhtml coverage.info --output-directory out
genhtml により out ディレクトリ下に html が生成されますので、
out ディレクトリ下の index.html をブラウザで開いてください。

参考までに、本家 LTP の説明ページ。あっさりし過ぎ。。。
http://ltp.sourceforge.net/coverage/lcov.php

続、Raspberry Pi をジョイスティックで操作する


前回からの続きになります。
前回、Raspberry Piでジョイスティックの入力検出する jsinputd デーモンを作りました。
今回は jsinputd デーモンを使用し、ジョイスティックによりRaspberry Piに実際にアクションさせてみたいと思います。

jsinputd デーモン、及びスクリプトは全て /home/pi/local/bin/ に置いてあるという前提で、下記は記述しています。新しく作成するスクリプトも同ディレクトリに置きます。

◆ジョイスティックのキー入力判定とアクション
ジョイスティックのどのボタンが押された時に、どういうアクションを行なうかを書いたファイルが下記です。

jscmd.sh
#!/bin/bash

JSFILE=$1

update_input() {
    js=(`cat ${JSFILE}`)
    bt_left=${js[0]}
    bt_down=${js[1]}
    bt_right=${js[2]}
    bt_up=${js[3]}
    bt_L1=${js[4]}
    bt_R1=${js[5]}
    bt_L2=${js[6]}
    bt_R2=${js[7]}
    bt_select=${js[8]}
    bt_start=${js[9]}
    bt_L3=${js[10]}
    bt_R3=${js[11]}
    st_LH=${js[13]}
    st_LV=${js[14]}
    st_RH=${js[15]}
    st_RV=${js[16]}
    st_crossH=${js[17]}
    st_crossV=${js[18]}
}

joystick_command() {
    if [ ${bt_start} -eq 1 ] && [ ${bt_select} -eq 1 ] &&
       [ ${bt_L1} -eq 1 ] && [ ${bt_R1} -eq 1 ] &&
       [ ${bt_L2} -eq 1 ] && [ ${bt_R2} -eq 1 ]; then
        /home/pi/local/bin/talk.sh "Shutdownします"
        sudo shutdown -h now
        exit 0
    fi

    if [ ${bt_start} -eq 1 ]; then
        /home/pi/local/bin/jihou.sh &
    fi
}

update_input
joystick_command

ソフトで1つ目に検出するボタンがジョイスティックの実際のどのボタンに対応するか(startボタンなのか、L1ボタンなのか)は、使用するジョイスティック毎に異なりますので、まずは update_input にてそれぞれ対応する変数に入れています。

joystick_command の部分が実際のアクション定義部分です。

上記例では、start+select+L1+L2+R1+R2 の同時押しで、Raspberry Piをシャットダウンします。
またその旨を音声出力しています。
もう一つのコマンドはstart ボタンだけを押した場合で、その時の時間をお知らせします。
talk.sh や jihou.sh は前々回に作成したスクリプトです。

この部分の追加、カスタマイズはお好きにどうぞ。
(拡張版を↓おまけ2に用意しました。)

# 最初 "#!/bin/sh" としていたのですが、
# "js=(`cat ${JSFILE}`)" という書き方が、"#!/bin/sh" だと駄目のようでした。
# とりあえずですが、#!/bin/bash 固定としておきます。

jsmonitor.sh
#!/bin/sh

JSDEV=$1
JSFILE=$2

while [ `cut -f1 -d. /proc/uptime` -lt 20 ]; do
    sleep 1
done

/home/pi/local/bin/jsinputd ${JSDEV} ${JSFILE} &

sleep 0.5

while inotifywait -qq -e modify ${JSFILE}
do
    /home/pi/local/bin/jscmd.sh ${JSFILE}
done

ジョイスティック入力検出のための jsinputd デーモンをバックグラウンド起動し、デーモンの出力ファイルに変更があった時(=キー入力に変更があった時)だけ jscmd.sh が呼ばれます。
キー入力に変化がない場合(無入力状態、またはキーを押しっぱなしの場合)は inotifywait により待ち状態となります。

jsinputd の実行の後に 0.5 秒の sleep を入れているのは、デーモンが動作し出力ファイルが作成されるのを待つためです。
一番最初の while の中の sleep は気にしないでください。(↓◆おまけ1で補足します。)

上記スクリプトを取ってきて、実行権限を与えます。
$ cd /home/pi/local/bin/

$ curl -O http://sstea.blog.jp/raspi/script/jscmd.sh
$ curl -O http://sstea.blog.jp/raspi/script/jsmonitor.sh

$ chmod 755 jscmd.sh jsmonitor.sh
実行してみます。
$ ./jsmonitor.sh /dev/input/js0 /tmp/jsinput
意図通りに動くか確認してみましょう。
jscmd.sh で jihou.sh をバックグラウンド実行させているので、start ボタンを連打しても、ちゃんと押した回数、時間報告してくれます。、

# 上記 jsmonitor.sh は Ctrl-C で終了しても、バックグラウンドで動いている jsinputd は終了しません。
# "killall jsinputd" してあげてください。
# もしくはUSBアダプタを抜いてやると終了します。

◆jsmonitor.shの自動起動
毎回、自分で jsmonitor.sh を実行するのは面倒なので自動的に起動させたいですが、起動時に自動実行させても起動時点でUSBアダプタが刺さっていない(起動後に挿す場合とか)と、どのみち自分で実行する必要があります。

幸いにも Linux には udev というデバイスのプラグアンドプレイに合わせて処理を行なわさせる機構が備わっています。(正直、udev はあまり詳しくないですが。。。)

jsevent.sh
#!/bin/sh

JSFILE=/tmp/jsinput

if [ $1 = "add" ]; then
    /home/pi/local/bin/jsmonitor.sh ${DEVNAME} ${JSFILE} &
elif [ $1 = "remove" ]; then
    rm -f ${JSFILE}
fi
ジョイスティックの抜き差し時に、上記 jsevent.sh を実行する udev のルールを追加してみましょう。

/etc/udev/rules.d/99-joystick.rules
SUBSYSTEMS=="input", KERNEL=="js[0-9]", ACTION=="add", RUN="/home/pi/local/bin/jsevent.sh add"
SUBSYSTEMS=="input", KERNEL=="js[0-9]", ACTION=="remove", RUN="/home/pi/local/bin/jsevent.sh remove"

上記ルールを下記コマンドにより追加します。
$ curl -O http://sstea.blog.jp/raspi/script/jsevent.sh
$ chmod 755 jsevent.sh

$ curl -O http://sstea.blog.jp/raspi/script/99-joystick.rules
$ sudo mv 99-joystick.rules /etc/udev/rules.d/99-joystick.rules
udev をリスタートします。
$ sudo service udev restart
これで完成です。
USBアダプタのプラグアンドプレイに合わせて、jsmonitor.sh を実行できるようになりました。

# ちなみに jsevent.sh の DEVNAME ですが、環境変数として設定されるようです。
# おそらく "udevadm info --query=property --name=/dev/input/js0" で
# 表示されるパラメータが使用可能だと思います。

◆おまけ1
udev ルールでプラグアンドプレイに合わせてスクリプトを実行するようにしたわけですが、プラグアンドプレイ時は問題なかったのですが、当初は起動時からUSBアダプタが刺さっている場合に問題がありました。

jsinputd が /tmp/jsinput ファイルを作成するのですが、起動時点で既にUSBアダプタが刺さっている場合、なぜかファイル作成に失敗していたのです。

いろいろデバッグした結果、推測も混じりますが、以下の事が分かりました。
起動時に既に条件を満たしたudevルールがある場合、他の初期化が完了する前の結構早い段階で実行されるようです。(fstab のマウント等より先のようです。)
そのため、まだファイルシステムがread onlyの状態(remount前)に書き込みをしようとして失敗しているようでした。(remountが終わっても、/tmp を ramdisk 化しているため、tmpfs のマウント前の /tmp に書き出していた場合もありました。)

単純に sleep 10 とかを入れて、初期化完了待ちをしようかと思いましたが、そうするとプラグアンドプレイ時に、それだけ待たされてしまいます。
苦肉の策としてですが、起動時からの時間が20秒経っていなければ、20秒経つまで待ちにするという sleep を入れました。
その結果、起動時からUSBアダプタが刺さっている場合でも、プラグアンドプレイ時でも期待した動作をするようになりました。

◆おまけ2
上記の jscmd.sh ではボタンの押しっぱなしによる連続入力が検出できません。
それを検出できるようにした拡張版が↓です。
また mpc 関連の操作ができるようにコマンドを追加しました。

jscmd2.sh
#!/bin/bash

JSFILE=$1

update_input() {
    :  (省略)
}

joystick_command() {
    if [ ${bt_start} -eq 1 ] && [ ${bt_select} -eq 1 ] &&
       [ ${bt_L1} -eq 1 ] && [ ${bt_R1} -eq 1 ] &&
       [ ${bt_L2} -eq 1 ] && [ ${bt_R2} -eq 1 ]; then
        /home/pi/local/bin/talk.sh "Shutdownします"
        sudo shutdown -h now
        exit 0
    fi
    if [ ${bt_L3} -eq 1 ] && [ ${bt_R3} -eq 1 ] &&
       [ ${bt_L1} -eq 1 ] && [ ${bt_R1} -eq 1 ] &&
       [ ${bt_L2} -eq 1 ] && [ ${bt_R2} -eq 1 ]; then
        /home/pi/local/bin/talk.sh "Rebootします"
        sudo reboot
        exit 0
    fi


    if [ ${bt_start} -eq 1 ]; then
        /home/pi/local/bin/jihou.sh &
        WAIT=5
        return 1

    fi

    if [ ${bt_right} -eq 1 ]; then
        mpc toggle
        exit 0
    fi
    if [ ${bt_down} -eq 1 ]; then
        mpc stop
        exit 0
    fi

    if [ ${bt_L1} -eq 1 ]; then
        mpc prev
        WAIT=5
        return 1
    fi
    if [ ${bt_R1} -eq 1 ]; then
        mpc next
        WAIT=5
        return 1
    fi

    if [ ${st_LH} -ne 0 ]; then
        if [ ${st_LH} -lt 0 ]; then
            mpc seek -1
        else
            mpc seek +1
        fi
        return 1
    fi
    if [ ${st_crossV} -ne 0 ]; then
        if [ ${st_crossV} -lt 0 ]; then
            mpc volume +10
        else
            mpc volume -10
        fi
        return 1
    fi

    return 0

}

while [ 1 ]; do
    input=`cat ${JSFILE}`
    if [ "${input}" != "${prev_input}" ]; then
        prev_input=${input}
        WAIT=0
    fi
    if [ ${WAIT} -ne 0 ]; then
        WAIT=$((${WAIT} - 1))
        sleep 0.1
        continue
    fi


    update_input
    joystick_command
    if [ $? -eq 0 ]; then
        break
    fi
done

update_input に関しては変更ありませんので、元スクリプトを参照。
$ cd /home/pi/local/bin/

$ curl -O http://sstea.blog.jp/raspi/script/jscmd2.sh
$ mv jscmd2.sh jscmd.sh

$ chmod 755 jscmd.sh

Raspberry Pi をジョイスティックで操作する

前回、Raspberry Pi で音を鳴らしてみましたが、今度はインターフェースの改善を試みたいと思います。

Raspberry Pi を操作するのにこれまでは TeraTerm でSSH接続して操作してきましたが、ホストマシンを立ち上げる必要もあり、Raspberry Pi の電源を落とすのにも一苦労(という程の苦労でもないのですが)します。

かと言って、Raspberry Pi に電源スイッチを(物理的に)増設するほどでもない。
何よりソフトソフトしていたいのです。(半田ゴテとかとは無縁の人なので。自分は。)

◆Raspberry Pi にジョイスティックを接続
一昔前に、PS3 の純正ジョイスティックのボタンがヘタってきたために買ったジョイスティック(GAMETECH ワイヤレスバトルパッドターボ3)がありましたので、それでどうにかしたいと思います。

# ジョイスティック?ジョイパッド?ゲームパッド?コントローラ?
# ちなみにアレは何て呼ぶのが正解なんでしょうか?
# とりあえずここではジョイスティックで統一しておきます。

ワイヤレスバトルパッドターボ3 はUSBの無線アダプタと、コントローラとに分かれています。
現在のうちの Raspberry Pi は↓のような構成になっています。緑色に光ってるのが無線アダプタです。

ss_rpi_connect01

このジョイスティックの無線アダプタであるUSBを接続したところ、
/var/log/messages に下記のようなログが出てました。
usb 1-1.2: new full-speed USB device number 10 using dwc_otg
usb 1-1.2: New USB device found, idVendor=1915, idProduct=001e
usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-1.2: Product: PS3 wireless GAME PAD
usb 1-1.2: Manufacturer: ACRUX
input: ACRUX PS3 wireless GAME PAD as /devices/platform/bcm2708_usb/usb1/1-1/1-1.2/1-1.2:1.0/0003:1915:001E.0006/input/input5
hid-generic 0003:1915:001E.0006: input,hidraw0: USB HID v1.11 Gamepad [ACRUX PS3 wireless GAME PAD] on usb-bcm2708_usb-1.2/input0
また、/dev/input/js0 が増えました。
ここまでは何もしていないですが、正常に認識できているようです。

◆理想のジョイスティックキー入力検出を求めて...
さて、これだけだと、ジョイスティックのボタンをポチポチ押しても、無反応です。
少し Google 先生と相談です。。。

pygame という python のモジュールでジョイスティックの入力が取得可能らしいですね。。。
python... 馴染みがないし、分かりませーん。C とシェルくらいしかまともには使えませーん。

その他、いくつか試してみましたが、、、
キー入力をポーリングで検出するのはどうにかしたいですねー。

sleep しながらループしないと top コマンドで CPU 使用率が100%です。
→ sleep 時間が長いと CPU 使用率は下がるが、キー入力を取りこぼす。
     キー入力の反応が悪く、キモチ悪い。
→ sleep 時間が短いと、キー入力の反応はいいものの、CPU 使用率が上がる。
     0.1秒 sleep だとこの処理だけで、CPU 使用率が 10~20% いってしまいます。
     また、反応がいいとはいいつつも、0.1秒 sleep でも少し違和感を感じました。

Raspberry Pi はただでさえ貧相なCPUなので、キー入力がない時は素直に寝ていて欲しいです。
(待ち受け(idle) 時は1%だってCPUを使って欲しくないのです。)

◆Raspberry Pi でのジョイスティックのキー入力検出
自分の求める要件としては、下記4点です。
・ボタンを押した時の動作はシェルで好きに書く事ができる(カスタマイズが可能)。
・キー同時押しが検出可能。(L1+L2+R1+R2+Start+Select でシャットダウンしたいからです。)
・ポーリングでのキー入力検出ではなくて、イベントドリブン(キー入力がある時だけ起きてくる)のがいい。
・キー入力の反応がサクサク。違和感を感じない。

もう少し頑張って探そうかとも思いましたが、どうせ頑張るなら自分で作る方向のベクトルで頑張った方がいろいろ近道かと思い、いろいろ参考にしつつ C で作ってみる事にしました。

自作したジョイスティック入力検出デーモン(jsinputd と命名)が下記です。(結構、真面目に書きました。)
$ curl -O http://sstea.blog.jp/raspi/csrc/jsinputd.c
下記で Raspberry Pi 上でもビルドできると思います。-DDEBUG はなくても可。
(もちろんホスト側のクロスコンパイラでクロスビルドでも全然問題ありません。)
$ gcc jsinputd.c -o jsinputd -O2 -DDEBUG

jsinputd.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/joystick.h>

#ifdef DEBUG
#define ERROR(...)    (fprintf(stderr, "<JSINPUTD:E> " __VA_ARGS__), -1)
#else /* !DEBUG */
#define ERROR(...)    (-1)
#endif /* !DEBUG */

struct joystick_struct {
    int fd;
    unsigned char nr_buttons;
    unsigned char nr_sticks;
    short *button;    /* button[nr_buttons] */
    short *stick;    /* stick[nr_sticks] */
    char *input;    /* input[nr_btn * 2 + nr_stk * 7 + 1] */
};

static int joystick_output(struct joystick_struct *js, const char *out_file);
static int joystick_get_input(struct joystick_struct *js);
static int joystick_get_info(struct joystick_struct *js);
static int joystick_init(struct joystick_struct *js, const char *dev_file);
static void joystick_exit(struct joystick_struct *js);
static void joystick_main(const char *dev_file, const char *out_file);

static int joystick_output(struct joystick_struct *js, const char *out_file)
{
    FILE *fp = stdout;
    unsigned char i, nr_btn, nr_stk;

    if (out_file != NULL) {
        fp = fopen(out_file, "w");
        if (fp == NULL) {
            return ERROR("fopen(%s)\n", out_file);
        }
    }

    nr_btn = js->nr_buttons;
    nr_stk = js->nr_sticks;

    for (i = 0; i < nr_btn; i++) {
        sprintf(&js->input[i * 2], "%2d", js->button[i] ? 1 : 0);
    }
    for (i = 0; i < nr_stk; i++) {
        sprintf(&js->input[nr_btn * 2 + i * 7], "%7d", js->stick[i]);
    }
    js->input[nr_btn * 2 + nr_stk * 7] = '\0';

    fprintf(fp, "%s\n", js->input);

    if (out_file != NULL) {
        fclose(fp);
    }

    return 0;
}

static int joystick_get_input(struct joystick_struct *js)
{
    int ret;
    struct js_event ev;
    unsigned char num;

    do {
        ret = read(js->fd, &ev, sizeof(struct js_event));
        if (ret != sizeof(struct js_event)) {
            return ERROR("read : %d\n", ret);
        }
    } while (ev.type & JS_EVENT_INIT);

    num = ev.number;
    switch (ev.type) {
    case JS_EVENT_BUTTON:
        if (num < js->nr_buttons) {
            js->button[num] = ev.value;
        }
        break;
    case JS_EVENT_AXIS:
        if (num < js->nr_sticks) {
            js->stick[num] = ev.value;
        }
        break;
    default:
        break;
    }

    return 0;
}

static int joystick_get_info(struct joystick_struct *js)
{
    int ret, fd = js->fd;
#ifdef DEBUG
    char name[64];
#endif /* DEBUG */


    ret = ioctl(fd, JSIOCGBUTTONS, &js->nr_buttons);
    if (ret < 0) {
        return ERROR("ioctl(JSIOCGBUTTONS)\n");
    }
    ret = ioctl(fd, JSIOCGAXES, &js->nr_sticks);
    if (ret < 0) {
        return ERROR("ioctl(JSIOCGAXES)\n");
    }
#ifdef DEBUG
    ret = ioctl(fd, JSIOCGNAME(sizeof(name)), &name);
    if (ret < 0) {
        return ERROR("ioctl(JSIOCGNAME)\n");
    }
    printf("name=\"%s\", buttons=%d, sticks=%d\n", name, js->nr_buttons, js->nr_sticks);
#endif /* DEBUG */


    return 0;
}

static int joystick_init(struct joystick_struct *js, const char *dev_file)
{
    int ret, array_size;
    unsigned char nr_btn, nr_stk;
    unsigned char *p;

    ret = open(dev_file, O_RDONLY);
    if (ret < 0) {
        return ERROR("open(%s)\n", dev_file);
    }
    js->fd = ret;

    ret = joystick_get_info(js);
    if (ret < 0) {
        close(js->fd);
        return ret;
    }
    nr_btn = js->nr_buttons;
    nr_stk = js->nr_sticks;

    array_size = (nr_btn + nr_stk) * sizeof(short);
    p = malloc(array_size + nr_btn * 2 + nr_stk * 7 + 1);
    if (p == NULL) {
        close(js->fd);
        return ERROR("malloc\n");
    }
    js->button = (short *)p;
    js->stick = (short *)&p[nr_btn * sizeof(short)];
    js->input = (char *)&p[array_size];

    return 0;
}

static void joystick_exit(struct joystick_struct *js)
{
    free(js->button);
    close(js->fd);
}

static void joystick_main(const char *dev_file, const char *out_file)
{
    struct joystick_struct js;

    if (joystick_init(&js, dev_file) == 0) {
        do {
            if (joystick_output(&js, out_file) < 0) {
                break;
            }
        } while (joystick_get_input(&js) == 0);

        joystick_exit(&js);
    }
}

/*
 * arg1 : device file (default is /dev/input/js0)
 * arg2 : output file (default is stdout)
 */

int main(int argc, char **argv)
{
    char *dev_file = "/dev/input/js0";
    char *out_file = NULL;

    if (argc >= 2) {
        dev_file = argv[1];
    }
    if (argc >= 3) {
        out_file = argv[2];
    }

    joystick_main(dev_file, out_file);

    return ERROR("exit\n");
}

使用方法としては、
・第一引数にデバイスファイル(省略時は /dev/input/js0)
・第二引数に出力ファイル(省略時は標準出力)
を指定する感じです。
→ "Usage: jsinputd [device-file] [output-file]"

出力フォーマットは ボタン入力は 0 か 1、スティック入力は -32767 ~ 32767 の範囲で出力します。
順番はボタン0、ボタン1・・・とボタンの数だけ出力し、次いでスティック0からスティックの数分出力されます。

とりあえず、引数なしで実行。
$ ./jsinputd
name="ACRUX PS3 wireless GAME PAD", buttons=13, sticks=6
 0 0 0 0 0 0 0 0 0 0 0 0 0      0      0      0      0      0      0
Start ボタンを押したまま、Select ボタンを押して離して、その後 Start ボタンを離した場合。
下記のようにキー入力に変化があった時だけ動作し、出力が出ます。
結構ヌルサクでいい感じです!!(そして、無操作時は CPU 負荷 0 です!)
$ ./jsinputd
name="ACRUX PS3 wireless GAME PAD", buttons=13, sticks=6
 0 0 0 0 0 0 0 0 0 0 0 0 0      0      0      0      0      0      0
 0 0 0 0 0 0 0 0 0 1 0 0 0      0      0      0      0      0      0
 0 0 0 0 0 0 0 0 1 1 0 0 0      0      0      0      0      0      0
 0 0 0 0 0 0 0 0 0 1 0 0 0      0      0      0      0      0      0
 0 0 0 0 0 0 0 0 0 0 0 0 0      0      0      0      0      0      0


ちなみに、ジョイスティックの無線アダプタを Raspberry Pi から抜くと、ioctl で失敗し、終了します。
それ以外だと、基本的には Ctrl-C で中断しない限り、終了しません。

◆ジョイスティックのキー入力検出結果の取り込み

後は、上記で作成した jsinputd の出力結果をシェルで取り込めば、やりたい事は出来そうです。
標準出力に出されても困るので、/tmp/jsinput にでも出力させておこうと思っています。
この jsinputd の出力結果である /tmp/jsinput をシェルで取り込んでアレヤコレヤするわけです。

jsinputd デーモンは起動時にでも、バックグラウンド実行させておく想定です。
("./jsinputd /dev/input/js0 /tmp/jsinput &" みたいな感じで実行すればいいだけです。上記の想定で、ああいうインターフェースにしました。)

ただし、シェルから /tmp/jsinput を取り込むのに、ポーリングしながら読み込んだのでは本末転倒です。

幸いにも、ファイルに変化があった時だけ通知するという inotify という仕組みが Linux カーネルにはあり、それをシェルから利用できるツールがあります。
まずは inotify-tools をインストールしておきましょう。
$ sudo apt-get install -y inotify-tools

ちょっと長くなってきたので、続きは次回

プライバシーポリシー
当サイトでは、Googleを含む第三者配信事業者や広告ネットワークが配信する広告を掲載しています。
当サイトでは、アクセス情報に基づいた適切な広告表示、及びトラフィックデータ収集のためにCookieを使用しています。
ユーザーはCookieの無効化により、これらの情報の提供を拒否する事ができます。
スポンサーリンク
記事検索
スポンサーリンク