root/opal/mca/pmix/pmix4x/pmix/src/include/pmix_globals.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cfcon
  2. cfdes
  3. cdcon
  4. cddes
  5. nscon
  6. nsdes
  7. ncdcon
  8. ncddes
  9. info_con
  10. info_des
  11. pcon
  12. pdes
  13. iofreqcon
  14. iofreqdes
  15. scon
  16. scdes
  17. cbcon
  18. cbdes
  19. ifcon
  20. ifdes
  21. qcon
  22. qdes
  23. pmix_execute_epilog
  24. dirpath_destroy
  25. dirpath_is_empty
  26. pmix_event_assign
  27. pmix_event_new

   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2014-2019 Intel, Inc.  All rights reserved.
   4  * Copyright (c) 2014-2019 Research Organization for Information Science
   5  *                         and Technology (RIST).  All rights reserved.
   6  * Copyright (c) 2014-2015 Artem Y. Polyakov <artpol84@gmail.com>.
   7  *                         All rights reserved.
   8  * Copyright (c) 2016      IBM Corporation.  All rights reserved.
   9  * Copyright (c) 2019      Mellanox Technologies, Inc.
  10  *                         All rights reserved.
  11  * $COPYRIGHT$
  12  *
  13  * Additional copyrights may follow
  14  *
  15  * $HEADER$
  16  */
  17 
  18 /* THIS FILE IS INCLUDED SOLELY TO INSTANTIATE AND INIT/FINALIZE THE GLOBAL CLASSES */
  19 
  20 #include <src/include/pmix_config.h>
  21 
  22 #include <pmix_common.h>
  23 #include <src/include/types.h>
  24 #include <src/include/pmix_stdint.h>
  25 #include <src/include/pmix_socket_errno.h>
  26 
  27 #include "src/include/pmix_globals.h"
  28 
  29 #ifdef HAVE_STRING_H
  30 #include <string.h>
  31 #endif
  32 #include <fcntl.h>
  33 #ifdef HAVE_UNISTD_H
  34 #include <unistd.h>
  35 #endif
  36 #ifdef HAVE_SYS_TYPES_H
  37 #include <sys/types.h>
  38 #endif
  39 #include <ctype.h>
  40 #include PMIX_EVENT_HEADER
  41 #if HAVE_SYS_STAT_H
  42 #include <sys/stat.h>
  43 #endif /* HAVE_SYS_STAT_H */
  44 #ifdef HAVE_DIRENT_H
  45 #include <dirent.h>
  46 #endif  /* HAVE_DIRENT_H */
  47 
  48 #include <pmix_common.h>
  49 
  50 #include "src/mca/bfrops/bfrops_types.h"
  51 #include "src/class/pmix_hash_table.h"
  52 #include "src/class/pmix_list.h"
  53 #include "src/threads/threads.h"
  54 #include "src/util/argv.h"
  55 #include "src/util/os_path.h"
  56 
  57 static void dirpath_destroy(char *path, pmix_cleanup_dir_t *cd,
  58                             pmix_epilog_t *epi);
  59 static bool dirpath_is_empty(const char *path);
  60 
  61 PMIX_EXPORT pmix_lock_t pmix_global_lock = {
  62     .mutex = PMIX_MUTEX_STATIC_INIT,
  63     .cond = PMIX_CONDITION_STATIC_INIT,
  64     .active = false
  65 };
  66 
  67 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_namelist_t,
  68                                 pmix_list_item_t,
  69                                 NULL, NULL);
  70 
  71 static void cfcon(pmix_cleanup_file_t *p)
  72 {
  73     p->path = NULL;
  74 }
  75 static void cfdes(pmix_cleanup_file_t *p)
  76 {
  77     if (NULL != p->path) {
  78         free(p->path);
  79     }
  80 }
  81 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_cleanup_file_t,
  82                                 pmix_list_item_t,
  83                                 cfcon, cfdes);
  84 
  85 static void cdcon(pmix_cleanup_dir_t *p)
  86 {
  87     p->path = NULL;
  88     p->recurse = false;
  89     p->leave_topdir = false;
  90 }
  91 static void cddes(pmix_cleanup_dir_t *p)
  92 {
  93     if (NULL != p->path) {
  94         free(p->path);
  95     }
  96 }
  97 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_cleanup_dir_t,
  98                                 pmix_list_item_t,
  99                                 cdcon, cddes);
 100 
 101 static void nscon(pmix_namespace_t *p)
 102 {
 103     p->nspace = NULL;
 104     p->nprocs = 0;
 105     p->nlocalprocs = 0;
 106     p->all_registered = false;
 107     p->version_stored = false;
 108     p->jobbkt = NULL;
 109     p->ndelivered = 0;
 110     p->nfinalized = 0;
 111     PMIX_CONSTRUCT(&p->ranks, pmix_list_t);
 112     memset(&p->compat, 0, sizeof(p->compat));
 113     PMIX_CONSTRUCT(&p->epilog.cleanup_dirs, pmix_list_t);
 114     PMIX_CONSTRUCT(&p->epilog.cleanup_files, pmix_list_t);
 115     PMIX_CONSTRUCT(&p->epilog.ignores, pmix_list_t);
 116     PMIX_CONSTRUCT(&p->setup_data, pmix_list_t);
 117 }
 118 static void nsdes(pmix_namespace_t *p)
 119 {
 120     if (NULL != p->nspace) {
 121         free(p->nspace);
 122     }
 123     if (NULL != p->jobbkt) {
 124         PMIX_RELEASE(p->jobbkt);
 125     }
 126     PMIX_LIST_DESTRUCT(&p->ranks);
 127     /* perform any epilog */
 128     pmix_execute_epilog(&p->epilog);
 129     /* cleanup the epilog */
 130     PMIX_LIST_DESTRUCT(&p->epilog.cleanup_dirs);
 131     PMIX_LIST_DESTRUCT(&p->epilog.cleanup_files);
 132     PMIX_LIST_DESTRUCT(&p->epilog.ignores);
 133     PMIX_LIST_DESTRUCT(&p->setup_data);
 134 }
 135 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_namespace_t,
 136                                 pmix_list_item_t,
 137                                 nscon, nsdes);
 138 
 139 static void ncdcon(pmix_nspace_caddy_t *p)
 140 {
 141     p->ns = NULL;
 142 }
 143 static void ncddes(pmix_nspace_caddy_t *p)
 144 {
 145     if (NULL != p->ns) {
 146         PMIX_RELEASE(p->ns);
 147     }
 148 }
 149 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_nspace_caddy_t,
 150                                 pmix_list_item_t,
 151                                 ncdcon, ncddes);
 152 
 153 static void info_con(pmix_rank_info_t *info)
 154 {
 155     info->peerid = -1;
 156     info->gid = info->uid = 0;
 157     info->pname.nspace = NULL;
 158     info->pname.rank = PMIX_RANK_UNDEF;
 159     info->modex_recvd = false;
 160     info->proc_cnt = 0;
 161     info->server_object = NULL;
 162 }
 163 static void info_des(pmix_rank_info_t *info)
 164 {
 165     if (NULL != info->pname.nspace) {
 166         free(info->pname.nspace);
 167     }
 168 }
 169 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_rank_info_t,
 170                                 pmix_list_item_t,
 171                                 info_con, info_des);
 172 
 173 static void pcon(pmix_peer_t *p)
 174 {
 175     p->proc_type = PMIX_PROC_UNDEF;
 176     p->protocol = PMIX_PROTOCOL_UNDEF;
 177     p->finalized = false;
 178     p->info = NULL;
 179     p->proc_cnt = 0;
 180     p->index = 0;
 181     p->sd = -1;
 182     p->send_ev_active = false;
 183     p->recv_ev_active = false;
 184     PMIX_CONSTRUCT(&p->send_queue, pmix_list_t);
 185     p->send_msg = NULL;
 186     p->recv_msg = NULL;
 187     p->commit_cnt = 0;
 188     PMIX_CONSTRUCT(&p->epilog.cleanup_dirs, pmix_list_t);
 189     PMIX_CONSTRUCT(&p->epilog.cleanup_files, pmix_list_t);
 190     PMIX_CONSTRUCT(&p->epilog.ignores, pmix_list_t);
 191 
 192 }
 193 
 194 static void pdes(pmix_peer_t *p)
 195 {
 196     if (0 <= p->sd) {
 197         CLOSE_THE_SOCKET(p->sd);
 198     }
 199     if (p->send_ev_active) {
 200         pmix_event_del(&p->send_event);
 201     }
 202     if (p->recv_ev_active) {
 203         pmix_event_del(&p->recv_event);
 204     }
 205 
 206     if (NULL != p->info) {
 207         PMIX_RELEASE(p->info);
 208     }
 209 
 210     PMIX_LIST_DESTRUCT(&p->send_queue);
 211     if (NULL != p->send_msg) {
 212         PMIX_RELEASE(p->send_msg);
 213     }
 214     if (NULL != p->recv_msg) {
 215         PMIX_RELEASE(p->recv_msg);
 216     }
 217     /* perform any epilog */
 218     pmix_execute_epilog(&p->epilog);
 219     /* cleanup the epilog */
 220     PMIX_LIST_DESTRUCT(&p->epilog.cleanup_dirs);
 221     PMIX_LIST_DESTRUCT(&p->epilog.cleanup_files);
 222     PMIX_LIST_DESTRUCT(&p->epilog.ignores);
 223     if (NULL != p->nptr) {
 224         PMIX_RELEASE(p->nptr);
 225     }
 226 }
 227 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_peer_t,
 228                                 pmix_object_t,
 229                                 pcon, pdes);
 230 
 231 static void iofreqcon(pmix_iof_req_t *p)
 232 {
 233     p->peer = NULL;
 234     memset(&p->pname, 0, sizeof(pmix_name_t));
 235     p->channels = PMIX_FWD_NO_CHANNELS;
 236     p->cbfunc = NULL;
 237 }
 238 static void iofreqdes(pmix_iof_req_t *p)
 239 {
 240     if (NULL != p->peer) {
 241         PMIX_RELEASE(p->peer);
 242     }
 243     if (NULL != p->pname.nspace) {
 244         free(p->pname.nspace);
 245     }
 246 }
 247 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_iof_req_t,
 248                                 pmix_list_item_t,
 249                                 iofreqcon, iofreqdes);
 250 
 251 
 252 static void scon(pmix_shift_caddy_t *p)
 253 {
 254     PMIX_CONSTRUCT_LOCK(&p->lock);
 255     p->codes = NULL;
 256     p->ncodes = 0;
 257     p->pname.nspace = NULL;
 258     p->pname.rank = PMIX_RANK_UNDEF;
 259     p->data = NULL;
 260     p->ndata = 0;
 261     p->key = NULL;
 262     p->info = NULL;
 263     p->ninfo = 0;
 264     p->directives = NULL;
 265     p->ndirs = 0;
 266     p->evhdlr = NULL;
 267     p->iofreq = NULL;
 268     p->kv = NULL;
 269     p->vptr = NULL;
 270     p->cd = NULL;
 271     p->tracker = NULL;
 272     p->enviro = false;
 273     p->cbfunc.relfn = NULL;
 274     p->cbdata = NULL;
 275     p->ref = 0;
 276 }
 277 static void scdes(pmix_shift_caddy_t *p)
 278 {
 279     PMIX_DESTRUCT_LOCK(&p->lock);
 280     if (NULL != p->pname.nspace) {
 281         free(p->pname.nspace);
 282     }
 283     if (NULL != p->kv) {
 284         PMIX_RELEASE(p->kv);
 285     }
 286 }
 287 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_shift_caddy_t,
 288                                 pmix_object_t,
 289                                 scon, scdes);
 290 
 291 static void cbcon(pmix_cb_t *p)
 292 {
 293     PMIX_CONSTRUCT_LOCK(&p->lock);
 294     p->checked = false;
 295     PMIX_CONSTRUCT(&p->data, pmix_buffer_t);
 296     p->cbfunc.ptlfn = NULL;
 297     p->cbdata = NULL;
 298     p->pname.nspace = NULL;
 299     p->pname.rank = PMIX_RANK_UNDEF;
 300     p->scope = PMIX_SCOPE_UNDEF;
 301     p->key = NULL;
 302     p->value = NULL;
 303     p->procs = NULL;
 304     p->nprocs = 0;
 305     p->info = NULL;
 306     p->ninfo = 0;
 307     p->nvals = 0;
 308     PMIX_CONSTRUCT(&p->kvs, pmix_list_t);
 309     p->copy = false;
 310     p->timer_running = false;
 311 }
 312 static void cbdes(pmix_cb_t *p)
 313 {
 314     if (p->timer_running) {
 315         pmix_event_del(&p->ev);
 316     }
 317     if (NULL != p->pname.nspace) {
 318         free(p->pname.nspace);
 319     }
 320     PMIX_DESTRUCT(&p->data);
 321     PMIX_LIST_DESTRUCT(&p->kvs);
 322 }
 323 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_cb_t,
 324                                 pmix_list_item_t,
 325                                 cbcon, cbdes);
 326 
 327 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_info_caddy_t,
 328                                 pmix_list_item_t,
 329                                 NULL, NULL);
 330 
 331 static void ifcon(pmix_infolist_t *p)
 332 {
 333     PMIX_INFO_CONSTRUCT(&p->info);
 334 }
 335 static void ifdes(pmix_infolist_t *p)
 336 {
 337     PMIX_INFO_DESTRUCT(&p->info);
 338 }
 339 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_infolist_t,
 340                                 pmix_list_item_t,
 341                                 ifcon, ifdes);
 342 
 343 static void qcon(pmix_query_caddy_t *p)
 344 {
 345     PMIX_CONSTRUCT_LOCK(&p->lock);
 346     p->queries = NULL;
 347     p->nqueries = 0;
 348     p->targets = NULL;
 349     p->ntargets = 0;
 350     p->info = NULL;
 351     p->ninfo = 0;
 352     PMIX_BYTE_OBJECT_CONSTRUCT(&p->bo);
 353     PMIX_CONSTRUCT(&p->results, pmix_list_t);
 354     p->cbfunc = NULL;
 355     p->valcbfunc = NULL;
 356     p->cbdata = NULL;
 357     p->relcbfunc = NULL;
 358     p->credcbfunc = NULL;
 359     p->validcbfunc = NULL;
 360 }
 361 static void qdes(pmix_query_caddy_t *p)
 362 {
 363     PMIX_DESTRUCT_LOCK(&p->lock);
 364     PMIX_BYTE_OBJECT_DESTRUCT(&p->bo);
 365     PMIX_PROC_FREE(p->targets, p->ntargets);
 366     PMIX_INFO_FREE(p->info, p->ninfo);
 367     PMIX_LIST_DESTRUCT(&p->results);
 368 }
 369 PMIX_EXPORT PMIX_CLASS_INSTANCE(pmix_query_caddy_t,
 370                                 pmix_object_t,
 371                                 qcon, qdes);
 372 
 373 void pmix_execute_epilog(pmix_epilog_t *epi)
 374 {
 375     pmix_cleanup_file_t *cf, *cfnext;
 376     pmix_cleanup_dir_t *cd, *cdnext;
 377     struct stat statbuf;
 378     int rc;
 379     char **tmp;
 380     size_t n;
 381 
 382     /* start with any specified files */
 383     PMIX_LIST_FOREACH_SAFE(cf, cfnext, &epi->cleanup_files, pmix_cleanup_file_t) {
 384         /* check the effective uid/gid of the file and ensure it
 385          * matches that of the peer - we do this to provide at least
 386          * some minimum level of protection */
 387         tmp = pmix_argv_split(cf->path, ',');
 388         for (n=0; NULL != tmp[n]; n++) {
 389             rc = stat(tmp[n], &statbuf);
 390             if (0 != rc) {
 391                 pmix_output_verbose(10, pmix_globals.debug_output,
 392                                     "File %s failed to stat: %d", tmp[n], rc);
 393                 continue;
 394             }
 395             if (statbuf.st_uid != epi->uid ||
 396                 statbuf.st_gid != epi->gid) {
 397                 pmix_output_verbose(10, pmix_globals.debug_output,
 398                                     "File %s uid/gid doesn't match: uid %lu(%lu) gid %lu(%lu)",
 399                                     cf->path,
 400                                     (unsigned long)statbuf.st_uid, (unsigned long)epi->uid,
 401                                     (unsigned long)statbuf.st_gid, (unsigned long)epi->gid);
 402                 continue;
 403             }
 404             rc = unlink(tmp[n]);
 405             if (0 != rc) {
 406                 pmix_output_verbose(10, pmix_globals.debug_output,
 407                                     "File %s failed to unlink: %d", tmp[n], rc);
 408             }
 409         }
 410         pmix_argv_free(tmp);
 411         pmix_list_remove_item(&epi->cleanup_files, &cf->super);
 412         PMIX_RELEASE(cf);
 413     }
 414 
 415     /* now cleanup the directories */
 416     PMIX_LIST_FOREACH_SAFE(cd, cdnext, &epi->cleanup_dirs, pmix_cleanup_dir_t) {
 417         /* check the effective uid/gid of the file and ensure it
 418          * matches that of the peer - we do this to provide at least
 419          * some minimum level of protection */
 420         tmp = pmix_argv_split(cd->path, ',');
 421         for (n=0; NULL != tmp[n]; n++) {
 422             rc = stat(tmp[n], &statbuf);
 423             if (0 != rc) {
 424                 pmix_output_verbose(10, pmix_globals.debug_output,
 425                                     "Directory %s failed to stat: %d", tmp[n], rc);
 426                 continue;
 427             }
 428             if (statbuf.st_uid != epi->uid ||
 429                 statbuf.st_gid != epi->gid) {
 430                 pmix_output_verbose(10, pmix_globals.debug_output,
 431                                     "Directory %s uid/gid doesn't match: uid %lu(%lu) gid %lu(%lu)",
 432                                     cd->path,
 433                                     (unsigned long)statbuf.st_uid, (unsigned long)epi->uid,
 434                                     (unsigned long)statbuf.st_gid, (unsigned long)epi->gid);
 435                 continue;
 436             }
 437             if ((statbuf.st_mode & S_IRWXU) == S_IRWXU) {
 438                 dirpath_destroy(tmp[n], cd, epi);
 439             } else {
 440                 pmix_output_verbose(10, pmix_globals.debug_output,
 441                                     "Directory %s lacks permissions", tmp[n]);
 442             }
 443         }
 444         pmix_argv_free(tmp);
 445         pmix_list_remove_item(&epi->cleanup_dirs, &cd->super);
 446         PMIX_RELEASE(cd);
 447     }
 448 }
 449 
 450 static void dirpath_destroy(char *path, pmix_cleanup_dir_t *cd, pmix_epilog_t *epi)
 451 {
 452     int rc;
 453     bool is_dir = false;
 454     DIR *dp;
 455     struct dirent *ep;
 456     char *filenm;
 457     struct stat buf;
 458     pmix_cleanup_file_t *cf;
 459 
 460     if (NULL == path) {  /* protect against error */
 461         return;
 462     }
 463 
 464     /* if this path is it to be ignored, then do so */
 465     PMIX_LIST_FOREACH(cf, &epi->ignores, pmix_cleanup_file_t) {
 466         if (0 == strcmp(cf->path, path)) {
 467             return;
 468         }
 469     }
 470 
 471     /* Open up the directory */
 472     dp = opendir(path);
 473     if (NULL == dp) {
 474         return;
 475     }
 476 
 477     while (NULL != (ep = readdir(dp))) {
 478         /* skip:
 479          *  - . and ..
 480          */
 481         if ((0 == strcmp(ep->d_name, ".")) ||
 482             (0 == strcmp(ep->d_name, ".."))) {
 483             continue;
 484         }
 485 
 486         /* Create a pathname.  This is not always needed, but it makes
 487          * for cleaner code just to create it here.  Note that we are
 488          * allocating memory here, so we need to free it later on.
 489          */
 490         filenm = pmix_os_path(false, path, ep->d_name, NULL);
 491 
 492         /* if this path is to be ignored, then do so */
 493         PMIX_LIST_FOREACH(cf, &epi->ignores, pmix_cleanup_file_t) {
 494             if (0 == strcmp(cf->path, filenm)) {
 495                 free(filenm);
 496                 filenm = NULL;
 497                 break;
 498             }
 499         }
 500         if (NULL == filenm) {
 501             continue;
 502         }
 503 
 504         /* Check to see if it is a directory */
 505         is_dir = false;
 506 
 507         rc = stat(filenm, &buf);
 508         if (0 > rc) {
 509             /* Handle a race condition. filenm might have been deleted by an
 510              * other process running on the same node. That typically occurs
 511              * when one task is removing the job_session_dir and an other task
 512              * is still removing its proc_session_dir.
 513              */
 514             free(filenm);
 515             continue;
 516         }
 517         /* if the uid/gid don't match, then leave it alone */
 518         if (buf.st_uid != epi->uid ||
 519             buf.st_gid != epi->gid) {
 520             free(filenm);
 521             continue;
 522         }
 523 
 524         if (S_ISDIR(buf.st_mode)) {
 525             is_dir = true;
 526         }
 527 
 528         /*
 529          * If not recursively decending, then if we find a directory then fail
 530          * since we were not told to remove it.
 531          */
 532         if (is_dir && !cd->recurse) {
 533             /* continue removing files */
 534             free(filenm);
 535             continue;
 536         }
 537 
 538         /* Directories are recursively destroyed */
 539         if (is_dir && cd->recurse && ((buf.st_mode & S_IRWXU) == S_IRWXU)) {
 540             dirpath_destroy(filenm, cd, epi);
 541             free(filenm);
 542         } else {
 543             /* Files are removed right here */
 544             unlink(filenm);
 545             free(filenm);
 546         }
 547     }
 548 
 549     /* Done with this directory */
 550     closedir(dp);
 551 
 552     /* If the directory is empty, then remove it unless we
 553      * were told to leave it */
 554     if (0 == strcmp(path, cd->path) && cd->leave_topdir) {
 555         return;
 556     }
 557     if (dirpath_is_empty(path)) {
 558         rmdir(path);
 559     }
 560 }
 561 
 562 static bool dirpath_is_empty(const char *path )
 563 {
 564     DIR *dp;
 565     struct dirent *ep;
 566 
 567     if (NULL != path) {  /* protect against error */
 568         dp = opendir(path);
 569         if (NULL != dp) {
 570             while ((ep = readdir(dp))) {
 571                         if ((0 != strcmp(ep->d_name, ".")) &&
 572                             (0 != strcmp(ep->d_name, ".."))) {
 573                             closedir(dp);
 574                             return false;
 575                         }
 576             }
 577             closedir(dp);
 578             return true;
 579         }
 580         return false;
 581     }
 582 
 583     return true;
 584 }
 585 
 586 int pmix_event_assign(struct event *ev, pmix_event_base_t *evbase,
 587                       int fd, short arg, event_callback_fn cbfn, void *cbd)
 588 {
 589 #if PMIX_HAVE_LIBEV
 590     event_set(ev, fd, arg, cbfn, cbd);
 591     event_base_set(evbase, ev);
 592 #else
 593     event_assign(ev, evbase, fd, arg, cbfn, cbd);
 594 #endif
 595     return 0;
 596 }
 597 
 598 pmix_event_t* pmix_event_new(pmix_event_base_t *b, int fd,
 599                              short fg, event_callback_fn cbfn, void *cbd)
 600 {
 601     pmix_event_t *ev = NULL;
 602 
 603 #if PMIX_HAVE_LIBEV
 604     ev = (pmix_event_t*)calloc(1, sizeof(pmix_event_t));
 605     ev->ev_base = b;
 606 #else
 607     ev = event_new(b, fd, fg, (event_callback_fn) cbfn, cbd);
 608 #endif
 609 
 610     return ev;
 611 }

/* [<][>][^][v][top][bottom][index][help] */