XRootD
XrdXrootdPrepare.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d X r o o t d P r e p a r e . c c */
4 /* */
5 /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <dirent.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <cstdio>
35 #include <cstdlib>
36 #include <strings.h>
37 #include <sys/param.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/uio.h>
41 
42 #ifdef __linux__
43 #include <syscall.h>
44 #define getdents(fd, dirp, cnt) syscall(SYS_getdents, fd, dirp, cnt)
45 #endif
46 
47 #include "XrdSys/XrdSysError.hh"
48 #include "XrdSys/XrdSysPlatform.hh"
49 #include "XrdOuc/XrdOucTList.hh"
52 
53 /******************************************************************************/
54 /* G l o b a l O b j e c t s */
55 /******************************************************************************/
56 
57 /******************************************************************************/
58 /* G l o b a l s */
59 /******************************************************************************/
60 
61 #ifndef NODEBUG
63 #endif
64 
65  XrdScheduler *XrdXrootdPrepare::SchedP;
66 
67  XrdSysError *XrdXrootdPrepare::eDest; // Error message handler
68 
69  int XrdXrootdPrepare::scrubtime = 60*60;
70  int XrdXrootdPrepare::scrubkeep = 60*60*24;
71  char *XrdXrootdPrepare::LogDir = 0;
72  int XrdXrootdPrepare::LogDirLen = 0;
73 const char *XrdXrootdPrepare::TraceID = "Prepare";
74 
75 /******************************************************************************/
76 /* C o n s t r u c t o r */
77 /******************************************************************************/
78 
80  bool nomsg) : XrdJob("Prep log scrubber")
81 {eDest = errp;
82  SchedP = sp;
83  if (LogDir) SchedP->Schedule((XrdJob *)this, scrubtime+time(0));
84 // else if (!nomsg) eDest->Say("Config warning: 'xrootd.prepare logdir' "
85 // "not specified; prepare tracking disabled.");
86 }
87 
88 /******************************************************************************/
89 /* L i s t */
90 /******************************************************************************/
91 
92 int XrdXrootdPrepare::List(XrdXrootdPrepArgs &pargs, char *resp, int resplen)
93 {
94  char *up, path[2048];
95  struct dirent *dp;
96  struct stat buf;
97  int rc;
98 
99 // If logging is not supported, return eof
100 //
101  if (!LogDir) return -1;
102 
103 // Check if this is the first call
104 //
105  if (!pargs.dirP)
106  {if (!(pargs.dirP = opendir((const char *)LogDir)))
107  {eDest->Emsg("List", errno, "open prep log directory", LogDir);
108  return -1;
109  }
110  if (pargs.reqid) pargs.reqlen = strlen(pargs.reqid);
111  if (pargs.user) pargs.usrlen = strlen(pargs.user);
112  }
113 
114 // Find the next entry that satisfies the search criteria
115 //
116  errno = 0;
117  while((dp = readdir(pargs.dirP)))
118  {if (!(up = (char *) index((const char *)dp->d_name, '_'))) continue;
119  if (pargs.reqlen && strncmp(dp->d_name, pargs.reqid, pargs.reqlen))
120  continue;
121  if (pargs.usrlen)
122  if (!up || strcmp((const char *)up+1,(const char *)pargs.user))
123  continue;
124  strcpy(path, (const char *)LogDir);
125  strcpy(path+LogDirLen, (const char *)dp->d_name);
126  if (stat((const char *)path, &buf)) continue;
127  *up = ' ';
128  if ((up = (char *) index((const char *)(up+1), (int)'_'))) *up = ' ';
129  else continue;
130  if ((up = (char *) index((const char *)(up+1), (int)'_'))) *up = ' ';
131  else continue;
132  return snprintf(resp, resplen-1, "%s %lld",
133  dp->d_name, (long long) buf.st_mtime);
134  }
135 
136 // Completed
137 //
138  if ((rc = errno))
139  eDest->Emsg("List", errno, "read prep log directory", LogDir);
140  closedir(pargs.dirP);
141  pargs.dirP = 0;
142  return (rc ? -1 : 0);
143 }
144 
145 /******************************************************************************/
146 /* L o g */
147 /******************************************************************************/
148 
150 {
151  int rc, pnum = 0, xfd;
152  XrdOucTList *tp = pargs.paths;
153  char buff[2048], blink[2048];
154  struct iovec iovec[2];
155 
156 // If logging not enabled, return
157 //
158  if (!LogDir) return;
159 
160 // Count number of paths in the list
161 //
162  while(tp) {pnum++; tp = tp->next;}
163 
164 // Construct the file name: <reqid>_<user>_<prty>_<numpaths>
165 //
166  snprintf(buff, sizeof(buff)-1, "%s%s_%s_%d_%d", LogDir,
167  pargs.reqid, pargs.user, pargs.prty, pnum);
168 
169 // Create the file
170 //
171  if ((xfd = open(buff, O_WRONLY|O_CREAT|O_TRUNC,0644)) < 0)
172  {eDest->Emsg("Log", errno, "open prep log file", buff);
173  return;
174  }
175 
176 // Write all the paths into the file, separating each by a space
177 //
178  iovec[1].iov_base = (char *)" ";
179  iovec[1].iov_len = 1;
180  tp = pargs.paths;
181  while(tp)
182  {if (tp->next == 0) iovec[1].iov_base = (char *)"\n";
183  iovec[0].iov_base = tp->text;
184  iovec[0].iov_len = strlen(tp->text);
185  do {rc = writev(xfd, (const struct iovec *)iovec, 2);}
186  while(rc < 0 && errno == EINTR);
187  if (rc < 0)
188  {eDest->Emsg("Log", errno, "write prep log file", buff);
189  close(xfd);
190  return;
191  }
192  tp = tp->next;
193  }
194 
195 // Create a symlink to the file
196 //
197  close(xfd);
198  strcpy(blink, LogDir);
199  strlcpy(blink+LogDirLen, pargs.reqid, sizeof(blink)-1);
200  if (symlink((const char *)buff, (const char *)blink))
201  {eDest->Emsg("Log", errno, "create symlink to prep log file", buff);
202  return;
203  }
204 }
205 
206 /******************************************************************************/
207 /* L o g d e l */
208 /******************************************************************************/
209 
210 void XrdXrootdPrepare::Logdel(char *reqid)
211 {
212  int rc;
213  char path[MAXPATHLEN+256], buff[MAXPATHLEN+1];
214 
215 // If logging not enabled, return
216 //
217  if (!LogDir || strlen(reqid) > 255) return;
218 
219 // Construct the file name of the symlink
220 //
221  strcpy(path, (const char *)LogDir);
222  strcpy(&path[LogDirLen], (const char *)reqid);
223 
224 // Read the symlink contents for this request
225 //
226  if ((rc = readlink((const char *)path, buff, sizeof(buff)-1)) < 0)
227  {if (errno != ENOENT) eDest->Emsg("Logdel",errno,"read symlink",path);
228  return;
229  }
230 
231 // Delete the file, then the symlink
232 //
233  buff[rc] = '\0';
234  if (unlink((const char *)buff)
235  && errno != ENOENT) eDest->Emsg("Logdel",errno,"remove",buff);
236  else TRACE(DEBUG, "Logdel removed " <<buff);
237  if (unlink((const char *)path)
238  && errno != ENOENT) eDest->Emsg("Logdel", errno, "remove", path);
239  else TRACE(DEBUG, "Logdel removed " <<path);
240 }
241 
242 /******************************************************************************/
243 /* O p e n */
244 /******************************************************************************/
245 
246 int XrdXrootdPrepare::Open(const char *reqid, int &fsz)
247 {
248  int fd;
249  char path[MAXPATHLEN+264];
250  struct stat buf;
251 
252 // If logging is not supported, indicate so
253 //
254  if (!LogDir) return -ENOTSUP;
255 
256 // Construct the file name
257 //
258  strcpy(path, (const char *)LogDir);
259  strcpy(path+LogDirLen, reqid);
260 
261 // Open the file and return the file descriptor
262 //
263  if ((fd = open((const char *)path, O_RDONLY)) < 0) return -errno;
264 
265 // Get the file size
266 //
267  if (fstat(fd, &buf) != 0) {
268  close(fd);
269  return -errno;
270  }
271 
272  fsz = buf.st_size;
273 
274  return fd;
275 }
276 
277 /******************************************************************************/
278 /* S c r u b */
279 /******************************************************************************/
280 
282 {
283  DIR *prepD;
284  time_t stale = time(0) - scrubkeep;
285  char *up, path[2048], *fn = path+LogDirLen;
286  struct dirent *dp;
287  struct stat buf;
288 
289 // If logging is not supported, return eof
290 //
291  if (!LogDir) return;
292 
293 // Open the log directory
294 //
295  if (!(prepD = opendir((const char *)LogDir)))
296  {eDest->Emsg("Scrub", errno, "open prep log directory", LogDir);
297  return;
298  }
299  strcpy(path, (const char *)LogDir);
300 
301 // Delete all stale entries
302 //
303  errno = 0;
304  while((dp = readdir(prepD)))
305  {if (!(up = (char *) index((const char *)dp->d_name, '_'))) continue;
306  strcpy(fn, (const char *)dp->d_name);
307  if (stat((const char *)path, &buf)) continue;
308  if (buf.st_mtime <= stale)
309  {TRACE(DEBUG, "Scrub removed stale prep log " <<path);
310  unlink((const char *)path);
311  *(fn+(up-dp->d_name)) = '\0';
312  unlink((const char *)path);
313  errno = 0;
314  }
315  }
316 
317 // All done
318 //
319  if (errno)
320  eDest->Emsg("List", errno, "read prep log directory", LogDir);
321  closedir(prepD);
322 }
323 
324 /******************************************************************************/
325 /* s e t P a r m s */
326 /******************************************************************************/
327 
328 int XrdXrootdPrepare::setParms(int stime, int keep)
329 {if (stime > 0) scrubtime = stime;
330  if (keep > 0) scrubkeep = keep;
331  return 0;
332 }
333 
335 {
336  char path[2048];
337  struct stat buf;
338  int plen;
339 
340 // If parm not supplied, ignore call
341 //
342  if (!ldir) return 0;
343 
344 // Make sure we have appropriate permissions for this directory
345 //
346  if (access((const char *)ldir, X_OK | W_OK | R_OK) || stat(ldir, &buf))
347  return -errno;
348  if ((buf.st_mode & S_IFMT) != S_IFDIR) return -ENOTDIR;
349 
350 // Create the path name
351 //
352  if (LogDir) free(LogDir);
353  LogDir = 0;
354  plen = strlen(ldir);
355  strcpy(path, ldir);
356  if (path[plen-1] != '/') path[plen++] = '/';
357  path[plen] = '\0';
358 
359 // Save the path and return
360 //
361  LogDir = strdup(path);
362  LogDirLen = strlen(LogDir);
363  return 0;
364 }
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
static XrdSysError eDest(0,"crypto_")
int stat(const char *path, struct stat *buf)
struct dirent * readdir(DIR *dirp)
int open(const char *path, int oflag,...)
int fstat(int fildes, struct stat *buf)
int unlink(const char *path)
int access(const char *path, int amode)
int closedir(DIR *dirp)
ssize_t writev(int fildes, const struct iovec *iov, int iovcnt)
DIR * opendir(const char *path)
#define close(a)
Definition: XrdPosix.hh:43
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TRACE(act, x)
Definition: XrdTrace.hh:63
XrdSysTrace XrdXrootdTrace
Definition: XrdJob.hh:43
XrdOucTList * next
Definition: XrdOucTList.hh:45
char * text
Definition: XrdOucTList.hh:46
void Schedule(XrdJob *jp)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
XrdOucTList * paths
static int List(XrdXrootdPrepArgs &pargs, char *resp, int resplen)
static void Log(XrdXrootdPrepArgs &pargs)
static void Logdel(char *reqid)
static void Scrub()
static int setParms(int stime, int skeep)
XrdXrootdPrepare(XrdSysError *lp, XrdScheduler *sp, bool nomsg)
static int Open(const char *reqid, int &fsz)