/******************************************************************************/ /* */ /* X r d X r o o t d P r e p a r e . c c */ /* */ /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */ /* All Rights Reserved */ /* Produced by Andrew Hanushevsky for Stanford University under contract */ /* DE-AC02-76-SFO0515 with the Department of Energy */ /* */ /* This file is part of the XRootD software suite. */ /* */ /* XRootD is free software: you can redistribute it and/or modify it under */ /* the terms of the GNU Lesser General Public License as published by the */ /* Free Software Foundation, either version 3 of the License, or (at your */ /* option) any later version. */ /* */ /* XRootD is distributed in the hope that it will be useful, but WITHOUT */ /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */ /* License for more details. */ /* */ /* You should have received a copy of the GNU Lesser General Public License */ /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ /* COPYING (GPL license). If not, see . */ /* */ /* The copyright holder's institutional names and contributor's names may not */ /* be used to endorse or promote products derived from this software without */ /* specific prior written permission of the institution or contributor. */ /******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #ifdef __linux__ #include #define getdents(fd, dirp, cnt) syscall(SYS_getdents, fd, dirp, cnt) #endif #include "XrdSys/XrdSysError.hh" #include "XrdSys/XrdSysPlatform.hh" #include "XrdOuc/XrdOucTList.hh" #include "XrdXrootd/XrdXrootdPrepare.hh" #include "XrdXrootd/XrdXrootdTrace.hh" /******************************************************************************/ /* G l o b a l O b j e c t s */ /******************************************************************************/ /******************************************************************************/ /* G l o b a l s */ /******************************************************************************/ #ifndef NODEBUG extern XrdOucTrace *XrdXrootdTrace; #endif XrdScheduler *XrdXrootdPrepare::SchedP; XrdSysError *XrdXrootdPrepare::eDest; // Error message handler int XrdXrootdPrepare::scrubtime = 60*60; int XrdXrootdPrepare::scrubkeep = 60*60*24; char *XrdXrootdPrepare::LogDir = 0; int XrdXrootdPrepare::LogDirLen = 0; const char *XrdXrootdPrepare::TraceID = "Prepare"; /******************************************************************************/ /* C o n s t r u c t o r */ /******************************************************************************/ XrdXrootdPrepare::XrdXrootdPrepare(XrdSysError *errp, XrdScheduler *sp) : XrdJob("Prep log scrubber") {eDest = errp; SchedP = sp; if (LogDir) SchedP->Schedule((XrdJob *)this, scrubtime+time(0)); else eDest->Say("Config warning: 'xrootd.prepare logdir' not specified; " "prepare tracking disabled."); } /******************************************************************************/ /* L i s t */ /******************************************************************************/ int XrdXrootdPrepare::List(XrdXrootdPrepArgs &pargs, char *resp, int resplen) { char *up, path[2048]; struct dirent *dp; struct stat buf; int rc; // If logging is not supported, return eof // if (!LogDir) return -1; // Check if this is the first call // if (!pargs.dirP) {if (!(pargs.dirP = opendir((const char *)LogDir))) {eDest->Emsg("List", errno, "open prep log directory", LogDir); return -1; } if (pargs.reqid) pargs.reqlen = strlen(pargs.reqid); if (pargs.user) pargs.usrlen = strlen(pargs.user); } // Find the next entry that satisfies the search criteria // errno = 0; while((dp = readdir(pargs.dirP))) {if (!(up = (char *) index((const char *)dp->d_name, '_'))) continue; if (pargs.reqlen && strncmp(dp->d_name, pargs.reqid, pargs.reqlen)) continue; if (pargs.usrlen) if (!up || strcmp((const char *)up+1,(const char *)pargs.user)) continue; strcpy(path, (const char *)LogDir); strcpy(path+LogDirLen, (const char *)dp->d_name); if (stat((const char *)path, &buf)) continue; *up = ' '; if ((up = (char *) index((const char *)(up+1), (int)'_'))) *up = ' '; else continue; if ((up = (char *) index((const char *)(up+1), (int)'_'))) *up = ' '; else continue; return snprintf(resp, resplen-1, "%s %ld", dp->d_name, buf.st_mtime); } // Completed // if ((rc = errno)) eDest->Emsg("List", errno, "read prep log directory", LogDir); closedir(pargs.dirP); pargs.dirP = 0; return (rc ? -1 : 0); } /******************************************************************************/ /* L o g */ /******************************************************************************/ void XrdXrootdPrepare::Log(XrdXrootdPrepArgs &pargs) { int rc, pnum = 0, xfd; XrdOucTList *tp = pargs.paths; char buff[2048], blink[2048]; struct iovec iovec[2]; // If logging not enabled, return // if (!LogDir) return; // Count number of paths in the list // while(tp) {pnum++; tp = tp->next;} // Construct the file name: ___ // snprintf(buff, sizeof(buff)-1, "%s%s_%s_%d_%d", LogDir, pargs.reqid, pargs.user, pargs.prty, pnum); // Create the file // if ((xfd = open(buff, O_WRONLY|O_CREAT|O_TRUNC,0644)) < 0) {eDest->Emsg("Log", errno, "open prep log file", buff); return; } // Write all the paths into the file, separating each by a space // iovec[1].iov_base = (char *)" "; iovec[1].iov_len = 1; tp = pargs.paths; while(tp) {if (tp->next == 0) iovec[1].iov_base = (char *)"\n"; iovec[0].iov_base = tp->text; iovec[0].iov_len = strlen(tp->text); do {rc = writev(xfd, (const struct iovec *)iovec, 2);} while(rc < 0 && errno == EINTR); if (rc < 0) {eDest->Emsg("Log", errno, "write prep log file", buff); close(xfd); return; } tp = tp->next; } // Create a symlink to the file // close(xfd); strcpy(blink, LogDir); strlcpy(blink+LogDirLen, pargs.reqid, sizeof(blink)-1); if (symlink((const char *)buff, (const char *)blink)) {eDest->Emsg("Log", errno, "create symlink to prep log file", buff); return; } } /******************************************************************************/ /* L o g d e l */ /******************************************************************************/ void XrdXrootdPrepare::Logdel(char *reqid) { int rc; char path[MAXPATHLEN+256], buff[MAXPATHLEN+1]; // If logging not enabled, return // if (!LogDir || strlen(reqid) > 255) return; // Construct the file name of the symlink // strcpy(path, (const char *)LogDir); strcpy(&path[LogDirLen], (const char *)reqid); // Read the symlink contents for this request // if ((rc = readlink((const char *)path, buff, sizeof(buff)-1)) < 0) {if (errno != ENOENT) eDest->Emsg("Logdel",errno,"read symlink",path); return; } // Delete the file, then the symlink // buff[rc] = '\0'; if (unlink((const char *)buff) && errno != ENOENT) eDest->Emsg("Logdel",errno,"remove",buff); else TRACE(DEBUG, "Logdel removed " <Emsg("Logdel", errno, "remove", path); else TRACE(DEBUG, "Logdel removed " <Emsg("Scrub", errno, "open prep log directory", LogDir); return; } strcpy(path, (const char *)LogDir); // Delete all stale entries // errno = 0; while((dp = readdir(prepD))) {if (!(up = (char *) index((const char *)dp->d_name, '_'))) continue; strcpy(fn, (const char *)dp->d_name); if (stat((const char *)path, &buf)) continue; if (buf.st_mtime <= stale) {TRACE(DEBUG, "Scrub removed stale prep log " <d_name)) = '\0'; unlink((const char *)path); errno = 0; } } // All done // if (errno) eDest->Emsg("List", errno, "read prep log directory", LogDir); closedir(prepD); } /******************************************************************************/ /* s e t P a r m s */ /******************************************************************************/ int XrdXrootdPrepare::setParms(int stime, int keep) {if (stime > 0) scrubtime = stime; if (keep > 0) scrubkeep = keep; return 0; } int XrdXrootdPrepare::setParms(char *ldir) { char path[2048]; struct stat buf; int plen; // If parm not supplied, ignore call // if (!ldir) return 0; // Make sure we have appropriate permissions for this directory // if (access((const char *)ldir, X_OK | W_OK | R_OK) || stat(ldir, &buf)) return -errno; if ((buf.st_mode & S_IFMT) != S_IFDIR) return -ENOTDIR; // Create the path name // if (LogDir) free(LogDir); LogDir = 0; plen = strlen(ldir); strcpy(path, ldir); if (path[plen-1] != '/') path[plen++] = '/'; path[plen] = '\0'; // Save the path and return // LogDir = strdup(path); LogDirLen = strlen(LogDir); return 0; }