write() 到 sysfs 条目 /sys/bus/pci/devices/.../driver/remove_id 失败
write() to sysfs entry /sys/bus/pci/devices/.../driver/remove_id fails
看到 write() 函数在 /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.
如果您发现代码片段有问题,请告诉我?
两个可能的问题:
- 在 write() 系统调用中使用 sizeof(in_buf) 写入字符串“vendorId deviceId”并且可能如果 in_buf[] 大于 10 个字符,则后面有更多垃圾数据。
- 也许 in_buf 不是 table 而是指针,因此 sizeof(in_buf) 将 return 4 或 8(指针的大小分别用于 32 位或 64 位系统)但不是它指向的字符串的长度。
因此,在这两种情况下(in_buf 定义为 table 或指针),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"
。
运行 它没有参数,或者以 -h
或 --help
作为唯一的参数,它会将使用信息打印到标准错误。
该程序基本上执行 echo -n "vendor_id device_id" > /sys/bus/pci/devices/.../drivers/remove_id
的操作。
如果成功,则不会输出任何内容,只是return成功(退出状态0)。如果有任何类型的错误,它将报告给标准错误。
如果您知道目标路径始终是设备或伪文件(如 /sys 或 /proc 中的那些),请改用 fd = open(path, O_WRONLY | O_NOCTTY | O_CLOEXEC);
。 O_CLOEXEC
意味着如果进程在任何时候分叉,这个特定的文件描述符不会被复制到子进程。 O_NOCTTY
表示如果路径是一个tty设备,并且当前进程没有控制终端,内核不会让打开的设备成为控制终端。
echo -n
使用O_CREAT | O_TRUNC
,这样如果目标路径存在且是普通文件,则t运行cated,不存在则创建.它不影响打开现有的字符设备和伪文件。每当使用 O_CREAT
时,必须有第三个参数,它影响创建的文件的访问模式。此模式通常为 0666
,允许由当前 umask 控制的读写访问。可以使用 mode_t mask = umask(0); umask(mask);
获得当前的 umask。 umask 中设置的访问模式位在最终访问模式中始终为零,而 umask 中清除的访问模式位取自创建文件时 open() 命令的第三个参数。
看到 write() 函数在 /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.
如果您发现代码片段有问题,请告诉我?
两个可能的问题:
- 在 write() 系统调用中使用 sizeof(in_buf) 写入字符串“vendorId deviceId”并且可能如果 in_buf[] 大于 10 个字符,则后面有更多垃圾数据。
- 也许 in_buf 不是 table 而是指针,因此 sizeof(in_buf) 将 return 4 或 8(指针的大小分别用于 32 位或 64 位系统)但不是它指向的字符串的长度。
因此,在这两种情况下(in_buf 定义为 table 或指针),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"
。
运行 它没有参数,或者以 -h
或 --help
作为唯一的参数,它会将使用信息打印到标准错误。
该程序基本上执行 echo -n "vendor_id device_id" > /sys/bus/pci/devices/.../drivers/remove_id
的操作。
如果成功,则不会输出任何内容,只是return成功(退出状态0)。如果有任何类型的错误,它将报告给标准错误。
如果您知道目标路径始终是设备或伪文件(如 /sys 或 /proc 中的那些),请改用 fd = open(path, O_WRONLY | O_NOCTTY | O_CLOEXEC);
。 O_CLOEXEC
意味着如果进程在任何时候分叉,这个特定的文件描述符不会被复制到子进程。 O_NOCTTY
表示如果路径是一个tty设备,并且当前进程没有控制终端,内核不会让打开的设备成为控制终端。
echo -n
使用O_CREAT | O_TRUNC
,这样如果目标路径存在且是普通文件,则t运行cated,不存在则创建.它不影响打开现有的字符设备和伪文件。每当使用 O_CREAT
时,必须有第三个参数,它影响创建的文件的访问模式。此模式通常为 0666
,允许由当前 umask 控制的读写访问。可以使用 mode_t mask = umask(0); umask(mask);
获得当前的 umask。 umask 中设置的访问模式位在最终访问模式中始终为零,而 umask 中清除的访问模式位取自创建文件时 open() 命令的第三个参数。