Сервер в кармане

Я не психопат — я просто мыслю творчески
(c) Гарри Поттер и методы рационального мышления

Участие в соревнованиях типа «евробота», где кодить приходить в самых разнообразных позах, согнувшись хрен знает как, под/на/за столом, да и пара других веселых поездочек натолкнули меня на не совсем адекватную мысль, что надо бы сделать из своего телефона что-то более полезное, чем звонилку. Не все же ему ворочать своими мегагерцами жабу.

Итак, в наличии имеем:

  • Тупой китайский кирпич HD7 Pro с android 2.3.5, умеющим точку доступа, и не развалившийся за полтора года службы. Внутри — MT6573
  • Прямые руки (2 шт., костлявые)
  • Немного свободного времени

Хотим получить

  • Набор штатных инструментов — lighttpd, ssh, git, прочее
  • WiFi точку доступа с локальным dns, выходом в интернеты (если есть)
  • Блэкджек и прочие полезности (с)

2013-03-18-00-19-06

Итак, приступаем. Все нижеизложенное требует прямых рук, красных глаз, и скорее всего лишает гарантии. При должной сноровке применимо ко всем аппаратам на андройде, какие только есть на рынке.
Ясное дело, что рут и бизибокс у меня был с хрен знает каких времен. Они нам и пригодятся.
Итак, первое что я сделал, это подсунул конфиг dnsmasq’у, чтобы тот поднял нам локальный dns.

Фактически когда мы поднимаем локальную сеть по WiFi, теперь это мы делаем с блекджеком и шлюхами с dns. Теперь, вместо того, чтобы вбивать IP адрес телефона, мы сможем вбивать просто http://anomalia, и точно так же со всеми компьютерами в сети. Годно, двигаемся дальше.
Общий план такой — закинуть на телефон корень дебиана, и запускать нужные мне службы из чрута, так как каждый раз огребать проблем с сбором той или иной софтины через ndk — застрелиться не жить.
А когда заработает — можно и набросать в эклипсе гуёвину, для запуска/остановки карманного сервера одним кликом прикосновением.
Если честно, то я так ни разу и не удосужился пощупать кишки своего аппарата за почти полтора года владения им. А это уже упущение — стареем-с. Итак, подцепляем по adb консольку и осматриваемся.

/ # uname -a
Linux localhost 2.6.35.7 #1 PREEMPT Wed Feb 8 19:45:24 CST 2012 armv6l GNU/Linux

/proc/filesystems выдает весьма нелицеприятный диагноз:

/ # cat /proc/filesystems 
nodev   sysfs
nodev   rootfs
nodev   bdev
nodev   proc
nodev   tmpfs
nodev   sockfs
nodev   pipefs
nodev   anon_inodefs
nodev   devpts
nodev   ramfs
        vfat
        msdos
        yaffs
        yaffs2
nodev   mqueue
nodev   mtd_inodefs

И это печально. Печально тем, что у нас нет ни одной файловой системы, кроме yaffs2, которая поддерживает все так нужные фичи и годиться для корневой фс дебиана. только убожества типа vfat и msdos. Так как телефон у меня на MTК6573, а про то, как медиатек открывает исходники любят говорить плохо, я изначально приготовился к тому, что ядро пересобрать не выйдет. Но мне повезло — в ядре были включены подгружаемые модули, а значит при должной сноровке можно дособрать необходимые куски в рабочем виде, даже не имея родных исходников ядра.
Но эту магию я, пожалуй, распишу как-нибудь в другой раз — мне повезло вдвойне — в /system/lib/modules/ оказалось…

/ # ls /system/lib/modules/
xlog.ko
wlan.ko
sec.ko
sbup.ko
pvrsrvkm.ko
p2p.ko
mtklfb.ko
mtk_stp_wmt.ko
mtk_stp_uart.ko
mtk_stp_sdio.ko
mtk_stp_gps.ko
mtk_stp_core.ko
mtk_stp_bt.ko
mtk_hif_sdio.ko
mtk_fm_priv.ko
mtk_drvb_73.ko
mt6573_mfv_kernel_driver.ko
mt6573_m4u.ko
lca_core.ko
ext2.ko
ccmni.ko
ccci.ko
aed.ko

