XRootD
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"
65 #include "XrdFfs/XrdFfsWcache.hh"
66 #include "XrdFfs/XrdFfsQueue.hh"
67 //#include "XrdFfs/XrdFfsDent.hh"
68 #include "XrdFfs/XrdFfsFsinfo.hh"
70 
71 #define MAXROOTURLLEN 1024 // this is also defined in other files
72 
73 struct 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 
85 int cwdfd; // File descript of the initial working dir
86 
87 struct XROOTDFS xrootdfs;
88 static struct fuse_opt xrootdfs_opts[14];
89 
90 enum { OPT_KEY_HELP, OPT_KEY_SECSSS, };
91 
92 bool usingEC = false;
93 
94 static 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 
167 static 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 
284 static 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 
295 static 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 
309 static 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 
372 static 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 
404 static 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;
435  XrdFfsPosix_close(fd);
436  if (xrootdfs.cns != NULL)
437  {
438  xrootdfs_do_create(path, xrootdfs.cns, O_CREAT | O_EXCL, false, &fd);
439  XrdFfsPosix_close(fd);
440  }
441  return res;
442 }
443 
444 static 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);
468  XrdFfsPosix_close(fd);
469  }
470  return res;
471 }
472 
473 static 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 
511 static 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 
546 static 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 
594 static 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 
606 static 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 
663 static 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 
675 static 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 
687 static 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 */
700 static 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;
707  XrdFfsWcache_flush(fd);
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 
730 static 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 
765 static 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 
783 static 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 
810 static 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 
846 static 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 
865 static 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 
932 static 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;
942  XrdFfsWcache_flush(fd);
944  XrdFfsPosix_close(fd);
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);
1020  XrdFfsPosix_close(fd);
1021  }
1022  }
1023 
1024  return 0;
1025 }
1026 
1027 static int xrootdfs_fsync(const char *path, int isdatasync,
1028  struct fuse_file_info *fi)
1029 {
1030  int fd;
1031 
1032  fd = (int) fi->fh;
1033  XrdFfsWcache_flush(fd);
1034  XrdFfsPosix_fsync(fd);
1035  return 0;
1036 }
1037 
1038 /* xattr operations are optional and can safely be left unimplemented */
1039 static 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 
1072 static 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 
1203 static 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 
1214 static 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  */
1235 void* XrdFfsMisc_logging_url_cache_pthread_create_cast( void *arg )
1236 {
1237  XrdFfsMisc_logging_url_cache( reinterpret_cast<char*>( arg ) );
1238  return 0;
1239 }
1240 
1241 void 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 
1261 static struct fuse_operations xrootdfs_oper;
1262 
1263 static 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 
1290 static 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 
1315 int 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 
1500 int main(int argc, char *argv[])
1501 {
1502  printf("This platform does not have FUSE; xrootdfs cannot be started!");
1503  exit(13);
1504 }
1505 #endif
#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)
Definition: XrdFfsFsinfo.cc:57
void XrdFfsMisc_logging_url_cache(const char *url)
Definition: XrdFfsMisc.cc:273
void XrdFfsMisc_xrd_init(const char *rdrurl, const char *urlcachelife, int startQueue)
Definition: XrdFfsMisc.cc:296
int XrdFfsMisc_get_list_of_data_servers(char *list)
Definition: XrdFfsMisc.cc:209
void XrdFfsMisc_xrd_secsss_register(uid_t user_uid, gid_t user_gid, int *id)
Definition: XrdFfsMisc.cc:380
void XrdFfsMisc_xrd_secsss_editurl(char *url, uid_t user_uid, int *id)
Definition: XrdFfsMisc.cc:424
#define MAXROOTURLLEN
Definition: XrdFfsMisc.cc:62
void XrdFfsMisc_refresh_url_cache(const char *url)
Definition: XrdFfsMisc.cc:249
#define XrdFfs_MAX_NUM_NODES
Definition: XrdFfsMisc.hh:34
int XrdFfsPosix_ftruncate(int fildes, off_t offset)
Definition: XrdFfsPosix.cc:172
int XrdFfsPosix_rmdirall(const char *rdrurl, const char *path, uid_t user_uid)
Definition: XrdFfsPosix.cc:334
int XrdFfsPosix_rename(const char *oldpath, const char *newpath)
Definition: XrdFfsPosix.cc:167
DIR * XrdFfsPosix_opendir(const char *path)
Definition: XrdFfsPosix.cc:82
int XrdFfsPosix_open(const char *path, int oflags, mode_t mode)
Definition: XrdFfsPosix.cc:122
int XrdFfsPosix_fsync(int fildes)
Definition: XrdFfsPosix.cc:157
int XrdFfsPosix_unlink(const char *path)
Definition: XrdFfsPosix.cc:162
int XrdFfsPosix_renameall(const char *rdrurl, const char *from, const char *to, uid_t user_uid)
Definition: XrdFfsPosix.cc:339
void XrdFfsPosix_clear_from_rdr_cache(const char *rdrurl)
Definition: XrdFfsPosix.cc:235
int XrdFfsPosix_truncate(const char *path, off_t Size)
Definition: XrdFfsPosix.cc:176
int XrdFfsPosix_truncateall(const char *rdrurl, const char *path, off_t size, uid_t user_uid)
Definition: XrdFfsPosix.cc:390
int XrdFfsPosix_closedir(DIR *dirp)
Definition: XrdFfsPosix.cc:92
int XrdFfsPosix_rmdir(const char *path)
Definition: XrdFfsPosix.cc:117
struct dirent * XrdFfsPosix_readdir(DIR *dirp)
Definition: XrdFfsPosix.cc:87
off_t XrdFfsPosix_lseek(int fildes, off_t offset, int whence)
Definition: XrdFfsPosix.cc:132
int XrdFfsPosix_close(int fildes)
Definition: XrdFfsPosix.cc:127
ssize_t XrdFfsPosix_pread(int fildes, void *buf, size_t nbyte, off_t offset)
Definition: XrdFfsPosix.cc:142
int XrdFfsPosix_statvfsall(const char *rdrurl, const char *path, struct statvfs *stbuf, uid_t user_uid)
Definition: XrdFfsPosix.cc:677
int XrdFfsPosix_readdirall(const char *rdrurl, const char *path, char ***direntarray, uid_t user_uid)
Definition: XrdFfsPosix.cc:474
int XrdFfsPosix_statall(const char *rdrurl, const char *path, struct stat *stbuf, uid_t user_uid)
Definition: XrdFfsPosix.cc:759
int XrdFfsPosix_unlinkall(const char *rdrurl, const char *path, uid_t user_uid)
Definition: XrdFfsPosix.cc:329
int XrdFfsPosix_stat(const char *path, struct stat *buf)
Definition: XrdFfsPosix.cc:66
int XrdFfsPosix_mkdir(const char *path, mode_t mode)
Definition: XrdFfsPosix.cc:97
long long XrdFfsPosix_getxattr(const char *path, const char *name, void *value, unsigned long long size)
Definition: XrdFfsPosix.cc:181
ssize_t XrdFfsPosix_write(int fildes, const void *buf, size_t nbyte)
Definition: XrdFfsPosix.cc:147
int XrdFfsQueue_remove_workers(int n)
Definition: XrdFfsQueue.cc:229
int XrdFfsQueue_count_workers()
Definition: XrdFfsQueue.cc:254
int XrdFfsQueue_create_workers(int n)
Definition: XrdFfsQueue.cc:192
void XrdFfsWcache_init(int basefd, int maxfd)
Definition: XrdFfsWcache.cc:85
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[])
int stat(const char *path, struct stat *buf)
int open(const char *path, int oflag,...)
int statvfs(const char *path, struct statvfs *buf)
#define close(a)
Definition: XrdPosix.hh:43
if(Avsz)
POSIX interface to XRootD with some extensions, as noted.
static int Fstat(int fildes, struct stat *buf)
Fstat() conforms to POSIX.1-2001 fstat()
static INT to(const char *buffer)
Definition: XrdZipUtils.hh:91