00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "XrdProofdPlatform.h"
00022
00023 #include "XrdOuc/XrdOucStream.hh"
00024 #include "XrdSys/XrdSysPriv.hh"
00025
00026 #include "XrdProofdAux.h"
00027 #include "XrdProofdConfig.h"
00028 #include "XrdProofdProtocol.h"
00029
00030
00031 #include "XrdProofdTrace.h"
00032
00033
00034 #ifdef XPD_MAXLEN
00035 #undefine XPD_MAXLEN
00036 #endif
00037 #define XPD_MAXLEN 1024
00038
00039 XrdSysRecMutex XrdProofdAux::fgFormMutex;
00040
00041
00042 const char *XrdProofdAux::AdminMsgType(int type)
00043 {
00044
00045
00046
00047 static const char *msgtypes[] = { "Undef",
00048 "QuerySessions", "SessionTag", "SessionAlias", "GetWorkers", "QueryWorkers",
00049 "CleanupSessions", "QueryLogPaths", "ReadBuffer", "QueryROOTVersions",
00050 "ROOTVersion", "GroupProperties", "SendMsgToUser", "ReleaseWorker",
00051 "Exec", "GetFile", "PutFile", "CpFile"};
00052
00053 if (type < 1000 || type >= kUndef) {
00054 return msgtypes[0];
00055 } else {
00056 int t = type - 999;
00057 return msgtypes[t];
00058 }
00059 }
00060
00061
00062 const char *XrdProofdAux::ProofRequestTypes(int type)
00063 {
00064
00065
00066
00067
00068 static const char *reqtypes[] = { "Undef",
00069 "XP_login", "XP_auth", "XP_create", "XP_destroy", "XP_attach", "XP_detach",
00070 "XP_3107", "XP_3108", "XP_3109", "XP_3110",
00071 "XP_urgent", "XP_sendmsg", "XP_admin", "XP_interrupt", "XP_ping",
00072 "XP_cleanup", "XP_readbuf", "XP_touch", "XP_ctrlc" };
00073
00074 if (type < 3101 || type >= kXP_Undef) {
00075 return reqtypes[0];
00076 } else {
00077 int t = type - 3100;
00078 return reqtypes[t];
00079 }
00080 }
00081
00082
00083 char *XrdProofdAux::Expand(char *p)
00084 {
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 if (!p || strlen(p) <= 0 || p[0] == '/')
00097 return p;
00098
00099 char *po = p;
00100
00101
00102 if (p[0] == '$') {
00103
00104 XrdOucString env(&p[1]);
00105 int isl = env.find('/');
00106 env.erase(isl);
00107 char *p1 = (isl > 0) ? (char *)(p + isl + 2) : 0;
00108 if (getenv(env.c_str())) {
00109 int lenv = strlen(getenv(env.c_str()));
00110 int lp1 = p1 ? strlen(p1) : 0;
00111 po = (char *) malloc(lp1 + lenv + 2);
00112 if (po) {
00113 memcpy(po, getenv(env.c_str()), lenv);
00114 if (p1) {
00115 memcpy(po+lenv+1, p1, lp1);
00116 po[lenv] = '/';
00117 }
00118 po[lp1 + lenv + 1] = 0;
00119 free(p);
00120 } else
00121 po = p;
00122 }
00123 return po;
00124 }
00125
00126
00127 if (p[0] != '~') {
00128 if (getenv("PWD")) {
00129 int lpwd = strlen(getenv("PWD"));
00130 int lp = strlen(p);
00131 po = (char *) malloc(lp + lpwd + 2);
00132 if (po) {
00133 memcpy(po, getenv("PWD"), lpwd);
00134 memcpy(po+lpwd+1, p, lp);
00135 po[lpwd] = '/';
00136 po[lpwd+lp+1] = 0;
00137 free(p);
00138 } else
00139 po = p;
00140 }
00141 return po;
00142 }
00143
00144
00145 if (p[0] == '~') {
00146 char *pu = p+1;
00147 char *pd = strchr(pu,'/');
00148 *pd++ = '\0';
00149
00150 XrdProofUI ui;
00151 int rc = 0;
00152 if (strlen(pu) > 0) {
00153 rc = XrdProofdAux::GetUserInfo(pu, ui);
00154 } else {
00155 rc = XrdProofdAux::GetUserInfo(getuid(), ui);
00156 }
00157 if (rc == 0) {
00158 int ldir = ui.fHomeDir.length();
00159 int lpd = strlen(pd);
00160 po = (char *) malloc(lpd + ldir + 2);
00161 if (po) {
00162 memcpy(po, ui.fHomeDir.c_str(), ldir);
00163 memcpy(po+ldir+1, pd, lpd);
00164 po[ldir] = '/';
00165 po[lpd + ldir + 1] = 0;
00166 free(p);
00167 } else
00168 po = p;
00169 }
00170 return po;
00171 }
00172
00173
00174 return po;
00175 }
00176
00177
00178 void XrdProofdAux::Expand(XrdOucString &p)
00179 {
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 char *po = strdup((char *)p.c_str());
00190 po = Expand(po);
00191 p = po;
00192 SafeFree(po);
00193 }
00194
00195
00196 long int XrdProofdAux::GetLong(char *str)
00197 {
00198
00199
00200
00201 char *p = str;
00202 while ((*p < 48 || *p > 57) && (*p) != '\0')
00203 p++;
00204 if (*p == '\0')
00205 return LONG_MAX;
00206
00207
00208 int j = 0;
00209 while (*(p+j) >= 48 && *(p+j) <= 57)
00210 j++;
00211 *(p+j) = '\0';
00212
00213
00214 return strtol(p, 0, 10);
00215 }
00216
00217
00218 int XrdProofdAux::GetGroupInfo(const char *grp, XrdProofGI &gi)
00219 {
00220
00221
00222
00223
00224 if (!grp || strlen(grp) <= 0)
00225 return -EINVAL;
00226
00227
00228 struct group gr;
00229 struct group *pgr = 0;
00230 char buf[2048];
00231 #if defined(__sun) && !defined(__GNUC__)
00232 pgr = getgrnam_r(grp, &gr, buf, sizeof(buf));
00233 #else
00234 getgrnam_r(grp, &gr, buf, sizeof(buf), &pgr);
00235 #endif
00236 if (pgr) {
00237
00238 gi.fGroup = grp;
00239 gi.fGid = (int) gr.gr_gid;
00240
00241 return 0;
00242 }
00243
00244
00245 if (errno != 0)
00246 return ((int) -errno);
00247 else
00248 return -ENOENT;
00249 }
00250
00251
00252 int XrdProofdAux::GetGroupInfo(int gid, XrdProofGI &gi)
00253 {
00254
00255
00256
00257
00258 if (gid <= 0)
00259 return -EINVAL;
00260
00261
00262 struct group gr;
00263 struct group *pgr = 0;
00264 char buf[2048];
00265 #if defined(__sun) && !defined(__GNUC__)
00266 pgr = getgrgid_r((gid_t)gid, &gr, buf, sizeof(buf));
00267 #else
00268 getgrgid_r((gid_t)gid, &gr, buf, sizeof(buf), &pgr);
00269 #endif
00270 if (pgr) {
00271
00272 gi.fGroup = gr.gr_name;
00273 gi.fGid = gid;
00274
00275 return 0;
00276 }
00277
00278
00279 if (errno != 0)
00280 return ((int) -errno);
00281 else
00282 return -ENOENT;
00283 }
00284
00285
00286 int XrdProofdAux::GetUserInfo(const char *usr, XrdProofUI &ui)
00287 {
00288
00289
00290
00291
00292 if (!usr || strlen(usr) <= 0)
00293 return -EINVAL;
00294
00295
00296 struct passwd pw;
00297 struct passwd *ppw = 0;
00298 char buf[2048];
00299 #if defined(__sun) && !defined(__GNUC__)
00300 ppw = getpwnam_r(usr, &pw, buf, sizeof(buf));
00301 #else
00302 getpwnam_r(usr, &pw, buf, sizeof(buf), &ppw);
00303 #endif
00304 if (ppw) {
00305
00306 ui.fUid = (int) pw.pw_uid;
00307 ui.fGid = (int) pw.pw_gid;
00308 ui.fHomeDir = pw.pw_dir;
00309 ui.fUser = usr;
00310
00311 return 0;
00312 }
00313
00314
00315 if (errno != 0)
00316 return ((int) -errno);
00317 else
00318 return -ENOENT;
00319 }
00320
00321
00322 int XrdProofdAux::GetUserInfo(int uid, XrdProofUI &ui)
00323 {
00324
00325
00326
00327
00328 if (uid < 0)
00329 return -EINVAL;
00330
00331
00332 struct passwd pw;
00333 struct passwd *ppw = 0;
00334 char buf[2048];
00335 #if defined(__sun) && !defined(__GNUC__)
00336 ppw = getpwuid_r((uid_t)uid, &pw, buf, sizeof(buf));
00337 #else
00338 getpwuid_r((uid_t)uid, &pw, buf, sizeof(buf), &ppw);
00339 #endif
00340 if (ppw) {
00341
00342 ui.fUid = uid;
00343 ui.fGid = (int) pw.pw_gid;
00344 ui.fHomeDir = pw.pw_dir;
00345 ui.fUser = pw.pw_name;
00346
00347 return 0;
00348 }
00349
00350
00351 if (errno != 0)
00352 return ((int) -errno);
00353 else
00354 return -ENOENT;
00355 }
00356
00357
00358 int XrdProofdAux::Write(int fd, const void *buf, size_t nb)
00359 {
00360
00361
00362
00363 if (fd < 0)
00364 return -1;
00365
00366 const char *pw = (const char *)buf;
00367 int lw = nb;
00368 int nw = 0, written = 0;
00369 while (lw) {
00370 if ((nw = write(fd, pw + written, lw)) < 0) {
00371 if (errno == EINTR) {
00372 errno = 0;
00373 continue;
00374 } else {
00375 break;
00376 }
00377 }
00378
00379 written += nw;
00380 lw -= nw;
00381 }
00382
00383
00384 return written;
00385 }
00386
00387
00388 int XrdProofdAux::AssertDir(const char *path, XrdProofUI ui, bool changeown)
00389 {
00390
00391
00392
00393
00394 XPDLOC(AUX, "Aux::AssertDir")
00395
00396 TRACE(DBG, path);
00397
00398 if (!path || strlen(path) <= 0)
00399 return -1;
00400
00401 struct stat st;
00402 if (stat(path,&st) != 0) {
00403 if (errno == ENOENT) {
00404
00405 { XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
00406 if (XpdBadPGuard(pGuard, ui.fUid) && changeown) {
00407 TRACE(XERR, "could not get privileges to create dir");
00408 return -1;
00409 }
00410
00411 if (mkdir(path, 0755) != 0) {
00412 TRACE(XERR, "unable to create dir: "<<path<<" (errno: "<<errno<<")");
00413 return -1;
00414 }
00415 }
00416 if (stat(path,&st) != 0) {
00417 TRACE(XERR, "unable to stat dir: "<<path<<" (errno: "<<errno<<")");
00418 return -1;
00419 }
00420 } else {
00421
00422 TRACE(XERR, "unable to stat dir: "<<path<<" (errno: "<<errno<<")");
00423 return -1;
00424 }
00425 }
00426
00427
00428 if (changeown &&
00429 ((int) st.st_uid != ui.fUid || (int) st.st_gid != ui.fGid)) {
00430
00431 XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
00432 if (XpdBadPGuard(pGuard, ui.fUid)) {
00433 TRACE(XERR, "could not get privileges to change ownership");
00434 return -1;
00435 }
00436
00437
00438 if (chown(path, ui.fUid, ui.fGid) == -1) {
00439 TRACE(XERR, "cannot set user ownership on path (errno: "<<errno<<")");
00440 return -1;
00441 }
00442 }
00443
00444
00445 return 0;
00446 }
00447
00448
00449 int XrdProofdAux::ChangeOwn(const char *path, XrdProofUI ui)
00450 {
00451
00452
00453
00454 XPDLOC(AUX, "Aux::ChangeOwn")
00455
00456 TRACE(DBG, path);
00457
00458 if (!path || strlen(path) <= 0)
00459 return -1;
00460
00461 struct stat st;
00462 if (stat(path,&st) != 0) {
00463
00464 TRACE(XERR, "unable to stat path: "<<path<<" (errno: "<<errno<<")");
00465 return -1;
00466 }
00467
00468
00469 if (S_ISDIR(st.st_mode)) {
00470
00471 DIR *dir = opendir(path);
00472 if (!dir) {
00473 TRACE(XERR,"cannot open "<<path<< "- errno: "<< errno);
00474 return -1;
00475 }
00476 XrdOucString proot(path);
00477 if (!proot.endswith('/')) proot += "/";
00478
00479 struct dirent *ent = 0;
00480 while ((ent = readdir(dir))) {
00481 if (ent->d_name[0] == '.' || !strcmp(ent->d_name, "..")) continue;
00482 XrdOucString fn(proot);
00483 fn += ent->d_name;
00484
00485 struct stat xst;
00486 if (stat(fn.c_str(),&xst) == 0) {
00487
00488 if (S_ISDIR(xst.st_mode)) {
00489 if (XrdProofdAux::ChangeOwn(fn.c_str(), ui) != 0) {
00490 TRACE(XERR, "problems changing recursively ownership of: "<<fn);
00491 return -1;
00492 }
00493 } else {
00494
00495 XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
00496 if (XpdBadPGuard(pGuard, ui.fUid)) {
00497 TRACE(XERR, "could not get privileges to change ownership");
00498 return -1;
00499 }
00500
00501 if (chown(fn.c_str(), ui.fUid, ui.fGid) == -1) {
00502 TRACE(XERR, "cannot set user ownership on path (errno: "<<errno<<")");
00503 return -1;
00504 }
00505 }
00506 } else {
00507 TRACE(XERR, "unable to stat dir: "<<fn<<" (errno: "<<errno<<")");
00508 }
00509 }
00510
00511 } else if (((int) st.st_uid != ui.fUid) || ((int) st.st_gid != ui.fGid)) {
00512
00513 XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
00514 if (XpdBadPGuard(pGuard, ui.fUid)) {
00515 TRACE(XERR, "could not get privileges to change ownership");
00516 return -1;
00517 }
00518
00519 if (chown(path, ui.fUid, ui.fGid) == -1) {
00520 TRACE(XERR, "cannot set user ownership on path (errno: "<<errno<<")");
00521 return -1;
00522 }
00523 }
00524
00525
00526 return 0;
00527 }
00528
00529
00530 int XrdProofdAux::ChangeMod(const char *path, unsigned int mode)
00531 {
00532
00533
00534
00535 XPDLOC(AUX, "Aux::ChangeMod")
00536
00537 TRACE(HDBG, "path: "<<path);
00538
00539 if (!path || strlen(path) <= 0)
00540 return -1;
00541
00542 struct stat st;
00543 if (stat(path,&st) != 0) {
00544
00545 TRACE(XERR, "unable to stat path: "<<path<<" (errno: "<<errno<<")");
00546 return -1;
00547 }
00548
00549
00550 {
00551 XrdSysPrivGuard pGuard(st.st_uid, st.st_gid);
00552 if (XpdBadPGuard(pGuard, st.st_uid)) {
00553 TRACE(XERR, "could not get privileges to change ownership");
00554 return -1;
00555 }
00556
00557 if (chmod(path, mode) == -1) {
00558 TRACE(XERR, "cannot change permissions on path (errno: "<<errno<<")");
00559 return -1;
00560 }
00561 }
00562
00563
00564 if (S_ISDIR(st.st_mode)) {
00565
00566 DIR *dir = opendir(path);
00567 if (!dir) {
00568 TRACE(XERR,"cannot open "<<path<< "- errno: "<< errno);
00569 return -1;
00570 }
00571 XrdOucString proot(path);
00572 if (!proot.endswith('/')) proot += "/";
00573
00574 struct dirent *ent = 0;
00575 while ((ent = readdir(dir))) {
00576 if (ent->d_name[0] == '.' || !strcmp(ent->d_name, "..")) continue;
00577 XrdOucString fn(proot);
00578 fn += ent->d_name;
00579
00580 struct stat xst;
00581 if (stat(fn.c_str(),&xst) == 0) {
00582 {
00583 TRACE(HDBG,"getting {"<<xst.st_uid<<", "<< xst.st_gid<<"} identity");
00584 XrdSysPrivGuard pGuard(xst.st_uid, xst.st_gid);
00585 if (XpdBadPGuard(pGuard, xst.st_uid)) {
00586 TRACE(XERR, "could not get privileges to change ownership");
00587 return -1;
00588 }
00589
00590 if (chmod(fn.c_str(), mode) == -1) {
00591 TRACE(XERR, "cannot change permissions on path (errno: "<<errno<<")");
00592 return -1;
00593 }
00594 }
00595
00596 if (S_ISDIR(xst.st_mode)) {
00597 if (XrdProofdAux::ChangeMod(fn.c_str(), mode) != 0) {
00598 TRACE(XERR, "problems changing recursively permissions of: "<<fn);
00599 return -1;
00600 }
00601 }
00602 } else {
00603 TRACE(XERR, "unable to stat dir: "<<fn<<" (errno: "<<errno<<")");
00604 }
00605 }
00606 }
00607
00608
00609 return 0;
00610 }
00611
00612
00613 int XrdProofdAux::ChangeToDir(const char *dir, XrdProofUI ui, bool changeown)
00614 {
00615
00616
00617
00618 XPDLOC(AUX, "Aux::ChangeToDir")
00619
00620 TRACE(DBG, "changing to " << ((dir) ? dir : "**undef***"));
00621
00622 if (!dir || strlen(dir) <= 0)
00623 return -1;
00624
00625 if (changeown && (int) geteuid() != ui.fUid) {
00626
00627 XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
00628 if (XpdBadPGuard(pGuard, ui.fUid)) {
00629 TRACE(XERR, changeown << ": could not get privileges; uid req:"<< ui.fUid <<
00630 ", euid: " << geteuid() <<", uid:"<<getuid() << "; errno: "<<errno);
00631 return -1;
00632 }
00633 if (chdir(dir) == -1) {
00634 TRACE(XERR, changeown << ": can't change directory to "<< dir << " ui.fUid: " << ui.fUid <<
00635 ", euid: " << geteuid() <<", uid:"<<getuid()<<"; errno: "<<errno);
00636 return -1;
00637 }
00638 } else {
00639 if (chdir(dir) == -1) {
00640 TRACE(XERR, changeown << ": can't change directory to "<< dir <<
00641 ", euid: " << geteuid() <<", uid:"<<getuid()<<"; errno: "<<errno);
00642 return -1;
00643 }
00644 }
00645
00646
00647 return 0;
00648 }
00649
00650
00651 int XrdProofdAux::SymLink(const char *path, const char *link)
00652 {
00653
00654
00655 XPDLOC(AUX, "Aux::SymLink")
00656
00657 TRACE(DBG, path<<" -> "<<link);
00658
00659 if (!path || strlen(path) <= 0 || !link || strlen(link) <= 0)
00660 return -1;
00661
00662
00663 if (unlink(link) != 0 && errno != ENOENT) {
00664 TRACE(XERR, "problems unlinking existing symlink "<< link<<
00665 " (errno: "<<errno<<")");
00666 return -1;
00667 }
00668 if (symlink(path, link) != 0) {
00669 TRACE(XERR, "problems creating symlink " << link<<
00670 " (errno: "<<errno<<")");
00671 return -1;
00672 }
00673
00674
00675 return 0;
00676 }
00677
00678
00679 int XrdProofdAux::CheckIf(XrdOucStream *s, const char *host)
00680 {
00681
00682
00683
00684 XPDLOC(AUX, "")
00685
00686
00687 char *val = s ? s->GetWord() : 0;
00688 if (!val || strncmp(val,"if",2)) {
00689 if (val)
00690
00691 s->RetToken();
00692 return -1;
00693 }
00694
00695
00696 val = s->GetWord();
00697 if (!val)
00698 return -1;
00699
00700
00701 TRACE(ALL, ">>> Warning: 'if' conditions at the end of the directive are deprecated ");
00702 TRACE(ALL, ">>> Please use standard Scalla/Xrootd 'if-else-fi' constructs");
00703 TRACE(ALL, ">>> (see http://xrootd.slac.stanford.edu/doc/xrd_config/xrd_config.htm)");
00704
00705
00706 TRACE(DBG, "Aux::CheckIf: <pattern>: " <<val);
00707
00708
00709 XrdOucString h(host);
00710 return h.matches((const char *)val);
00711 }
00712
00713
00714 int XrdProofdAux::GetNumCPUs()
00715 {
00716
00717
00718 XPDLOC(AUX, "Aux::GetNumCPUs")
00719
00720 static int ncpu = -1;
00721
00722
00723 if (ncpu > 0)
00724 return ncpu;
00725 ncpu = 0;
00726
00727 XrdOucString emsg;
00728
00729 #if defined(linux)
00730
00731 XrdOucString fcpu("/proc/cpuinfo");
00732 FILE *fc = fopen(fcpu.c_str(), "r");
00733 if (!fc) {
00734 if (errno == ENOENT) {
00735 TRACE(XERR, "/proc/cpuinfo missing!!! Something very bad going on");
00736 } else {
00737 XPDFORM(emsg, "cannot open %s; errno: %d", fcpu.c_str(), errno);
00738 TRACE(XERR, emsg);
00739 }
00740 return -1;
00741 }
00742
00743 char line[2048] = { 0 };
00744 while (fgets(line, sizeof(line), fc)) {
00745 if (!strncmp(line, "processor", strlen("processor")))
00746 ncpu++;
00747 }
00748
00749 fclose(fc);
00750
00751 #elif defined(__sun)
00752
00753
00754 FILE *fp = popen("psrinfo", "r");
00755 if (fp != 0) {
00756 char line[2048] = { 0 };
00757 while (fgets(line, sizeof(line), fp))
00758 ncpu++;
00759 pclose(fp);
00760 }
00761
00762 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
00763
00764
00765 FILE *fp = popen("sysctl -n hw.ncpu", "r");
00766 if (fp != 0) {
00767 char line[2048] = { 0 };
00768 while (fgets(line, sizeof(line), fp))
00769 ncpu = XrdProofdAux::GetLong(&line[0]);
00770 pclose(fp);
00771 }
00772 #endif
00773
00774 TRACE(DBG, "# of cores found: "<<ncpu);
00775
00776
00777 return (ncpu <= 0) ? (int)(-1) : ncpu ;
00778 }
00779
00780 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
00781
00782 int XrdProofdAux::GetMacProcList(kinfo_proc **plist, int &nproc)
00783 {
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794 XPDLOC(AUX, "Aux::GetMacProcList")
00795
00796 int rc = 0;
00797 kinfo_proc *res;
00798 bool done = 0;
00799 static const int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
00800
00801 TRACE(DBG, "enter");
00802
00803
00804
00805 size_t len = 0;
00806
00807 if (!plist || (*plist))
00808 return EINVAL;
00809 nproc = 0;
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821 res = 0;
00822 do {
00823
00824 len = 0;
00825 if ((rc = sysctl((int *)name, (sizeof(name)/sizeof(*name)) - 1,
00826 0, &len, 0, 0)) == -1) {
00827 rc = errno;
00828 }
00829
00830
00831
00832 if (rc == 0) {
00833 res = (kinfo_proc *) malloc(len);
00834 if (!res)
00835 rc = ENOMEM;
00836 }
00837
00838
00839
00840 if (rc == 0) {
00841 if ((rc = sysctl((int *)name, (sizeof(name)/sizeof(*name)) - 1,
00842 res, &len, 0, 0)) == -1) {
00843 rc = errno;
00844 }
00845 if (rc == 0) {
00846 done = 1;
00847 } else if (rc == ENOMEM) {
00848 if (res)
00849 free(res);
00850 res = 0;
00851 rc = 0;
00852 }
00853 }
00854 } while (rc == 0 && !done);
00855
00856
00857 if (rc != 0 && !res) {
00858 free(res);
00859 res = 0;
00860 }
00861 *plist = res;
00862 if (rc == 0)
00863 nproc = len / sizeof(kinfo_proc);
00864
00865
00866 return rc;
00867 }
00868 #endif
00869
00870
00871 int XrdProofdAux::GetProcesses(const char *pn, std::map<int,XrdOucString> *pmap)
00872 {
00873
00874
00875
00876
00877 XPDLOC(AUX, "Aux::GetProcesses")
00878
00879 int np = 0;
00880
00881
00882 if (!pn || strlen(pn) <= 0 || !pmap) {
00883 TRACE(XERR, "invalid inputs");
00884 return -1;
00885 }
00886 TRACE(DBG, "process name: "<<pn);
00887
00888 XrdOucString emsg;
00889
00890 #if defined(linux) || defined(__sun)
00891
00892 DIR *dir = opendir("/proc");
00893 if (!dir) {
00894 emsg = "cannot open /proc - errno: ";
00895 emsg += errno;
00896 TRACE(DBG, emsg.c_str());
00897 return -1;
00898 }
00899
00900 struct dirent *ent = 0;
00901 while ((ent = readdir(dir))) {
00902 if (DIGIT(ent->d_name[0])) {
00903 XrdOucString fn("/proc/", 256);
00904 fn += ent->d_name;
00905 #if defined(linux)
00906 fn += "/status";
00907
00908 FILE *ffn = fopen(fn.c_str(), "r");
00909 if (!ffn) {
00910 emsg = "cannot open file ";
00911 emsg += fn; emsg += " - errno: "; emsg += errno;
00912 TRACE(HDBG, emsg);
00913 continue;
00914 }
00915
00916 bool ok = 0;
00917 int pid = -1;
00918 char line[2048] = { 0 };
00919 while (fgets(line, sizeof(line), ffn)) {
00920
00921 if (strstr(line, "Name:")) {
00922 if (strstr(line, pn)) {
00923
00924 ok = 1;
00925 }
00926
00927 break;
00928 }
00929 }
00930 if (ok) {
00931 fclose(ffn);
00932 fn.replace("/status", "/cmdline");
00933
00934 if (!(ffn = fopen(fn.c_str(), "r"))) {
00935 emsg = "cannot open file ";
00936 emsg += fn; emsg += " - errno: "; emsg += errno;
00937 TRACE(HDBG, emsg);
00938 continue;
00939 }
00940
00941 XrdOucString cmd;
00942 char buf[256];
00943 char *p = &buf[0];
00944 int pos = 0, ltot = 0, nr = 1;
00945 errno = 0;
00946 while (nr > 0) {
00947 while ((nr = read(fileno(ffn), p + pos, 1)) == -1 && errno == EINTR) {
00948 errno = 0;
00949 }
00950 ltot += nr;
00951 if (ltot == 254) {
00952 buf[255] = 0;
00953 cmd += buf;
00954 pos = 0;
00955 ltot = 0;
00956 } else if (nr > 0) {
00957 if (*p == 0) *p = ' ';
00958 p += nr;
00959 }
00960 }
00961
00962 buf[ltot] = 0;
00963 cmd += buf;
00964
00965 pid = strtol(ent->d_name, 0, 10);
00966 pmap->insert(std::make_pair(pid, cmd));
00967 np++;
00968 }
00969
00970 fclose(ffn);
00971 #elif defined(__sun)
00972 fn += "/psinfo";
00973
00974 int ffd = open(fn.c_str(), O_RDONLY);
00975 if (ffd <= 0) {
00976 emsg = "cannot open file ";
00977 emsg += fn; emsg += " - errno: "; emsg += errno;
00978 TRACE(HDBG, emsg);
00979 continue;
00980 }
00981
00982 psinfo_t psi;
00983 if (read(ffd, &psi, sizeof(psinfo_t)) != sizeof(psinfo_t)) {
00984 emsg = "cannot read ";
00985 emsg += fn; emsg += ": errno: "; emsg += errno;
00986 TRACE(XERR, emsg);
00987 close(ffd);
00988 continue;
00989 }
00990
00991 if (strstr(psi.pr_fname, pn)) {
00992
00993 XrdOucString cmd(psi.pr_fname);
00994 if (cmd.length() > 0) cmd += " ";
00995 cmd += psi.pr_psargs;
00996
00997 int pid = strtol(ent->d_name, 0, 10);
00998 pmap->insert(std::make_pair(pid, cmd));
00999 np++;
01000 }
01001
01002 close(ffd);
01003 #endif
01004 }
01005 }
01006
01007 closedir(dir);
01008
01009 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
01010
01011
01012 kinfo_proc *pl = 0;
01013 int ern = 0;
01014 if ((ern = XrdProofdAux::GetMacProcList(&pl, np)) != 0) {
01015 emsg = "cannot get the process list: errno: ";
01016 emsg += ern;
01017 TRACE(XERR, emsg);
01018 return -1;
01019 }
01020
01021
01022 int ii = np;
01023 while (ii--) {
01024 if (strstr(pl[ii].kp_proc.p_comm, pn)) {
01025
01026 pmap->insert(std::make_pair(pl[ii].kp_proc.p_pid, XrdOucString(pl[ii].kp_proc.p_comm)));
01027 np++;
01028 }
01029 }
01030
01031 free(pl);
01032 #else
01033
01034
01035
01036
01037 XrdOucString cmd = "ps ax -ww | grep proofserv 2>/dev/null";
01038
01039
01040 XrdOucString pids = ":";
01041 FILE *fp = popen(cmd.c_str(), "r");
01042 if (fp != 0) {
01043 char line[2048] = { 0 };
01044 while (fgets(line, sizeof(line), fp)) {
01045 int pid = (int) XrdProofdAux::GetLong(&line[from]);
01046 pmap->insert(std::make_pair(pid, XrdOucString(line)));
01047 np++;
01048 }
01049 pclose(fp);
01050 } else {
01051
01052 return -1;
01053 }
01054
01055 #endif
01056
01057
01058 return np;
01059 }
01060
01061
01062 int XrdProofdAux::GetIDFromPath(const char *path, XrdOucString &emsg)
01063 {
01064
01065
01066 emsg = "";
01067
01068 int id = -1;
01069 FILE *fid = fopen(path, "r");
01070 if (fid) {
01071 char line[64];
01072 if (fgets(line, sizeof(line), fid))
01073 sscanf(line, "%d", &id);
01074 fclose(fid);
01075 } else if (errno != ENOENT) {
01076 XPDFORM(emsg, "GetIDFromPath: error reading id from: %s (errno: %d)",
01077 path, errno);
01078 }
01079
01080 return id;
01081 }
01082
01083
01084 bool XrdProofdAux::HasToken(const char *s, const char *tokens)
01085 {
01086
01087
01088
01089 if (s && strlen(s) > 0) {
01090 XrdOucString tks(tokens), tok;
01091 int from = 0;
01092 while ((from = tks.tokenize(tok, from, ',')) != -1)
01093 if (strstr(s, tok.c_str())) return 1;
01094 }
01095 return 0;
01096 }
01097
01098
01099 int XrdProofdAux::VerifyProcessByID(int pid, const char *pname)
01100 {
01101
01102
01103
01104
01105
01106 XPDLOC(AUX, "Aux::VerifyProcessByID")
01107
01108 int rc = 0;
01109
01110 TRACE(DBG, "pid: "<<pid);
01111
01112
01113 if (pid < 0) {
01114 TRACE(XERR, "invalid pid");
01115 return -1;
01116 }
01117
01118 XrdOucString emsg;
01119
01120
01121 const char *pn = (pname && strlen(pname) > 0) ? pname : "proofserv";
01122
01123 #if defined(linux)
01124
01125 XrdOucString fn("/proc/");
01126 fn += pid;
01127 fn += "/stat";
01128 FILE *ffn = fopen(fn.c_str(), "r");
01129 if (!ffn) {
01130 if (errno == ENOENT) {
01131 TRACE(DBG, "process does not exists anymore");
01132 return 0;
01133 } else {
01134 XPDFORM(emsg, "cannot open %s; errno: %d", fn.c_str(), errno);
01135 TRACE(XERR, emsg);
01136 return -1;
01137 }
01138 }
01139
01140 char line[2048] = { 0 };
01141 if (fgets(line, sizeof(line), ffn)) {
01142 if (XrdProofdAux::HasToken(line, pn))
01143
01144 rc = 1;
01145 } else {
01146 XPDFORM(emsg, "cannot read %s; errno: %d", fn.c_str(), errno);
01147 TRACE(XERR, emsg);
01148 fclose(ffn);
01149 return -1;
01150 }
01151
01152 fclose(ffn);
01153
01154 #elif defined(__sun)
01155
01156
01157 XrdOucString fn("/proc/");
01158 fn += pid;
01159 fn += "/psinfo";
01160 int ffd = open(fn.c_str(), O_RDONLY);
01161 if (ffd <= 0) {
01162 if (errno == ENOENT) {
01163 TRACE(DBG, "VerifyProcessByID: process does not exists anymore");
01164 return 0;
01165 } else {
01166 XPDFORM(emsg, "cannot open %s; errno: %d", fn.c_str(), errno);
01167 TRACE(XERR, emsg);
01168 return -1;
01169 }
01170 }
01171
01172 psinfo_t psi;
01173 if (read(ffd, &psi, sizeof(psinfo_t)) != sizeof(psinfo_t)) {
01174 XPDFORM(emsg, "cannot read %s; errno: %d", fn.c_str(), errno);
01175 TRACE(XERR, emsg);
01176 close(ffd);
01177 return -1;
01178 }
01179
01180
01181 if (XrdProofdAux::HasToken(psi.pr_fname, pn))
01182
01183 rc = 1;
01184
01185
01186 close(ffd);
01187
01188 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
01189
01190
01191 kinfo_proc *pl = 0;
01192 int np;
01193 int ern = 0;
01194 if ((ern = XrdProofdAux::GetMacProcList(&pl, np)) != 0) {
01195 XPDFORM(emsg, "cannot get the process list: errno: %d", ern);
01196 TRACE(XERR, emsg);
01197 return -1;
01198 }
01199
01200
01201 while (np--) {
01202 if (pl[np].kp_proc.p_pid == pid &&
01203 XrdProofdAux::HasToken(pl[np].kp_proc.p_comm, pn)) {
01204
01205 rc = 1;
01206 break;
01207 }
01208 }
01209
01210 free(pl);
01211 #else
01212
01213 XrdOucString cmd = "ps ax | grep proofserv 2>/dev/null";
01214 if (pname && strlen(pname))
01215 cmd.replace("proofserv", pname);
01216 FILE *fp = popen(cmd.c_str(), "r");
01217 if (fp != 0) {
01218 char line[2048] = { 0 };
01219 while (fgets(line, sizeof(line), fp)) {
01220 if (pid == XrdProofdAux::GetLong(line)) {
01221
01222 rc = 1;
01223 break;
01224 }
01225 }
01226 pclose(fp);
01227 } else {
01228
01229 return -1;
01230 }
01231 #endif
01232
01233 return rc;
01234 }
01235
01236
01237 int XrdProofdAux::KillProcess(int pid, bool forcekill, XrdProofUI ui, bool changeown)
01238 {
01239
01240
01241
01242
01243
01244 XPDLOC(AUX, "Aux::KillProcess")
01245
01246 TRACE(DBG, "pid: "<<pid<< ", forcekill: "<< forcekill);
01247
01248 XrdOucString msg;
01249 if (pid > 0) {
01250
01251 XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
01252 if (XpdBadPGuard(pGuard, ui.fUid) && changeown) {
01253 TRACE(XERR, "could not get privileges");
01254 return -1;
01255 } else {
01256 bool signalled = 1;
01257 if (forcekill) {
01258
01259 if (kill(pid, SIGKILL) != 0) {
01260 if (errno != ESRCH) {
01261 XPDFORM(msg, "kill(pid,SIGKILL) failed for process %d; errno: %d", pid, errno);
01262 TRACE(XERR, msg);
01263 return -1;
01264 }
01265 signalled = 0;
01266 }
01267 } else {
01268
01269 if (kill(pid, SIGTERM) != 0) {
01270 if (errno != ESRCH) {
01271 XPDFORM(msg, "kill(pid,SIGTERM) failed for process %d; errno: %d", pid, errno);
01272 TRACE(XERR, msg);
01273 return -1;
01274 }
01275 signalled = 0;
01276 }
01277 }
01278
01279 if (!signalled) {
01280 TRACE(DBG, "process ID "<<pid<<" not found in the process table");
01281 }
01282 }
01283 } else {
01284 return -1;
01285 }
01286
01287
01288 return 0;
01289 }
01290
01291
01292 int XrdProofdAux::RmDir(const char *path)
01293 {
01294
01295
01296 XPDLOC(AUX, "Aux::RmDir")
01297
01298 int rc = 0;
01299
01300 TRACE(DBG, path);
01301
01302
01303 DIR *dir = opendir(path);
01304 if (!dir) {
01305 TRACE(XERR, "cannot open dir "<<path<<" ; error: "<<errno);
01306 return -errno;
01307 }
01308
01309
01310 XrdOucString entry;
01311 struct stat st;
01312 struct dirent *ent = 0;
01313 while ((ent = (struct dirent *)readdir(dir))) {
01314
01315 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue;
01316
01317 XPDFORM(entry, "%s/%s", path, ent->d_name);
01318 if (stat(entry.c_str(), &st) != 0) {
01319 TRACE(XERR, "cannot stat entry "<<entry<<" ; error: "<<errno);
01320 rc = -errno;
01321 break;
01322 }
01323
01324 if (S_ISDIR(st.st_mode)) {
01325 rc = XrdProofdAux::RmDir(entry.c_str());
01326 if (rc != 0) {
01327 TRACE(XERR, "problems removing"<<entry<<" ; error: "<<-rc);
01328 break;
01329 }
01330 } else {
01331
01332 if (unlink(entry.c_str()) != 0) {
01333 rc = -errno;
01334 TRACE(XERR, "problems removing"<<entry<<" ; error: "<<-rc);
01335 break;
01336 }
01337 }
01338 }
01339
01340 closedir(dir);
01341
01342
01343 if (!rc && rmdir(path) != 0) {
01344 rc = -errno;
01345 TRACE(XERR, "problems removing"<<path<<" ; error: "<<-rc);
01346 }
01347
01348
01349 return rc;
01350 }
01351
01352
01353 int XrdProofdAux::MvDir(const char *oldpath, const char *newpath)
01354 {
01355
01356
01357
01358 XPDLOC(AUX, "Aux::MvDir")
01359
01360 int rc = 0;
01361
01362 TRACE(DBG, "oldpath "<<oldpath<<", newpath: "<<newpath);
01363
01364
01365 DIR *dir = opendir(oldpath);
01366 if (!dir) {
01367 TRACE(XERR, "cannot open dir "<<oldpath<<" ; error: "<<errno);
01368 return -errno;
01369 }
01370
01371
01372 struct stat st;
01373 if (stat(newpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
01374 TRACE(XERR, "destination dir "<<newpath<<
01375 " does not exist or is not a directory; errno: "<<errno);
01376 return -ENOENT;
01377 }
01378
01379
01380 XrdOucString srcentry, dstentry;
01381 struct dirent *ent = 0;
01382 while ((ent = (struct dirent *)readdir(dir))) {
01383
01384 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue;
01385
01386 XPDFORM(srcentry, "%s/%s", oldpath, ent->d_name);
01387 if (stat(srcentry.c_str(), &st) != 0) {
01388 TRACE(XERR, "cannot stat entry "<<srcentry<<" ; error: "<<errno);
01389 rc = -errno;
01390 break;
01391 }
01392
01393 XPDFORM(dstentry, "%s/%s", newpath, ent->d_name);
01394
01395 if (S_ISDIR(st.st_mode)) {
01396 mode_t srcmode = st.st_mode;
01397
01398 if (stat(dstentry.c_str(), &st) == 0) {
01399 if (!S_ISDIR(st.st_mode)) {
01400 TRACE(XERR, "destination path already exists and is not a directory: "<<dstentry);
01401 rc = -ENOTDIR;
01402 break;
01403 }
01404 } else {
01405 if (mkdir(dstentry.c_str(), srcmode) != 0) {
01406 TRACE(XERR, "cannot create entry "<<dstentry<<" ; error: "<<errno);
01407 rc = -errno;
01408 break;
01409 }
01410 }
01411 if ((rc = XrdProofdAux::MvDir(srcentry.c_str(), dstentry.c_str())) != 0) {
01412 TRACE(XERR, "problems moving "<<srcentry<<" to "<<dstentry<<"; error: "<<-rc);
01413 break;
01414 }
01415 if ((rc = XrdProofdAux::RmDir(srcentry.c_str())) != 0) {
01416 TRACE(XERR, "problems removing "<<srcentry<<"; error: "<<-rc);
01417 break;
01418 }
01419 } else {
01420
01421 if (rename(srcentry.c_str(), dstentry.c_str()) != 0) {
01422 rc = -errno;
01423 TRACE(XERR, "problems moving "<<srcentry<<" to "<<dstentry<<"; error: "<<-rc);
01424 break;
01425 }
01426 }
01427 }
01428
01429 closedir(dir);
01430
01431
01432 return rc;
01433 }
01434
01435
01436 int XrdProofdAux::Touch(const char *path, int opt)
01437 {
01438
01439
01440
01441
01442 if (opt == 0) {
01443 if (utime(path, 0) != 0)
01444 return -errno;
01445 } else if (opt <= 2) {
01446 struct stat st;
01447 if (stat(path, &st) != 0)
01448 return -errno;
01449 struct utimbuf ut;
01450 if (opt == 1) {
01451 ut.actime = time(0);
01452 ut.modtime = st.st_mtime;
01453 } else if (opt == 2) {
01454 ut.modtime = time(0);
01455 ut.actime = st.st_atime;
01456 }
01457 if (utime(path, &ut) != 0)
01458 return -errno;
01459 } else {
01460
01461 return -1;
01462 }
01463
01464 return 0;
01465 }
01466
01467
01468 int XrdProofdAux::ReadMsg(int fd, XrdOucString &msg)
01469 {
01470
01471 XPDLOC(AUX, "Aux::ReadMsg")
01472
01473 msg = "";
01474 if (fd > 0) {
01475
01476
01477 int len = 0;
01478 if (read(fd, &len, sizeof(len)) != sizeof(len))
01479 return -errno;
01480 TRACE(HDBG,fd<<": len: "<<len);
01481
01482
01483 char buf[XPD_MAXLEN];
01484 int nr = -1;
01485 do {
01486 int wanted = (len > XPD_MAXLEN-1) ? XPD_MAXLEN-1 : len;
01487 while ((nr = read(fd, buf, wanted)) < 0 &&
01488 errno == EINTR)
01489 errno = 0;
01490 if (nr < wanted) {
01491 break;
01492 } else {
01493 buf[nr] = '\0';
01494 msg += buf;
01495 }
01496
01497 len -= nr;
01498 } while (nr > 0 && len > 0);
01499
01500 TRACE(HDBG,fd<<": buf: "<<buf);
01501
01502
01503 return 0;
01504 }
01505
01506 TRACE(XERR, "pipe descriptor undefined: "<<fd);
01507 return -1;
01508 }
01509
01510
01511 int XrdProofdAux::ParsePidPath(const char *path,
01512 XrdOucString &before, XrdOucString &after)
01513 {
01514
01515
01516
01517
01518 XPDLOC(AUX, "ParsePidPath")
01519
01520 long int pid = -1;
01521 if (path && strlen(path)) {
01522 pid = 0;
01523 int from = 0;
01524 XrdOucString spid, s(path);
01525 bool nopid = 1;
01526 while ((from = s.tokenize(spid, from, '.')) != -1) {
01527 if (spid.length() > 0) {
01528 if (spid.isdigit()) {
01529
01530 pid = (int) spid.atoi();
01531 if (!XPD_LONGOK(pid)) {
01532
01533 pid = 0;
01534 }
01535 }
01536 if (nopid && pid > 0) {
01537 nopid = 0;
01538 } else if (nopid) {
01539 if (before.length() > 0) before += ".";
01540 before += spid;
01541 } else {
01542 if (after.length() > 0) after += ".";
01543 after += spid;
01544 }
01545 }
01546 }
01547 if (pid == 0 && before.length() == 0) {
01548 before = after;
01549 after = "";
01550 }
01551 }
01552
01553 TRACE(HDBG,"path: "<<path<<" --> before: '"<<before<<"', pid: "<<pid<<", after: '"<<after<<"'");
01554
01555
01556 return pid;
01557 }
01558
01559
01560 int XrdProofdAux::ParseUsrGrp(const char *path, XrdOucString &usr, XrdOucString &grp)
01561 {
01562
01563
01564
01565 XrdOucString rest, after;
01566 int pid = ParsePidPath(path, rest, after);
01567
01568 if (pid >= 0 && rest.length() > 0) {
01569
01570 usr = rest;
01571 int ip = STR_NPOS;
01572 if ((ip = rest.rfind('.')) != STR_NPOS) {
01573 usr.erase(ip);
01574
01575 grp = rest;
01576 grp.erase(0, ip + 1);
01577 }
01578 }
01579
01580 return pid;
01581 }
01582
01583
01584
01585
01586
01587
01588 int DoDirectiveClass(XrdProofdDirective *d, char *val, XrdOucStream *cfg, bool rcf)
01589 {
01590
01591
01592 if (!d || !(d->fVal))
01593
01594 return -1;
01595
01596 return ((XrdProofdConfig *)d->fVal)->DoDirective(d, val, cfg, rcf);
01597 }
01598
01599
01600 int DoDirectiveInt(XrdProofdDirective *d, char *val, XrdOucStream *cfg, bool rcf)
01601 {
01602
01603 XPDLOC(AUX, "DoDirectiveInt")
01604
01605 if (!d || !(d->fVal) || !val)
01606
01607 return -1;
01608
01609 if (rcf && !d->fRcf)
01610
01611 return 0;
01612
01613
01614 if (d->fHost && cfg)
01615 if (XrdProofdAux::CheckIf(cfg, d->fHost) == 0)
01616 return 0;
01617
01618 long int v = strtol(val,0,10);
01619 *((int *)d->fVal) = v;
01620
01621 TRACE(DBG, "set "<<d->fName<<" to "<<*((int *)d->fVal));
01622
01623 return 0;
01624 }
01625
01626
01627 int DoDirectiveString(XrdProofdDirective *d, char *val, XrdOucStream *cfg, bool rcf)
01628 {
01629
01630 XPDLOC(AUX, "DoDirectiveString")
01631
01632 if (!d || !(d->fVal) || !val)
01633
01634 return -1;
01635
01636 if (rcf && !d->fRcf)
01637
01638 return 0;
01639
01640
01641 if (d->fHost && cfg)
01642 if (XrdProofdAux::CheckIf(cfg, d->fHost) == 0)
01643 return 0;
01644
01645 *((XrdOucString *)d->fVal) = val;
01646
01647 TRACE(DBG, "set "<<d->fName<<" to "<<*((XrdOucString *)d->fVal));
01648 return 0;
01649 }
01650
01651
01652 int SetHostInDirectives(const char *, XrdProofdDirective *d, void *h)
01653 {
01654
01655
01656 const char *host = (const char *)h;
01657
01658 if (!d || !host || strlen(host) <= 0)
01659
01660 return 1;
01661
01662 d->fHost = host;
01663
01664
01665 return 0;
01666 }
01667
01668
01669
01670
01671
01672 XrdProofdPipe::XrdProofdPipe()
01673 {
01674
01675
01676
01677 if (pipe(fPipe) != 0) {
01678 fPipe[0] = -1;
01679 fPipe[1] = -1;
01680 }
01681 }
01682
01683
01684 XrdProofdPipe::~XrdProofdPipe()
01685 {
01686
01687
01688
01689 Close();
01690 }
01691
01692
01693 void XrdProofdPipe::Close()
01694 {
01695
01696
01697 if (IsValid()) {
01698 close(fPipe[0]);
01699 close(fPipe[1]);
01700 fPipe[0] = -1;
01701 fPipe[1] = -1;
01702 }
01703 }
01704
01705
01706 int XrdProofdPipe::Post(int type, const char *msg)
01707 {
01708
01709 XPDLOC(AUX, "Pipe::Post")
01710
01711
01712 if (IsValid()) {
01713 XrdOucString buf;
01714 if (msg && strlen(msg) > 0) {
01715 XPDFORM(buf, "%d %s", type, msg);
01716 } else {
01717 buf += type;
01718 }
01719 TRACE(HDBG, fPipe[1] << ": posting: type: "<<type<<", buf: "<<buf);
01720 int len = buf.length() + 1;
01721 XrdSysMutexHelper mh(fWrMtx);
01722 if (write(fPipe[1], &len, sizeof(len)) != sizeof(len))
01723 return -errno;
01724 if (write(fPipe[1], buf.c_str(), len) != len)
01725 return -errno;
01726
01727 return 0;
01728 }
01729
01730 TRACE(XERR, "pipe is invalid");
01731 return -1;
01732 }
01733
01734
01735 int XrdProofdPipe::Recv(XpdMsg &msg)
01736 {
01737
01738 XPDLOC(AUX, "Pipe::Recv")
01739
01740 if (IsValid()) {
01741 XrdOucString buf;
01742 { XrdSysMutexHelper mh(fRdMtx);
01743 if (XrdProofdAux::ReadMsg(fPipe[0], buf) != 0)
01744 return -1;
01745 }
01746 TRACE(HDBG, fPipe[0] << ": receiving: msg: "<< buf);
01747 msg.Init(buf.c_str());
01748
01749 return 0;
01750 }
01751
01752 TRACE(XERR, "pipe is invalid");
01753 return -1;
01754 }
01755
01756
01757 int XrdProofdPipe::Poll(int to)
01758 {
01759
01760 XPDLOC(AUX, "Pipe::Poll")
01761
01762 if (IsValid()) {
01763
01764
01765 struct pollfd fds_r;
01766 fds_r.fd = fPipe[0];
01767 fds_r.events = POLLIN;
01768
01769
01770 int pollrc = 0;
01771 int xto = (to > 0) ? to * 1000 : -1;
01772 while ((pollrc = poll(&fds_r, 1, xto)) < 0 && (errno == EINTR)) {
01773 errno = 0;
01774 }
01775
01776 return (pollrc >= 0) ? pollrc : -errno;
01777 }
01778
01779 TRACE(XERR, "pipe is invalid");
01780 return -1;
01781 }
01782
01783
01784
01785
01786
01787 int XpdMsg::Init(const char *buf)
01788 {
01789
01790 XPDLOC(AUX, "Msg::Init")
01791
01792 fType = -1;
01793 fBuf = "";
01794 fFrom = -1;
01795
01796 TRACE(HDBG, "buf: "<< (const char *)(buf ? buf : "+++ empty +++"));
01797
01798 if (buf && strlen(buf) > 0) {
01799 fBuf = buf;
01800 fFrom = 0;
01801
01802 XrdOucString ctyp;
01803 if ((fFrom = fBuf.tokenize(ctyp, fFrom, ' ')) == -1 || ctyp.length() <= 0) {
01804 TRACE(XERR, "ctyp: "<<ctyp<<" fFrom: "<<fFrom);
01805 fBuf = "";
01806 fFrom = -1;
01807 return -1;
01808 }
01809 fType = ctyp.atoi();
01810 if (!XPD_LONGOK(fType)) {
01811 TRACE(XERR, "ctyp: "<<ctyp<<" fType: "<<fType);
01812 fBuf = "";
01813 fFrom = -1;
01814 return -1;
01815 }
01816 fBuf.erase(0,fFrom);
01817 while (fBuf.beginswith(' '))
01818 fBuf.erase(0, 1);
01819 fFrom = 0;
01820 TRACE(HDBG, fType<<", "<<fBuf);
01821 }
01822
01823 return 0;
01824 }
01825
01826
01827 int XpdMsg::Get(int &i)
01828 {
01829
01830 XPDLOC(AUX, "Msg::Get")
01831
01832 TRACE(HDBG,"int &i: "<<fFrom<<" "<<fBuf);
01833
01834 int iold = i;
01835 XrdOucString tkn;
01836 if ((fFrom = fBuf.tokenize(tkn, fFrom, ' ')) == -1 || tkn.length() <= 0)
01837 return -1;
01838 i = tkn.atoi();
01839 if (!XPD_LONGOK(i)) {
01840 TRACE(XERR, "tkn: "<<tkn<<" i: "<<i);
01841 i = iold;
01842 return -1;
01843 }
01844
01845 return 0;
01846 }
01847
01848
01849 int XpdMsg::Get(XrdOucString &s)
01850 {
01851
01852 XPDLOC(AUX, "Msg::Get")
01853
01854 TRACE(HDBG,"XrdOucString &s: "<<fFrom<<" "<<fBuf);
01855
01856 if ((fFrom = fBuf.tokenize(s, fFrom, ' ')) == -1 || s.length() <= 0) {
01857 TRACE(XERR, "s: "<<s<<" fFrom: "<<fFrom);
01858 return -1;
01859 }
01860
01861
01862 return 0;
01863 }
01864
01865
01866 int XpdMsg::Get(void **p)
01867 {
01868
01869 XPDLOC(AUX, "Msg::Get")
01870
01871 TRACE(HDBG,"void **p: "<<fFrom<<" "<<fBuf);
01872
01873 XrdOucString tkn;
01874 if ((fFrom = fBuf.tokenize(tkn, fFrom, ' ')) == -1 || tkn.length() <= 0) {
01875 TRACE(XERR, "tkn: "<<tkn<<" fFrom: "<<fFrom);
01876 return -1;
01877 }
01878 sscanf(tkn.c_str(), "%p", p);
01879
01880
01881 return 0;
01882 }
01883
01884
01885
01886
01887
01888
01889
01890 void XrdProofdMultiStr::Init(const char *s)
01891 {
01892
01893
01894
01895
01896
01897
01898
01899
01900
01901
01902
01903
01904
01905 fN = 0;
01906 if (s && strlen(s)) {
01907 XrdOucString kernel(s);
01908
01909 int ib = kernel.find('[');
01910 if (ib == STR_NPOS) return;
01911
01912 int ie = kernel.find(']', ib + 1);
01913 if (ie == STR_NPOS) return;
01914
01915 if (ie == ib + 1) return;
01916
01917 fHead.assign(kernel, 0, ib -1);
01918 fTail.assign(kernel, ie + 1);
01919
01920 XrdOucString tkns(kernel, ib + 1, ie - 1);
01921
01922 int from = 0;
01923 XrdOucString tkn;
01924 while ((from = tkns.tokenize(tkn, from, ',')) != -1) {
01925 if (tkn.length() > 0) {
01926 XrdProofdMultiStrToken t(tkn.c_str());
01927 if (t.IsValid()) {
01928 fN += t.N();
01929 fTokens.push_back(t);
01930 }
01931 }
01932 }
01933
01934 if (!IsValid()) {
01935 fHead = "";
01936 fTail = "";
01937 }
01938 }
01939 }
01940
01941
01942 bool XrdProofdMultiStr::Matches(const char *s)
01943 {
01944
01945
01946 if (s && strlen(s)) {
01947 XrdOucString str(s);
01948 if (fHead.length() <= 0 || str.beginswith(fHead)) {
01949 if (fTail.length() <= 0 || str.endswith(fTail)) {
01950 str.replace(fHead,"");
01951 str.replace(fTail,"");
01952 std::list<XrdProofdMultiStrToken>::iterator it = fTokens.begin();
01953 for (; it != fTokens.end(); it++) {
01954 if ((*it).Matches(str.c_str()))
01955 return 1;
01956 }
01957 }
01958 }
01959 }
01960
01961 return 0;
01962 }
01963
01964
01965 XrdOucString XrdProofdMultiStr::Export()
01966 {
01967
01968
01969 XrdOucString str(fN * (fHead.length() + fTail.length() + 4)) ;
01970 str = "";
01971 if (fN > 0) {
01972 std::list<XrdProofdMultiStrToken>::iterator it = fTokens.begin();
01973 for (; it != fTokens.end(); it++) {
01974 int n = (*it).N(), j = -1;
01975 while (n--) {
01976 str += fHead;
01977 str += (*it).Export(j);
01978 str += fTail;
01979 str += ",";
01980 }
01981 }
01982 }
01983
01984 if (str.endswith(','))
01985 str.erase(str.rfind(','));
01986
01987 return str;
01988 }
01989
01990
01991 XrdOucString XrdProofdMultiStr::Get(int i)
01992 {
01993
01994
01995 XrdOucString str;
01996
01997 if (i >= 0) {
01998 std::list<XrdProofdMultiStrToken>::iterator it = fTokens.begin();
01999 for (; it != fTokens.end(); it++) {
02000 int n = (*it).N(), j = -1;
02001 if ((i + 1) > n) {
02002 i -= n;
02003 } else {
02004 j = i;
02005 str = fHead;
02006 str += (*it).Export(j);
02007 str += fTail;
02008 break;
02009 }
02010 }
02011 }
02012
02013
02014 return str;
02015 }
02016
02017
02018 void XrdProofdMultiStrToken::Init(const char *s)
02019 {
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031 XPDLOC(AUX, "MultiStrToken::Init")
02032
02033 fIa = LONG_MAX;
02034 fIb = LONG_MAX;
02035 fType = kUndef;
02036 fN = 0;
02037 bool bad = 0;
02038 XrdOucString emsg;
02039 if (s && strlen(s)) {
02040 fA = s;
02041
02042 int id = fA.find('-');
02043 if (id == STR_NPOS) {
02044
02045 fN = 1;
02046 fType = kSimple;
02047 return;
02048 }
02049
02050 fB.assign(fA, id + 1);
02051 fA.erase(id);
02052 if (fB.length() <= 0) {
02053 if (fA.length() > 0) {
02054
02055 fN = 1;
02056 fType = kSimple;
02057 }
02058
02059 return;
02060 }
02061
02062 char *a = (char *)fA.c_str();
02063 char *b = (char *)fB.c_str();
02064 if (fA.length() == 1 && fB.length() == 1) {
02065 LETTOIDX(*a, fIa);
02066 if (fIa != LONG_MAX) {
02067 LETTOIDX(*b, fIb);
02068 if (fIb != LONG_MAX && fIa <= fIb) {
02069
02070 fType = kLetter;
02071 fN = fIb - fIa + 1;
02072 return;
02073 }
02074 } else if (DIGIT(*a) && DIGIT(*b) &&
02075 (fIa = *a) <= (fIb = *b)) {
02076
02077 fType = kDigit;
02078 fN = fIb - fIa + 1;
02079 return;
02080 }
02081
02082 emsg = "not-supported single-field extremes";
02083 bad = 1;
02084 }
02085 if (!bad) {
02086 fIa = fA.atoi();
02087 if (fIa != LONG_MAX && fIa != LONG_MIN) {
02088 fIb = fB.atoi();
02089 if (fIb != LONG_MAX && fIb != LONG_MIN && fIb >= fIa) {
02090 fType = kDigits;
02091 fN = fIb - fIa + 1;
02092 return;
02093 }
02094
02095 emsg = "non-digit or wrong-ordered extremes";
02096 bad = 1;
02097 } else {
02098
02099 emsg = "non-digit extremes";
02100 bad = 1;
02101 }
02102 }
02103 }
02104
02105 if (bad) {
02106 TRACE(XERR, emsg);
02107 fA = "";
02108 fB = "";
02109 fIa = LONG_MAX;
02110 fIb = LONG_MAX;
02111 }
02112
02113 return;
02114 }
02115
02116
02117 bool XrdProofdMultiStrToken::Matches(const char *s)
02118 {
02119
02120
02121 if (s && strlen(s)) {
02122 if (fType == kSimple)
02123 return ((fA == s) ? 1 : 0);
02124
02125 XrdOucString str(s);
02126 long ls = LONG_MIN;
02127 if (fType != kDigits) {
02128 if (str.length() > 1)
02129 return 0;
02130 char *ps = (char *)s;
02131 if (fType == kDigit) {
02132 if (!DIGIT(*ps) || *ps < fIa || *ps > fIb)
02133 return 0;
02134 } else if (fType == kLetter) {
02135 LETTOIDX(*ps, ls);
02136 if (ls == LONG_MAX || ls < fIa || ls > fIb)
02137 return 0;
02138 }
02139 } else {
02140 ls = str.atoi();
02141 if (ls == LONG_MAX || ls < fIa || ls > fIb)
02142 return 0;
02143 }
02144
02145 return 1;
02146 }
02147
02148 return 0;
02149 }
02150
02151
02152 XrdOucString XrdProofdMultiStrToken::Export(int &next)
02153 {
02154
02155
02156 XrdOucString tkn(fA.length());
02157
02158
02159 if (fType == kSimple)
02160 return (tkn = fA);
02161
02162
02163 if (next > fIb - fIa)
02164 return tkn;
02165
02166
02167 if (next == -1)
02168 next = 0;
02169
02170
02171 if (fType == kLetter) {
02172 char c = 0;
02173 IDXTOLET(fIa + next, c);
02174 next++;
02175 return (tkn = c);
02176 }
02177
02178
02179 if (fType == kDigit) {
02180 tkn = (char)(fIa + next);
02181 next++;
02182 return tkn;
02183 }
02184
02185
02186 XrdOucString tmp(fA.length());
02187 tmp.form("%ld", fIa + next);
02188 next++;
02189 int dl = fA.length() - tmp.length();
02190 if (dl <= 0) return tmp;
02191
02192 tkn = "";
02193 while (dl--) tkn += "0";
02194 tkn += tmp;
02195 return tkn;
02196 }
02197
02198
02199 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02200 int ns, const char *ss[5],
02201 int ni, int ii[5],
02202 int np, void *pp[5])
02203 {
02204
02205
02206
02207 int len = 0;
02208 if (!fmt || (len = strlen(fmt)) <= 0) return;
02209
02210 char si[32], sp[32];
02211
02212
02213 int i = ns;
02214 while (i-- > 0) { if (ss[i]) { len += strlen(ss[i]); } }
02215 i = ni + np;
02216 while (i-- > 0) { len += 32; }
02217
02218 s.resize(len+1);
02219
02220 int from = 0;
02221 s.assign(fmt, from);
02222 int nii = 0, nss = 0, npp = 0;
02223 int k = STR_NPOS;
02224 while ((k = s.find('%', from)) != STR_NPOS) {
02225 bool replaced = 0;
02226 if (s[k+1] == 's') {
02227 if (nss < ns) {
02228 s.replace("%s", ss[nss++], k, k + 1);
02229 replaced = 1;
02230 }
02231 } else if (s[k+1] == 'd') {
02232 if (nii < ni) {
02233 sprintf(si,"%d", ii[nii++]);
02234 s.replace("%d", si, k, k + 1);
02235 replaced = 1;
02236 }
02237 } else if (s[k+1] == 'p') {
02238 if (npp < np) {
02239 sprintf(sp,"%p", pp[npp++]);
02240 s.replace("%p", sp, k, k + 1);
02241 replaced = 1;
02242 }
02243 }
02244 if (!replaced) from = k + 1;
02245 }
02246 }
02247
02248
02249 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02250 const char *s0, const char *s1,
02251 const char *s2, const char *s3, const char *s4)
02252 {
02253
02254
02255 const char *ss[5] = {s0, s1, s2, s3, s4};
02256 int ii[5] = {0,0,0,0,0};
02257 void *pp[5] = {0,0,0,0,0};
02258
02259 XrdProofdAux::Form(s,fmt,5,ss,0,ii,0,pp);
02260 }
02261
02262
02263 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02264 int i0, int i1, int i2, int i3, int i4)
02265 {
02266
02267
02268 const char *ss[5] = {0, 0, 0, 0, 0};
02269 int ii[5] = {i0,i1,i2,i3,i4};
02270 void *pp[5] = {0,0,0,0,0};
02271
02272 XrdProofdAux::Form(s,fmt,0,ss,5,ii,5,pp);
02273 }
02274
02275
02276 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02277 void *p0, void *p1, void *p2, void *p3, void *p4)
02278 {
02279
02280
02281 const char *ss[5] = {0, 0, 0, 0, 0};
02282 int ii[5] = {0,0,0,0,0};
02283 void *pp[5] = {p0,p1,p2,p3,p4};
02284
02285 XrdProofdAux::Form(s,fmt,0,ss,0,ii,5,pp);
02286 }
02287
02288
02289
02290 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0, const char *s0,
02291 const char *s1, const char *s2, const char *s3)
02292 {
02293
02294
02295 const char *ss[5] = {s0, s1, s2, s3, 0};
02296 int ii[5] = {i0,0,0,0,0};
02297 void *pp[5] = {0,0,0,0,0};
02298
02299 XrdProofdAux::Form(s,fmt,4,ss,1,ii,0,pp);
02300 }
02301
02302
02303 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, const char *s0,
02304 int i0, int i1, int i2, int i3)
02305 {
02306
02307
02308 const char *ss[5] = {s0,0,0,0,0};
02309 int ii[5] = {i0,i1,i2,i3,0};
02310 void *pp[5] = {0,0,0,0,0};
02311
02312 XrdProofdAux::Form(s,fmt,1,ss,4,ii,0,pp);
02313 }
02314
02315
02316 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, const char *s0, const char *s1,
02317 int i0, int i1, int i2)
02318 {
02319
02320
02321 const char *ss[5] = {s0,s1,0,0,0};
02322 int ii[5] = {i0,i1,i2,0,0};
02323 void *pp[5] = {0,0,0,0,0};
02324
02325 XrdProofdAux::Form(s,fmt,2,ss,3,ii,0,pp);
02326 }
02327
02328
02329 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0, int i1,
02330 const char *s0, const char *s1, const char *s2)
02331 {
02332
02333
02334 const char *ss[5] = {s0,s1,s2,0,0};
02335 int ii[5] = {i0,i1,0,0,0};
02336 void *pp[5] = {0,0,0,0,0};
02337
02338 XrdProofdAux::Form(s,fmt,3,ss,2,ii,0,pp);
02339 }
02340
02341
02342
02343 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, const char *s0,
02344 const char *s1, const char *s2,
02345 int i0, int i1)
02346 {
02347
02348
02349 const char *ss[5] = {s0,s1,s2,0,0};
02350 int ii[5] = {i0,i1,0,0,0};
02351 void *pp[5] = {0,0,0,0,0};
02352
02353 XrdProofdAux::Form(s,fmt,3,ss,2,ii,0,pp);
02354 }
02355
02356
02357 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0, int i1, int i2,
02358 const char *s0, const char *s1)
02359 {
02360
02361
02362 const char *ss[5] = {s0,s1,0,0,0};
02363 int ii[5] = {i0,i1,i2,0,0};
02364 void *pp[5] = {0,0,0,0,0};
02365
02366 XrdProofdAux::Form(s,fmt,2,ss,3,ii,0,pp);
02367 }
02368
02369
02370
02371 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, const char *s0,
02372 const char *s1, const char *s2, const char *s3, int i0)
02373 {
02374
02375
02376 const char *ss[5] = {s0,s1,s2,s3,0};
02377 int ii[5] = {i0,0,0,0,0};
02378 void *pp[5] = {0,0,0,0,0};
02379
02380 XrdProofdAux::Form(s,fmt,4,ss,1,ii,0,pp);
02381 }
02382
02383
02384 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0, int i1, int i2,
02385 int i3, const char *s0)
02386 {
02387
02388
02389 const char *ss[5] = {s0,0,0,0,0};
02390 int ii[5] = {i0,i1,i2,i3,0};
02391 void *pp[5] = {0,0,0,0,0};
02392
02393 XrdProofdAux::Form(s,fmt,1,ss,4,ii,0,pp);
02394 }
02395
02396
02397 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0, int i1, void *p0)
02398 {
02399
02400
02401 const char *ss[5] = {0,0,0,0,0};
02402 int ii[5] = {i0,i1,0,0,0};
02403 void *pp[5] = {p0,0,0,0,0};
02404
02405 XrdProofdAux::Form(s,fmt,0,ss,2,ii,1,pp);
02406 }
02407
02408
02409 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02410 int i0, int i1, int i2, void *p0)
02411 {
02412
02413
02414 const char *ss[5] = {0,0,0,0,0};
02415 int ii[5] = {i0,i1,i2,0,0};
02416 void *pp[5] = {p0,0,0,0,0};
02417
02418 XrdProofdAux::Form(s,fmt,0,ss,3,ii,1,pp);
02419 }
02420
02421
02422 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02423 int i0, int i1, int i2, int i3, void *p0)
02424 {
02425
02426
02427 const char *ss[5] = {0,0,0,0,0};
02428 int ii[5] = {i0,i1,i2,i3,0};
02429 void *pp[5] = {p0,0,0,0,0};
02430
02431 XrdProofdAux::Form(s,fmt,0,ss,4,ii,1,pp);
02432 }
02433
02434
02435 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0, int i1,
02436 void *p0, int i2, int i3)
02437 {
02438
02439
02440 const char *ss[5] = {0,0,0,0,0};
02441 int ii[5] = {i0,i1,i2,i3,0};
02442 void *pp[5] = {p0,0,0,0,0};
02443
02444 XrdProofdAux::Form(s,fmt,0,ss,4,ii,1,pp);
02445 }
02446
02447
02448 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, void *p0, int i0, int i1)
02449 {
02450
02451
02452 const char *ss[5] = {0,0,0,0,0};
02453 int ii[5] = {i0,i1,0,0,0};
02454 void *pp[5] = {p0,0,0,0,0};
02455
02456 XrdProofdAux::Form(s,fmt,0,ss,2,ii,1,pp);
02457 }
02458
02459
02460 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02461 const char *s0, void *p0, int i0, int i1)
02462 {
02463
02464
02465 const char *ss[5] = {s0,0,0,0,0};
02466 int ii[5] = {i0,i1,0,0,0};
02467 void *pp[5] = {p0,0,0,0,0};
02468
02469 XrdProofdAux::Form(s,fmt,1,ss,2,ii,1,pp);
02470 }
02471
02472
02473 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02474 void *p0, const char *s0, int i0)
02475 {
02476
02477
02478 const char *ss[5] = {s0,0,0,0,0};
02479 int ii[5] = {i0,0,0,0,0};
02480 void *pp[5] = {p0,0,0,0,0};
02481
02482 XrdProofdAux::Form(s,fmt,1,ss,1,ii,1,pp);
02483 }
02484
02485
02486 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02487 const char *s0, const char *s1, void *p0)
02488 {
02489
02490
02491 const char *ss[5] = {s0,s1,0,0,0};
02492 int ii[5] = {0,0,0,0,0};
02493 void *pp[5] = {p0,0,0,0,0};
02494
02495 XrdProofdAux::Form(s,fmt,2,ss,0,ii,1,pp);
02496 }
02497
02498
02499 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0,
02500 const char *s0, const char *s1, int i1, int i2)
02501 {
02502
02503
02504 const char *ss[5] = {s0,s1,0,0,0};
02505 int ii[5] = {i0,i1,i2,0,0};
02506 void *pp[5] = {0,0,0,0,0};
02507
02508 XrdProofdAux::Form(s,fmt,2,ss,3,ii,0,pp);
02509 }
02510
02511
02512 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0,
02513 const char *s0, int i1, int i2)
02514 {
02515
02516
02517 const char *ss[5] = {s0,0,0,0,0};
02518 int ii[5] = {i0,i1,i2,0,0};
02519 void *pp[5] = {0,0,0,0,0};
02520
02521 XrdProofdAux::Form(s,fmt,1,ss,3,ii,0,pp);
02522 }
02523