Logo ROOT   6.07/09
Reference Guide
XrdProofdAdmin.cxx
Go to the documentation of this file.
1 // @(#)root/proofd:$Id$
2 // Author: G. Ganis Feb 2008
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //////////////////////////////////////////////////////////////////////////
13 // //
14 // XrdProofdAdmin //
15 // //
16 // Author: G. Ganis, CERN, 2008 //
17 // //
18 // Envelop class for admin services. //
19 // Loaded as service by XrdProofdManager. //
20 // //
21 //////////////////////////////////////////////////////////////////////////
22 #include "XrdProofdPlatform.h"
23 
24 
25 #include "XpdSysError.h"
26 
27 #include "Xrd/XrdBuffer.hh"
28 #include "Xrd/XrdScheduler.hh"
30 #include "XrdOuc/XrdOucStream.hh"
31 
32 #include "XrdProofdAdmin.h"
33 #include "XrdProofdClient.h"
34 #include "XrdProofdClientMgr.h"
35 #include "XrdProofdManager.h"
36 #include "XrdProofdNetMgr.h"
37 #include "XrdProofdPriorityMgr.h"
38 #include "XrdProofdProofServMgr.h"
39 #include "XrdProofdProtocol.h"
40 #include "XrdProofGroup.h"
41 #include "XrdProofSched.h"
42 #include "XrdProofdProofServ.h"
43 #include "XrdROOT.h"
44 
45 // Tracing utilities
46 #include "XrdProofdTrace.h"
47 
48 ////////////////////////////////////////////////////////////////////////////////
49 /// Decrease active session counters on worker w
50 
51 static int ExportCpCmd(const char *k, XpdAdminCpCmd *cc, void *s)
52 {
53  XPDLOC(PMGR, "ExportCpCmd")
54 
55  XrdOucString *ccs = (XrdOucString *)s;
56  if (cc && ccs) {
57  if (ccs->length() > 0) *ccs += ",";
58  *ccs += k;
59  *ccs += ":";
60  *ccs += cc->fCmd;
61  TRACE(DBG, k <<" : "<<cc->fCmd<<" fmt: '"<<cc->fFmt<<"'");
62  // Check next
63  return 0;
64  }
65 
66  // Not enough info: stop
67  return 1;
68 }
69 
70 ////////////////////////////////////////////////////////////////////////////////
71 /// Constructor
72 
74  XrdProtocol_Config *pi, XrdSysError *e)
75  : XrdProofdConfig(pi->ConfigFN, e)
76 {
77  fMgr = mgr;
78  fExportPaths.clear();
79  // Map of default copy commands supported / allowed, keyed by the protocol
80  fAllowedCpCmds.Add("file", new XpdAdminCpCmd("cp","cp -rp %s %s",1));
81  fAllowedCpCmds.Add("root", new XpdAdminCpCmd("xrdcp","xrdcp %s %s",1));
82  fAllowedCpCmds.Add("xrd", new XpdAdminCpCmd("xrdcp","xrdcp %s %s",1));
83 #if !defined(__APPLE__)
84  fAllowedCpCmds.Add("http", new XpdAdminCpCmd("wget","wget %s -O %s",0));
85  fAllowedCpCmds.Add("https", new XpdAdminCpCmd("wget","wget %s -O %s",0));
86 #else
87  fAllowedCpCmds.Add("http", new XpdAdminCpCmd("curl","curl %s -o %s",0));
88  fAllowedCpCmds.Add("https", new XpdAdminCpCmd("curl","curl %s -o %s",0));
89 #endif
90  fCpCmds = "";
91  fAllowedCpCmds.Apply(ExportCpCmd, (void *)&fCpCmds);
92 
93  // Configuration directives
95 }
96 
97 ////////////////////////////////////////////////////////////////////////////////
98 /// Register directives for configuration
99 
101 {
102  Register("exportpath", new XrdProofdDirective("exportpath", this, &DoDirectiveClass));
103  Register("cpcmd", new XrdProofdDirective("cpcmd", this, &DoDirectiveClass));
104 }
105 
106 ////////////////////////////////////////////////////////////////////////////////
107 /// Process admin request
108 
110 {
111  XPDLOC(ALL, "Admin::Process")
112 
113  int rc = 0;
114  XPD_SETRESP(p, "Process");
115 
116  TRACEP(p, REQ, "req id: " << type << " ("<<
117  XrdProofdAux::AdminMsgType(type) << ")");
118 
119  XrdOucString emsg;
120  switch (type) {
121  case kQueryMssUrl:
122  return QueryMssUrl(p);
123  case kQuerySessions:
124  return QuerySessions(p);
125  case kQueryLogPaths:
126  return QueryLogPaths(p);
127  case kCleanupSessions:
128  return CleanupSessions(p);
129  case kSendMsgToUser:
130  return SendMsgToUser(p);
131  case kGroupProperties:
132  return SetGroupProperties(p);
133  case kGetWorkers:
134  return GetWorkers(p);
135  case kQueryWorkers:
136  return QueryWorkers(p);
137  case kQueryROOTVersions:
138  return QueryROOTVersions(p);
139  case kROOTVersion:
140  return SetROOTVersion(p);
141  case kSessionAlias:
142  return SetSessionAlias(p);
143  case kSessionTag:
144  return SetSessionTag(p);
145  case kReleaseWorker:
146  return ReleaseWorker(p);
147  case kExec:
148  return Exec(p);
149  case kGetFile:
150  return GetFile(p);
151  case kPutFile:
152  return PutFile(p);
153  case kCpFile:
154  return CpFile(p);
155  default:
156  emsg += "Invalid type: ";
157  emsg += type;
158  break;
159  }
160 
161  // Notify invalid request
162  response->Send(kXR_InvalidRequest, emsg.c_str());
163 
164  // Done
165  return 0;
166 }
167 
168 ////////////////////////////////////////////////////////////////////////////////
169 /// Run configuration and parse the entered config directives.
170 /// Return 0 on success, -1 on error
171 
173 {
174  XPDLOC(ALL, "Admin::Config")
175 
176  // Run first the configurator
177  if (XrdProofdConfig::Config(rcf) != 0) {
178  XPDERR("problems parsing file ");
179  return -1;
180  }
181 
182  XrdOucString msg;
183  msg = (rcf) ? "re-configuring" : "configuring";
184  TRACE(ALL, msg.c_str());
185 
186  // Exported paths
187  if (fExportPaths.size() > 0) {
188  TRACE(ALL, "additional paths which can be browsed by all users: ");
189  std::list<XrdOucString>::iterator is = fExportPaths.begin();
190  while (is != fExportPaths.end()) { TRACE(ALL, " "<<*is); is++; }
191  }
192  // Allowed / supported copy commands
193  TRACE(ALL, "allowed/supported copy commands: "<<fCpCmds);
194 
195  // Done
196  return 0;
197 }
198 
199 ////////////////////////////////////////////////////////////////////////////////
200 /// Update the priorities of the active sessions.
201 
203  char *val, XrdOucStream *cfg, bool rcf)
204 {
205  XPDLOC(SMGR, "Admin::DoDirective")
206 
207  if (!d)
208  // undefined inputs
209  return -1;
210 
211  if (d->fName == "exportpath") {
212  return DoDirectiveExportPath(val, cfg, rcf);
213  } else if (d->fName == "cpcmd") {
214  return DoDirectiveCpCmd(val, cfg, rcf);
215  }
216  TRACE(XERR,"unknown directive: "<<d->fName);
217  return -1;
218 }
219 
220 ////////////////////////////////////////////////////////////////////////////////
221 /// Process 'exportpath' directives
222 /// eg: xpd.exportpath /tmp/data /data2/data
223 
224 int XrdProofdAdmin::DoDirectiveExportPath(char *val, XrdOucStream *cfg, bool)
225 {
226  XPDLOC(SMGR, "Admin::DoDirectiveExportPath")
227 
228  if (!val || !cfg)
229  // undefined inputs
230  return -1;
231 
232  TRACE(ALL,"val: "<<val);
233 
234  while (val) {
235  XrdOucString tkns(val), tkn;
236  int from = 0;
237  while ((from = tkns.tokenize(tkn, from, ' ')) != STR_NPOS) {
238  fExportPaths.push_back(tkn);
239  }
240  // Get next
241  val = cfg->GetWord();
242  }
243 
244  return 0;
245 }
246 
247 ////////////////////////////////////////////////////////////////////////////////
248 /// Process 'cpcmd' directives
249 /// eg: xpd.cpcmd alien aliencp fmt:"%s %s" put:0
250 
251 int XrdProofdAdmin::DoDirectiveCpCmd(char *val, XrdOucStream *cfg, bool)
252 {
253  XPDLOC(SMGR, "Admin::DoDirectiveCpCmd")
254 
255  if (!val || !cfg)
256  // undefined inputs
257  return -1;
258 
259  XrdOucString proto, cpcmd, fmt;
260  bool canput = 0, isfmt = 0, rm = 0;
261 
262  while (val) {
263  XrdOucString tkn(val);
264  if (proto.length() <= 0) {
265  proto = tkn;
266  if (proto.beginswith('-')) {
267  rm = 1;
268  proto.erase(0, 1);
269  break;
270  }
271  } else if (cpcmd.length() <= 0) {
272  cpcmd = tkn;
273  } else if (tkn.beginswith("put:")) {
274  isfmt = 0;
275  if (tkn == "put:1") canput = 1;
276  } else if (tkn.beginswith("fmt:")) {
277  fmt.assign(tkn, 4, -1);
278  isfmt = 1;
279  } else {
280  if (isfmt) {
281  fmt += " ";
282  fmt += tkn;
283  }
284  }
285  // Get next
286  val = cfg->GetWord();
287  }
288 
289  if (rm) {
290  // Remove the related entry
291  fAllowedCpCmds.Del(proto.c_str());
292  } else if (cpcmd.length() > 0 && fmt.length() > 0) {
293  // Add or replace
294  fmt.insert(" ", 0);
295  fmt.insert(cpcmd, 0);
296  fAllowedCpCmds.Rep(proto.c_str(), new XpdAdminCpCmd(cpcmd.c_str(),fmt.c_str(),canput));
297  } else {
298  TRACE(ALL, "incomplete information: ignoring!");
299  }
300 
301  // Fill again the export string
302  fCpCmds = "";
303  fAllowedCpCmds.Apply(ExportCpCmd, (void *)&fCpCmds);
304 
305  return 0;
306 }
307 
308 ////////////////////////////////////////////////////////////////////////////////
309 /// Handle request for the URL to the MSS attached to the cluster.
310 /// The reply contains also the namespace, i.e. proto://host:port//namespace
311 
313 {
314  XPDLOC(ALL, "Admin::QueryMssUrl")
315 
316  int rc = 0;
317  XPD_SETRESP(p, "QueryMssUrl");
318 
319  XrdOucString msg = fMgr->PoolURL();
320  msg += "/";
321  msg += fMgr->NameSpace();
322 
323  TRACEP(p, DBG, "sending: "<<msg);
324 
325  // Send back to user
326  response->Send((void *)msg.c_str(), msg.length()+1);
327 
328  // Over
329  return 0;
330 }
331 
332 ////////////////////////////////////////////////////////////////////////////////
333 /// Handle request for list of ROOT versions
334 
336 {
337  XPDLOC(ALL, "Admin::QueryROOTVersions")
338 
339  int rc = 0;
340  XPD_SETRESP(p, "QueryROOTVersions");
341 
342  XrdOucString msg = fMgr->ROOTMgr()->ExportVersions(p->Client()->ROOT());
343 
344  TRACEP(p, DBG, "sending: "<<msg);
345 
346  // Send back to user
347  response->Send((void *)msg.c_str(), msg.length()+1);
348 
349  // Over
350  return 0;
351 }
352 
353 ////////////////////////////////////////////////////////////////////////////////
354 /// Handle request for changing the default ROOT version
355 
357 {
358  XPDLOC(ALL, "Admin::SetROOTVersion")
359 
360  int rc = 0;
361  XPD_SETRESP(p, "SetROOTVersion");
362 
363  // Change default ROOT version
364  const char *t = p->Argp() ? (const char *) p->Argp()->buff : "default";
365  int len = p->Argp() ? p->Request()->header.dlen : strlen("default");
366  XrdOucString tag(t,len);
367 
368  // If a user name is given separate it out and check if
369  // we can do the operation
370  XrdOucString usr;
371  if (tag.beginswith("u:")) {
372  usr = tag;
373  usr.erase(usr.rfind(' '));
374  usr.replace("u:","");
375  // Isolate the tag
376  tag.erase(0,tag.find(' ') + 1);
377  }
378  TRACEP(p, REQ, "usr: "<<usr<<", version tag: "<< tag);
379 
380  // If the action is requested for a user different from us we
381  // must be 'superuser'
382  XrdProofdClient *c = p->Client();
383  XrdOucString grp;
384  if (usr.length() > 0) {
385  // Separate group info, if any
386  if (usr.find(':') != STR_NPOS) {
387  grp = usr;
388  grp.erase(grp.rfind(':'));
389  usr.erase(0,usr.find(':') + 1);
390  } else {
391  XrdProofGroup *g =
392  (fMgr->GroupsMgr()) ? fMgr->GroupsMgr()->GetUserGroup(usr.c_str()) : 0;
393  grp = g ? g->Name() : "default";
394  }
395  if (usr != p->Client()->User()) {
396  if (!p->SuperUser()) {
397  usr.insert("not allowed to change settings for usr '", 0);
398  usr += "'";
399  TRACEP(p, XERR, usr.c_str());
400  response->Send(kXR_InvalidRequest, usr.c_str());
401  return 0;
402  }
403  // Lookup the list
404  if (!(c = fMgr->ClientMgr()->GetClient(usr.c_str(), grp.c_str()))) {
405  // No: fail
406  XrdOucString emsg("user not found or not allowed: ");
407  emsg += usr;
408  TRACEP(p, XERR, emsg.c_str());
409  response->Send(kXR_InvalidRequest, emsg.c_str());
410  return 0;
411  }
412  }
413  }
414 
415  // Search in the list
416  XrdROOT *r = fMgr->ROOTMgr()->GetVersion(tag.c_str());
417  bool ok = r ? 1 : 0;
418  if (!r && tag == "default") {
419  // If not found we may have been requested to set the default version
420  r = fMgr->ROOTMgr()->DefaultVersion();
421  ok = r ? 1 : 0;
422  }
423 
424  if (ok) {
425  // Save the version in the client instance
426  c->SetROOT(r);
427  // Notify
428  TRACEP(p, DBG, "default changed to "<<c->ROOT()->Tag()<<
429  " for {client, group} = {"<<usr<<", "<<grp<<"} ("<<c<<")");
430  // Forward down the tree, if not leaf
431  int brc = 0;
432  if (fMgr->SrvType() != kXPD_Worker) {
433  XrdOucString buf("u:");
434  buf += c->UI().fUser;
435  buf += " ";
436  buf += tag;
437  int type = ntohl(p->Request()->proof.int1);
438  brc = fMgr->NetMgr()->Broadcast(type, buf.c_str(), p->Client()->User(), response);
439  }
440  if (brc == 0) {
441  // Acknowledge user
442  response->Send();
443  } else {
444  // Notify something wrong
445  tag.insert("tag '", 0);
446  tag += "' not found in the list of available ROOT versions on some worker nodes";
447  TRACEP(p, XERR, tag.c_str());
448  response->Send(kXR_InvalidRequest, tag.c_str());
449  }
450  } else {
451  tag.insert("tag '", 0);
452  tag += "' not found in the list of available ROOT versions";
453  TRACEP(p, XERR, tag.c_str());
454  response->Send(kXR_InvalidRequest, tag.c_str());
455  }
456 
457  // Over
458  return 0;
459 }
460 
461 ////////////////////////////////////////////////////////////////////////////////
462 /// Handle request for getting the list of potential workers
463 
465 {
466  XPDLOC(ALL, "Admin::QueryWorkers")
467 
468  int rc = 0;
469  XPD_SETRESP(p, "QueryWorkers");
470 
471  // Send back a list of potentially available workers
472  XrdOucString sbuf(1024);
473  fMgr->ProofSched()->ExportInfo(sbuf);
474 
475  // Send buffer
476  char *buf = (char *) sbuf.c_str();
477  int len = sbuf.length() + 1;
478  TRACEP(p, DBG, "sending: "<<buf);
479 
480  // Send back to user
481  response->Send(buf, len);
482 
483  // Over
484  return 0;
485 }
486 
487 ////////////////////////////////////////////////////////////////////////////////
488 /// Handle request for getting the best set of workers
489 
491 {
492  XPDLOC(ALL, "Admin::GetWorkers")
493 
494  int rc = 0;
495  XPD_SETRESP(p, "GetWorkers");
496 
497  // Unmarshall the data
498  int psid = ntohl(p->Request()->proof.sid);
499 
500  // Find server session
501  XrdProofdProofServ *xps = 0;
502  if (!p->Client() || !(xps = p->Client()->GetServer(psid))) {
503  TRACEP(p, XERR, "session ID not found: "<<psid);
504  response->Send(kXR_InvalidRequest,"session ID not found");
505  return 0;
506  }
507  int pid = xps->SrvPID();
508  TRACEP(p, REQ, "request from session "<<pid);
509 
510  // We should query the chosen resource provider
511  XrdOucString wrks("");
512 
513  // Read the message associated with the request; needs to do like this because
514  // of a bug in the XrdOucString constructor when length is 0
515  XrdOucString msg;
516  if (p->Request()->header.dlen > 0)
517  msg.assign((const char *) p->Argp()->buff, 0, p->Request()->header.dlen);
518  if (fMgr->GetWorkers(wrks, xps, msg.c_str()) < 0 ) {
519  // Something wrong
520  response->Send(kXR_InvalidRequest, "GetWorkers failed");
521  return 0;
522  }
523 
524  // Send buffer
525  // In case the session was enqueued, pass an empty list.
526  char *buf = (char *) wrks.c_str();
527  int len = wrks.length() + 1;
528  TRACEP(p, DBG, "sending: "<<buf);
529 
530  // Send back to user
531  if (buf) {
532  response->Send(buf, len);
533  } else {
534  // Something wrong
535  response->Send(kXR_InvalidRequest, "GetWorkers failed");
536  return 0;
537  }
538 
539  // Over
540  return 0;
541 }
542 
543 ////////////////////////////////////////////////////////////////////////////////
544 /// Handle request for setting group properties
545 
547 {
548  XPDLOC(ALL, "Admin::SetGroupProperties")
549 
550  int rc = 1;
551  XPD_SETRESP(p, "SetGroupProperties");
552 
553  // User's group
554  int len = p->Request()->header.dlen;
555  char *grp = new char[len+1];
556  memcpy(grp, p->Argp()->buff, len);
557  grp[len] = 0;
558  TRACEP(p, DBG, "request to change priority for group '"<< grp<<"'");
559 
560  // Make sure is the current one of the user
561  if (strcmp(grp, p->Client()->UI().fGroup.c_str())) {
562  TRACEP(p, XERR, "received group does not match the user's one");
563  response->Send(kXR_InvalidRequest,
564  "SetGroupProperties: received group does not match the user's one");
565  SafeDelArray(grp);
566  return 0;
567  }
568 
569  // The priority value
570  int priority = ntohl(p->Request()->proof.int2);
571 
572  // Tell the priority manager
573  if (fMgr && fMgr->PriorityMgr()) {
574  XrdOucString buf;
575  XPDFORM(buf, "%s %d", grp, priority);
577  buf.c_str()) != 0) {
578  TRACEP(p, XERR, "problem sending message on the pipe");
579  response->Send(kXR_ServerError,
580  "SetGroupProperties: problem sending message on the pipe");
581  SafeDelArray(grp);
582  return 0;
583  }
584  }
585 
586  // Notify
587  TRACEP(p, REQ, "priority for group '"<< grp<<"' has been set to "<<priority);
588 
589  SafeDelArray(grp);
590 
591  // Acknowledge user
592  response->Send();
593 
594  // Over
595  return 0;
596 }
597 
598 ////////////////////////////////////////////////////////////////////////////////
599 /// Handle request for sending a message to a user
600 
602 {
603  XPDLOC(ALL, "Admin::SendMsgToUser")
604 
605  int rc = 0;
606  XPD_SETRESP(p, "SendMsgToUser");
607 
608  // Target client (default us)
609  XrdProofdClient *tgtclnt = p->Client();
610  XrdProofdClient *c = 0;
611  std::list<XrdProofdClient *>::iterator i;
612 
613  // Extract the user name, if any
614  int len = p->Request()->header.dlen;
615  if (len <= 0) {
616  // No message: protocol error?
617  TRACEP(p, XERR, "no message");
618  response->Send(kXR_InvalidRequest,"SendMsgToUser: no message");
619  return 0;
620  }
621 
622  XrdOucString cmsg((const char *)p->Argp()->buff, len);
623  XrdOucString usr;
624  if (cmsg.beginswith("u:")) {
625  // Extract user
626  int isp = cmsg.find(' ');
627  if (isp != STR_NPOS) {
628  usr.assign(cmsg, 2, isp-1);
629  cmsg.erase(0, isp+1);
630  }
631  if (usr.length() > 0) {
632  TRACEP(p, REQ, "request for user: '"<<usr<<"'");
633  // Find the client instance
634  bool clntfound = 0;
635  if ((c = fMgr->ClientMgr()->GetClient(usr.c_str(), 0))) {
636  tgtclnt = c;
637  clntfound = 1;
638  }
639  if (!clntfound) {
640  // No user: protocol error?
641  TRACEP(p, XERR, "target client not found");
642  response->Send(kXR_InvalidRequest,
643  "SendMsgToUser: target client not found");
644  return 0;
645  }
646  }
647  }
648  // Recheck message length
649  if (cmsg.length() <= 0) {
650  // No message: protocol error?
651  TRACEP(p, XERR, "no message after user specification");
652  response->Send(kXR_InvalidRequest,
653  "SendMsgToUser: no message after user specification");
654  return 0;
655  }
656 
657  // Check if allowed
658  if (!p->SuperUser()) {
659  if (usr.length() > 0) {
660  if (tgtclnt != p->Client()) {
661  TRACEP(p, XERR, "not allowed to send messages to usr '"<<usr<<"'");
662  response->Send(kXR_InvalidRequest,
663  "SendMsgToUser: not allowed to send messages to specified usr");
664  return 0;
665  }
666  } else {
667  TRACEP(p, XERR, "not allowed to send messages to connected users");
668  response->Send(kXR_InvalidRequest,
669  "SendMsgToUser: not allowed to send messages to connected users");
670  return 0;
671  }
672  } else {
673  if (usr.length() <= 0) tgtclnt = 0;
674  }
675 
676  // The clients to notified
677  fMgr->ClientMgr()->Broadcast(tgtclnt, cmsg.c_str());
678 
679  // Acknowledge user
680  response->Send();
681 
682  // Over
683  return 0;
684 }
685 
686 ////////////////////////////////////////////////////////////////////////////////
687 /// Handle request for list of sessions
688 
690 {
691  XPDLOC(ALL, "Admin::QuerySessions")
692 
693  int rc = 0;
694  XPD_SETRESP(p, "QuerySessions");
695 
696  XrdOucString notmsg, msg;
697  { // This is needed to block the session checks
699  msg = p->Client()->ExportSessions(notmsg, response);
700  }
701 
702  if (notmsg.length() > 0) {
703  // Some sessions seem non-responding: notify the client
704  response->Send(kXR_attn, kXPD_srvmsg, 0, (char *) notmsg.c_str(), notmsg.length());
705  }
706 
707  TRACEP(p, DBG, "sending: "<<msg);
708 
709  // Send back to user
710  response->Send((void *)msg.c_str(), msg.length()+1);
711 
712  // Over
713  return 0;
714 }
715 
716 ////////////////////////////////////////////////////////////////////////////////
717 /// Handle request for log paths
718 
720 {
721  XPDLOC(ALL, "Admin::QueryLogPaths")
722 
723  int rc = 0;
724  XPD_SETRESP(p, "QueryLogPaths");
725 
726  int ridx = ntohl(p->Request()->proof.int2);
727  bool broadcast = (ntohl(p->Request()->proof.int3) == 1) ? 1 : 0;
728 
729  // Find out for which session is this request
730  XrdOucString stag, master, user, ord, buf;
731  int len = p->Request()->header.dlen;
732  if (len > 0) {
733  buf.assign(p->Argp()->buff,0,len-1);
734  int im = buf.find("|master:");
735  int iu = buf.find("|user:");
736  int io = buf.find("|ord:");
737  stag = buf;
738  stag.erase(stag.find("|"));
739  if (im != STR_NPOS) {
740  master.assign(buf, im + strlen("|master:"));
741  master.erase(master.find("|"));
742  }
743  if (iu != STR_NPOS) {
744  user.assign(buf, iu + strlen("|user:"));
745  user.erase(user.find("|"));
746  }
747  if (io != STR_NPOS) {
748  ord.assign(buf, iu + strlen("|ord:"));
749  ord.erase(user.find("|"));
750  }
751  if (stag.beginswith('*'))
752  stag = "";
753  }
754  TRACEP(p, DBG, "master: "<<master<<", user: "<<user<<", ord: "<<ord<<", stag: "<<stag);
755 
756  XrdProofdClient *client = (user.length() > 0) ? 0 : p->Client();
757  if (!client)
758  // Find the client instance
759  client = fMgr->ClientMgr()->GetClient(user.c_str(), 0);
760  if (!client) {
761  TRACEP(p, XERR, "query sess logs: client for '"<<user<<"' not found");
762  response->Send(kXR_InvalidRequest,"QueryLogPaths: query log: client not found");
763  return 0;
764  }
765 
766  XrdOucString tag = (stag == "" && ridx >= 0) ? "last" : stag;
767  if (stag == "" && client->Sandbox()->GuessTag(tag, ridx) != 0) {
768  TRACEP(p, XERR, "query sess logs: session tag not found");
769  response->Send(kXR_InvalidRequest,"QueryLogPaths: query log: session tag not found");
770  return 0;
771  }
772 
773  // Return message
774  XrdOucString rmsg;
775 
776  if (master.length() <= 0) {
777  // The session tag first
778  rmsg += tag; rmsg += "|";
779  // The pool URL second
780  rmsg += fMgr->PoolURL(); rmsg += "|";
781  }
782 
783  // Locate the local log file
784  XrdOucString sdir(client->Sandbox()->Dir());
785  sdir += "/session-";
786  sdir += tag;
787 
788  // Open dir
789  DIR *dir = opendir(sdir.c_str());
790  if (!dir) {
791  XrdOucString msg("cannot open dir ");
792  msg += sdir; msg += " (errno: "; msg += errno; msg += ")";
793  TRACEP(p, XERR, msg.c_str());
794  response->Send(kXR_InvalidRequest, msg.c_str());
795  return 0;
796  }
797 
798  // Masters have the .workers file
799  XrdOucString wfile(sdir);
800  wfile += "/.workers";
801  bool ismaster = (access(wfile.c_str(), F_OK) == 0) ? 1 : 0;
802 
803  // Scan the directory to add the top master (only if top master)
804  XrdOucString xo, logtag, xf;
805  int ilog, idas, iund1, iund2;
806  struct dirent *ent = 0;
807  while ((ent = (struct dirent *)readdir(dir))) {
808  if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue;
809  XPDFORM(xf, "%s/%s", sdir.c_str(), (const char *) ent->d_name);
810  struct stat st;
811  if (stat(xf.c_str(), &st) != 0) continue;
812  if (!S_ISREG(st.st_mode)) continue;
813  xo = ent->d_name;
814  if (xo.matches("*-*-*-*-*.log") <= 0 && xo.matches("*-*-*-*-*.valgrind.log") <= 0) continue;
815  TRACEP(p, ALL, "xf: "<<xf<<"; st_mode: "<<st.st_mode);
816  bool recordinfo = 0;
817  if ((ilog = xo.find(".log")) != STR_NPOS) {
818  xo.replace(".log", "");
819 
820  // If it is an "additional" logfile, extract a "tag" identifying it
821  // from the filename. Tag is in format: __<tag>__
822  iund1 = xo.find("__");
823  if (iund1 != STR_NPOS) {
824  iund2 = xo.rfind("__");
825  if ((iund2 != STR_NPOS) && (iund2 != iund1)) {
826  logtag = xo;
827  logtag.erase(iund2);
828  logtag.erase(0, iund1+2);
829  }
830  }
831 
832  if ((idas = xo.find('-')) != STR_NPOS) xo.erase(0, idas + 1);
833  if ((idas = xo.find('-')) != STR_NPOS) xo.erase(idas);
834  if (ord.length() > 0 && (ord == xo)) {
835  recordinfo = 1;
836  } else {
837  if (ismaster && !broadcast) {
838  if (!strncmp(ent->d_name, "master-", 7)) recordinfo = 1;
839  } else {
840  recordinfo = 1;
841  }
842  }
843  if (recordinfo) {
844  rmsg += "|"; rmsg += xo;
845  if (logtag != "") { rmsg += '('; rmsg += logtag; rmsg += ')'; }
846  rmsg += " proof://"; rmsg += fMgr->Host(); rmsg += ':';
847  rmsg += fMgr->Port(); rmsg += '/';
848  rmsg += sdir; rmsg += '/'; rmsg += ent->d_name;
849  }
850  }
851  }
852  // Close dir
853  closedir(dir);
854 
855  // If required and it makes sense, ask the underlying nodes
856  if (broadcast && ismaster) {
857  XrdOucString msg(tag);
858  msg += "|master:";
859  msg += fMgr->Host();
860  msg += "|user:";
861  msg += client->User();
862  char *bmst = fMgr->NetMgr()->ReadLogPaths(msg.c_str(), ridx);
863  if (bmst) {
864  rmsg += bmst;
865  free(bmst);
866  }
867  } else if (ismaster) {
868  // Get info from the .workers file
869  // Now open the workers file
870  FILE *f = fopen(wfile.c_str(), "r");
871  if (f) {
872  char ln[2048];
873  while (fgets(ln, sizeof(ln), f)) {
874  if (ln[strlen(ln)-1] == '\n')
875  ln[strlen(ln)-1] = 0;
876  // Locate status and url
877  char *ps = strchr(ln, ' ');
878  if (ps) {
879  *ps = 0;
880  ps++;
881  // Locate ordinal
882  char *po = strchr(ps, ' ');
883  if (po) {
884  po++;
885  // Locate path
886  char *pp = strchr(po, ' ');
887  if (pp) {
888  *pp = 0;
889  pp++;
890  // Record now
891  rmsg += "|"; rmsg += po; rmsg += " ";
892  if (master.length() > 0) {
893  rmsg += master;
894  rmsg += ",";
895  }
896  rmsg += ln; rmsg += '/';
897  rmsg += pp;
898  // Reposition on the file name
899  char *ppl = strrchr(pp, '/');
900  pp = (ppl) ? ppl : pp;
901  // If the line is for a submaster, we have to get the info
902  // about its workers
903  bool ismst = (strstr(pp, "master-")) ? 1 : 0;
904  if (ismst) {
905  XrdClientUrlInfo u((const char *)&ln[0]);
906  XrdOucString msg(stag);
907  msg += "|master:";
908  msg += ln;
909  msg += "|user:";
910  msg += u.User;
911  u.User = p->Client()->User() ? p->Client()->User() : fMgr->EffectiveUser();
912  char *bmst = fMgr->NetMgr()->ReadLogPaths(u.GetUrl().c_str(), msg.c_str(), ridx);
913  if (bmst) {
914  rmsg += bmst;
915  free(bmst);
916  }
917  }
918  }
919  }
920  }
921  }
922  fclose(f);
923  }
924  }
925 
926  // Send back to user
927  response->Send((void *) rmsg.c_str(), rmsg.length()+1);
928 
929  // Over
930  return 0;
931 }
932 
933 ////////////////////////////////////////////////////////////////////////////////
934 /// Handle request of
935 
937 {
938  XPDLOC(ALL, "Admin::CleanupSessions")
939 
940  int rc = 0;
941  XPD_SETRESP(p, "CleanupSessions");
942 
943  XrdOucString cmsg;
944 
945  // Target client (default us)
946  XrdProofdClient *tgtclnt = p->Client();
947 
948  // If super user we may be requested to cleanup everything
949  bool all = 0;
950  char *usr = 0;
951  bool clntfound = 1;
952  if (p->SuperUser()) {
953  int what = ntohl(p->Request()->proof.int2);
954  all = (what == 1) ? 1 : 0;
955 
956  if (!all) {
957  // Get a user name, if any.
958  // A super user can ask cleaning for clients different from itself
959  char *buf = 0;
960  int len = p->Request()->header.dlen;
961  if (len > 0) {
962  clntfound = 0;
963  buf = p->Argp()->buff;
964  len = (len < 9) ? len : 8;
965  } else {
966  buf = (char *) p->Client()->User();
967  len = strlen(p->Client()->User());
968  }
969  if (len > 0) {
970  usr = new char[len+1];
971  memcpy(usr, buf, len);
972  usr[len] = '\0';
973  // Group info, if any
974  char *grp = strstr(usr, ":");
975  if (grp)
976  *grp++ = 0;
977  // Find the client instance
978  XrdProofdClient *c = fMgr->ClientMgr()->GetClient(usr, grp);
979  if (c) {
980  tgtclnt = c;
981  clntfound = 1;
982  }
983  TRACEP(p, REQ, "superuser, cleaning usr: "<< usr);
984  }
985  } else {
986  tgtclnt = 0;
987  TRACEP(p, REQ, "superuser, all sessions cleaned");
988  }
989  } else {
990  // Define the user name for later transactions (their executed under
991  // the admin name)
992  int len = strlen(tgtclnt->User()) + 1;
993  usr = new char[len+1];
994  memcpy(usr, tgtclnt->User(), len);
995  usr[len] = '\0';
996  }
997 
998  // We cannot continue if we do not have anything to clean
999  if (!clntfound) {
1000  TRACEP(p, DBG, "client '"<<usr<<"' has no sessions - do nothing");
1001  }
1002 
1003  // hard or soft (always hard for old clients)
1004  bool hard = (ntohl(p->Request()->proof.int3) == 1 || p->ProofProtocol() < 18) ? 1 : 0;
1005  const char *lab = hard ? "hard-reset" : "soft-reset";
1006 
1007  // Asynchronous notification to requester
1008  if (fMgr->SrvType() != kXPD_Worker) {
1009  XPDFORM(cmsg, "CleanupSessions: %s: signalling active sessions for termination", lab);
1010  response->Send(kXR_attn, kXPD_srvmsg, (char *) cmsg.c_str(), cmsg.length());
1011  }
1012 
1013  // Send a termination request to client sessions
1014  XPDFORM(cmsg, "CleanupSessions: %s: cleaning up client: requested by: %s", lab, p->Link()->ID);
1015  int srvtype = ntohl(p->Request()->proof.int2);
1016  fMgr->ClientMgr()->TerminateSessions(tgtclnt, cmsg.c_str(), srvtype);
1017 
1018  // Forward down the tree only if not leaf
1019  if (hard && fMgr->SrvType() != kXPD_Worker) {
1020 
1021  // Asynchronous notification to requester
1022  XPDFORM(cmsg, "CleanupSessions: %s: forwarding the reset request to next tier(s) ", lab);
1023  response->Send(kXR_attn, kXPD_srvmsg, 0, (char *) cmsg.c_str(), cmsg.length());
1024 
1025  int type = ntohl(p->Request()->proof.int1);
1026  fMgr->NetMgr()->Broadcast(type, usr, p->Client()->User(), response, 1);
1027  }
1028 
1029  // Wait just a bit before testing the activity of the session manager
1030  sleep(1);
1031 
1032  // Additional waiting (max 10 secs) depends on the activity of the session manager
1033  int twait = 10;
1034  while (twait-- > 0 &&
1036  if (twait < 7) {
1037  XPDFORM(cmsg, "CleanupSessions: %s: wait %d more seconds for completion ...", lab, twait);
1038  response->Send(kXR_attn, kXPD_srvmsg, 0, (char *) cmsg.c_str(), cmsg.length());
1039  }
1040  sleep(1);
1041  }
1042 
1043  // Cleanup usr
1044  SafeDelArray(usr);
1045 
1046  // Acknowledge user
1047  response->Send();
1048 
1049  // Over
1050  return 0;
1051 }
1052 
1053 ////////////////////////////////////////////////////////////////////////////////
1054 /// Handle request for setting the session alias
1055 
1057 {
1058  XPDLOC(ALL, "Admin::SetSessionAlias")
1059 
1060  int rc = 0;
1061  XPD_SETRESP(p, "SetSessionAlias");
1062 
1063  //
1064  // Specific info about a session
1065  int psid = ntohl(p->Request()->proof.sid);
1066  XrdProofdProofServ *xps = 0;
1067  if (!p->Client() || !(xps = p->Client()->GetServer(psid))) {
1068  TRACEP(p, XERR, "session ID not found: "<<psid);
1069  response->Send(kXR_InvalidRequest,"SetSessionAlias: session ID not found");
1070  return 0;
1071  }
1072 
1073  // Set session alias
1074  const char *msg = (const char *) p->Argp()->buff;
1075  int len = p->Request()->header.dlen;
1076  if (len > kXPROOFSRVALIASMAX - 1)
1077  len = kXPROOFSRVALIASMAX - 1;
1078 
1079  // Save tag
1080  if (len > 0 && msg) {
1081  xps->SetAlias(msg);
1082  if (TRACING(DBG)) {
1083  XrdOucString alias(xps->Alias());
1084  TRACEP(p, DBG, "session alias set to: "<<alias);
1085  }
1086  }
1087 
1088  // Acknowledge user
1089  response->Send();
1090 
1091  // Over
1092  return 0;
1093 }
1094 
1095 ////////////////////////////////////////////////////////////////////////////////
1096 /// Handle request for setting the session tag
1097 
1099 {
1100  XPDLOC(ALL, "Admin::SetSessionTag")
1101 
1102  int rc = 0;
1103  XPD_SETRESP(p, "SetSessionTag");
1104  //
1105  // Specific info about a session
1106  int psid = ntohl(p->Request()->proof.sid);
1107  XrdProofdProofServ *xps = 0;
1108  if (!p->Client() || !(xps = p->Client()->GetServer(psid))) {
1109  TRACEP(p, XERR, "session ID not found: "<<psid);
1110  response->Send(kXR_InvalidRequest,"SetSessionTag: session ID not found");
1111  return 0;
1112  }
1113 
1114  // Set session tag
1115  const char *msg = (const char *) p->Argp()->buff;
1116  int len = p->Request()->header.dlen;
1117  if (len > kXPROOFSRVTAGMAX - 1)
1118  len = kXPROOFSRVTAGMAX - 1;
1119 
1120  // Save tag
1121  if (len > 0 && msg) {
1122  xps->SetTag(msg);
1123  if (TRACING(DBG)) {
1124  XrdOucString tag(xps->Tag());
1125  TRACEP(p, DBG, "session tag set to: "<<tag);
1126  }
1127  }
1128 
1129  // Acknowledge user
1130  response->Send();
1131 
1132  // Over
1133  return 0;
1134 }
1135 
1136 ////////////////////////////////////////////////////////////////////////////////
1137 /// Handle request for releasing a worker
1138 
1140 {
1141  XPDLOC(ALL, "Admin::ReleaseWorker")
1142 
1143  int rc = 0;
1144  XPD_SETRESP(p, "ReleaseWorker");
1145  //
1146  // Specific info about a session
1147  int psid = ntohl(p->Request()->proof.sid);
1148  XrdProofdProofServ *xps = 0;
1149  if (!p->Client() || !(xps = p->Client()->GetServer(psid))) {
1150  TRACEP(p, XERR, "session ID not found: "<<psid);
1151  response->Send(kXR_InvalidRequest,"ReleaseWorker: session ID not found");
1152  return 0;
1153  }
1154 
1155  // Set session tag
1156  const char *msg = (const char *) p->Argp()->buff;
1157  int len = p->Request()->header.dlen;
1158  if (len > kXPROOFSRVTAGMAX - 1)
1159  len = kXPROOFSRVTAGMAX - 1;
1160 
1161  // Save tag
1162  if (len > 0 && msg) {
1163  xps->RemoveWorker(msg);
1164  TRACEP(p, DBG, "worker \""<<msg<<"\" released");
1165  if (TRACING(HDBG)) fMgr->NetMgr()->Dump();
1166  }
1167 
1168  // Acknowledge user
1169  response->Send();
1170 
1171  // Over
1172  return 0;
1173 }
1174 
1175 ////////////////////////////////////////////////////////////////////////////////
1176 /// Check is 's' contains any of the forbidden chars '(){};'
1177 /// Return 0 if OK (no forbidden chars), -1 in not OK
1178 
1180 {
1181  int len = 0;
1182  if (!s || (len = strlen(s)) <= 0) return 0;
1183 
1184  int j = len;
1185  while (j--) {
1186  char c = s[j];
1187  if (c == '(' || c == ')' || c == '{' || c == '}' || c == ';') {
1188  return -1;
1189  }
1190  }
1191  // Done
1192  return 0;
1193 }
1194 
1195 ////////////////////////////////////////////////////////////////////////////////
1196 /// Handle request of cleaning parts of the sandbox
1197 
1199 {
1200  XPDLOC(ALL, "Admin::Exec")
1201 
1202  // Commands; must be synchronized with EAdminExecType in XProofProtocol.h
1203 #if !defined(__APPLE__)
1204  const char *cmds[] = { "rm", "ls", "more", "grep", "tail", "md5sum", "stat", "find" };
1205 #else
1206  const char *cmds[] = { "rm", "ls", "more", "grep", "tail", "md5", "stat", "find" };
1207 #endif
1208  const char *actcmds[] = { "remove", "access", "open", "open", "open", "open", "stat", "find"};
1209 
1210  int rc = 0;
1211  XPD_SETRESP(p, "Exec");
1212 
1213  XrdOucString emsg;
1214 
1215  // Target client (default us)
1216  XrdProofdClient *tgtclnt = p->Client();
1217  if (!tgtclnt) {
1218  emsg = "client instance not found";
1219  TRACEP(p, XERR, emsg);
1220  response->Send(kXR_InvalidRequest, emsg.c_str());
1221  return 0;
1222  }
1223 
1224  // Action type
1225  int action = ntohl(p->Request()->proof.int2);
1226  if (action < kRm || action > kFind) {
1227  emsg = "unknown action type: ";
1228  emsg += action;
1229  TRACEP(p, XERR, emsg);
1230  response->Send(kXR_InvalidRequest, emsg.c_str());
1231  return 0;
1232  }
1233 
1234  // Parse the string
1235  int dlen = p->Request()->header.dlen;
1236  XrdOucString msg, node, path, opt;
1237  if (dlen > 0 && p->Argp()->buff) {
1238  msg.assign((const char *)p->Argp()->buff, 0, dlen);
1239  // Parse
1240  emsg = "";
1241  int from = 0;
1242  if ((from = msg.tokenize(node, from, '|')) != -1) {
1243  if ((from = msg.tokenize(path, from, '|')) != -1) {
1244  from = msg.tokenize(opt, from, '|');
1245  } else {
1246  emsg = "'path' not found in message";
1247  }
1248  } else {
1249  emsg = "'node' not found in message";
1250  }
1251  if (emsg.length() > 0) {
1252  TRACEP(p, XERR, emsg);
1253  response->Send(kXR_InvalidRequest, emsg.c_str());
1254  return 0;
1255  }
1256  }
1257 
1258  // Path and opt cannot contain multiple commands (e.g. file; rm *)
1259  if (CheckForbiddenChars(path.c_str()) != 0) {
1260  emsg = "none of the characters '(){};' are allowed in path string ("; emsg += path; emsg += ")";
1261  TRACEP(p, XERR, emsg);
1262  response->Send(kXR_InvalidRequest, emsg.c_str());
1263  return 0;
1264  }
1265  if (CheckForbiddenChars(opt.c_str()) != 0) {
1266  emsg = "none of the characters '(){};' are allowed in opt string ("; emsg += opt; emsg += ")";
1267  TRACEP(p, XERR, emsg);
1268  response->Send(kXR_InvalidRequest, emsg.c_str());
1269  return 0;
1270  }
1271 
1272  // Check if we have to forward this request
1273  XrdOucString result;
1274  bool islocal = fMgr->NetMgr()->IsLocal(node.c_str(), 1);
1275  if (fMgr->SrvType() != kXPD_Worker) {
1276  int type = ntohl(p->Request()->proof.int1);
1277  if (node == "all") {
1278  if (action == kStat || action == kMd5sum) {
1279  emsg = "action cannot be run in mode 'all' - running on master only";
1280  response->Send(kXR_attn, kXPD_srvmsg, 2, (char *)emsg.c_str(), emsg.length());
1281  } else {
1282  fMgr->NetMgr()->Broadcast(type, msg.c_str(), p->Client()->User(), response, 0, action);
1283  }
1284  } else if (!islocal) {
1285  // Create 'url'
1286  XrdOucString u = (p->Client()->User()) ? p->Client()->User() : fMgr->EffectiveUser();
1287  u += '@';
1288  u += node;
1289  TRACEP(p, HDBG, "sending request to "<<u);
1290  // Send request
1291  XrdClientMessage *xrsp;
1292  if (!(xrsp = fMgr->NetMgr()->Send(u.c_str(), type, msg.c_str(), 0, response, 0, action))) {
1293  TRACEP(p, XERR, "problems sending request to "<<u);
1294  } else {
1295  if (action == kStat || action == kMd5sum) {
1296  // Extract the result
1297  result.assign((const char *) xrsp->GetData(), 0, xrsp->DataLen());
1298  } else if (action == kRm) {
1299  // Send 'OK'
1300  result = "OK";
1301  }
1302  }
1303  // Cleanup answer
1304  SafeDel(xrsp);
1305  }
1306  }
1307 
1308  // We may not have been requested to execute the command
1309  if (node != "all" && !islocal) {
1310  // We are done: acknowledge user ...
1311  if (result.length() > 0) {
1312  response->Send(result.c_str());
1313  } else {
1314  response->Send();
1315  }
1316  // ... and go
1317  return 0;
1318  }
1319 
1320  // Here we execute the request
1321  XrdOucString cmd, pfx(fMgr->Host());
1322  pfx += ":"; pfx += fMgr->Port();
1323 
1324  // Notify the client
1325  if (node != "all") {
1326  if (action != kStat && action != kMd5sum && action != kRm) {
1327  emsg = "Node: "; emsg += pfx;
1328  emsg += "\n-----";
1329  response->Send(kXR_attn, kXPD_srvmsg, 2, (char *)emsg.c_str(), emsg.length());
1330  }
1331  pfx = "";
1332  } else {
1333  pfx += "| ";
1334  }
1335 
1336  // Get the full path, check if in sandbox and if the user is allowed
1337  // to access it
1338  XrdOucString fullpath(path);
1339  bool sandbox = 0;
1340  bool haswild = (fullpath.find('*') != STR_NPOS) ? 1 : 0;
1341  int check = (action == kMore || action == kTail ||
1342  action == kGrep || action == kMd5sum) ? 2 : 1;
1343  if ((action == kRm || action == kLs) && haswild) check = 0;
1344  int rccp = 0;
1345  struct stat st;
1346  if ((rccp = CheckPath(p->SuperUser(), tgtclnt->Sandbox()->Dir(),
1347  fullpath, check, sandbox, &st, emsg)) != 0) {
1348  if (rccp == -2) {
1349  emsg = cmds[action];
1350  emsg += ": cannot ";
1351  emsg += actcmds[action];
1352  emsg += " `";
1353  emsg += fullpath;
1354  emsg += "': No such file or directory";
1355  } else if (rccp == -3) {
1356  emsg = cmds[action];
1357  emsg += ": cannot stat ";
1358  emsg += fullpath;
1359  emsg += ": errno: ";
1360  emsg += (int) errno;
1361  } else if (rccp == -4) {
1362  emsg = cmds[action];
1363  emsg += ": ";
1364  emsg += fullpath;
1365  emsg += ": Is not a regular file";
1366  }
1367  TRACEP(p, XERR, emsg);
1368  response->Send(kXR_InvalidRequest, emsg.c_str());
1369  return 0;
1370  }
1371 
1372  // Additional checks for remove requests
1373  if (action == kRm) {
1374  // Ownership required and no support for wild cards for absolute paths
1375  if (!sandbox) {
1376  if (haswild) {
1377  emsg = "not allowed to rm with wild cards on path: ";
1378  emsg += fullpath;
1379  TRACEP(p, XERR, emsg);
1380  response->Send(kXR_InvalidRequest, emsg.c_str());
1381  return 0;
1382  }
1383  if ((int) st.st_uid != tgtclnt->UI().fUid || (int) st.st_gid != tgtclnt->UI().fGid) {
1384  emsg = "rm on path: ";
1385  emsg += fullpath;
1386  emsg += " requires ownership; path owned by: (";
1387  emsg += (int) st.st_uid; emsg += ",";
1388  emsg += (int) st.st_gid; emsg += ")";
1389  TRACEP(p, XERR, emsg);
1390  response->Send(kXR_InvalidRequest, emsg.c_str());
1391  return 0;
1392  }
1393  } else {
1394  // Will not allow to remove basic sandbox sub-dirs
1395  const char *sbdir[5] = {"queries", "packages", "cache", "datasets", "data"};
1396  while (fullpath.endswith('/'))
1397  fullpath.erasefromend(1);
1398  XrdOucString sball(tgtclnt->Sandbox()->Dir()), sball1 = sball;
1399  sball += "/*"; sball1 += "/*/";
1400  if (fullpath == sball || fullpath == sball1) {
1401  emsg = "removing all sandbox directory is not allowed: ";
1402  emsg += fullpath;
1403  TRACEP(p, XERR, emsg);
1404  response->Send(kXR_InvalidRequest, emsg.c_str());
1405  return 0;
1406  }
1407  int kk = 5;
1408  while (kk--) {
1409  if (fullpath.endswith(sbdir[kk])) {
1410  emsg = "removing a basic sandbox directory is not allowed: ";
1411  emsg += fullpath;
1412  TRACEP(p, XERR, emsg);
1413  response->Send(kXR_InvalidRequest, emsg.c_str());
1414  return 0;
1415  }
1416  }
1417  }
1418 
1419  // Prepare the command
1420  cmd = cmds[action];
1421  if (opt.length() <= 0) opt = "-f";
1422  cmd += " "; cmd += opt;
1423  cmd += " "; cmd += fullpath;
1424  cmd += " 2>&1";
1425 
1426  } else {
1427 
1428  XrdOucString rederr;
1429  cmd = cmds[action];
1430  switch (action) {
1431  case kLs:
1432  if (opt.length() <= 0) opt = "-C";
1433  rederr = " 2>&1";
1434  break;
1435  case kMore:
1436  case kGrep:
1437  case kTail:
1438  case kFind:
1439  rederr = " 2>&1";
1440  break;
1441  case kStat:
1442  cmd = "";
1443  opt = "";
1444  break;
1445  case kMd5sum:
1446  opt = "";
1447  rederr = " 2>&1";
1448  break;
1449  default:
1450  emsg = "undefined action: ";
1451  emsg = action;
1452  emsg = " - protocol error!";
1453  TRACEP(p, XERR, emsg);
1454  response->Send(kXR_ServerError, emsg.c_str());
1455  break;
1456  }
1457  if (action != kFind) {
1458  if (cmd.length() > 0) cmd += " ";
1459  if (opt.length() > 0) { cmd += opt; cmd += " ";}
1460  cmd += fullpath;
1461  } else {
1462  cmd += " "; cmd += fullpath;
1463  if (opt.length() > 0) { cmd += " "; cmd += opt; }
1464  }
1465  if (rederr.length() > 0) cmd += rederr;
1466  }
1467 
1468  // Run the command now
1469  emsg = pfx;
1470  if (ExecCmd(p, response, action, cmd.c_str(), emsg) != 0) {
1471  TRACEP(p, XERR, emsg);
1472  response->Send(kXR_ServerError, emsg.c_str());
1473  } else {
1474  // Done
1475  switch (action) {
1476  case kStat:
1477  case kMd5sum:
1478  response->Send(emsg.c_str());
1479  break;
1480  case kRm:
1481  response->Send("OK");
1482  break;
1483  default:
1484  response->Send();
1485  break;
1486  }
1487  }
1488 
1489  // Over
1490  return 0;
1491 }
1492 
1493 ////////////////////////////////////////////////////////////////////////////////
1494 /// Low-level execution handler. The commands must be executed in user space.
1495 /// We do that by forking and logging as user in the forked instance. The
1496 /// parent will just send over te messages received from the user-child via
1497 /// the pipe.
1498 /// Return 0 on success, -1 on error
1499 
1501  int action, const char *cmd, XrdOucString &emsg)
1502 {
1503  XPDLOC(ALL, "Admin::ExecCmd")
1504 
1505  int rc = 0;
1506  XrdOucString pfx = emsg;
1507  emsg = "";
1508 
1509  // We do it via the shell
1510  if (!cmd || strlen(cmd) <= 0) {
1511  emsg = "undefined command!";
1512  return -1;
1513  }
1514 
1515  // Pipe for child-to-parent communications
1516  XrdProofdPipe pp;
1517  if (!pp.IsValid()) {
1518  emsg = "cannot create the pipe";
1519  return -1;
1520  }
1521 
1522  // Fork a test agent process to handle this session
1523  TRACEP(p, DBG, "forking to execute in the private sandbox");
1524  int pid = -1;
1525  if (!(pid = fMgr->Sched()->Fork("adminexeccmd"))) {
1526  // Child process
1527  // We set to the user environment as we must to run the command
1528  // in the user space
1529  if (fMgr->SessionMgr()->SetUserEnvironment(p) != 0) {
1530  emsg = "SetUserEnvironment did not return OK";
1531  rc = 1;
1532  } else {
1533  // Execute the command
1534  if (action == kStat) {
1535  struct stat st;
1536  if ((stat(cmd, &st)) != 0) {
1537  if (errno == ENOENT) {
1538  emsg += "stat: cannot stat `";
1539  emsg += cmd;
1540  emsg += "': No such file or directory";
1541  } else {
1542  emsg += "stat: cannot stat ";
1543  emsg += cmd;
1544  emsg += ": errno: ";
1545  emsg += (int) errno;
1546  }
1547  } else {
1548  // Fill the buffer and go
1549  char msg[256];
1550  int islink = S_ISLNK(st.st_mode);
1551  snprintf(msg, 256, "%ld %ld %d %d %d %lld %ld %d", (long)st.st_dev,
1552  (long)st.st_ino, st.st_mode, (int)(st.st_uid),
1553  (int)(st.st_gid), (kXR_int64)st.st_size, st.st_mtime, islink);
1554  emsg = msg;
1555  }
1556  } else {
1557  // Execute the command in a pipe
1558  FILE *fp = popen(cmd, "r");
1559  if (!fp) {
1560  emsg = "could not run '"; emsg += cmd; emsg += "'";
1561  rc = 1;
1562  } else {
1563  // Read line by line
1564  int pfxlen = pfx.length();
1565  int len = 0;
1566  char line[2048];
1567  char buf[1024];
1568  int bufsiz = 1024, left = bufsiz - 1, lines = 0;
1569  while (fgets(line, sizeof(line), fp)) {
1570  // Parse the line
1571  int llen = strlen(line);
1572  lines++;
1573  // If md5sum, we need to parse only the first line
1574  if (lines == 1 && action == kMd5sum) {
1575  if (line[llen-1] == '\n') {
1576  line[llen-1] = '\0';
1577  llen--;
1578  }
1579 #if !defined(__APPLE__)
1580  // The first token
1581  XrdOucString sl(line);
1582  sl.tokenize(emsg, 0, ' ');
1583 #else
1584  // The last token
1585  XrdOucString sl(line), tkn;
1586  int from = 0;
1587  while ((from = sl.tokenize(tkn, from, ' ')) != STR_NPOS) {
1588  emsg = tkn;
1589  }
1590 #endif
1591  break;
1592  }
1593  // Send over this part, if no more space
1594  if ((llen + pfxlen) > left) {
1595  buf[len] = '\0';
1596  if (buf[len-1] == '\n') buf[len-1] = '\0';
1597  if (r->Send(kXR_attn, kXPD_srvmsg, 2, (char *) &buf[0], len) != 0) {
1598  emsg = "error sending message to requester";
1599  rc = 1;
1600  break;
1601  }
1602  buf[0] = 0;
1603  len = 0;
1604  left = bufsiz -1;
1605  }
1606  // Add prefix to the buffer, if any
1607  if (pfxlen > 0) {
1608  memcpy(buf+len, pfx.c_str(), pfxlen);
1609  len += pfxlen;
1610  left -= pfxlen;
1611  }
1612  // Add line to the buffer
1613  memcpy(buf+len, line, llen);
1614  len += llen;
1615  left -= llen;
1616  // Check if we have been interrupted
1617  if (lines > 0 && !(lines % 10)) {
1618  char b[1];
1619  if (p->Link()->Peek(&b[0], 1, 0) == 1) {
1620  p->Process(p->Link());
1621  if (p->IsCtrlC()) break;
1622  }
1623  }
1624  }
1625  // Send the last bunch
1626  if (len > 0) {
1627  buf[len] = '\0';
1628  if (buf[len-1] == '\n') buf[len-1] = '\0';
1629  if (r->Send(kXR_attn, kXPD_srvmsg, 2, (char *) &buf[0], len) != 0) {
1630  emsg = "error sending message to requester";
1631  rc = 1;
1632  }
1633  }
1634  // Close the pipe
1635  int rcpc = 0;
1636  if ((rcpc = pclose(fp)) == -1) {
1637  emsg = "could not close the command pipe";
1638  rc = 1;
1639  }
1640  if (WEXITSTATUS(rcpc) != 0) {
1641  emsg = "failure: return code: ";
1642  emsg += (int) WEXITSTATUS(rcpc);
1643  rc = 1;
1644  }
1645  }
1646  }
1647  }
1648  // Send error, if any
1649  if (rc == 1) {
1650  // Post Error
1651  if (pp.Post(-1, emsg.c_str()) != 0) rc = 1;
1652  }
1653 
1654  // End-Of-Transmission
1655  if (pp.Post(0, emsg.c_str()) != 0) rc = 1;
1656 
1657  // Done
1658  exit(rc);
1659  }
1660 
1661  // Parent process
1662  if (pid < 0) {
1663  emsg = "forking failed - errno: "; emsg += (int) errno;
1664  return -1;
1665  }
1666 
1667  // now we wait for the callback to be (successfully) established
1668  TRACEP(p, DBG, "forking OK: wait for information");
1669 
1670  // Read status-of-setup from pipe
1671  int prc = 0, rst = -1;
1672  // We wait for 60 secs max among transfers
1673  while (rst < 0 && rc >= 0) {
1674  while ((prc = pp.Poll(60)) > 0) {
1675  XpdMsg msg;
1676  if (pp.Recv(msg) != 0) {
1677  emsg = "error receiving message from pipe";
1678  return -1;
1679  }
1680  // Status is the message type
1681  rst = msg.Type();
1682  // Read string, if any
1683  XrdOucString buf;
1684  if (rst < 0) {
1685  buf = msg.Buf();
1686  if (buf.length() <= 0) {
1687  emsg = "error reading string from received message";
1688  return -1;
1689  }
1690  // Store error message
1691  emsg = buf;
1692  } else {
1693  if (action == kMd5sum || action == kStat) {
1694  buf = msg.Buf();
1695  if (buf.length() <= 0) {
1696  emsg = "error reading string from received message";
1697  return -1;
1698  }
1699  // Store md5sum
1700  emsg = buf;
1701  }
1702  // Done
1703  break;
1704  }
1705  }
1706  if (prc == 0) {
1707  emsg = "timeout from poll";
1708  return -1;
1709  } else if (prc < 0) {
1710  emsg = "error from poll - errno: "; emsg += -prc;
1711  return -1;
1712  }
1713  }
1714 
1715  // Done
1716  return rc;
1717 }
1718 
1719 ////////////////////////////////////////////////////////////////////////////////
1720 /// Handle request for sending a file
1721 
1722 int XrdProofdAdmin::CheckPath(bool superuser, const char *sbdir,
1723  XrdOucString &fullpath, int check, bool &sandbox,
1724  struct stat *st, XrdOucString &emsg)
1725 {
1726  if (!sbdir || strlen(sbdir) <= 0) {
1727  emsg = "CheckPath: sandbox dir undefined!";
1728  return -1;
1729  }
1730 
1731  // Get the full path and check if in sandbox
1732  XrdOucString path(fullpath);
1733  sandbox = 0;
1734  if (path.beginswith('/')) {
1735  fullpath = path;
1736  if (fullpath.beginswith(sbdir)) sandbox = 1;
1737  } else {
1738  if (path.beginswith("../")) path.erase(0,2);
1739  if (path.beginswith("./") || path.beginswith("~/")) path.erase(0,1);
1740  if (!path.beginswith("/")) path.insert('/',0);
1741  fullpath = sbdir;
1742  fullpath += path;
1743  sandbox = 1;
1744  }
1745  fullpath.replace("//","/");
1746 
1747  // If the path is absolute, we must check a normal user is allowed to browse
1748  if (!sandbox && !superuser) {
1749  bool notfound = 1;
1750  std::list<XrdOucString>::iterator si = fExportPaths.begin();
1751  while (si != fExportPaths.end()) {
1752  if (path.beginswith((*si).c_str())) {
1753  notfound = 0;
1754  break;
1755  }
1756  si++;
1757  }
1758  if (notfound) {
1759  emsg = "CheckPath: not allowed to run the requested action on ";
1760  emsg += path;
1761  return -1;
1762  }
1763  }
1764 
1765  if (check > 0 && st) {
1766  // Check if the file exists
1767  if (stat(fullpath.c_str(), st) != 0) {
1768  if (errno == ENOENT) {
1769  return -2;
1770  } else {
1771  return -3;
1772  }
1773  }
1774 
1775  // Certain actions require a regular file
1776  if ((check == 2) && !S_ISREG(st->st_mode)) return -4;
1777  }
1778 
1779  // Done
1780  return 0;
1781 }
1782 
1783 ////////////////////////////////////////////////////////////////////////////////
1784 /// Handle request for sending a file
1785 
1787 {
1788  XPDLOC(ALL, "Admin::GetFile")
1789 
1790  int rc = 0;
1791  XPD_SETRESP(p, "GetFile");
1792 
1793  XrdOucString emsg;
1794 
1795  // Target client (default us)
1796  XrdProofdClient *tgtclnt = p->Client();
1797  if (!tgtclnt) {
1798  emsg = "client instance not found";
1799  TRACEP(p, XERR, emsg);
1800  response->Send(kXR_InvalidRequest, emsg.c_str());
1801  return 0;
1802  }
1803 
1804  // Parse the string
1805  int dlen = p->Request()->header.dlen;
1806  XrdOucString path;
1807  if (dlen > 0 && p->Argp()->buff) {
1808  path.assign((const char *)p->Argp()->buff, 0, dlen);
1809  if (path.length() <= 0) {
1810  TRACEP(p, XERR, "path missing!");
1811  response->Send(kXR_InvalidRequest, "path missing!");
1812  return 0;
1813  }
1814  }
1815 
1816  // Get the full path, check if in sandbox and if the user is allowed
1817  // to access it
1818  XrdOucString fullpath(path);
1819  bool sandbox = 0, check = 2;
1820  int rccp = 0;
1821  struct stat st;
1822  if ((rccp = CheckPath(p->SuperUser(), tgtclnt->Sandbox()->Dir(),
1823  fullpath, check, sandbox, &st, emsg)) != 0) {
1824  if (rccp == -2) {
1825  emsg = "Cannot open `";
1826  emsg += fullpath;
1827  emsg += "': No such file or directory";
1828  } else if (rccp == -3) {
1829  emsg = "Cannot stat `";
1830  emsg += fullpath;
1831  emsg += "': errno: ";
1832  emsg += (int) errno;
1833  } else if (rccp == -4) {
1834  emsg = fullpath;
1835  emsg += " is not a regular file";
1836  }
1837  TRACEP(p, XERR, emsg);
1838  response->Send(kXR_InvalidRequest, emsg.c_str());
1839  return 0;
1840  }
1841 
1842  // Pipe for child-to-parent communications
1843  XrdProofdPipe pp;
1844  if (!pp.IsValid()) {
1845  emsg = "cannot create the pipe for internal communications";
1846  TRACEP(p, XERR, emsg);
1847  response->Send(kXR_InvalidRequest, emsg.c_str());
1848  }
1849 
1850  // Fork a test agent process to handle this session
1851  TRACEP(p, DBG, "forking to execute in the private sandbox");
1852  int pid = -1;
1853  if (!(pid = fMgr->Sched()->Fork("admingetfile"))) {
1854 
1855  // Child process
1856  // We set to the user environment as we must to run the command
1857  // in the user space
1858  if (fMgr->SessionMgr()->SetUserEnvironment(p) != 0) {
1859  emsg = "SetUserEnvironment did not return OK";
1860  rc = 1;
1861  } else {
1862 
1863  // Open the file
1864  int fd = open(fullpath.c_str(), O_RDONLY);
1865  if (fd < 0) {
1866  emsg = "cannot open file: ";
1867  emsg += fullpath;
1868  emsg += " - errno:";
1869  emsg += (int) errno;
1870  TRACEP(p, XERR, emsg);
1871  response->Send(kXR_ServerError, emsg.c_str());
1872  rc = 1;
1873 
1874  } else {
1875  // Send the size as OK message
1876  char sizmsg[64];
1877  snprintf(sizmsg, 64, "%lld", (kXR_int64) st.st_size);
1878  response->Send((const char *) &sizmsg[0]);
1879  TRACEP(p, XERR, "size is "<<sizmsg<<" bytes");
1880 
1881  // Now we send the content
1882  const int kMAXBUF = 16384;
1883  char buf[kMAXBUF];
1884  off_t pos = 0;
1885  lseek(fd, pos, SEEK_SET);
1886 
1887  while (rc == 0 && pos < st.st_size) {
1888  off_t left = st.st_size - pos;
1889  if (left > kMAXBUF) left = kMAXBUF;
1890 
1891  int siz;
1892  while ((siz = read(fd, &buf[0], left)) < 0 && errno == EINTR)
1893  errno = 0;
1894  if (siz < 0 || siz != left) {
1895  emsg = "error reading from file: errno: ";
1896  emsg += (int) errno;
1897  rc = 1;
1898  break;
1899  }
1900 
1901  int src = 0;
1902  if ((src = response->Send(kXR_attn, kXPD_msg, (void *)&buf[0], left)) != 0) {
1903  emsg = "error reading from file: errno: ";
1904  emsg += src;
1905  rc = 1;
1906  break;
1907  }
1908  // Re-position
1909  pos += left;
1910  // Reset the timeout
1911  if (pp.Post(0, "") != 0) {
1912  rc = 1;
1913  break;
1914  }
1915  }
1916  // Close the file
1917  close(fd);
1918  // Send error, if any
1919  if (rc != 0) {
1920  TRACEP(p, XERR, emsg);
1921  response->Send(kXR_attn, kXPD_srvmsg, 0, (char *) emsg.c_str(), emsg.length());
1922  }
1923  }
1924  }
1925 
1926  // Send error, if any
1927  if (rc == 1) {
1928  // Post Error
1929  if (pp.Post(-1, emsg.c_str()) != 0) rc = 1;
1930  } else {
1931  // End-Of-Transmission
1932  if (pp.Post(1, "") != 0) rc = 1;
1933  }
1934 
1935  // Done
1936  exit(rc);
1937  }
1938 
1939  // Parent process
1940  if (pid < 0) {
1941  emsg = "forking failed - errno: "; emsg += (int) errno;
1942  TRACEP(p, XERR, emsg);
1943  response->Send(kXR_ServerError, emsg.c_str());
1944  return 0;
1945  }
1946 
1947  // The parent is done: wait for the child
1948  TRACEP(p, DBG, "forking OK: execution will continue in the child process");
1949 
1950  // Wait for end-of-operations from pipe
1951  int prc = 0, rst = 0;
1952  // We wait for 60 secs max among transfers
1953  while (rst == 0 && rc >= 0) {
1954  while ((prc = pp.Poll(60)) > 0) {
1955  XpdMsg msg;
1956  if (pp.Recv(msg) != 0) {
1957  emsg = "error receiving message from pipe";
1958  return -1;
1959  }
1960  // Status is the message type
1961  rst = msg.Type();
1962  // Read string, if any
1963  if (rst < 0) {
1964  // Error
1965  rc = -1;
1966  // Store error message
1967  emsg = msg.Buf();
1968  if (emsg.length() <= 0) {
1969  emsg = "error reading string from received message";
1970  }
1971  // We stop here
1972  break;
1973  } else if (rst > 0) {
1974  // We are done
1975  break;
1976  }
1977  }
1978  if (prc == 0) {
1979  emsg = "timeout from poll";
1980  rc = -1;
1981  } else if (prc < 0) {
1982  emsg = "error from poll - errno: "; emsg += -prc;
1983  rc = -1;
1984  }
1985  }
1986 
1987  // The parent is done
1988  TRACEP(p, DBG, "execution over: "<< ((rc == 0) ? "ok" : "failed"));
1989 
1990  // Done
1991  return 0;
1992 }
1993 
1994 ////////////////////////////////////////////////////////////////////////////////
1995 /// Handle request for recieving a file
1996 
1998 {
1999  XPDLOC(ALL, "Admin::PutFile")
2000 
2001  int rc = 0;
2002  XPD_SETRESP(p, "PutFile");
2003 
2004  XrdOucString emsg;
2005 
2006  // Target client (default us)
2007  XrdProofdClient *tgtclnt = p->Client();
2008  if (!tgtclnt) {
2009  emsg = "client instance not found";
2010  TRACEP(p, XERR, emsg);
2011  response->Send(kXR_InvalidRequest, emsg.c_str());
2012  return 0;
2013  }
2014 
2015  // Parse the string
2016  kXR_int64 size = -1;
2017  int dlen = p->Request()->header.dlen;
2018  XrdOucString cmd, path, ssiz, opt;
2019  if (dlen > 0 && p->Argp()->buff) {
2020  cmd.assign((const char *)p->Argp()->buff, 0, dlen);
2021  if (cmd.length() <= 0) {
2022  TRACEP(p, XERR, "input buffer missing!");
2023  response->Send(kXR_InvalidRequest, "input buffer missing!");
2024  return 0;
2025  }
2026  int from = 0;
2027  if ((from = cmd.tokenize(path, from, ' ')) < 0) {
2028  TRACEP(p, XERR, "cannot resolve path!");
2029  response->Send(kXR_InvalidRequest, "cannot resolve path!");
2030  return 0;
2031  }
2032  if ((from = cmd.tokenize(ssiz, from, ' ')) < 0) {
2033  TRACEP(p, XERR, "cannot resolve word with size!");
2034  response->Send(kXR_InvalidRequest, "cannot resolve word with size!");
2035  return 0;
2036  }
2037  // Extract size
2038  size = atoll(ssiz.c_str());
2039  if (size < 0) {
2040  TRACEP(p, XERR, "cannot resolve size!");
2041  response->Send(kXR_InvalidRequest, "cannot resolve size!");
2042  return 0;
2043  }
2044  // Any option?
2045  cmd.tokenize(opt, from, ' ');
2046  }
2047  TRACEP(p, DBG, "path: '"<<path<<"'; size: "<<size<<" bytes; opt: '"<<opt<<"'");
2048 
2049  // Default open and mode flags
2050  kXR_unt32 openflags = O_WRONLY | O_TRUNC | O_CREAT;
2051  kXR_unt32 modeflags = 0600;
2052 
2053  // Get the full path and check if in sandbox and if the user is allowed
2054  // to create/access it
2055  XrdOucString fullpath(path);
2056  bool sandbox = 0, check = 1;
2057  struct stat st;
2058  int rccp = 0;
2059  if ((rccp = CheckPath(p->SuperUser(), tgtclnt->Sandbox()->Dir(),
2060  fullpath, check, sandbox, &st, emsg)) != 0) {
2061  if (rccp == -3) {
2062  emsg = "File `";
2063  emsg += fullpath;
2064  emsg += "' exists but cannot be stat: errno: ";
2065  emsg += (int) errno;
2066  }
2067  if (rccp != -2) {
2068  TRACEP(p, XERR, emsg);
2069  response->Send(kXR_InvalidRequest, emsg.c_str());
2070  return 0;
2071  }
2072  } else {
2073  // File exists: either force deletion or fail
2074  if (opt == "force") {
2075  openflags = O_WRONLY | O_TRUNC;
2076  } else {
2077  emsg = "file'";
2078  emsg += fullpath;
2079  emsg += "' exists; user option 'force' to override it";
2080  TRACEP(p, XERR, emsg);
2081  response->Send(kXR_InvalidRequest, emsg.c_str());
2082  return 0;
2083  }
2084  }
2085 
2086  // Pipe for child-to-parent communications
2087  XrdProofdPipe pp;
2088  if (!pp.IsValid()) {
2089  emsg = "cannot create the pipe for internal communications";
2090  TRACEP(p, XERR, emsg);
2091  response->Send(kXR_InvalidRequest, emsg.c_str());
2092  }
2093 
2094  // Fork a test agent process to handle this session
2095  TRACEP(p, DBG, "forking to execute in the private sandbox");
2096  int pid = -1;
2097  if (!(pid = fMgr->Sched()->Fork("adminputfile"))) {
2098  // Child process
2099  // We set to the user environment as we must to run the command
2100  // in the user space
2101  if (fMgr->SessionMgr()->SetUserEnvironment(p) != 0) {
2102  emsg = "SetUserEnvironment did not return OK";
2103  rc = 1;
2104  } else {
2105  // Open the file
2106  int fd = open(fullpath.c_str(), openflags, modeflags);
2107  if (fd < 0) {
2108  emsg = "cannot open file: ";
2109  emsg += fullpath;
2110  emsg += " - errno: ";
2111  emsg += (int) errno;
2112  TRACEP(p, XERR, emsg);
2113  response->Send(kXR_ServerError, emsg.c_str());
2114  rc = 1;
2115  } else {
2116  // We read in the content sent by the client
2117  rc = 0;
2118  response->Send("OK");
2119  // Receive the file
2120  const int kMAXBUF = XrdProofdProtocol::MaxBuffsz();
2121  // Get a buffer
2122  XrdBuffer *argp = XrdProofdProtocol::GetBuff(kMAXBUF);
2123  if (!argp) {
2124  emsg = "cannot get buffer to read data out";
2125  rc = 1;
2126  }
2127  int r;
2128  kXR_int64 filesize = 0, left = 0;
2129  while (rc == 0 && filesize < size) {
2130  left = size - filesize;
2131  if (left > kMAXBUF) left = kMAXBUF;
2132  // Read a bunch of data
2133  TRACEP(p, ALL, "receiving "<<left<<" ...");
2134  if ((rc = p->GetData("data", argp->buff, left))) {
2136  emsg = "cannot read data out";
2137  rc = 1;
2138  break;
2139  }
2140  // Update counters
2141  filesize += left;
2142  // Write to local file
2143  char *b = argp->buff;
2144  r = left;
2145  while (r) {
2146  int w = 0;
2147  while ((w = write(fd, b, r)) < 0 && errno == EINTR)
2148  errno = 0;
2149  if (w < 0) {
2150  emsg = "error writing to unit: ";
2151  emsg += fd;
2152  rc = 1;
2153  break;
2154  }
2155  r -= w;
2156  b += w;
2157  }
2158  // Reset the timeout
2159  if (pp.Post(0, "") != 0) {
2160  rc = 1;
2161  break;
2162  }
2163  }
2164  // Close the file
2165  close(fd);
2166  // Release the buffer
2168  // Send error, if any
2169  if (rc != 0) {
2170  TRACEP(p, XERR, emsg);
2171  response->Send(kXR_attn, kXPD_srvmsg, 0, (char *) emsg.c_str(), emsg.length());
2172  }
2173  }
2174  }
2175  // Send error, if any
2176  if (rc == 1) {
2177  // Post Error
2178  if (pp.Post(-1, emsg.c_str()) != 0) rc = 1;
2179  } else {
2180  // End-Of-Transmission
2181  if (pp.Post(1, "") != 0) rc = 1;
2182  }
2183  // Done
2184  exit(rc);
2185  }
2186 
2187  // Parent process
2188  if (pid < 0) {
2189  emsg = "forking failed - errno: "; emsg += (int) errno;
2190  TRACEP(p, XERR, emsg);
2191  response->Send(kXR_ServerError, emsg.c_str());
2192  return 0;
2193  }
2194 
2195  // The parent is done: wait for the child
2196  TRACEP(p, DBG, "forking OK: execution will continue in the child process");
2197 
2198  // Wait for end-of-operations from pipe
2199  int prc = 0, rst = 0;
2200  // We wait for 60 secs max among transfers
2201  while (rst == 0 && rc >= 0) {
2202  while ((prc = pp.Poll(60)) > 0) {
2203  XpdMsg msg;
2204  if (pp.Recv(msg) != 0) {
2205  emsg = "error receiving message from pipe";
2206  return -1;
2207  }
2208  // Status is the message type
2209  rst = msg.Type();
2210  // Read string, if any
2211  if (rst < 0) {
2212  // Error
2213  rc = -1;
2214  // Store error message
2215  emsg = msg.Buf();
2216  if (emsg.length() <= 0) {
2217  emsg = "error reading string from received message";
2218  }
2219  // We stop here
2220  break;
2221  } else if (rst > 0) {
2222  // We are done
2223  break;
2224  }
2225  }
2226  if (prc == 0) {
2227  emsg = "timeout from poll";
2228  rc = -1;
2229  } else if (prc < 0) {
2230  emsg = "error from poll - errno: "; emsg += -prc;
2231  rc = -1;
2232  }
2233  }
2234 
2235  // The parent is done
2236  TRACEP(p, DBG, "execution over: "<< ((rc == 0) ? "ok" : "failed"));
2237 
2238  // Done
2239  return 0;
2240 }
2241 
2242 ////////////////////////////////////////////////////////////////////////////////
2243 /// Handle request for copy files from / to the sandbox
2244 
2246 {
2247  XPDLOC(ALL, "Admin::CpFile")
2248 
2249  int rc = 0;
2250  XPD_SETRESP(p, "CpFile");
2251 
2252  XrdOucString emsg;
2253 
2254  // Target client (default us)
2255  XrdProofdClient *tgtclnt = p->Client();
2256  if (!tgtclnt) {
2257  emsg = "client instance not found";
2258  TRACEP(p, XERR, emsg);
2259  response->Send(kXR_InvalidRequest, emsg.c_str());
2260  return 0;
2261  }
2262 
2263  // Parse the string
2264  int dlen = p->Request()->header.dlen;
2265  XrdOucString buf, src, dst, fmt;
2266  if (dlen > 0 && p->Argp()->buff) {
2267  buf.assign((const char *)p->Argp()->buff, 0, dlen);
2268  if (buf.length() <= 0) {
2269  TRACEP(p, XERR, "input buffer missing!");
2270  response->Send(kXR_InvalidRequest, "input buffer missing!");
2271  return 0;
2272  }
2273  int from = 0;
2274  if ((from = buf.tokenize(src, from, ' ')) < 0) {
2275  TRACEP(p, XERR, "cannot resolve src path!");
2276  response->Send(kXR_InvalidRequest, "cannot resolve src path!");
2277  return 0;
2278  }
2279  if ((from = buf.tokenize(dst, from, ' ')) < 0) {
2280  TRACEP(p, XERR, "cannot resolve dst path!");
2281  response->Send(kXR_InvalidRequest, "cannot resolve dst path!");
2282  return 0;
2283  }
2284  // The rest, if any, is the format string (including options)
2285  fmt.assign(buf, from);
2286  }
2287  TRACEP(p, DBG, "src: '"<<src<<"'; dst: '"<<dst<<"'; fmt: '"<<fmt<<"'");
2288 
2289  // Check paths
2290  bool locsrc = 1;
2291  XrdClientUrlInfo usrc(src.c_str());
2292  if (usrc.Proto.length() > 0 && usrc.Proto != "file") {
2293  locsrc = 0;
2294  if (!fAllowedCpCmds.Find(usrc.Proto.c_str())) {
2295  TRACEP(p, XERR, "protocol for source file not supported");
2296  response->Send(kXR_InvalidRequest, "protocol for source file not supported");
2297  return 0;
2298  }
2299  }
2300  if (usrc.Proto == "file") src = usrc.File;
2301  bool locdst = 1;
2302  XrdClientUrlInfo udst(dst.c_str());
2303  if (udst.Proto.length() > 0 && udst.Proto != "file") {
2304  locdst = 0;
2305  if (!fAllowedCpCmds.Find(udst.Proto.c_str())) {
2306  TRACEP(p, XERR, "protocol for destination file not supported");
2307  response->Send(kXR_InvalidRequest, "protocol for destination file not supported");
2308  return 0;
2309  }
2310  }
2311  if (udst.Proto == "file") dst = udst.File;
2312 
2313  // Locate the remote protocol, if any
2314  bool loc2loc = 1;
2315  bool loc2rem = 0;
2316  bool rem2loc = 0;
2317  XpdAdminCpCmd *xc = 0;
2318  if (!locsrc && !locdst) {
2319  // Files cannot be both remote
2320  TRACEP(p, XERR, "At least destination or source must be local");
2321  response->Send(kXR_InvalidRequest, "At least destination or source must be local");
2322  return 0;
2323  } else if (!locdst) {
2324  // Find the requested protocol and check if we can put
2325  xc = fAllowedCpCmds.Find(udst.Proto.c_str());
2326  if (!xc->fCanPut) {
2327  TRACEP(p, XERR, "not allowed to create destination file with the chosen protocol");
2328  response->Send(kXR_InvalidRequest, "not allowed to create destination file with the chosen protocol");
2329  return 0;
2330  }
2331  loc2loc = 0;
2332  loc2rem = 1;
2333  } else if (!locsrc) {
2334  // Find the requested protocol
2335  xc = fAllowedCpCmds.Find(usrc.Proto.c_str());
2336  loc2loc = 0;
2337  rem2loc = 1;
2338  } else {
2339  // Default local protocol
2340  xc = fAllowedCpCmds.Find("file");
2341  }
2342 
2343  // Check the local paths
2344  XrdOucString srcpath(src), dstpath(dst);
2345  bool sbsrc = 0, sbdst = 0;
2346  struct stat stsrc, stdst;
2347  int rccpsrc = 0, rccpdst = 0;
2348  if (loc2loc || loc2rem) {
2349  if ((rccpsrc = CheckPath(p->SuperUser(), tgtclnt->Sandbox()->Dir(),
2350  srcpath, 2, sbsrc, &stsrc, emsg)) != 0) {
2351  if (rccpsrc == -2) {
2352  emsg = xc->fCmd;
2353  emsg += ": cannot open `";
2354  emsg += srcpath;
2355  emsg += "': No such file or directory";
2356  } else if (rccpsrc == -3) {
2357  emsg = xc->fCmd;
2358  emsg += ": cannot stat ";
2359  emsg += srcpath;
2360  emsg += ": errno: ";
2361  emsg += (int) errno;
2362  } else if (rccpsrc == -4) {
2363  emsg = xc->fCmd;
2364  emsg += ": ";
2365  emsg += srcpath;
2366  emsg += ": Is not a regular file";
2367  }
2368  TRACEP(p, XERR, emsg);
2369  response->Send(kXR_InvalidRequest, emsg.c_str());
2370  return 0;
2371  }
2372  }
2373  if (loc2loc || rem2loc) {
2374  if ((rccpdst = CheckPath(p->SuperUser(), tgtclnt->Sandbox()->Dir(),
2375  dstpath, 0, sbdst, &stdst, emsg)) != 0) {
2376  if (rccpdst == -2) {
2377  emsg = xc->fCmd;
2378  emsg += ": cannot open `";
2379  emsg += dstpath;
2380  emsg += "': No such file or directory";
2381  } else if (rccpdst == -3) {
2382  emsg = xc->fCmd;
2383  emsg += ": cannot stat ";
2384  emsg += dstpath;
2385  emsg += ": errno: ";
2386  emsg += (int) errno;
2387  } else if (rccpdst == -4) {
2388  emsg = xc->fCmd;
2389  emsg += ": ";
2390  emsg += dstpath;
2391  emsg += ": Is not a regular file";
2392  }
2393  TRACEP(p, XERR, emsg);
2394  response->Send(kXR_InvalidRequest, emsg.c_str());
2395  return 0;
2396  }
2397  }
2398 
2399  // Check the format string
2400  if (fmt.length() <= 0) {
2401  fmt = xc->fFmt;
2402  } else {
2403  if (!fmt.beginswith(xc->fCmd)) {
2404  fmt.insert(" ", 0);
2405  fmt.insert(xc->fCmd, 0);
2406  }
2407  if (fmt.find("%s") == STR_NPOS) {
2408  fmt.insert(" %s %s", -1);
2409  }
2410  }
2411 
2412  // Create the command now
2413  XrdOucString cmd;
2414  XrdProofdAux::Form(cmd, fmt.c_str(), srcpath.c_str(), dstpath.c_str());
2415  cmd += " 2>&1";
2416  TRACEP(p, DBG, "Executing command: " << cmd);
2417 
2418  // Pipe for child-to-parent communications
2419  XrdProofdPipe pp;
2420  if (!pp.IsValid()) {
2421  emsg = "cannot create the pipe";
2422  TRACEP(p, XERR, emsg);
2423  response->Send(kXR_ServerError, emsg.c_str());
2424  return 0;
2425  }
2426 
2427  // Fork a test agent process to handle this session
2428  TRACEP(p, DBG, "forking to execute in the private sandbox");
2429  int pid = -1;
2430  if (!(pid = fMgr->Sched()->Fork("admincpfile"))) {
2431  // Child process
2432  // We set to the user environment as we must to run the command
2433  // in the user space
2434  if (fMgr->SessionMgr()->SetUserEnvironment(p) != 0) {
2435  emsg = "SetUserEnvironment did not return OK";
2436  rc = 1;
2437  } else {
2438  // Execute the command in a pipe
2439  FILE *fp = popen(cmd.c_str(), "r");
2440  if (!fp) {
2441  emsg = "could not run '"; emsg += cmd; emsg += "'";
2442  rc = 1;
2443  } else {
2444  // Read line by line
2445  char line[2048];
2446  while (fgets(line, sizeof(line), fp)) {
2447  // Parse the line
2448  int llen = strlen(line);
2449  if (llen > 0 && line[llen-1] == '\n') {
2450  line[llen-1] = '\0';
2451  llen--;
2452  }
2453  // Real-time sending (line-by-line)
2454  if (llen > 0 &&
2455  response->Send(kXR_attn, kXPD_srvmsg, 4, (char *) &line[0], llen) != 0) {
2456  emsg = "error sending message to requester";
2457  rc = 1;
2458  break;
2459  }
2460  // Check if we have been interrupted
2461  char b[1];
2462  if (p->Link()->Peek(&b[0], 1, 0) == 1) {
2463  p->Process(p->Link());
2464  if (p->IsCtrlC()) break;
2465  }
2466  // Reset timeout
2467  if (pp.Post(0, "") != 0) {
2468  rc = 1;
2469  break;
2470  }
2471  }
2472  // Close the pipe if not in error state (otherwise we may block here)
2473  int rcpc = 0;
2474  if ((rcpc = pclose(fp)) == -1) {
2475  emsg = "error while trying to close the command pipe";
2476  rc = 1;
2477  }
2478  if (WEXITSTATUS(rcpc) != 0) {
2479  emsg = "return code: ";
2480  emsg += (int) WEXITSTATUS(rcpc);
2481  rc = 1;
2482  }
2483  // Close the notification messages
2484  char cp[1] = {'\n'};
2485  if (response->Send(kXR_attn, kXPD_srvmsg, 3, (char *) &cp[0], 1) != 0) {
2486  emsg = "error sending progress notification to requester";
2487  rc = 1;
2488  }
2489  }
2490  }
2491  // Send error, if any
2492  if (rc == 1) {
2493  // Post Error
2494  if (pp.Post(-1, emsg.c_str()) != 0) rc = 1;
2495  }
2496 
2497  // End-Of-Transmission
2498  if (pp.Post(1, "") != 0) rc = 1;
2499 
2500  // Done
2501  exit(rc);
2502  }
2503 
2504  // Parent process
2505  if (pid < 0) {
2506  emsg = "forking failed - errno: "; emsg += (int) errno;
2507  return -1;
2508  }
2509 
2510  // now we wait for the callback to be (successfully) established
2511  TRACEP(p, DBG, "forking OK: wait for execution");
2512 
2513  // Read status-of-setup from pipe
2514  int prc = 0, rst = 0;
2515  // We wait for 60 secs max among transfers
2516  while (rst == 0 && rc >= 0) {
2517  while ((prc = pp.Poll(60)) > 0) {
2518  XpdMsg msg;
2519  if (pp.Recv(msg) != 0) {
2520  emsg = "error receiving message from pipe";;
2521  rc = -1;
2522  }
2523  // Status is the message type
2524  rst = msg.Type();
2525  // Read string, if any
2526  if (rst < 0) {
2527  // Error
2528  rc = -1;
2529  // Store error message
2530  emsg = msg.Buf();
2531  if (emsg.length() <= 0)
2532  emsg = "error reading string from received message";
2533  } else if (rst == 1) {
2534  // Done
2535  break;
2536  }
2537  }
2538  if (prc == 0) {
2539  emsg = "timeout from poll";
2540  rc = -1;
2541  } else if (prc < 0) {
2542  emsg = "error from poll - errno: "; emsg += -prc;
2543  rc = -1;
2544  }
2545  }
2546 
2547  // The parent is done
2548  TRACEP(p, DBG, "execution over: "<< ((rc == 0) ? "ok" : "failed"));
2549 
2550  if (rc != 0) {
2551  emsg.insert("failure: ", 0);
2552  TRACEP(p, XERR, emsg);
2553  response->Send(kXR_ServerError, emsg.c_str());
2554  } else {
2555  response->Send("OK");
2556  }
2557 
2558  // Done
2559  return 0;
2560 }
double read(const std::string &file_name)
reading
int QueryLogPaths(XrdProofdProtocol *p)
Handle request for log paths.
#define SafeDel(x)
Definition: XrdProofdAux.h:335
int GetFile(XrdProofdProtocol *p)
Handle request for sending a file.
XrdOucString fFmt
XrdOucString fCpCmds
XrdProofdClientMgr * ClientMgr() const
int Poll(int to=-1)
Poll over the read pipe for to secs; return whatever poll returns.
#define kXPROOFSRVTAGMAX
int ReleaseWorker(XrdProofdProtocol *p)
Handle request for releasing a worker.
static int MaxBuffsz()
int Exec(XrdProofdProtocol *p)
Handle request of cleaning parts of the sandbox.
int QuerySessions(XrdProofdProtocol *p)
Handle request for list of sessions.
int GetWorkers(XrdOucString &workers, XrdProofdProofServ *, const char *)
Get a list of workers from the available resource broker.
int ExecCmd(XrdProofdProtocol *p, XrdProofdResponse *r, int action, const char *cmd, XrdOucString &emsg)
Low-level execution handler.
#define TRACING(x)
const char * Dir() const
const char * PoolURL() const
int CheckPath(bool superuser, const char *sbdir, XrdOucString &fullpath, int check, bool &sandbox, struct stat *st, XrdOucString &emsg)
Handle request for sending a file.
double write(int n, const std::string &file_name, const std::string &vector_type, int compress=0)
writing
TLine * line
const double pi
return c
static const char * AdminMsgType(int type)
Translates the admin message type in a human readable string.
int Process(XrdProofdProtocol *p, int type)
Process admin request.
int DoDirectiveClass(XrdProofdDirective *, char *val, XrdOucStream *cfg, bool rcf)
Generic class directive processor.
int QueryMssUrl(XrdProofdProtocol *p)
Handle request for the URL to the MSS attached to the cluster.
#define TRACE(Flag, Args)
Definition: TGHtml.h:124
int SrvType() const
XrdProofGroupMgr * GroupsMgr() const
const char * Tag() const
Definition: XrdROOT.h:83
int DoDirective(XrdProofdDirective *d, char *val, XrdOucStream *cfg, bool rcf)
Update the priorities of the active sessions.
void Broadcast(XrdProofdClient *c, const char *msg)
Broadcast message &#39;msg&#39; to the connected instances of client &#39;clnt&#39; or to all connected instances if ...
int Port() const
XrdProofdProofServMgr * SessionMgr() const
XrdProofUI UI() const
int SetSessionTag(XrdProofdProtocol *p)
Handle request for setting the session tag.
int CheckForbiddenChars(const char *s)
Check is &#39;s&#39; contains any of the forbidden chars &#39;(){};&#39; Return 0 if OK (no forbidden chars)...
virtual int ExportInfo(XrdOucString &)
Fill sbuf with some info about our current status.
static XrdBuffer * GetBuff(int quantum, XrdBuffer *argp=0)
Allocate a buffer to handle quantum bytes; if argp points to an existing buffer, its size is checked ...
int Type() const
Definition: XrdProofdAux.h:194
struct ClientRequestHdr header
int Recv(XpdMsg &msg)
Recv message from the pipe.
XrdROOT * DefaultVersion() const
Definition: XrdROOT.h:118
XrdClientMessage * Send(const char *url, int type, const char *msg, int srvtype, XrdProofdResponse *r, bool notify=0, int subtype=-1)
Broadcast request to known potential sub-nodes.
short int ProofProtocol() const
char * ReadLogPaths(const char *url, const char *stag, int isess)
Get log paths from next tier; used in multi-master setups Returns 0 in case of error.
#define SafeDelArray(x)
Definition: XrdProofdAux.h:338
XrdOucString ExportSessions(XrdOucString &emsg, XrdProofdResponse *r=0)
Return a string describing the existing sessions.
int Broadcast(int type, const char *msg, const char *usr=0, XrdProofdResponse *r=0, bool notify=0, int subtype=-1)
Broadcast request to known potential sub-nodes.
bool SuperUser() const
int QueryROOTVersions(XrdProofdProtocol *p)
Handle request for list of ROOT versions.
int QueryWorkers(XrdProofdProtocol *p)
Handle request for getting the list of potential workers.
static void Form(XrdOucString &s, const char *fmt, int ns, const char *ss[5], int ni, int ii[6], int np, void *pp[5], int nu=0, unsigned int ui=0)
Recreate the string according to &#39;fmt&#39;, the up to 5 &#39;const char *&#39;, up to 6 &#39;int&#39; arguments...
XrdOucString fUser
Definition: XrdProofdAux.h:40
const char * Buf() const
Definition: XrdProofdAux.h:185
#define XPDLOC(d, x)
XrdProofSched * ProofSched() const
static const char * what
Definition: stlLoader.cc:6
void TerminateSessions(XrdProofdClient *c, const char *msg, int srvtype)
Terminate sessions of client &#39;clnt&#39; or to of all clients if clnt == 0.
#define kXPROOFSRVALIASMAX
const char * NameSpace() const
int PutFile(XrdProofdProtocol *p)
Handle request for recieving a file.
#define XPDERR(x)
XPClientRequest * Request() const
std::list< XrdOucString > fExportPaths
TRandom2 r(17)
XrdProofdPipe * Pipe()
int DoDirectiveExportPath(char *, XrdOucStream *, bool)
Process &#39;exportpath&#39; directives eg: xpd.exportpath /tmp/data /data2/data.
XrdOucString fGroup
Definition: XrdProofdAux.h:41
XrdROOT * GetVersion(const char *tag)
Return pointer to the ROOT version corresponding to &#39;tag&#39; or 0 if not found.
Definition: XrdROOT.cxx:730
XrdOucString ExportVersions(XrdROOT *def)
Return a string describing the available versions, with the default version &#39;def&#39; markde with a &#39;*&#39;...
Definition: XrdROOT.cxx:706
struct XPClientProofRequest proof
XrdScheduler * Sched() const
#define XrdSysError
Definition: XpdSysError.h:8
#define TRACEP(p, act, x)
int SetGroupProperties(XrdProofdProtocol *p)
Handle request for setting group properties.
XrdProofdAdmin(XrdProofdManager *mgr, XrdProtocol_Config *pi, XrdSysError *e)
Constructor.
XrdProofdNetMgr * NetMgr() const
int GuessTag(XrdOucString &tag, int ridx=1)
Guess session tag completing &#39;tag&#39; (typically "-<pid>") by scanning the active session file or the se...
int GetData(const char *dtype, char *buff, int blen)
Get data from the open link.
XrdProofGroup * GetUserGroup(const char *usr, const char *grp=0)
Returns the instance of the first group to which this user belongs; if grp != 0, return the instance ...
XrdOucString GetUrl()
XrdProofdSandbox * Sandbox() const
XrdOucHash< XpdAdminCpCmd > fAllowedCpCmds
int CpFile(XrdProofdProtocol *p)
Handle request for copy files from / to the sandbox.
#define XPDFORM
Definition: XrdProofdAux.h:381
#define kXPD_Worker
XrdROOT * ROOT() const
double f(double x)
XrdBuffer * Argp() const
static int ExportCpCmd(const char *k, XpdAdminCpCmd *cc, void *s)
Decrease active session counters on worker w.
void RegisterDirectives()
Register directives for configuration.
int type
Definition: TGX11.cxx:120
void SetROOT(XrdROOT *r)
#define free
Definition: civetweb.c:821
int SetSessionAlias(XrdProofdProtocol *p)
Handle request for setting the session alias.
XrdProofdManager * fMgr
int Config(bool rcf=0)
Run configuration and parse the entered config directives.
const char * Host() const
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
bool IsValid() const
Definition: XrdProofdAux.h:209
int Process(XrdLink *lp)
Process the information received on the active link.
#define XPD_SETRESP(p, x)
int CleanupSessions(XrdProofdProtocol *p)
Handle request of.
R__EXTERN C unsigned int sleep(unsigned int seconds)
bool IsLocal(const char *host, bool checkport=0)
Check if &#39;host&#39; is this local host.
XrdProofdPriorityMgr * PriorityMgr() const
int SetROOTVersion(XrdProofdProtocol *p)
Handle request for changing the default ROOT version.
static void ReleaseBuff(XrdBuffer *argp)
Release a buffer previously allocated via GetBuff.
XrdOucString fName
Definition: XrdProofdAux.h:111
void Dump()
Dump status.
const char * EffectiveUser() const
int GetWorkers(XrdProofdProtocol *p)
Handle request for getting the best set of workers.
const char * User() const
you should not use this method at all Int_t Int_t Double_t Double_t Double_t Int_t Double_t Double_t Double_t Double_t b
Definition: TRolke.cxx:630
XrdROOTMgr * ROOTMgr() const
#define snprintf
Definition: civetweb.c:822
const char * Name() const
Definition: XrdProofGroup.h:75
const char * proto
Definition: civetweb.c:11652
XrdProofdClient * GetClient(const char *usr, const char *grp=0, bool create=1)
Handle request for localizing a client instance for {usr, grp} from the list.
int Post(int type, const char *msg)
Post message on the pipe.
double result[121]
int SendMsgToUser(XrdProofdProtocol *p)
Handle request for sending a message to a user.
XrdProofdProofServ * GetServer(int psid)
Get from the vector server instance with ID psid.
XrdLink * Link() const
virtual int Config(bool rcf=0)
int Send(void)
Auxilliary Send method.
XrdOucString fCmd
const char * cnt
Definition: TXMLSetup.cxx:75
void Register(const char *dname, XrdProofdDirective *d)
XrdProofdClient * Client() const
int DoDirectiveCpCmd(char *, XrdOucStream *, bool)
Process &#39;cpcmd&#39; directives eg: xpd.cpcmd alien aliencp fmt:"%s %s" put:0.
int SetUserEnvironment(XrdProofdProtocol *p)
Set user environment: set effective user and group ID of the process to the ones of the owner of this...