命名管道中的访问权限

时间:2019-05-03 20:23:26

标签: c operating-system

我有这个简单的代码,可以使用命名管道将值从子进程传递到父进程。代码:

App.php

我读到0666授予读和写权限,0200授予只写权限,0400授予只读权限,0000没有权限。但是,如果我将0666更改为其中任何一个,则代码可以正常工作。为什么会发生这种情况,我想念什么?

1 个答案:

答案 0 :(得分:1)

正如我在评论中指出的那样,使用0666可以向用户,组和其他用户授予读取和写入权限,而0400意味着只有用户可以访问管道,并且他们只能从中读取(只有超级用户可以向其中写入数据) ),而0200表示只有用户可以访问该管道,并且他们只能对其进行写入(只有超级用户可以从中读取)。 (名称“ superuser”是“具有适当特权的用户”的简写,在基于Unix的系统上通常表示root。)

这是您的代码版本,用于演示错误检查和报告。它使用可选的命令行参数作为要使用的FIFO的名称。它测试0666040002000的每个模式。如果操作花费的时间太长,就会因超时而感到困惑。信号处理代码要注意avoid using printf() in a signal handler,并且字符串具有足够的空间来容纳7位PID,例如在AIX上找到的。

该程序使用我的“标准错误报告功能”,该代码可在GitHub上的SOQ(堆栈溢出问题)存储库中以文件stderr.cstderr.h中的文件形式使用src/libsoq子目录。使用它们可以简化错误处理代码。包含rem的函数名称进行注释(并继续);报告错误消息后,那些以err结尾的代码将退出。这些选项将时间报告为毫秒分辨率,并确保PID出现在错误消息中。

#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

#include "stderr.h"

static void test_fifo(const char *fifo, int mode);
static void alarm_handler(int signum);

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);
    err_setlogopts(ERR_PID|ERR_MILLI);
    int modes[] = { 0666, 0400, 0200, 0 };
    enum { NUM_MODES = sizeof(modes) / sizeof(modes[0]) };
    char *myfifo = "/tmp/myfifo";
    if (argc > 1)
        myfifo = argv[1];

    signal(SIGALRM, alarm_handler);

    for (int i = 0; i < NUM_MODES; i++)
    {
        putchar('\n');
        test_fifo(myfifo, modes[i]);
        int corpse;
        int status;
        while ((corpse = wait(&status)) > 0)
            err_remark("Child %d exited with status 0x%.4X\n", corpse, status);
    }

    return 0;
}

static void set_pid(int pid, char *str)
{
    if (pid / 10 > 0)
        set_pid(pid / 10, str + 1);
    else
    {
        str[1] = '\n';
        str[2] = '\0';
    }
    *str = (pid % 10) + '0';
}

static void alarm_handler(int signum)
{
    char msg[] = "Signal ?? received by ???????\n";
    msg[7] = (signum / 10) > 0 ? (signum / 10) + '0' : ' ';
    msg[8] = (signum % 10) + '0';
    set_pid(getpid(), &msg[22]);
    write(0, msg, strlen(msg));
}

static void test_fifo(const char *fifo, int mode)
{
    unlink(fifo);
    if (mkfifo(fifo, mode) != 0)
    {
        err_sysrem("failed to create FIFO '%s' with mode %0o\n", fifo, mode);
        return;
    }
    pid_t c = fork();
    /* With ERR_PID set, the PID is reported automatically */
    err_remark("(PPID %d) at work\n", (int)getppid());

    if (c == 0)
    {
        /* Child */
        srand(time(0));
        int val = rand() % 100;
        alarm(10);
        int fd = open(fifo, O_WRONLY);
        if (fd < 0)
            err_syserr("failed to open FIFO '%s' for writing\n", fifo);
        if (write(fd, &val, sizeof(val)) != sizeof(val))
            err_syserr("failed to write to FIFO '%s'\n", fifo);
        printf("Wrote %d to FIFO '%s'\n", val, fifo);
        close(fd);
        exit(0);
    }

    if (c > 0)
    {
        /* Parent */
        alarm(10);
        int fd = open(fifo, O_RDONLY);
        if (fd < 0)
        {
            err_sysrem("failed to open FIFO '%s' for reading\n", fifo);
            return;
        }
        int val;
        if (read(fd, &val, sizeof(val)) != sizeof(val))
        {
            err_sysrem("failed to write to FIFO '%s'\n", fifo);
            return;
        }
        printf("read value %d from FIFO '%s'\n", val, fifo);
        close(fd);
        if (unlink(fifo) != 0)
            err_sysrem("failed to remove FIFO '%s'\n", fifo);
    }
}

我有意识地选择不报告close()中的错误;如果close()仍然报告失败,则您无能为力。未检查第一个unlink();如果FIFO不存在,则期望失败;如果不存在,则期望成功。如果FIFO存在但无法删除(因为它是目录,或者用户没有权限,或者其他原因),则错误报告检查mkfifo()将处理问题。 wait()循环的位置有助于确保显示错误消息等,即使父级由于无法打开FIFO而快速完成而子级由于能够打开FIFO而完成得很慢也是如此。

示例输出(我调用了程序fifo37,源代码在fifo37.c中)

$ ./fifo37

fifo37: 2019-05-03 14:58:48.612 - pid=94485: (PPID 51845) at work
fifo37: 2019-05-03 14:58:48.612 - pid=94486: (PPID 94485) at work
Wrote 1 to FIFO '/tmp/myfifo'
read value 1 from FIFO '/tmp/myfifo'
fifo37: 2019-05-03 14:58:48.614 - pid=94485: Child 94486 exited with status 0x0000

fifo37: 2019-05-03 14:58:48.614 - pid=94485: (PPID 51845) at work
fifo37: 2019-05-03 14:58:48.614 - pid=94487: (PPID 94485) at work
fifo37: 2019-05-03 14:58:48.614 - pid=94487: failed to open FIFO '/tmp/myfifo' for writing
error (13) Permission denied
Signal 14 received by 58449
fifo37: 2019-05-03 14:58:58.615 - pid=94485: failed to open FIFO '/tmp/myfifo' for reading
error (4) Interrupted system call
fifo37: 2019-05-03 14:58:58.615 - pid=94485: Child 94487 exited with status 0x0100

fifo37: 2019-05-03 14:58:58.616 - pid=94485: (PPID 51845) at work
fifo37: 2019-05-03 14:58:58.616 - pid=94485: failed to open FIFO '/tmp/myfifo' for reading
error (13) Permission denied
fifo37: 2019-05-03 14:58:58.616 - pid=94488: (PPID 94485) at work
Signal 14 received by 58449
Signal 14 received by 88449
fifo37: 2019-05-03 14:59:08.619 - pid=94488: failed to open FIFO '/tmp/myfifo' for writing
error (4) Interrupted system call
fifo37: 2019-05-03 14:59:08.621 - pid=94485: Child 94488 exited with status 0x0100

fifo37: 2019-05-03 14:59:08.621 - pid=94485: (PPID 51845) at work
fifo37: 2019-05-03 14:59:08.621 - pid=94485: failed to open FIFO '/tmp/myfifo' for reading
error (13) Permission denied
fifo37: 2019-05-03 14:59:08.621 - pid=94489: (PPID 94485) at work
fifo37: 2019-05-03 14:59:08.622 - pid=94489: failed to open FIFO '/tmp/myfifo' for writing
error (13) Permission denied
fifo37: 2019-05-03 14:59:08.622 - pid=94485: Child 94489 exited with status 0x0100
$