在 C 中使用 ioctl() 设置不可变标志

Setting Immutable Flag using ioctl() in C

我试图创建一个脚本来创建一个文件,然后将其设置为不可变,类似于 linux 的 chattr +i 命令。 脚本编译(使用 gcc),运行并创建文件。但是 文件 本身 不是不可变的,可以通过简单的 rm -f 删除 。我试图在调用 chattr 的地方进行堆栈跟踪,我发现了一个名为 ioctl 的函数。然后,我使用了我能收集到的少量信息,并得出了下面的结论。我从 ext2_fs.h 缩小了它的范围,但它似乎不起作用。我显然忽略了一些东西。

对先前条目的更新编译returns-1 ioctl() 函数。 地址错误 perror().

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>

int main()
{
    FILE *fp;
    char shovel[16] = "I have a shovel!";
    fp = fopen("/shovel.txt", "w+");
    fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
    ioctl(fileno(fp), FS_IOC_SETFLAGS, 0x00000010);
    fclose(fp);
}

感谢任何帮助。

主要问题是 ioctl 需要一个指向 掩码的 指针,而不是直接常量。您必须定义一个 int 变量,将掩码 (0x10) 存储在其中并将其地址作为 ioctl.

的第三个参数传递

此外,我会添加一些提示:

  • 其他改变属性的程序直接使用低级I/O(打开,关闭...)。此外,该文件通常使用 O_RDONLY 打开。
  • 使用 FS_IMMUTABLE_FL 代替原始常量。
  • 首先获取当前属性掩码 (FS_IOC_SETFLAGS) 并用新标志对其进行掩码,这样服务就不会丢失其他设置。

您使用了正确的 ioctl 命令,但传递给它的参数错误。

ioctl_list(2) 的联机帮助页显示 FS_IOC_SETFLAGS 期望收到指向 int 的指针(一个 int *),但您向它传递了一个整数文字(因此 Bad Address 错误)。

您不进行任何错误检查这一事实也无济于事。

传递给 FS_IOC_SETFLAGS 的正确标志是一个指针,其中包含值 EXT2_IMMUTABLE_FL,它在 ext2fs/ext2_fs.h 中定义(一些较旧的/不同的 Linux 发行版似乎放在 linux/ext2_fs.h 下),所以你需要 #include <ext2fs/etx2_fs.h>。确保安装 e2fslibs-dev(您可能还需要 linux-headers)。

此代码有效:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <ext2fs/ext2_fs.h>

int main()
{
    FILE *fp;
    char shovel[16] = "I have a shovel!";

    if ((fp = fopen("shovel.txt", "w+")) == NULL) {
        perror("fopen(3) error");
        exit(EXIT_FAILURE);
    }

    fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);

    int val = EXT2_IMMUTABLE_FL;
    if (ioctl(fileno(fp), FS_IOC_SETFLAGS, &val) < 0)
        perror("ioctl(2) error");

    fclose(fp);

    return 0;
}

记住 运行 这是 root。

更新:

作为 Giuseppe Guerrini suggests in ,您可能想改用 FS_IMMUTABLE_FL,并且不需要包括 ext2_fs.h:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>

int main()
{
    FILE *fp;
    char shovel[16] = "I have a shovel!";

    if ((fp = fopen("shovel.txt", "w+")) == NULL) {
        perror("fopen(3) error");
        exit(EXIT_FAILURE);
    }

    fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);

    int val = FS_IMMUTABLE_FL;
    if (ioctl(fileno(fp), FS_IOC_SETFLAGS, &val) < 0)
        perror("ioctl(2) error");

    fclose(fp);

    return 0;
}