Logo ROOT   6.10/09
Reference Guide
XrdProofdProofServMgr.cxx
Go to the documentation of this file.
1 // @(#)root/proofd:$Id$
2 // Author: G. Ganis Jan 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 // XrdProofdProofServMgr //
15 // //
16 // Author: G. Ganis, CERN, 2008 //
17 // //
18 // Class managing proofserv sessions manager. //
19 // //
20 //////////////////////////////////////////////////////////////////////////
21 #include "XrdProofdPlatform.h"
22 
23 #include "XpdSysDNS.h"
24 #include "XpdSysError.h"
25 #include "XpdSysLogger.h"
26 
27 #include "Xrd/XrdBuffer.hh"
28 #include "Xrd/XrdPoll.hh"
29 #include "Xrd/XrdScheduler.hh"
30 #include "XrdNet/XrdNet.hh"
31 #include "XrdOuc/XrdOucRash.hh"
32 #include "XrdOuc/XrdOucStream.hh"
33 #include "XrdSys/XrdSysPriv.hh"
34 #include "XrdSys/XrdSysPlugin.hh"
35 #include "XrdProofdClient.h"
36 #include "XrdProofdClientMgr.h"
37 #include "XrdProofdManager.h"
38 #include "XrdProofdNetMgr.h"
39 #include "XrdProofdPriorityMgr.h"
40 #include "XrdProofdProofServMgr.h"
41 #include "XrdProofdProtocol.h"
42 #include "XrdProofGroup.h"
43 #include "XrdProofSched.h"
44 #include "XrdROOT.h"
45 
46 #include <grp.h>
47 #include <map>
48 #include <unistd.h>
49 
50 // Aux structures for scan through operations
51 typedef struct {
52  XrdProofGroupMgr *fGroupMgr;
53  int *fNBroadcast;
54 } XpdBroadcastPriority_t;
55 typedef struct {
56  XrdProofdManager *fMgr;
57  XrdProofdClient *fClient;
58  FILE *fEnv;
59  bool fExport;
60 } XpdWriteEnv_t;
61 
62 #ifndef PutEnv
63 #define PutEnv(x,e) { if (e) { putenv(x); } else { delete[] x; } }
64 #endif
65 
66 // Tracing utilities
67 #include "XrdProofdTrace.h"
68 
70 
71 //--------------------------------------------------------------------------
72 //
73 // XrdProofdProofServCron
74 //
75 // Function run in separate thread watching changes in session status
76 // frequency
77 //
78 ////////////////////////////////////////////////////////////////////////////////
79 /// This is an endless loop to check the system periodically or when
80 /// triggered via a message in a dedicated pipe
81 
82 void *XrdProofdProofServCron(void *p)
83 {
84  XPDLOC(SMGR, "ProofServCron")
85 
88  XrdProofSched *sched = mc->fProofSched;
89  if (!(mgr)) {
90  TRACE(XERR, "undefined session manager: cannot start");
91  return (void *)0;
92  }
93 
94  // Quicj checks for client disconnections: frequency (5 secs) and
95  // flag for disconnections effectively occuring
96  int quickcheckfreq = 5;
97  int clnlostscale = 0;
98 
99  // Time of last full sessions check
100  int lastrun = time(0);
101  int lastcheck = lastrun, ckfreq = mgr->CheckFrequency(), waitt = 0;
102  int deltat = ((int)(0.1*ckfreq) >= 1) ? (int)(0.1*ckfreq) : 1;
103  int maxdelay = 5*ckfreq; // Force check after 5 times the check frequency
104  mgr->SetNextSessionsCheck(lastcheck + ckfreq);
105  TRACE(ALL, "next full sessions check in "<<ckfreq<<" secs");
106  while(1) {
107  // We check for client disconnections every 'quickcheckfreq' secs; we do
108  // a full check every mgr->CheckFrequency() secs; we make sure that we
109  // do not pass a negative value (meaning no timeout)
110  waitt = ckfreq - (time(0) - lastcheck);
111  if (waitt > quickcheckfreq || waitt <= 0)
112  waitt = quickcheckfreq;
113  int pollRet = mgr->Pipe()->Poll(waitt);
114 
115  if (pollRet > 0) {
116  // Read message
117  XpdMsg msg;
118  int rc = 0;
119  if ((rc = mgr->Pipe()->Recv(msg)) != 0) {
120  TRACE(XERR, "problems receiving message; errno: "<<-rc);
121  continue;
122  }
123  // Parse type
125  // A session has just gone: read process id
126  XrdOucString fpid;
127  if ((rc = msg.Get(fpid)) != 0) {
128  TRACE(XERR, "kSessionRemoval: problems receiving process ID (buf: '"<<
129  msg.Buf()<<"'); errno: "<<-rc);
130  continue;
131  }
132  XrdSysMutexHelper mhp(mgr->Mutex());
133  // Remove it from the hash list
134  mgr->DeleteFromSessions(fpid.c_str());
135  // Move the entry to the terminated sessions area
136  mgr->MvSession(fpid.c_str());
137  // Notify the scheduler too
138  if (sched) {
139  if (sched->Pipe()->Post(XrdProofSched::kReschedule, 0) != 0) {
140  TRACE(XERR, "kSessionRemoval: problem posting the scheduler pipe");
141  }
142  }
143  // Notify action
144  TRACE(REQ, "kSessionRemoval: session: "<<fpid<<
145  " has been removed from the active list");
146  } else if (msg.Type() == XrdProofdProofServMgr::kClientDisconnect) {
147  // Obsolete
148  TRACE(XERR, "obsolete type: XrdProofdProofServMgr::kClientDisconnect");
149  } else if (msg.Type() == XrdProofdProofServMgr::kCleanSessions) {
150  // Request for cleanup all sessions of a client (or all clients)
152  XrdOucString usr;
153  rc = msg.Get(usr);
154  int svrtype = kXPD_AnyServer;
155  rc = (rc == 0) ? msg.Get(svrtype) : rc;
156  if (rc != 0) {
157  TRACE(XERR, "kCleanSessions: problems parsing message (buf: '"<<
158  msg.Buf()<<"'); errno: "<<-rc);
159  continue;
160  }
161  // Notify action
162  TRACE(REQ, "kCleanSessions: request for user: '"<<usr<<"', server type: "<<svrtype);
163  // Clean sessions
164  mgr->CleanClientSessions(usr.c_str(), svrtype);
165  // Check if there is any orphalin sessions and clean them up
166  mgr->CleanupLostProofServ();
167  } else if (msg.Type() == XrdProofdProofServMgr::kProcessReq) {
168  // Process request from some client: if we are here it means they can go ahead
169  mgr->ProcessSem()->Post();
170  } else if (msg.Type() == XrdProofdProofServMgr::kChgSessionSt) {
171  // Propagate cluster information to active sessions after one session changed its state
172  mgr->BroadcastClusterInfo();
173  } else {
174  TRACE(XERR, "unknown type: "<<msg.Type());
175  continue;
176  }
177  } else {
178 
179  // The current time
180  int now = time(0);
181 
182  // If there is any activity in mgr->Process() we postpone the checks in 5 secs
184  if (cnt > 0) {
185  if ((now - lastrun) < maxdelay) {
186  // The current time
187  lastcheck = now + 5 - ckfreq;
188  mgr->SetNextSessionsCheck(now + 5);
189  // Notify
190  TRACE(ALL, "postponing sessions check (will retry in 5 secs)");
191  continue;
192  } else {
193  // Max time without checks reached: force a check
194  TRACE(ALL, "Max time without checks reached ("<<maxdelay<<"): force a session check");
195  // Reset the counter
197  }
198  }
199 
200  bool full = (now > mgr->NextSessionsCheck() - deltat) ? 1 : 0;
201  if (full) {
202  // Run periodical full checks
203  mgr->CheckActiveSessions();
205  if (clnlostscale <= 0) {
206  mgr->CleanupLostProofServ();
207  clnlostscale = 10;
208  } else {
209  clnlostscale--;
210  }
211  // How many active sessions do we have
212  int cursess = mgr->CurrentSessions(1);
213  TRACE(ALL, cursess << " sessions are currently active");
214  // Remember when ...
215  lastrun = now;
216  lastcheck = now;
217  mgr->SetNextSessionsCheck(lastcheck + mgr->CheckFrequency());
218  // Notify
219  TRACE(ALL, "next sessions check in "<<mgr->CheckFrequency()<<" secs");
220  } else {
221  TRACE(HDBG, "nothing to do; "<<mgr->NextSessionsCheck()-now<<" secs to full check");
222  }
223  }
224  }
225 
226  // Should never come here
227  return (void *)0;
228 }
229 
230 //--------------------------------------------------------------------------
231 //
232 // XrdProofdProofServRecover
233 //
234 // Function run in a separate thread waiting for session to recover after
235 // an abrupt shutdown
236 //
237 ////////////////////////////////////////////////////////////////////////////////
238 /// Waiting for session to recover after an abrupt shutdown
239 
241 {
242  XPDLOC(SMGR, "ProofServRecover")
243 
246  if (!(mgr)) {
247  TRACE(XERR, "undefined session manager: cannot start");
248  return (void *)0;
249  }
250 
251  // Recover active sessions
252  int rc = mgr->RecoverActiveSessions();
253 
254  // Notify end of recovering
255  if (rc > 0) {
256  TRACE(ALL, "timeout recovering sessions: "<<rc<<" sessions not recovered");
257  } else if (rc < 0) {
258  TRACE(XERR, "some problem occured while recovering sessions");
259  } else {
260  TRACE(ALL, "recovering successfully terminated");
261  }
262 
263  // Should never come here
264  return (void *)0;
265 }
266 
267 ////////////////////////////////////////////////////////////////////////////////
268 /// Constructor
269 
271  XrdProtocol_Config *pi, XrdSysError *e)
272  : XrdProofdConfig(pi->ConfigFN, e), fProcessSem(0)
273 {
274  XPDLOC(SMGR, "XrdProofdProofServMgr")
275 
276  fMgr = mgr;
277  fLogger = pi->eDest->logger();
278  fInternalWait = 10;
279  fActiveSessions.clear();
280  fShutdownOpt = 1;
281  fShutdownDelay = 0;
282  fReconnectTime = -1;
283  fReconnectTimeOut = 300;
284  fNextSessionsCheck = -1;
285  // Init internal counters
286  for (int i = 0; i < PSMMAXCNTS; i++) {
287  fCounters[i] = 0;
288  }
289  fCurrentSessions = 0;
290 
291  fSeqSessionN = 0;
292 
293  fCredsSaver = 0;
294 
295  // Defaults can be changed via 'proofservmgr'
296  fCheckFrequency = 30;
299  fRecoverTimeOut = 10;
300  fCheckLost = 1;
301  fUseFork = 1;
302  fParentExecs = "xproofd,xrootd";
303 
304  // Recover-related quantities
305  fRecoverClients = 0;
306  fRecoverDeadline = -1;
307 
308  // Init pipe for the poller
309  if (!fPipe.IsValid()) {
310  TRACE(XERR, "unable to generate pipe for the session poller");
311  return;
312  }
313 
314  // Configuration directives
316 }
317 
318 ////////////////////////////////////////////////////////////////////////////////
319 /// Run configuration and parse the entered config directives.
320 /// Return 0 on success, -1 on error
321 
323 {
324  XPDLOC(SMGR, "ProofServMgr::Config")
325 
327 
328  bool notify = (rcf) ? 0 : 1;
329  if (rcf && ReadFile(0)) {
330  // Cleanup lists of envs and RCs
331  fProofServRCs.clear();
332  fProofServEnvs.clear();
333  // Notify possible new settings
334  notify = 1;
335  }
336 
337  // Run first the configurator
338  if (XrdProofdConfig::Config(rcf) != 0) {
339  TRACE(XERR, "problems parsing file ");
340  return -1;
341  }
342 
343  XrdOucString msg;
344  msg = (rcf) ? "re-configuring" : "configuring";
345  if (notify) XPDPRT(msg);
346 
347  // Notify timeout on internal communications
348  XPDFORM(msg, "setting internal timeout to %d secs", fInternalWait);
349  if (notify) XPDPRT(msg);
350 
351  // Shutdown options
352  msg = "client sessions shutdown after disconnection";
353  if (fShutdownOpt > 0) {
354  XPDFORM(msg, "client sessions kept %sfor %d secs after disconnection",
355  (fShutdownOpt == 1) ? "idle " : "", fShutdownDelay);
356  }
357  if (notify) XPDPRT(msg);
358 
359  if (!rcf) {
360  // Admin paths
362  fActiAdminPath += "/activesessions";
364  fTermAdminPath += "/terminatedsessions";
365 
366  // Make sure they exist
367  XrdProofUI ui;
369  if (XrdProofdAux::AssertDir(fActiAdminPath.c_str(), ui, 1) != 0) {
370  TRACE(XERR, "unable to assert the admin path: "<<fActiAdminPath);
371  fActiAdminPath = "";
372  return -1;
373  }
374  XPDPRT("active sessions admin path set to: "<<fActiAdminPath);
375 
376  if (XrdProofdAux::AssertDir(fTermAdminPath.c_str(), ui, 1) != 0) {
377  TRACE(XERR, "unable to assert the admin path "<<fTermAdminPath);
378  fTermAdminPath = "";
379  return -1;
380  }
381  XPDPRT("terminated sessions admin path set to "<<fTermAdminPath);
382  }
383 
384  if (notify) {
385  XPDPRT("RC settings: "<< fProofServRCs.size());
386  if (fProofServRCs.size() > 0) {
387  std::list<XpdEnv>::iterator ircs = fProofServRCs.begin();
388  for ( ; ircs != fProofServRCs.end(); ircs++) { (*ircs).Print("rc"); }
389  }
390  XPDPRT("ENV settings: "<< fProofServEnvs.size());
391  if (fProofServEnvs.size() > 0) {
392  std::list<XpdEnv>::iterator ienvs = fProofServEnvs.begin();
393  for ( ; ienvs != fProofServEnvs.end(); ienvs++) { (*ienvs).Print("env"); }
394  }
395  }
396 
397  // Notify sessions startup technology
398  XPDFORM(msg, "using %s to start proofserv sessions", fUseFork ? "fork()" : "system()");
399  if (notify) XPDPRT(msg);
400 
401  if (!rcf) {
402  // Try to recover active session previously started
403  int nr = -1;
404  if ((nr = PrepareSessionRecovering()) < 0) {
405  TRACE(XERR, "problems trying to recover active sessions");
406  } else if (nr > 0) {
407  XPDFORM(msg, "%d active sessions have been recovered", nr);
408  XPDPRT(msg);
409  }
410 
411  // Start cron thread
412  pthread_t tid;
413  // Fill manager pointers structure
414  fManagerCron.fClientMgr = fMgr->ClientMgr();
415  fManagerCron.fSessionMgr = this;
416  if (XrdSysThread::Run(&tid, XrdProofdProofServCron,
417  (void *)&fManagerCron, 0, "ProofServMgr cron thread") != 0) {
418  TRACE(XERR, "could not start cron thread");
419  return 0;
420  }
421  XPDPRT("cron thread started");
422  }
423 
424  // Done
425  return 0;
426 }
427 
428 ////////////////////////////////////////////////////////////////////////////////
429 /// Add new active session
430 
432 {
433  XPDLOC(SMGR, "ProofServMgr::AddSession")
434 
435  TRACE(REQ, "adding new active session ...");
436 
437  // Check inputs
438  if (!s || !p->Client()) {
439  TRACE(XERR,"invalid inputs: "<<(s ? "" : "s, ") <<", "<< (p->Client() ? "" : "p->Client()"));
440  return -1;
441  }
442  XrdProofdClient *c = p->Client();
443 
444  // Path
445  XrdOucString path;
446  XPDFORM(path, "%s/%s.%s.%d", fActiAdminPath.c_str(), c->User(), c->Group(), s->SrvPID());
447 
448  // Save session info to file
449  XrdProofSessionInfo info(c, s);
450  int rc = info.SaveToFile(path.c_str());
451 
452  return rc;
453 }
454 
455 ////////////////////////////////////////////////////////////////////////////////
456 /// Checks is fpid is the path of a session UNIX socket
457 /// Returns TRUE is yes; cleans the socket if the session is gone.
458 
460 {
461  XPDLOC(SMGR, "ProofServMgr::IsSessionSocket")
462 
463  TRACE(REQ, "checking "<<fpid<<" ...");
464 
465  // Check inputs
466  if (!fpid || strlen(fpid) <= 0) {
467  TRACE(XERR, "invalid input: "<<(fpid ? fpid : "<nul>"));
468  return 0;
469  }
470 
471  // Paths
472  XrdOucString spath(fpid);
473  if (!spath.endswith(".sock")) return 0;
474  if (!spath.beginswith(fActiAdminPath.c_str())) {
475  // We are given a partial path: create full paths
476  XPDFORM(spath, "%s/%s", fActiAdminPath.c_str(), fpid);
477  }
478  XrdOucString apath = spath;
479  apath.replace(".sock", "");
480 
481  // Check the admin path
482  struct stat st;
483  if (stat(apath.c_str(), &st) != 0 && (errno == ENOENT)) {
484  // Remove the socket path if not during creation
485  if (CheckCounter(kCreateCnt) <= 0) {
486  unlink(spath.c_str());
487  TRACE(REQ, "missing admin path: removing "<<spath<<" ...");
488  }
489  }
490 
491  // Done
492  return 1;
493 }
494 
495 ////////////////////////////////////////////////////////////////////////////////
496 /// Move session file from the active to the terminated areas
497 
498 int XrdProofdProofServMgr::MvSession(const char *fpid)
499 {
500  XPDLOC(SMGR, "ProofServMgr::MvSession")
501 
502  TRACE(REQ, "moving "<<fpid<<" ...");
503 
504  // Check inputs
505  if (!fpid || strlen(fpid) <= 0) {
506  TRACE(XERR, "invalid input: "<<(fpid ? fpid : "<nul>"));
507  return -1;
508  }
509 
510  // Paths
511  XrdOucString opath(fpid), npath;
512  if (!opath.beginswith(fActiAdminPath.c_str())) {
513  // We are given a partial path: create full paths
514  XPDFORM(opath, "%s/%s", fActiAdminPath.c_str(), fpid);
515  opath.replace(".status", "");
516  } else {
517  // Full path: just create the new path
518  opath.replace(".status", "");
519  }
520  // The target path
521  npath = opath;
522  npath.replace(fActiAdminPath.c_str(), fTermAdminPath.c_str());
523 
524  // Remove the socket path
525  XrdOucString spath = opath;
526  spath += ".sock";
527  if (unlink(spath.c_str()) != 0 && errno != ENOENT)
528  TRACE(XERR, "problems removing the UNIX socket path: "<<spath<<"; errno: "<<errno);
529  spath.replace(".sock", ".status");
530  if (unlink(spath.c_str()) != 0 && errno != ENOENT)
531  TRACE(XERR, "problems removing the status file: "<<spath<<"; errno: "<<errno);
532 
533  // Move the file
534  errno = 0;
535  int rc = 0;
536  if ((rc = rename(opath.c_str(), npath.c_str())) == 0 || (errno == ENOENT)) {
537  if (!rc)
538  // Record the time when we did this
539  TouchSession(fpid, npath.c_str());
540  return 0;
541  }
542 
543  TRACE(XERR, "session pid file cannot be moved: "<<opath<<
544  "; target file: "<<npath<<"; errno: "<<errno);
545  return -1;
546 }
547 
548 ////////////////////////////////////////////////////////////////////////////////
549 /// Remove session file from the terminated sessions area
550 
551 int XrdProofdProofServMgr::RmSession(const char *fpid)
552 {
553  XPDLOC(SMGR, "ProofServMgr::RmSession")
554 
555  TRACE(REQ, "removing "<<fpid<<" ...");
556 
557  // Check inputs
558  if (!fpid || strlen(fpid) <= 0) {
559  TRACE(XERR, "invalid input: "<< (fpid ? fpid : "<nul>"));
560  return -1;
561  }
562 
563  // Path
564  XrdOucString path;
565  XPDFORM(path, "%s/%s", fTermAdminPath.c_str(), fpid);
566 
567  // remove the file
568  if (unlink(path.c_str()) == 0)
569  return 0;
570 
571  TRACE(XERR, "session pid file cannot be unlinked: "<<
572  path<<"; error: "<<errno);
573  return -1;
574 }
575 
576 ////////////////////////////////////////////////////////////////////////////////
577 /// Update the access time for the session pid file to the current time
578 
579 int XrdProofdProofServMgr::TouchSession(const char *fpid, const char *fpath)
580 {
581  XPDLOC(SMGR, "ProofServMgr::TouchSession")
582 
583  TRACE(REQ, "touching "<<(fpid ? fpid : "<nul>")<<", "<<(fpath ? fpath : "<nul>")<<" ...");
584 
585  // Check inputs
586  if (!fpid || strlen(fpid) <= 0) {
587  TRACE(XERR, "invalid input: "<<(fpid ? fpid : "<nul>"));
588  return -1;
589  }
590 
591  // Path
592  XrdOucString path(fpath);
593  if (!fpath || !fpath[0])
594  XPDFORM(path, "%s/%s.status", fActiAdminPath.c_str(), fpid);
595 
596  // Update file time stamps
597  if (utime(path.c_str(), 0) == 0)
598  return 0;
599 
600  TRACE(XERR, "time stamps for session pid file cannot be updated: "<<
601  path<<"; error: "<<errno);
602  return -1;
603 }
604 
605 ////////////////////////////////////////////////////////////////////////////////
606 /// Check if the session is alive, i.e. if it has recently touched its admin file.
607 /// Return 0 if alive, 1 if not-responding, -1 in case of error.
608 /// The timeout for verification is 'to' if positive, else fVerifyTimeOut;
609 /// the admin file is looked under 'fpath' if defined, else fActiAdminPath.
610 
612  int to, const char *fpath)
613 {
614  XPDLOC(SMGR, "ProofServMgr::VerifySession")
615 
616  // Check inputs
617  if (!fpid || strlen(fpid) <= 0) {
618  TRACE(XERR, "invalid input: "<<(fpid ? fpid : "<nul>"));
619  return -1;
620  }
621 
622  // Path
623  XrdOucString path;
624  if (fpath && strlen(fpath) > 0)
625  XPDFORM(path, "%s/%s", fpath, fpid);
626  else
627  XPDFORM(path, "%s/%s", fActiAdminPath.c_str(), fpid);
628 
629  // Check first the new file but also the old one, for backward compatibility
630  int deltat = -1;
631  bool checkmore = 1;
632  while (checkmore) {
633  // Current settings
634  struct stat st;
635  if (stat(path.c_str(), &st)) {
636  TRACE(XERR, "session status file cannot be stat'ed: "<<
637  path<<"; error: "<<errno);
638  return -1;
639  }
640  // Check times
641  int xto = (to > 0) ? to : fVerifyTimeOut;
642  deltat = time(0) - st.st_mtime;
643  if (deltat > xto) {
644  if (path.endswith(".status")) {
645  // Check the old one too
646  path.erase(path.rfind(".status"));
647  } else {
648  // Dead
649  TRACE(DBG, "admin path for session "<<fpid<<" hase not been touched"
650  " since at least "<< xto <<" secs");
651  return 1;
652  }
653  } else {
654  // We are done
655  checkmore = 0;
656  }
657  }
658 
659  // Alive
660  TRACE(DBG, "admin path for session "<<fpid<<" was touched " <<
661  deltat <<" secs ago");
662  return 0;
663 }
664 
665 ////////////////////////////////////////////////////////////////////////////////
666 /// Delete from the hash list the session with ID pid.
667 /// Return -ENOENT if not found, or 0.
668 
670 {
671  XPDLOC(SMGR, "ProofServMgr::DeleteFromSessions")
672 
673  TRACE(REQ, "session: "<<fpid);
674 
675  // Check inputs
676  if (!fpid || strlen(fpid) <= 0) {
677  TRACE(XERR, "invalid input: "<<(fpid ? fpid : "<nul>"));
678  return -1;
679  }
680 
681  XrdOucString key = fpid;
682  key.replace(".status", "");
683  key.erase(0, key.rfind('.') + 1);
684  XrdProofdProofServ *xps = 0;
685  { XrdSysMutexHelper mhp(fMutex); xps = fSessions.Find(key.c_str()); }
686  if (xps) {
687  // Tell other attached clients, if any, that this session is gone
688  XrdOucString msg;
689  XPDFORM(msg, "session: %s terminated by peer", fpid);
690  TRACE(DBG, msg);
691  // Reset this instance
692  int tp = xps->Reset(msg.c_str(), kXPD_wrkmortem);
693  // Update counters and lists
695  if (tp == 1) fCurrentSessions--;
696  // remove from the list of active sessions
697  fActiveSessions.remove(xps);
698  }
699  int rc = -1;
700  { XrdSysMutexHelper mhp(fMutex); rc = fSessions.Del(key.c_str()); }
701  return rc;
702 }
703 
704 ////////////////////////////////////////////////////////////////////////////////
705 /// Go through the active sessions admin path and prepare reconnection of those
706 /// still alive.
707 /// Called at start-up.
708 
710 {
711  XPDLOC(SMGR, "ProofServMgr::PrepareSessionRecovering")
712 
713  // Open dir
714  DIR *dir = opendir(fActiAdminPath.c_str());
715  if (!dir) {
716  TRACE(XERR, "cannot open dir "<<fActiAdminPath<<" ; error: "<<errno);
717  return -1;
718  }
719  TRACE(REQ, "preparing recovering of active sessions ...");
720 
721  // Scan the active sessions admin path
722  fRecoverClients = new std::list<XpdClientSessions *>;
723  struct dirent *ent = 0;
724  while ((ent = (struct dirent *)readdir(dir))) {
725  if (!strncmp(ent->d_name, ".", 1) || !strncmp(ent->d_name, "..", 2)) continue;
726  // Get the session instance (skip non-digital entries)
727  XrdOucString rest, a;
728  int pid = XrdProofdAux::ParsePidPath(ent->d_name, rest, a);
729  if (!XPD_LONGOK(pid) || pid <= 0) continue;
730  if (a.length() > 0) continue;
731  bool rmsession = 1;
732  // Check if the process is still alive
733  if (XrdProofdAux::VerifyProcessByID(pid) != 0) {
734  if (ResolveSession(ent->d_name) == 0) {
735  TRACE(DBG, "found active session: "<<pid);
736  rmsession = 0;
737  }
738  }
739  // Remove the session, if needed
740  if (rmsession)
741  MvSession(ent->d_name);
742  }
743  // Close the directory
744  closedir(dir);
745 
746  // Start the recovering thread, if needed
747  int nrc = 0;
748  { XrdSysMutexHelper mhp(fRecoverMutex); nrc = fRecoverClients->size(); }
749  if (nrc > 0) {
750  // Start recovering thread
751  pthread_t tid;
752  // Fill manager pointers structure
753  fManagerCron.fClientMgr = fMgr->ClientMgr();
754  fManagerCron.fSessionMgr = this;
755  fManagerCron.fProofSched = fMgr->ProofSched();
756  if (XrdSysThread::Run(&tid, XrdProofdProofServRecover, (void *)&fManagerCron,
757  0, "ProofServMgr session recover thread") != 0) {
758  TRACE(XERR, "could not start session recover thread");
759  return 0;
760  }
761  XPDPRT("session recover thread started");
762  } else {
763  // End reconnect state if there is nothing to reconnect
764  if (fMgr->ClientMgr() && fMgr->ClientMgr()->GetNClients() <= 0)
765  SetReconnectTime(0);
766  }
767 
768  // Done
769  return 0;
770 }
771 
772 
773 ////////////////////////////////////////////////////////////////////////////////
774 /// Accept connections from sessions still alive. This is run in a dedicated
775 /// thread.
776 /// Returns -1 in case of failure, 0 if all alive sessions reconnected or the
777 /// numer of sessions not reconnected if the timeout (fRecoverTimeOut per client)
778 /// expired.
779 
781 {
782  XPDLOC(SMGR, "ProofServMgr::RecoverActiveSessions")
783 
784  int rc = 0;
785 
786  if (!fRecoverClients) {
787  // Invalid input
788  TRACE(XERR, "recovering clients list undefined");
789  return -1;
790  }
791 
792  int nrc = 0;
793  { XrdSysMutexHelper mhp(fRecoverMutex); nrc = fRecoverClients->size(); }
794  TRACE(REQ, "start recovering of "<<nrc<<" clients");
795 
796  // Recovering deadline
798  fRecoverDeadline = time(0) + fRecoverTimeOut * nrc; }
799 
800  // Respect the deadline
801  int nr = 0;
802  XpdClientSessions *cls = 0;
803  bool go = true;
804  while (go) {
805 
806  // Pickup the first one in the list
807  { XrdSysMutexHelper mhp(fRecoverMutex); cls = fRecoverClients->front(); }
808  if (cls) {
810  nr += Recover(cls);
811 
812  // If all client sessions reconnected remove the client from the list
813  { XrdSysMutexHelper mhp(cls->fMutex);
814  if (cls->fProofServs.size() <= 0) {
816  fRecoverClients->remove(cls);
817  // We may be over
818  if ((nrc = fRecoverClients->size()) <= 0)
819  break;
820  }
821  }
822  }
823  TRACE(REQ, nrc<<" clients still to recover");
824 
825  // Check the deadline
827  go = (time(0) < fRecoverDeadline) ? true : false; }
828  }
829  // End reconnect state
830  SetReconnectTime(0);
831 
832  // If we reached the deadline, calculate the number of sessions not reconnected
833  rc = 0;
835  if (fRecoverClients->size() > 0) {
836  std::list<XpdClientSessions* >::iterator ii = fRecoverClients->begin();
837  for (; ii != fRecoverClients->end(); ii++) {
838  rc += (*ii)->fProofServs.size();
839  }
840  }
841  }
842 
843  // Delete the recovering clients list
845  fRecoverClients->clear();
846  delete fRecoverClients;
847  fRecoverClients = 0;
848  fRecoverDeadline = -1;
849  }
850 
851  // Done
852  return rc;
853 }
854 
855 ////////////////////////////////////////////////////////////////////////////////
856 /// Returns true (an the recovering deadline) if the client has sessions in
857 /// recovering state; returns false otherwise.
858 /// Called during for attach requests.
859 
860 bool XrdProofdProofServMgr::IsClientRecovering(const char *usr, const char *grp,
861  int &deadline)
862 {
863  XPDLOC(SMGR, "ProofServMgr::IsClientRecovering")
864 
865  if (!usr || !grp) {
866  TRACE(XERR, "invalid inputs: usr: "<<(usr ? usr : "")<<", grp:"<<(grp ? grp : "")<<" ...");
867  return false;
868  }
869 
870  deadline = -1;
871  int rc = false;
873  if (fRecoverClients && fRecoverClients->size() > 0) {
874  std::list<XpdClientSessions *>::iterator ii = fRecoverClients->begin();
875  for (; ii != fRecoverClients->end(); ii++) {
876  if ((*ii)->fClient && (*ii)->fClient->Match(usr, grp)) {
877  rc = true;
878  deadline = fRecoverDeadline;
879  break;
880  }
881  }
882  }
883  }
884  TRACE(DBG, "checking usr: "<<usr<<", grp:"<<grp<<" ... recovering? "<<
885  rc<<", until: "<<deadline);
886 
887  // Done
888  return rc;
889 }
890 
891 ////////////////////////////////////////////////////////////////////////////////
892 /// Go through the active sessions admin path and make sure sessions are alive.
893 /// If 'verify' is true also ask the session to proof that they are alive
894 /// via asynchronous ping (the result will be done at next check).
895 /// Move those not responding in the terminated sessions admin path.
896 
898 {
899  XPDLOC(SMGR, "ProofServMgr::CheckActiveSessions")
900 
901  TRACE(REQ, "checking active sessions ...");
902 
903  // Open dir
904  DIR *dir = opendir(fActiAdminPath.c_str());
905  if (!dir) {
906  TRACE(XERR, "cannot open dir "<<fActiAdminPath<<" ; error: "<<errno);
907  return -1;
908  }
909 
910  // Scan the active sessions admin path
911  struct dirent *ent = 0;
912  while ((ent = (struct dirent *)readdir(dir))) {
913  if (!strncmp(ent->d_name, ".", 1) || !strncmp(ent->d_name, "..", 2)) continue;
914  // If a socket path, make sure that the associated session still exists
915  // and go to the next
916  if (strstr(ent->d_name, ".sock") && IsSessionSocket(ent->d_name)) continue;
917  // Get the session instance (skip non-digital entries)
918  XrdOucString rest, key, after;
919  int pid = XrdProofdAux::ParsePidPath(ent->d_name, rest, after);
920  // If not a status path, go to the next
921  if (after != "status") continue;
922  // If not a good pid
923  if (!XPD_LONGOK(pid) || pid <= 0) continue;
924  key += pid;
925  //
926  XrdProofdProofServ *xps = 0;
927  { XrdSysMutexHelper mhp(fMutex);
928  xps = fSessions.Find(key.c_str());
929  }
930 
931  bool sessionalive = (VerifySession(ent->d_name) == 0) ? 1 : 0;
932  bool rmsession = 0;
933  if (xps) {
934  if (!xps->IsValid() || !sessionalive) rmsession = 1;
935  } else {
936  // Session not yet registered, possibly starting
937  // Skips checks the admin file verification was OK
938  if (sessionalive) continue;
939  rmsession = 1;
940  }
941 
942  // For backward compatibility we need to check the session version
943  bool oldvers = (xps && xps->ROOT() && xps->ROOT()->SrvProtVers() >= 18) ? 0 : 1;
944 
945  // If somebody is interested in this session, we give them some
946  // more time by skipping the connected clients check this time
947  int nc = -1;
948  if (!rmsession)
949  rmsession = xps->CheckSession(oldvers, IsReconnecting(),
951 
952  // Verify the session: this just sends a request to the session
953  // to touch the session file; all this will be done asynchronously;
954  // the result will be checked next time.
955  // We do not want further propagation at this stage.
956  if (!rmsession && verify && !oldvers) {
957  if (xps->VerifyProofServ(0) != 0) {
958  // This means that the connection is already gone
959  rmsession = 1;
960  }
961  }
962  TRACE(REQ, "session: "<<ent->d_name<<"; nc: "<<nc<<"; rm: "<<rmsession);
963  // Remove the session, if needed
964  if (rmsession)
965  MvSession(ent->d_name);
966  }
967  // Close the directory
968  closedir(dir);
969 
970  // Done
971  return 0;
972 }
973 
974 ////////////////////////////////////////////////////////////////////////////////
975 /// Go through the terminated sessions admin path and make sure sessions they
976 /// are gone.
977 /// Hard-kill those still alive.
978 
980 {
981  XPDLOC(SMGR, "ProofServMgr::CheckTerminatedSessions")
982 
983  TRACE(REQ, "checking terminated sessions ...");
984 
985  // Open dir
986  DIR *dir = opendir(fTermAdminPath.c_str());
987  if (!dir) {
988  TRACE(XERR, "cannot open dir "<<fTermAdminPath<<" ; error: "<<errno);
989  return -1;
990  }
991 
992  // Scan the terminated sessions admin path
993  int now = -1;
994  struct dirent *ent = 0;
995  while ((ent = (struct dirent *)readdir(dir))) {
996  if (!strncmp(ent->d_name, ".", 1) || !strncmp(ent->d_name, "..", 2)) continue;
997  // Get the session instance (skip non-digital entries)
998  XrdOucString rest, a;
999  int pid = XrdProofdAux::ParsePidPath(ent->d_name, rest, a);
1000  if (!XPD_LONGOK(pid) || pid <= 0) continue;
1001 
1002  // Current time
1003  now = (now > 0) ? now : time(0);
1004 
1005  // Full path
1006  XrdOucString path;
1007  XPDFORM(path, "%s/%s", fTermAdminPath.c_str(), ent->d_name);
1008 
1009  // Check termination time
1010  struct stat st;
1011  int rcst = stat(path.c_str(), &st);
1012  TRACE(DBG, pid<<": rcst: "<<rcst<<", now - mtime: "<<now - st.st_mtime<<" secs")
1013  if ((now - st.st_mtime) > fTerminationTimeOut || rcst != 0) {
1014  // Check if the process is still alive
1015  if (XrdProofdAux::VerifyProcessByID(pid) != 0) {
1016  // Send again an hard-kill signal
1017  XrdProofSessionInfo info(path.c_str());
1018  XrdProofUI ui;
1019  XrdProofdAux::GetUserInfo(info.fUser.c_str(), ui);
1020  XrdProofdAux::KillProcess(pid, 1, ui, fMgr->ChangeOwn());
1021  } else {
1022  // Delete the entry
1023  RmSession(ent->d_name);
1024  }
1025  }
1026  }
1027  // Close the directory
1028  closedir(dir);
1029 
1030  // Done
1031  return 0;
1032 }
1033 
1034 ////////////////////////////////////////////////////////////////////////////////
1035 /// Go through the sessions admin path and clean all sessions belonging to 'usr'.
1036 /// Move those not responding in the terminated sessions admin path.
1037 
1038 int XrdProofdProofServMgr::CleanClientSessions(const char *usr, int srvtype)
1039 {
1040  XPDLOC(SMGR, "ProofServMgr::CleanClientSessions")
1041 
1042  TRACE(REQ, "cleaning "<<usr<<" ...");
1043 
1044  // Check which client
1045  bool all = (!usr || strlen(usr) <= 0 || !strcmp(usr, "all")) ? 1 : 0;
1046 
1047  // Get user info
1048  XrdProofUI ui;
1049  if (!all)
1050  XrdProofdAux::GetUserInfo(usr, ui);
1051  XrdOucString path, rest, key, a;
1052 
1053  // We need lock to avoid session actions request while we are doing this
1054  XrdSysRecMutex *mtx = 0;
1055  if (all) {
1056  // Lock us all
1057  mtx = &fMutex;
1058  } else {
1059  // Lock the client
1060  XrdProofdClient *c = fMgr->ClientMgr()->GetClient(usr);
1061  if (c) mtx = c->Mutex();
1062  }
1063 
1064  std::list<int> tobedel;
1065  { XrdSysMutexHelper mtxh(mtx);
1066 
1067  // Check the terminated session dir first
1068  DIR *dir = opendir(fTermAdminPath.c_str());
1069  if (!dir) {
1070  TRACE(XERR, "cannot open dir "<<fTermAdminPath<<" ; error: "<<errno);
1071  } else {
1072  // Go trough
1073  struct dirent *ent = 0;
1074  while ((ent = (struct dirent *)readdir(dir))) {
1075  // Skip basic entries
1076  if (!strncmp(ent->d_name, ".", 1) || !strncmp(ent->d_name, "..", 2)) continue;
1077  // Get the session instance
1078  int pid = XrdProofdAux::ParsePidPath(ent->d_name, rest, a);
1079  if (!XPD_LONGOK(pid) || pid <= 0) continue;
1080  // Read info from file and check that we are interested in this session
1081  XPDFORM(path, "%s/%s", fTermAdminPath.c_str(), ent->d_name);
1082  XrdProofSessionInfo info(path.c_str());
1083  // Check user
1084  if (!all && info.fUser != usr) continue;
1085  // Check server type
1086  if (srvtype != kXPD_AnyServer && info.fSrvType != srvtype) continue;
1087  // Refresh user info, if needed
1088  if (all)
1089  XrdProofdAux::GetUserInfo(info.fUser.c_str(), ui);
1090  // Check if the process is still alive
1091  if (XrdProofdAux::VerifyProcessByID(pid) != 0) {
1092  // Send a hard-kill signal
1093  XrdProofdAux::KillProcess(pid, 1, ui, fMgr->ChangeOwn());
1094  } else {
1095  // Delete the entry
1096  RmSession(ent->d_name);
1097  }
1098  }
1099  // Close the directory
1100  closedir(dir);
1101  }
1102 
1103  // Check the active session dir now
1104  dir = opendir(fActiAdminPath.c_str());
1105  if (!dir) {
1106  TRACE(XERR, "cannot open dir "<<fActiAdminPath<<" ; error: "<<errno);
1107  return -1;
1108  }
1109 
1110  // Scan the active sessions admin path
1111  struct dirent *ent = 0;
1112  while ((ent = (struct dirent *)readdir(dir))) {
1113  // Skip basic entries
1114  if (!strncmp(ent->d_name, ".", 1) || !strncmp(ent->d_name, "..", 2)) continue;
1115  // Get the session instance
1116  int pid = XrdProofdAux::ParsePidPath(ent->d_name, rest, a);
1117  if (a == "status") continue;
1118  if (!XPD_LONGOK(pid) || pid <= 0) continue;
1119  // Read info from file and check that we are interested in this session
1120  XPDFORM(path, "%s/%s", fActiAdminPath.c_str(), ent->d_name);
1121  XrdProofSessionInfo info(path.c_str());
1122  if (!all && info.fUser != usr) continue;
1123  // Check server type
1124  if (srvtype != kXPD_AnyServer && info.fSrvType != srvtype) continue;
1125  // Refresh user info, if needed
1126  if (all)
1127  XrdProofdAux::GetUserInfo(info.fUser.c_str(), ui);
1128  // Check if the process is still alive
1129  if (XrdProofdAux::VerifyProcessByID(pid) != 0) {
1130  // We will remove this later
1131  tobedel.push_back(pid);
1132  // Send a termination signal
1133  XrdProofdAux::KillProcess(pid, 0, ui, fMgr->ChangeOwn());
1134  }
1135  // Flag as terminated
1136  MvSession(ent->d_name);
1137  }
1138  // Close the directory
1139  closedir(dir);
1140  }
1141 
1142  // Cleanup fSessions
1143  std::list<int>::iterator ii = tobedel.begin();
1144  while (ii != tobedel.end()) {
1145  XPDFORM(key, "%d", *ii);
1147  XrdProofdProofServ *xps = fSessions.Find(key.c_str());
1148  bool active = 0;
1149  std::list<XrdProofdProofServ *>::iterator ixps = fActiveSessions.begin();
1150  while (ixps != fActiveSessions.end()) {
1151  if (*ixps == xps) {
1152  active = 1;
1153  break;
1154  }
1155  ixps++;
1156  }
1157  if (!active) fSessions.Del(key.c_str());
1158  ii++;
1159  }
1160 
1161  // Done
1162  return 0;
1163 }
1164 
1165 ////////////////////////////////////////////////////////////////////////////////
1166 /// Register directives for configuration
1167 
1169 {
1170  // Register special config directives
1171  Register("proofservmgr", new XrdProofdDirective("proofservmgr", this, &DoDirectiveClass));
1172  Register("putenv", new XrdProofdDirective("putenv", this, &DoDirectiveClass));
1173  Register("putrc", new XrdProofdDirective("putrc", this, &DoDirectiveClass));
1174  Register("shutdown", new XrdProofdDirective("shutdown", this, &DoDirectiveClass));
1175  // Register config directives for ints
1176  Register("intwait",
1177  new XrdProofdDirective("intwait", (void *)&fInternalWait, &DoDirectiveInt));
1178  Register("reconnto",
1179  new XrdProofdDirective("reconnto", (void *)&fReconnectTimeOut, &DoDirectiveInt));
1180  // Register config directives for strings
1181  Register("proofplugin",
1182  new XrdProofdDirective("proofplugin", (void *)&fProofPlugin, &DoDirectiveString));
1183  Register("proofservparents",
1184  new XrdProofdDirective("proofservparents", (void *)&fParentExecs, &DoDirectiveString));
1185 }
1186 
1187 ////////////////////////////////////////////////////////////////////////////////
1188 /// Update the priorities of the active sessions.
1189 
1191  char *val, XrdOucStream *cfg, bool rcf)
1192 {
1193  XPDLOC(SMGR, "ProofServMgr::DoDirective")
1194 
1195  if (!d)
1196  // undefined inputs
1197  return -1;
1198 
1199  if (d->fName == "proofservmgr") {
1200  return DoDirectiveProofServMgr(val, cfg, rcf);
1201  } else if (d->fName == "putenv") {
1202  return DoDirectivePutEnv(val, cfg, rcf);
1203  } else if (d->fName == "putrc") {
1204  return DoDirectivePutRc(val, cfg, rcf);
1205  } else if (d->fName == "shutdown") {
1206  return DoDirectiveShutdown(val, cfg, rcf);
1207  }
1208  TRACE(XERR,"unknown directive: "<<d->fName);
1209  return -1;
1210 }
1211 
1212 ////////////////////////////////////////////////////////////////////////////////
1213 /// Process 'proofswrvmgr' directive
1214 /// eg: xpd.proofswrvmgr checkfq:120 termto:100 verifyto:5 recoverto:20
1215 
1216 int XrdProofdProofServMgr::DoDirectiveProofServMgr(char *val, XrdOucStream *cfg, bool rcf)
1217 {
1218  XPDLOC(SMGR, "ProofServMgr::DoDirectiveProofServMgr")
1219 
1220  if (!val || !cfg)
1221  // undefined inputs
1222  return -1;
1223 
1224  if (rcf)
1225  // Do not reconfigure this (need to check what happens with the cron thread ...
1226  return 0;
1227 
1228  int checkfq = -1;
1229  int termto = -1;
1230  int verifyto = -1;
1231  int recoverto = -1;
1232  int checklost = 0;
1233  int usefork = 0;
1234 
1235  while (val) {
1236  XrdOucString tok(val);
1237  if (tok.beginswith("checkfq:")) {
1238  tok.replace("checkfq:", "");
1239  checkfq = strtol(tok.c_str(), 0, 10);
1240  } else if (tok.beginswith("termto:")) {
1241  tok.replace("termto:", "");
1242  termto = strtol(tok.c_str(), 0, 10);
1243  } else if (tok.beginswith("verifyto:")) {
1244  tok.replace("verifyto:", "");
1245  verifyto = strtol(tok.c_str(), 0, 10);
1246  } else if (tok.beginswith("recoverto:")) {
1247  tok.replace("recoverto:", "");
1248  recoverto = strtol(tok.c_str(), 0, 10);
1249  } else if (tok.beginswith("checklost:")) {
1250  tok.replace("checklost:", "");
1251  checklost = strtol(tok.c_str(), 0, 10);
1252  } else if (tok.beginswith("usefork:")) {
1253  tok.replace("usefork:", "");
1254  usefork = strtol(tok.c_str(), 0, 10);
1255  }
1256  // Get next
1257  val = cfg->GetWord();
1258  }
1259 
1260  // Check deprecated 'if' directive
1261  if (fMgr->Host() && cfg)
1262  if (XrdProofdAux::CheckIf(cfg, fMgr->Host()) == 0)
1263  return 0;
1264 
1265  // Set the values
1266  fCheckFrequency = (XPD_LONGOK(checkfq) && checkfq > 0) ? checkfq : fCheckFrequency;
1267  fTerminationTimeOut = (XPD_LONGOK(termto) && termto > 0) ? termto : fTerminationTimeOut;
1268  fVerifyTimeOut = (XPD_LONGOK(verifyto) && (verifyto > fCheckFrequency + 1))
1269  ? verifyto : fVerifyTimeOut;
1270  fRecoverTimeOut = (XPD_LONGOK(recoverto) && recoverto > 0) ? recoverto : fRecoverTimeOut;
1271  if (XPD_LONGOK(checklost)) fCheckLost = (checklost != 0) ? 1 : 0;
1272  if (XPD_LONGOK(usefork)) fUseFork = (usefork != 0) ? 1 : 0;
1273 
1274  XrdOucString msg;
1275  XPDFORM(msg, "checkfq: %d s, termto: %d s, verifyto: %d s, recoverto: %d s, checklost: %d, usefork: %d",
1277  TRACE(ALL, msg);
1278 
1279  return 0;
1280 }
1281 
1282 ////////////////////////////////////////////////////////////////////////////////
1283 /// Process 'putenv' directives
1284 
1285 int XrdProofdProofServMgr::DoDirectivePutEnv(char *val, XrdOucStream *cfg, bool)
1286 {
1287  if (!val)
1288  // undefined inputs
1289  return -1;
1290 
1291  // Parse env variables to be passed to 'proofserv':
1292  XrdOucString users, groups, rcval, rcnam;
1293  int smi = -1, smx = -1, vmi = -1, vmx = -1;
1294  bool hex = 0;
1295  ExtractEnv(val, cfg, users, groups, rcval, rcnam, smi, smx, vmi, vmx, hex);
1296 
1297  // Adjust name of the variable
1298  int iequ = rcnam.find('=');
1299  if (iequ == STR_NPOS) return -1;
1300  rcnam.erase(iequ);
1301 
1302  // Fill entries
1303  FillEnvList(&fProofServEnvs, rcnam.c_str(), rcval.c_str(),
1304  users.c_str(), groups.c_str(), smi, smx, vmi, vmx, hex);
1305 
1306  return 0;
1307 }
1308 
1309 ////////////////////////////////////////////////////////////////////////////////
1310 /// Process 'putrc' directives.
1311 /// Syntax:
1312 /// xpd.putrc [u:<usr1>,<usr2>,...] [g:<grp1>,<grp2>,...]
1313 /// [s:[svnmin][-][svnmax]] [v:[vermin][-][vermax]] RcVarName RcVarValue
1314 /// NB: <usr1>,... and <grp1>,... may contain the wild card '*'
1315 
1316 int XrdProofdProofServMgr::DoDirectivePutRc(char *val, XrdOucStream *cfg, bool)
1317 {
1318  if (!val || !cfg)
1319  // undefined inputs
1320  return -1;
1321 
1322  // Parse rootrc variables to be passed to 'proofserv':
1323  XrdOucString users, groups, rcval, rcnam;
1324  int smi = -1, smx = -1, vmi = -1, vmx = -1;
1325  bool hex = 0;
1326  ExtractEnv(val, cfg, users, groups, rcval, rcnam, smi, smx, vmi, vmx, hex);
1327 
1328  // Fill entries
1329  FillEnvList(&fProofServRCs, rcnam.c_str(), rcval.c_str(),
1330  users.c_str(), groups.c_str(), smi, smx, vmi, vmx, hex);
1331 
1332  return 0;
1333 }
1334 
1335 ////////////////////////////////////////////////////////////////////////////////
1336 /// Extract env information from the stream 'cfg'
1337 
1338 void XrdProofdProofServMgr::ExtractEnv(char *val, XrdOucStream *cfg,
1339  XrdOucString &users, XrdOucString &groups,
1340  XrdOucString &rcval, XrdOucString &rcnam,
1341  int &smi, int &smx, int &vmi, int &vmx, bool &hex)
1342 {
1343  XrdOucString ssvn, sver;
1344  int idash = -1;
1345  while (val && val[0]) {
1346  if (!strncmp(val, "u:", 2)) {
1347  users = val;
1348  users.erase(0,2);
1349  } else if (!strncmp(val, "g:", 2)) {
1350  groups = val;
1351  groups.erase(0,2);
1352  } else if (!strncmp(val, "s:", 2)) {
1353  ssvn = val;
1354  ssvn.erase(0,2);
1355  idash = ssvn.find('-');
1356  if (idash != STR_NPOS) {
1357  if (ssvn.isdigit(0, idash-1)) smi = ssvn.atoi(0, idash-1);
1358  if (ssvn.isdigit(idash+1)) smx = ssvn.atoi(idash+1);
1359  } else {
1360  if (ssvn.isdigit()) smi = ssvn.atoi();
1361  }
1362  } else if (!strncmp(val, "v:", 2)) {
1363  sver = val;
1364  sver.erase(0,2);
1365  hex = 0;
1366  if (sver.beginswith('x')) {
1367  hex = 1;
1368  sver.erase(0,1);
1369  }
1370  idash = sver.find('-');
1371  if (idash != STR_NPOS) {
1372  if (sver.isdigit(0, idash-1)) vmi = sver.atoi(0, idash-1);
1373  if (sver.isdigit(idash+1)) vmx = sver.atoi(idash+1);
1374  } else {
1375  if (sver.isdigit()) vmi = sver.atoi();
1376  }
1377  } else {
1378  if (rcval.length() > 0) {
1379  rcval += ' ';
1380  } else {
1381  rcnam = val;
1382  }
1383  rcval += val;
1384  }
1385  val = cfg->GetWord();
1386  }
1387  // Done
1388  return;
1389 }
1390 
1391 ////////////////////////////////////////////////////////////////////////////////
1392 /// Fill env entry(ies) in the relevant list
1393 
1394 void XrdProofdProofServMgr::FillEnvList(std::list<XpdEnv> *el, const char *nam, const char *val,
1395  const char *usrs, const char *grps,
1396  int smi, int smx, int vmi, int vmx, bool hex)
1397 {
1398  XPDLOC(SMGR, "ProofServMgr::FillEnvList")
1399 
1400  if (!el) {
1401  TRACE(ALL, "env list undefined!");
1402  return;
1403  }
1404 
1405  XrdOucString users(usrs), groups(grps);
1406  // Transform version numbers in the human unreadable format used internally (version code)
1407  if (vmi > 0) vmi = XpdEnv::ToVersCode(vmi, hex);
1408  if (vmx > 0) vmx = XpdEnv::ToVersCode(vmx, hex);
1409  // Create the entry
1410  XpdEnv xpe(nam, val, users.c_str(), groups.c_str(), smi, smx, vmi, vmx);
1411  if (users.length() > 0) {
1412  XrdOucString usr;
1413  int from = 0;
1414  while ((from = users.tokenize(usr, from, ',')) != -1) {
1415  if (usr.length() > 0) {
1416  if (groups.length() > 0) {
1417  XrdOucString grp;
1418  int fromg = 0;
1419  while ((fromg = groups.tokenize(grp, from, ',')) != -1) {
1420  if (grp.length() > 0) {
1421  xpe.Reset(nam, val, usr.c_str(), grp.c_str(), smi, smx, vmi, vmx);
1422  el->push_back(xpe);
1423  }
1424  }
1425  } else {
1426  xpe.Reset(nam, val, usr.c_str(), 0, smi, smx, vmi, vmx);
1427  el->push_back(xpe);
1428  }
1429  }
1430  }
1431  } else {
1432  if (groups.length() > 0) {
1433  XrdOucString grp;
1434  int fromg = 0;
1435  while ((fromg = groups.tokenize(grp, fromg, ',')) != -1) {
1436  if (grp.length() > 0) {
1437  xpe.Reset(nam, val, 0, grp.c_str(), smi, smx, vmi, vmx);
1438  el->push_back(xpe);
1439  }
1440  }
1441  } else {
1442  el->push_back(xpe);
1443  }
1444  }
1445  // Done
1446  return;
1447 }
1448 
1449 ////////////////////////////////////////////////////////////////////////////////
1450 /// Process 'shutdown' directive
1451 
1452 int XrdProofdProofServMgr::DoDirectiveShutdown(char *val, XrdOucStream *cfg, bool)
1453 {
1454  if (!val || !cfg)
1455  // undefined inputs
1456  return -1;
1457 
1458  int opt = -1;
1459  int delay = -1;
1460 
1461  // Shutdown option
1462  int dp = strtol(val,0,10);
1463  if (dp >= 0 && dp <= 2)
1464  opt = dp;
1465  // Shutdown delay
1466  if ((val = cfg->GetWord())) {
1467  int l = strlen(val);
1468  int f = 1;
1469  XrdOucString tval = val;
1470  // Parse
1471  if (val[l-1] == 's') {
1472  val[l-1] = 0;
1473  } else if (val[l-1] == 'm') {
1474  f = 60;
1475  val[l-1] = 0;
1476  } else if (val[l-1] == 'h') {
1477  f = 3600;
1478  val[l-1] = 0;
1479  } else if (val[l-1] < 48 || val[l-1] > 57) {
1480  f = -1;
1481  }
1482  if (f > 0) {
1483  int de = strtol(val,0,10);
1484  if (de > 0)
1485  delay = de * f;
1486  }
1487  }
1488 
1489  // Check deprecated 'if' directive
1490  if (fMgr->Host() && cfg)
1491  if (XrdProofdAux::CheckIf(cfg, fMgr->Host()) == 0)
1492  return 0;
1493 
1494  // Set the values
1495  fShutdownOpt = (opt > -1) ? opt : fShutdownOpt;
1496  fShutdownDelay = (delay > -1) ? delay : fShutdownDelay;
1497 
1498  return 0;
1499 }
1500 
1501 ////////////////////////////////////////////////////////////////////////////////
1502 /// Process manager request
1503 
1505 {
1506  XPDLOC(SMGR, "ProofServMgr::Process")
1507 
1508  int rc = 1;
1509  XPD_SETRESP(p, "Process");
1510 
1511  TRACEP(p, REQ, "enter: req id: " << p->Request()->header.requestid << " (" <<
1512  XrdProofdAux::ProofRequestTypes(p->Request()->header.requestid) << ")");
1513 
1514  XrdSysMutexHelper mtxh(p->Client()->Mutex());
1515 
1516  // Once logged-in, the user can request the real actions
1517  XrdOucString emsg("Invalid request code: ");
1518 
1519  int twait = 20;
1520 
1521  if (Pipe()->Post(XrdProofdProofServMgr::kProcessReq, 0) != 0) {
1522  response->Send(kXR_ServerError,
1523  "ProofServMgr::Process: error posting internal pipe for authorization to proceed");
1524  return 0;
1525  }
1526  if (fProcessSem.Wait(twait) != 0) {
1527  response->Send(kXR_ServerError,
1528  "ProofServMgr::Process: timed-out waiting for authorization to proceed - retry later");
1529  return 0;
1530  }
1531 
1532  // This is needed to block the session checks
1534 
1535  switch(p->Request()->header.requestid) {
1536  case kXP_create:
1537  return Create(p);
1538  case kXP_destroy:
1539  return Destroy(p);
1540  case kXP_attach:
1541  return Attach(p);
1542  case kXP_detach:
1543  return Detach(p);
1544  default:
1545  emsg += p->Request()->header.requestid;
1546  break;
1547  }
1548 
1549  // Whatever we have, it's not valid
1550  response->Send(kXR_InvalidRequest, emsg.c_str());
1551  return 0;
1552 }
1553 
1554 ////////////////////////////////////////////////////////////////////////////////
1555 /// Handle a request to attach to an existing session
1556 
1558 {
1559  XPDLOC(SMGR, "ProofServMgr::Attach")
1560 
1561  int psid = -1, rc = 0;
1562  XPD_SETRESP(p, "Attach");
1563 
1564  // Unmarshall the data
1565  psid = ntohl(p->Request()->proof.sid);
1566  TRACEP(p, REQ, "psid: "<<psid<<", CID = "<<p->CID());
1567 
1568  // The client instance must be defined
1569  XrdProofdClient *c = p->Client();
1570  if (!c) {
1571  TRACEP(p, XERR, "client instance undefined");
1572  response->Send(kXR_ServerError,"client instance undefined");
1573  return 0;
1574  }
1575 
1576  // Find server session; sessions maybe recovering, so we need to take
1577  // that into account
1578  XrdProofdProofServ *xps = 0;
1579  int now = time(0);
1580  int deadline = -1, defdeadline = now + fRecoverTimeOut;
1581  while ((deadline < 0) || (now < deadline)) {
1582  if (!(xps = c->GetServer(psid)) || !xps->IsValid()) {
1583  // If the client is recovering start regular checks
1584  if (!IsClientRecovering(c->User(), c->Group(), deadline)) {
1585  // Failure
1586  TRACEP(p, XERR, "session ID not found: "<<psid);
1587  response->Send(kXR_InvalidRequest,"session ID not found");
1588  return 0;
1589  } else {
1590  // Make dure we do not enter an infinite loop
1591  deadline = (deadline > 0) ? deadline : defdeadline;
1592  // Wait until deadline in 1 sec steps
1593  sleep(1);
1594  now++;
1595  }
1596  } else {
1597  // Found
1598  break;
1599  }
1600  }
1601  // If we deadline we should fail now
1602  if (!xps || !xps->IsValid()) {
1603  TRACEP(p, XERR, "session ID not found: "<<psid);
1604  response->Send(kXR_InvalidRequest,"session ID not found");
1605  return 0;
1606  }
1607  TRACEP(p, DBG, "xps: "<<xps<<", status: "<< xps->Status());
1608 
1609  // Stream ID
1610  unsigned short sid;
1611  memcpy((void *)&sid, (const void *)&(p->Request()->header.streamid[0]), 2);
1612 
1613  // We associate this instance to the corresponding slot in the
1614  // session vector of attached clients
1615  XrdClientID *csid = xps->GetClientID(p->CID());
1616  csid->SetP(p);
1617  csid->SetSid(sid);
1618 
1619  // Take parentship, if orphalin
1620  if (!(xps->Parent()))
1621  xps->SetParent(csid);
1622 
1623  // Notify to user
1624  int protvers = (xps && xps->ROOT()) ? xps->ROOT()->SrvProtVers() : -1;
1625  if (p->ConnType() == kXPD_ClientMaster) {
1626  // Send also back the data pool url
1627  XrdOucString dpu = fMgr->PoolURL();
1628  if (!dpu.endswith('/'))
1629  dpu += '/';
1630  dpu += fMgr->NameSpace();
1631  response->SendI(psid, protvers, (kXR_int16)XPROOFD_VERSBIN,
1632  (void *) dpu.c_str(), dpu.length());
1633  } else
1634  response->SendI(psid, protvers, (kXR_int16)XPROOFD_VERSBIN);
1635 
1636  // Send saved start processing message, if not idle
1637  if (xps->Status() == kXPD_running && xps->StartMsg()) {
1638  TRACEP(p, XERR, "sending start process message ("<<xps->StartMsg()->fSize<<" bytes)");
1639  response->Send(kXR_attn, kXPD_msg,
1640  xps->StartMsg()->fBuff, xps->StartMsg()->fSize);
1641  }
1642 
1643  // Over
1644  return 0;
1645 }
1646 
1647 ////////////////////////////////////////////////////////////////////////////////
1648 /// Allocate and prepare the XrdProofdProofServ object describing this session
1649 
1652  unsigned short &sid)
1653 {
1654  XPDLOC(SMGR, "ProofServMgr::PrepareProofServ")
1655 
1656  // Allocate next free server ID and fill in the basic stuff
1657  XrdProofdProofServ *xps = p->Client()->GetFreeServObj();
1658  xps->SetClient(p->Client()->User());
1659  xps->SetSrvType(p->ConnType());
1660 
1661  // Prepare the stream identifier
1662  memcpy((void *)&sid, (const void *)&(p->Request()->header.streamid[0]), 2);
1663  // We associate this instance to the corresponding slot in the
1664  // session vector of attached clients
1665  XrdClientID *csid = xps->GetClientID(p->CID());
1666  csid->SetSid(sid);
1667  csid->SetP(p);
1668  // Take parentship, if orphalin
1669  xps->SetParent(csid);
1670 
1671  // The ROOT version to be used
1672  xps->SetROOT(p->Client()->ROOT());
1673  XrdOucString msg;
1674  XPDFORM(msg, "using ROOT version: %s", xps->ROOT()->Export());
1675  TRACEP(p, REQ, msg);
1676  if (p->ConnType() == kXPD_ClientMaster) {
1677  // Notify the client if using a version different from the default one
1678  if (fMgr && p->Client()->ROOT() != fMgr->ROOTMgr()->DefaultVersion()) {
1679  XPDFORM(msg, "++++ Using NON-default ROOT version: %s ++++\n", xps->ROOT()->Export());
1680  r->Send(kXR_attn, kXPD_srvmsg, (char *) msg.c_str(), msg.length());
1681  }
1682  }
1683 
1684  // Done
1685  return xps;
1686 }
1687 
1688 ////////////////////////////////////////////////////////////////////////////////
1689 /// Extract relevant quantities from the buffer received during a create request
1690 
1692  XrdProofdProofServ *xps,
1693  XrdOucString &tag, XrdOucString &ord,
1694  XrdOucString &cffile,
1695  XrdOucString &uenvs, int &intwait)
1696 {
1697  XPDLOC(SMGR, "ProofServMgr::ParseCreateBuffer")
1698 
1699  // Parse buffer
1700  char *buf = p->Argp()->buff;
1701  int len = p->Request()->proof.dlen;
1702 
1703  // Extract session tag
1704  tag.assign(buf,0,len-1);
1705 
1706  TRACEP(p, DBG, "received buf: "<<tag);
1707 
1708  tag.erase(tag.find('|'));
1709  xps->SetTag(tag.c_str());
1710  TRACEP(p, DBG, "tag: "<<tag);
1711 
1712  // Extract ordinal number
1713  ord = "0";
1714  if ((p->ConnType() == kXPD_MasterWorker) || (p->ConnType() == kXPD_MasterMaster)) {
1715  ord.assign(buf,0,len-1);
1716  int iord = ord.find("|ord:");
1717  if (iord != STR_NPOS) {
1718  ord.erase(0,iord+5);
1719  ord.erase(ord.find("|"));
1720  } else
1721  ord = "0";
1722  }
1723  xps->SetOrdinal(ord.c_str());
1724 
1725  // Extract config file, if any (for backward compatibility)
1726  cffile.assign(buf,0,len-1);
1727  int icf = cffile.find("|cf:");
1728  if (icf != STR_NPOS) {
1729  cffile.erase(0,icf+4);
1730  cffile.erase(cffile.find("|"));
1731  } else
1732  cffile = "";
1733 
1734  // Extract # number of workers, if plite master
1735  XrdOucString plitenwk;
1736  plitenwk.assign(buf,0,len-1);
1737  int inwk = plitenwk.find("|plite:");
1738  if (inwk != STR_NPOS) {
1739  plitenwk.erase(0,inwk+7);
1740  plitenwk.erase(plitenwk.find("|"));
1741  int nwk = plitenwk.atoi();
1742  if (nwk > -1) {
1743  xps->SetPLiteNWrks(nwk);
1744  TRACEP(p, DBG, "P-Lite master with "<<nwk<<" workers (0 means # or cores)");
1745  }
1746  }
1747 
1748  // Extract user envs, if any
1749  uenvs.assign(buf,0,len-1);
1750  int ienv = uenvs.find("|envs:");
1751  if (ienv != STR_NPOS) {
1752  uenvs.erase(0,ienv+6);
1753  uenvs.erase(uenvs.find("|"));
1754  xps->SetUserEnvs(uenvs.c_str());
1755  } else
1756  uenvs = "";
1757 
1758  // Check if the user wants to wait more for the session startup
1759  intwait = fInternalWait;
1760  if (uenvs.length() > 0) {
1761  TRACEP(p, DBG, "user envs: "<<uenvs);
1762  int iiw = STR_NPOS;
1763  if ((iiw = uenvs.find("PROOF_INTWAIT=")) != STR_NPOS) {
1764  XrdOucString s(uenvs, iiw + strlen("PROOF_INTWAIT="));
1765  s.erase(s.find(','));
1766  if (s.isdigit()) {
1767  intwait = s.atoi();
1768  TRACEP(p, ALL, "startup internal wait set by user to "<<intwait);
1769  }
1770  }
1771  }
1772 }
1773 
1774 ////////////////////////////////////////////////////////////////////////////////
1775 /// Handle a request to create a new session
1776 
1778 {
1779  XPDLOC(SMGR, "ProofServMgr::Create")
1780 
1781  int psid = -1, rc = 0;
1782  XPD_SETRESP(p, "Create");
1783 
1784  TRACEP(p, DBG, "enter");
1785  XrdOucString msg;
1786 
1787  XpdSrvMgrCreateGuard mcGuard;
1788 
1789  // Check if we are allowed to start a new session
1790  int mxsess = (fMgr && fMgr->ProofSched()) ? fMgr->ProofSched()->MaxSessions() : -1;
1791  if (p->ConnType() == kXPD_ClientMaster && mxsess > 0) {
1793  int cursess = CurrentSessions();
1794  TRACEP(p,ALL," cursess: "<<cursess);
1795  if (mxsess <= cursess) {
1796  XPDFORM(msg, " ++++ Max number of sessions reached (%d) - please retry later ++++ \n", cursess);
1797  response->Send(kXR_attn, kXPD_srvmsg, (char *) msg.c_str(), msg.length());
1798  response->Send(kXP_TooManySess, "cannot start a new session");
1799  return 0;
1800  }
1801  // If we fail this guarantees that the counters are decreased, if needed
1802  mcGuard.Set(&fCurrentSessions);
1803  }
1804 
1805  // Update counter to control checks during creation
1807  if (TRACING(DBG)) {
1808  int nc = CheckCounter(kCreateCnt);
1809  TRACEP(p, DBG, nc << " threads are creating a new session");
1810  }
1811 
1812  // Allocate and prepare the XrdProofdProofServ object describing this session
1813  unsigned short sid;
1814  XrdProofdProofServ *xps = PrepareProofServ(p, response, sid);
1815  psid = xps->ID();
1816 
1817  // Unmarshall log level
1818  int loglevel = ntohl(p->Request()->proof.int1);
1819 
1820  // Parse buffer
1821  int intwait;
1822  XrdOucString tag, ord, cffile, uenvs;
1823  ParseCreateBuffer(p, xps, tag, ord, cffile, uenvs, intwait);
1824 
1825  // Notify
1826  TRACEP(p, DBG, "{ord,cfg,psid,cid,log}: {"<<ord<<","<<cffile<<","<<psid
1827  <<","<<p->CID()<<","<<loglevel<<"}");
1828 
1829  // Here we fork: for some weird problem on SMP machines there is a
1830  // non-zero probability for a deadlock situation in system mutexes.
1831  // The semaphore seems to have solved the problem.
1832  if (fForkSem.Wait(10) != 0) {
1833  xps->Reset();
1834  // Timeout acquire fork semaphore
1835  response->Send(kXP_ServerError, "timed-out acquiring fork semaphore");
1836  return 0;
1837  }
1838 
1839  // Pipe for child-to-parent communications during setup
1840  XrdProofdPipe fpc, fcp;
1841  if (!(fpc.IsValid()) || !(fcp.IsValid())) {
1842  xps->Reset();
1843  // Failure creating pipe
1844  response->Send(kXP_ServerError,
1845  "unable to create pipes for communication during setup");
1846  return 0;
1847  }
1848 
1849  // Start setting up the unique tag and relevant dirs for this session
1850  ProofServEnv_t in = {xps, loglevel, cffile.c_str(), "", "", tag.c_str(), "", "", 1};
1851  GetTagDirs(0, p, xps, in.fSessionTag, in.fTopSessionTag, in.fSessionDir, in.fWrkDir);
1852 
1853  // Fork an agent process to handle this session
1854  int pid = -1;
1855  TRACEP(p, FORK,"Forking external proofsrv");
1856  if (!(pid = fMgr->Sched()->Fork("proofsrv"))) {
1857 
1858  // Finalize unique tag and relevant dirs for this session
1859  GetTagDirs((int)getpid(),
1860  p, xps, in.fSessionTag, in.fTopSessionTag, in.fSessionDir, in.fWrkDir);
1861 
1862  // Create log file path
1863  FormFileNameInSessionDir(p, xps, in.fSessionDir.c_str(), "log", in.fLogFile);
1864 
1865  // Log to the session log file from now on
1866  if (fLogger) fLogger->Bind(in.fLogFile.c_str());
1867  TRACE(FORK, "log file: "<<in.fLogFile);
1868 
1869  XrdOucString pmsg = "*** spawned child process ";
1870  pmsg += (int) getpid();
1871  pmsg += " ***";
1872  TRACE(ALL, pmsg);
1873 
1874  // These files belongs to the client
1875  if (chown(in.fLogFile.c_str(), p->Client()->UI().fUid, p->Client()->UI().fGid) != 0)
1876  TRACE(XERR, "chown on '"<<in.fLogFile.c_str()<<"'; errno: "<<errno);
1877 
1878  XpdMsg xmsg;
1879  XrdOucString path, sockpath, emsg;
1880 
1881  // Receive the admin path from the parent
1882  if (fpc.Poll() < 0) {
1883  TRACE(XERR, "error while polling to receive the admin path from parent - EXIT" );
1884  exit(1);
1885  }
1886  if (fpc.Recv(xmsg) != 0) {
1887  TRACE(XERR, "error reading message while waiting for the admin path from parent - EXIT" );
1888  exit(1);
1889  }
1890  if (xmsg.Type() < 0) {
1891  TRACE(XERR, "the parent failed to setup the admin path - EXIT" );
1892  exit(1);
1893  }
1894  // Set the path w/o asserting the related files
1895  path = xmsg.Buf();
1896  xps->SetAdminPath(path.c_str(), 0, fMgr->ChangeOwn());
1897  TRACE(FORK, "admin path: "<<path);
1898 
1899  xmsg.Reset();
1900  // Receive the sock path from the parent
1901  if (fpc.Poll() < 0) {
1902  TRACE(XERR, "error while polling to receive the sock path from parent - EXIT" );
1903  exit(1);
1904  }
1905  if (fpc.Recv(xmsg) != 0) {
1906  TRACE(XERR, "error reading message while waiting for the sock path from parent - EXIT" );
1907  exit(1);
1908  }
1909  if (xmsg.Type() < 0) {
1910  TRACE(XERR, "the parent failed to setup the sock path - EXIT" );
1911  exit(1);
1912  }
1913  // Set the UNIX sock path
1914  sockpath = xmsg.Buf();
1915  xps->SetUNIXSockPath(sockpath.c_str());
1916  TRACE(FORK, "UNIX sock path: "<<sockpath);
1917 
1918  // We set to the user ownerships and create relevant dirs
1919  bool asserdatadir = 1;
1920  int srvtype = xps->SrvType();
1921  TRACE(ALL,"srvtype = "<< srvtype);
1922  if (xps->SrvType() != kXPD_Worker && !strchr(fMgr->DataDirOpts(), 'M')) {
1923  asserdatadir = 0;
1924  } else if (xps->SrvType() == kXPD_Worker && !strchr(fMgr->DataDirOpts(), 'W')) {
1925  asserdatadir = 0;
1926  }
1927  const char *pord = asserdatadir ? ord.c_str() : 0;
1928  const char *ptag = asserdatadir ? in.fSessionTag.c_str() : 0;
1929  if (SetUserOwnerships(p, pord, ptag) != 0) {
1930  emsg = "SetUserOwnerships did not return OK - EXIT";
1931  TRACE(XERR, emsg);
1932  if (fcp.Post(0, emsg.c_str()) != 0)
1933  TRACE(XERR, "cannot write to internal pipe; errno: "<<errno);
1934  exit(1);
1935  }
1936 
1937  // We set to the user environment
1938  if (SetUserEnvironment(p) != 0) {
1939  emsg = "SetUserEnvironment did not return OK - EXIT";
1940  TRACE(XERR, emsg);
1941  if (fcp.Post(0, emsg.c_str()) != 0)
1942  TRACE(XERR, "cannot write to internal pipe; errno: "<<errno);
1943  exit(1);
1944  }
1945 
1946  char *argvv[7] = {0};
1947 
1948  // We set to the user environment
1949  if (!fMgr) {
1950  emsg = "XrdProofdManager instance undefined!";
1951  TRACE(XERR, emsg);
1952  if (fcp.Post(0, emsg.c_str()) != 0)
1953  TRACE(XERR, "cannot write to internal pipe; errno: "<<errno);
1954  exit(1);
1955  }
1956  char *sxpd = 0;
1957  if (fMgr->AdminPath()) {
1958  // We add our admin path to be able to identify processes coming from us
1959  size_t len = strlen(fMgr->AdminPath()) + strlen("xpdpath:") + 1;
1960  sxpd = new char[len];
1961  snprintf(sxpd, len, "xpdpath:%s", fMgr->AdminPath());
1962  } else {
1963  // We add our PID to be able to identify processes coming from us
1964  sxpd = new char[10];
1965  snprintf(sxpd, 10, "%d", getppid());
1966  }
1967 
1968  // Log level
1969  char slog[10] = {0};
1970  snprintf(slog, 10, "%d", loglevel);
1971 
1972  // Server type
1973  char ssrv[10] = {0};
1974  snprintf(ssrv, 10, "%d", xps->SrvType());
1975 
1976  // start server
1977  argvv[0] = (char *) xps->ROOT()->PrgmSrv();
1978  argvv[1] = (char *)((p->ConnType() == kXPD_MasterWorker) ? "proofslave"
1979  : "proofserv");
1980  argvv[2] = (char *)"xpd";
1981  argvv[3] = (char *)sxpd;
1982  argvv[4] = (char *)slog;
1983  argvv[5] = (char *)ssrv;
1984  argvv[6] = 0;
1985 
1986  // Set environment for proofserv
1987  if (SetProofServEnv(p, (void *)&in) != 0) {
1988  emsg = "SetProofServEnv did not return OK - EXIT";
1989  TRACE(XERR, emsg);
1990  if (fcp.Post(0, emsg.c_str()) != 0)
1991  TRACE(XERR, "cannot write to internal pipe; errno: "<<errno);
1992  exit(1);
1993  }
1994  TRACE(FORK, (int)getpid() << ": proofserv env set up");
1995 
1996  // Setup OK: now we go
1997  // Communicate the logfile path
1998  if (fcp.Post(1, xps->Fileout()) != 0) {
1999  TRACE(XERR, "cannot write log file path to internal pipe; errno: "<<errno);
2000  exit(1);
2001  }
2002  TRACE(FORK, (int)getpid()<< ": log file path communicated");
2003 
2004  // Unblock SIGUSR1 and SIGUSR2
2005  sigset_t myset;
2006  sigemptyset(&myset);
2007  sigaddset(&myset, SIGUSR1);
2008  sigaddset(&myset, SIGUSR2);
2009  pthread_sigmask(SIG_UNBLOCK, &myset, 0);
2010 
2011  // Close pipes
2012  fpc.Close();
2013  fcp.Close();
2014 
2015  TRACE(FORK, (int)getpid()<<": user: "<<p->Client()->User()<<
2016  ", uid: "<<getuid()<<", euid:"<<geteuid()<<
2017  ", psrv: "<<xps->ROOT()->PrgmSrv()<<", argvv[1]: "<<argvv[1]);
2018  // Run the program
2019  execv(xps->ROOT()->PrgmSrv(), argvv);
2020 
2021  // We should not be here!!!
2022  TRACE(XERR, "returned from execv: bad, bad sign !!! errno:" << (int)errno);
2023  exit(1);
2024  }
2025 
2026  // Wakeup colleagues
2027  fForkSem.Post();
2028 
2029  // parent process
2030  if (pid < 0) {
2031  xps->Reset();
2032  // Failure in forking
2033  response->Send(kXP_ServerError, "could not fork agent");
2034  return 0;
2035  }
2036 
2037  TRACEP(p, FORK,"Parent process: child is "<<pid);
2038  XrdOucString emsg;
2039 
2040  // Finalize unique tag and relevant dirs for this session
2041  GetTagDirs((int)pid, p, xps, in.fSessionTag, in.fTopSessionTag, in.fSessionDir, in.fWrkDir);
2042 
2043  // Create log file path
2044  FormFileNameInSessionDir(p, xps, in.fSessionDir.c_str(), "log", in.fLogFile);
2045 
2046  TRACEP(p, FORK, "log file: "<<in.fLogFile);
2047 
2048  // Log prefix
2049  XrdOucString npfx;
2050  XPDFORM(npfx, "%s-%s:", (p->ConnType() == kXPD_MasterWorker) ? "wrk" : "mst", xps->Ordinal());
2051 
2052  // Cleanup current socket, if any
2053  if (xps->UNIXSock()) {
2054  TRACEP(p, FORK,"current UNIX sock: "<<xps->UNIXSock() <<", path: "<<xps->UNIXSockPath());
2055  xps->DeleteUNIXSock();
2056  }
2057 
2058  // Admin and UNIX Socket Path (set path and create the socket); we need to
2059  // set and create them in here, otherwise the cleaning may remove the socket
2060  XrdOucString path, sockpath;
2061  XPDFORM(path, "%s/%s.%s.%d", fActiAdminPath.c_str(),
2062  p->Client()->User(), p->Client()->Group(), pid);
2063  // Sock path under dedicated directory to avoid problems related to its length
2064  XPDFORM(sockpath, "%s/xpd.%d.%d", fMgr->SockPathDir(), fMgr->Port(), pid);
2065  struct sockaddr_un unserver;
2066  if (sockpath.length() > (int)(sizeof(unserver.sun_path) - 1)) {
2067  emsg = "socket path very long (";
2068  emsg += sockpath.length();
2069  emsg += "): this may lead to stack corruption!";
2070  emsg += " Use xpd.sockpathdir to change it";
2071  TRACEP(p, XERR, emsg.c_str());
2072  }
2073  int pathrc = 0;
2074  if (!pathrc && !(pathrc = xps->SetAdminPath(path.c_str(), 1, fMgr->ChangeOwn()))) {
2075  // Communicate the path to child
2076  if ((pathrc = fpc.Post(0, path.c_str())) != 0) {
2077  emsg = "failed to communicating path to child";
2078  XrdProofdAux::LogEmsgToFile(in.fLogFile.c_str(), emsg.c_str(), npfx.c_str());
2079  TRACEP(p, XERR, emsg.c_str());
2080  }
2081  } else {
2082  emsg = "failed to setup child admin path";
2083  // Communicate failure to child
2084  if ((pathrc = fpc.Post(-1, path.c_str())) != 0) {
2085  emsg += ": failed communicating failure to child";
2086  XrdProofdAux::LogEmsgToFile(in.fLogFile.c_str(), emsg.c_str(), npfx.c_str());
2087  TRACEP(p, XERR, emsg.c_str());
2088  }
2089  }
2090  // Now create the UNIX sock path
2091  if (!pathrc) {
2092  xps->SetUNIXSockPath(sockpath.c_str());
2093  if ((pathrc = xps->CreateUNIXSock(fEDest)) != 0) {
2094  // Failure
2095  emsg = "failure creating UNIX socket on " ;
2096  emsg += sockpath;
2097  XrdProofdAux::LogEmsgToFile(in.fLogFile.c_str(), emsg.c_str(), npfx.c_str());
2098  TRACEP(p, XERR, emsg.c_str());
2099  }
2100  }
2101  if (!pathrc) {
2102  TRACEP(p, FORK,"UNIX sock: "<<xps->UNIXSockPath());
2103  if ((pathrc = chown(sockpath.c_str(), p->Client()->UI().fUid, p->Client()->UI().fGid)) != 0) {
2104  emsg = "failure changing ownership of the UNIX socket on " ;
2105  emsg += sockpath;
2106  emsg += "; errno: " ;
2107  emsg += errno;
2108  XrdProofdAux::LogEmsgToFile(in.fLogFile.c_str(), emsg.c_str(), npfx.c_str());
2109  TRACEP(p, XERR, emsg.c_str());
2110  }
2111  }
2112  // Communicate sockpath or failure, if any
2113  if (!pathrc) {
2114  // Communicate the path to child
2115  if ((pathrc = fpc.Post(0, sockpath.c_str())) != 0) {
2116  emsg = "failed to communicating path to child";
2117  XrdProofdAux::LogEmsgToFile(in.fLogFile.c_str(), emsg.c_str(), npfx.c_str());
2118  TRACEP(p, XERR, emsg.c_str());
2119  }
2120  } else {
2121  emsg = "failed to setup child admin path";
2122  // Communicate failure to child
2123  if ((pathrc = fpc.Post(-1, sockpath.c_str())) != 0) {
2124  emsg += ": failed communicating failure to child";
2125  XrdProofdAux::LogEmsgToFile(in.fLogFile.c_str(), emsg.c_str(), npfx.c_str());
2126  TRACEP(p, XERR, emsg.c_str());
2127  }
2128  }
2129 
2130  if (pathrc != 0) {
2131  // Failure
2132  xps->Reset();
2133  XrdProofdAux::KillProcess(pid, 1, p->Client()->UI(), fMgr->ChangeOwn());
2134  // Make sure that the log file path reaches the caller
2135  emsg += "|log:";
2136  emsg += in.fLogFile;
2137  emsg.insert(npfx, 0);
2138  response->Send(kXP_ServerError, emsg.c_str());
2139  return 0;
2140  }
2141 
2142  TRACEP(p, FORK, "waiting for client setup status ...");
2143 
2144  emsg = "proofserv setup";
2145  // Wait for the setup process on the pipe, 20 secs max (10 x 2000 millisecs): this
2146  // is enough to cover possible delays due to heavy load; the client will anyhow
2147  // retry a few times
2148  int ntry = 10, prc = 0, rst = -1;
2149  while (prc == 0 && ntry--) {
2150  // Poll for 2 secs
2151  if ((prc = fcp.Poll(2)) > 0) {
2152  // Got something: read the message out
2153  XpdMsg xmsg;
2154  if (fcp.Recv(xmsg) != 0) {
2155  emsg = "error receiving message from pipe";
2156  XrdProofdAux::LogEmsgToFile(in.fLogFile.c_str(), emsg.c_str(), npfx.c_str());
2157  TRACEP(p, XERR, emsg.c_str());
2158  prc = -1;
2159  break;
2160  }
2161  // Status is the message type
2162  rst = xmsg.Type();
2163  // Read string, if any
2164  XrdOucString xbuf = xmsg.Buf();
2165  if (xbuf.length() <= 0) {
2166  emsg = "error reading buffer {logfile, error message} from message received on the pipe";
2167  XrdProofdAux::LogEmsgToFile(in.fLogFile.c_str(), emsg.c_str(), npfx.c_str());
2168  TRACEP(p, XERR, emsg.c_str());
2169  prc = -1;
2170  break;
2171  }
2172  if (rst > 0) {
2173  // Set the log file
2174  xps->SetFileout(xbuf.c_str());
2175  // Set also the session tag
2176  XrdOucString stag(xbuf);
2177  stag.erase(stag.rfind('/'));
2178  stag.erase(0, stag.find("session-") + strlen("session-"));
2179  xps->SetTag(stag.c_str());
2180 
2181  } else {
2182  // Setup failed: save the error
2183  prc = -1;
2184  emsg = "failed: ";
2185  emsg += xbuf;
2186  XrdProofdAux::LogEmsgToFile(in.fLogFile.c_str(), emsg.c_str(), npfx.c_str());
2187  TRACEP(p, XERR, emsg.c_str());
2188  break;
2189  }
2190 
2191  } else if (prc < 0) {
2192  emsg = "error receive status-of-setup from pipe";
2193  XrdProofdAux::LogEmsgToFile(in.fLogFile.c_str(), emsg.c_str(), npfx.c_str());
2194  TRACEP(p, XERR, emsg.c_str());
2195  break;
2196  } else {
2197  TRACEP(p, FORK, "receiving status-of-setup from pipe: waiting 2 s ..."<<pid);
2198  }
2199  }
2200 
2201  // Close pipes
2202  fpc.Close();
2203  fcp.Close();
2204 
2205  TRACEP(p, FORK, "tags: tag:"<<in.fSessionTag<<" top:"<<in.fTopSessionTag<<" xps:"<<xps->Tag());
2206 
2207  // Notify the user
2208  if (prc <= 0) {
2209  // Timed-out or failed: we are done; if timed-out finalize the notification message
2210  emsg = "failure setting up proofserv" ;
2211  if (prc == 0) emsg += ": timed-out receiving status-of-setup from pipe";
2212  // Dump to the log file
2213  XrdProofdAux::LogEmsgToFile(in.fLogFile.c_str(), emsg.c_str(), npfx.c_str());
2214  // Recycle the session object
2215  xps->Reset();
2216  XrdProofdAux::KillProcess(pid, 1, p->Client()->UI(), fMgr->ChangeOwn());
2217  // Make sure that the log file path reaches the caller
2218  emsg += "|log:";
2219  emsg += in.fLogFile;
2220  TRACEP(p, XERR, emsg.c_str());
2221  emsg.insert(npfx, 0);
2222  response->Send(kXP_ServerError, emsg.c_str());
2223  return 0;
2224 
2225  } else {
2226  // Setup was successful
2227  XrdOucString info;
2228  // The log file path (so we do it independently of a successful session startup)
2229  info += "|log:";
2230  info += xps->Fileout();
2231  // Send it back
2232  response->SendI(psid, xps->ROOT()->SrvProtVers(), (kXR_int16)XPROOFD_VERSBIN,
2233  (void *) info.c_str(), info.length());
2234  }
2235 
2236  // now we wait for the callback to be (successfully) established
2237  TRACEP(p, FORK, "server launched: wait for callback ");
2238 
2239  // Set ID
2240  xps->SetSrvPID(pid);
2241 
2242  // Wait for the call back
2243  if (AcceptPeer(xps, intwait, emsg) != 0) {
2244  emsg = "problems accepting callback: ";
2245  // Failure: kill the child process
2246  if (XrdProofdAux::KillProcess(pid, 0, p->Client()->UI(), fMgr->ChangeOwn()) != 0)
2247  emsg += "process could not be killed - pid: ";
2248  else
2249  emsg += "process killed - pid: ";
2250  emsg += (int)pid;
2251  // Dump to the log file
2252  XrdProofdAux::LogEmsgToFile(in.fLogFile.c_str(), emsg.c_str(), npfx.c_str());
2253  // Reset the instance
2254  xps->Reset();
2255  // Notify
2256  TRACEP(p, XERR, emsg.c_str());
2257  emsg.insert(npfx, 0);
2258  response->Send(kXR_attn, kXPD_errmsg, (char *) emsg.c_str(), emsg.length());
2259  return 0;
2260  }
2261  // Set the group, if any
2262  xps->SetGroup(p->Client()->Group());
2263 
2264  // Change child process priority, if required
2265  int dp = 0;
2266  if (fMgr->PriorityMgr()->SetProcessPriority(xps->SrvPID(),
2267  p->Client()->User(), dp) != 0) {
2268  TRACEP(p, XERR, "problems changing child process priority");
2269  } else if (dp > 0) {
2270  TRACEP(p, DBG, "priority of the child process changed by " << dp << " units");
2271  }
2272 
2273  XrdClientID *cid = xps->Parent();
2274  TRACEP(p, FORK, "xps: "<<xps<<", ClientID: "<<(int *)cid<<" (sid: "<<sid<<")"<<" NClients: "<<xps->GetNClients(1));
2275 
2276  // Record this session in the client sandbox
2277  if (p->Client()->Sandbox()->AddSession(xps->Tag()) == -1)
2278  TRACEP(p, REQ, "problems recording session in sandbox");
2279 
2280  // Success; avoid that the global counter is decreased
2281  mcGuard.Set(0);
2282 
2283  // Update the global session handlers
2284  XrdOucString key; key += pid;
2285  { XrdSysMutexHelper mh(fMutex);
2286  fSessions.Add(key.c_str(), xps, 0, Hash_keepdata);
2287  fActiveSessions.push_back(xps);
2288  }
2289  AddSession(p, xps);
2290 
2291  // Check session validity
2292  if (!xps->IsValid()) {
2293  // Notify
2294  TRACEP(p, XERR, "PROOF session is invalid: protocol error? " <<emsg);
2295  }
2296 
2297  // Over
2298  return 0;
2299 }
2300 ////////////////////////////////////////////////////////////////////////////////
2301 /// Create the admin path for the starting session
2302 /// Return 0 on success, -1 on error (error message in 'emsg')
2303 
2305  XrdProofdProtocol *p, int pid,
2306  XrdOucString &emsg)
2307 {
2308  XrdOucString path;
2309  bool assert = (pid > 0) ? 1 : 0;
2310  XPDFORM(path, "%s/%s.%s.", fActiAdminPath.c_str(),
2311  p->Client()->User(), p->Client()->Group());
2312  if (pid > 0) path += pid;
2313  if (xps->SetAdminPath(path.c_str(), assert, fMgr->ChangeOwn()) != 0) {
2314  XPDFORM(emsg, "failure setting admin path '%s'", path.c_str());
2315  return -1;
2316  }
2317  // Done
2318  return 0;
2319 }
2320 
2321 ////////////////////////////////////////////////////////////////////////////////
2322 /// Create the socket path for the starting session
2323 /// Return 0 on success, -1 on error (error message in 'emsg')
2324 
2326  XrdProofdProtocol *p,
2327  unsigned int seq, XrdOucString &emsg)
2328 {
2329  XPDLOC(SMGR, "ProofServMgr::CreateSockPath")
2330 
2331  XrdOucString sockpath;
2332  // Sock path under dedicated directory to avoid problems related to its length
2333  XPDFORM(sockpath, "%s/xpd.%d.%d.%u", fMgr->SockPathDir(), fMgr->Port(), getpid(), seq);
2334  TRACEP(p, ALL, "socket path: " << sockpath);
2335  struct sockaddr_un unserver;
2336  if (sockpath.length() > (int)(sizeof(unserver.sun_path) - 1)) {
2337  XPDFORM(emsg, "socket path very long (%d): this may lead to stack corruption! ", sockpath.length());
2338  return -1;
2339  }
2340  // Now create the UNIX sock path and set its permissions
2341  xps->SetUNIXSockPath(sockpath.c_str());
2342  if (xps->CreateUNIXSock(fEDest) != 0) {
2343  // Failure
2344  XPDFORM(emsg, "failure creating UNIX socket on '%s'", sockpath.c_str());
2345  return -1;
2346  }
2347  if (chmod(sockpath.c_str(), 0755) != 0) {
2348  XPDFORM(emsg, "failure changing permissions of the UNIX socket on '%s'; errno: %d",
2349  sockpath.c_str(), (int)errno);
2350  return -1;
2351  }
2352 
2353  // Done
2354  return 0;
2355 }
2356 
2357 ////////////////////////////////////////////////////////////////////////////////
2358 /// Send content of errlog upstream asynchronously
2359 
2361 {
2362  XPDLOC(SMGR, "ProofServMgr::SendErrLog")
2363 
2364  XrdOucString emsg("An error occured: the content of errlog follows:");
2365  r->Send(kXR_attn, kXPD_srvmsg, (char *) emsg.c_str(), emsg.length());
2366  emsg = "------------------------------------------------\n";
2367  r->Send(kXR_attn, kXPD_srvmsg, 2, (char *) emsg.c_str(), emsg.length());
2368 
2369  int ierr = open(errlog, O_RDONLY);
2370  if (ierr < 0) {
2371  XPDFORM(emsg, "cannot open '%s' (errno: %d)", errlog, errno);
2372  r->Send(kXR_attn, kXPD_srvmsg, 2, (char *) emsg.c_str(), emsg.length());
2373  return;
2374  }
2375  struct stat st;
2376  if (fstat(ierr, &st) != 0) {
2377  XPDFORM(emsg, "cannot stat '%s' (errno: %d)", errlog, errno);
2378  r->Send(kXR_attn, kXPD_srvmsg, 2, (char *) emsg.c_str(), emsg.length());
2379  close (ierr);
2380  return;
2381  }
2382  off_t len = st.st_size;
2383  TRACE(ALL, " reading "<<len<<" bytes from "<<errlog);
2384  ssize_t chunk = 2048, nb, nr;
2385  char buf[2048];
2386  ssize_t left = len;
2387  while (left > 0) {
2388  nb = (left > chunk) ? chunk : left;
2389  if ((nr = read(ierr, buf, nb)) < 0) {
2390  XPDFORM(emsg, "problems reading from '%s' (errno: %d)", errlog, errno);
2391  r->Send(kXR_attn, kXPD_srvmsg, 2, (char *) emsg.c_str(), emsg.length());
2392  close(ierr);
2393  return;
2394  }
2395  TRACE(ALL, buf);
2396  r->Send(kXR_attn, kXPD_srvmsg, 2, buf, nr);
2397  left -= nr;
2398  }
2399  close(ierr);
2400  emsg = "------------------------------------------------";
2401  r->Send(kXR_attn, kXPD_srvmsg, 2, (char *) emsg.c_str(), emsg.length());
2402 
2403  // Done
2404  return;
2405 }
2406 
2407 ////////////////////////////////////////////////////////////////////////////////
2408 /// Handle a request to recover a session after stop&restart
2409 
2411 {
2412  XPDLOC(SMGR, "ProofServMgr::ResolveSession")
2413 
2414  TRACE(REQ, "resolving "<< (fpid ? fpid : "<nul>")<<" ...");
2415 
2416  // Check inputs
2417  if (!fpid || strlen(fpid)<= 0 || !(fMgr->ClientMgr()) || !fRecoverClients) {
2418  TRACE(XERR, "invalid inputs: "<<(fpid ? fpid : "<nul>")<<", "<<fMgr->ClientMgr()<<
2419  ", "<<fRecoverClients);
2420  return -1;
2421  }
2422 
2423  // Path to the session file
2424  XrdOucString path;
2425  XPDFORM(path, "%s/%s", fActiAdminPath.c_str(), fpid);
2426 
2427  // Read info
2428  XrdProofSessionInfo si(path.c_str());
2429 
2430  // Check if recovering is supported
2431  if (si.fSrvProtVers < 18) {
2432  TRACE(DBG, "session does not support recovering: protocol "
2433  <<si.fSrvProtVers<<" < 18");
2434  return -1;
2435  }
2436 
2437  // Create client instance
2438  XrdProofdClient *c = fMgr->ClientMgr()->GetClient(si.fUser.c_str(), si.fGroup.c_str(),
2439  si.fUnixPath.c_str());
2440  if (!c) {
2441  TRACE(DBG, "client instance not initialized");
2442  return -1;
2443  }
2444 
2445  // Allocate the server object
2446  int psid = si.fID;
2447  XrdProofdProofServ *xps = c->GetServObj(psid);
2448  if (!xps) {
2449  TRACE(DBG, "server object not initialized");
2450  return -1;
2451  }
2452 
2453  // Fill info for this session
2454  si.FillProofServ(*xps, fMgr->ROOTMgr());
2455  if (xps->CreateUNIXSock(fEDest) != 0) {
2456  // Failure
2457  TRACE(XERR,"failure creating UNIX socket on " << xps->UNIXSockPath());
2458  xps->Reset();
2459  return -1;
2460  }
2461 
2462  // Set invalid as we are not yet connected
2463  xps->SetValid(0);
2464 
2465  // Add to the lists
2467  std::list<XpdClientSessions *>::iterator ii = fRecoverClients->begin();
2468  while (ii != fRecoverClients->end()) {
2469  if ((*ii)->fClient == c)
2470  break;
2471  ii++;
2472  }
2473  if (ii != fRecoverClients->end()) {
2474  (*ii)->fProofServs.push_back(xps);
2475  } else {
2476  XpdClientSessions *cl = new XpdClientSessions(c);
2477  cl->fProofServs.push_back(xps);
2478  fRecoverClients->push_back(cl);
2479  }
2480 
2481  // Done
2482  return 0;
2483 }
2484 
2485 ////////////////////////////////////////////////////////////////////////////////
2486 /// Handle a request to recover a session after stop&restart for a specific client
2487 
2489 {
2490  XPDLOC(SMGR, "ProofServMgr::Recover")
2491 
2492  if (!cl) {
2493  TRACE(XERR, "invalid input!");
2494  return 0;
2495  }
2496 
2497  TRACE(DBG, "client: "<< cl->fClient->User());
2498 
2499  int nr = 0;
2500  XrdOucString emsg;
2501  XrdProofdProofServ *xps = 0;
2502  int nps = 0;
2503  { XrdSysMutexHelper mhp(cl->fMutex); nps = cl->fProofServs.size(); }
2504  while (nps--) {
2505 
2506  { XrdSysMutexHelper mhp(cl->fMutex); xps = cl->fProofServs.front();
2507  cl->fProofServs.remove(xps); cl->fProofServs.push_back(xps); }
2508 
2509  // Short steps of 1 sec
2510  if (AcceptPeer(xps, 1, emsg) != 0) {
2511  if (emsg == "timeout") {
2512  TRACE(DBG, "timeout while accepting callback");
2513  } else {
2514  TRACE(XERR, "problems accepting callback: "<<emsg);
2515  }
2516  } else {
2517  // Update the global session handlers
2518  XrdOucString key; key += xps->SrvPID();
2519  fSessions.Add(key.c_str(), xps, 0, Hash_keepdata);
2520  fActiveSessions.push_back(xps);
2521  xps->Protocol()->SetAdminPath(xps->AdminPath());
2522  // Remove from the temp list
2523  { XrdSysMutexHelper mhp(cl->fMutex); cl->fProofServs.remove(xps); }
2524  // Count
2525  nr++;
2526  // Notify
2527  if (TRACING(REQ)) {
2528  int pid = xps->SrvPID();
2529  int left = -1;
2530  { XrdSysMutexHelper mhp(cl->fMutex); left = cl->fProofServs.size(); }
2531  XPDPRT("session for "<<cl->fClient->User()<<"."<<cl->fClient->Group()<<
2532  " successfully recovered ("<<left<<" left); pid: "<<pid);
2533  }
2534  }
2535  }
2536 
2537  // Over
2538  return nr;
2539 }
2540 
2541 #ifndef ROOT_XrdFour
2542 ////////////////////////////////////////////////////////////////////////////////
2543 /// Accept a callback from a starting-up server and setup the related protocol
2544 /// object. Used for old servers.
2545 /// Return 0 if successful or -1 in case of failure.
2546 
2548  int to, XrdOucString &msg)
2549 {
2550  XPDLOC(SMGR, "ProofServMgr::AcceptPeer")
2551 
2552  // We will get back a peer to initialize a link
2553  XrdNetPeer peerpsrv;
2554 
2555  // Check inputs
2556  if (!xps || !xps->UNIXSock()) {
2557  XPDFORM(msg, "session pointer undefined or socket invalid: %p", xps);
2558  return -1;
2559  }
2560  TRACE(REQ, "waiting for server callback for "<<to<<" secs ... on "<<xps->UNIXSockPath());
2561 
2562  // Perform regular accept
2563  if (!(xps->UNIXSock()->Accept(peerpsrv, XRDNET_NODNTRIM, to))) {
2564  msg = "timeout";
2565  return -1;
2566  }
2567 
2568  // Setup the protocol serving this peer
2569  if (SetupProtocol(peerpsrv, xps, msg) != 0) {
2570  msg = "could not assert connected peer: ";
2571  return -1;
2572  }
2573 
2574  // Done
2575  return 0;
2576 }
2577 
2578 ////////////////////////////////////////////////////////////////////////////////
2579 /// Setup the protocol object serving the peer described by 'peerpsrv'
2580 
2581 int XrdProofdProofServMgr::SetupProtocol(XrdNetPeer &peerpsrv,
2582  XrdProofdProofServ *xps, XrdOucString &msg)
2583 {
2584  XPDLOC(SMGR, "ProofServMgr::SetupProtocol")
2585 
2586  // We will get back a peer to initialize a link
2587  XrdLink *linkpsrv = 0;
2588  XrdProtocol *xp = 0;
2589  int lnkopts = 0;
2590  bool go = 1;
2591 
2592  // Make sure we have the full host name
2593  if (peerpsrv.InetName) free(peerpsrv.InetName);
2594  peerpsrv.InetName = XrdSysDNS::getHostName("localhost");
2595 
2596  // Allocate a new network object
2597  if (!(linkpsrv = XrdLink::Alloc(peerpsrv, lnkopts))) {
2598  msg = "could not allocate network object: ";
2599  go = 0;
2600  }
2601 
2602  if (go) {
2603  // Keep buffer after object goes away
2604  peerpsrv.InetBuff = 0;
2605  TRACE(DBG, "connection accepted: matching protocol ... ");
2606  // Get a protocol object off the stack (if none, allocate a new one)
2608  if (!(xp = p->Match(linkpsrv))) {
2609  msg = "match failed: protocol error: ";
2610  go = 0;
2611  }
2612  delete p;
2613  }
2614 
2615  if (go) {
2616  // Save path into the protocol instance: it may be needed during Process
2617  XrdOucString apath(xps->AdminPath());
2618  apath += ".status";
2619  ((XrdProofdProtocol *)xp)->SetAdminPath(apath.c_str());
2620  // Take a short-cut and process the initial request as a sticky request
2621  if (xp->Process(linkpsrv) != 0) {
2622  msg = "handshake with internal link failed: ";
2623  go = 0;
2624  }
2625  }
2626 
2627  // Attach this link to the appropriate poller and enable it.
2628  if (go && !XrdPoll::Attach(linkpsrv)) {
2629  msg = "could not attach new internal link to poller: ";
2630  go = 0;
2631  }
2632 
2633  if (!go) {
2634  // Close the link
2635  if (linkpsrv)
2636  linkpsrv->Close();
2637  return -1;
2638  }
2639 
2640  // Tight this protocol instance to the link
2641  linkpsrv->setProtocol(xp);
2642 
2643  TRACE(REQ, "Protocol "<<xp<<" attached to link "<<linkpsrv<<" ("<< peerpsrv.InetName <<")");
2644 
2645  // Schedule it
2646  fMgr->Sched()->Schedule((XrdJob *)linkpsrv);
2647 
2648  // Save the protocol in the session instance
2649  xps->SetProtocol((XrdProofdProtocol *)xp);
2650 
2651  // Done
2652  return 0;
2653 }
2654 
2655 #else
2656 
2657 ////////////////////////////////////////////////////////////////////////////////
2658 /// Accept a callback from a starting-up server and setup the related protocol
2659 /// object. Used for old servers.
2660 /// Return 0 if successful or -1 in case of failure.
2661 
2663  int to, XrdOucString &msg)
2664 {
2665  XPDLOC(SMGR, "ProofServMgr::AcceptPeer")
2666 
2667  // We will get back a peer to initialize a link
2668  XrdNetAddr netaddr;
2669 
2670  // Check inputs
2671  if (!xps || !xps->UNIXSock()) {
2672  XPDFORM(msg, "session pointer undefined or socket invalid: %p", xps);
2673  return -1;
2674  }
2675  TRACE(REQ, "waiting for server callback for "<<to<<" secs ... on "<<xps->UNIXSockPath());
2676 
2677  // Perform regular accept
2678  if (!(xps->UNIXSock()->Accept(netaddr, 0, to))) {
2679  msg = "timeout";
2680  return -1;
2681  }
2682 
2683  // Setup the protocol serving this peer
2684  if (SetupProtocol(netaddr, xps, msg) != 0) {
2685  msg = "could not assert connected peer: ";
2686  return -1;
2687  }
2688 
2689  // Done
2690  return 0;
2691 }
2692 
2693 ////////////////////////////////////////////////////////////////////////////////
2694 /// Setup the protocol object serving the peer described by 'peerpsrv'
2695 
2696 int XrdProofdProofServMgr::SetupProtocol(XrdNetAddr &netaddr,
2697  XrdProofdProofServ *xps, XrdOucString &msg)
2698 {
2699  XPDLOC(SMGR, "ProofServMgr::SetupProtocol")
2700 
2701  // We will get back a peer to initialize a link
2702  XrdLink *linkpsrv = 0;
2703  XrdProtocol *xp = 0;
2704  int lnkopts = 0;
2705  bool go = 1;
2706 
2707  // Allocate a new network object
2708  if (!(linkpsrv = XrdLink::Alloc(netaddr, lnkopts))) {
2709  msg = "could not allocate network object: ";
2710  go = 0;
2711  }
2712 
2713  if (go) {
2714  TRACE(DBG, "connection accepted: matching protocol ... ");
2715  // Get a protocol object off the stack (if none, allocate a new one)
2717  if (!(xp = p->Match(linkpsrv))) {
2718  msg = "match failed: protocol error: ";
2719  go = 0;
2720  }
2721  delete p;
2722  }
2723 
2724  if (go) {
2725  // Save path into the protocol instance: it may be needed during Process
2726  XrdOucString apath(xps->AdminPath());
2727  apath += ".status";
2728  ((XrdProofdProtocol *)xp)->SetAdminPath(apath.c_str());
2729  // Take a short-cut and process the initial request as a sticky request
2730  if (xp->Process(linkpsrv) != 0) {
2731  msg = "handshake with internal link failed: ";
2732  go = 0;
2733  }
2734  }
2735 
2736  // Attach this link to the appropriate poller and enable it.
2737  if (go && !XrdPoll::Attach(linkpsrv)) {
2738  msg = "could not attach new internal link to poller: ";
2739  go = 0;
2740  }
2741 
2742  if (!go) {
2743  // Close the link
2744  if (linkpsrv)
2745  linkpsrv->Close();
2746  return -1;
2747  }
2748 
2749  // Tight this protocol instance to the link
2750  linkpsrv->setProtocol(xp);
2751 
2752  TRACE(REQ, "Protocol "<<xp<<" attached to link "<<linkpsrv<<" ("<< netaddr.Name() <<")");
2753 
2754  // Schedule it
2755  fMgr->Sched()->Schedule((XrdJob *)linkpsrv);
2756 
2757  // Save the protocol in the session instance
2758  xps->SetProtocol((XrdProofdProtocol *)xp);
2759 
2760  // Done
2761  return 0;
2762 }
2763 
2764 #endif
2765 
2766 ////////////////////////////////////////////////////////////////////////////////
2767 /// Handle a request to detach from an existing session
2768 
2770 {
2771  XPDLOC(SMGR, "ProofServMgr::Detach")
2772 
2773  int psid = -1, rc = 0;
2774  XPD_SETRESP(p, "Detach");
2775 
2776  // Unmarshall the data
2777  psid = ntohl(p->Request()->proof.sid);
2778  TRACEP(p, REQ, "psid: "<<psid);
2779 
2780  // Find server session
2781  XrdProofdProofServ *xps = 0;
2782  if (!p->Client() || !(xps = p->Client()->GetServer(psid))) {
2783  TRACEP(p, XERR, "session ID not found: "<<psid);
2784  response->Send(kXR_InvalidRequest,"session ID not found");
2785  return 0;
2786  }
2787  xps->FreeClientID(p->Pid());
2788 
2789  // Notify to user
2790  response->Send();
2791 
2792  return 0;
2793 }
2794 
2795 ////////////////////////////////////////////////////////////////////////////////
2796 /// Handle a request to shutdown an existing session
2797 
2799 {
2800  XPDLOC(SMGR, "ProofServMgr::Destroy")
2801 
2802  int psid = -1, rc = 0;
2803  XPD_SETRESP(p, "Destroy");
2804 
2805  // Unmarshall the data
2806  psid = ntohl(p->Request()->proof.sid);
2807  TRACEP(p, REQ, "psid: "<<psid);
2808 
2809  XrdOucString msg;
2810 
2811  // Find server session
2812  XrdProofdProofServ *xpsref = 0;
2813  if (psid > -1) {
2814  // Request for a specific session
2815  if (!p->Client() || !(xpsref = p->Client()->GetServer(psid))) {
2816  TRACEP(p, XERR, "reference session ID not found");
2817  response->Send(kXR_InvalidRequest,"reference session ID not found");
2818  return 0;
2819  }
2820  XPDFORM(msg, "session %d destroyed by %s", xpsref->SrvPID(), p->Link()->ID);
2821  } else {
2822  XPDFORM(msg, "all sessions destroyed by %s", p->Link()->ID);
2823  }
2824 
2825  // Terminate the servers
2826  p->Client()->TerminateSessions(kXPD_AnyServer, xpsref,
2827  msg.c_str(), Pipe(), fMgr->ChangeOwn());
2828 
2829  // Add to destroyed list
2830  fDestroyTimes[p] = time(0);
2831 
2832  // Notify to user
2833  response->Send();
2834 
2835  // Over
2836  return 0;
2837 }
2838 
2839 ////////////////////////////////////////////////////////////////////////////////
2840 /// Run thorugh entries to broadcast the relevant priority
2841 
2842 static int WriteSessEnvs(const char *, XpdEnv *env, void *s)
2843 {
2844  XPDLOC(SMGR, "WriteSessEnvs")
2845 
2846  XrdOucString emsg;
2847 
2848  XpdWriteEnv_t *xwe = (XpdWriteEnv_t *)s;
2849 
2850  if (env && xwe && xwe->fMgr && xwe->fClient && xwe->fEnv) {
2851  if (env->fEnv.length() > 0) {
2852  // Resolve keywords
2853  xwe->fMgr->ResolveKeywords(env->fEnv, xwe->fClient);
2854  // Set the env now
2855  char *ev = new char[env->fEnv.length()+1];
2856  strncpy(ev, env->fEnv.c_str(), env->fEnv.length());
2857  ev[env->fEnv.length()] = 0;
2858  fprintf(xwe->fEnv, "%s\n", ev);
2859  TRACE(DBG, ev);
2860  PutEnv(ev, xwe->fExport);
2861  }
2862  // Go to next
2863  return 0;
2864  } else {
2865  emsg = "some input undefined";
2866  }
2867 
2868  // Some problem
2869  TRACE(XERR,"protocol error: "<<emsg);
2870  return 1;
2871 }
2872 
2873 ////////////////////////////////////////////////////////////////////////////////
2874 /// Set environment for proofserv; old version preparing the environment for
2875 /// proofserv protocol version <= 13. Needed for backward compatibility.
2876 
2878 {
2879  XPDLOC(SMGR, "ProofServMgr::SetProofServEnvOld")
2880 
2881  char *ev = 0;
2882 
2883  // Check inputs
2884  if (!p || !p->Client() || !input) {
2885  TRACE(XERR, "at leat one input is invalid - cannot continue");
2886  return -1;
2887  }
2888 
2889  // Set basic environment for proofserv
2890  if (SetProofServEnv(fMgr, p->Client()->ROOT()) != 0) {
2891  TRACE(XERR, "problems setting basic environment - exit");
2892  return -1;
2893  }
2894 
2895  ProofServEnv_t *in = (ProofServEnv_t *)input;
2896 
2897  // Session proxy
2898  XrdProofdProofServ *xps = in->fPS;
2899  if (!xps) {
2900  TRACE(XERR, "unable to get instance of proofserv proxy");
2901  return -1;
2902  }
2903  int psid = xps->ID();
2904  TRACE(REQ, "psid: "<<psid<<", log: "<<in->fLogLevel);
2905 
2906  // Work directory
2907  XrdOucString udir = p->Client()->Sandbox()->Dir();
2908  TRACE(DBG, "working dir for "<<p->Client()->User()<<" is: "<<udir);
2909 
2910  size_t len = strlen("ROOTPROOFSESSDIR=") + in->fWrkDir.length() + 2;
2911  ev = new char[len];
2912  snprintf(ev, len, "ROOTPROOFSESSDIR=%s", in->fWrkDir.c_str());
2913  putenv(ev);
2914  TRACE(DBG, ev);
2915 
2916  // Log level
2917  len = strlen("ROOTPROOFLOGLEVEL=") + 5;
2918  ev = new char[len];
2919  snprintf(ev, len, "ROOTPROOFLOGLEVEL=%d", in->fLogLevel);
2920  putenv(ev);
2921  TRACE(DBG, ev);
2922 
2923  // Ordinal number
2924  len = strlen("ROOTPROOFORDINAL=")+strlen(xps->Ordinal()) + 2;
2925  ev = new char[len];
2926  snprintf(ev, len, "ROOTPROOFORDINAL=%s", xps->Ordinal());
2927  putenv(ev);
2928  TRACE(DBG, ev);
2929 
2930  // ROOT Version tag if not the default one
2931  len = strlen("ROOTVERSIONTAG=")+strlen(p->Client()->ROOT()->Tag())+2;
2932  ev = new char[len];
2933  snprintf(ev, len, "ROOTVERSIONTAG=%s", p->Client()->ROOT()->Tag());
2934  putenv(ev);
2935  TRACE(DBG, ev);
2936 
2937  // Create the env file
2938  TRACE(DBG, "creating env file");
2939  XrdOucString envfile = in->fWrkDir;
2940  envfile += ".env";
2941  FILE *fenv = fopen(envfile.c_str(), "w");
2942  if (!fenv) {
2943  TRACE(XERR,
2944  "unable to open env file: "<<envfile);
2945  return -1;
2946  }
2947  TRACE(DBG, "environment file: "<< envfile);
2948 
2949  // Forwarded sec credentials, if any
2950  if (p->AuthProt()) {
2951 
2952  // Additional envs possibly set by the protocol for next application
2953  XrdOucString secenvs(getenv("XrdSecENVS"));
2954  if (secenvs.length() > 0) {
2955  // Go through the list
2956  XrdOucString env;
2957  int from = 0;
2958  while ((from = secenvs.tokenize(env, from, ',')) != -1) {
2959  if (env.length() > 0) {
2960  // Set the env now
2961  ev = new char[env.length()+1];
2962  strncpy(ev, env.c_str(), env.length());
2963  ev[env.length()] = 0;
2964  putenv(ev);
2965  fprintf(fenv, "%s\n", ev);
2966  TRACE(DBG, ev);
2967  }
2968  }
2969  }
2970 
2971  // The credential buffer, if any
2972  XrdSecCredentials *creds = p->AuthProt()->getCredentials();
2973  if (creds) {
2974  len = strlen("XrdSecCREDS=")+creds->size;
2975  ev = new char[len + 1];
2976  strcpy(ev, "XrdSecCREDS=");
2977  memcpy(ev + strlen("XrdSecCREDS="), creds->buffer, creds->size);
2978  ev[len] = 0;
2979  putenv(ev);
2980  TRACE(DBG, "XrdSecCREDS set");
2981  if (fCredsSaver) {
2982  XrdOucString credsdir = udir;
2983  credsdir += "/.creds";
2984  // Make sure the directory exists
2985  if (!XrdProofdAux::AssertDir(credsdir.c_str(), p->Client()->UI(), fMgr->ChangeOwn())) {
2986  if ((*fCredsSaver)(creds, credsdir.c_str(), p->Client()->UI()) != 0) {
2987  TRACE(DBG, "problems in saving authentication creds under "<<credsdir);
2988  }
2989  } else {
2990  TRACE(XERR, "unable to create creds dir: "<<credsdir);
2991  fclose(fenv);
2992  return -1;
2993  }
2994  }
2995  }
2996  }
2997 
2998  // Set ROOTSYS
2999  fprintf(fenv, "ROOTSYS=%s\n", xps->ROOT()->Dir());
3000 
3001  // Set conf dir
3002  fprintf(fenv, "ROOTCONFDIR=%s\n", xps->ROOT()->Dir());
3003 
3004  // Set TMPDIR
3005  fprintf(fenv, "ROOTTMPDIR=%s\n", fMgr->TMPdir());
3006 
3007  // Port (really needed?)
3008  fprintf(fenv, "ROOTXPDPORT=%d\n", fMgr->Port());
3009 
3010  // Work dir
3011  fprintf(fenv, "ROOTPROOFWORKDIR=%s\n", udir.c_str());
3012 
3013  // Session tag
3014  fprintf(fenv, "ROOTPROOFSESSIONTAG=%s\n", in->fSessionTag.c_str());
3015 
3016  // Whether user specific config files are enabled
3017  if (fMgr->NetMgr()->WorkerUsrCfg())
3018  fprintf(fenv, "ROOTUSEUSERCFG=1\n");
3019 
3020  // Set Open socket
3021  fprintf(fenv, "ROOTOPENSOCK=%s\n", xps->UNIXSockPath());
3022 
3023  // Entity
3024  fprintf(fenv, "ROOTENTITY=%s@%s\n", p->Client()->User(), p->Link()->Host());
3025 
3026  // Session ID
3027  fprintf(fenv, "ROOTSESSIONID=%d\n", psid);
3028 
3029  // Client ID
3030  fprintf(fenv, "ROOTCLIENTID=%d\n", p->CID());
3031 
3032  // Client Protocol
3033  fprintf(fenv, "ROOTPROOFCLNTVERS=%d\n", p->ProofProtocol());
3034 
3035  // Ordinal number
3036  fprintf(fenv, "ROOTPROOFORDINAL=%s\n", xps->Ordinal());
3037 
3038  // ROOT version tag if different from the default one
3039  if (getenv("ROOTVERSIONTAG"))
3040  fprintf(fenv, "ROOTVERSIONTAG=%s\n", getenv("ROOTVERSIONTAG"));
3041 
3042  // Config file
3043  if (in->fCfg.length() > 0)
3044  fprintf(fenv, "ROOTPROOFCFGFILE=%s\n", in->fCfg.c_str());
3045 
3046  // Log file in the log dir
3047  fprintf(fenv, "ROOTPROOFLOGFILE=%s\n", in->fLogFile.c_str());
3048  xps->SetFileout(in->fLogFile.c_str());
3049 
3050  // Additional envs (xpd.putenv directive)
3052  if (fProofServEnvs.size() > 0) {
3053  // Hash list of the directives applying to this {user, group, svn, version}
3054  XrdOucHash<XpdEnv> sessenvs;
3055  std::list<XpdEnv>::iterator ienvs = fProofServEnvs.begin();
3056  for ( ; ienvs != fProofServEnvs.end(); ienvs++) {
3057  int envmatch = (*ienvs).Matches(p->Client()->User(), p->Client()->Group(),
3058  p->Client()->ROOT()->VersionCode());
3059  if (envmatch >= 0) {
3060  XpdEnv *env = sessenvs.Find((*ienvs).fName.c_str());
3061  if (env) {
3062  int envmtcex = env->Matches(p->Client()->User(), p->Client()->Group(),
3063  p->Client()->ROOT()->VersionCode());
3064  if (envmatch > envmtcex) {
3065  // Replace the entry
3066  env = &(*ienvs);
3067  sessenvs.Rep(env->fName.c_str(), env, 0, Hash_keepdata);
3068  }
3069  } else {
3070  // Add an entry
3071  env = &(*ienvs);
3072  sessenvs.Add(env->fName.c_str(), env, 0, Hash_keepdata);
3073  }
3074  TRACE(HDBG, "Adding: "<<(*ienvs).fEnv);
3075  }
3076  }
3077  XpdWriteEnv_t xpwe = {fMgr, p->Client(), fenv, in->fOld};
3078  sessenvs.Apply(WriteSessEnvs, (void *)&xpwe);
3079  }
3080  }
3081 
3082  // Set the user envs
3083  if (xps->UserEnvs() &&
3084  strlen(xps->UserEnvs()) && strstr(xps->UserEnvs(),"=")) {
3085  // The single components
3086  XrdOucString ue = xps->UserEnvs();
3087  XrdOucString env, namelist;
3088  int from = 0, ieq = -1;
3089  while ((from = ue.tokenize(env, from, ',')) != -1) {
3090  if (env.length() > 0 && (ieq = env.find('=')) != -1) {
3091  // Resolve keywords
3092  ResolveKeywords(env, in);
3093  ev = new char[env.length()+1];
3094  strncpy(ev, env.c_str(), env.length());
3095  ev[env.length()] = 0;
3096  putenv(ev);
3097  fprintf(fenv, "%s\n", ev);
3098  TRACE(DBG, ev);
3099  env.erase(ieq);
3100  if (namelist.length() > 0)
3101  namelist += ',';
3102  namelist += env;
3103  }
3104  }
3105  // The list of names, ','-separated
3106  len = strlen("PROOF_ALLVARS=") + namelist.length() + 2;
3107  ev = new char[len];
3108  snprintf(ev, len, "PROOF_ALLVARS=%s", namelist.c_str());
3109  putenv(ev);
3110  fprintf(fenv, "%s\n", ev);
3111  TRACE(DBG, ev);
3112  }
3113 
3114  // Close file
3115  fclose(fenv);
3116 
3117  // Create or Update symlink to last session
3118  TRACE(DBG, "creating symlink");
3119  XrdOucString syml = udir;
3120  if (p->ConnType() == kXPD_MasterWorker)
3121  syml += "/last-worker-session";
3122  else
3123  syml += "/last-master-session";
3124  if (XrdProofdAux::SymLink(in->fSessionDir.c_str(), syml.c_str()) != 0) {
3125  TRACE(XERR, "problems creating symlink to last session (errno: "<<errno<<")");
3126  }
3127 
3128  // We are done
3129  TRACE(DBG, "done");
3130  return 0;
3131 }
3132 
3133 ////////////////////////////////////////////////////////////////////////////////
3134 /// Set basic environment accordingly to 'r'
3135 
3137 {
3138  XPDLOC(SMGR, "ProofServMgr::SetProofServEnv")
3139 
3140  char *ev = 0;
3141  size_t len = 0;
3142 
3143  TRACE(REQ, "ROOT dir: "<< (r ? r->Dir() : "*** undef ***"));
3144 
3145  if (r) {
3146  char *libdir = (char *) r->LibDir();
3147  char *ldpath = 0;
3148  if (mgr->BareLibPath() && strlen(mgr->BareLibPath()) > 0) {
3149  len = 32 + strlen(libdir) + strlen(mgr->BareLibPath());
3150  ldpath = new char[len];
3151  snprintf(ldpath, len, "%s=%s:%s", XPD_LIBPATH, libdir, mgr->BareLibPath());
3152  } else {
3153  len = 32 + strlen(libdir);
3154  ldpath = new char[len];
3155  snprintf(ldpath, len, "%s=%s", XPD_LIBPATH, libdir);
3156  }
3157  putenv(ldpath);
3158  // Set ROOTSYS
3159  char *rootsys = (char *) r->Dir();
3160  len = 15 + strlen(rootsys);
3161  ev = new char[len];
3162  snprintf(ev, len, "ROOTSYS=%s", rootsys);
3163  putenv(ev);
3164 
3165  // Set bin directory
3166  char *bindir = (char *) r->BinDir();
3167  len = 15 + strlen(bindir);
3168  ev = new char[len];
3169  snprintf(ev, len, "ROOTBINDIR=%s", bindir);
3170  putenv(ev);
3171 
3172  // Set conf dir
3173  char *confdir = (char *) r->DataDir();
3174  len = 20 + strlen(confdir);
3175  ev = new char[len];
3176  snprintf(ev, len, "ROOTCONFDIR=%s", confdir);
3177  putenv(ev);
3178 
3179  // Set TMPDIR
3180  len = 20 + strlen(mgr->TMPdir());
3181  ev = new char[len];
3182  snprintf(ev, len, "TMPDIR=%s", mgr->TMPdir());
3183  putenv(ev);
3184 
3185  // Done
3186  return 0;
3187  }
3188 
3189  // Bad input
3190  TRACE(XERR, "XrdROOT instance undefined!");
3191  return -1;
3192 }
3193 
3194 ////////////////////////////////////////////////////////////////////////////////
3195 
3197  XrdProofdProofServ *xps,
3198  const char *sessiondir,
3199  const char *extension,
3200  XrdOucString &outfn)
3201 {
3202  XrdOucString host = fMgr->Host();
3203  XrdOucString ord = xps->Ordinal();
3204  XrdOucString role;
3205 
3206  // Shorten host name
3207  if (host.find(".") != STR_NPOS)
3208  host.erase(host.find("."));
3209 
3210  if (p->ConnType() == kXPD_MasterWorker) role = "worker";
3211  else role = "master";
3212 
3213  // File name format:
3214  // <sessiondir>/[master|worker]-<ordinal>-<host>.<ext>
3215  // No PID is contained
3216  XPDFORM(outfn, "%s/%s-%s-%s.%s",
3217  sessiondir,
3218  role.c_str(),
3219  ord.c_str(),
3220  host.c_str(),
3221  extension
3222  );
3223 }
3224 
3225 ////////////////////////////////////////////////////////////////////////////////
3226 /// Determine the unique tag and relevant dirs for this session
3227 
3230  XrdOucString &sesstag, XrdOucString &topsesstag,
3231  XrdOucString &sessiondir, XrdOucString &sesswrkdir)
3232 {
3233  XPDLOC(SMGR, "GetTagDirs")
3234 
3235  // Client sandbox
3236  XrdOucString udir = p->Client()->Sandbox()->Dir();
3237 
3238  if (pid == 0) {
3239 
3240  // Create the unique tag identify this session
3241  XrdOucString host = fMgr->Host();
3242  if (host.find(".") != STR_NPOS)
3243  host.erase(host.find("."));
3244  XPDFORM(sesstag, "%s-%d-", host.c_str(), (int)time(0));
3245 
3246  // Session dir
3247  sessiondir = udir;
3248  if (p->ConnType() == kXPD_ClientMaster) {
3249  sessiondir += "/session-";
3250  sessiondir += sesstag;
3251  topsesstag = sesstag;
3252  } else {
3253  sessiondir += "/";
3254  sessiondir += xps->Tag();
3255  topsesstag = xps->Tag();
3256  topsesstag.replace("session-","");
3257  // If the child, make sure the directory exists ...
3258  if (XrdProofdAux::AssertDir(sessiondir.c_str(), p->Client()->UI(),
3259  fMgr->ChangeOwn()) == -1) {
3260  TRACE(XERR, "problems asserting dir '"<<sessiondir<<"' - errno: "<<errno);
3261  return;
3262  }
3263  }
3264 
3265  } else if (pid > 0) {
3266 
3267  // Finalize unique tag identifying this session
3268  sesstag += pid;
3269 
3270  // Session dir
3271  if (p->ConnType() == kXPD_ClientMaster) {
3272  topsesstag = sesstag;
3273  sessiondir += pid;
3274  xps->SetTag(sesstag.c_str());
3275  }
3276 
3277  // If the child, make sure the directory exists ...
3278  if (pid == (int) getpid()) {
3279  if (XrdProofdAux::AssertDir(sessiondir.c_str(), p->Client()->UI(),
3280  fMgr->ChangeOwn()) == -1) {
3281  return;
3282  }
3283  }
3284 
3285  // The session working dir depends on the role
3286  sesswrkdir = sessiondir;
3287  if (p->ConnType() == kXPD_MasterWorker) {
3288  XPDFORM(sesswrkdir, "%s/worker-%s-%s", sessiondir.c_str(), xps->Ordinal(), sesstag.c_str());
3289  } else {
3290  XPDFORM(sesswrkdir, "%s/master-%s-%s", sessiondir.c_str(), xps->Ordinal(), sesstag.c_str());
3291  }
3292  } else {
3293  TRACE(XERR, "negative pid ("<<pid<<"): should not have got here!");
3294  }
3295 
3296  // Done
3297  return;
3298 }
3299 
3300 ////////////////////////////////////////////////////////////////////////////////
3301 /// Run thorugh entries to broadcast the relevant priority
3302 
3303 static int WriteSessRCs(const char *, XpdEnv *erc, void *f)
3304 {
3305  XPDLOC(SMGR, "WriteSessRCs")
3306 
3307  XrdOucString emsg;
3308  FILE *frc = (FILE *)f;
3309  if (frc && erc) {
3310  XrdOucString rc = erc->fEnv;
3311  if (rc.length() > 0) {
3312  if (rc.find("Proof.DataSetManager") != STR_NPOS) {
3313  TRACE(ALL,"Proof.DataSetManager ignored: use xpd.datasetsrc to define dataset managers");
3314  } else {
3315  fprintf(frc, "%s\n", rc.c_str());
3316  }
3317  }
3318  // Go to next
3319  return 0;
3320  } else {
3321  emsg = "file or input entry undefined";
3322  }
3323 
3324  // Some problem
3325  TRACE(XERR,"protocol error: "<<emsg);
3326  return 1;
3327 }
3328 
3329 ////////////////////////////////////////////////////////////////////////////////
3330 /// Set environment for proofserv
3331 
3333 {
3334  XPDLOC(SMGR, "ProofServMgr::SetProofServEnv")
3335 
3336  // Check inputs
3337  if (!p || !p->Client() || !input) {
3338  TRACE(XERR, "at leat one input is invalid - cannot continue");
3339  return -1;
3340  }
3341 
3342  // Old proofservs expect different settings
3343  int rootvers = p->Client()->ROOT() ? p->Client()->ROOT()->SrvProtVers() : -1;
3344  TRACE(DBG, "rootvers: "<< rootvers);
3345  if (rootvers < 14 && rootvers > -1)
3346  return SetProofServEnvOld(p, input);
3347 
3348  ProofServEnv_t *in = (ProofServEnv_t *)input;
3349 
3350  // Session proxy
3351  XrdProofdProofServ *xps = in->fPS;
3352  if (!xps) {
3353  TRACE(XERR, "unable to get instance of proofserv proxy");
3354  return -1;
3355  }
3356  int psid = xps->ID();
3357  TRACE(REQ, "psid: "<<psid<<", log: "<<in->fLogLevel);
3358 
3359  // Client sandbox
3360  XrdOucString udir = p->Client()->Sandbox()->Dir();
3361  TRACE(DBG, "sandbox for "<<p->Client()->User()<<" is: "<<udir);
3362  TRACE(DBG, "session unique tag "<<in->fSessionTag);
3363  TRACE(DBG, "session dir " << in->fSessionDir);
3364  TRACE(DBG, "session working dir:" << in->fWrkDir);
3365 
3366  // Log into the session it
3367  if (XrdProofdAux::ChangeToDir(in->fSessionDir.c_str(), p->Client()->UI(),
3368  fMgr->ChangeOwn()) != 0) {
3369  TRACE(XERR, "couldn't change directory to " << in->fSessionDir);
3370  return -1;
3371  }
3372 
3373  // Set basic environment for proofserv
3374  if (SetProofServEnv(fMgr, p->Client()->ROOT()) != 0) {
3375  TRACE(XERR, "problems setting basic environment - exit");
3376  return -1;
3377  }
3378 
3379  // Create .rootrc and .env files
3380  TRACE(DBG, "creating rc and env files");
3381  XrdOucString rcfile, envfile;
3382  FormFileNameInSessionDir(p, xps, in->fSessionDir.c_str(), "rootrc", rcfile);
3383  if (CreateProofServRootRc(p, in, rcfile.c_str()) != 0) {
3384  TRACE(XERR, "problems creating RC file "<<rcfile.c_str());
3385  return -1;
3386  }
3387 
3388  FormFileNameInSessionDir(p, xps, in->fSessionDir.c_str(), "env", envfile);
3389  if (CreateProofServEnvFile(p, in, envfile.c_str(), rcfile.c_str()) != 0) {
3390  TRACE(XERR, "problems creating environment file "<<envfile.c_str());
3391  return -1;
3392  }
3393 
3394  // Create or Update symlink to last session
3395  if (in->fOld) {
3396  TRACE(REQ, "creating symlink");
3397  XrdOucString syml = udir;
3398  if (p->ConnType() == kXPD_MasterWorker)
3399  syml += "/last-worker-session";
3400  else
3401  syml += "/last-master-session";
3402  if (XrdProofdAux::SymLink(in->fSessionDir.c_str(), syml.c_str()) != 0) {
3403  TRACE(XERR, "problems creating symlink to "
3404  " last session (errno: "<<errno<<")");
3405  }
3406  }
3407 
3408  // We are done
3409  TRACE(REQ, "done");
3410  return 0;
3411 }
3412 
3413 ////////////////////////////////////////////////////////////////////////////////
3414 /// Create in 'rcfn' the rootrc file for the proofserv being created
3415 /// return 0 on success, -1 on error
3416 
3418  const char *envfn, const char *rcfn)
3419 {
3420  XPDLOC(SMGR, "ProofServMgr::CreateProofServEnvFile")
3421 
3422  // Check inputs
3423  if (!p || !input || (!envfn ||
3424  (envfn && strlen(envfn) <= 0)) || (!rcfn || (rcfn && strlen(rcfn) <= 0))) {
3425  TRACE(XERR, "invalid inputs!");
3426  return -1;
3427  }
3428 
3429  // Attach the structure
3430  ProofServEnv_t *in = (ProofServEnv_t *)input;
3431 
3432  // Session proxy
3433  XrdProofdProofServ *xps = in->fPS;
3434  if (!xps) {
3435  TRACE(XERR, "unable to get instance of proofserv proxy");
3436  return -1;
3437  }
3438 
3439  FILE *fenv = fopen(envfn, "w");
3440  if (!fenv) {
3441  TRACE(XERR, "unable to open env file: "<<envfn);
3442  return -1;
3443  }
3444  TRACE(REQ, "environment file: "<< envfn);
3445 
3446  char *ev = 0;
3447  size_t len = 0;
3448  // Forwarded sec credentials, if any
3449  if (p->AuthProt()) {
3450 
3451  // Additional envs possibly set by the protocol for next application
3452  XrdOucString secenvs(getenv("XrdSecENVS"));
3453  if (secenvs.length() > 0) {
3454  // Go through the list
3455  XrdOucString env;
3456  int from = 0;
3457  while ((from = secenvs.tokenize(env, from, ',')) != -1) {
3458  if (env.length() > 0) {
3459  // Set the env now
3460  ev = new char[env.length()+1];
3461  strncpy(ev, env.c_str(), env.length());
3462  ev[env.length()] = 0;
3463  fprintf(fenv, "%s\n", ev);
3464  TRACE(DBG, ev);
3465  PutEnv(ev, in->fOld);
3466  }
3467  }
3468  }
3469 
3470  // The credential buffer, if any
3471  XrdSecCredentials *creds = p->AuthProt()->getCredentials();
3472  if (creds) {
3473  int lev = strlen("XrdSecCREDS=") + creds->size;
3474  ev = new char[lev+1];
3475  strncpy(ev, "XrdSecCREDS=", lev);
3476  memcpy(ev+strlen("XrdSecCREDS="), creds->buffer, creds->size);
3477  ev[lev] = 0;
3478  PutEnv(ev, in->fOld);
3479  TRACE(DBG, "XrdSecCREDS set");
3480 
3481  if (fCredsSaver) {
3482  XrdOucString credsdir = p->Client()->Sandbox()->Dir();
3483  credsdir += "/.creds";
3484  // Make sure the directory exists
3485  if (!XrdProofdAux::AssertDir(credsdir.c_str(), p->Client()->UI(), fMgr->ChangeOwn())) {
3486  if ((*fCredsSaver)(creds, credsdir.c_str(), p->Client()->UI()) != 0) {
3487  TRACE(DBG, "problems in saving authentication creds under "<<credsdir);
3488  }
3489  } else {
3490  TRACE(XERR, "unable to create creds dir: "<<credsdir);
3491  fclose(fenv);
3492  return -1;
3493  }
3494  }
3495  }
3496  }
3497 
3498  // Library path
3499  fprintf(fenv, "%s=%s\n", XPD_LIBPATH, getenv(XPD_LIBPATH));
3500 
3501  // ROOTSYS
3502  fprintf(fenv, "ROOTSYS=%s\n", xps->ROOT()->Dir());
3503 
3504  // Conf dir
3505  fprintf(fenv, "ROOTCONFDIR=%s\n", xps->ROOT()->Dir());
3506 
3507  // TMPDIR
3508  fprintf(fenv, "TMPDIR=%s\n", fMgr->TMPdir());
3509 
3510  // RC file
3511  if (in->fOld) {
3512  len = strlen("ROOTRCFILE=") + strlen(rcfn) + 2;
3513  ev = new char[len];
3514  snprintf(ev, len, "ROOTRCFILE=%s", rcfn);
3515  fprintf(fenv, "%s\n", ev);
3516  TRACE(DBG, ev);
3517  PutEnv(ev, in->fOld);
3518  }
3519 
3520  // ROOT version tag (needed in building packages)
3521  len = strlen("ROOTVERSIONTAG=") + strlen(p->Client()->ROOT()->Tag()) + 2;
3522  ev = new char[len];
3523  snprintf(ev, len, "ROOTVERSIONTAG=%s", p->Client()->ROOT()->Tag());
3524  fprintf(fenv, "%s\n", ev);
3525  TRACE(DBG, ev);
3526  PutEnv(ev, in->fOld);
3527 
3528  // Log file in the log dir
3529  if (in->fOld) {
3530  len = strlen("ROOTPROOFLOGFILE=") + in->fLogFile.length() + 2;
3531  ev = new char[len];
3532  snprintf(ev, len, "ROOTPROOFLOGFILE=%s", in->fLogFile.c_str());
3533  fprintf(fenv, "%s\n", ev);
3534  xps->SetFileout(in->fLogFile.c_str());
3535  TRACE(DBG, ev);
3536  PutEnv(ev, in->fOld);
3537  }
3538 
3539  // Local data server
3540  XrdOucString locdatasrv;
3541  if (strlen(fMgr->RootdExe()) <= 0) {
3542  XPDFORM(locdatasrv, "root://%s", fMgr->Host());
3543  } else {
3544  XrdOucString uh(fMgr->Host());
3545  if (fMgr->MultiUser()) {
3546  XPDFORM(uh, "%s@%s", fMgr->EffectiveUser(), fMgr->Host());
3547  } else {
3548  XPDFORM(uh, "<effuser>@%s", fMgr->Host());
3549  }
3550  XPDFORM(locdatasrv, "rootd://%s:%d", uh.c_str(), fMgr->Port());
3551  }
3552  int nrk = fMgr->ResolveKeywords(locdatasrv, p->Client());
3553  TRACE(HDBG, nrk << " placeholders resolved for LOCALDATASERVER");
3554  len = strlen("LOCALDATASERVER=") + locdatasrv.length() + 2;
3555  ev = new char[len];
3556  snprintf(ev, len, "LOCALDATASERVER=%s", locdatasrv.c_str());
3557  fprintf(fenv, "%s\n", ev);
3558  TRACE(DBG, ev);
3559  PutEnv(ev, in->fOld);
3560 
3561  // Xrootd config file
3562  if (CfgFile()) {
3563  len = strlen("XRDCF=") + strlen(CfgFile()) + 2;
3564  ev = new char[len];
3565  snprintf(ev, len, "XRDCF=%s", CfgFile());
3566  fprintf(fenv, "%s\n", ev);
3567  TRACE(DBG, ev);
3568  PutEnv(ev, in->fOld);
3569  }
3570 
3571  // Additional envs (xpd.putenv directive)
3573  if (fProofServEnvs.size() > 0) {
3574  // Hash list of the directives applying to this {user, group, svn, version}
3575  XrdOucHash<XpdEnv> sessenvs;
3576  std::list<XpdEnv>::iterator ienvs = fProofServEnvs.begin();
3577  for ( ; ienvs != fProofServEnvs.end(); ienvs++) {
3578  int envmatch = (*ienvs).Matches(p->Client()->User(), p->Client()->Group(),
3579  p->Client()->ROOT()->VersionCode());
3580  if (envmatch >= 0) {
3581  XpdEnv *env = sessenvs.Find((*ienvs).fName.c_str());
3582  if (env) {
3583  int envmtcex = env->Matches(p->Client()->User(), p->Client()->Group(),
3584  p->Client()->ROOT()->VersionCode());
3585  if (envmatch > envmtcex) {
3586  // Replace the entry
3587  env = &(*ienvs);
3588  sessenvs.Rep(env->fName.c_str(), env, 0, Hash_keepdata);
3589  }
3590  } else {
3591  // Add an entry
3592  env = &(*ienvs);
3593  sessenvs.Add(env->fName.c_str(), env, 0, Hash_keepdata);
3594  }
3595  TRACE(HDBG, "Adding: "<<(*ienvs).fEnv);
3596  }
3597  }
3598  XpdWriteEnv_t xpwe = {fMgr, p->Client(), fenv, in->fOld};
3599  sessenvs.Apply(WriteSessEnvs, (void *)&xpwe);
3600  }
3601  }
3602  // Set the user envs
3603  if (xps->UserEnvs() &&
3604  strlen(xps->UserEnvs()) && strstr(xps->UserEnvs(),"=")) {
3605  // The single components
3606  XrdOucString ue = xps->UserEnvs();
3607  XrdOucString env, namelist;
3608  int from = 0, ieq = -1;
3609  while ((from = ue.tokenize(env, from, ',')) != -1) {
3610  if (env.length() > 0 && (ieq = env.find('=')) != -1) {
3611  // Resolve keywords
3612  ResolveKeywords(env, in);
3613  ev = new char[env.length()+1];
3614  strncpy(ev, env.c_str(), env.length());
3615  ev[env.length()] = 0;
3616  if (env.find("WRAPPERCMD") == STR_NPOS || !xps->IsPLite())
3617  fprintf(fenv, "%s\n", ev);
3618  TRACE(DBG, ev);
3619  PutEnv(ev, in->fOld);
3620  if (env.find("WRAPPERCMD") == STR_NPOS || !xps->IsPLite()) {
3621  env.erase(ieq);
3622  if (namelist.length() > 0)
3623  namelist += ',';
3624  namelist += env;
3625  }
3626  }
3627  }
3628  // The list of names, ','-separated
3629  len = strlen("PROOF_ALLVARS=") + namelist.length() + 2;
3630  ev = new char[len];
3631  snprintf(ev, len, "PROOF_ALLVARS=%s", namelist.c_str());
3632  fprintf(fenv, "%s\n", ev);
3633  TRACE(DBG, ev);
3634  PutEnv(ev, in->fOld);
3635  }
3636 
3637  // Close file
3638  fclose(fenv);
3639 
3640  // We are done
3641  return 0;
3642 }
3643 
3644 ////////////////////////////////////////////////////////////////////////////////
3645 /// Create in 'rcfn' the rootrc file for the proofserv being created
3646 /// return 0 on success, -1 on error
3647 
3649  void *input, const char *rcfn)
3650 {
3651  XPDLOC(SMGR, "ProofServMgr::CreateProofServRootRc")
3652 
3653  // Check inputs
3654  if (!p || !input || (!rcfn || (rcfn && strlen(rcfn) <= 0))) {
3655  TRACE(XERR, "invalid inputs!");
3656  return -1;
3657  }
3658 
3659  // Attach the structure
3660  ProofServEnv_t *in = (ProofServEnv_t *)input;
3661 
3662  // Session proxy
3663  XrdProofdProofServ *xps = in->fPS;
3664  if (!xps) {
3665  TRACE(XERR, "unable to get instance of proofserv proxy");
3666  return -1;
3667  }
3668  int psid = xps->ID();
3669 
3670  FILE *frc = fopen(rcfn, "w");
3671  if (!frc) {
3672  TRACE(XERR, "unable to open rootrc file: "<<rcfn);
3673  return -1;
3674  }
3675  // Symlink to session.rootrc
3676  if (in->fOld) {
3677  if (XrdProofdAux::SymLink(rcfn, "session.rootrc") != 0) {
3678  TRACE(XERR, "problems creating symlink to 'session.rootrc' (errno: "<<errno<<")");
3679  }
3680  }
3681  TRACE(REQ, "session rootrc file: "<< rcfn);
3682 
3683  // Port
3684  fprintf(frc, "# XrdProofdProtocol listening port\n");
3685  fprintf(frc, "ProofServ.XpdPort: %d\n", fMgr->Port());
3686 
3687  // Local root prefix
3688  if (fMgr->LocalROOT() && strlen(fMgr->LocalROOT()) > 0) {
3689  fprintf(frc, "# Prefix to be prepended to local paths\n");
3690  fprintf(frc, "Path.Localroot: %s\n", fMgr->LocalROOT());
3691  }
3692 
3693  // Data pool entry-point URL
3694  if (fMgr->PoolURL() && strlen(fMgr->PoolURL()) > 0) {
3695  XrdOucString purl(fMgr->PoolURL());
3696  if (!purl.endswith("/"))
3697  purl += "/";
3698  fprintf(frc, "# URL for the data pool entry-point\n");
3699  fprintf(frc, "ProofServ.PoolUrl: %s\n", purl.c_str());
3700  }
3701 
3702  // The session working dir depends on the role
3703  if (in->fOld) {
3704  fprintf(frc, "# The session working dir\n");
3705  fprintf(frc, "ProofServ.SessionDir: %s\n", in->fWrkDir.c_str());
3706  }
3707 
3708  // Log / Debug level
3709  fprintf(frc, "# Proof Log/Debug level\n");
3710  fprintf(frc, "Proof.DebugLevel: %d\n", in->fLogLevel);
3711 
3712  // Ordinal number
3713  fprintf(frc, "# Ordinal number\n");
3714  fprintf(frc, "ProofServ.Ordinal: %s\n", xps->Ordinal());
3715 
3716  // ROOT Version tag
3717  if (p->Client()->ROOT()) {
3718  fprintf(frc, "# ROOT Version tag\n");
3719  fprintf(frc, "ProofServ.RootVersionTag: %s\n", p->Client()->ROOT()->Tag());
3720  }
3721  // Proof group
3722  if (p->Client()->Group()) {
3723  fprintf(frc, "# Proof group\n");
3724  fprintf(frc, "ProofServ.ProofGroup: %s\n", p->Client()->Group());
3725  }
3726 
3727  // Path to file with group information
3728  if (fMgr->GroupsMgr() && fMgr->GroupsMgr()->GetCfgFile()) {
3729  fprintf(frc, "# File with group information\n");
3730  fprintf(frc, "Proof.GroupFile: %s\n", fMgr->GroupsMgr()->GetCfgFile());
3731  }
3732 
3733  // Work dir
3734  XrdOucString udir = p->Client()->Sandbox()->Dir();
3735  fprintf(frc, "# Users sandbox\n");
3736  fprintf(frc, "ProofServ.Sandbox: %s\n", udir.c_str());
3737 
3738  // Image
3739  if (fMgr->Image() && strlen(fMgr->Image()) > 0) {
3740  fprintf(frc, "# Server image\n");
3741  fprintf(frc, "ProofServ.Image: %s\n", fMgr->Image());
3742  }
3743 
3744  // Session tags
3745  if (in->fOld) {
3746  fprintf(frc, "# Session tag\n");
3747  fprintf(frc, "ProofServ.SessionTag: %s\n", in->fSessionTag.c_str());
3748  fprintf(frc, "# Top Session tag\n");
3749  fprintf(frc, "ProofServ.TopSessionTag: %s\n", in->fTopSessionTag.c_str());
3750  }
3751 
3752  // Session admin path
3753  fprintf(frc, "# Session admin path\n");
3754  int proofvrs = (p->Client()->ROOT()) ? p->Client()->ROOT()->SrvProtVers() : -1;
3755  if (proofvrs < 0 || proofvrs < 27) {
3756  // Use the first version of the session status file
3757  fprintf(frc, "ProofServ.AdminPath: %s\n", xps->AdminPath());
3758  } else {
3759  if (in->fOld) {
3760  // New version with updated status
3761  fprintf(frc, "ProofServ.AdminPath: %s.status\n", xps->AdminPath());
3762  }
3763  }
3764 
3765  // Whether user specific config files are enabled
3766  if (fMgr->NetMgr()->WorkerUsrCfg()) {
3767  fprintf(frc, "# Whether user specific config files are enabled\n");
3768  fprintf(frc, "ProofServ.UseUserCfg: 1\n");
3769  }
3770  // Set Open socket
3771  fprintf(frc, "# Open socket\n");
3772  fprintf(frc, "ProofServ.OpenSock: %s\n", xps->UNIXSockPath());
3773  // Entity
3774  fprintf(frc, "# Entity\n");
3775  if (p->Client()->UI().fGroup.length() > 0)
3776  fprintf(frc, "ProofServ.Entity: %s:%s@%s\n",
3777  p->Client()->User(), p->Client()->UI().fGroup.c_str(), p->Link()->Host());
3778  else
3779  fprintf(frc, "ProofServ.Entity: %s@%s\n", p->Client()->User(), p->Link()->Host());
3780 
3781 
3782  // Session ID
3783  fprintf(frc, "# Session ID\n");
3784  fprintf(frc, "ProofServ.SessionID: %d\n", psid);
3785 
3786  // Client ID
3787  fprintf(frc, "# Client ID\n");
3788  fprintf(frc, "ProofServ.ClientID: %d\n", p->CID());
3789 
3790  // Client Protocol
3791  fprintf(frc, "# Client Protocol\n");
3792  fprintf(frc, "ProofServ.ClientVersion: %d\n", p->ProofProtocol());
3793 
3794  // Config file
3795  if (in->fCfg.length() > 0) {
3796  if (in->fCfg == "masteronly") {
3797  fprintf(frc, "# MasterOnly option\n");
3798  // Master Only setup
3799  fprintf(frc, "Proof.MasterOnly: 1\n");
3800  } else {
3801  fprintf(frc, "# Config file\n");
3802  // User defined
3803  fprintf(frc, "ProofServ.ProofConfFile: %s\n", in->fCfg.c_str());
3804  }
3805  } else {
3806  fprintf(frc, "# Config file\n");
3807  if (fMgr->IsSuperMst()) {
3808  fprintf(frc, "ProofServ.ProofConfFile: sm:\n");
3809  } else if (xps->IsPLite()) {
3810  fprintf(frc, "ProofServ.ProofConfFile: lite:\n");
3811  fprintf(frc, "# Number of ProofLite workers\n");
3812  fprintf(frc, "ProofLite.Workers: %d\n", xps->PLiteNWrks());
3813  fprintf(frc, "# Users sandbox\n");
3814  fprintf(frc, "ProofLite.Sandbox: %s\n", udir.c_str());
3815  fprintf(frc, "# No subpaths\n");
3816  fprintf(frc, "ProofLite.SubPath: 0\n");
3817  } else if (fProofPlugin.length() > 0) {
3818  fprintf(frc, "ProofServ.ProofConfFile: %s\n", fProofPlugin.c_str());
3819  }
3820  }
3821 
3822  // We set this to avoid blocking to much on xrdclient actions; they can be
3823  // oevrwritten with explicit putrc directives
3824  fprintf(frc, "# Default settings for XrdClient\n");
3825  fprintf(frc, "XNet.FirstConnectMaxCnt 3\n");
3826  fprintf(frc, "XNet.ConnectTimeout 5\n");
3827 
3828  // This is a workaround for a problem fixed in 5.24/00
3829  int vrscode = (p->Client()->ROOT()) ? p->Client()->ROOT()->VersionCode() : -1;
3830  if (vrscode > 0 && vrscode < XrdROOT::GetVersionCode(5,24,0)) {
3831  fprintf(frc, "# Force remote reading also for local files to avoid a wrong TTreeCache initialization\n");
3832  fprintf(frc, "Path.ForceRemote 1\n");
3833  }
3834 
3835  // Additional rootrcs (xpd.putrc directive)
3837  if (fProofServRCs.size() > 0) {
3838  fprintf(frc, "# Additional rootrcs (xpd.putrc directives)\n");
3839  // Hash list of the directives applying to this {user, group, svn, version}
3840  XrdOucHash<XpdEnv> sessrcs;
3841  std::list<XpdEnv>::iterator ircs = fProofServRCs.begin();
3842  for ( ; ircs != fProofServRCs.end(); ircs++) {
3843  int rcmatch = (*ircs).Matches(p->Client()->User(), p->Client()->Group(),
3844  p->Client()->ROOT()->VersionCode());
3845  if (rcmatch >= 0) {
3846  XpdEnv *rcenv = sessrcs.Find((*ircs).fName.c_str());
3847  if (rcenv) {
3848  int rcmtcex = rcenv->Matches(p->Client()->User(), p->Client()->Group(),
3849  p->Client()->ROOT()->VersionCode());
3850  if (rcmatch > rcmtcex) {
3851  // Replace the entry
3852  rcenv = &(*ircs);
3853  sessrcs.Rep(rcenv->fName.c_str(), rcenv, 0, Hash_keepdata);
3854  }
3855  } else {
3856  // Add an entry
3857  rcenv = &(*ircs);
3858  sessrcs.Add(rcenv->fName.c_str(), rcenv, 0, Hash_keepdata);
3859  }
3860  TRACE(HDBG, "Adding: "<<(*ircs).fEnv);
3861  }
3862  }
3863  sessrcs.Apply(WriteSessRCs, (void *)frc);
3864  }
3865  }
3866  // If applicable, add dataset managers initiators
3867  if (fMgr->DataSetSrcs()->size() > 0) {
3868  fprintf(frc, "# Dataset sources\n");
3869  XrdOucString rc("Proof.DataSetManager: ");
3870  std::list<XrdProofdDSInfo *>::iterator ii;
3871  for (ii = fMgr->DataSetSrcs()->begin(); ii != fMgr->DataSetSrcs()->end(); ii++) {
3872  if (ii != fMgr->DataSetSrcs()->begin()) rc += ", ";
3873  rc += (*ii)->fType;
3874  rc += " dir:";
3875  rc += (*ii)->fUrl;
3876  rc += " opt:";
3877  rc += (*ii)->fOpts;
3878  rc += " ";
3879  rc += (*ii)->fObscure;
3880  }
3881  fprintf(frc, "%s\n", rc.c_str());
3882  }
3883 
3884  // If applicable, add staging requests repository directive initiator
3885  if (strlen(fMgr->StageReqRepo()) > 0) {
3886  fprintf(frc, "# Dataset staging requests repository\n");
3887  fprintf(frc, "Proof.DataSetStagingRequests: %s\n", fMgr->StageReqRepo());
3888  }
3889 
3890  // If applicable, add datadir location
3891  if (fMgr->DataDir() && strlen(fMgr->DataDir()) > 0) {
3892  fprintf(frc, "# Data directory\n");
3893  XrdOucString rc;
3894  XPDFORM(rc, "ProofServ.DataDir: %s/%s/%s/%s/%s", fMgr->DataDir(),
3895  p->Client()->Group(), p->Client()->User(), xps->Ordinal(),
3896  in->fSessionTag.c_str());
3897  if (fMgr->DataDirUrlOpts() && strlen(fMgr->DataDirUrlOpts()) > 0) {
3898  fprintf(frc, "%s %s\n", rc.c_str(), fMgr->DataDirUrlOpts());
3899  } else {
3900  fprintf(frc, "%s\n", rc.c_str());
3901  }
3902  }
3903 
3904  // Done with this
3905  fclose(frc);
3906 
3907  // Done
3908  return 0;
3909 }
3910 
3911 ////////////////////////////////////////////////////////////////////////////////
3912 /// Cleanup (kill) all 'proofserv' processes which lost control from their
3913 /// creator or controller daemon. We rely here on the information in the admin
3914 /// path(s) (<xrd_admin>/.xproof.<port>).
3915 /// This is called regurarly by the cron job to avoid having proofservs around.
3916 /// Return number of process killed or -1 in case of any error.
3917 
3919 {
3920  XPDLOC(SMGR, "ProofServMgr::CleanupLostProofServ")
3921 
3922  if (!fCheckLost) {
3923  TRACE(REQ, "disabled ...");
3924  return 0;
3925  }
3926 
3927  TRACE(REQ, "checking for orphalin proofserv processes ...");
3928  int nk = 0;
3929 
3930  // Get the list of existing proofserv processes from the process table
3931  std::map<int,XrdOucString> procs;
3932  if (XrdProofdAux::GetProcesses("proofserv", &procs) <= 0) {
3933  TRACE(DBG, " no proofservs around: nothing to do");
3934  return 0;
3935  }
3936 
3937  XrdProofUI ui;
3938  if (XrdProofdAux::GetUserInfo(fMgr->EffectiveUser(), ui) != 0) {
3939  TRACE(DBG, "problems getting info for user " << fMgr->EffectiveUser());
3940  return -1;
3941  }
3942 
3943  // Hash list of controlled and xrootd process
3944  XrdOucRash<int, int> controlled, xrdproc;
3945 
3946  // Hash list of sessions files loaded
3947  XrdOucHash<XrdOucString> sessionspaths;
3948 
3949  // For each process extract the information about the daemon supposed to be in control
3950  int pid, ia, a;
3951  XrdOucString cmd, apath, pidpath, sessiondir, emsg, rest, after;
3952  std::map<int,XrdOucString>::iterator ip;
3953  for (ip = procs.begin(); ip != procs.end(); ip++) {
3954  pid = ip->first;
3955  cmd = ip->second;
3956  if ((ia = cmd.find("xpdpath:")) != STR_NPOS) {
3957  cmd.tokenize(apath, ia, ' ');
3958  apath.replace("xpdpath:", "");
3959  if (apath.length() <= 0) {
3960  TRACE(ALL, "admin path not found; initial cmd line: "<<cmd);
3961  continue;
3962  }
3963  // Extract daemon PID and check that it is alive
3964  XPDFORM(pidpath, "%s/xrootd.pid", apath.c_str());
3965  TRACE(ALL, "pidpath: "<<pidpath);
3966  int xpid = XrdProofdAux::GetIDFromPath(pidpath.c_str(), emsg);
3967  int *alive = xrdproc.Find(xpid);
3968  if (!alive) {
3969  a = (XrdProofdAux::VerifyProcessByID(xpid, fParentExecs.c_str())) ? 1 : 0;
3970  xrdproc.Add(xpid, a);
3971  } else {
3972  a = *alive;
3973  }
3974  // If the daemon is still there check that the process has its entry in the
3975  // session path(s);
3976  bool ok = 0;
3977  if (a == 1) {
3978  const char *subdir[2] = {"activesessions", "terminatedsessions"};
3979  for (int i = 0; i < 2; i++) {
3980  XPDFORM(sessiondir, "%s/%s", apath.c_str(), subdir[i]);
3981  if (!sessionspaths.Find(sessiondir.c_str())) {
3982  DIR *sdir = opendir(sessiondir.c_str());
3983  if (!sdir) {
3984  XPDFORM(emsg, "cannot open '%s' - errno: %d", apath.c_str(), errno);
3985  TRACE(XERR, emsg.c_str());
3986  continue;
3987  }
3988  struct dirent *sent = 0;
3989  while ((sent = readdir(sdir))) {
3990  if (!strncmp(sent->d_name, ".", 1) || !strncmp(sent->d_name, "..", 2))
3991  continue;
3992  // Get the pid
3993  int ppid = XrdProofdAux::ParsePidPath(sent->d_name, rest, after);
3994  // Add to the list
3995  controlled.Add(ppid, ppid);
3996  }
3997  closedir(sdir);
3998  sessionspaths.Add(sessiondir.c_str(), 0, 0, Hash_data_is_key);
3999  }
4000  ok = (controlled.Find(pid)) ? 1 : ok;
4001  // We are done, if the process is controlled
4002  if (ok) break;
4003  }
4004  }
4005  // If the process is not controlled we have to kill it
4006  if (!ok) {
4007  TRACE(ALL,"process: "<<pid<<" lost its controller: killing");
4008  if (XrdProofdAux::KillProcess(pid, 1, ui, fMgr->ChangeOwn()) == 0)
4009  nk++;
4010  }
4011  }
4012 
4013  }
4014 
4015  // Done
4016  return nk;
4017 }
4018 
4019 ////////////////////////////////////////////////////////////////////////////////
4020 /// Cleanup (kill) all 'proofserv' processes from the process table.
4021 /// Only the processes associated with 'usr' are killed,
4022 /// unless 'all' is TRUE, in which case all 'proofserv' instances are
4023 /// terminated (this requires superuser privileges).
4024 /// Super users can also terminated all processes fo another user (specified
4025 /// via usr).
4026 /// Return number of process notified for termination on success, -1 otherwise
4027 
4028 int XrdProofdProofServMgr::CleanupProofServ(bool all, const char *usr)
4029 {
4030  XPDLOC(SMGR, "ProofServMgr::CleanupProofServ")
4031 
4032  TRACE(REQ, "all: "<<all<<", usr: " << (usr ? usr : "undef"));
4033  int nk = 0;
4034 
4035  // Name
4036  const char *pn = "proofserv";
4037 
4038  // Uid
4039  XrdProofUI ui;
4040  int refuid = -1;
4041  if (!all) {
4042  if (!usr) {
4043  TRACE(DBG, "usr must be defined for all = FALSE");
4044  return -1;
4045  }
4046  if (XrdProofdAux::GetUserInfo(usr, ui) != 0) {
4047  TRACE(DBG, "problems getting info for user " << usr);
4048  return -1;
4049  }
4050  refuid = ui.fUid;
4051  }
4052 
4053 #if defined(linux)
4054  // Loop over the "/proc" dir
4055  DIR *dir = opendir("/proc");
4056  if (!dir) {
4057  XrdOucString emsg("cannot open /proc - errno: ");
4058  emsg += errno;
4059  TRACE(DBG, emsg.c_str());
4060  return -1;
4061  }
4062 
4063  struct dirent *ent = 0;
4064  while ((ent = readdir(dir))) {
4065  if (!strncmp(ent->d_name, ".", 1) || !strncmp(ent->d_name, "..", 2)) continue;
4066  if (DIGIT(ent->d_name[0])) {
4067  XrdOucString fn("/proc/", 256);
4068  fn += ent->d_name;
4069  fn += "/status";
4070  // Open file
4071  FILE *ffn = fopen(fn.c_str(), "r");
4072  if (!ffn) {
4073  XrdOucString emsg("cannot open file ");
4074  emsg += fn; emsg += " - errno: "; emsg += errno;
4075  TRACE(HDBG, emsg);
4076  continue;
4077  }
4078  // Read info
4079  bool xname = 1, xpid = 1, xppid = 1;
4080  bool xuid = (all) ? 0 : 1;
4081  int pid = -1;
4082  int ppid = -1;
4083  char line[2048] = { 0 };
4084  while (fgets(line, sizeof(line), ffn) &&
4085  (xname || xpid || xppid || xuid)) {
4086  // Check name
4087  if (xname && strstr(line, "Name:")) {
4088  if (!strstr(line, pn))
4089  break;
4090  xname = 0;
4091  }
4092  if (xpid && strstr(line, "Pid:")) {
4093  pid = (int) XrdProofdAux::GetLong(&line[strlen("Pid:")]);
4094  xpid = 0;
4095  }
4096  if (xppid && strstr(line, "PPid:")) {
4097  ppid = (int) XrdProofdAux::GetLong(&line[strlen("PPid:")]);
4098  // Parent process must be us or be dead
4099  if (ppid != getpid() && XrdProofdAux::VerifyProcessByID(ppid, fParentExecs.c_str()))
4100  // Process created by another running xrootd
4101  break;
4102  xppid = 0;
4103  }
4104  if (xuid && strstr(line, "Uid:")) {
4105  int uid = (int) XrdProofdAux::GetLong(&line[strlen("Uid:")]);
4106  if (refuid == uid)
4107  xuid = 0;
4108  }
4109  }
4110  // Close the file
4111  fclose(ffn);
4112  // If this is a good candidate, kill it
4113  if (!xname && !xpid && !xppid && !xuid) {
4114 
4115  bool muok = 1;
4116  if (fMgr->MultiUser() && !all) {
4117  // We need to check the user name: we may be the owner of somebody
4118  // else process; if not session is attached, we kill it
4119  muok = 0;
4121  if (!srv || (srv && !strcmp(usr, srv->Client())))
4122  muok = 1;
4123  }
4124  if (muok)
4125  if (XrdProofdAux::KillProcess(pid, 1, ui, fMgr->ChangeOwn()) == 0)
4126  nk++;
4127  }
4128  }
4129  }
4130  // Close the directory
4131  closedir(dir);
4132 
4133 #elif defined(__sun)
4134 
4135  // Loop over the "/proc" dir
4136  DIR *dir = opendir("/proc");
4137  if (!dir) {
4138  XrdOucString emsg("cannot open /proc - errno: ");
4139  emsg += errno;
4140  TRACE(DBG, emsg);
4141  return -1;
4142  }
4143 
4144  struct dirent *ent = 0;
4145  while ((ent = readdir(dir))) {
4146  if (!strncmp(ent->d_name, ".", 1) || !strncmp(ent->d_name, "..", 2)) continue;
4147  if (DIGIT(ent->d_name[0])) {
4148  XrdOucString fn("/proc/", 256);
4149  fn += ent->d_name;
4150  fn += "/psinfo";
4151  // Open file
4152  int ffd = open(fn.c_str(), O_RDONLY);
4153  if (ffd <= 0) {
4154  XrdOucString emsg("cannot open file ");
4155  emsg += fn; emsg += " - errno: "; emsg += errno;
4156  TRACE(HDBG, emsg);
4157  continue;
4158  }
4159  // Read info
4160  bool xname = 1;
4161  bool xuid = (all) ? 0 : 1;
4162  bool xppid = 1;
4163  // Get the information
4164  psinfo_t psi;
4165  if (read(ffd, &psi, sizeof(psinfo_t)) != sizeof(psinfo_t)) {
4166  XrdOucString emsg("cannot read ");
4167  emsg += fn; emsg += ": errno: "; emsg += errno;
4168  TRACE(XERR, emsg);
4169  close(ffd);
4170  continue;
4171  }
4172  // Close the file
4173  close(ffd);
4174 
4175  // Check name
4176  if (xname) {
4177  if (!strstr(psi.pr_fname, pn))
4178  continue;
4179  xname = 0;
4180  }
4181  // Check uid, if required
4182  if (xuid) {
4183  if (refuid == psi.pr_uid)
4184  xuid = 0;
4185  }
4186  // Parent process must be us or be dead
4187  int ppid = psi.pr_ppid;
4188  if (ppid != getpid() && XrdProofdAux::VerifyProcessByID(ppid, fParentExecs.c_str())) {
4189  // Process created by another running xrootd
4190  continue;
4191  xppid = 0;
4192  }
4193 
4194  // If this is a good candidate, kill it
4195  if (!xname && !xppid && !xuid) {
4196  bool muok = 1;
4197  if (fMgr->MultiUser() && !all) {
4198  // We need to check the user name: we may be the owner of somebody
4199  // else process; if no session is attached , we kill it
4200  muok = 0;
4201  XrdProofdProofServ *srv = GetActiveSession(psi.pr_pid);
4202  if (!srv || (srv && !strcmp(usr, srv->Client())))
4203  muok = 1;
4204  }
4205  if (muok)
4206  if (XrdProofdAux::KillProcess(psi.pr_pid, 1, ui, fMgr->ChangeOwn()) == 0)
4207  nk++;
4208  }
4209  }
4210  }
4211  // Close the directory
4212  closedir(dir);
4213 
4214 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
4215 
4216  // Get the proclist
4217  kinfo_proc *pl = 0;
4218  int np;
4219  int ern = 0;
4220  if ((ern = XrdProofdAux::GetMacProcList(&pl, np)) != 0) {
4221  XrdOucString emsg("cannot get the process list: errno: ");
4222  emsg += ern;
4223  TRACE(XERR, emsg);
4224  return -1;
4225  }
4226 
4227  // Loop over the list
4228  int ii = np;
4229  while (ii--) {
4230  if (strstr(pl[ii].kp_proc.p_comm, pn)) {
4231  if (all || (int)(pl[ii].kp_eproc.e_ucred.cr_uid) == refuid) {
4232  // Parent process must be us or be dead
4233  int ppid = pl[ii].kp_eproc.e_ppid;
4234  bool xppid = 0;
4235  if (ppid != getpid()) {
4236  int jj = np;
4237  while (jj--) {
4238  if (strstr(pl[jj].kp_proc.p_comm, "xrootd") &&
4239  pl[jj].kp_proc.p_pid == ppid) {
4240  xppid = 1;
4241  break;
4242  }
4243  }
4244  }
4245  if (!xppid) {
4246  bool muok = 1;
4247  if (fMgr->MultiUser() && !all) {
4248  // We need to check the user name: we may be the owner of somebody
4249  // else process; if no session is attached, we kill it
4250  muok = 0;
4251  XrdProofdProofServ *srv = GetActiveSession(pl[np].kp_proc.p_pid);
4252  if (!srv || (srv && !strcmp(usr, srv->Client())))
4253  muok = 1;
4254  }
4255  if (muok)
4256  // Good candidate to be shot
4257  if (XrdProofdAux::KillProcess(pl[np].kp_proc.p_pid, 1, ui, fMgr->ChangeOwn()))
4258  nk++;
4259  }
4260  }
4261  }
4262  }
4263  // Cleanup
4264  free(pl);
4265 #else
4266  // For the remaining cases we use 'ps' via popen to localize the processes
4267 
4268  // Build command
4269  XrdOucString cmd = "ps ";
4270  bool busr = 0;
4271 #if 0
4272  // Left over of some previous implementation; but here fSuperUser is not defined: to be checked
4273  const char *cusr = (usr && strlen(usr) && fSuperUser) ? usr : fPClient->ID();
4274 #else
4275  const char *cusr = (usr && strlen(usr)) ? usr : 0;
4276 #endif
4277  if (all) {
4278  cmd += "ax";
4279  } else {
4280  if (cusr) {
4281  cmd += "-U ";
4282  cmd += cusr;
4283  cmd += " -u ";
4284  cmd += cusr;
4285  }
4286  cmd += " -f";
4287  busr = 1;
4288  }
4289  cmd += " | grep proofserv 2>/dev/null";
4290 
4291  // Our parent ID as a string
4292  char cpid[10];
4293  snprintf(cpid, 10, "%d", getpid());
4294 
4295  // Run it ...
4296  XrdOucString pids = ":";
4297  FILE *fp = popen(cmd.c_str(), "r");
4298  if (fp != 0) {
4299  char line[2048] = { 0 };
4300  while (fgets(line, sizeof(line), fp)) {
4301  // Parse line: make sure that we are the parent
4302  char *px = strstr(line, "xpd");
4303  if (!px)
4304  // Not xpd: old proofd ?
4305  continue;
4306  char *pi = strstr(px+3, cpid);
4307  if (!pi) {
4308  // Not started by us: check if the parent is still running
4309  pi = px + 3;
4310  int ppid = (int) XrdProofdAux::GetLong(pi);
4311  TRACE(HDBG, "found alternative parent ID: "<< ppid);
4312  // If still running then skip
4313  if (XrdProofdAux::VerifyProcessByID(ppid, fParentExecs.c_str()))
4314  continue;
4315  }
4316  // Get pid now
4317  int from = 0;
4318  if (busr)
4319  from += strlen(cusr);
4320  int pid = (int) XrdProofdAux::GetLong(&line[from]);
4321  bool muok = 1;
4322  if (fMgr->MultiUser() && !all) {
4323  // We need to check the user name: we may be the owner of somebody
4324  // else process; if no session is attached, we kill it
4325  muok = 0;
4327  if (!srv || (srv && !strcmp(usr, srv->Client())))
4328  muok = 1;
4329  }
4330  if (muok)
4331  // Kill it
4332  if (XrdProofdAux::KillProcess(pid, 1, ui, fMgr->ChangeOwn()) == 0)
4333  nk++;
4334  }
4335  pclose(fp);
4336  } else {
4337  // Error executing the command
4338  return -1;
4339  }
4340 #endif
4341 
4342  // Done
4343  return nk;
4344 }
4345 
4346 ////////////////////////////////////////////////////////////////////////////////
4347 /// Set user ownerships on some critical files or directories.
4348 /// Return 0 on success, -1 if enything goes wrong.
4349 
4351  const char *ord, const char *stag)
4352 {
4353  XPDLOC(SMGR, "ProofServMgr::SetUserOwnerships")
4354 
4355  TRACE(REQ, "enter");
4356 
4357  // If applicable, make sure that the private dataset dir for this user exists
4358  // and has the right permissions
4359  if (fMgr->DataSetSrcs()->size() > 0) {
4360  XrdProofUI ui;
4362  std::list<XrdProofdDSInfo *>::iterator ii;
4363  for (ii = fMgr->DataSetSrcs()->begin(); ii != fMgr->DataSetSrcs()->end(); ii++) {
4364  TRACE(ALL, "Checking dataset source: url:"<<(*ii)->fUrl<<", local:"
4365  <<(*ii)->fLocal<<", rw:"<<(*ii)->fRW);
4366  if ((*ii)->fLocal && (*ii)->fRW) {
4367  XrdOucString d;
4368  XPDFORM(d, "%s/%s", ((*ii)->fUrl).c_str(), p->Client()->UI().fGroup.c_str());
4369  if (XrdProofdAux::AssertDir(d.c_str(), ui, fMgr->ChangeOwn()) == 0) {
4370  if (XrdProofdAux::ChangeMod(d.c_str(), 0777) == 0) {
4371  XPDFORM(d, "%s/%s/%s", ((*ii)->fUrl).c_str(), p->Client()->UI().fGroup.c_str(),
4372  p->Client()->UI().fUser.c_str());
4373  if (XrdProofdAux::AssertDir(d.c_str(), p->Client()->UI(), fMgr->ChangeOwn()) == 0) {
4374  if (XrdProofdAux::ChangeMod(d.c_str(), 0755) != 0) {
4375  TRACE(XERR, "problems setting permissions 0755 on: "<<d);
4376  }
4377  } else {
4378  TRACE(XERR, "problems asserting: "<<d);
4379  }
4380  } else {
4381  TRACE(XERR, "problems setting permissions 0777 on: "<<d);
4382  }
4383  } else {
4384  TRACE(XERR, "problems asserting: "<<d);
4385  }
4386  }
4387  }
4388  }
4389 
4390  // If applicable, make sure that the private data dir for this user exists
4391  // and has the right permissions
4392  if (fMgr->DataDir() && strlen(fMgr->DataDir()) > 0 &&
4393  fMgr->DataDirOpts() && strlen(fMgr->DataDirOpts()) > 0 && ord && stag) {
4394  XrdProofUI ui;
4396  XrdOucString dgr, dus[3];
4397  XPDFORM(dgr, "%s/%s", fMgr->DataDir(), p->Client()->UI().fGroup.c_str());
4398  if (XrdProofdAux::AssertDir(dgr.c_str(), ui, fMgr->ChangeOwn()) == 0) {
4399  if (XrdProofdAux::ChangeMod(dgr.c_str(), 0777) == 0) {
4400  unsigned int mode = 0755;
4401  if (strchr(fMgr->DataDirOpts(), 'g')) mode = 0775;
4402  if (strchr(fMgr->DataDirOpts(), 'a') || strchr(fMgr->DataDirOpts(), 'o')) mode = 0777;
4403  XPDFORM(dus[0], "%s/%s", dgr.c_str(), p->Client()->UI().fUser.c_str());
4404  XPDFORM(dus[1], "%s/%s", dus[0].c_str(), ord);
4405  XPDFORM(dus[2], "%s/%s", dus[1].c_str(), stag);
4406  for (int i = 0; i < 3; i++) {
4407  if (XrdProofdAux::AssertDir(dus[i].c_str(), p->Client()->UI(), fMgr->ChangeOwn()) == 0) {
4408  if (XrdProofdAux::ChangeMod(dus[i].c_str(), mode) != 0) {
4409  std::ios_base::fmtflags oflags = std::cerr.flags();
4410  TRACE(XERR, "problems setting permissions "<< oct << mode<<" on: "<<dus[i]);
4411  std::cerr.flags(oflags);
4412  }
4413  } else {
4414  TRACE(XERR, "problems asserting: "<<dus[i]);
4415  break;
4416  }
4417  }
4418  } else {
4419  TRACE(XERR, "problems setting permissions 0777 on: "<<dgr);
4420  }
4421  } else {
4422  TRACE(XERR, "problems asserting: "<<dgr);
4423  }
4424  }
4425 
4426  if (fMgr->ChangeOwn()) {
4427  // Change ownership of '.creds'
4428  XrdOucString creds(p->Client()->Sandbox()->Dir());
4429  creds += "/.creds";
4430  if (XrdProofdAux::ChangeOwn(creds.c_str(), p->Client()->UI()) != 0) {
4431  TRACE(XERR, "can't change ownership of "<<creds);
4432  return -1;
4433  }
4434  }
4435 
4436  // We are done
4437  TRACE(REQ, "done");
4438  return 0;
4439 }
4440 
4441 ////////////////////////////////////////////////////////////////////////////////
4442 /// Set user environment: set effective user and group ID of the process
4443 /// to the ones of the owner of this protocol instnace and change working
4444 /// dir to the sandbox.
4445 /// Return 0 on success, -1 if enything goes wrong.
4446 
4448 {
4449  XPDLOC(SMGR, "ProofServMgr::SetUserEnvironment")
4450 
4451  TRACE(REQ, "enter");
4452 
4454  p->Client()->UI(), fMgr->ChangeOwn()) != 0) {
4455  TRACE(XERR, "couldn't change directory to "<< p->Client()->Sandbox()->Dir());
4456  return -1;
4457  }
4458 
4459  size_t len = 0;
4460  // set HOME env
4461  len = 8 + strlen(p->Client()->Sandbox()->Dir());
4462  char *h = new char[len];
4463  snprintf(h, len, "HOME=%s", p->Client()->Sandbox()->Dir());
4464  putenv(h);
4465  TRACE(DBG, "set "<<h);
4466 
4467  // set USER env
4468  len = 8 + strlen(p->Client()->User());
4469  char *u = new char[len];
4470  snprintf(u, len, "USER=%s", p->Client()->User());
4471  putenv(u);
4472  TRACE(DBG, "set "<<u);
4473 
4474  // Set access control list from /etc/initgroup
4475  // (super-user privileges required)
4476  TRACE(DBG, "setting ACLs");
4477  if (fMgr->ChangeOwn() && (int) geteuid() != p->Client()->UI().fUid) {
4478 
4479  XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
4480  if (XpdBadPGuard(pGuard, p->Client()->UI().fUid)) {
4481  TRACE(XERR, "could not get privileges");
4482  return -1;
4483  }
4484 
4485  initgroups(p->Client()->UI().fUser.c_str(), p->Client()->UI().fGid);
4486  }
4487 
4488  if (fMgr->ChangeOwn()) {
4489  // acquire permanently target user privileges
4490  TRACE(DBG, "acquiring target user identity: "<<(uid_t)p->Client()->UI().fUid<<
4491  ", "<<(gid_t)p->Client()->UI().fGid);
4492  if (XrdSysPriv::ChangePerm((uid_t)p->Client()->UI().fUid,
4493  (gid_t)p->Client()->UI().fGid) != 0) {
4494  TRACE(XERR, "can't acquire "<< p->Client()->UI().fUser <<" identity");
4495  return -1;
4496  }
4497  }
4498 
4499  // We are done
4500  TRACE(REQ, "done");
4501  return 0;
4502 }
4503 
4504 ////////////////////////////////////////////////////////////////////////////////
4505 /// Return active session with process ID pid, if any.
4506 
4508 {
4509  XrdOucString key; key += pid;
4510  return fSessions.Find(key.c_str());
4511 }
4512 
4513 ////////////////////////////////////////////////////////////////////////////////
4514 /// Run thorugh entries to broadcast the relevant priority
4515 
4516 static int BroadcastPriority(const char *, XrdProofdProofServ *ps, void *s)
4517 {
4518  XPDLOC(SMGR, "BroadcastPriority")
4519 
4520  XpdBroadcastPriority_t *bp = (XpdBroadcastPriority_t *)s;
4521 
4522  int nb = *(bp->fNBroadcast);
4523 
4524  XrdOucString emsg;
4525  if (ps) {
4526  if (ps->IsValid() && (ps->Status() == kXPD_running) &&
4527  !(ps->SrvType() == kXPD_Master)) {
4528  XrdProofGroup *g = (ps->Group() && bp->fGroupMgr)
4529  ? bp->fGroupMgr->GetGroup(ps->Group()) : 0;
4530  TRACE(DBG, "group: "<< g<<", client: "<<ps->Client());
4531  if (g && g->Active() > 0) {
4532  TRACE(DBG, "priority: "<< g->Priority()<<" active: "<<g->Active());
4533  int prio = (int) (g->Priority() * 100);
4534  ps->BroadcastPriority(prio);
4535  nb++;
4536  }
4537  }
4538  // Go to next
4539  return 0;
4540  } else {
4541  emsg = "input entry undefined";
4542  }
4543 
4544  // Some problem
4545  TRACE(XERR,"protocol error: "<<emsg);
4546  return 1;
4547 }
4548 
4549 ////////////////////////////////////////////////////////////////////////////////
4550 /// Broadcast cluster info to the active sessions
4551 
4553 {
4554  XPDLOC(SMGR, "ProofServMgr::BroadcastClusterInfo")
4555 
4556  TRACE(REQ, "enter");
4557 
4558  int tot = 0, act = 0;
4559  std::list<XrdProofdProofServ *>::iterator si = fActiveSessions.begin();
4560  while (si != fActiveSessions.end()) {
4561  if ((*si)->SrvType() != kXPD_Worker) {
4562  tot++;
4563  if ((*si)->Status() == kXPD_running) act++;
4564  }
4565  si++;
4566  }
4567  if (tot > 0) {
4568  XPDPRT("tot: "<<tot<<", act: "<<act);
4569  // Now propagate to master or sub-masters
4570  si = fActiveSessions.begin();
4571  while (si != fActiveSessions.end()) {
4572  if ((*si)->Status() == kXPD_running &&
4573  (*si)->SrvType() != kXPD_Worker) (*si)->SendClusterInfo(tot, act);
4574  si++;
4575  }
4576  } else {
4577  TRACE(DBG, "No master or submaster controlled by this manager");
4578  }
4579 }
4580 
4581 ////////////////////////////////////////////////////////////////////////////////
4582 /// Broadcast priorities to the active sessions.
4583 /// Returns the number of sessions contacted.
4584 
4586 {
4587  XPDLOC(SMGR, "ProofServMgr::BroadcastPriorities")
4588 
4589  TRACE(REQ, "enter");
4590 
4591  int nb = 0;
4592  XpdBroadcastPriority_t bp = { (fMgr ? fMgr->GroupsMgr() : 0), &nb };
4593  fSessions.Apply(BroadcastPriority, (void *)&bp);
4594  // Done
4595  return nb;
4596 }
4597 
4598 ////////////////////////////////////////////////////////////////////////////////
4599 /// Return true if in reconnection state, i.e. during
4600 /// that period during which clients are expected to reconnect.
4601 /// Return false if the session is fully effective
4602 
4604 {
4605  int rect = -1;
4606  if (fReconnectTime >= 0) {
4607  rect = time(0) - fReconnectTime;
4608  if (rect < fReconnectTimeOut)
4609  return true;
4610  }
4611  // Not reconnecting
4612  return false;
4613 }
4614 
4615 ////////////////////////////////////////////////////////////////////////////////
4616 /// Change reconnecting status
4617 ///
4618 
4620 {
4622 
4623  if (on) {
4624  fReconnectTime = time(0);
4625  } else {
4626  fReconnectTime = -1;
4627  }
4628 }
4629 
4630 ////////////////////////////////////////////////////////////////////////////////
4631 /// Check destroyed status
4632 ///
4633 
4635 {
4637 
4638  bool alive = true;
4639  int now = time(0);
4640  std::map<XrdProofdProtocol*,int>::iterator iter = fDestroyTimes.begin();
4641  while (iter != fDestroyTimes.end()) {
4642  int rect = now - iter->second;
4643  if (rect < fReconnectTimeOut) {
4644  if (p == iter->first) alive = false;
4645  } else {
4646  fDestroyTimes.erase(iter);
4647  }
4648  iter++;
4649  }
4650 
4651  return alive;
4652 }
4653 
4654 ////////////////////////////////////////////////////////////////////////////////
4655 /// Run through entries to reset the disconnecting client slots
4656 
4657 static int FreeClientID(const char *, XrdProofdProofServ *ps, void *s)
4658 {
4659  XPDLOC(SMGR, "FreeClientID")
4660 
4661  int pid = *((int *)s);
4662 
4663  if (ps) {
4664  ps->FreeClientID(pid);
4665  // Go to next
4666  return 0;
4667  }
4668 
4669  // Some problem
4670  TRACE(XERR, "protocol error: undefined session!");
4671  return 1;
4672 }
4673 
4674 ////////////////////////////////////////////////////////////////////////////////
4675 /// Change reconnecting status
4676 ///
4677 
4679 {
4681 
4682  fSessions.Apply(FreeClientID, (void *)&pid);
4683 }
4684 
4685 ////////////////////////////////////////////////////////////////////////////////
4686 /// Run thorugh entries to count top-masters
4687 
4688 static int CountTopMasters(const char *, XrdProofdProofServ *ps, void *s)
4689 {
4690  XPDLOC(SMGR, "CountTopMasters")
4691 
4692  int *ntm = (int *)s;
4693 
4694  XrdOucString emsg;
4695  if (ps) {
4696  if (ps->SrvType() == kXPD_TopMaster) (*ntm)++;
4697  // Go to next
4698  return 0;
4699  } else {
4700  emsg = "input entry undefined";
4701  }
4702 
4703  // Some problem
4704  TRACE(XERR,"protocol error: "<<emsg);
4705  return 1;
4706 }
4707 
4708 ////////////////////////////////////////////////////////////////////////////////
4709 /// Return the number of current sessions (top masters)
4710 
4712 {
4713  XPDLOC(SMGR, "ProofServMgr::CurrentSessions")
4714 
4715  TRACE(REQ, "enter");
4716 
4718  if (recalculate) {
4719  fCurrentSessions = 0;
4720  fSessions.Apply(CountTopMasters, (void *)&fCurrentSessions);
4721  }
4722 
4723  // Done
4724  return fCurrentSessions;
4725 }
4726 
4727 ////////////////////////////////////////////////////////////////////////////////
4728 /// Resolve some keywords in 's'
4729 /// <logfileroot>, <user>, <rootsys>
4730 
4732 {
4733  if (!in) return;
4734 
4735  bool isWorker = 0;
4736  if (in->fPS->SrvType() == kXPD_Worker) isWorker = 1;
4737 
4738  // Log file
4739  if (!isWorker && s.find("<logfilemst>") != STR_NPOS) {
4740  XrdOucString lfr(in->fLogFile);
4741  if (lfr.endswith(".log")) lfr.erase(lfr.rfind(".log"));
4742  s.replace("<logfilemst>", lfr);
4743  } else if (isWorker && s.find("<logfilewrk>") != STR_NPOS) {
4744  XrdOucString lfr(in->fLogFile);
4745  if (lfr.endswith(".log")) lfr.erase(lfr.rfind(".log"));
4746  s.replace("<logfilewrk>", lfr);
4747  }
4748 
4749  // user
4750  if (getenv("USER") && s.find("<user>") != STR_NPOS) {
4751  XrdOucString usr(getenv("USER"));
4752  s.replace("<user>", usr);
4753  }
4754 
4755  // rootsys
4756  if (getenv("ROOTSYS") && s.find("<rootsys>") != STR_NPOS) {
4757  XrdOucString rootsys(getenv("ROOTSYS"));
4758  s.replace("<rootsys>", rootsys);
4759  }
4760 }
4761 
4762 //
4763 // Auxilliary class to handle session pid files
4764 //
4765 
4766 ////////////////////////////////////////////////////////////////////////////////
4767 /// Construct from 'c' and 's'
4768 
4770 {
4771  fLastAccess = 0;
4772 
4773  // Fill from the client instance
4774  fUser = c ? c->User() : "";
4775  fGroup = c ? c->Group() : "";
4776 
4777  // Fill from the server instance
4778  fPid = s ? s->SrvPID() : -1;
4779  fID = s ? s->ID() : -1;
4780  fSrvType = s ? s->SrvType() : -1;
4781  fPLiteNWrks = s ? s->PLiteNWrks() : -1;
4782  fStatus = s ? s->Status() : kXPD_unknown;
4783  fOrdinal = s ? s->Ordinal() : "";
4784  fTag = s ? s->Tag() : "";
4785  fAlias = s ? s->Alias() : "";
4786  fLogFile = s ? s->Fileout() : "";
4787  fROOTTag = (s && s->ROOT())? s->ROOT()->Tag() : "";
4788  fSrvProtVers = (s && s->ROOT()) ? s->ROOT()->SrvProtVers() : -1;
4789  fUserEnvs = s ? s->UserEnvs() : "";
4790  fAdminPath = s ? s->AdminPath() : "";
4791  fUnixPath = s ? s->UNIXSockPath() : "";
4792 }
4793 
4794 ////////////////////////////////////////////////////////////////////////////////
4795 /// Fill 's' fields using the stored info
4796 
4798 {
4799  XPDLOC(SMGR, "SessionInfo::FillProofServ")
4800 
4801  s.SetClient(fUser.c_str());
4802  s.SetGroup(fGroup.c_str());
4803  if (fPid > 0)
4804  s.SetSrvPID(fPid);
4805  if (fID >= 0)
4806  s.SetID(fID);
4807  s.SetSrvType(fSrvType);
4808  s.SetPLiteNWrks(fPLiteNWrks);
4809  s.SetStatus(fStatus);
4810  s.SetOrdinal(fOrdinal.c_str());
4811  s.SetTag(fTag.c_str());
4812  s.SetAlias(fAlias.c_str());
4813  s.SetFileout(fLogFile.c_str());
4814  if (rmgr) {
4815  if (rmgr->GetVersion(fROOTTag.c_str())) {
4816  s.SetROOT(rmgr->GetVersion(fROOTTag.c_str()));
4817  } else {
4818  TRACE(ALL, "ROOT version '"<< fROOTTag <<
4819  "' not availabe anymore: setting the default");
4820  s.SetROOT(rmgr->DefaultVersion());
4821  }
4822  }
4823  s.SetUserEnvs(fUserEnvs.c_str());
4824  s.SetAdminPath(fAdminPath.c_str(), 0, 0);
4825  s.SetUNIXSockPath(fUnixPath.c_str());
4826 }
4827 
4828 ////////////////////////////////////////////////////////////////////////////////
4829 /// Save content to 'file'
4830 
4832 {
4833  XPDLOC(SMGR, "SessionInfo::SaveToFile")
4834 
4835  // Check inputs
4836  if (!file || strlen(file) <= 0) {
4837  TRACE(XERR,"invalid input: "<< (file ? file : "<nul>"));
4838  return -1;
4839  }
4840  TRACE(HDBG,"session saved to file: "<<file);
4841 
4842  // Create the file
4843  FILE *fpid = fopen(file, "w");
4844  if (fpid) {
4845  fprintf(fpid, "%s %s\n", fUser.c_str(), fGroup.c_str());
4846  fprintf(fpid, "%s\n", fUnixPath.c_str());
4847  fprintf(fpid, "%d %d %d %d\n", fPid, fID, fSrvType, fPLiteNWrks);
4848  fprintf(fpid, "%s %s %s\n", fOrdinal.c_str(), fTag.c_str(), fAlias.c_str());
4849  fprintf(fpid, "%s\n", fLogFile.c_str());
4850  fprintf(fpid, "%d %s\n", fSrvProtVers, fROOTTag.c_str());
4851  if (fUserEnvs.length() > 0)
4852  fprintf(fpid, "\n%s", fUserEnvs.c_str());
4853  fclose(fpid);
4854 
4855  // Make it writable by anyone (to allow the corresponding proofserv
4856  // to touch it for the asynchronous ping request)
4857  if (chmod(file, 0666) != 0) {
4858  TRACE(XERR, "could not change mode to 0666 on file "<<
4859  file<<"; error: "<<errno);
4860  }
4861 
4862  return 0;
4863  }
4864 
4865  TRACE(XERR,"session pid file cannot be (re-)created: "<<
4866  file<<"; error: "<<errno);
4867  return -1;
4868 }
4869 
4870 ////////////////////////////////////////////////////////////////////////////////
4871 /// Reset the content
4872 
4874 {
4875  fLastAccess = 0;
4876  fUser = "";
4877  fGroup = "";
4878  fAdminPath = "";
4879  fUnixPath = "";
4880  fPid = -1;
4881  fStatus = kXPD_unknown;
4882  fID = -1;
4883  fSrvType = -1;
4884  fPLiteNWrks = -1;
4885  fOrdinal = "";
4886  fTag = "";
4887  fAlias = "";
4888  fLogFile = "";
4889  fROOTTag = "";
4890  fSrvProtVers = -1;
4891  fUserEnvs = "";
4892 }
4893 
4894 ////////////////////////////////////////////////////////////////////////////////
4895 /// Read content from 'file'
4896 
4898 {
4899  XPDLOC(SMGR, "SessionInfo::ReadFromFile")
4900 
4901  Reset();
4902 
4903  // Check inputs
4904  if (!file || strlen(file) <= 0) {
4905  TRACE(XERR,"invalid input: "<<(file ? file : "<nul>"));
4906  return -1;
4907  }
4908 
4909  // Open the session file
4910  FILE *fpid = fopen(file,"r");
4911  if (fpid) {
4912  char line[4096];
4913  XrdOucString sline, t;
4914  int from = 0;
4915  if (fgets(line, sizeof(line), fpid)) {
4916  if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
4917  sline = line;
4918  if ((from = sline.tokenize(fUser, from, ' ')) == -1)
4919  TRACE(XERR,"warning: fUser: corrupted line? "<<line<<" (file: "<<file<<")");
4920  if ((from = sline.tokenize(fGroup, from, ' ')) == -1)
4921  TRACE(XERR,"warning: fGroup: corrupted line? "<<line<<" (file: "<<file<<")");
4922  }
4923  if (fgets(line, sizeof(line), fpid)) {
4924  if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
4925  fUnixPath = line;
4926  }
4927  if (fgets(line, sizeof(line), fpid)) {
4928  if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
4929  sline = line;
4930  from = 0;
4931  if ((from = sline.tokenize(t, from, ' ')) == -1)
4932  TRACE(XERR,"warning: fPid: corrupted line? "<<line<<" (file: "<<file<<")");
4933  fPid = t.atoi();
4934  if ((from = sline.tokenize(t, from, ' ')) == -1)
4935  TRACE(XERR,"warning: fID: corrupted line? "<<line<<" (file: "<<file<<")");
4936  fID = t.atoi();
4937  if ((from = sline.tokenize(t, from, ' ')) == -1)
4938  TRACE(XERR,"warning: fSrvType: corrupted line? "<<line<<" (file: "<<file<<")");
4939  fSrvType = t.atoi();
4940  }
4941  if (fgets(line, sizeof(line), fpid)) {
4942  if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
4943  sline = line;
4944  from = 0;
4945  if ((from = sline.tokenize(fOrdinal, from, ' ')) == -1)
4946  TRACE(XERR,"warning: fOrdinal: corrupted line? "<<line<<" (file: "<<file<<")");
4947  if ((from = sline.tokenize(fTag, from, ' ')) == -1)
4948  TRACE(XERR,"warning: fTag: corrupted line? "<<line<<" (file: "<<file<<")");
4949  if ((from = sline.tokenize(fAlias, from, ' ')) == -1)
4950  TRACE(HDBG,"fAlias undefined "<<line);
4951  }
4952  if (fgets(line, sizeof(line), fpid)) {
4953  if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
4954  fLogFile = line;
4955  }
4956  if (fgets(line, sizeof(line), fpid)) {
4957  if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
4958  sline = line;
4959  from = 0;
4960  if ((from = sline.tokenize(t, from, ' ')) == -1)
4961  TRACE(XERR,"warning: fSrvProtVers: corrupted line? "<<line<<" (file: "<<file<<")");
4962  fSrvProtVers = t.atoi();
4963  if ((from = sline.tokenize(fROOTTag, from, ' ')) == -1)
4964  TRACE(XERR,"warning: fROOTTag: corrupted line? "<<line<<" (file: "<<file<<")");
4965  }
4966  // All the remaining into fUserEnvs
4967  fUserEnvs = "";
4968  off_t lnow = lseek(fileno(fpid), (off_t) 0, SEEK_CUR);
4969  off_t ltot = lseek(fileno(fpid), (off_t) 0, SEEK_END);
4970  int left = (int)(ltot - lnow);
4971  int len = -1;
4972  do {
4973  int wanted = (left > 4095) ? 4095 : left;
4974  while ((len = read(fileno(fpid), line, wanted)) < 0 &&
4975  errno == EINTR)
4976  errno = 0;
4977  if (len < 0 || len < wanted) {
4978  break;
4979  } else {
4980  line[len] = '\0';
4981  fUserEnvs += line;
4982  }
4983  // Update counters
4984  left -= len;
4985  } while (len > 0 && left > 0);
4986  // Done
4987  fclose(fpid);
4988  // The file name is the admin path
4989  fAdminPath = file;
4990  // Fill access time
4991  struct stat st;
4992  if (!stat(file, &st))
4993  fLastAccess = st.st_atime;
4994  } else {
4995  TRACE(XERR,"session file cannot be open: "<< file<<"; error: "<<errno);
4996  return -1;
4997  }
4998 
4999  // Read the last status now if the session is active
5000  XrdOucString fs(file);
5001  fs += ".status";
5002  fpid = fopen(fs.c_str(),"r");
5003  if (fpid) {
5004  char line[64];
5005  if (fgets(line, sizeof(line), fpid)) {
5006  if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = 0;
5007  fStatus = atoi(line);
5008  }
5009  // Done
5010  fclose(fpid);
5011  } else {
5012  TRACE(DBG,"no session status file for: "<< fs<<"; session was probably terminated");
5013  }
5014 
5015  // Done
5016  return 0;
5017 }
5018 
5019 ////////////////////////////////////////////////////////////////////////////////
5020 /// Check if this env applies to 'usr', 'grp, 'ver'.
5021 /// Returns -1 if it does not match, >=0 if it matches. The value is a linear
5022 /// combination of matching lengths for user and group, with a weight of 1000 for
5023 /// the users one, so that an exact user match will always win.
5024 
5025 int XpdEnv::Matches(const char *usr, const char *grp, int ver)
5026 {
5027  XPDLOC(SMGR, "XpdEnv::Matches")
5028 
5029  int nmtc = -1;
5030  // Check the user
5031  if (fUsers.length() > 0) {
5032  XrdOucString u(usr);
5033  if ((nmtc = u.matches(fUsers.c_str())) == 0) return -1;
5034  } else {
5035  nmtc = strlen(usr);
5036  }
5037  nmtc += 1000; // Weigth of user name match
5038  // Check the group
5039  int nmtcg = -1;
5040  if (fGroups.length() > 0) {
5041  XrdOucString g(grp);
5042  if ((nmtcg = g.matches(fGroups.c_str())) == 0) return -1;
5043  } else {
5044  nmtcg = strlen(grp);
5045  }
5046  nmtc += nmtcg;
5047 
5048  TRACE(HDBG, fEnv <<", u:"<<usr<<", g:"<<grp<<" --> nmtc: "<<nmtc);
5049 
5050  // Check the version code
5051  TRACE(HDBG, fEnv <<", ver:"<<ver);
5052  if (fVerMin > 0 && ver < fVerMin) return -1;
5053  if (fVerMax > 0 && ver > fVerMax) return -1;
5054 
5055  // If we are here then it matches
5056  return nmtc;
5057 }
5058 
5059 ////////////////////////////////////////////////////////////////////////////////
5060 /// Transform version number ver (format patch + 100*minor + 10000*maj, e.g. 52706)
5061 /// If 'hex' is true, the components are decoded as hex numbers
5062 
5063 int XpdEnv::ToVersCode(int ver, bool hex)
5064 {
5065  int maj = -1, min = -1, ptc = -1, xv = ver;
5066  if (hex) {
5067  maj = xv / 65536;
5068  xv -= maj * 65536;
5069  min = xv / 256;
5070  ptc = xv - min * 256;
5071  } else {
5072  maj = xv / 10000;
5073  xv -= maj * 10000;
5074  min = xv / 100;
5075  ptc = xv - min * 100;
5076  }
5077  // Get the version code now
5078  int vc = (maj << 16) + (min << 8) + ptc;
5079  return vc;
5080 }
5081 
5082 ////////////////////////////////////////////////////////////////////////////////
5083 /// Print the content of this env
5084 
5085 void XpdEnv::Print(const char *what)
5086 {
5087  XPDLOC(SMGR, what)
5088 
5089  XrdOucString vmi("-1"), vmx("-1");
5090  if (fVerMin > 0) {
5091  int maj = (fVerMin >> 16);
5092  int min = ((fVerMin - maj * 65536) >> 8);
5093  int ptc = fVerMin - maj * 65536 - min * 256;
5094  XPDFORM(vmi, "%d%d%d", maj, min, ptc);
5095  }
5096  if (fVerMax > 0) {
5097  int maj = (fVerMax >> 16);
5098  int min = ((fVerMax - maj * 65536) >> 8);
5099  int ptc = fVerMax - maj * 65536 - min * 256;
5100  XPDFORM(vmx, "%d%d%d", maj, min, ptc);
5101  }
5102  XrdOucString u("allusers"), g("allgroups");
5103  if (fUsers.length() > 0) u = fUsers;
5104  if (fGroups.length() > 0) u = fGroups;
5105 
5106  TRACE(ALL, "'"<<fEnv<<"' {"<<u<<"|"<<g<<
5107  "} svn:["<<fSvnMin<<","<<fSvnMax<<"] vers:["<<vmi<<","<<vmx<<"]");
5108 }
int CreateSockPath(XrdProofdProofServ *xps, XrdProofdProtocol *p, unsigned int seq, XrdOucString &emsg)
Create the socket path for the starting session Return 0 on success, -1 on error (error message in &#39;e...
int FreeClientID(int pid)
Free instance corresponding to protocol connecting process &#39;pid&#39;.
double read(const std::string &file_name)
reading
void SetParent(XrdClientID *cid)
XrdSysRecMutex * Mutex() const
const char * Dir() const
int SetupProtocol(XrdNetPeer &peerpsrv, XrdProofdProofServ *xps, XrdOucString &e)
Setup the protocol object serving the peer described by &#39;peerpsrv&#39;.
static int BroadcastPriority(const char *, XrdProofdProofServ *ps, void *s)
Run thorugh entries to broadcast the relevant priority.
void Reset(const char *n, const char *env, const char *usr=0, const char *grp=0, int smi=-1, int smx=-1, int vmi=-1, int vmx=-1)
const char * Group() const
int BroadcastPriorities()
Broadcast priorities to the active sessions.
XrdOucHash< XrdProofdProofServ > fSessions
void SetReconnectTime(bool on=1)
Change reconnecting status.
int Poll(int to=-1)
Poll over the read pipe for to secs; return whatever poll returns.
int CurrentSessions(bool recalculate=0)
Return the number of current sessions (top masters)
#define XPD_LIBPATH
static int ToVersCode(int ver, bool hex=0)
Transform version number ver (format patch + 100*minor + 10000*maj, e.g.
bool IsValid() const
Definition: XrdProofdAux.h:209
#define kXPD_TopMaster
const char * RootdExe() const
#define TRACING(x)
int Process(XrdProofdProtocol *p)
Process manager request.
#define XPROOFD_VERSBIN
const char * BareLibPath() const
void Print(const char *what)
Print the content of this env.
TLine * line
const double pi
static int GetUserInfo(const char *usr, XrdProofUI &ui)
Get information about user &#39;usr&#39; in a thread safe way.
XrdProtocol * Match(XrdLink *lp)
Check whether the request matches this protocol.
XrdLink * Link() const
int CleanupProofServ(bool all=0, const char *usr=0)
Cleanup (kill) all &#39;proofserv&#39; processes from the process table.
const char * Group() const
XrdROOT * DefaultVersion() const
Definition: XrdROOT.h:118
bool IsClientRecovering(const char *usr, const char *grp, int &deadline)
Returns true (an the recovering deadline) if the client has sessions in recovering state; returns fal...
void ParseCreateBuffer(XrdProofdProtocol *p, XrdProofdProofServ *xps, XrdOucString &tag, XrdOucString &ord, XrdOucString &cffile, XrdOucString &uenvs, int &intwait)
Extract relevant quantities from the buffer received during a create request.
void SetAlias(const char *a)
XrdProofdNetMgr * NetMgr() const
const char * Tag() const
int SetUserOwnerships(XrdProofdProtocol *p, const char *ord, const char *stag)
Set user ownerships on some critical files or directories.
int SetProofServEnv(XrdProofdProtocol *p, void *in)
Set environment for proofserv.
#define PutEnv(x, e)
const char * Client() const
std::map< XrdProofdProtocol *, int > fDestroyTimes
int DoDirectiveClass(XrdProofdDirective *, char *val, XrdOucStream *cfg, bool rcf)
Generic class directive processor.
TH1 * h
Definition: legend2.C:5
const char * Buf() const
Definition: XrdProofdAux.h:185
#define XrdSysRecMutex
Definition: XrdSysToOuc.h:18
bool IsSessionSocket(const char *fpid)
Checks is fpid is the path of a session UNIX socket Returns TRUE is yes; cleans the socket if the ses...
int CheckSession(bool oldvers, bool isrec, int shutopt, int shutdel, bool changeown, int &nc)
Calculate the effective number of users on this session nodes and communicate it to the master togeth...
int CreateProofServRootRc(XrdProofdProtocol *p, void *input, const char *rcfn)
Create in &#39;rcfn&#39; the rootrc file for the proofserv being created return 0 on success, -1 on error.
#define TRACE(Flag, Args)
Definition: TGHtml.h:120
void UpdateCounter(int t, int n)
const char * Alias() const
void SetSid(unsigned short sid)
int RmSession(const char *fpid)
Remove session file from the terminated sessions area.
XrdProofdProofServ * GetServObj(int id)
Get server at &#39;id&#39;. If needed, increase the vector size.
virtual int MaxSessions() const
Definition: XrdProofSched.h:89
kXR_int32 CID() const
int DeleteFromSessions(const char *pid)
Delete from the hash list the session with ID pid.
void Reset()
Reset this instance.
static int FreeClientID(const char *, XrdProofdProofServ *ps, void *s)
Run through entries to reset the disconnecting client slots.
int Type() const
Definition: XrdProofdAux.h:194
XrdNet * UNIXSock() const
XrdScheduler * Sched() const
int DoDirectiveInt(XrdProofdDirective *, char *val, XrdOucStream *cfg, bool rcf)
Process directive for an integer.
TArc * a
Definition: textangle.C:12
short int ID() const
#define kXPD_MasterMaster
const char * LibDir() const
Definition: XrdROOT.h:69
#define XPD_LONGOK(x)
XrdSrvBuffer * StartMsg() const
void ResolveKeywords(XrdOucString &s, ProofServEnv_t *in)
Resolve some keywords in &#39;s&#39; <logfileroot>, <user>, <rootsys>
void SetOrdinal(const char *o)
void SetAdminPath(const char *p)
const char * GetCfgFile() const
bool Alive(XrdProofdProtocol *p)
Check destroyed status.
bool ChangeOwn() const
int AddSession(XrdProofdProtocol *p, XrdProofdProofServ *s)
Add new active session.
#define kXPD_ClientMaster
short int ProofProtocol() const
const char * DataDir() const
static int ChangePerm(uid_t uid, gid_t gid)
kXR_int16 SrvProtVers() const
Definition: XrdROOT.h:82
XrdClientID * GetClientID(int cid)
Get instance corresponding to cid.
XrdSecProtocol * AuthProt() const
const char * StageReqRepo() const
#define XPDPRT(x)
struct ClientRequestHdr header
XrdSysSemWait * ProcessSem()
const char * SockPathDir() const
int CreateUNIXSock(XrdSysError *edest)
Create UNIX socket for internal connections.
int Recv(XpdMsg &msg)
Recv message from the pipe.
static int CountTopMasters(const char *, XrdProofdProofServ *ps, void *s)
Run thorugh entries to count top-masters.
void * XrdProofdProofServRecover(void *p)
Waiting for session to recover after an abrupt shutdown.
XrdSecCredsSaver_t fCredsSaver
int CreateProofServEnvFile(XrdProofdProtocol *p, void *input, const char *envfn, const char *rcfn)
Create in &#39;rcfn&#39; the rootrc file for the proofserv being created return 0 on success, -1 on error.
static int GetVersionCode(const char *release)
Translate &#39;release&#39; into a version code integer following the rules in $ROOTSYS/include/RVersion.h.
Definition: XrdROOT.cxx:275
void ExtractEnv(char *, XrdOucStream *, XrdOucString &users, XrdOucString &groups, XrdOucString &rcval, XrdOucString &rcnam, int &smi, int &smx, int &vmi, int &vmx, bool &hex)
Extract env information from the stream &#39;cfg&#39;.
static int ParsePidPath(const char *path, XrdOucString &before, XrdOucString &after)
Parse a path in the form of "<before>[.<pid>][.<after>]", filling &#39;rest&#39; and returning &#39;pid&#39;...
XrdProofSched * ProofSched() const
int Destroy(XrdProofdProtocol *p)
Handle a request to shutdown an existing session.
const char * UNIXSockPath() const
static int SymLink(const char *path, const char *link)
Create a symlink &#39;link&#39; to &#39;path&#39; Return 0 in case of success, -1 in case of error.
void SetProtocol(XrdProofdProtocol *p)
XrdProofGroupMgr * GroupsMgr() const
const char * User() const
void FormFileNameInSessionDir(XrdProofdProtocol *p, XrdProofdProofServ *xps, const char *sessiondir, const char *extension, XrdOucString &outfn)
int CreateAdminPath(XrdProofdProofServ *xps, XrdProofdProtocol *p, int pid, XrdOucString &emsg)
Create the admin path for the starting session Return 0 on success, -1 on error (error message in &#39;em...
XrdBuffer * Argp() const
XrdProofSessionInfo(XrdProofdClient *c, XrdProofdProofServ *s)
Construct from &#39;c&#39; and &#39;s&#39;.
int SetProcessPriority(int pid, const char *usr, int &dp)
Change priority of process pid belonging to user, if needed.
XrdOucString fName
std::list< XpdEnv > fProofServEnvs
bool IsReconnecting()
Return true if in reconnection state, i.e.
const char * DataDir() const
Definition: XrdROOT.h:67
void Close()
If open, close and invalidated the pipe descriptors.
void DeleteUNIXSock()
Delete the current UNIX socket.
bool WorkerUsrCfg() const
XrdProofdClientMgr * fClientMgr
int CheckActiveSessions(bool verify=1)
Go through the active sessions admin path and make sure sessions are alive.
const char * Ordinal() const
static int Attach(XrdLink *lp)
void SetUNIXSockPath(const char *s)
int TouchSession(const char *fpid, const char *path=0)
Update the access time for the session pid file to the current time.
std::list< XrdProofdProofServ * > fActiveSessions
static int EUidAtStartup()
XrdOucString fUser
Definition: XrdProofdAux.h:40
XrdSysError * fEDest
void DisconnectFromProofServ(int pid)
Change reconnecting status.
void SetGroup(const char *g)
int Matches(const char *usr, const char *grp, int ver=-1)
Check if this env applies to &#39;usr&#39;, &#39;grp, &#39;ver&#39;.
#define XPDLOC(d, x)
XrdProofdPipe * Pipe()
std::list< XpdClientSessions * > * fRecoverClients
const char * NameSpace() const
void SetROOT(XrdROOT *r)
void FillProofServ(XrdProofdProofServ &s, XrdROOTMgr *rmgr)
Fill &#39;s&#39; fields using the stored info.
void RegisterDirectives()
Register directives for configuration.
XrdProofSched * fProofSched
std::list< XrdProofdProofServ * > fProofServs
int Config(bool rcf=0)
Run configuration and parse the entered config directives.
void SetFileout(const char *f)
int Attach(XrdProofdProtocol *p)
Handle a request to attach to an existing session.
int GetNClients(bool check)
Get the number of connected clients.
std::list< XpdEnv > fProofServRCs
#define kXPD_MasterWorker
float Priority() const
Definition: XrdProofGroup.h:80
static XpdManagerCron_t fManagerCron
TRandom2 r(17)
static const char * ProofRequestTypes(int type)
Translates the proof request type in a human readable string.
static int GetIDFromPath(const char *path, XrdOucString &emsg)
Extract an integer from a file.
const char * DataDirUrlOpts() const
int ResolveSession(const char *fpid)
Handle a request to recover a session after stop&restart.
bool MultiUser() const
XrdOucString fGroup
Definition: XrdProofdAux.h:41
void SetP(XrdProofdProtocol *p)
XrdROOT * GetVersion(const char *tag)
Return pointer to the ROOT version corresponding to &#39;tag&#39; or 0 if not found.
Definition: XrdROOT.cxx:738
#define XrdSysMutexHelper
Definition: XrdSysToOuc.h:17
XrdProofdSandbox * Sandbox() const
static int WriteSessEnvs(const char *, XpdEnv *env, void *s)
Run thorugh entries to broadcast the relevant priority.
struct XPClientProofRequest proof
const char * Host() const
#define XrdSysError
Definition: XpdSysError.h:8
void Reset()
Reset the content.
int Recover(XpdClientSessions *cl)
Handle a request to recover a session after stop&restart for a specific client.
#define TRACEP(p, act, x)
int CleanClientSessions(const char *usr, int srvtype)
Go through the sessions admin path and clean all sessions belonging to &#39;usr&#39;.
int MvSession(const char *fpid)
Move session file from the active to the terminated areas.
#define XpdBadPGuard(g, u)
Definition: XrdProofdAux.h:368
XrdProofdClientMgr * ClientMgr() const
TLine * l
Definition: textangle.C:4
const char * Tag() const
Definition: XrdROOT.h:83
int PrepareSessionRecovering()
Go through the active sessions admin path and prepare reconnection of those still alive...
int VerifySession(const char *fpid, int to=-1, const char *path=0)
Check if the session is alive, i.e.
std::list< XrdProofdDSInfo * > * DataSetSrcs()
void Reset(Detail::TBranchProxy *x)
int Active(const char *usr=0)
Return the number of active groups (usr = 0) or the number of active sessions for user &#39;usr&#39;...
int Detach(XrdProofdProtocol *p)
Handle a request to detach from an existing session.
void SetID(short int id)
static long int GetLong(char *str)
Extract first integer from string at &#39;str&#39;, if any.
void GetTagDirs(int opt, XrdProofdProtocol *p, XrdProofdProofServ *xps, XrdOucString &sesstag, XrdOucString &topsesstag, XrdOucString &sessiondir, XrdOucString &sesswrkdir)
Determine the unique tag and relevant dirs for this session.
#define kXPD_AnyServer
void SetTag(const char *t)
int AddSession(const char *tag)
Record entry for new proofserv session tagged &#39;tag&#39; in the active sessions file (<SandBox>/.sessions).
XrdProofdProofServ * fPS
int BroadcastPriority(int priority)
Broadcast a new group priority value to the worker servers.
const char * TMPdir() const
const char * extension
Definition: civetweb.c:5005
const char * AdminPath() const
const char * Fileout() const
int SetAdminPath(const char *a, bool assert, bool setown)
Set the admin path and make sure the file exists.
static int AssertDir(const char *path, XrdProofUI ui, bool changeown)
Make sure that &#39;path&#39; exists and is owned by the entity described by &#39;ui&#39;.
XrdROOTMgr * ROOTMgr() const
void TerminateSessions(int srvtype, XrdProofdProofServ *ref, const char *msg, XrdProofdPipe *pipe, bool changeown)
Terminate client sessions; IDs of signalled processes are added to sigpid.
#define XPDFORM
Definition: XrdProofdAux.h:381
#define kXPD_Worker
XrdProofdProtocol * Protocol() const
XrdProofdProofServMgr * fSessionMgr
double f(double x)
static int CheckIf(XrdOucStream *s, const char *h)
Check existence and match condition of an &#39;if&#39; directive If none (valid) is found, return -1.
int CheckTerminatedSessions()
Go through the terminated sessions admin path and make sure sessions they are gone.
int ResolveKeywords(XrdOucString &s, XrdProofdClient *pcl)
Resolve special keywords in &#39;s&#39; for client &#39;pcl&#39;.
const char * LocalROOT() const
#define DIGIT(x)
Definition: XrdProofdAux.h:349
int DoDirectiveString(XrdProofdDirective *, char *val, XrdOucStream *cfg, bool rcf)
Process directive for a string.
void SendErrLog(const char *errlog, XrdProofdResponse *r)
Send content of errlog upstream asynchronously.
int CleanupLostProofServ()
Cleanup (kill) all &#39;proofserv&#39; processes which lost control from their creator or controller daemon...
XrdOucString fSessionDir
XrdOucString fSessionTag
int SetProofServEnvOld(XrdProofdProtocol *p, void *in)
Set environment for proofserv; old version preparing the environment for proofserv protocol version <...
#define free
Definition: civetweb.c:821
XrdROOT * ROOT() const
void SetValid(bool valid=1)
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
void SetUserEnvs(const char *t)
const char * AdminPath() const
const char * EffectiveUser() const
XrdProofdProofServ * PrepareProofServ(XrdProofdProtocol *p, XrdProofdResponse *r, unsigned short &sid)
Allocate and prepare the XrdProofdProofServ object describing this session.
static int ChangeMod(const char *path, unsigned int mode)
Change the permission mode of &#39;path&#39; to &#39;mode&#39;.
const char * PoolURL() const
int DoDirectiveShutdown(char *, XrdOucStream *, bool)
Process &#39;shutdown&#39; directive.
const char * Export() const
Definition: XrdROOT.h:70
#define XPD_SETRESP(p, x)
R__EXTERN C unsigned int sleep(unsigned int seconds)
static int WriteSessRCs(const char *, XpdEnv *erc, void *f)
Run thorugh entries to broadcast the relevant priority.
void FillEnvList(std::list< XpdEnv > *el, const char *nam, const char *val, const char *usrs=0, const char *grps=0, int smi=-1, int smx=-1, int vmi=-1, int vmx=-1, bool hex=0)
Fill env entry(ies) in the relevant list.
XrdClientID * Parent() const
XrdProofdPriorityMgr * PriorityMgr() const
XrdROOT * ROOT() const
XrdOucString fName
Definition: XrdProofdAux.h:111
int Get(int &i)
Get next token and interpret it as an int.
const char * DataDirOpts() const
bool IsSuperMst() const
Definition: file.py:1
XrdProofdProofServMgr(XrdProofdManager *mgr, XrdProtocol_Config *pi, XrdSysError *e)
Constructor.
int Create(XrdProofdProtocol *p)
Handle a request to create a new session.
static int ChangeToDir(const char *dir, XrdProofUI ui, bool changeown)
Change current directory to &#39;dir&#39;.
XrdProofUI UI() const
void * XrdProofdProofServCron(void *p)
This is an endless loop to check the system periodically or when triggered via a message in a dedicat...
const char * CfgFile() const
#define snprintf
Definition: civetweb.c:822
XrdOucString fTopSessionTag
int DoDirective(XrdProofdDirective *d, char *val, XrdOucStream *cfg, bool rcf)
Update the priorities of the active sessions.
int DoDirectivePutRc(char *, XrdOucStream *, bool)
Process &#39;putrc&#39; directives.
const char * Image() const
XrdProofdProofServ * GetActiveSession(int pid)
Return active session with process ID pid, if any.
#define kXPD_Master
int ReadFromFile(const char *file)
Read content from &#39;file&#39;.
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.
XrdProofdClient * Client() const
static int ChangeOwn(const char *path, XrdProofUI ui)
Change the ownership of &#39;path&#39; to the entity described by &#39;ui&#39;.
int Post(int type, const char *msg)
Post message on the pipe.
static int VerifyProcessByID(int pid, const char *pname="proofserv")
Check if a process named &#39;pname&#39; and process &#39;pid&#39; is still in the process table. ...
int AcceptPeer(XrdProofdProofServ *xps, int to, XrdOucString &e)
Accept a callback from a starting-up server and setup the related protocol object.
int RecoverActiveSessions()
Accept connections from sessions still alive.
int DoDirectivePutEnv(char *, XrdOucStream *, bool)
Process &#39;putenv&#39; directives.
XrdOucString fEnv
#define PSMMAXCNTS
XrdProofdProofServ * GetServer(int psid)
Get from the vector server instance with ID psid.
static int GetProcesses(const char *pn, std::map< int, XrdOucString > *plist)
Get from the process table list of PIDs for processes named "proofserv&#39; For {linux, sun, macosx} it uses the system info; for other systems it invokes the command shell &#39;ps ax&#39; via popen.
static void LogEmsgToFile(const char *flog, const char *emsg, const char *pfx=0)
Logs error message &#39;emsg&#39; to file &#39;flog&#39; using standard technology.
const char * BinDir() const
Definition: XrdROOT.h:66
int VerifyProofServ(bool fw)
Check if the associated proofserv process is alive.
XrdProofdProofServ * GetFreeServObj()
Get next free server ID.
virtual int Config(bool rcf=0)
const char * UserEnvs() const
bool ReadFile(bool update=true)
Return true if the file has never been read or did change since last reading, false otherwise...
int Send(void)
Auxilliary Send method.
const char * Dir() const
Definition: XrdROOT.h:65
XrdProofdClient * fClient
void SetClient(const char *c)
static int KillProcess(int pid, bool forcekill, XrdProofUI ui, bool changeown)
Kill the process &#39;pid&#39;.
const char * cnt
Definition: TXMLSetup.cxx:75
void Register(const char *dname, XrdProofdDirective *d)
XPClientRequest * Request() const
int SaveToFile(const char *file)
Save content to &#39;file&#39;.
int DoDirectiveProofServMgr(char *, XrdOucStream *, bool)
Process &#39;proofswrvmgr&#39; directive eg: xpd.proofswrvmgr checkfq:120 termto:100 verifyto:5 recoverto:20...
void BroadcastClusterInfo()
Broadcast cluster info to the active sessions.
int SetUserEnvironment(XrdProofdProtocol *p)
Set user environment: set effective user and group ID of the process to the ones of the owner of this...
const char * PrgmSrv() const
Definition: XrdROOT.h:79
int VersionCode() const
Definition: XrdROOT.h:84