tar compress внутри android adb su root -c sub команда создает пустой tar файл.

Вопрос или проблема

Я только что наткнулся на странное поведение в 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-архива вызывает создание пустого файла.

Объяснение проблемы:

  1. Описание поведения:
    Использование команды su root -c для создания архива с помощью tar приводит к созданию пустого архива. При исполнении команды без su root -c, архив создается корректно. Добавление задержки через sleep или команды stat после выполнения tar также приводит к корректному созданию архива.

  2. Важные наблюдения:

    • Использование tar из пакета Toybox вызывает проблему, но BusyBox успешно создает архив с правами суперпользователя.
    • Проблема повторяется независимо от локации файлов.
    • Самостоятельное копирование файлов проходит без проблем, что исключает проблему на стороне дисковой подсистемы.

Анализ возможных причин:

  1. Конкуренция за ресурсы:
    Вызывающаяся с привилегиями su командная оболочка может завершаться раньше, чем tar полностью завершает запись буфера на диск. Это связано с особенностями управления процессами в Toybox для Android.

  2. Буферизация ввода/вывода:
    Tar в Toybox может неправильно обрабатывать буферизацию ввода/вывода в контексте su root -c, из-за чего изменение контекста пользователя влияет на процедуру flush для кэша данных, не обеспечивая своевременную запись на диск.

  3. Версия программного обеспечения:
    Учитывая, что проблема не повторяется с BusyBox, это может указывать на баг или не поддерживаемое поведение в определенной версии Toybox, используемой в вашем окружении Android 11.

Рекомендации и решения:

  1. Использовать BusyBox:
    Поскольку BusyBox не имеет проблемы с созданием архива, его использование может стать временным решением.

  2. Модифицировать порядок команды:
    Распределение выполнения посредством добавления дополнительных системных вызовов (как stat) или задержки (sleep) может обеспечить выполнение flush перед завершением процесса su.

  3. Совместимость и обновление:
    Проверьте наличие более новой версии Toybox или других инструментов archiving на вашем устройстве для обновления, которые могут устранить данную неисправность.

  4. Оставлять открытый сессионный процесс:
    Проверка применения альтернативного способа выполнения, что оставляет процесс su активным для успешной flush операции.

Эта проблема подчеркивает сложности взаимодействия между программным обеспечением для администрирования и особенностями файловой системы Android. Препятствия в эмуляторе могут отличаться от production-систем, и подчеркивают необходимость тестирования в реальных условиях.

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

Капча загружается...