Почему в fakeroot chown возвращает EPERM, даже если все прошло успешно (но, с другой стороны, это не так)?

Почему в fakeroot chown возвращает EPERM, даже если все прошло успешно (но, с другой стороны, это не так)?

Я сталкивался со странным поведением при использованииЧаун(2)в среде fakeroot. Следующая минимальная программа иллюстрирует проблему:

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>

int main() {
    //choose a reasonably unique filename
    char path[30];
    sprintf(path, "./file-%d", getpid());

    //create file
    close(creat(path, 0644));

    //chown to some random UID/GID
    chown(path, 4444, 4444);

    //stat again (result can be seen in strace below)
    struct stat s;
    stat(path, &s);

    return 0;
}

Предположим, что это main.c. Теперь я запускаю следующее в fakeroot bash:

$ gcc -o main main.c
$ strace -v ./main
...
creat("./file-10872", 0644)             = 3
close(3)                                = 0
...
lchown("./file-10872", 84, 84)          = -1 EPERM (Operation not permitted)
stat("./file-10872", {st_dev=makedev(8, 3), st_ino=3932971, st_mode=S_IFREG|0644, st_nlink=1, st_uid=1001, st_gid=100, st_blksize=4096, st_blocks=0, st_size=0, st_atime=2015/10/31-20:12:07, st_mtime=2015/10/31-20:12:07, st_ctime=2015/10/31-20:12:07}) = 0
...
$ ls -l file-10872
-rw-r--r-- 1 4444 4444 0 31. Okt 20:12 file-10872

Что мы здесь видим?

  1. Вызов chownне выполнен из-за ошибки EPERM (операция не разрешена).
  2. Последующее statпоказывает st_uid=1001, st_gid=100, какой из моих настоящих (не поддельных) UID и GID (что странно, потому что, если я правильно понимаю fakeroot, он должен как минимум показывать st_uid=0, st_gid=0).
  3. Последующее ls -lв том же файле показывает, что chownУСПЕШНО, хотя chownсообщалось о неудаче, и последующее statподтверждает это.

Что за фигня тут происходит? Я нашел ошибку в fakeroot или это просто непонимание того, как работает fakeroot?

(У меня fakerootверсия 1.20.2, а моя система — Arch Linux со всеми обновлениями.)

Обновлять:Йонас Велицкий правильно заметил, что strace работает на уровне системных вызовов и, таким образом, вводит в заблуждение, поскольку результаты системных вызовов будут искажены libfakeroot перед тем, как будут возвращены в саму программу. Оказывается, что после stat(path, &s), struct stat sсодержит новые UID и GID. Но все равно сбивает с толку то, что chownне работает с EPERM.

решение1

chownна самом деле возвращает ноль при запуске под fakeroot. Таким образом, согласно errno(3):

Его значение имеет значение только тогда, когда возвращаемое значение вызова указывает на ошибку (т. е. -1 из большинства системных вызовов; -1 или NULL из большинства библиотечных функций); функция, которая завершается успешно, может изменить errno.

Значение errnoне имеет существенного значения и chownна самом деле не провалилось.

Как уже обсуждалось в комментариях, straceвывод содержит EPERM и неподдельные uid/gid, как и ожидалось, в виде straceтрассировок ниже библиотеки fakeroot LD_PRELOAD. Распечатка uid/gid из программы показывает правильный (поддельный) вывод.

Связанный контент