-
Notifications
You must be signed in to change notification settings - Fork 204
/
Copy pathshim_fs_pseudo.h
225 lines (186 loc) · 9 KB
/
shim_fs_pseudo.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/* Copyright (C) 2021 Intel Corporation
* Paweł Marczewski <pawel@invisiblethingslab.com>
*/
/*
* This file defines the "pseudo" filesystem: a building block for implementing pseudo-FSes such as
* `/proc`, `/sys` or `/dev`.
*
* A pseudo-filesystem is defined by creating a tree of `pseudo_node` nodes:
*
* struct pseudo_node* root = pseudo_add_root_dir("proc");
* pseudo_add_link(root, "self", &proc_self_follow_link);
* pseudo_add_str(root, "cpuinfo", &proc_cpuinfo_load);
*
* It can then be mounted by providing the root name ("proc" in the example):
*
* ret = mount_fs("pseudo", "proc", "/proc");
*
* See the documentation of `pseudo_node` structure for details.
*
* TODO: The pseudo filesystem currently does not implement proper invalidation for
* dynamically-generated directory listings (such as `/proc/<pid>`), so stale dentries might remain
* for files that shouldn't exist anymore.
*
* TODO: The string-backed files are kept per handle, not per dentry. This doesn't matter so much
* for read-only files, but if a writable file is opened twice, changes will not propagate between
* handles.
*/
#ifndef SHIM_FS_PSEUDO_H_
#define SHIM_FS_PSEUDO_H_
#include "list.h"
#include "perm.h"
#include "shim_fs.h"
/* Node types */
enum pseudo_type {
/* Directory */
PSEUDO_DIR = 1,
/* Symbolic link */
PSEUDO_LINK = 2,
/* String-backed file */
PSEUDO_STR = 3,
/* Character device */
PSEUDO_DEV = 4,
};
/* Callbacks for PSEUDO_DEV nodes */
struct shim_dev_ops {
int (*open)(struct shim_handle* hdl, struct shim_dentry* dent, int flags);
int (*close)(struct shim_handle* hdl);
ssize_t (*read)(struct shim_handle* hdl, void* buf, size_t count);
ssize_t (*write)(struct shim_handle* hdl, const void* buf, size_t count);
int (*flush)(struct shim_handle* hdl);
int64_t (*seek)(struct shim_handle* hdl, int64_t offset, int whence);
int (*truncate)(struct shim_handle* hdl, uint64_t len);
};
#define PSEUDO_PERM_DIR PERM_r_xr_xr_x /* default for directories */
#define PSEUDO_PERM_LINK PERM_rwxrwxrwx /* default for links */
#define PSEUDO_PERM_FILE_R PERM_r__r__r__ /* default for all other files */
#define PSEUDO_PERM_FILE_RW PERM_rw_rw_rw_
/*
* A node of the pseudo filesystem. A single node can describe either a single file, or a family of
* files (see `name_exists` and `list_names` below).
*
* The constructors for `pseudo_node` (`pseudo_add_*`) take arguments for most commonly used fields.
* The node can then be further customized by directly modifying other fields.
*/
DEFINE_LIST(pseudo_node);
DEFINE_LISTP(pseudo_node);
struct pseudo_node {
enum pseudo_type type;
LIST_TYPE(pseudo_node) siblings;
struct pseudo_node* parent;
/* File name. Can be NULL if the node provides the below callbacks. */
const char* name;
/* Returns true if a file with a given name exists. */
bool (*name_exists)(struct shim_dentry* parent, const char* name);
/* Retrieves all file names for this node. Works the same as `readdir`. */
int (*list_names)(struct shim_dentry* parent, readdir_callback_t callback, void* arg);
/* File permissions. See `PSEUDO_PERM_*` above for defaults. */
mode_t perm;
/* Type-specific fields: */
union {
/* PSEUDO_DIR */
struct {
LISTP_TYPE(pseudo_node) children;
} dir;
/* PSEUDO_LINK */
struct {
/*
* Reads link target. Should allocate a new (null-terminated) string: it will be freed
* using `free`.
*
* If the callback is not provided, the `target` field will be used instead.
*/
int (*follow_link)(struct shim_dentry* dent, char** out_target);
const char* target;
} link;
/* PSEUDO_STR */
struct {
/*
* Provides data for newly-opened file. Should allocate a new buffer: on file close, the
* buffer will be freed using `free`.
*
* If the callback is not provided, the opened file will start out empty.
*/
int (*load)(struct shim_dentry* dent, char** out_data, size_t* out_size);
/* Invoked when saving a modified file (on `close` or `flush`). Optional. */
int (*save)(struct shim_dentry* dent, const char* data, size_t size);
} str;
/* PSEUDO_DEV */
struct {
/* Callbacks to use with this device */
struct shim_dev_ops dev_ops;
/* Device major and minor numbers, used with `stat` */
unsigned int major;
unsigned int minor;
} dev;
};
};
/*
* \brief Convert a string to number (for use in paths)
*
* \param str the string
* \param max_value maximum value
* \param[out] out_value on success, set to the parsed number
*
* \return 0 on success, -1 on failure
*
* Recognizes a string that is a unique representation of a number (0 <= value <= max_value):
* the string should be non-empty, consist only of digits, and have no leading zeroes.
*
* Provided for use in `name_exists` callback for recognizing pseudo-filesystem file names.
*/
int pseudo_parse_ulong(const char* str, unsigned long max_value, unsigned long* out_value);
struct pseudo_node* pseudo_add_root_dir(const char* name);
struct pseudo_node* pseudo_add_dir(struct pseudo_node* parent_ent, const char* name);
struct pseudo_node* pseudo_add_link(struct pseudo_node* parent_ent, const char* name,
int (*follow_link)(struct shim_dentry*, char**));
struct pseudo_node* pseudo_add_str(struct pseudo_node* parent_ent, const char* name,
int (*load)(struct shim_dentry*, char**, size_t*));
struct pseudo_node* pseudo_add_dev(struct pseudo_node* parent_ent, const char* name);
extern struct shim_fs pseudo_builtin_fs;
/* procfs */
int init_procfs(void);
int proc_meminfo_load(struct shim_dentry* dent, char** out_data, size_t* out_size);
int proc_cpuinfo_load(struct shim_dentry* dent, char** out_data, size_t* out_size);
int proc_self_follow_link(struct shim_dentry* dent, char** out_target);
bool proc_thread_pid_name_exists(struct shim_dentry* parent, const char* name);
int proc_thread_pid_list_names(struct shim_dentry* parent, readdir_callback_t callback, void* arg);
bool proc_thread_tid_name_exists(struct shim_dentry* parent, const char* name);
int proc_thread_tid_list_names(struct shim_dentry* parent, readdir_callback_t callback, void* arg);
int proc_thread_follow_link(struct shim_dentry* dent, char** out_target);
int proc_thread_maps_load(struct shim_dentry* dent, char** out_data, size_t* out_size);
int proc_thread_cmdline_load(struct shim_dentry* dent, char** out_data, size_t* out_size);
bool proc_thread_fd_name_exists(struct shim_dentry* parent, const char* name);
int proc_thread_fd_list_names(struct shim_dentry* parent, readdir_callback_t callback, void* arg);
int proc_thread_fd_follow_link(struct shim_dentry* dent, char** out_target);
bool proc_ipc_thread_pid_name_exists(struct shim_dentry* parent, const char* name);
int proc_ipc_thread_follow_link(struct shim_dentry* dent, char** out_target);
/* devfs */
int init_devfs(void);
int init_attestation(struct pseudo_node* dev);
/* sysfs */
int init_sysfs(void);
int sys_load(const char* str, char** out_data, size_t* out_size);
int sys_resource_find(struct shim_dentry* parent, const char* name, unsigned int* num);
bool sys_resource_name_exists(struct shim_dentry* parent, const char* name);
int sys_resource_list_names(struct shim_dentry* parent, readdir_callback_t callback, void* arg);
int sys_node_general_load(struct shim_dentry* dent, char** out_data, size_t* out_size);
int sys_node_load(struct shim_dentry* dent, char** out_data, size_t* out_size);
int sys_cpu_general_load(struct shim_dentry* dent, char** out_data, size_t* out_size);
int sys_cpu_load(struct shim_dentry* dent, char** out_data, size_t* out_size);
int sys_cache_load(struct shim_dentry* dent, char** out_data, size_t* out_size);
bool sys_cpu_online_name_exists(struct shim_dentry* parent, const char* name);
int sys_cpu_online_list_names(struct shim_dentry* parent, readdir_callback_t callback, void* arg);
/* Converts struct pal_res_range_info to a string representation.
* Example output when sep == ',': "10-63,68,70-127".
* Note: This function adds a newline at the end of the string. */
int sys_convert_ranges_to_str(const struct pal_res_range_info* resource_range_info, const char* sep,
char* str, size_t str_size);
/* Converts struct pal_res_range_info to a sysfs CPU bitmask representation with bitmask size based
* on the possible cores count in the system.
* Example output for 64 cores in total and ranges 0-15,48-55: "00ff0000,0000ffff".
* Note: This function adds a newline at the end of the string. */
int sys_convert_ranges_to_cpu_bitmap_str(const struct pal_res_range_info* resource_range_info, char* str,
size_t str_size);
#endif /* SHIM_FS_PSEUDO_H_ */