Вопрос или проблема
Я только что наткнулся на странное поведение в Android:
echo test>/data/local/tmp/test.txt
su root -c "cat /data/local/tmp/test.txt && \
tar -cvzf /data/local/tmp/test.tar.gz /data/local/tmp/test.txt && \
echo $?"
ls -alh /data/local/tmp/test.txt
Это создаст пустой test.tar.gz:
test
removing leading "https://unix.stackexchange.com/" from member names
data/local/tmp/test.txt
0
-rw-r--r-- 1 root root 0 2025-01-09 17:43 /data/local/tmp/test.tar.gz
Запуск без su root -c
создаст tar.gz размером 120 байт:
-rw-r--r-- 1 root root 120 2025-01-09 17:47 /data/local/tmp/test.tar.gz
Добавление задержки, как здесь:
su root -c "tar -cvzf /data/local/tmp/test.tar.gz /data/local/tmp/test.txt && sleep 1"
Также создаст tar.gz размером 120 байт.
Обновление:
При выполнении с файлом размером 50 МБ, подкоманда tar блокируется, пока не завершится, и создает недопустимый tar.gz, который на 22031 байт меньше допустимого tar.gz, созданного без su -c
$ ls -alh /system/apex/com.android.art.release.apex
-rw-r--r-- 1 root root 54M 2009-01-01 00:00 /system/apex/com.android.art.release.apex
$ tar -cvzf /data/local/tmp/big.tar.gz /system/apex/com.android.art.release.apex
$ su root -c "tar -cvzf /data/local/tmp/bigsu.tar.gz /system/apex/com.android.art.release.apex"
removing leading "https://unix.stackexchange.com/" from member names
system/apex/com.android.art.release.apex
$ ls -al /data/local/tmp/b*
-rw-r--r-- 1 root root 22541839 2025-01-09 21:43 /data/local/tmp/big.tar.gz
-rw-r--r-- 1 root root 22519808 2025-01-09 21:33 /data/local/tmp/bigsu.tar.gz
$ tar -xvzf /data/local/tmp/bigsu.tar.gz /data/local/tmp/big.apex ; echo $?
zcat: gzclose: Inappropriate ioctl for device
tar: EOF: Illegal seek
1
$ tar -xvzf /data/local/tmp/big.tar.gz /data/local/tmp/big.apex ; echo $?
0
Такое же поведение при использовании другого пользователя, кроме root.
Эта проблема возникает на эмуляторе Android 11. Мне не удалось воспроизвести ее на моих Linux серверах.
Единственное объяснение, которое я могу найти, заключается в том, что буфер записи из tar не очищается на эмуляторе диска.
Команда stat для файла внутри подкоманды заставляет данные корректно записываться:
$ su root -c "tar -cvzf /data/local/tmp/test.tar.gz /data/local/tmp/test.txt && stat /data/local/tmp/test.tar.gz"
removing leading "https://unix.stackexchange.com/" from member names
data/local/tmp/test.txt
File: /data/local/tmp/test.tar.gz
Size: 120 Blocks: 16 IO Blocks: 512 regular file
Device: fd05h/64773d Inode: 65546 Links: 1 Device
type: 0,0
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2025-01-09 17:43:44.964000000 +0000
Modify: 2025-01-09 22:00:28.496000000 +0000
Change: 2025-01-09 22:00:28.496000000 +0000
$ ls -alh /data/local/tmp/test.tar.gz
-rw-r--r-- 1 root root 120 2025-01-09 22:00 /data/local/tmp/test.tar.gz
Но почему завершение под оболочки предотвращает запись в выходной файл? Когда tar завершается с кодом успеха 0, это означает, что записанные данные должны быть уже обработаны и сохранены ядром.
Простое копирование не имеет проблем с записью. Так что это может быть ошибка в tar.
su root -c "cp /system/apex/com.android.art.release.apex>/data/local/tmp/release.apex"
su root -c "cat /system/apex/com.android.art.release.apex>/data/local/tmp/releasecat.apex"
ls -al /data/local/tmp/release*
-rw-r--r-- 1 root root 56510850 2025-01-09 22:31 /data/local/tmp/release.apex
-rw-r--r-- 1 root root 56510850 2025-01-09 22:33 /data/local/tmp/releasecat.apex
Версия tar в busybox не имеет этой проблемы!
$ su root -c "/data/adb/magisk/busybox tar --version"
tar (busybox) 1.36.1-Magisk
$ su root -c "/data/adb/magisk/busybox tar -cvzf /data/local/tmp/test.tar.gz /data/local/tmp/test.txt"
$ ls -alh /data/local/tmp/test.tar.gz
-rw-r--r-- 1 root root 120 2025-01-09 22:42 /data/local/tmp/test.tar.gz
Примечания:
- версия tar
toybox 0.8.3-android
- то же самое при использовании /sdcard/Download в качестве директории.
Ответ или решение
Похоже, вы столкнулись с интересной проблемой при использовании tar
на Android устройстве через ADB с правами superuser. Рассмотрим проблему и возможные причины возникновения следующего поведения: команда с использованием su root -c
для создания tar-архива вызывает создание пустого файла.
Объяснение проблемы:
-
Описание поведения:
Использование командыsu root -c
для создания архива с помощьюtar
приводит к созданию пустого архива. При исполнении команды безsu root -c
, архив создается корректно. Добавление задержки черезsleep
или командыstat
после выполненияtar
также приводит к корректному созданию архива. -
Важные наблюдения:
- Использование
tar
из пакета Toybox вызывает проблему, но BusyBox успешно создает архив с правами суперпользователя. - Проблема повторяется независимо от локации файлов.
- Самостоятельное копирование файлов проходит без проблем, что исключает проблему на стороне дисковой подсистемы.
- Использование
Анализ возможных причин:
-
Конкуренция за ресурсы:
Вызывающаяся с привилегиямиsu
командная оболочка может завершаться раньше, чемtar
полностью завершает запись буфера на диск. Это связано с особенностями управления процессами в Toybox для Android. -
Буферизация ввода/вывода:
Tar в Toybox может неправильно обрабатывать буферизацию ввода/вывода в контекстеsu root -c
, из-за чего изменение контекста пользователя влияет на процедуру flush для кэша данных, не обеспечивая своевременную запись на диск. -
Версия программного обеспечения:
Учитывая, что проблема не повторяется с BusyBox, это может указывать на баг или не поддерживаемое поведение в определенной версии Toybox, используемой в вашем окружении Android 11.
Рекомендации и решения:
-
Использовать BusyBox:
Поскольку BusyBox не имеет проблемы с созданием архива, его использование может стать временным решением. -
Модифицировать порядок команды:
Распределение выполнения посредством добавления дополнительных системных вызовов (какstat
) или задержки (sleep
) может обеспечить выполнение flush перед завершением процессаsu
. -
Совместимость и обновление:
Проверьте наличие более новой версии Toybox или других инструментов archiving на вашем устройстве для обновления, которые могут устранить данную неисправность. -
Оставлять открытый сессионный процесс:
Проверка применения альтернативного способа выполнения, что оставляет процессsu
активным для успешной flush операции.
Эта проблема подчеркивает сложности взаимодействия между программным обеспечением для администрирования и особенностями файловой системы Android. Препятствия в эмуляторе могут отличаться от production-систем, и подчеркивают необходимость тестирования в реальных условиях.