-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.c
More file actions
233 lines (210 loc) · 7.62 KB
/
main.c
File metadata and controls
233 lines (210 loc) · 7.62 KB
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
226
227
228
229
230
231
232
233
/* Use newer version of FUSE API. */
#define FUSE_USE_VERSION 26
#include <fuse.h>
#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <log.h>
#include "config.h"
#include "entry.h"
#include "fileops.h"
#include "globals.h"
/* Configuration file to read. */
static char *config_filename = NULL;
/* Debugging enabled. */
static int debug = 0;
/* Entries to present to the user in the mount point. */
entry_t *entries = NULL;
size_t entries_sz = 0;
/* Identity of the mounter. This will become the owner of all entries in the
* mount point.
*/
uid_t uid;
gid_t gid;
/* Size in bytes to assign to each file. */
#define DEFAULT_SIZE (10 * 1024) /* 10 KB */
size_t size = DEFAULT_SIZE;
/* Debugging functions. */
static void debug_dump_entries(void) {
assert(entries_sz != PARSE_FAIL);
size_t i;
fprintf(stderr, "Entries table has %u entries:\n", (unsigned int)entries_sz);
for (i = 0; i < entries_sz; ++i) {
fprintf(stderr, " Path: %s; -%c%c%c%c%c%c%c%c%c; Exec: %s; Size %d\n", entries[i].path,
entries[i].u_r?'r':'-', entries[i].u_w?'w':'-', entries[i].u_x?'x':'-',
entries[i].g_r?'r':'-', entries[i].g_w?'w':'-', entries[i].g_x?'x':'-',
entries[i].o_r?'r':'-', entries[i].o_w?'w':'-', entries[i].o_x?'x':'-',
entries[i].command, entries[i].size);
}
}
static int debug_printf(char *format, ...) {
va_list ap;
int result;
va_start(ap, format);
result = vfprintf(stderr, format, ap);
va_end(ap);
return result;
}
/* Signal handling functions. */
static void handle_sigchld(int signal) {
/* Collect any zombie children. */
pid_t pid;
do {
pid = waitpid(-1, NULL, WNOHANG);
} while (pid > 0);
}
static void install_signal_handlers(void) {
signal(SIGCHLD, handle_sigchld);
}
/* Parse command line arguments. Returns 0 on success, non-zero on failure. */
static int parse_args(int argc, char **argv, int *last) {
static struct option options[] = {
{"debug", no_argument, &debug, 1},
{"config", required_argument, 0, 'c'},
{"fuse", no_argument, 0, 'f'},
{"help", no_argument, 0, '?'},
{"log", required_argument, 0, 'l'},
{"size", required_argument, 0, 's'},
{"version", no_argument, 0, 'v'},
{0, 0, 0, 0},
};
int index;
int c;
char *log_file = NULL;
while ((c = getopt_long(argc, argv, "dc:f?", options, &index)) != -1) {
switch (c) {
case 0: {
/* This should have set a flag. */
assert(options[index].flag != 0);
break;
} case 'c': {
if (config_filename != NULL) {
/* Let a later config parameter override an earlier one. */
free(config_filename);
config_filename = NULL;
}
config_filename = strdup(optarg);
if (config_filename == NULL) {
/* Out of memory. */
return -1;
}
break;
} case 'd': {
debug = 1;
break;
} case 'f': {
/* We've hit the FUSE arguments. */
assert(last != NULL);
*last = optind;
if (log_file != NULL) {
if (log_init(debug ? DEBUG : INFO, log_file, NULL, 1) != 0) {
fprintf(stderr, "Failed to open log file %s\n", log_file);
return -1;
}
free(log_file);
}
return 0;
} case 'l': {
log_file = strdup(optarg);
if (log_file == NULL) {
errno = ENOMEM;
return -1;
}
break;
} case 's': {
size_t sz = atoi(optarg);
if (sz == 0) {
fprintf(stderr, "Invalid file size %s passed\n", optarg);
errno = EINVAL;
return -1;
}
size = sz;
break;
} case 'v': {
printf("execfs version %s\n", VERSION);
exit(0);
} case '?': {
printf("Usage: %s options -f fuse_options\n"
" -c, --config FILE Read configuration from the given file. This argument\n"
" is required.\n"
" -d, --debug Enable debugging output on startup.\n"
" -f, --fuse Any arguments following this are interpreted as\n"
" arguments to be passed through to FUSE. This argument\n"
" must be used to terminate your execfs argument list.\n"
" -?, --help Print this usage information.\n"
" -l, --log FILE Write logging information to FILE. Without this\n"
" argument no logging is performed.\n"
" -s, --size SIZE A size in bytes to report each file entry as having\n"
" (default 10). The argument exists because some programs\n"
" will stat a file before reading it and only read as\n"
" many bytes as its reported size. Increase this value if\n"
" you find the output of your executed commands is being\n"
" truncated when read.\n",
argv[0]);
exit(0);
} default: {
fprintf(stderr, "Unrecognised argument: %c\n", optopt);
errno = EINVAL;
return -1;
}
}
}
/* If we reached here, then we never found a -f/--fuse argument. */
fprintf(stderr, "No -f/--fuse argument provided.\n");
errno = EINVAL;
return -1;
}
int main(int argc, char **argv) {
int last_arg;
if (parse_args(argc, argv, &last_arg) != 0) {
perror("Failed to parse arguments");
return -1;
}
if (config_filename == NULL) {
fprintf(stderr, "No configuration file specified.\n");
return -1;
}
entries = parse_config(&entries_sz, config_filename, debug ? &debug_printf : NULL);
if (entries_sz == PARSE_FAIL) {
if (errno != 0) {
perror("Failed to parse configuration file");
} else {
fprintf(stderr, "Failed to parse configuration file\n");
}
return -1;
}
/* We don't need the configuration file any more. */
free(config_filename);
config_filename = NULL;
if (debug) {
debug_dump_entries();
}
/* Install our signal handlers now. */
install_signal_handlers();
/* Set the owner of the mount point entries. */
uid = geteuid();
gid = getegid();
/* Adjust arguments to hide any that we handled from FUSE. */
--last_arg;
assert(last_arg > 0);
assert(last_arg < argc);
argv[last_arg] = argv[0];
argv += last_arg;
argc -= last_arg;
assert(argv[argc] == NULL);
if (debug) {
fprintf(stderr, "Altered argument parameters:\n");
int i;
for (i = 0; i < argc; ++i) {
fprintf(stderr, "%d: %s\n", i, argv[i]);
}
}
return fuse_main(argc, argv, &ops, NULL);
}