ext2.ko. Который надо полагать и не подгружался автоматом. Сойдет. Как говориться — на безрыбье и рак рыба.
загружаем@проверяем…

/ # cat /proc/filesystems 
nodev   sysfs
nodev   rootfs
nodev   bdev
nodev   proc
nodev   tmpfs
nodev   sockfs
nodev   pipefs
nodev   anon_inodefs
nodev   devpts
nodev   ramfs
        vfat
        msdos
        yaffs
        yaffs2
nodev   mqueue
nodev   mtd_inodefs
        ext2
/ #

И оно даже работает. Вин.
Далее я поставил бэкапится всю свою 32GiB карту, так как предстояла ее переразбивка на два раздела. Первый так и останется в vfat’е для андроеда, второй гига эдак на 3-4 станет корнем для debian’а.
Оный, пока шел бэкап, я забутсрепил раскурив оффициальный(tm) мануал на Debian Wiki.
после шаманства с cfdisk’ом и распаковки минимальный дебиан был водружен на раздел. И вот тут-то и потребовалось шаманство.
Так как графические приложения из дебиана мне на телефоне не сильно нужны, мне надо только запустить/остановить пяток служб. Не долго думая, я выдавил из себя вот такое вот шаманство на баше:

DAEMONS="lighttpd ssh minidlna mysql"
 
export SDCARD=/sdcard
export ROOT=/data/debian
export DEV=/dev/block/mmcblk0p2
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH
CMD=$1
 
 
log()
{
am broadcast -a org.ncrmnt.serverctl.log -e log "$*"
}
 
prepare()
{
log "Mounting debian chroot..."
insmod /system/lib/modules/ext2.ko 
mount -o rw,noatime -t ext2 $DEV $ROOT
mount -o bind /sys $ROOT/sys
mount -o bind /dev $ROOT/dev
mount -o bind /proc $ROOT/proc
mount -o bind /dev/pts $ROOT/dev/pts
mount -o bind,users $SDCARD $ROOT/mnt
mount -t tmpfs none $ROOT/tmp
mount -o rw -t tmpfs none $ROOT/var/log
mkdir $ROOT/var/log/lighttpd
hostname `cat $ROOT/etc/hostname`
log "Hostname set to `cat $ROOT/etc/hostname`"
}
 
run_service()
{
log `chroot $ROOT /etc/init.d/$1 $CMD`
}
 
t_done()
{
 log "chroot environment fully unmounted. "
 exit
}
 
if [ "$CMD" == "terminate" ]; then
 
        echo "Cleaning up..."
        $0 stop
        #Kill any working ssh sessions.
        killall -9 sshd
        killall ssh
        umount $ROOT/var/log
        umount $ROOT/tmp
        umount $ROOT/dev/pts
        umount $ROOT/dev
        umount $ROOT/proc
        umount $ROOT/sys
        umount $ROOT/mnt
        umount $ROOT
        rmmod /system/lib/modules/ext2.ko
        [ -f "$ROOT/etc/hostname" ] || t_done
        log "ERROR: chroot is still mounted"
        log "ERROR: ditch any running ssh sessions and try again"
        log "ERROR: termination failed"
        exit
fi
 
log "clean"
log "Necromant's pocket server"
 
[ -d $ROOT/dev ] || prepare 
 
for s in $DAEMONS; do
run_service $s
done
 
log "All done, have fun"

