繁体   English   中英

write() 到 sysfs 条目 /sys/bus/pci/devices/.../driver/remove_id 失败

[英]write() to sysfs entry /sys/bus/pci/devices/.../driver/remove_id fails

看到write() function 在/sys/bus/pci/devices/.../driver/remove_id文件上失败,返回 -1, errno等于 19 ( ENODEV )。

但是,同样可以通过命令行正常工作。 我已经检查了文件权限,这似乎很好 (--w--------) 用户可以对该文件执行写入。

int fp = 0;
int buffer_length = 0;
int bytes_written = 0;

fp = open(cmd_buf, O_WRONLY); // where cmd_buf will hold this string 
                              // "/sys/bus/pci/devices/.../driver/remove_id"
if (fp == -1)
{
    return -1;
}

// where inbuf will be a char * pointing to pci vendor device id like 
// this, "XXXX YYYY"
bytes_written = write(fp, in_buf, sizeof(in_buf));
printf(" bytes_written : %d \n ", bytes_written);

看到 bytes_written 等于 -1 并且errno显示 19。

如果您发现代码片段有问题,请告诉我?

两个可能的问题:

  1. write()系统调用中使用sizeof(in_buf)写入字符串“vendorId deviceId”,如果in_buf[]大于 10 个字符,则可能在其后有更多垃圾数据。
  2. 也许in_buf不是表而是指针,因此sizeof(in_buf)将返回 4 或 8(指针的大小分别适用于 32 位或 64 位系统),但不是它指向的字符串的长度。

因此,在这两种情况下( in_buf定义为表或指针), strlen(in_buf)而不是sizeof(in_buf)是要写入的数据长度的最安全解决方案,前提是字符串以 '\0' 终止.

您没有提供足够的信息来查明问题。

但是,这里有一个示例程序,example.c,表明是您的实现存在错误:

#define _POSIX_C_SOURCE  200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>

/* Write string 'data' to existing file or device at 'path'.
   Returns 0 if success, errno error code otherwise.
*/
int write_file(const char *path, const char *data)
{
    const char *const  ends = (data) ? data + strlen(data) : data;
    ssize_t            n;
    int                fd;

    /* NULL or empty path is invalid. */
    if (!path || !*path)
        return errno = EINVAL;

    fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_NOCTTY | O_CLOEXEC, 0666);
    if (fd == -1)
        return errno; /* errno already set by open(). */

    /* Write the contents of data. */
    while (data < ends) {
        n = write(fd, data, (size_t)(ends - data));
        if (n > 0) {
            /* Wrote n bytes. */
            data += n;
        } else
        if (n != -1) {
            /* C Library bug: Should never occur. */
            close(fd);
            return errno = EIO;
        } else {
            /* Error in errno. */
            const int  saved_errno = errno;
            close(fd);
            return errno = saved_errno;
        }
    }

    if (close(fd) == -1) {
        /* It is possible for close() to report a delayed I/O error. */
        return errno;
    }

    /* Success. */
    return 0;
}

static void usage(const char *argv0)
{
    fprintf(stderr, "\n");
    fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv0);
    fprintf(stderr, "       %s FILE CONTENTS\n", argv0);
    fprintf(stderr, "\n");
    fprintf(stderr, "This does the same thing as 'echo -n \"CONTENTS\" > FILE'.\n");
    fprintf(stderr, "\n");
}


int main(int argc, char *argv[])
{
    if (argc < 2) {
        usage((argv && argv[0] && argv[0][0]) ? argv[0] : "(this)");
        return EXIT_SUCCESS;
    } else
    if (argc > 3) {
        usage((argv && argv[0] && argv[0][0]) ? argv[0] : "(this)");
        return EXIT_FAILURE;
    } else
    if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
        usage((argv && argv[0] && argv[0][0]) ? argv[0] : "(this)");
        return EXIT_SUCCESS;
    }

    if (write_file(argv[1], argv[2])) {
        fprintf(stderr, "%s: %s.\n", argv[1], strerror(errno));
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

使用例如gcc -Wall -Wextra -O2 example.c -o example编译它,并使用例如./example /sys/bus/pci/devices/.../driver/remove_id "vendor_id device_id"运行。 在没有 arguments 的情况下运行它,或者使用-h--help作为唯一参数,它会将使用信息打印到标准错误。

该程序基本上执行echo -n "vendor_id device_id" > /sys/bus/pci/devices/.../drivers/remove_id执行的操作。

如果成功,它不会 output 任何东西,只是返回成功(退出状态 0)。 如果有任何类型的错误,它将报告给标准错误。

如果您知道目标路径始终是设备或伪文件(如 /sys 或 /proc 中的文件),请使用fd = open(path, O_WRONLY | O_NOCTTY | O_CLOEXEC); 反而。 O_CLOEXEC意味着如果进程在任何时候分叉,这个特定的文件描述符不会被复制到子进程。 O_NOCTTY表示如果路径是 tty 设备,并且当前进程没有控制终端,则 kernel 不会使打开的设备成为控制终端。

echo -n使用O_CREAT | O_TRUNC O_CREAT | O_TRUNC ,这样如果目标路径存在且是普通文件,则截断,如果不存在,则创建。 它不影响打开现有的字符设备和伪文件。 每当使用O_CREAT时,必须有第三个参数,它影响创建的文件的访问模式。 此模式通常为0666 ,允许由当前 umask 调节的读写访问。 可以使用mode_t mask = umask(0); umask(mask); mode_t mask = umask(0); umask(mask); . umask 中设置的访问模式位在最终访问模式中始终为零,而 umask 中清除的访问模式位取自创建文件时 open() 命令的第三个参数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM