XRootD
Loading...
Searching...
No Matches
XrdFfsXrootdfs.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* xrootdfs.cc FUSE based file system interface to Xrootd Storage Cluster */
3/* */
4/* (c) 2010 by the Board of Trustees of the Leland Stanford, Jr., University */
5/* All Rights Reserved */
6/* Author: Wei Yang (SLAC National Accelerator Laboratory, 2009) */
7/* Contract DE-AC02-76-SFO0515 with the Department of Energy */
8/* */
9/* This file is part of the XRootD software suite. */
10/* */
11/* XRootD is free software: you can redistribute it and/or modify it under */
12/* the terms of the GNU Lesser General Public License as published by the */
13/* Free Software Foundation, either version 3 of the License, or (at your */
14/* option) any later version. */
15/* */
16/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19/* License for more details. */
20/* */
21/* You should have received a copy of the GNU Lesser General Public License */
22/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24/* */
25/* The copyright holder's institutional names and contributor's names may not */
26/* be used to endorse or promote products derived from this software without */
27/* specific prior written permission of the institution or contributor. */
28/******************************************************************************/
29
30#define FUSE_USE_VERSION 26
31
32#include <cstdio>
33#include <cstdlib>
34#include <unistd.h>
35#include <stddef.h>
36
37#if defined(__linux__)
38/* For pread()/pwrite() */
39#ifndef _XOPEN_SOURCE
40#define _XOPEN_SOURCE 500
41#endif
42#endif
43
44#ifdef HAVE_FUSE
45#include <fuse.h>
46#include <fuse/fuse_opt.h>
47#include <cctype>
48#include <cstring>
49#include <fcntl.h>
50#include <dirent.h>
51#include <cerrno>
52#include <sys/time.h>
53#include <pthread.h>
54#include <pwd.h>
55#include <libgen.h>
56#include <syslog.h>
57#include <signal.h>
58#if defined(__linux__)
59#include <sys/prctl.h>
60#endif
61#include <sys/xattr.h>
62
63#include "XrdFfs/XrdFfsPosix.hh"
64#include "XrdFfs/XrdFfsMisc.hh"
66#include "XrdFfs/XrdFfsQueue.hh"
67//#include "XrdFfs/XrdFfsDent.hh"
70
71#define MAXROOTURLLEN 1024 // this is also defined in other files
72
73struct XROOTDFS {
74 char *rdr;
75 char *cns;
76 char *fastls;
77 char *daemon_user;
78 char *ssskeytab;
79 char *urlcachelife;
80 bool ofsfwd;
81 int nworkers;
82 int maxfd;
83};
84
85int cwdfd; // File descript of the initial working dir
86
87struct XROOTDFS xrootdfs;
88static struct fuse_opt xrootdfs_opts[14];
89
90enum { OPT_KEY_HELP, OPT_KEY_SECSSS, };
91
92bool usingEC = false;
93
94static void* xrootdfs_init(struct fuse_conn_info *conn)
95{
96 struct passwd pw, *pwp;
97 char *pwbuf;
98 size_t pwbuflen;
99
100 struct rlimit rl;
101 rl.rlim_cur = RLIM_INFINITY;
102 rl.rlim_max = RLIM_INFINITY;
103 setrlimit(RLIMIT_CORE, &rl); // attemp to enable core dump
104
105 pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
106 pwbuf = (char*)malloc(pwbuflen + 1);
107
108 if (xrootdfs.daemon_user != NULL)
109 {
110 int i, len;
111 len = strlen(xrootdfs.daemon_user);
112 for (i=0; i<len; i++) // daemon_user can be both string name or uid
113 {
114 if (isdigit(xrootdfs.daemon_user[i]) == 0)
115 {
116 getpwnam_r(xrootdfs.daemon_user, &pw, pwbuf, pwbuflen, &pwp);
117 break;
118 }
119 }
120 if (i == len) getpwuid_r(atoi(xrootdfs.daemon_user), &pw, pwbuf, pwbuflen, &pwp);
121 if( setgid((gid_t)pw.pw_gid) != 0 )
122 syslog( LOG_ERR, "ERROR: Unable to set gid to %d", pw.pw_gid );
123 if( setuid((uid_t)pw.pw_uid) != 0 )
124 syslog( LOG_ERR, "ERROR: Unable to set uid to %d", pw.pw_uid );
125#if defined(__linux__)
126 prctl(PR_SET_DUMPABLE, 1); // enable core dump after setuid/setgid
127#endif
128 }
129 free(pwbuf);
130
131/* put Xrootd related initialization calls here, after fuse daemonize itself. */
132 XrdPosixXrootd *abc = new XrdPosixXrootd(-xrootdfs.maxfd);
133 XrdFfsMisc_xrd_init(xrootdfs.rdr,xrootdfs.urlcachelife,0);
134 XrdFfsWcache_init(abc->fdOrigin(), xrootdfs.maxfd);
135
136 char *next, *savptr;
137 next = strtok_r(strdup(xrootdfs.rdr), "//", &savptr);
138 next = strtok_r(NULL, "//", &savptr);
139 char exportpath[1024];
140 while ((next = strtok_r(NULL, "//", &savptr)) != NULL)
141 {
142 strcat(exportpath, "/");
143 strcat(exportpath, next);
144 }
145 setenv("XRDEXPORTS", exportpath, 1);
146/*
147 From FAQ:
148 Miscellaneous threads should be started from the init() method.
149 Threads started before fuse_main() will exit when the process goes
150 into the background.
151*/
152
153#ifndef NOUSE_QUEUE
154 XrdFfsQueue_create_workers(xrootdfs.nworkers);
155
156 syslog(LOG_INFO, "INFO: Starting %d workers", XrdFfsQueue_count_workers());
157#else
158 syslog(LOG_INFO, "INFO: Not compiled to use task queue");
159#endif
160
161 if (fchdir(cwdfd)) {};
162 close(cwdfd);
163
164 return NULL;
165}
166
167static int xrootdfs_getattr(const char *path, struct stat *stbuf)
168{
169// int res, fd;
170 int res;
171 char rootpath[MAXROOTURLLEN];
172// uid_t user_uid, uid;
173// gid_t user_gid, gid;
174
175// user_uid = fuse_get_context()->uid;
176// uid = getuid();
177
178// user_gid = fuse_get_context()->gid;
179// gid = getgid();
180
181 XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid, 0);
182
183 rootpath[0]='\0';
184/*
185 if (xrootdfs.cns != NULL && xrootdfs.fastls != NULL)
186 strcat(rootpath,xrootdfs.cns);
187 else
188 strcat(rootpath,xrootdfs.rdr);
189 strcat(rootpath,path);
190
191// setegid(fuse_get_context()->gid);
192// seteuid(fuse_get_context()->uid);
193
194 res = XrdFfsPosix_stat(rootpath, stbuf);
195*/
196
197 if (xrootdfs.cns != NULL && xrootdfs.fastls != NULL)
198 {
199 strncat(rootpath,xrootdfs.cns, MAXROOTURLLEN - strlen(rootpath) -1);
200 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
201 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
202 res = XrdFfsPosix_stat(rootpath, stbuf);
203 }
204 else
205 res = XrdFfsPosix_statall(xrootdfs.rdr, path, stbuf, fuse_get_context()->uid);
206
207// seteuid(getuid());
208// setegid(getgid());
209
210// stbuf->st_uid = user_uid;
211// stbuf->st_gid = user_gid;
212
213 if (res == 0)
214 {
215 if (S_ISREG(stbuf->st_mode))
216 {
217/*
218 By adding the following 'if' block, 'xrootdfs.fastls = RDR' will force XrootdFS to check
219 with redirector for file status info (not directory).
220
221 Some applicatios such as SRM may do extensive file or directory existence checking.
222 These applications can't tolerant slow responding on file or directory info (if
223 don't exist). They also expect correct file size. For this type of application, we
224 can set 'xrootdfs.fastls = RDR'.
225
226 Allowing multi-thread may solve this problem. However, XrootdFS crashs under some
227 situation, and we have to add -s (single thread) option when runing XrootdFS.
228 */
229 if (xrootdfs.cns != NULL && xrootdfs.fastls != NULL && strcmp(xrootdfs.fastls,"RDR") == 0)
230 {
231 rootpath[0]='\0';
232 strncat(rootpath,xrootdfs.rdr, MAXROOTURLLEN - strlen(rootpath) -1);
233 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
234 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
235 XrdFfsPosix_stat(rootpath, stbuf);
236// stbuf->st_uid = user_uid;
237// stbuf->st_gid = user_gid;
238 }
239 stbuf->st_mode |= 0666;
240 stbuf->st_mode &= 0772777; /* remove sticky bit and suid bit */
241 stbuf->st_blksize = 32768; /* unfortunately, it is ignored, see include/fuse.h */
242 return 0;
243 }
244 else if (S_ISDIR(stbuf->st_mode))
245 {
246 stbuf->st_mode |= 0777;
247 stbuf->st_mode &= 0772777; /* remove sticky bit and suid bit */
248 return 0;
249 }
250 else
251 return -EIO;
252 }
253 else if (res == -1 && xrootdfs.cns != NULL && xrootdfs.fastls != NULL)
254 return -errno;
255 else if (xrootdfs.cns == NULL)
256 return -errno;
257 else
258 {
259 rootpath[0]='\0';
260 strncat(rootpath,xrootdfs.cns, MAXROOTURLLEN - strlen(rootpath) -1);
261 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
262 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
263 res = XrdFfsPosix_stat(rootpath, stbuf);
264// stbuf->st_uid = user_uid;
265// stbuf->st_gid = user_gid;
266 if (res == -1)
267 return -errno;
268 else
269 {
270 if (S_ISREG(stbuf->st_mode))
271 return -ENOENT;
272 else if (S_ISDIR(stbuf->st_mode))
273 {
274 stbuf->st_mode |= 0777;
275 stbuf->st_mode &= 0772777;
276 return 0;
277 }
278 else
279 return -EIO;
280 }
281 }
282}
283
284static int xrootdfs_access(const char *path, int mask)
285{
286/*
287 int res;
288 res = access(path, mask);
289 if (res == -1)
290 return -errno;
291*/
292 return 0;
293}
294
295static int xrootdfs_readlink(const char *path, char *buf, size_t size)
296{
297/*
298 int res;
299
300 res = readlink(path, buf, size - 1);
301 if (res == -1)
302 return -errno;
303
304 buf[res] = '\0';
305*/
306 return 0;
307}
308
309static int xrootdfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
310 off_t offset, struct fuse_file_info *fi)
311{
312 DIR *dp;
313 struct dirent *de;
314
315 (void) offset;
316 (void) fi;
317
318 char rootpath[MAXROOTURLLEN];
319
320 XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid, 0);
321/*
322 if CNS server is not defined, there is no way to list files in a directory
323 because we don't know the data nodes
324*/
325 if (xrootdfs.cns != NULL)
326 {
327 rootpath[0]='\0';
328 strncat(rootpath,xrootdfs.cns, MAXROOTURLLEN - strlen(rootpath) -1);
329 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
330
331 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
332 dp = XrdFfsPosix_opendir(rootpath);
333 if (dp == NULL)
334 return -errno;
335
336 while ((de = XrdFfsPosix_readdir(dp)) != NULL)
337 {
338/*
339 struct stat st;
340 memset(&st, 0, sizeof(st));
341 st.st_ino = de->d_ino;
342 st.st_mode = de->d_type << 12;
343 */
344 if (filler(buf, de->d_name, NULL, 0))
345 break;
346 }
348 return 0;
349 }
350 else /* if there is no CNS, try collect dirents from all known data servers. */
351 {
352 int i, n;
353 char **dnarray = NULL;
354
355 n = XrdFfsPosix_readdirall(xrootdfs.rdr, path, &dnarray, fuse_get_context()->uid);
356
357 for (i = 0; i < n; i++)
358 if (filler(buf, dnarray[i], NULL, 0)) break;
359
360/*
361 this loop should not be merged with the above loop because all members of
362 dnarray[] should be freed, or there will be memory leak.
363 */
364 for (i = 0; i < n; i++)
365 free(dnarray[i]);
366 free(dnarray);
367
368 return -errno;
369 }
370}
371
372static int xrootdfs_do_create(const char *path, const char *url, int oflags, bool use_link_id, int *fd)
373/* Actually implement creating a file as generally as possible.
374 *
375 * path: file path
376 * url: xrootd root url to use
377 * oflags: posix oflags
378 * use_link_id: register multiple secsss user numbers for editurl
379 * fd: return file descriptor here
380 *
381 * returns: 0 on success, -errno on error.
382 */
383{
384 int res, link_id;
385 int *p_link_id = NULL;
386 char rootpath[MAXROOTURLLEN] = "";
387
388 if (use_link_id)
389 p_link_id = &link_id;
390
391 XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid, p_link_id);
392 strncat(rootpath, url, MAXROOTURLLEN - strlen(rootpath) - 1);
393 strncat(rootpath, path, MAXROOTURLLEN - strlen(rootpath) - 1);
394
395 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, p_link_id);
396 res = XrdFfsPosix_open(rootpath, oflags, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
397 if (res == -1)
398 return -errno;
399 if (fd != NULL)
400 *fd = res;
401 return 0;
402}
403
404static int xrootdfs_mknod(const char *path, mode_t mode, dev_t rdev)
405/* Implement MKNOD for FUSE, which is supposed to be used for special files.
406 * Can be used when CREATE is not available.
407 * This implementation only supports normal files.
408 * Just create the file, then close it. Also create cns file.
409 *
410 * path: file path
411 * mode: file attribute bitmask
412 * rdev: device number
413 *
414 * returns: 0 on success, -errno on error.
415 */
416{
417 int res, fd;
418 if (!S_ISREG(mode))
419 return -EPERM;
420/*
421 Around May 2008, the O_EXCL was added to the _open(). No reason was given. It is removed again
422 due to the following reason (the situation that redirector thinks a file exist while it doesn't):
423
424 1. FUSE will use _getattr to determine file status. _mknod() will be called only if _getattr()
425 determined that the file does not exist.
426 2. In the case that rootd security is enabled, if a user create a file at an unauthorized path
427 (and fail), redirector thinks the files exist but it actually does't exist (enabling security
428 on redirector doesn't seems to help. An authorized user won't be able to create the same file
429 until the redirector forgets about it.
430
431 res = XrdFfsPosix_open(rootpath, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
432*/
433 res = xrootdfs_do_create(path, xrootdfs.rdr, O_CREAT | O_WRONLY, false, &fd);
434 if (res < 0) return res;
436 if (xrootdfs.cns != NULL)
437 {
438 xrootdfs_do_create(path, xrootdfs.cns, O_CREAT | O_EXCL, false, &fd);
440 }
441 return res;
442}
443
444static int xrootdfs_create(const char *path, mode_t mode, struct fuse_file_info *fi)
445/* Implement CREATE for FUSE, to create and open a normal file.
446 * Create a file and return its fd. Also create cns file.
447 *
448 * path: file path
449 * mode: file attribute bitmask
450 * fi: file info, return file descriptor in here
451 *
452 * returns: 0 on success, -errno on error.
453 */
454{
455 int res, fd;
456 if (!S_ISREG(mode))
457 return -EPERM;
458 if (usingEC)
459 res = xrootdfs_do_create(path, xrootdfs.rdr, O_CREAT | O_WRONLY | O_EXCL, true, &fd);
460 else
461 res = xrootdfs_do_create(path, xrootdfs.rdr, O_CREAT | O_WRONLY, true, &fd);
462 if (res < 0) return res;
463 fi->fh = fd;
464 XrdFfsWcache_create(fd, fi->flags); // Unlike mknod and like open, prepare wcache.
465 if (xrootdfs.cns != NULL)
466 {
467 xrootdfs_do_create(path, xrootdfs.cns, O_CREAT | O_EXCL, false, &fd);
469 }
470 return res;
471}
472
473static int xrootdfs_mkdir(const char *path, mode_t mode)
474{
475 int res;
476 char rootpath[1024];
477/*
478 Posix Mkdir() fails on the current version of Xrootd, 20071101-0808p1
479 So we avoid doing that. This is fixed in CVS head version.
480*/
481/*
482 if CNS is defined, only mkdir() on CNS. Otherwise, mkdir() on redirector
483 */
484 rootpath[0]='\0';
485
486 if (xrootdfs.cns != NULL)
487 strncat(rootpath,xrootdfs.cns, MAXROOTURLLEN - strlen(rootpath) -1);
488 else
489 strncat(rootpath,xrootdfs.rdr, MAXROOTURLLEN - strlen(rootpath) -1);
490
491 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
492
493 XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid, 0);
494 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
495
496 res = XrdFfsPosix_mkdir(rootpath, mode);
497 if (res == 0) return 0;
498/*
499 now we are here either because there is either a race to create the directory, or the redirector
500 incorrectly cached a non-existing one (see _mknod() for more explaitation)
501
502 the following code try to clear the redirector cache. In the case of two racing mkdir(), it doesn't
503 care which one will success/fail.
504*/
506
507 res = XrdFfsPosix_mkdir(rootpath, mode);
508 return ((res == -1)? -errno : 0);
509}
510
511static int xrootdfs_unlink(const char *path)
512{
513 int res;
514 char rootpath[MAXROOTURLLEN];
515
516 rootpath[0]='\0';
517 strncat(rootpath,xrootdfs.rdr, MAXROOTURLLEN - strlen(rootpath) -1);
518 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
519
520 XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid, 0);
521 if (xrootdfs.ofsfwd == true)
522 {
523 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
524 res = XrdFfsPosix_unlink(rootpath);
525 }
526 else
527 res = XrdFfsPosix_unlinkall(xrootdfs.rdr, path, fuse_get_context()->uid);
528
529 if (res == -1)
530 return -errno;
531
532 if (xrootdfs.cns != NULL && xrootdfs.ofsfwd == false)
533 {
534 rootpath[0]='\0';
535 strncat(rootpath,xrootdfs.cns, MAXROOTURLLEN - strlen(rootpath) -1);
536 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
537
538 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
539 res = XrdFfsPosix_unlink(rootpath);
540 if (res == -1)
541 return -errno;
542 }
543 return 0;
544}
545
546static int xrootdfs_rmdir(const char *path)
547{
548 int res;
549// struct stat stbuf;
550 char rootpath[MAXROOTURLLEN];
551
552 rootpath[0]='\0';
553 strncat(rootpath,xrootdfs.rdr, MAXROOTURLLEN - strlen(rootpath) -1);
554 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
555
556 XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid, 0);
557 if (xrootdfs.ofsfwd == true)
558 {
559 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
560 res = XrdFfsPosix_rmdir(rootpath);
561 }
562 else
563 res = XrdFfsPosix_rmdirall(xrootdfs.rdr, path, fuse_get_context()->uid);
564
565 if (res == -1)
566 return -errno;
567
568 if (xrootdfs.cns != NULL && xrootdfs.ofsfwd == false)
569 {
570 rootpath[0]='\0';
571 strncat(rootpath,xrootdfs.cns, MAXROOTURLLEN - strlen(rootpath) -1);
572 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
573
574 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
575 res = XrdFfsPosix_rmdir(rootpath);
576 if (res == -1)
577 return -errno;
578 }
579 /*
580 clear cache in redirector. otherwise, an immediate mkdir(path) will fail
581 if (xrootdfs.ofsfwd == false)
582 {
583 rootpath[0]='\0';
584 strcat(rootpath,xrootdfs.rdr);
585 strcat(rootpath,path);
586
587 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid);
588 XrdFfsPosix_clear_from_xrootdfs.rdr_cache(rootpath); // no needed. _mkdir() is doing this.
589 }
590 */
591 return 0;
592}
593
594static int xrootdfs_symlink(const char *from, const char *to)
595{
596/*
597 int res;
598
599 res = symlink(from, to);
600 if (res == -1)
601 return -errno;
602*/
603 return -EIO;
604}
605
606static int xrootdfs_rename(const char *from, const char *to)
607{
608 int res;
609 char from_path[MAXROOTURLLEN], to_path[MAXROOTURLLEN];
610 struct stat stbuf;
611
612 from_path[0]='\0';
613 strncat(from_path, xrootdfs.rdr, MAXROOTURLLEN - strlen(from_path) -1);
614 strncat(from_path, from, MAXROOTURLLEN - strlen(from_path) -1);
615
616 to_path[0]='\0';
617 strncat(to_path, xrootdfs.rdr, MAXROOTURLLEN - strlen(to_path) -1);
618 strncat(to_path, to, MAXROOTURLLEN - strlen(to_path) -1);
619/*
620 1. do actual renaming on data servers if if is a file in order to speed up
621 renaming
622 2. return -EXDEV for renaming of directory so that files in the directory
623 are renamed individually (in order for the .pfn pointing back correctly).
624 */
625
626 XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid, 0);
627 XrdFfsMisc_xrd_secsss_editurl(from_path, fuse_get_context()->uid, 0);
628
629 XrdFfsPosix_stat(from_path, &stbuf);
630 if (S_ISDIR(stbuf.st_mode)) /* && xrootdfs.cns == NULL && xrootdfs.ofsfwd == false) */
631 return -EXDEV;
632
633 if (xrootdfs.ofsfwd == true)
634 res = XrdFfsPosix_rename(from_path, to_path);
635 else
636 res = XrdFfsPosix_renameall(xrootdfs.rdr, from, to, fuse_get_context()->uid);
637
638 if (res == -1)
639 return -errno;
640
641/* data servers may not notify redirector about the renaming. So we notify redirector */
643
644 if (xrootdfs.cns != NULL && xrootdfs.ofsfwd == false)
645 {
646 from_path[0]='\0';
647 strncat(from_path, xrootdfs.cns, MAXROOTURLLEN - strlen(from_path) -1);
648 strncat(from_path, from, MAXROOTURLLEN - strlen(from_path) -1);
649
650 to_path[0]='\0';
651 strncat(to_path, xrootdfs.cns, MAXROOTURLLEN - strlen(to_path) -1);
652 strncat(to_path, to, MAXROOTURLLEN - strlen(to_path) -1);
653
654 res = XrdFfsPosix_rename(from_path, to_path);
655 if (res == -1)
656 return -errno;
657 }
658 return 0;
659
660/* return -EXDEV */
661}
662
663static int xrootdfs_link(const char *from, const char *to)
664{
665/*
666 int res;
667
668 res = link(from, to);
669 if (res == -1)
670 return -errno;
671*/
672 return -EMLINK;
673}
674
675static int xrootdfs_chmod(const char *path, mode_t mode)
676{
677/*
678 int res;
679
680 res = chmod(path, mode);
681 if (res == -1)
682 return -errno;
683*/
684 return 0;
685}
686
687static int xrootdfs_chown(const char *path, uid_t uid, gid_t gid)
688{
689/*
690 int res;
691
692 res = lchown(path, uid, gid);
693 if (res == -1)
694 return -errno;
695*/
696 return 0;
697}
698
699/* _ftruncate() will only work with kernel >= 2.6.15. See FUSE ChangeLog */
700static int xrootdfs_ftruncate(const char *path, off_t size,
701 struct fuse_file_info *fi)
702{
703 int fd, res;
704// char rootpath[1024];
705
706 fd = (int) fi->fh;
708 res = XrdFfsPosix_ftruncate(fd, size);
709 if (res == -1)
710 return -errno;
711
712/*
713 There is no need to update the size of the CNS shadow file now. That
714 should be updated when the file is closed
715
716 if (xrootdfs.cns != NULL)
717 {
718 rootpath[0]='\0';
719 strcat(rootpath,xrootdfs.cns);
720 strcat(rootpath,path);
721
722 res = XrdFfsPosix_truncate(rootpath, size);
723 if (res == -1)
724 return -errno;
725 }
726*/
727 return 0;
728}
729
730static int xrootdfs_truncate(const char *path, off_t size)
731{
732 int res;
733 char rootpath[MAXROOTURLLEN];
734
735 rootpath[0]='\0';
736 strncat(rootpath,xrootdfs.rdr, MAXROOTURLLEN - strlen(rootpath) -1);
737 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
738
739 XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid, 0);
740 if (xrootdfs.ofsfwd == true)
741 {
742 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
743 res = XrdFfsPosix_truncate(rootpath, size);
744 }
745 else
746 res = XrdFfsPosix_truncateall(xrootdfs.rdr, path, size, fuse_get_context()->uid);
747
748 if (res == -1)
749 return -errno;
750
751 if (xrootdfs.cns != NULL && xrootdfs.ofsfwd == false)
752 {
753 rootpath[0]='\0';
754 strncat(rootpath,xrootdfs.cns, MAXROOTURLLEN - strlen(rootpath) -1);
755 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
756
757 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
758 res = XrdFfsPosix_truncate(rootpath, size);
759 if (res == -1)
760 return -errno;
761 }
762 return 0;
763}
764
765static int xrootdfs_utimens(const char *path, const struct timespec ts[2])
766{
767/*
768 int res;
769 struct timeval tv[2];
770
771 tv[0].tv_sec = ts[0].tv_sec;
772 tv[0].tv_usec = ts[0].tv_nsec / 1000;
773 tv[1].tv_sec = ts[1].tv_sec;
774 tv[1].tv_usec = ts[1].tv_nsec / 1000;
775
776 res = utimes(path, tv);
777 if (res == -1)
778 return -errno;
779*/
780 return 0;
781}
782
783static int xrootdfs_open(const char *path, struct fuse_file_info *fi)
784/*
785 * path: path to file
786 * fi: file info, return file descriptor in fi->fh
787 *
788 * returns 0 on success and -errno on error
789 */
790{
791 int fd, lid = 1;
792 char rootpath[MAXROOTURLLEN]="";
793 strncat(rootpath,xrootdfs.rdr, MAXROOTURLLEN - strlen(rootpath) -1);
794 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
795
796 XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid, &lid);
797 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, &lid);
798 fd = XrdFfsPosix_open(rootpath, fi->flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
799 if (fd == -1)
800 return -errno;
801
802 fi->fh = fd;
803 // be careful, 0 means error for this function
804 if (XrdFfsWcache_create(fi->fh, fi->flags))
805 return 0;
806 else
807 return -errno;
808}
809
810static int xrootdfs_read(const char *path, char *buf, size_t size, off_t offset,
811 struct fuse_file_info *fi)
812{
813 int fd;
814 int res;
815
816 fd = (int) fi->fh;
817 if (fi->flags & O_RDWR) XrdFfsWcache_flush(fd);
818
819 if (usingEC)
820 {
821 struct stat stbuf;
822 XrdPosixXrootd::Fstat(fd, &stbuf); // Silly but does not seem to hurt performance
823 off_t fsize = stbuf.st_size;
824
826 if ( offset >= fsize )
827 return 0;
828
829 size = (size_t)(fsize - offset) > size ? size : fsize - offset;
830 // Restrict the use of read cache to O_DIRECT use case
831 // See comment in XRdFfsWcache_pread()
832 if ( ! (fi->flags & O_RDWR) && (fi->flags & O_DIRECT) )
833 res = XrdFfsWcache_pread(fd, buf, size, offset);
834 else
835 res = XrdFfsPosix_pread(fd, buf, size, offset);
836 }
837 else
838 res = XrdFfsPosix_pread(fd, buf, size, offset);
839
840 if (res == -1)
841 res = -errno;
842
843 return res;
844}
845
846static int xrootdfs_write(const char *path, const char *buf, size_t size,
847 off_t offset, struct fuse_file_info *fi)
848{
849 int fd;
850 int res;
851
852/*
853 File already existed. FUSE uses xrootdfs_open() and xrootdfs_truncate() to open and
854 truncate a file before calling xrootdfs_write()
855*/
856 fd = (int) fi->fh;
857// res = XrdFfsPosix_pwrite(fd, buf, size, offset);
858 res = XrdFfsWcache_pwrite(fd, (char *)buf, size, offset);
859 if (res == -1)
860 res = -errno;
861
862 return res;
863}
864
865static int xrootdfs_statfs(const char *path, struct statvfs *stbuf)
866{
867 int res;
868// char rootpath[1024], xattr[256];
869// char *token, *key, *value;
870// char *lasts_xattr[256], *lasts_tokens[128];
871// long long size;
872
873// XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid);
874#ifndef __APPLE__
875 stbuf->f_bsize = 1024;
876#else
877 stbuf->f_bsize = 1024 * 128; // work around 32 bit fsblkcnt_t in struct statvfs on Mac OSX
878 stbuf->f_frsize = stbuf->f_bsize; // seems there are other limitations, 1024*128 is a max we set
879#endif
880
881// res = XrdFfsPosix_statvfsall(xrootdfs.rdr, path, stbuf, fuse_get_context()->uid);
882 res = XrdFfsFsinfo_cache_search(&XrdFfsPosix_statvfsall, xrootdfs.rdr, path, stbuf, fuse_get_context()->uid);
883
884/*
885 stbuf->f_blocks /= stbuf->f_bsize;
886 stbuf->f_bavail /= stbuf->f_bsize;
887 stbuf->f_bfree /= stbuf->f_bsize;
888*/
889 return res;
890/*
891 stbuf->f_bsize = 16384;
892 stbuf->f_blocks = 1048576;
893 stbuf->f_bfree = stbuf->f_blocks;
894 stbuf->f_bavail = stbuf->f_blocks;
895
896 if (xrootdfs.cns == NULL) return 0;
897
898 rootpath[0]='\0';
899 strcat(rootpath,xrootdfs.cns);
900 strcat(rootpath,path);
901
902 res = XrdFfsPosix_getxattr(rootpath, "xroot.space", xattr, 256);
903 if (res == -1)
904 return 0;
905 else
906 {
907 token = strtok_r(xattr, "&", lasts_xattr);
908 while (token != NULL)
909 {
910 token = strtok_r(NULL, "&", lasts_xattr);
911 if (token == NULL) break;
912 key = strtok_r(token, "=", lasts_tokens);
913 value = strtok_r(NULL, "=", lasts_tokens);
914 if (!strcmp(key,"oss.used"))
915 {
916 sscanf((const char*)value, "%lld", &size);
917 stbuf->f_bavail = size / stbuf->f_bsize;
918 }
919 else if (!strcmp(key,"oss.quota"))
920 {
921 sscanf((const char*)value, "%lld", &size);
922 stbuf->f_blocks = size / stbuf->f_bsize;
923 }
924 }
925 stbuf->f_bavail = stbuf->f_blocks - stbuf->f_bavail;
926 stbuf->f_bfree = stbuf->f_bavail;
927 }
928 return 0;
929 */
930}
931
932static int xrootdfs_release(const char *path, struct fuse_file_info *fi)
933{
934 /* Just a stub. This method is optional and can safely be left
935 unimplemented */
936
937 int fd, oflag;
938 struct stat xrdfile, cnsfile;
939 char rootpath[MAXROOTURLLEN];
940
941 fd = (int) fi->fh;
945 fi->fh = 0;
946/*
947 Return at here because the current version of Cluster Name Space daemon
948 doesn't implement the 'truncate' functon we originally planned.
949
950 return 0;
951*/
952 if (xrootdfs.cns == NULL || (fi->flags & 0100001) == (0100000 | O_RDONLY))
953 return 0;
954
955 int res;
956 char xattr[256], xrdtoken[256];
957 char *token, *key, *value;
958 char *lasts_xattr[256], *lasts_tokens[128];
959
960 rootpath[0]='\0';
961 strncat(rootpath,xrootdfs.rdr, MAXROOTURLLEN - strlen(rootpath) -1);
962 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
963/*
964 * Get xrootd token info from data nodes. And set the token info on CNS
965 */
966 XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid, 0);
967 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
968 xrdtoken[0]='\0';
969 res = XrdFfsPosix_getxattr(rootpath, "xroot.xattr", xattr, 256);
970 if (res != -1)
971 {
972 token = strtok_r(xattr, "&", lasts_xattr);
973 while (token != NULL)
974 {
975 key = strtok_r(token, "=", lasts_tokens);
976 value = strtok_r(NULL, "=", lasts_tokens);
977 if (!strcmp(key,"oss.cgroup"))
978 strcpy(xrdtoken, value);
979
980 if (!strcmp(key,"oss.used"))
981 {long long llVal;
982 sscanf((const char*)value, "%lld", &llVal);
983 xrdfile.st_size = llVal;
984 }
985 token = strtok_r(NULL, "&", lasts_xattr);
986 }
987 }
988 else
989 {
990 XrdFfsPosix_stat(rootpath,&xrdfile);
991 }
992
993 rootpath[0]='\0';
994 strncat(rootpath,xrootdfs.cns, MAXROOTURLLEN - strlen(rootpath) -1);
995 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
996
997 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
998 if (xrdtoken[0] != '\0' && strstr(path,"?oss.cgroup=") == NULL)
999 {
1000 strncat(rootpath,"?oss.cgroup=", MAXROOTURLLEN - strlen(rootpath) -1);
1001 strncat(rootpath,xrdtoken, MAXROOTURLLEN - strlen(rootpath) -1);
1002 }
1003
1004 if (XrdFfsPosix_stat(rootpath,&cnsfile) == -1)
1005 oflag = O_CREAT|O_WRONLY;
1006 else
1007 oflag = O_TRUNC|O_WRONLY;
1008
1009/*
1010 This creates a file on CNS with the right size. But it is actually an empty file.
1011 It doesn't use disk space, only inodes.
1012*/
1013 if (cnsfile.st_size != xrdfile.st_size)
1014 {
1015 fd = XrdFfsPosix_open(rootpath,oflag,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
1016 if (fd >= 0)
1017 {
1018 XrdFfsPosix_lseek(fd,(off_t)xrdfile.st_size-1,SEEK_SET);
1019 XrdFfsPosix_write(fd,"",1);
1021 }
1022 }
1023
1024 return 0;
1025}
1026
1027static int xrootdfs_fsync(const char *path, int isdatasync,
1028 struct fuse_file_info *fi)
1029{
1030 int fd;
1031
1032 fd = (int) fi->fh;
1035 return 0;
1036}
1037
1038/* xattr operations are optional and can safely be left unimplemented */
1039static int xrootdfs_setxattr(const char *path, const char *name, const char *value,
1040 size_t size, int flags)
1041{
1042 if (fuse_get_context()->uid != 0 && fuse_get_context()->uid != getuid())
1043 return -EPERM;
1044
1045 if (!strcmp(name,"xrootdfs.fs.dataserverlist"))
1046 {
1047 XrdFfsMisc_refresh_url_cache(xrootdfs.rdr);
1049 }
1050 else if (!strcmp(name,"xrootdfs.fs.nworkers"))
1051 {
1052 int i, j;
1053 char *tmp_value;
1054 tmp_value=strdup(value);
1055 if (size > 0) tmp_value[size] = '\0';
1056
1058 j = atoi(tmp_value);
1059 free(tmp_value);
1060 if (j > i)
1062 if (j < i)
1063 XrdFfsQueue_remove_workers( i-j ); // XrdFfsQueue_remove_workers() will wait until workers are removed.
1065#ifndef NOUSE_QUEUE
1066 syslog(LOG_INFO, "INFO: Adjust the number of workers from %d to %d", i, j);
1067#endif
1068 }
1069 return 0;
1070}
1071
1072static int xrootdfs_getxattr(const char *path, const char *name, char *value,
1073 size_t size)
1074{
1075 int xattrlen;
1076 char rootpath[MAXROOTURLLEN]="";
1077 char rooturl[MAXROOTURLLEN]="";
1078
1079 if (!strcmp(name,"xroot.url"))
1080 {
1081 errno = 0;
1082 strncat(rootpath,xrootdfs.rdr, MAXROOTURLLEN - strlen(rootpath) -1);
1083 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
1084
1085// XrdFfsMisc_get_current_url(rootpath, rooturl);
1086 strcpy(rooturl, rootpath);
1087
1088 if (size == 0)
1089 return strlen(rooturl);
1090 else if (size > strlen(rooturl)) // check the size to make sure strcat(value, rooturl) is safe
1091 {
1092 size = strlen(rooturl);
1093 if (size != 0)
1094 {
1095 value[0] = '\0';
1096 strcat(value, rooturl);
1097 }
1098 return size;
1099 }
1100 else
1101 {
1102 errno = ERANGE;
1103 return -1;
1104 }
1105 }
1106 else if (!strcmp(name, "xrootdfs.fs.dataserverlist"))
1107 {
1108 char *hostlist;
1109
1110 hostlist = (char*) malloc(sizeof(char) * XrdFfs_MAX_NUM_NODES * 256);
1112
1113 if (size == 0)
1114 {
1115 xattrlen = strlen(hostlist);
1116 free(hostlist);
1117 return xattrlen;
1118 }
1119 else if (size > strlen(hostlist))
1120 {
1121 size = strlen(hostlist);
1122 if (size != 0)
1123 {
1124 value[0] = '\0';
1125 strcat(value, hostlist);
1126 }
1127 free(hostlist);
1128 return size;
1129 }
1130 else
1131 {
1132 errno = ERANGE;
1133 free(hostlist);
1134 return -1;
1135 }
1136 }
1137 else if (!strcmp(name, "xrootdfs.fs.nworkers"))
1138 {
1139 char nworkers[7];
1140 int n;
1142 sprintf(nworkers, "%d", n);
1143
1144 if (size == 0)
1145 return strlen(nworkers);
1146 else if (size > strlen(nworkers))
1147 {
1148 size = strlen(nworkers);
1149 if (size != 0)
1150 {
1151 value[0] = '\0';
1152 strcat(value, nworkers);
1153 }
1154 return size;
1155 }
1156 else
1157 {
1158 errno = ERANGE;
1159 return -1;
1160 }
1161 }
1162 else if (!strcmp(name, "xrootdfs.file.permission"))
1163 {
1164 char xattr[256]="";
1165 strncat(rootpath,xrootdfs.rdr, MAXROOTURLLEN - strlen(rootpath) -1);
1166 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
1167
1168 XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid, 0);
1169 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
1170
1171 xattrlen = XrdFfsPosix_getxattr(rootpath, "xroot.xattr.ofs.ap", xattr, 255);
1172 if (size == 0)
1173 return xattrlen;
1174 else if (size > (size_t)xattrlen)
1175 {
1176 strncpy(value, xattr, size);
1177 size = xattrlen;
1178 value[size] = '\0';
1179 return size;
1180 }
1181 else
1182 {
1183 errno = ERANGE;
1184 return -1;
1185 }
1186 }
1187
1188 if (xrootdfs.cns != NULL)
1189 strncat(rootpath,xrootdfs.cns, MAXROOTURLLEN - strlen(rootpath) -1);
1190 else
1191 strncat(rootpath,xrootdfs.rdr, MAXROOTURLLEN - strlen(rootpath) -1);
1192 strncat(rootpath,path, MAXROOTURLLEN - strlen(rootpath) -1);
1193
1194 XrdFfsMisc_xrd_secsss_register(fuse_get_context()->uid, fuse_get_context()->gid, 0);
1195 XrdFfsMisc_xrd_secsss_editurl(rootpath, fuse_get_context()->uid, 0);
1196 xattrlen = XrdFfsPosix_getxattr(rootpath, name, value, size);
1197 if (xattrlen == -1)
1198 return -errno;
1199 else
1200 return xattrlen;
1201}
1202
1203static int xrootdfs_listxattr(const char *path, char *list, size_t size)
1204{
1205/*
1206 int res = llistxattr(path, list, size);
1207 if (res == -1)
1208 return -errno;
1209 return res;
1210*/
1211 return 0;
1212}
1213
1214static int xrootdfs_removexattr(const char *path, const char *name)
1215{
1216/*
1217 int res = lremovexattr(path, name);
1218 if (res == -1)
1219 return -errno;
1220*/
1221 return 0;
1222}
1223
1224/*
1225 * We need this as casting function pointer to a function pointer
1226 * of a different type and then calling it results in undefined
1227 * behavior (Annex J.2).
1228 *
1229 * GCC 8 available on Fedora 28 is very picky about those things.
1230 * On the other hand unfortunatelly we cannot use a lambda expression
1231 * as it is not supported on GCC 4.4 which is shipped by default on
1232 * EPEL 6.
1233 *
1234 */
1235void* XrdFfsMisc_logging_url_cache_pthread_create_cast( void *arg )
1236{
1237 XrdFfsMisc_logging_url_cache( reinterpret_cast<char*>( arg ) );
1238 return 0;
1239}
1240
1241void xrootdfs_sigusr1_handler(int sig)
1242{
1243/* Do this in a new thread because XrdFfsMisc_refresh_url_cache() contents mutex. */
1244 pthread_t *thread;
1245 pthread_attr_t attr;
1246 size_t stacksize = 2*1024*1024;
1247
1248 pthread_attr_init(&attr);
1249 pthread_attr_setstacksize(&attr, stacksize);
1250 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1251
1252 thread = (pthread_t*) malloc(sizeof(pthread_t));
1253 pthread_create(thread, &attr, XrdFfsMisc_logging_url_cache_pthread_create_cast,
1254 xrootdfs.rdr);
1255 pthread_detach(*thread);
1256 free(thread);
1257
1258 pthread_attr_destroy(&attr);
1259}
1260
1261static struct fuse_operations xrootdfs_oper;
1262
1263static void xrootdfs_usage(const char *progname)
1264{
1265 fprintf(stderr,
1266"usage: %s mountpoint options\n"
1267"\n"
1268"XrootdFS options:\n"
1269" -h -help --help print help\n"
1270"\n"
1271"Default options:\n"
1272" fsname=xrootdfs,allow_other,max_write=131072,attr_timeout=10,entry_timeout=10,negative_timeout=5\n"
1273" In case of an Erasure Encoding storage, entry_timeout=0\n"
1274"\n"
1275"[Required]\n"
1276" -o rdr=redirector_url root URL of the Xrootd redirector\n"
1277"\n"
1278"[Optional]\n"
1279" -o cns=cns_server_url root URL of the CNS server\n"
1280" -o uid=username cause XrootdFS to switch effective uid to that of username if possible\n"
1281" -o sss[=keytab] use Xrootd seciruty module \"sss\", specifying a keytab file is optional\n"
1282" -o refreshdslist=NNNs/m/h/d refresh internal list of data servers in NNN sec/min/hour/day, default unit is second\n"
1283" Absents of this option will disable automatically refreshing\n"
1284" -o maxfd=N number of virtual file descriptors for posix requests, default 8192 (min 2048)\n"
1285" -o nworkers=N number of workers to handle parallel requests to data servers, default 4\n"
1286" -o fastls=RDR set to RDR when CNS is presented will cause stat() to go to redirector\n"
1287"\n", progname);
1288}
1289
1290static int xrootdfs_opt_proc(void* data, const char* arg, int key, struct fuse_args* outargs)
1291{
1292 (void) data;
1293 (void) outargs;
1294
1295// printf("hellow key %d arg %s\n", key, arg);
1296 switch (key) {
1297 case FUSE_OPT_KEY_OPT:
1298 return 1;
1299 case FUSE_OPT_KEY_NONOPT:
1300 return 1;
1301 case OPT_KEY_SECSSS:
1302 setenv("XROOTDFS_SECMOD", "sss", 1);
1303 return 0;
1304 case OPT_KEY_HELP:
1305 xrootdfs_usage(outargs->argv[0]);
1306 fuse_opt_add_arg(outargs, "-ho");
1307 fuse_main(outargs->argc, outargs->argv, &xrootdfs_oper, NULL);
1308 exit(1);
1309 default:
1310 return(-1);
1311 ;
1312 }
1313}
1314
1315int main(int argc, char *argv[])
1316{
1317 xrootdfs_oper.init = xrootdfs_init;
1318 xrootdfs_oper.getattr = xrootdfs_getattr;
1319 xrootdfs_oper.access = xrootdfs_access;
1320 xrootdfs_oper.readlink = xrootdfs_readlink;
1321 xrootdfs_oper.readdir = xrootdfs_readdir;
1322 xrootdfs_oper.mknod = xrootdfs_mknod;
1323 xrootdfs_oper.mkdir = xrootdfs_mkdir;
1324 xrootdfs_oper.create = xrootdfs_create;
1325 xrootdfs_oper.symlink = xrootdfs_symlink;
1326 xrootdfs_oper.unlink = xrootdfs_unlink;
1327 xrootdfs_oper.rmdir = xrootdfs_rmdir;
1328 xrootdfs_oper.rename = xrootdfs_rename;
1329 xrootdfs_oper.link = xrootdfs_link;
1330 xrootdfs_oper.chmod = xrootdfs_chmod;
1331 xrootdfs_oper.chown = xrootdfs_chown;
1332 xrootdfs_oper.ftruncate = xrootdfs_ftruncate;
1333 xrootdfs_oper.truncate = xrootdfs_truncate;
1334 xrootdfs_oper.utimens = xrootdfs_utimens;
1335 xrootdfs_oper.open = xrootdfs_open;
1336 xrootdfs_oper.read = xrootdfs_read;
1337 xrootdfs_oper.write = xrootdfs_write;
1338 xrootdfs_oper.statfs = xrootdfs_statfs;
1339 xrootdfs_oper.release = xrootdfs_release;
1340 xrootdfs_oper.fsync = xrootdfs_fsync;
1341 xrootdfs_oper.setxattr = xrootdfs_setxattr;
1342 xrootdfs_oper.getxattr = xrootdfs_getxattr;
1343 xrootdfs_oper.listxattr = xrootdfs_listxattr;
1344 xrootdfs_oper.removexattr = xrootdfs_removexattr;
1345
1346/* Define XrootdFS options */
1347 char **cmdline_opts;
1348
1349 if (getenv("XRDCL_EC")) usingEC = true;
1350
1351 cmdline_opts = (char **) malloc(sizeof(char*) * (argc -1 + 3));
1352 cmdline_opts[0] = argv[0];
1353 cmdline_opts[1] = strdup("-o");
1354 if (getenv("XROOTDFS_NO_ALLOW_OTHER") != NULL && ! strcmp(getenv("XROOTDFS_NO_ALLOW_OTHER"),"1") )
1355 {
1356 if (! usingEC)
1357 cmdline_opts[2] = strdup("fsname=xrootdfs,max_write=131072,attr_timeout=10,entry_timeout=10,negative_timeout=5");
1358 else
1359 cmdline_opts[2] = strdup("fsname=xrootdfs,max_write=131072,attr_timeout=10,entry_timeout=0,negative_timeout=5");
1360 }
1361 else
1362 {
1363 if (! usingEC)
1364 cmdline_opts[2] = strdup("fsname=xrootdfs,allow_other,max_write=131072,attr_timeout=10,entry_timeout=10,negative_timeout=5");
1365 else
1366 cmdline_opts[2] = strdup("fsname=xrootdfs,allow_other,max_write=131072,attr_timeout=10,entry_timeout=0,negative_timeout=5");
1367 }
1368
1369 for (int i = 1; i < argc; i++)
1370 cmdline_opts[i+2] = argv[i];
1371
1372 struct fuse_args args = FUSE_ARGS_INIT(argc -1 + 3, cmdline_opts);
1373
1374 xrootdfs_opts[0].templ = "-h";
1375 xrootdfs_opts[0].offset = -1U;
1376 xrootdfs_opts[0].value = OPT_KEY_HELP;
1377
1378 xrootdfs_opts[1].templ = "-help";
1379 xrootdfs_opts[1].offset = -1U;
1380 xrootdfs_opts[1].value = OPT_KEY_HELP;
1381
1382 xrootdfs_opts[2].templ = "--help";
1383 xrootdfs_opts[2].offset = -1U;
1384 xrootdfs_opts[2].value = OPT_KEY_HELP;
1385
1386 xrootdfs_opts[3].templ = "rdr=%s";
1387 xrootdfs_opts[3].offset = offsetof(struct XROOTDFS, rdr);
1388 xrootdfs_opts[3].value = 0;
1389
1390 xrootdfs_opts[4].templ = "cns=%s";
1391 xrootdfs_opts[4].offset = offsetof(struct XROOTDFS, cns);
1392 xrootdfs_opts[4].value = 0;
1393
1394 xrootdfs_opts[5].templ = "fastls=%s";
1395 xrootdfs_opts[5].offset = offsetof(struct XROOTDFS, fastls);
1396 xrootdfs_opts[5].value = 0;
1397
1398 xrootdfs_opts[6].templ = "uid=%s";
1399 xrootdfs_opts[6].offset = offsetof(struct XROOTDFS, daemon_user);
1400 xrootdfs_opts[6].value = 0;
1401
1402 xrootdfs_opts[7].templ = "ofsfwd=%s";
1403 xrootdfs_opts[7].offset = offsetof(struct XROOTDFS, ofsfwd);
1404 xrootdfs_opts[7].value = 0;
1405
1406/* using "sss" security module. the actually location of the key is determined
1407 by shell enviornment variable XrdSecsssKT (or default locations). */
1408
1409/* The location of the key is not specified in command line. */
1410 xrootdfs_opts[8].templ = "sss";
1411 xrootdfs_opts[8].offset = -1U;
1412 xrootdfs_opts[8].value = OPT_KEY_SECSSS;
1413
1414/* The location of the key is specified in command line. */
1415 xrootdfs_opts[9].templ = "sss=%s";
1416 xrootdfs_opts[9].offset = offsetof(struct XROOTDFS, ssskeytab);
1417 xrootdfs_opts[9].value = 0;
1418
1419/* life time of the data server list */
1420 xrootdfs_opts[10].templ = "refreshdslist=%s";
1421 xrootdfs_opts[10].offset = offsetof(struct XROOTDFS, urlcachelife);
1422 xrootdfs_opts[10].value = 0;
1423
1424/* number of workers to handle parallel requests to data servers */
1425 xrootdfs_opts[11].templ = "nworkers=%d";
1426 xrootdfs_opts[11].offset = offsetof(struct XROOTDFS, nworkers);
1427 xrootdfs_opts[11].value = 0;
1428
1429/* number of virtual file descriptors */
1430 xrootdfs_opts[12].templ = "maxfd=%d";
1431 xrootdfs_opts[12].offset = offsetof(struct XROOTDFS, maxfd);
1432 xrootdfs_opts[12].value = 0;
1433
1434 xrootdfs_opts[13].templ = NULL;
1435
1436/* initialize struct xrootdfs */
1437// memset(&xrootdfs, 0, sizeof(xrootdfs));
1438 xrootdfs.rdr = NULL;
1439 xrootdfs.cns = NULL;
1440 xrootdfs.fastls = NULL;
1441 xrootdfs.daemon_user = NULL;
1442 xrootdfs.ofsfwd = false;
1443 xrootdfs.ssskeytab = NULL;
1444 xrootdfs.urlcachelife = strdup("3650d"); /* 10 years */
1445 xrootdfs.nworkers = 4;
1446 xrootdfs.maxfd = 8192;
1447
1448/* Get options from environment variables first */
1449 xrootdfs.rdr = getenv("XROOTDFS_RDRURL");
1450 xrootdfs.cns = getenv("XROOTDFS_CNSURL");
1451 xrootdfs.fastls = getenv("XROOTDFS_FASTLS");
1452// If this is defined, XrootdFS will setuid/setgid to this user at xrootdfs_init().
1453 xrootdfs.daemon_user = getenv("XROOTDFS_USER");
1454 if (getenv("XROOTDFS_OFSFWD") != NULL && ! strcmp(getenv("XROOTDFS_OFSFWD"),"1")) xrootdfs.ofsfwd = true;
1455 if (getenv("XROOTDFS_NWORKERS") != NULL) sscanf(getenv("XROOTDFS_NWORKERS"), "%d", &xrootdfs.nworkers);
1456 if (getenv("XROOTDFS_MAXFD") != NULL) sscanf(getenv("XROOTDFS_MAXFD"), "%d", &xrootdfs.maxfd);
1457
1458/* Parse XrootdFS options, will overwrite those defined in environment variables */
1459 fuse_opt_parse(&args, &xrootdfs, xrootdfs_opts, xrootdfs_opt_proc);
1460
1461/* make sure xrootdfs.rdr is specified */
1462 if (xrootdfs.rdr == NULL)
1463 {
1464 argc = 2;
1465 argv[1] = strdup("-h");
1466 struct fuse_args xargs = FUSE_ARGS_INIT(argc, argv);
1467 fuse_opt_parse(&xargs, &xrootdfs, xrootdfs_opts, xrootdfs_opt_proc);
1468 }
1469
1470/* convert xroot://... to root://... */
1471 if (xrootdfs.rdr != NULL && xrootdfs.rdr[0] == 'x') xrootdfs.rdr += 1;
1472 if (xrootdfs.cns != NULL && xrootdfs.cns[0] == 'x') xrootdfs.cns += 1;
1473/*
1474 XROOTDFS_OFSFWD (ofs.fwd (and ofs.fwd 3way) on rm, rmdir, mv, truncate.
1475 if this is not defined, XrootdFS will go to CNS and each data server
1476 and do the work.
1477
1478 If CNS is not defined, we have to set ofsfwd to false, or we will not be able to
1479 get a return status of rm, rmdir, mv and truncate.
1480 */
1481 if (xrootdfs.cns == NULL) xrootdfs.ofsfwd = false;
1482
1483 if (xrootdfs.ssskeytab != NULL)
1484 {
1485 setenv("XROOTDFS_SECMOD", "sss", 1);
1486 setenv("XrdSecsssKT", xrootdfs.ssskeytab, 1);
1487 }
1488
1489 if (xrootdfs.maxfd < 2048) xrootdfs.maxfd = 2048;
1490
1491 signal(SIGUSR1,xrootdfs_sigusr1_handler);
1492
1493 cwdfd = open(".",O_RDONLY);
1494 umask(0);
1495
1496 return fuse_main(args.argc, args.argv, &xrootdfs_oper, NULL);
1497}
1498#else
1499
1500int main(int argc, char *argv[])
1501{
1502 printf("This platform does not have FUSE; xrootdfs cannot be started!");
1503 exit(13);
1504}
1505#endif
static std::string ts()
timestamp output for logging messages
Definition XrdCephOss.cc:53
#define O_DIRECT
Definition XrdCrc32c.cc:51
int XrdFfsFsinfo_cache_search(int(*func)(const char *, const char *, struct statvfs *, uid_t), const char *rdrurl, const char *path, struct statvfs *stbuf, uid_t user_uid)
void XrdFfsMisc_logging_url_cache(const char *url)
void XrdFfsMisc_xrd_init(const char *rdrurl, const char *urlcachelife, int startQueue)
int XrdFfsMisc_get_list_of_data_servers(char *list)
void XrdFfsMisc_xrd_secsss_register(uid_t user_uid, gid_t user_gid, int *id)
void XrdFfsMisc_xrd_secsss_editurl(char *url, uid_t user_uid, int *id)
#define MAXROOTURLLEN
Definition XrdFfsMisc.cc:62
void XrdFfsMisc_refresh_url_cache(const char *url)
#define XrdFfs_MAX_NUM_NODES
Definition XrdFfsMisc.hh:34
int XrdFfsPosix_ftruncate(int fildes, off_t offset)
int XrdFfsPosix_rmdirall(const char *rdrurl, const char *path, uid_t user_uid)
int XrdFfsPosix_rename(const char *oldpath, const char *newpath)
DIR * XrdFfsPosix_opendir(const char *path)
int XrdFfsPosix_open(const char *path, int oflags, mode_t mode)
int XrdFfsPosix_fsync(int fildes)
int XrdFfsPosix_unlink(const char *path)
struct dirent * XrdFfsPosix_readdir(DIR *dirp)
int XrdFfsPosix_renameall(const char *rdrurl, const char *from, const char *to, uid_t user_uid)
void XrdFfsPosix_clear_from_rdr_cache(const char *rdrurl)
int XrdFfsPosix_truncate(const char *path, off_t Size)
int XrdFfsPosix_truncateall(const char *rdrurl, const char *path, off_t size, uid_t user_uid)
int XrdFfsPosix_closedir(DIR *dirp)
int XrdFfsPosix_rmdir(const char *path)
off_t XrdFfsPosix_lseek(int fildes, off_t offset, int whence)
int XrdFfsPosix_close(int fildes)
ssize_t XrdFfsPosix_pread(int fildes, void *buf, size_t nbyte, off_t offset)
int XrdFfsPosix_statvfsall(const char *rdrurl, const char *path, struct statvfs *stbuf, uid_t user_uid)
int XrdFfsPosix_readdirall(const char *rdrurl, const char *path, char ***direntarray, uid_t user_uid)
int XrdFfsPosix_statall(const char *rdrurl, const char *path, struct stat *stbuf, uid_t user_uid)
int XrdFfsPosix_unlinkall(const char *rdrurl, const char *path, uid_t user_uid)
int XrdFfsPosix_stat(const char *path, struct stat *buf)
int XrdFfsPosix_mkdir(const char *path, mode_t mode)
long long XrdFfsPosix_getxattr(const char *path, const char *name, void *value, unsigned long long size)
ssize_t XrdFfsPosix_write(int fildes, const void *buf, size_t nbyte)
int XrdFfsQueue_remove_workers(int n)
int XrdFfsQueue_count_workers()
int XrdFfsQueue_create_workers(int n)
void XrdFfsWcache_init(int basefd, int maxfd)
void XrdFfsWcache_destroy(int fd)
ssize_t XrdFfsWcache_pwrite(int fd, char *buf, size_t len, off_t offset)
ssize_t XrdFfsWcache_pread(int fd, char *buf, size_t len, off_t offset)
ssize_t XrdFfsWcache_flush(int fd)
int XrdFfsWcache_create(int fd, int flags)
int main(int argc, char *argv[])
#define close(a)
Definition XrdPosix.hh:48
#define open
Definition XrdPosix.hh:76
#define statvfs(a, b)
Definition XrdPosix.hh:105
#define stat(a, b)
Definition XrdPosix.hh:101
POSIX interface to XRootD with some extensions, as noted.
static int Fstat(int fildes, struct stat *buf)
Fstat() conforms to POSIX.1-2001 fstat()