По коду только заострю внимание на паре вещей:

  • Для ext2/3/4 опция noatime. Эта опция нам здорово продлит срок службы карты, так как не будет фиксировать каждое прикосновение к файлу.
  • /tmp и /var/log — я поместил в tmpfs с той же самой целью — меньше нагрузки на карту.
  • Для того, чтобы лайти взлетел ему пришлось создать каталог для логов.
  • Так как инит дебиана у нас не стартует, то имя хоста мы выставляем хаком при подкотовке чрута.
  • /dev в подмонтированной FS служит нам маркером, что мы все сделали.
  • Terminate специально натаскан пришибать все висящие ssh сеансы чтобы отрубить чрут окружение.

Далее мы тупо запускаем/останавливаем выводок наших демонов из переменной «DAEMONS». Осталось только сохранить этот скрипт как serverctl куда-нибудь в /system/bin или на карту памяти и можно делать

serverctl start/stop/restart

Тут есть один нюанс. Когда корень дебиана монтируется куда-то на карту памяти, у меня по этой фс начинал шастать media scanner, из-за которого нельзя было размонтировать chroot. Потому, я создал каталог debian в /data, и монтирую корень уже в него.

Дальше я штатными средствами установил и настроил стандартную связку: lighttpd, php, minidlna, gitweb, ssh, mysql и сел рисовать вебгуй.
Особо не запариваясь стянул темплейт с freecsstemplates и начал его уродовать. Так как тянуть cms’ку с темплейтингом было очень лень, я решил обойтись одним хтмль файлом, который заполнять/обновлять ажаксом. Ну и несколько штук php файликов в две-три строчки, которые выдают данные. Больше-то и не надо.
В ходе копаний в /sys обнаружились интересные «вкусняшки», которые я и решил вывести в веб-гуй. Сделал я это через очень простые костыли на php, от которых матерых веб девелоперов должно в теории передернуть.

$f=$_GET['file']; 
$f=str_replace("..","",$f); 
$f=str_replace("\/\/","",$f); 
$a=file_get_contents("/sys/$f"); 
echo $a;

Таким образом в веб-интерфейс попали данные о напряжении/температуре батарейки, потребляемый ток, напряжение на заряднике (если он подцеплен), и куча других не менее бесполезных данных, которые я периодически получаю из веб-гуя ажаксом.
Дополнил я это еще несколькими не менее уродливыми скриптами на php:
Для получения свободного места:

$fs = $_GET['fs'];
$data=shell_exec("df -h $fs");
$data = explode("\n",$data);
$data = preg_split ("/\s+/",$data[1]);
//print_r($data);
foreach ($data as $d) {
        echo "'$d',";
}

Всего у меня получилось около 5-7 таких страшеньких файликов, которые я закинул в /var/www.

На очереди было поднятие gitweb и вообще организация git репозиториев на этом карманном сервере. Начал я с того, что добавил пользователя git.
Далее создал в каталоге этого пользователя .ssh, где создаем файлик authorized_keys. Так как push и pull мы будем делать по ssh, то и авторизацию лучше поставить по ключу, а ключи добавлять через веб интерфейс. Сначала я экспериментировал с правами и strictmode опцией в sshd, но потом забил, и заставил lighttpd работать от имени пользователя git. Это упростило задачу, и я быстренько нарисовал скрипты для решения из веба основных задач: создание пустого репозитория, клонирование репозитория к себе по урлу и отображение ссылок для клона и добавления remote. Все тот же php, который запускает шелл. Можно было сделать и красивее, но мне было очень лень.
Получился эдакий github в кармане.

Из более тяжелых php скриптов (собственно, ради которых я вообще тащил туда php) на карманном сервере быстренько разместились sticky-notes и phpmyadmin (за компанию). В планах еще подыскать какой-нибудь удобоваримый и простой багтрекер уровня TODO листа на php.

anomalia4

anomalia1

anomalia3

anomalia5

Наконец, венец моего на сегодня сумасшествия — гуй для запуска/останова всего этого хозяйства. Для этого я выдавил из себя немного кода на джаве.
Для обратной связи с гуем, я добавил в баш скрипт рассыл броадкаста по запуску каждой из служб. Все это добро присутствует выше.

