Print usage when missing mandatory arguments
[deb_libnfs.git] / examples / fuse_nfs.c
1 /*
2 Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2013
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17 /* A FUSE filesystem based on libnfs. */
18
19 #define FUSE_USE_VERSION 26
20 #define _FILE_OFFSET_BITS 64
21
22 #include <fuse.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <getopt.h>
29
30 #include <nfsc/libnfs.h>
31
32 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
33
34 struct nfs_context *nfs = NULL;
35
36 static int fuse_nfs_getattr(const char *path, struct stat *stbuf)
37 {
38 int ret = 0;
39
40 memset(stbuf, 0, sizeof(struct stat));
41 ret = nfs_stat(nfs, path, stbuf);
42
43 return ret;
44 }
45
46 static int fuse_nfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
47 off_t offset, struct fuse_file_info *fi)
48 {
49 struct nfsdir *nfsdir;
50 struct nfsdirent *nfsdirent;
51
52 int ret = 0;
53
54 ret = nfs_opendir(nfs, path, &nfsdir);
55 if (ret < 0) {
56 return ret;
57 }
58 while ((nfsdirent = nfs_readdir(nfs, nfsdir)) != NULL) {
59 filler(buf, nfsdirent->name, NULL, 0);
60 }
61
62 return ret;
63 }
64
65 static int fuse_nfs_open(const char *path, struct fuse_file_info *fi)
66 {
67 int ret = 0;
68 struct nfsfh *nfsfh;
69
70 fi->fh = 0;
71 ret = nfs_open(nfs, path, fi->flags, &nfsfh);
72 if (ret < 0) {
73 return ret;
74 }
75
76 fi->fh = (uint64_t)nfsfh;
77
78 return ret;
79 }
80
81 static int fuse_nfs_release(const char *path, struct fuse_file_info *fi)
82 {
83 struct nfsfh *nfsfh = (struct nfsfh *)fi->fh;
84
85 nfs_close(nfs, nfsfh);
86 return 0;
87 }
88
89 static int fuse_nfs_read(const char *path, char *buf, size_t size,
90 off_t offset, struct fuse_file_info *fi)
91 {
92 int ret = 0;
93 struct nfsfh *nfsfh = (struct nfsfh *)fi->fh;
94
95 ret = nfs_pread(nfs, nfsfh, offset, size, buf);
96
97 return ret;
98 }
99
100 static int fuse_nfs_write(const char *path, const char *buf, size_t size,
101 off_t offset, struct fuse_file_info *fi)
102 {
103 int ret = 0;
104 struct nfsfh *nfsfh = (struct nfsfh *)fi->fh;
105
106 ret = nfs_pwrite(nfs, nfsfh, offset, size, discard_const(buf));
107
108 return ret;
109 }
110
111 static int fuse_nfs_create(const char *path, mode_t mode, struct fuse_file_info *fi)
112 {
113 int ret = 0;
114 struct nfsfh *nfsfh;
115
116 ret = nfs_creat(nfs, path, mode, &nfsfh);
117 if (ret < 0) {
118 return ret;
119 }
120
121 fi->fh = (uint64_t)nfsfh;
122
123 return ret;
124 }
125
126 static int fuse_nfs_utime(const char *path, struct utimbuf *times)
127 {
128 int ret = 0;
129
130 ret = nfs_utime(nfs, path, times);
131 if (ret < 0) {
132 return ret;
133 }
134
135 return ret;
136 }
137
138 static int fuse_nfs_unlink(const char *path)
139 {
140 int ret = 0;
141
142 ret = nfs_unlink(nfs, path);
143 if (ret < 0) {
144 return ret;
145 }
146
147 return ret;
148 }
149
150 static int fuse_nfs_rmdir(const char *path)
151 {
152 int ret = 0;
153
154 ret = nfs_rmdir(nfs, path);
155 if (ret < 0) {
156 return ret;
157 }
158
159 return ret;
160 }
161
162 static int fuse_nfs_mkdir(const char *path, mode_t mode)
163 {
164 int ret = 0;
165
166 ret = nfs_mkdir(nfs, path);
167 if (ret < 0) {
168 return ret;
169 }
170 ret = nfs_chmod(nfs, path, mode);
171 if (ret < 0) {
172 return ret;
173 }
174
175 return ret;
176 }
177
178 static struct fuse_operations nfs_oper = {
179 .create = fuse_nfs_create,
180 .getattr = fuse_nfs_getattr,
181 .mkdir = fuse_nfs_mkdir,
182 .open = fuse_nfs_open,
183 .read = fuse_nfs_read,
184 .readdir = fuse_nfs_readdir,
185 .release = fuse_nfs_release,
186 .rmdir = fuse_nfs_rmdir,
187 .unlink = fuse_nfs_unlink,
188 .utime = fuse_nfs_utime,
189 .write = fuse_nfs_write,
190 };
191
192 void print_usage(char *name)
193 {
194 printf("Usage: %s [-?|--help] [-n|--nfs-share=nfs-url] [-m|--mountpoint=mountpoint]\n",
195 name);
196 exit(0);
197 }
198
199 int main(int argc, char *argv[])
200 {
201 int ret = 0;
202 static struct option long_opts[] = {
203 { "help", no_argument, 0, '?' },
204 { "nfs-share", required_argument, 0, 'n' },
205 { "mountpoint", required_argument, 0, 'm' },
206 { NULL, 0, 0, 0 }
207 };
208 int c;
209 int opt_idx = 0;
210 char *url = NULL;
211 char *mnt = NULL;
212 char *server = NULL, *export = NULL, *strp;
213 int fuse_nfs_argc = 5;
214 char *fuse_nfs_argv[16] = {
215 "fuse-nfs",
216 "<export>",
217 "-oallow_other",
218 "-odefault_permissions",
219 "-omax_write=32768",
220 NULL,
221 NULL,
222 NULL,
223 NULL,
224 NULL,
225 NULL,
226 NULL,
227 NULL,
228 NULL,
229 NULL,
230 NULL,
231 };
232
233 while ((c = getopt_long(argc, argv, "?hm:n:", long_opts,
234 &opt_idx)) > 0) {
235 switch (c) {
236 case 'h':
237 case '?':
238 print_usage(argv[0]);
239 return 0;
240 case 'm':
241 mnt = strdup(optarg);
242 break;
243 case 'n':
244 url = strdup(optarg);
245 break;
246 }
247 }
248
249 if (url == NULL) {
250 fprintf(stderr, "-n was not specified.\n");
251 print_usage(argv[0]);
252 ret = 10;
253 goto finished;
254 }
255 if (mnt == NULL) {
256 fprintf(stderr, "-m was not specified.\n");
257 print_usage(argv[0]);
258 ret = 10;
259 goto finished;
260 }
261
262
263 if (strncmp(url, "nfs://", 6)) {
264 fprintf(stderr, "Invalid URL specified.\n");
265 ret = 10;
266 goto finished;
267 }
268 server = strdup(url + 6);
269 if (server == NULL) {
270 fprintf(stderr, "Failed to strdup server string\n");
271 ret = 10;
272 goto finished;
273 }
274 if (server[0] == '/' || server[0] == '\0') {
275 fprintf(stderr, "Invalid server string.\n");
276 ret = 10;
277 goto finished;
278 }
279 strp = strchr(server, '/');
280 if (strp == NULL) {
281 fprintf(stderr, "Invalid URL specified.\n");
282 ret = 10;
283 goto finished;
284 }
285 export = strdup(strp);
286 if (export == NULL) {
287 fprintf(stderr, "Failed to strdup server string\n");
288 ret = 10;
289 goto finished;
290 }
291 if (export[0] != '/') {
292 fprintf(stderr, "Invalid export.\n");
293 ret = 10;
294 goto finished;
295 }
296 *strp = 0;
297
298 nfs = nfs_init_context();
299 if (nfs == NULL) {
300 printf("failed to init context\n");
301 goto finished;
302 }
303
304 ret = nfs_mount(nfs, server, export);
305 if (ret != 0) {
306 printf("Failed to mount nfs share : %s\n", nfs_get_error(nfs));
307 goto finished;
308 }
309
310
311 fuse_nfs_argv[1] = mnt;
312 return fuse_main(fuse_nfs_argc, fuse_nfs_argv, &nfs_oper, NULL);
313
314 finished:
315 if (nfs != NULL) {
316 nfs_destroy_context(nfs);
317 }
318 free(server);
319 free(export);
320 free(url);
321 free(mnt);
322 return ret;
323 }