XRootD
XrdPrep.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d P r e p . c c */
4 /* */
5 /* (c) 2021 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 <iostream>
32 #include <vector>
33 #include <string>
34 
35 #include <ctype.h>
36 #include <errno.h>
37 #include <limits.h>
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <sys/param.h>
41 #include <sys/types.h>
42 
43 #include "XrdOuc/XrdOucEnv.hh"
44 #include "XrdSys/XrdSysE2T.hh"
45 #include "XrdSys/XrdSysPlatform.hh"
46 #include "XrdCl/XrdClFileSystem.hh"
47 
48 using namespace XrdCl;
49 
50 /******************************************************************************/
51 /* L o c a l D e f i n e s */
52 /******************************************************************************/
53 
54 #define EMSG(x) std::cerr <<"xrdprep: "<<x<<std::endl
55 
56 /******************************************************************************/
57 /* G e t N u m */
58 /******************************************************************************/
59 
60 namespace
61 {
62 bool GetNum(const char *emsg, const char *item, int *val, int minv, int maxv=-1)
63 {
64  char *eP;
65 
66  if (!item || !*item)
67  {EMSG(emsg<<" value not specified"); return false;}
68 
69  errno = 0;
70  *val = strtol(item, &eP, 10);
71  if (errno || *eP)
72  {EMSG(emsg<<" '"<<item<<"' is not a number");
73  return false;
74  }
75 
76  if (*val < minv)
77  {EMSG(emsg<<" may not be less than "<<minv); return false;}
78  if (maxv >= 0 && *val > maxv)
79  {EMSG(emsg<<" may not be greater than "<<maxv); return false;}
80 
81  return true;
82 }
83 }
84 
85 /******************************************************************************/
86 /* U s a g e */
87 /******************************************************************************/
88 
89 namespace
90 {
91 void Usage(int rc)
92 {
93 std::cerr<<"\nUsage: xrdprep [opts1] [prepare] host[:port] [path [...]]\n";
94 std::cerr<<"\n xrdprep [opts2] {cancel | query} host[:port] handle [path [...]]\n";
95 std::cerr<<"\nOpts1: [-E] [-p prty] [-s] [-S] [-w] [opts2]\n";
96 std::cerr<<"\nOpts2: [-d n] [-f fn]" <<std::endl;
97 exit(rc);
98 }
99 }
100 
101 /******************************************************************************/
102 /* m a i n */
103 /******************************************************************************/
104 
105 int main(int argc, char **argv)
106 {
107  extern char *optarg;
108  extern int optind, opterr;
109 
110  static const int MaxPathLen = MAXPATHLEN+1;
111  static const PrepareFlags::Flags mPrep = PrepareFlags::Cancel |
114 
115  std::vector<std::string> fList;
116  FILE *Stream = 0;
117  const char *msgArgs[] = {"execute", "prepare"};
118  char Target[512];
119  char *inFile = 0;
121  int rc, Prty = 0, Debug = 0;
122  char c, lastOpt = 0;
123  bool isQuery = false, needHandle = false;
124 
125 // See simple help is needed
126 //
127  if (argc <= 1) Usage(0);
128 
129 // Process the options
130 //
131  opterr = 0;
132  if (argc > 1 && '-' == *argv[1])
133  while ((c = getopt(argc,argv,"d:Ef:p:sStw")) && ((unsigned char)c != 0xff))
134  { switch(c)
135  {
136  case 'd': if (!GetNum("debug level", optarg, &Debug, 0, 5)) exit(1);
137  break;
138  case 'E': lastOpt = c;
140  break;
141  case 'f': inFile = optarg;
142  break;
143  case 'p': lastOpt = c;
144  if (!GetNum("priority", optarg, &Prty, 0, 3)) exit(1);
145  break;
146  case 's': lastOpt = c; Opts |= PrepareFlags::Stage;
147  break;
148  case 'S': lastOpt = c; Opts |=(PrepareFlags::Stage|PrepareFlags::Colocate);
149  break;
150  case 't': lastOpt = c; Opts |= PrepareFlags::Fresh;
151  break;
152  case 'w': lastOpt = c; Opts |= PrepareFlags::WriteMode;
153  break;
154  default: EMSG("Invalid option '-"<<argv[optind-1]<<"'");
155  Usage(1);
156  }
157  }
158 
159 // The next argument is either a keyword or the hostname
160 //
161  while(optind < argc)
162  { if (!strcmp(argv[optind], "cancel")) Opts = PrepareFlags::Cancel;
163  else if (!strcmp(argv[optind], "query")) isQuery = true;
164  else if (!strcmp(argv[optind], "prepare")){optind++; break;}
165  else break;
166  if (lastOpt)
167  {EMSG('-'<<lastOpt<<"' option is invalid for '"<<argv[optind]<<"'");
168  Usage(1);
169  }
170  needHandle = true;
171  msgArgs[0] = argv[optind++];
172  break;
173  }
174 
175 // Make sure a host has been specified
176 //
177  if (optind >= argc || !isalnum(*argv[optind]))
178  {EMSG("target host name not specified");
179  Usage(1);
180  }
181 
182 // Grab the host name or address
183 //
184  strcpy(Target, "root://");
185  strcat(Target, argv[optind]);
186  optind++;
187 
188 // If we need a handle then make sure we have one
189 //
190  if (needHandle)
191  {if (optind >= argc || *argv[optind] == '/')
192  {EMSG(msgArgs[0]<<" prepare request handle not specified");
193  Usage(1);
194  }
195  }
196 
197 // Pre-process any command line paths at this point
198 //
199  std::string strArg;
200  int totArgLen = 0;
201  for (int i = optind; i < argc; i++)
202  {strArg = argv[i];
203  totArgLen += strArg.size() + 1;
204  fList.push_back(strArg);
205  }
206 
207 // If an infile was specified, make sure we can open it
208 //
209  if (inFile)
210  {if (!(Stream = fopen(inFile, "r")))
211  {EMSG("Unable to open "<<inFile<<"; "<<XrdSysE2T(errno));
212  exit(4);
213  }
214  char *sP, fBuff[MaxPathLen];
215  do {if (!(sP = fgets(fBuff, MaxPathLen, Stream))) break;
216  while(*sP && *sP == ' ') sP++;
217  if (*sP && *sP != '\n')
218  {strArg = sP;
219  if (strArg.size() && strArg.back() == '\n') strArg.pop_back();
220  while(strArg.size() && strArg.back() == ' ') strArg.pop_back();
221  totArgLen += strArg.size() + 1;
222  fList.push_back(strArg);
223  }
224  } while(!feof(Stream) && !ferror(Stream));
225  if ((rc = ferror(Stream)))
226  {EMSG("unable to read "<<inFile<<"; "<<XrdSysE2T(rc));
227  exit(4);
228  }
229  fclose(Stream);
230  }
231 
232 // If this is a prepare request then we need at least one path
233 //
234  if (!needHandle && fList.size() == 0)
235  {EMSG("No files specified for 'prepare'");
236  Usage(1);
237  }
238 
239 // Cleanup options if eviction is wanted
240 //
241  if (Opts & PrepareFlags::Evict) Opts &= ~mPrep;
242 
243 // Establish debugging level
244 //
245  if (Debug > 0)
246  {const char *dbg[] = {"Info","Warning","Error","Debug","Dump"};
247  if (Debug > 5) Debug = 5;
248  XrdOucEnv::Export("XRD_LOGLEVEL", dbg[Debug-1]);
249  }
250 
251 // Get an instance of the file system
252 //
253  FileSystem Admin(Target);
254 
255 // Issue the relevant operation
256 //
257  Buffer *response = 0;
258  XRootDStatus st;
259  if (!isQuery) st = Admin.Prepare(fList, Opts, uint8_t(Prty), response);
260  else {Buffer qryArgs(totArgLen);
261  char *bP = qryArgs.GetBuffer();
262  for (int i = 0; i < (int)fList.size(); i++)
263  {strcpy(bP, fList[i].c_str());
264  bP += fList[i].size();
265  *bP++ = '\n';
266  }
267  *(bP-1) = 0;
268  st = Admin.Query(QueryCode::Prepare, qryArgs, response);
269  }
270 
271 // Check if all went well
272 //
273  if (!st.IsOK())
274  {std::string estr = st.ToStr();
275  const char *einfo, *etxt = estr.c_str();
276  if (!(einfo = rindex(etxt, ']'))) einfo = etxt;
277  else {einfo++;
278  while(*einfo && *einfo == ' ') einfo++;
279  }
280  EMSG("Unable to "<<msgArgs[0]<<' '<<msgArgs[1]<<"; "
281  <<(char)tolower(*einfo)<<einfo+1);
282  exit(8);
283  }
284 
285 // Display the result
286 //
287  std::string rstr = response->ToString();
288  const char *xx = rstr.c_str();
289  if (*xx) std::cout << xx << std::endl;
290  delete response;
291 
292 // All done
293 //
294  exit(0);
295 }
void Usage(const char *msg)
Definition: XrdAccTest.cc:105
int optind
int fclose(FILE *stream)
#define fopen(a, b)
Definition: XrdPosix.hh:49
int main(int argc, char **argv)
Definition: XrdPrep.cc:105
#define EMSG(x)
Definition: XrdPrep.cc:54
int emsg(int rc, char *msg)
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
Binary blob representation.
Definition: XrdClBuffer.hh:34
const char * GetBuffer(uint32_t offset=0) const
Get the message buffer.
Definition: XrdClBuffer.hh:72
std::string ToString() const
Convert the buffer to a string.
Definition: XrdClBuffer.hh:215
Send file/filesystem queries to an XRootD cluster.
std::string ToStr() const
Convert to string.
static int Export(const char *Var, const char *Val)
Definition: XrdOucEnv.cc:188
XrdCmsAdmin Admin
int Opts
Definition: XrdMpxStats.cc:58
@ Cancel
cancel staging request
@ Colocate
co-locate staged files, if possible
@ Prepare
Query prepare status.
bool IsOK() const
We're fine.
Definition: XrdClStatus.hh:124