2013-03-18-00-19-21

Все? Нет, и это еще не все, ибо знатно что-то меня сегодня припекло. (Весна?) До кучи я решил выводить в веб-интерфейс данные с камер. А то один хрен на главной странице пустое место. Подумаешь, захватить картинку через v4l?
Оказалось, что нет. Суровые тайваньцы/китайцы/хрен_этих_азиатов_разберет из медиатека положили крепежные изделия на поддержку v4l/v4l2 и камера у них заведена через «нестандартное техническое решение»(tm). По-русски — проприетарный огороженный костыль. (Как и блютуз, кстати — никакими bluez’ами и dbus’ами на медиатеках даже и не пахло!).
Получить картинку из debian’а просто так не вышло. В итоге, потыкавшись минуты три, пришлось в мою запускалку на java за компанию добавить службу, которая слушает порт 8888 и на по GET запросам выдает картинки с передней камеры и задней, которые уже вставляются в веб страницу.
Для добавления пафоса, я реализовал это через lightbox2, который обеспечивает плавно вылетающее всплывающее окно с фотографией по нажатию на front cam или back cam. Выглядит примерно так:

anomalia2

Теперь самое вкусное, а именно исходники этого маразма, которые можно бесплатно и без смс скачать на github’е. (Achtung! Код писался за пару вечеров и ОЧЕНЬ страшен!)

WebUI
Android app

Впечатления:
Телефон у меня, мягко говоря, не топовый, и интерфейс андроеда на нем иногда подлагивает, и плавностью анимаций как на топовых телефонах или эталоне гламурности и пафосности — iPhone тут даже не пахнет.
Внутри arm1176 на частоте 650Mhz и 512 мегабайт памяти из которых половину, если не больше отожрал сам андройд, 64 метра откусил еще при старте 3д ускоритель. И тем не менее, несмотря на все это, я не заметил заметных тормозов ни при пользовании gitweb’ом, ни при поьзовании sticky-notes. Даже phpmyadmin, поставленный смеха ради, и который должен быть эталоном тормознутости ворочается вполне себе быстро… И только java… «не тормозит» (с) ™.

Сервер в кармане: 7 комментариев

  1. Интересное решение. остается выкинуть все внутренности андроида кроме браузера, звонилки и медиасервера и будет суровая firefoxOS 🙂

    и еще один риторический вопрос: а почему не арч?

  2. @domov0y: WebUi заскриншотен с десктопа, на телефоне я его обычно не открываю, телефон при этом работает как телефон, без каких либо проблем.

    > и еще один риторический вопрос: а почему не арч?

    У дебиана реже апдейты, и реже что-то ломают. Арч я юзаю только на десктопе, где для работы нужен апстрим как можно свежее. На сервере/телефоне возня с арчем не окупает временных затрат.

  3. «В планах еще подыскать какой-нибудь удобоваримый и простой багтрекер уровня TODO листа на php. »
    http://mantisbt.org/ не подойдет? Он вроде сьедобный и явного отторжения не вызывает.

    смысл сервера — флешка с сорцами в условиях когда до интернета сто верст и все лесом?

  4. @domov0y:

    mantis щупал, таки сильно навороченный для задачи.

    Смысл — это не флешка в кармане, а уже карманный роутер+сервер, которым можно быстро сорганизовать работу в полевых условиях небольшой команды, и иметь под рукой все инструменты. git да, на флешке можно держать, и делать push/pull друг другу, но менее удобно.

  5. Вопрос: из chroot окружения звук мплеером вывести можно? или все глухо чуть менее чем полностью?

  6. @domov0y: Зависит от трубки. дройдовский звуковой сервер может залочить устройство на себя, и куку. А может и нет, и тогда все через альзу нормально полезет.

  7. Т.е от того на каком SOC сделано оно не зависит?! если так, то обидно.
    Я надеялся, что доблестные китайцы работающие с медиатек, чаще реализуют alsa на уровне ядра.

Добавить комментарий