2023-08-21 19:13:24 +00:00
|
|
|
/*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public
|
|
|
|
* License v2 as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public
|
|
|
|
* License along with this program; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 021110-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kerncompat.h"
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <uuid/uuid.h>
|
|
|
|
#include "common/sysfs-utils.h"
|
|
|
|
#include "common/path-utils.h"
|
|
|
|
#include "common/utils.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open a file in fsid directory in sysfs and return the file descriptor or
|
|
|
|
* error
|
|
|
|
*/
|
2023-12-08 21:43:59 +00:00
|
|
|
static int sysfs_open_fsid_file_flags(int fd, const char *filename, int flags)
|
2023-08-21 19:13:24 +00:00
|
|
|
{
|
|
|
|
u8 fsid[BTRFS_UUID_SIZE];
|
|
|
|
char fsid_str[BTRFS_UUID_UNPARSED_SIZE];
|
|
|
|
char sysfs_file[PATH_MAX];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = get_fsid_fd(fd, fsid);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
uuid_unparse(fsid, fsid_str);
|
|
|
|
|
|
|
|
ret = path_cat3_out(sysfs_file, "/sys/fs/btrfs", fsid_str, filename);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2023-12-08 21:50:57 +00:00
|
|
|
ret = open(sysfs_file, flags);
|
|
|
|
return (ret < 0 ? -errno : ret);
|
2023-12-08 21:43:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int sysfs_open_fsid_file(int fd, const char *filename)
|
|
|
|
{
|
|
|
|
return sysfs_open_fsid_file_flags(fd, filename, O_RDONLY);
|
|
|
|
}
|
|
|
|
|
|
|
|
int sysfs_open_fsid_file_rw(int fd, const char *filename)
|
|
|
|
{
|
|
|
|
return sysfs_open_fsid_file_flags(fd, filename, O_RDWR);
|
2023-08-21 19:13:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open a file in the toplevel sysfs directory and return the file descriptor
|
|
|
|
* or error.
|
|
|
|
*/
|
2023-12-08 21:43:59 +00:00
|
|
|
static int sysfs_open_file_flags(const char *name, int flags)
|
2023-08-21 19:13:24 +00:00
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = path_cat_out(path, "/sys/fs/btrfs", name);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2023-12-08 21:50:57 +00:00
|
|
|
ret = open(path, flags);
|
|
|
|
return (ret < 0 ? -errno : ret);
|
2023-12-08 21:43:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int sysfs_open_file(const char *name)
|
|
|
|
{
|
|
|
|
return sysfs_open_file_flags(name, O_RDONLY);
|
|
|
|
}
|
|
|
|
|
|
|
|
int sysfs_open_file_rw(const char *name)
|
|
|
|
{
|
|
|
|
return sysfs_open_file_flags(name, O_RDWR);
|
2023-08-21 19:13:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open a directory by name in fsid directory in sysfs and return the file
|
|
|
|
* descriptor or error, filedescriptor suitable for fdreaddir. The @dirname
|
|
|
|
* must be a directory name.
|
|
|
|
*/
|
|
|
|
int sysfs_open_fsid_dir(int fd, const char *dirname)
|
|
|
|
{
|
|
|
|
u8 fsid[BTRFS_UUID_SIZE];
|
|
|
|
char fsid_str[BTRFS_UUID_UNPARSED_SIZE];
|
|
|
|
char sysfs_file[PATH_MAX];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = get_fsid_fd(fd, fsid);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
uuid_unparse(fsid, fsid_str);
|
|
|
|
|
|
|
|
ret = path_cat3_out(sysfs_file, "/sys/fs/btrfs", fsid_str, dirname);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2023-12-08 21:50:57 +00:00
|
|
|
ret = open(sysfs_file, O_DIRECTORY | O_RDONLY);
|
|
|
|
return (ret < 0 ? -errno : ret);
|
2023-08-21 19:13:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read up to @size bytes to @buf from @fd
|
|
|
|
*/
|
|
|
|
int sysfs_read_file(int fd, char *buf, size_t size)
|
|
|
|
{
|
2023-12-08 21:50:57 +00:00
|
|
|
int ret;
|
|
|
|
|
2023-08-21 19:13:24 +00:00
|
|
|
lseek(fd, 0, SEEK_SET);
|
|
|
|
memset(buf, 0, size);
|
2023-12-08 21:50:57 +00:00
|
|
|
ret = read(fd, buf, size);
|
|
|
|
return (ret < 0 ? -errno : ret);
|
2023-08-21 19:13:24 +00:00
|
|
|
}
|
|
|
|
|
2023-12-08 21:43:59 +00:00
|
|
|
int sysfs_write_file(int fd, const char *buf, size_t size)
|
|
|
|
{
|
2023-12-08 21:50:57 +00:00
|
|
|
int ret;
|
|
|
|
|
2023-12-08 21:43:59 +00:00
|
|
|
lseek(fd, 0, SEEK_SET);
|
2023-12-08 21:50:57 +00:00
|
|
|
ret = write(fd, buf, size);
|
|
|
|
return (ret < 0 ? -errno : ret);
|
2023-12-08 21:43:59 +00:00
|
|
|
}
|
|
|
|
|
2023-08-21 19:26:31 +00:00
|
|
|
int sysfs_read_file_u64(const char *name, u64 *value)
|
|
|
|
{
|
|
|
|
int fd = -1;
|
|
|
|
int ret;
|
|
|
|
char str[32] = { 0 };
|
|
|
|
|
|
|
|
fd = sysfs_open_file(name);
|
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
ret = sysfs_read_file(fd, str, sizeof(str));
|
|
|
|
if (ret < 0)
|
|
|
|
goto out;
|
|
|
|
/* Raw value in any numeric format should work, followed by a newline. */
|
2023-12-01 01:10:23 +00:00
|
|
|
errno = 0;
|
2023-08-21 19:26:31 +00:00
|
|
|
*value = strtoull(str, NULL, 0);
|
2023-12-08 21:50:57 +00:00
|
|
|
ret = -errno;
|
2023-08-21 19:26:31 +00:00
|
|
|
out:
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-12-08 21:43:59 +00:00
|
|
|
int sysfs_write_file_u64(const char *name, u64 value)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int ret;
|
|
|
|
char str[32] = { 0 };
|
|
|
|
|
|
|
|
fd = sysfs_open_file_rw(name);
|
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
ret = snprintf(str, sizeof(str), "%llu", value);
|
|
|
|
ret = sysfs_write_file(fd, str, ret);
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-08-21 19:26:31 +00:00
|
|
|
int sysfs_read_fsid_file_u64(int fd, const char *name, u64 *value)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
char str[32] = { 0 };
|
|
|
|
|
|
|
|
fd = sysfs_open_fsid_file(fd, name);
|
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
ret = sysfs_read_file(fd, str, sizeof(str));
|
|
|
|
if (ret < 0)
|
|
|
|
goto out;
|
|
|
|
/* Raw value in any numeric format should work, followed by a newline. */
|
2023-12-01 01:10:23 +00:00
|
|
|
errno = 0;
|
2023-08-21 19:26:31 +00:00
|
|
|
*value = strtoull(str, NULL, 0);
|
2023-12-08 21:50:57 +00:00
|
|
|
ret = -errno;
|
2023-08-21 19:26:31 +00:00
|
|
|
out:
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
2023-12-08 21:43:59 +00:00
|
|
|
|
|
|
|
int sysfs_write_fsid_file_u64(int fd, const char *name, u64 value)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
char str[32] = { 0 };
|
|
|
|
|
|
|
|
fd = sysfs_open_fsid_file_rw(fd, name);
|
|
|
|
if (fd < 0)
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
ret = snprintf(str, sizeof(str), "%llu", value);
|
|
|
|
ret = sysfs_write_file(fd, str, ret);
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|