Logo ROOT  
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"
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
51typedef struct {
55typedef struct {
58 FILE *fEnv;
59 bool fExport;
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
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");
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
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
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) {
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;
285 // Init internal counters
286 for (int i = 0; i < PSMMAXCNTS; i++) {
287 fCounters[i] = 0;
288 }
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
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
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
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
579int 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
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)
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
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
860bool 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;
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);
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
1038int 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)
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
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
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
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
1216int 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
1285int 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
1316int 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
1338void 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
1394void 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
1452int 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;
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;
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
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 {
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
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
2696int 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
2842static 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
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
3303static 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
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
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 XPDFORM(locdatasrv, "root://%s", fMgr->Host());
3542
3543 int nrk = fMgr->ResolveKeywords(locdatasrv, p->Client());
3544 TRACE(HDBG, nrk << " placeholders resolved for LOCALDATASERVER");
3545 len = strlen("LOCALDATASERVER=") + locdatasrv.length() + 2;
3546 ev = new char[len];
3547 snprintf(ev, len, "LOCALDATASERVER=%s", locdatasrv.c_str());
3548 fprintf(fenv, "%s\n", ev);
3549 TRACE(DBG, ev);
3550 PutEnv(ev, in->fOld);
3551
3552 // Xrootd config file
3553 if (CfgFile()) {
3554 len = strlen("XRDCF=") + strlen(CfgFile()) + 2;
3555 ev = new char[len];
3556 snprintf(ev, len, "XRDCF=%s", CfgFile());
3557 fprintf(fenv, "%s\n", ev);
3558 TRACE(DBG, ev);
3559 PutEnv(ev, in->fOld);
3560 }
3561
3562 // Additional envs (xpd.putenv directive)
3564 if (fProofServEnvs.size() > 0) {
3565 // Hash list of the directives applying to this {user, group, svn, version}
3566 XrdOucHash<XpdEnv> sessenvs;
3567 std::list<XpdEnv>::iterator ienvs = fProofServEnvs.begin();
3568 for ( ; ienvs != fProofServEnvs.end(); ++ienvs) {
3569 int envmatch = (*ienvs).Matches(p->Client()->User(), p->Client()->Group(),
3570 p->Client()->ROOT()->VersionCode());
3571 if (envmatch >= 0) {
3572 XpdEnv *env = sessenvs.Find((*ienvs).fName.c_str());
3573 if (env) {
3574 int envmtcex = env->Matches(p->Client()->User(), p->Client()->Group(),
3575 p->Client()->ROOT()->VersionCode());
3576 if (envmatch > envmtcex) {
3577 // Replace the entry
3578 env = &(*ienvs);
3579 sessenvs.Rep(env->fName.c_str(), env, 0, Hash_keepdata);
3580 }
3581 } else {
3582 // Add an entry
3583 env = &(*ienvs);
3584 sessenvs.Add(env->fName.c_str(), env, 0, Hash_keepdata);
3585 }
3586 TRACE(HDBG, "Adding: "<<(*ienvs).fEnv);
3587 }
3588 }
3589 XpdWriteEnv_t xpwe = {fMgr, p->Client(), fenv, in->fOld};
3590 sessenvs.Apply(WriteSessEnvs, (void *)&xpwe);
3591 }
3592 }
3593 // Set the user envs
3594 if (xps->UserEnvs() &&
3595 strlen(xps->UserEnvs()) && strstr(xps->UserEnvs(),"=")) {
3596 // The single components
3597 XrdOucString ue = xps->UserEnvs();
3598 XrdOucString env, namelist;
3599 int from = 0, ieq = -1;
3600 while ((from = ue.tokenize(env, from, ',')) != -1) {
3601 if (env.length() > 0 && (ieq = env.find('=')) != -1) {
3602 // Resolve keywords
3603 ResolveKeywords(env, in);
3604 ev = new char[env.length()+1];
3605 strncpy(ev, env.c_str(), env.length());
3606 ev[env.length()] = 0;
3607 if (env.find("WRAPPERCMD") == STR_NPOS || !xps->IsPLite())
3608 fprintf(fenv, "%s\n", ev);
3609 TRACE(DBG, ev);
3610 PutEnv(ev, in->fOld);
3611 if (env.find("WRAPPERCMD") == STR_NPOS || !xps->IsPLite()) {
3612 env.erase(ieq);
3613 if (namelist.length() > 0)
3614 namelist += ',';
3615 namelist += env;
3616 }
3617 }
3618 }
3619 // The list of names, ','-separated
3620 len = strlen("PROOF_ALLVARS=") + namelist.length() + 2;
3621 ev = new char[len];
3622 snprintf(ev, len, "PROOF_ALLVARS=%s", namelist.c_str());
3623 fprintf(fenv, "%s\n", ev);
3624 TRACE(DBG, ev);
3625 PutEnv(ev, in->fOld);
3626 }
3627
3628 // Close file
3629 fclose(fenv);
3630
3631 // We are done
3632 return 0;
3633}
3634
3635////////////////////////////////////////////////////////////////////////////////
3636/// Create in 'rcfn' the rootrc file for the proofserv being created
3637/// return 0 on success, -1 on error
3638
3640 void *input, const char *rcfn)
3641{
3642 XPDLOC(SMGR, "ProofServMgr::CreateProofServRootRc")
3643
3644 // Check inputs
3645 if (!p || !input || (!rcfn || (rcfn && strlen(rcfn) <= 0))) {
3646 TRACE(XERR, "invalid inputs!");
3647 return -1;
3648 }
3649
3650 // Attach the structure
3652
3653 // Session proxy
3654 XrdProofdProofServ *xps = in->fPS;
3655 if (!xps) {
3656 TRACE(XERR, "unable to get instance of proofserv proxy");
3657 return -1;
3658 }
3659 int psid = xps->ID();
3660
3661 FILE *frc = fopen(rcfn, "w");
3662 if (!frc) {
3663 TRACE(XERR, "unable to open rootrc file: "<<rcfn);
3664 return -1;
3665 }
3666 // Symlink to session.rootrc
3667 if (in->fOld) {
3668 if (XrdProofdAux::SymLink(rcfn, "session.rootrc") != 0) {
3669 TRACE(XERR, "problems creating symlink to 'session.rootrc' (errno: "<<errno<<")");
3670 }
3671 }
3672 TRACE(REQ, "session rootrc file: "<< rcfn);
3673
3674 // Port
3675 fprintf(frc, "# XrdProofdProtocol listening port\n");
3676 fprintf(frc, "ProofServ.XpdPort: %d\n", fMgr->Port());
3677
3678 // Local root prefix
3679 if (fMgr->LocalROOT() && strlen(fMgr->LocalROOT()) > 0) {
3680 fprintf(frc, "# Prefix to be prepended to local paths\n");
3681 fprintf(frc, "Path.Localroot: %s\n", fMgr->LocalROOT());
3682 }
3683
3684 // Data pool entry-point URL
3685 if (fMgr->PoolURL() && strlen(fMgr->PoolURL()) > 0) {
3686 XrdOucString purl(fMgr->PoolURL());
3687 if (!purl.endswith("/"))
3688 purl += "/";
3689 fprintf(frc, "# URL for the data pool entry-point\n");
3690 fprintf(frc, "ProofServ.PoolUrl: %s\n", purl.c_str());
3691 }
3692
3693 // The session working dir depends on the role
3694 if (in->fOld) {
3695 fprintf(frc, "# The session working dir\n");
3696 fprintf(frc, "ProofServ.SessionDir: %s\n", in->fWrkDir.c_str());
3697 }
3698
3699 // Log / Debug level
3700 fprintf(frc, "# Proof Log/Debug level\n");
3701 fprintf(frc, "Proof.DebugLevel: %d\n", in->fLogLevel);
3702
3703 // Ordinal number
3704 fprintf(frc, "# Ordinal number\n");
3705 fprintf(frc, "ProofServ.Ordinal: %s\n", xps->Ordinal());
3706
3707 // ROOT Version tag
3708 if (p->Client()->ROOT()) {
3709 fprintf(frc, "# ROOT Version tag\n");
3710 fprintf(frc, "ProofServ.RootVersionTag: %s\n", p->Client()->ROOT()->Tag());
3711 }
3712 // Proof group
3713 if (p->Client()->Group()) {
3714 fprintf(frc, "# Proof group\n");
3715 fprintf(frc, "ProofServ.ProofGroup: %s\n", p->Client()->Group());
3716 }
3717
3718 // Path to file with group information
3719 if (fMgr->GroupsMgr() && fMgr->GroupsMgr()->GetCfgFile()) {
3720 fprintf(frc, "# File with group information\n");
3721 fprintf(frc, "Proof.GroupFile: %s\n", fMgr->GroupsMgr()->GetCfgFile());
3722 }
3723
3724 // Work dir
3725 XrdOucString udir = p->Client()->Sandbox()->Dir();
3726 fprintf(frc, "# Users sandbox\n");
3727 fprintf(frc, "ProofServ.Sandbox: %s\n", udir.c_str());
3728
3729 // Image
3730 if (fMgr->Image() && strlen(fMgr->Image()) > 0) {
3731 fprintf(frc, "# Server image\n");
3732 fprintf(frc, "ProofServ.Image: %s\n", fMgr->Image());
3733 }
3734
3735 // Session tags
3736 if (in->fOld) {
3737 fprintf(frc, "# Session tag\n");
3738 fprintf(frc, "ProofServ.SessionTag: %s\n", in->fSessionTag.c_str());
3739 fprintf(frc, "# Top Session tag\n");
3740 fprintf(frc, "ProofServ.TopSessionTag: %s\n", in->fTopSessionTag.c_str());
3741 }
3742
3743 // Session admin path
3744 fprintf(frc, "# Session admin path\n");
3745 int proofvrs = (p->Client()->ROOT()) ? p->Client()->ROOT()->SrvProtVers() : -1;
3746 if (proofvrs < 0 || proofvrs < 27) {
3747 // Use the first version of the session status file
3748 fprintf(frc, "ProofServ.AdminPath: %s\n", xps->AdminPath());
3749 } else {
3750 if (in->fOld) {
3751 // New version with updated status
3752 fprintf(frc, "ProofServ.AdminPath: %s.status\n", xps->AdminPath());
3753 }
3754 }
3755
3756 // Whether user specific config files are enabled
3757 if (fMgr->NetMgr()->WorkerUsrCfg()) {
3758 fprintf(frc, "# Whether user specific config files are enabled\n");
3759 fprintf(frc, "ProofServ.UseUserCfg: 1\n");
3760 }
3761 // Set Open socket
3762 fprintf(frc, "# Open socket\n");
3763 fprintf(frc, "ProofServ.OpenSock: %s\n", xps->UNIXSockPath());
3764 // Entity
3765 fprintf(frc, "# Entity\n");
3766 if (p->Client()->UI().fGroup.length() > 0)
3767 fprintf(frc, "ProofServ.Entity: %s:%s@%s\n",
3768 p->Client()->User(), p->Client()->UI().fGroup.c_str(), p->Link()->Host());
3769 else
3770 fprintf(frc, "ProofServ.Entity: %s@%s\n", p->Client()->User(), p->Link()->Host());
3771
3772
3773 // Session ID
3774 fprintf(frc, "# Session ID\n");
3775 fprintf(frc, "ProofServ.SessionID: %d\n", psid);
3776
3777 // Client ID
3778 fprintf(frc, "# Client ID\n");
3779 fprintf(frc, "ProofServ.ClientID: %d\n", p->CID());
3780
3781 // Client Protocol
3782 fprintf(frc, "# Client Protocol\n");
3783 fprintf(frc, "ProofServ.ClientVersion: %d\n", p->ProofProtocol());
3784
3785 // Config file
3786 if (in->fCfg.length() > 0) {
3787 if (in->fCfg == "masteronly") {
3788 fprintf(frc, "# MasterOnly option\n");
3789 // Master Only setup
3790 fprintf(frc, "Proof.MasterOnly: 1\n");
3791 } else {
3792 fprintf(frc, "# Config file\n");
3793 // User defined
3794 fprintf(frc, "ProofServ.ProofConfFile: %s\n", in->fCfg.c_str());
3795 }
3796 } else {
3797 fprintf(frc, "# Config file\n");
3798 if (fMgr->IsSuperMst()) {
3799 fprintf(frc, "ProofServ.ProofConfFile: sm:\n");
3800 } else if (xps->IsPLite()) {
3801 fprintf(frc, "ProofServ.ProofConfFile: lite:\n");
3802 fprintf(frc, "# Number of ProofLite workers\n");
3803 fprintf(frc, "ProofLite.Workers: %d\n", xps->PLiteNWrks());
3804 fprintf(frc, "# Users sandbox\n");
3805 fprintf(frc, "ProofLite.Sandbox: %s\n", udir.c_str());
3806 fprintf(frc, "# No subpaths\n");
3807 fprintf(frc, "ProofLite.SubPath: 0\n");
3808 } else if (fProofPlugin.length() > 0) {
3809 fprintf(frc, "ProofServ.ProofConfFile: %s\n", fProofPlugin.c_str());
3810 }
3811 }
3812
3813 // We set this to avoid blocking to much on xrdclient actions; they can be
3814 // oevrwritten with explicit putrc directives
3815 fprintf(frc, "# Default settings for XrdClient\n");
3816 fprintf(frc, "XNet.FirstConnectMaxCnt 3\n");
3817 fprintf(frc, "XNet.ConnectTimeout 5\n");
3818
3819 // This is a workaround for a problem fixed in 5.24/00
3820 int vrscode = (p->Client()->ROOT()) ? p->Client()->ROOT()->VersionCode() : -1;
3821 if (vrscode > 0 && vrscode < XrdROOT::GetVersionCode(5,24,0)) {
3822 fprintf(frc, "# Force remote reading also for local files to avoid a wrong TTreeCache initialization\n");
3823 fprintf(frc, "Path.ForceRemote 1\n");
3824 }
3825
3826 // Additional rootrcs (xpd.putrc directive)
3828 if (fProofServRCs.size() > 0) {
3829 fprintf(frc, "# Additional rootrcs (xpd.putrc directives)\n");
3830 // Hash list of the directives applying to this {user, group, svn, version}
3831 XrdOucHash<XpdEnv> sessrcs;
3832 std::list<XpdEnv>::iterator ircs = fProofServRCs.begin();
3833 for ( ; ircs != fProofServRCs.end(); ++ircs) {
3834 int rcmatch = (*ircs).Matches(p->Client()->User(), p->Client()->Group(),
3835 p->Client()->ROOT()->VersionCode());
3836 if (rcmatch >= 0) {
3837 XpdEnv *rcenv = sessrcs.Find((*ircs).fName.c_str());
3838 if (rcenv) {
3839 int rcmtcex = rcenv->Matches(p->Client()->User(), p->Client()->Group(),
3840 p->Client()->ROOT()->VersionCode());
3841 if (rcmatch > rcmtcex) {
3842 // Replace the entry
3843 rcenv = &(*ircs);
3844 sessrcs.Rep(rcenv->fName.c_str(), rcenv, 0, Hash_keepdata);
3845 }
3846 } else {
3847 // Add an entry
3848 rcenv = &(*ircs);
3849 sessrcs.Add(rcenv->fName.c_str(), rcenv, 0, Hash_keepdata);
3850 }
3851 TRACE(HDBG, "Adding: "<<(*ircs).fEnv);
3852 }
3853 }
3854 sessrcs.Apply(WriteSessRCs, (void *)frc);
3855 }
3856 }
3857 // If applicable, add dataset managers initiators
3858 if (fMgr->DataSetSrcs()->size() > 0) {
3859 fprintf(frc, "# Dataset sources\n");
3860 XrdOucString rc("Proof.DataSetManager: ");
3861 std::list<XrdProofdDSInfo *>::iterator ii;
3862 for (ii = fMgr->DataSetSrcs()->begin(); ii != fMgr->DataSetSrcs()->end(); ++ii) {
3863 if (ii != fMgr->DataSetSrcs()->begin()) rc += ", ";
3864 rc += (*ii)->fType;
3865 rc += " dir:";
3866 rc += (*ii)->fUrl;
3867 rc += " opt:";
3868 rc += (*ii)->fOpts;
3869 rc += " ";
3870 rc += (*ii)->fObscure;
3871 }
3872 fprintf(frc, "%s\n", rc.c_str());
3873 }
3874
3875 // If applicable, add staging requests repository directive initiator
3876 if (strlen(fMgr->StageReqRepo()) > 0) {
3877 fprintf(frc, "# Dataset staging requests repository\n");
3878 fprintf(frc, "Proof.DataSetStagingRequests: %s\n", fMgr->StageReqRepo());
3879 }
3880
3881 // If applicable, add datadir location
3882 if (fMgr->DataDir() && strlen(fMgr->DataDir()) > 0) {
3883 fprintf(frc, "# Data directory\n");
3884 XrdOucString rc;
3885 XPDFORM(rc, "ProofServ.DataDir: %s/%s/%s/%s/%s", fMgr->DataDir(),
3886 p->Client()->Group(), p->Client()->User(), xps->Ordinal(),
3887 in->fSessionTag.c_str());
3888 if (fMgr->DataDirUrlOpts() && strlen(fMgr->DataDirUrlOpts()) > 0) {
3889 fprintf(frc, "%s %s\n", rc.c_str(), fMgr->DataDirUrlOpts());
3890 } else {
3891 fprintf(frc, "%s\n", rc.c_str());
3892 }
3893 }
3894
3895 // Done with this
3896 fclose(frc);
3897
3898 // Done
3899 return 0;
3900}
3901
3902////////////////////////////////////////////////////////////////////////////////
3903/// Cleanup (kill) all 'proofserv' processes which lost control from their
3904/// creator or controller daemon. We rely here on the information in the admin
3905/// path(s) (`<xrd_admin>`/.xproof.`<port>`).
3906/// This is called regurarly by the cron job to avoid having proofservs around.
3907/// Return number of process killed or -1 in case of any error.
3908
3910{
3911 XPDLOC(SMGR, "ProofServMgr::CleanupLostProofServ")
3912
3913 if (!fCheckLost) {
3914 TRACE(REQ, "disabled ...");
3915 return 0;
3916 }
3917
3918 TRACE(REQ, "checking for orphalin proofserv processes ...");
3919 int nk = 0;
3920
3921 // Get the list of existing proofserv processes from the process table
3922 std::map<int,XrdOucString> procs;
3923 if (XrdProofdAux::GetProcesses("proofserv", &procs) <= 0) {
3924 TRACE(DBG, " no proofservs around: nothing to do");
3925 return 0;
3926 }
3927
3928 XrdProofUI ui;
3929 if (XrdProofdAux::GetUserInfo(fMgr->EffectiveUser(), ui) != 0) {
3930 TRACE(DBG, "problems getting info for user " << fMgr->EffectiveUser());
3931 return -1;
3932 }
3933
3934 // Hash list of controlled and xrootd process
3935 XrdOucRash<int, int> controlled, xrdproc;
3936
3937 // Hash list of sessions files loaded
3938 XrdOucHash<XrdOucString> sessionspaths;
3939
3940 // For each process extract the information about the daemon supposed to be in control
3941 int pid, ia, a;
3942 XrdOucString cmd, apath, pidpath, sessiondir, emsg, rest, after;
3943 std::map<int,XrdOucString>::iterator ip;
3944 for (ip = procs.begin(); ip != procs.end(); ++ip) {
3945 pid = ip->first;
3946 cmd = ip->second;
3947 if ((ia = cmd.find("xpdpath:")) != STR_NPOS) {
3948 cmd.tokenize(apath, ia, ' ');
3949 apath.replace("xpdpath:", "");
3950 if (apath.length() <= 0) {
3951 TRACE(ALL, "admin path not found; initial cmd line: "<<cmd);
3952 continue;
3953 }
3954 // Extract daemon PID and check that it is alive
3955 XPDFORM(pidpath, "%s/xrootd.pid", apath.c_str());
3956 TRACE(ALL, "pidpath: "<<pidpath);
3957 int xpid = XrdProofdAux::GetIDFromPath(pidpath.c_str(), emsg);
3958 int *alive = xrdproc.Find(xpid);
3959 if (!alive) {
3960 a = (XrdProofdAux::VerifyProcessByID(xpid, fParentExecs.c_str())) ? 1 : 0;
3961 xrdproc.Add(xpid, a);
3962 } else {
3963 a = *alive;
3964 }
3965 // If the daemon is still there check that the process has its entry in the
3966 // session path(s);
3967 bool ok = 0;
3968 if (a == 1) {
3969 const char *subdir[2] = {"activesessions", "terminatedsessions"};
3970 for (int i = 0; i < 2; i++) {
3971 XPDFORM(sessiondir, "%s/%s", apath.c_str(), subdir[i]);
3972 if (!sessionspaths.Find(sessiondir.c_str())) {
3973 DIR *sdir = opendir(sessiondir.c_str());
3974 if (!sdir) {
3975 XPDFORM(emsg, "cannot open '%s' - errno: %d", apath.c_str(), errno);
3976 TRACE(XERR, emsg.c_str());
3977 continue;
3978 }
3979 struct dirent *sent = 0;
3980 while ((sent = readdir(sdir))) {
3981 if (!strncmp(sent->d_name, ".", 1) || !strncmp(sent->d_name, "..", 2))
3982 continue;
3983 // Get the pid
3984 int ppid = XrdProofdAux::ParsePidPath(sent->d_name, rest, after);
3985 // Add to the list
3986 controlled.Add(ppid, ppid);
3987 }
3988 closedir(sdir);
3989 sessionspaths.Add(sessiondir.c_str(), 0, 0, Hash_data_is_key);
3990 }
3991 ok = (controlled.Find(pid)) ? 1 : ok;
3992 // We are done, if the process is controlled
3993 if (ok) break;
3994 }
3995 }
3996 // If the process is not controlled we have to kill it
3997 if (!ok) {
3998 TRACE(ALL,"process: "<<pid<<" lost its controller: killing");
3999 if (XrdProofdAux::KillProcess(pid, 1, ui, fMgr->ChangeOwn()) == 0)
4000 nk++;
4001 }
4002 }
4003
4004 }
4005
4006 // Done
4007 return nk;
4008}
4009
4010////////////////////////////////////////////////////////////////////////////////
4011/// Cleanup (kill) all 'proofserv' processes from the process table.
4012/// Only the processes associated with 'usr' are killed,
4013/// unless 'all' is TRUE, in which case all 'proofserv' instances are
4014/// terminated (this requires superuser privileges).
4015/// Super users can also terminated all processes fo another user (specified
4016/// via usr).
4017/// Return number of process notified for termination on success, -1 otherwise
4018
4019int XrdProofdProofServMgr::CleanupProofServ(bool all, const char *usr)
4020{
4021 XPDLOC(SMGR, "ProofServMgr::CleanupProofServ")
4022
4023 TRACE(REQ, "all: "<<all<<", usr: " << (usr ? usr : "undef"));
4024 int nk = 0;
4025
4026 // Name
4027 const char *pn = "proofserv";
4028
4029 // Uid
4030 XrdProofUI ui;
4031 int refuid = -1;
4032 if (!all) {
4033 if (!usr) {
4034 TRACE(DBG, "usr must be defined for all = FALSE");
4035 return -1;
4036 }
4037 if (XrdProofdAux::GetUserInfo(usr, ui) != 0) {
4038 TRACE(DBG, "problems getting info for user " << usr);
4039 return -1;
4040 }
4041 refuid = ui.fUid;
4042 }
4043
4044#if defined(linux)
4045 // Loop over the "/proc" dir
4046 DIR *dir = opendir("/proc");
4047 if (!dir) {
4048 XrdOucString emsg("cannot open /proc - errno: ");
4049 emsg += errno;
4050 TRACE(DBG, emsg.c_str());
4051 return -1;
4052 }
4053
4054 struct dirent *ent = 0;
4055 while ((ent = readdir(dir))) {
4056 if (!strncmp(ent->d_name, ".", 1) || !strncmp(ent->d_name, "..", 2)) continue;
4057 if (DIGIT(ent->d_name[0])) {
4058 XrdOucString fn("/proc/", 256);
4059 fn += ent->d_name;
4060 fn += "/status";
4061 // Open file
4062 FILE *ffn = fopen(fn.c_str(), "r");
4063 if (!ffn) {
4064 XrdOucString emsg("cannot open file ");
4065 emsg += fn; emsg += " - errno: "; emsg += errno;
4066 TRACE(HDBG, emsg);
4067 continue;
4068 }
4069 // Read info
4070 bool xname = 1, xpid = 1, xppid = 1;
4071 bool xuid = (all) ? 0 : 1;
4072 int pid = -1;
4073 int ppid = -1;
4074 char line[2048] = { 0 };
4075 while (fgets(line, sizeof(line), ffn) &&
4076 (xname || xpid || xppid || xuid)) {
4077 // Check name
4078 if (xname && strstr(line, "Name:")) {
4079 if (!strstr(line, pn))
4080 break;
4081 xname = 0;
4082 }
4083 if (xpid && strstr(line, "Pid:")) {
4084 pid = (int) XrdProofdAux::GetLong(&line[strlen("Pid:")]);
4085 xpid = 0;
4086 }
4087 if (xppid && strstr(line, "PPid:")) {
4088 ppid = (int) XrdProofdAux::GetLong(&line[strlen("PPid:")]);
4089 // Parent process must be us or be dead
4090 if (ppid != getpid() && XrdProofdAux::VerifyProcessByID(ppid, fParentExecs.c_str()))
4091 // Process created by another running xrootd
4092 break;
4093 xppid = 0;
4094 }
4095 if (xuid && strstr(line, "Uid:")) {
4096 int uid = (int) XrdProofdAux::GetLong(&line[strlen("Uid:")]);
4097 if (refuid == uid)
4098 xuid = 0;
4099 }
4100 }
4101 // Close the file
4102 fclose(ffn);
4103 // If this is a good candidate, kill it
4104 if (!xname && !xpid && !xppid && !xuid) {
4105
4106 bool muok = 1;
4107 if (fMgr->MultiUser() && !all) {
4108 // We need to check the user name: we may be the owner of somebody
4109 // else process; if not session is attached, we kill it
4110 muok = 0;
4112 if (!srv || (srv && !strcmp(usr, srv->Client())))
4113 muok = 1;
4114 }
4115 if (muok)
4116 if (XrdProofdAux::KillProcess(pid, 1, ui, fMgr->ChangeOwn()) == 0)
4117 nk++;
4118 }
4119 }
4120 }
4121 // Close the directory
4122 closedir(dir);
4123
4124#elif defined(__sun)
4125
4126 // Loop over the "/proc" dir
4127 DIR *dir = opendir("/proc");
4128 if (!dir) {
4129 XrdOucString emsg("cannot open /proc - errno: ");
4130 emsg += errno;
4131 TRACE(DBG, emsg);
4132 return -1;
4133 }
4134
4135 struct dirent *ent = 0;
4136 while ((ent = readdir(dir))) {
4137 if (!strncmp(ent->d_name, ".", 1) || !strncmp(ent->d_name, "..", 2)) continue;
4138 if (DIGIT(ent->d_name[0])) {
4139 XrdOucString fn("/proc/", 256);
4140 fn += ent->d_name;
4141 fn += "/psinfo";
4142 // Open file
4143 int ffd = open(fn.c_str(), O_RDONLY);
4144 if (ffd <= 0) {
4145 XrdOucString emsg("cannot open file ");
4146 emsg += fn; emsg += " - errno: "; emsg += errno;
4147 TRACE(HDBG, emsg);
4148 continue;
4149 }
4150 // Read info
4151 bool xname = 1;
4152 bool xuid = (all) ? 0 : 1;
4153 bool xppid = 1;
4154 // Get the information
4155 psinfo_t psi;
4156 if (read(ffd, &psi, sizeof(psinfo_t)) != sizeof(psinfo_t)) {
4157 XrdOucString emsg("cannot read ");
4158 emsg += fn; emsg += ": errno: "; emsg += errno;
4159 TRACE(XERR, emsg);
4160 close(ffd);
4161 continue;
4162 }
4163 // Close the file
4164 close(ffd);
4165
4166 // Check name
4167 if (xname) {
4168 if (!strstr(psi.pr_fname, pn))
4169 continue;
4170 xname = 0;
4171 }
4172 // Check uid, if required
4173 if (xuid) {
4174 if (refuid == psi.pr_uid)
4175 xuid = 0;
4176 }
4177 // Parent process must be us or be dead
4178 int ppid = psi.pr_ppid;
4179 if (ppid != getpid() && XrdProofdAux::VerifyProcessByID(ppid, fParentExecs.c_str())) {
4180 // Process created by another running xrootd
4181 continue;
4182 xppid = 0;
4183 }
4184
4185 // If this is a good candidate, kill it
4186 if (!xname && !xppid && !xuid) {
4187 bool muok = 1;
4188 if (fMgr->MultiUser() && !all) {
4189 // We need to check the user name: we may be the owner of somebody
4190 // else process; if no session is attached , we kill it
4191 muok = 0;
4192 XrdProofdProofServ *srv = GetActiveSession(psi.pr_pid);
4193 if (!srv || (srv && !strcmp(usr, srv->Client())))
4194 muok = 1;
4195 }
4196 if (muok)
4197 if (XrdProofdAux::KillProcess(psi.pr_pid, 1, ui, fMgr->ChangeOwn()) == 0)
4198 nk++;
4199 }
4200 }
4201 }
4202 // Close the directory
4203 closedir(dir);
4204
4205#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
4206
4207 // Get the proclist
4208 kinfo_proc *pl = 0;
4209 int np;
4210 int ern = 0;
4211 if ((ern = XrdProofdAux::GetMacProcList(&pl, np)) != 0) {
4212 XrdOucString emsg("cannot get the process list: errno: ");
4213 emsg += ern;
4214 TRACE(XERR, emsg);
4215 return -1;
4216 }
4217
4218 // Loop over the list
4219 int ii = np;
4220 while (ii--) {
4221 if (strstr(pl[ii].kp_proc.p_comm, pn)) {
4222 if (all || (int)(pl[ii].kp_eproc.e_ucred.cr_uid) == refuid) {
4223 // Parent process must be us or be dead
4224 int ppid = pl[ii].kp_eproc.e_ppid;
4225 bool xppid = 0;
4226 if (ppid != getpid()) {
4227 int jj = np;
4228 while (jj--) {
4229 if (strstr(pl[jj].kp_proc.p_comm, "xrootd") &&
4230 pl[jj].kp_proc.p_pid == ppid) {
4231 xppid = 1;
4232 break;
4233 }
4234 }
4235 }
4236 if (!xppid) {
4237 bool muok = 1;
4238 if (fMgr->MultiUser() && !all) {
4239 // We need to check the user name: we may be the owner of somebody
4240 // else process; if no session is attached, we kill it
4241 muok = 0;
4242 XrdProofdProofServ *srv = GetActiveSession(pl[np].kp_proc.p_pid);
4243 if (!srv || (srv && !strcmp(usr, srv->Client())))
4244 muok = 1;
4245 }
4246 if (muok)
4247 // Good candidate to be shot
4248 if (XrdProofdAux::KillProcess(pl[np].kp_proc.p_pid, 1, ui, fMgr->ChangeOwn()))
4249 nk++;
4250 }
4251 }
4252 }
4253 }
4254 // Cleanup
4255 free(pl);
4256#else
4257 // For the remaining cases we use 'ps' via popen to localize the processes
4258
4259 // Build command
4260 XrdOucString cmd = "ps ";
4261 bool busr = 0;
4262#if 0
4263 // Left over of some previous implementation; but here fSuperUser is not defined: to be checked
4264 const char *cusr = (usr && strlen(usr) && fSuperUser) ? usr : fPClient->ID();
4265#else
4266 const char *cusr = (usr && strlen(usr)) ? usr : 0;
4267#endif
4268 if (all) {
4269 cmd += "ax";
4270 } else {
4271 if (cusr) {
4272 cmd += "-U ";
4273 cmd += cusr;
4274 cmd += " -u ";
4275 cmd += cusr;
4276 }
4277 cmd += " -f";
4278 busr = 1;
4279 }
4280 cmd += " | grep proofserv 2>/dev/null";
4281
4282 // Our parent ID as a string
4283 char cpid[10];
4284 snprintf(cpid, 10, "%d", getpid());
4285
4286 // Run it ...
4287 XrdOucString pids = ":";
4288 FILE *fp = popen(cmd.c_str(), "r");
4289 if (fp != 0) {
4290 char line[2048] = { 0 };
4291 while (fgets(line, sizeof(line), fp)) {
4292 // Parse line: make sure that we are the parent
4293 char *px = strstr(line, "xpd");
4294 if (!px)
4295 // Not xpd: old proofd ?
4296 continue;
4297 char *pi = strstr(px+3, cpid);
4298 if (!pi) {
4299 // Not started by us: check if the parent is still running
4300 pi = px + 3;
4301 int ppid = (int) XrdProofdAux::GetLong(pi);
4302 TRACE(HDBG, "found alternative parent ID: "<< ppid);
4303 // If still running then skip
4305 continue;
4306 }
4307 // Get pid now
4308 int from = 0;
4309 if (busr)
4310 from += strlen(cusr);
4311 int pid = (int) XrdProofdAux::GetLong(&line[from]);
4312 bool muok = 1;
4313 if (fMgr->MultiUser() && !all) {
4314 // We need to check the user name: we may be the owner of somebody
4315 // else process; if no session is attached, we kill it
4316 muok = 0;
4318 if (!srv || (srv && !strcmp(usr, srv->Client())))
4319 muok = 1;
4320 }
4321 if (muok)
4322 // Kill it
4323 if (XrdProofdAux::KillProcess(pid, 1, ui, fMgr->ChangeOwn()) == 0)
4324 nk++;
4325 }
4326 pclose(fp);
4327 } else {
4328 // Error executing the command
4329 return -1;
4330 }
4331#endif
4332
4333 // Done
4334 return nk;
4335}
4336
4337////////////////////////////////////////////////////////////////////////////////
4338/// Set user ownerships on some critical files or directories.
4339/// Return 0 on success, -1 if enything goes wrong.
4340
4342 const char *ord, const char *stag)
4343{
4344 XPDLOC(SMGR, "ProofServMgr::SetUserOwnerships")
4345
4346 TRACE(REQ, "enter");
4347
4348 // If applicable, make sure that the private dataset dir for this user exists
4349 // and has the right permissions
4350 if (fMgr->DataSetSrcs()->size() > 0) {
4351 XrdProofUI ui;
4353 std::list<XrdProofdDSInfo *>::iterator ii;
4354 for (ii = fMgr->DataSetSrcs()->begin(); ii != fMgr->DataSetSrcs()->end(); ++ii) {
4355 TRACE(ALL, "Checking dataset source: url:"<<(*ii)->fUrl<<", local:"
4356 <<(*ii)->fLocal<<", rw:"<<(*ii)->fRW);
4357 if ((*ii)->fLocal && (*ii)->fRW) {
4358 XrdOucString d;
4359 XPDFORM(d, "%s/%s", ((*ii)->fUrl).c_str(), p->Client()->UI().fGroup.c_str());
4360 if (XrdProofdAux::AssertDir(d.c_str(), ui, fMgr->ChangeOwn()) == 0) {
4361 if (XrdProofdAux::ChangeMod(d.c_str(), 0777) == 0) {
4362 XPDFORM(d, "%s/%s/%s", ((*ii)->fUrl).c_str(), p->Client()->UI().fGroup.c_str(),
4363 p->Client()->UI().fUser.c_str());
4364 if (XrdProofdAux::AssertDir(d.c_str(), p->Client()->UI(), fMgr->ChangeOwn()) == 0) {
4365 if (XrdProofdAux::ChangeMod(d.c_str(), 0755) != 0) {
4366 TRACE(XERR, "problems setting permissions 0755 on: "<<d);
4367 }
4368 } else {
4369 TRACE(XERR, "problems asserting: "<<d);
4370 }
4371 } else {
4372 TRACE(XERR, "problems setting permissions 0777 on: "<<d);
4373 }
4374 } else {
4375 TRACE(XERR, "problems asserting: "<<d);
4376 }
4377 }
4378 }
4379 }
4380
4381 // If applicable, make sure that the private data dir for this user exists
4382 // and has the right permissions
4383 if (fMgr->DataDir() && strlen(fMgr->DataDir()) > 0 &&
4384 fMgr->DataDirOpts() && strlen(fMgr->DataDirOpts()) > 0 && ord && stag) {
4385 XrdProofUI ui;
4387 XrdOucString dgr, dus[3];
4388 XPDFORM(dgr, "%s/%s", fMgr->DataDir(), p->Client()->UI().fGroup.c_str());
4389 if (XrdProofdAux::AssertDir(dgr.c_str(), ui, fMgr->ChangeOwn()) == 0) {
4390 if (XrdProofdAux::ChangeMod(dgr.c_str(), 0777) == 0) {
4391 unsigned int mode = 0755;
4392 if (strchr(fMgr->DataDirOpts(), 'g')) mode = 0775;
4393 if (strchr(fMgr->DataDirOpts(), 'a') || strchr(fMgr->DataDirOpts(), 'o')) mode = 0777;
4394 XPDFORM(dus[0], "%s/%s", dgr.c_str(), p->Client()->UI().fUser.c_str());
4395 XPDFORM(dus[1], "%s/%s", dus[0].c_str(), ord);
4396 XPDFORM(dus[2], "%s/%s", dus[1].c_str(), stag);
4397 for (int i = 0; i < 3; i++) {
4398 if (XrdProofdAux::AssertDir(dus[i].c_str(), p->Client()->UI(), fMgr->ChangeOwn()) == 0) {
4399 if (XrdProofdAux::ChangeMod(dus[i].c_str(), mode) != 0) {
4400 std::ios_base::fmtflags oflags = std::cerr.flags();
4401 TRACE(XERR, "problems setting permissions "<< oct << mode<<" on: "<<dus[i]);
4402 std::cerr.flags(oflags);
4403 }
4404 } else {
4405 TRACE(XERR, "problems asserting: "<<dus[i]);
4406 break;
4407 }
4408 }
4409 } else {
4410 TRACE(XERR, "problems setting permissions 0777 on: "<<dgr);
4411 }
4412 } else {
4413 TRACE(XERR, "problems asserting: "<<dgr);
4414 }
4415 }
4416
4417 if (fMgr->ChangeOwn()) {
4418 // Change ownership of '.creds'
4419 XrdOucString creds(p->Client()->Sandbox()->Dir());
4420 creds += "/.creds";
4421 if (XrdProofdAux::ChangeOwn(creds.c_str(), p->Client()->UI()) != 0) {
4422 TRACE(XERR, "can't change ownership of "<<creds);
4423 return -1;
4424 }
4425 }
4426
4427 // We are done
4428 TRACE(REQ, "done");
4429 return 0;
4430}
4431
4432////////////////////////////////////////////////////////////////////////////////
4433/// Set user environment: set effective user and group ID of the process
4434/// to the ones of the owner of this protocol instnace and change working
4435/// dir to the sandbox.
4436/// Return 0 on success, -1 if enything goes wrong.
4437
4439{
4440 XPDLOC(SMGR, "ProofServMgr::SetUserEnvironment")
4441
4442 TRACE(REQ, "enter");
4443
4444 if (XrdProofdAux::ChangeToDir(p->Client()->Sandbox()->Dir(),
4445 p->Client()->UI(), fMgr->ChangeOwn()) != 0) {
4446 TRACE(XERR, "couldn't change directory to "<< p->Client()->Sandbox()->Dir());
4447 return -1;
4448 }
4449
4450 size_t len = 0;
4451 // set HOME env
4452 len = 8 + strlen(p->Client()->Sandbox()->Dir());
4453 char *h = new char[len];
4454 snprintf(h, len, "HOME=%s", p->Client()->Sandbox()->Dir());
4455 putenv(h);
4456 TRACE(DBG, "set "<<h);
4457
4458 // set USER env
4459 len = 8 + strlen(p->Client()->User());
4460 char *u = new char[len];
4461 snprintf(u, len, "USER=%s", p->Client()->User());
4462 putenv(u);
4463 TRACE(DBG, "set "<<u);
4464
4465 // Set access control list from /etc/initgroup
4466 // (super-user privileges required)
4467 TRACE(DBG, "setting ACLs");
4468 if (fMgr->ChangeOwn() && (int) geteuid() != p->Client()->UI().fUid) {
4469
4470 XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
4471 if (XpdBadPGuard(pGuard, p->Client()->UI().fUid)) {
4472 TRACE(XERR, "could not get privileges");
4473 return -1;
4474 }
4475
4476 initgroups(p->Client()->UI().fUser.c_str(), p->Client()->UI().fGid);
4477 }
4478
4479 if (fMgr->ChangeOwn()) {
4480 // acquire permanently target user privileges
4481 TRACE(DBG, "acquiring target user identity: "<<(uid_t)p->Client()->UI().fUid<<
4482 ", "<<(gid_t)p->Client()->UI().fGid);
4483 if (XrdSysPriv::ChangePerm((uid_t)p->Client()->UI().fUid,
4484 (gid_t)p->Client()->UI().fGid) != 0) {
4485 TRACE(XERR, "can't acquire "<< p->Client()->UI().fUser <<" identity");
4486 return -1;
4487 }
4488 }
4489
4490 // We are done
4491 TRACE(REQ, "done");
4492 return 0;
4493}
4494
4495////////////////////////////////////////////////////////////////////////////////
4496/// Return active session with process ID pid, if any.
4497
4499{
4500 XrdOucString key; key += pid;
4501 return fSessions.Find(key.c_str());
4502}
4503
4504////////////////////////////////////////////////////////////////////////////////
4505/// Run thorugh entries to broadcast the relevant priority
4506
4507static int BroadcastPriority(const char *, XrdProofdProofServ *ps, void *s)
4508{
4509 XPDLOC(SMGR, "BroadcastPriority")
4510
4512
4513 int nb = *(bp->fNBroadcast);
4514
4515 XrdOucString emsg;
4516 if (ps) {
4517 if (ps->IsValid() && (ps->Status() == kXPD_running) &&
4518 !(ps->SrvType() == kXPD_Master)) {
4519 XrdProofGroup *g = (ps->Group() && bp->fGroupMgr)
4520 ? bp->fGroupMgr->GetGroup(ps->Group()) : 0;
4521 TRACE(DBG, "group: "<< g<<", client: "<<ps->Client());
4522 if (g && g->Active() > 0) {
4523 TRACE(DBG, "priority: "<< g->Priority()<<" active: "<<g->Active());
4524 int prio = (int) (g->Priority() * 100);
4525 ps->BroadcastPriority(prio);
4526 nb++;
4527 }
4528 }
4529 // Go to next
4530 return 0;
4531 } else {
4532 emsg = "input entry undefined";
4533 }
4534
4535 // Some problem
4536 TRACE(XERR,"protocol error: "<<emsg);
4537 return 1;
4538}
4539
4540////////////////////////////////////////////////////////////////////////////////
4541/// Broadcast cluster info to the active sessions
4542
4544{
4545 XPDLOC(SMGR, "ProofServMgr::BroadcastClusterInfo")
4546
4547 TRACE(REQ, "enter");
4548
4549 int tot = 0, act = 0;
4550 std::list<XrdProofdProofServ *>::iterator si = fActiveSessions.begin();
4551 while (si != fActiveSessions.end()) {
4552 if ((*si)->SrvType() != kXPD_Worker) {
4553 tot++;
4554 if ((*si)->Status() == kXPD_running) act++;
4555 }
4556 ++si;
4557 }
4558 if (tot > 0) {
4559 XPDPRT("tot: "<<tot<<", act: "<<act);
4560 // Now propagate to master or sub-masters
4561 si = fActiveSessions.begin();
4562 while (si != fActiveSessions.end()) {
4563 if ((*si)->Status() == kXPD_running &&
4564 (*si)->SrvType() != kXPD_Worker) (*si)->SendClusterInfo(tot, act);
4565 ++si;
4566 }
4567 } else {
4568 TRACE(DBG, "No master or submaster controlled by this manager");
4569 }
4570}
4571
4572////////////////////////////////////////////////////////////////////////////////
4573/// Broadcast priorities to the active sessions.
4574/// Returns the number of sessions contacted.
4575
4577{
4578 XPDLOC(SMGR, "ProofServMgr::BroadcastPriorities")
4579
4580 TRACE(REQ, "enter");
4581
4582 int nb = 0;
4583 XpdBroadcastPriority_t bp = { (fMgr ? fMgr->GroupsMgr() : 0), &nb };
4584 fSessions.Apply(BroadcastPriority, (void *)&bp);
4585 // Done
4586 return nb;
4587}
4588
4589////////////////////////////////////////////////////////////////////////////////
4590/// Return true if in reconnection state, i.e. during
4591/// that period during which clients are expected to reconnect.
4592/// Return false if the session is fully effective
4593
4595{
4596 int rect = -1;
4597 if (fReconnectTime >= 0) {
4598 rect = time(0) - fReconnectTime;
4599 if (rect < fReconnectTimeOut)
4600 return true;
4601 }
4602 // Not reconnecting
4603 return false;
4604}
4605
4606////////////////////////////////////////////////////////////////////////////////
4607/// Change reconnecting status
4608///
4609
4611{
4613
4614 if (on) {
4615 fReconnectTime = time(0);
4616 } else {
4617 fReconnectTime = -1;
4618 }
4619}
4620
4621////////////////////////////////////////////////////////////////////////////////
4622/// Check destroyed status
4623///
4624
4626{
4628
4629 bool alive = true;
4630 int now = time(0);
4631 std::map<XrdProofdProtocol*,int>::iterator iter = fDestroyTimes.begin();
4632 while (iter != fDestroyTimes.end()) {
4633 int rect = now - iter->second;
4634 if (rect < fReconnectTimeOut) {
4635 if (p == iter->first) alive = false;
4636 ++iter;
4637 } else {
4638 iter = fDestroyTimes.erase(iter);
4639 }
4640 }
4641
4642 return alive;
4643}
4644
4645////////////////////////////////////////////////////////////////////////////////
4646/// Run through entries to reset the disconnecting client slots
4647
4648static int FreeClientID(const char *, XrdProofdProofServ *ps, void *s)
4649{
4650 XPDLOC(SMGR, "FreeClientID")
4651
4652 int pid = *((int *)s);
4653
4654 if (ps) {
4655 ps->FreeClientID(pid);
4656 // Go to next
4657 return 0;
4658 }
4659
4660 // Some problem
4661 TRACE(XERR, "protocol error: undefined session!");
4662 return 1;
4663}
4664
4665////////////////////////////////////////////////////////////////////////////////
4666/// Change reconnecting status
4667///
4668
4670{
4672
4673 fSessions.Apply(FreeClientID, (void *)&pid);
4674}
4675
4676////////////////////////////////////////////////////////////////////////////////
4677/// Run thorugh entries to count top-masters
4678
4679static int CountTopMasters(const char *, XrdProofdProofServ *ps, void *s)
4680{
4681 XPDLOC(SMGR, "CountTopMasters")
4682
4683 int *ntm = (int *)s;
4684
4685 XrdOucString emsg;
4686 if (ps) {
4687 if (ps->SrvType() == kXPD_TopMaster) (*ntm)++;
4688 // Go to next
4689 return 0;
4690 } else {
4691 emsg = "input entry undefined";
4692 }
4693
4694 // Some problem
4695 TRACE(XERR,"protocol error: "<<emsg);
4696 return 1;
4697}
4698
4699////////////////////////////////////////////////////////////////////////////////
4700/// Return the number of current sessions (top masters)
4701
4703{
4704 XPDLOC(SMGR, "ProofServMgr::CurrentSessions")
4705
4706 TRACE(REQ, "enter");
4707
4709 if (recalculate) {
4710 fCurrentSessions = 0;
4712 }
4713
4714 // Done
4715 return fCurrentSessions;
4716}
4717
4718////////////////////////////////////////////////////////////////////////////////
4719/// Resolve some keywords in 's'
4720/// `<logfileroot>`, `<user>`, `<rootsys>`
4721
4723{
4724 if (!in) return;
4725
4726 bool isWorker = 0;
4727 if (in->fPS->SrvType() == kXPD_Worker) isWorker = 1;
4728
4729 // Log file
4730 if (!isWorker && s.find("<logfilemst>") != STR_NPOS) {
4731 XrdOucString lfr(in->fLogFile);
4732 if (lfr.endswith(".log")) lfr.erase(lfr.rfind(".log"));
4733 s.replace("<logfilemst>", lfr);
4734 } else if (isWorker && s.find("<logfilewrk>") != STR_NPOS) {
4735 XrdOucString lfr(in->fLogFile);
4736 if (lfr.endswith(".log")) lfr.erase(lfr.rfind(".log"));
4737 s.replace("<logfilewrk>", lfr);
4738 }
4739
4740 // user
4741 if (getenv("USER") && s.find("<user>") != STR_NPOS) {
4742 XrdOucString usr(getenv("USER"));
4743 s.replace("<user>", usr);
4744 }
4745
4746 // rootsys
4747 if (getenv("ROOTSYS") && s.find("<rootsys>") != STR_NPOS) {
4748 XrdOucString rootsys(getenv("ROOTSYS"));
4749 s.replace("<rootsys>", rootsys);
4750 }
4751}
4752
4753//
4754// Auxilliary class to handle session pid files
4755//
4756
4757////////////////////////////////////////////////////////////////////////////////
4758/// Construct from 'c' and 's'
4759
4761{
4762 fLastAccess = 0;
4763
4764 // Fill from the client instance
4765 fUser = c ? c->User() : "";
4766 fGroup = c ? c->Group() : "";
4767
4768 // Fill from the server instance
4769 fPid = s ? s->SrvPID() : -1;
4770 fID = s ? s->ID() : -1;
4771 fSrvType = s ? s->SrvType() : -1;
4772 fPLiteNWrks = s ? s->PLiteNWrks() : -1;
4773 fStatus = s ? s->Status() : kXPD_unknown;
4774 fOrdinal = s ? s->Ordinal() : "";
4775 fTag = s ? s->Tag() : "";
4776 fAlias = s ? s->Alias() : "";
4777 fLogFile = s ? s->Fileout() : "";
4778 fROOTTag = (s && s->ROOT())? s->ROOT()->Tag() : "";
4779 fSrvProtVers = (s && s->ROOT()) ? s->ROOT()->SrvProtVers() : -1;
4780 fUserEnvs = s ? s->UserEnvs() : "";
4781 fAdminPath = s ? s->AdminPath() : "";
4782 fUnixPath = s ? s->UNIXSockPath() : "";
4783}
4784
4785////////////////////////////////////////////////////////////////////////////////
4786/// Fill 's' fields using the stored info
4787
4789{
4790 XPDLOC(SMGR, "SessionInfo::FillProofServ")
4791
4792 s.SetClient(fUser.c_str());
4793 s.SetGroup(fGroup.c_str());
4794 if (fPid > 0)
4795 s.SetSrvPID(fPid);
4796 if (fID >= 0)
4797 s.SetID(fID);
4798 s.SetSrvType(fSrvType);
4799 s.SetPLiteNWrks(fPLiteNWrks);
4800 s.SetStatus(fStatus);
4801 s.SetOrdinal(fOrdinal.c_str());
4802 s.SetTag(fTag.c_str());
4803 s.SetAlias(fAlias.c_str());
4804 s.SetFileout(fLogFile.c_str());
4805 if (rmgr) {
4806 if (rmgr->GetVersion(fROOTTag.c_str())) {
4807 s.SetROOT(rmgr->GetVersion(fROOTTag.c_str()));
4808 } else {
4809 TRACE(ALL, "ROOT version '"<< fROOTTag <<
4810 "' not availabe anymore: setting the default");
4811 s.SetROOT(rmgr->DefaultVersion());
4812 }
4813 }
4814 s.SetUserEnvs(fUserEnvs.c_str());
4815 s.SetAdminPath(fAdminPath.c_str(), 0, 0);
4816 s.SetUNIXSockPath(fUnixPath.c_str());
4817}
4818
4819////////////////////////////////////////////////////////////////////////////////
4820/// Save content to 'file'
4821
4823{
4824 XPDLOC(SMGR, "SessionInfo::SaveToFile")
4825
4826 // Check inputs
4827 if (!file || strlen(file) <= 0) {
4828 TRACE(XERR,"invalid input: "<< (file ? file : "<nul>"));
4829 return -1;
4830 }
4831 TRACE(HDBG,"session saved to file: "<<file);
4832
4833 // Create the file
4834 FILE *fpid = fopen(file, "w");
4835 if (fpid) {
4836 fprintf(fpid, "%s %s\n", fUser.c_str(), fGroup.c_str());
4837 fprintf(fpid, "%s\n", fUnixPath.c_str());
4838 fprintf(fpid, "%d %d %d %d\n", fPid, fID, fSrvType, fPLiteNWrks);
4839 fprintf(fpid, "%s %s %s\n", fOrdinal.c_str(), fTag.c_str(), fAlias.c_str());
4840 fprintf(fpid, "%s\n", fLogFile.c_str());
4841 fprintf(fpid, "%d %s\n", fSrvProtVers, fROOTTag.c_str());
4842 if (fUserEnvs.length() > 0)
4843 fprintf(fpid, "\n%s", fUserEnvs.c_str());
4844 fclose(fpid);
4845
4846 // Make it writable by anyone (to allow the corresponding proofserv
4847 // to touch it for the asynchronous ping request)
4848 if (chmod(file, 0666) != 0) {
4849 TRACE(XERR, "could not change mode to 0666 on file "<<
4850 file<<"; error: "<<errno);
4851 }
4852
4853 return 0;
4854 }
4855
4856 TRACE(XERR,"session pid file cannot be (re-)created: "<<
4857 file<<"; error: "<<errno);
4858 return -1;
4859}
4860
4861////////////////////////////////////////////////////////////////////////////////
4862/// Reset the content
4863
4865{
4866 fLastAccess = 0;
4867 fUser = "";
4868 fGroup = "";
4869 fAdminPath = "";
4870 fUnixPath = "";
4871 fPid = -1;
4873 fID = -1;
4874 fSrvType = -1;
4875 fPLiteNWrks = -1;
4876 fOrdinal = "";
4877 fTag = "";
4878 fAlias = "";
4879 fLogFile = "";
4880 fROOTTag = "";
4881 fSrvProtVers = -1;
4882 fUserEnvs = "";
4883}
4884
4885////////////////////////////////////////////////////////////////////////////////
4886/// Read content from 'file'
4887
4889{
4890 XPDLOC(SMGR, "SessionInfo::ReadFromFile")
4891
4892 Reset();
4893
4894 // Check inputs
4895 if (!file || strlen(file) <= 0) {
4896 TRACE(XERR,"invalid input: "<<(file ? file : "<nul>"));
4897 return -1;
4898 }
4899
4900 // Open the session file
4901 FILE *fpid = fopen(file,"r");
4902 if (fpid) {
4903 char line[4096];
4904 XrdOucString sline, t;
4905 int from = 0;
4906 if (fgets(line, sizeof(line), fpid)) {
4907 if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
4908 sline = line;
4909 if ((from = sline.tokenize(fUser, from, ' ')) == -1)
4910 TRACE(XERR,"warning: fUser: corrupted line? "<<line<<" (file: "<<file<<")");
4911 if ((from = sline.tokenize(fGroup, from, ' ')) == -1)
4912 TRACE(XERR,"warning: fGroup: corrupted line? "<<line<<" (file: "<<file<<")");
4913 }
4914 if (fgets(line, sizeof(line), fpid)) {
4915 if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
4916 fUnixPath = line;
4917 }
4918 if (fgets(line, sizeof(line), fpid)) {
4919 if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
4920 sline = line;
4921 from = 0;
4922 if ((from = sline.tokenize(t, from, ' ')) == -1)
4923 TRACE(XERR,"warning: fPid: corrupted line? "<<line<<" (file: "<<file<<")");
4924 fPid = t.atoi();
4925 if ((from = sline.tokenize(t, from, ' ')) == -1)
4926 TRACE(XERR,"warning: fID: corrupted line? "<<line<<" (file: "<<file<<")");
4927 fID = t.atoi();
4928 if ((from = sline.tokenize(t, from, ' ')) == -1)
4929 TRACE(XERR,"warning: fSrvType: corrupted line? "<<line<<" (file: "<<file<<")");
4930 fSrvType = t.atoi();
4931 }
4932 if (fgets(line, sizeof(line), fpid)) {
4933 if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
4934 sline = line;
4935 from = 0;
4936 if ((from = sline.tokenize(fOrdinal, from, ' ')) == -1)
4937 TRACE(XERR,"warning: fOrdinal: corrupted line? "<<line<<" (file: "<<file<<")");
4938 if ((from = sline.tokenize(fTag, from, ' ')) == -1)
4939 TRACE(XERR,"warning: fTag: corrupted line? "<<line<<" (file: "<<file<<")");
4940 if ((from = sline.tokenize(fAlias, from, ' ')) == -1)
4941 TRACE(HDBG,"fAlias undefined "<<line);
4942 }
4943 if (fgets(line, sizeof(line), fpid)) {
4944 if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
4945 fLogFile = line;
4946 }
4947 if (fgets(line, sizeof(line), fpid)) {
4948 if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0';
4949 sline = line;
4950 from = 0;
4951 if ((from = sline.tokenize(t, from, ' ')) == -1)
4952 TRACE(XERR,"warning: fSrvProtVers: corrupted line? "<<line<<" (file: "<<file<<")");
4953 fSrvProtVers = t.atoi();
4954 if ((from = sline.tokenize(fROOTTag, from, ' ')) == -1)
4955 TRACE(XERR,"warning: fROOTTag: corrupted line? "<<line<<" (file: "<<file<<")");
4956 }
4957 // All the remaining into fUserEnvs
4958 fUserEnvs = "";
4959 off_t lnow = lseek(fileno(fpid), (off_t) 0, SEEK_CUR);
4960 off_t ltot = lseek(fileno(fpid), (off_t) 0, SEEK_END);
4961 int left = (int)(ltot - lnow);
4962 int len = -1;
4963 do {
4964 int wanted = (left > 4095) ? 4095 : left;
4965 while ((len = read(fileno(fpid), line, wanted)) < 0 &&
4966 errno == EINTR)
4967 errno = 0;
4968 if (len < 0 || len < wanted) {
4969 break;
4970 } else {
4971 line[len] = '\0';
4972 fUserEnvs += line;
4973 }
4974 // Update counters
4975 left -= len;
4976 } while (len > 0 && left > 0);
4977 // Done
4978 fclose(fpid);
4979 // The file name is the admin path
4980 fAdminPath = file;
4981 // Fill access time
4982 struct stat st;
4983 if (!stat(file, &st))
4984 fLastAccess = st.st_atime;
4985 } else {
4986 TRACE(XERR,"session file cannot be open: "<< file<<"; error: "<<errno);
4987 return -1;
4988 }
4989
4990 // Read the last status now if the session is active
4991 XrdOucString fs(file);
4992 fs += ".status";
4993 fpid = fopen(fs.c_str(),"r");
4994 if (fpid) {
4995 char line[64];
4996 if (fgets(line, sizeof(line), fpid)) {
4997 if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = 0;
4998 fStatus = atoi(line);
4999 }
5000 // Done
5001 fclose(fpid);
5002 } else {
5003 TRACE(DBG,"no session status file for: "<< fs<<"; session was probably terminated");
5004 }
5005
5006 // Done
5007 return 0;
5008}
5009
5010////////////////////////////////////////////////////////////////////////////////
5011/// Check if this env applies to 'usr', 'grp, 'ver'.
5012/// Returns -1 if it does not match, >=0 if it matches. The value is a linear
5013/// combination of matching lengths for user and group, with a weight of 1000 for
5014/// the users one, so that an exact user match will always win.
5015
5016int XpdEnv::Matches(const char *usr, const char *grp, int ver)
5017{
5018 XPDLOC(SMGR, "XpdEnv::Matches")
5019
5020 int nmtc = -1;
5021 // Check the user
5022 if (fUsers.length() > 0) {
5023 XrdOucString u(usr);
5024 if ((nmtc = u.matches(fUsers.c_str())) == 0) return -1;
5025 } else {
5026 nmtc = strlen(usr);
5027 }
5028 nmtc += 1000; // Weigth of user name match
5029 // Check the group
5030 int nmtcg = -1;
5031 if (fGroups.length() > 0) {
5032 XrdOucString g(grp);
5033 if ((nmtcg = g.matches(fGroups.c_str())) == 0) return -1;
5034 } else {
5035 nmtcg = strlen(grp);
5036 }
5037 nmtc += nmtcg;
5038
5039 TRACE(HDBG, fEnv <<", u:"<<usr<<", g:"<<grp<<" --> nmtc: "<<nmtc);
5040
5041 // Check the version code
5042 TRACE(HDBG, fEnv <<", ver:"<<ver);
5043 if (fVerMin > 0 && ver < fVerMin) return -1;
5044 if (fVerMax > 0 && ver > fVerMax) return -1;
5045
5046 // If we are here then it matches
5047 return nmtc;
5048}
5049
5050////////////////////////////////////////////////////////////////////////////////
5051/// Transform version number ver (format patch + 100*minor + 10000*maj, e.g. 52706)
5052/// If 'hex' is true, the components are decoded as hex numbers
5053
5054int XpdEnv::ToVersCode(int ver, bool hex)
5055{
5056 int maj = -1, min = -1, ptc = -1, xv = ver;
5057 if (hex) {
5058 maj = xv / 65536;
5059 xv -= maj * 65536;
5060 min = xv / 256;
5061 ptc = xv - min * 256;
5062 } else {
5063 maj = xv / 10000;
5064 xv -= maj * 10000;
5065 min = xv / 100;
5066 ptc = xv - min * 100;
5067 }
5068 // Get the version code now
5069 int vc = (maj << 16) + (min << 8) + ptc;
5070 return vc;
5071}
5072
5073////////////////////////////////////////////////////////////////////////////////
5074/// Print the content of this env
5075
5076void XpdEnv::Print(const char *what)
5077{
5078 XPDLOC(SMGR, what)
5079
5080 XrdOucString vmi("-1"), vmx("-1");
5081 if (fVerMin > 0) {
5082 int maj = (fVerMin >> 16);
5083 int min = ((fVerMin - maj * 65536) >> 8);
5084 int ptc = fVerMin - maj * 65536 - min * 256;
5085 XPDFORM(vmi, "%d%d%d", maj, min, ptc);
5086 }
5087 if (fVerMax > 0) {
5088 int maj = (fVerMax >> 16);
5089 int min = ((fVerMax - maj * 65536) >> 8);
5090 int ptc = fVerMax - maj * 65536 - min * 256;
5091 XPDFORM(vmx, "%d%d%d", maj, min, ptc);
5092 }
5093 XrdOucString u("allusers"), g("allgroups");
5094 if (fUsers.length() > 0) u = fUsers;
5095 if (fGroups.length() > 0) u = fGroups;
5096
5097 TRACE(ALL, "'"<<fEnv<<"' {"<<u<<"|"<<g<<
5098 "} svn:["<<fSvnMin<<","<<fSvnMax<<"] vers:["<<vmi<<","<<vmx<<"]");
5099}
#define d(i)
Definition: RSha256.hxx:102
#define f(i)
Definition: RSha256.hxx:104
#define c(i)
Definition: RSha256.hxx:101
#define h(i)
Definition: RSha256.hxx:106
#define e(i)
Definition: RSha256.hxx:103
#define TRACE(Flag, Args)
Definition: TGHtml.h:121
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Definition: