PageRenderTime 66ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/common/hostlist.c

https://github.com/cfenoy/slurm
C | 3862 lines | 2680 code | 644 blank | 538 comment | 726 complexity | 7b88cc68a24d92279e53c853d9951f8f MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. /*****************************************************************************\
  2. * $Id$
  3. *****************************************************************************
  4. * $LSDId: hostlist.c,v 1.14 2003/10/14 20:11:54 grondo Exp $
  5. *****************************************************************************
  6. * Copyright (C) 2002 The Regents of the University of California.
  7. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  8. * Written by Mark Grondona <mgrondona@llnl.gov>
  9. * CODE-OCEC-09-009. All rights reserved.
  10. *
  11. * This file is part of SLURM, a resource management program.
  12. * For details, see <http://www.schedmd.com/slurmdocs/>.
  13. * Please also read the included file: DISCLAIMER.
  14. *
  15. * SLURM is free software; you can redistribute it and/or modify it under
  16. * the terms of the GNU General Public License as published by the Free
  17. * Software Foundation; either version 2 of the License, or (at your option)
  18. * any later version.
  19. *
  20. * In addition, as a special exception, the copyright holders give permission
  21. * to link the code of portions of this program with the OpenSSL library under
  22. * certain conditions as described in each individual source file, and
  23. * distribute linked combinations including the two. You must obey the GNU
  24. * General Public License in all respects for all of the code used other than
  25. * OpenSSL. If you modify file(s) with this exception, you may extend this
  26. * exception to your version of the file(s), but you are not obligated to do
  27. * so. If you do not wish to do so, delete this exception statement from your
  28. * version. If you delete this exception statement from all source files in
  29. * the program, then also delete it here.
  30. *
  31. * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
  32. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  33. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  34. * details.
  35. *
  36. * You should have received a copy of the GNU General Public License along
  37. * with SLURM; if not, write to the Free Software Foundation, Inc.,
  38. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  39. \*****************************************************************************/
  40. #ifdef HAVE_CONFIG_H
  41. # include "config.h"
  42. # if HAVE_INTTYPES_H
  43. # include <inttypes.h>
  44. # else
  45. # if HAVE_STDINT_H
  46. # include <stdint.h>
  47. # endif
  48. # endif /* HAVE_INTTYPES_H */
  49. # if HAVE_STRING_H
  50. # include <string.h>
  51. # endif
  52. # if HAVE_PTHREAD_H
  53. # include <pthread.h>
  54. # endif
  55. #else /* !HAVE_CONFIG_H */
  56. # include <inttypes.h>
  57. # include <string.h>
  58. # include <pthread.h>
  59. #endif /* HAVE_CONFIG_H */
  60. #include <stdio.h>
  61. #include <stdlib.h>
  62. #include <stdarg.h>
  63. #include <assert.h>
  64. #include <errno.h>
  65. #include <ctype.h>
  66. #include <sys/param.h>
  67. #include <unistd.h>
  68. #include <slurm/slurmdb.h>
  69. #include "src/common/hostlist.h"
  70. #include "src/common/log.h"
  71. #include "src/common/macros.h"
  72. #include "src/common/xmalloc.h"
  73. #include "src/common/timers.h"
  74. #include "src/common/xassert.h"
  75. #include "src/common/working_cluster.h"
  76. /*
  77. * Define slurm-specific aliases for use by plugins, see slurm_xlator.h
  78. * for details.
  79. */
  80. strong_alias(hostlist_create_dims, slurm_hostlist_create_dims);
  81. strong_alias(hostlist_create, slurm_hostlist_create);
  82. strong_alias(hostlist_copy, slurm_hostlist_copy);
  83. strong_alias(hostlist_count, slurm_hostlist_count);
  84. strong_alias(hostlist_delete, slurm_hostlist_delete);
  85. strong_alias(hostlist_delete_host, slurm_hostlist_delete_host);
  86. strong_alias(hostlist_delete_nth, slurm_hostlist_delete_nth);
  87. strong_alias(hostlist_deranged_string_dims,
  88. slurm_hostlist_deranged_string_dims);
  89. strong_alias(hostlist_deranged_string, slurm_hostlist_deranged_string);
  90. strong_alias(hostlist_deranged_string_malloc,
  91. slurm_hostlist_deranged_string_malloc);
  92. strong_alias(hostlist_deranged_string_xmalloc_dims,
  93. slurm_hostlist_deranged_string_xmalloc_dims);
  94. strong_alias(hostlist_deranged_string_xmalloc,
  95. slurm_hostlist_deranged_string_xmalloc);
  96. strong_alias(hostlist_destroy, slurm_hostlist_destroy);
  97. strong_alias(hostlist_find, slurm_hostlist_find);
  98. strong_alias(hostlist_iterator_create, slurm_hostlist_iterator_create);
  99. strong_alias(hostlist_iterator_destroy, slurm_hostlist_iterator_destroy);
  100. strong_alias(hostlist_iterator_reset, slurm_hostlist_iterator_reset);
  101. strong_alias(hostlist_next, slurm_hostlist_next);
  102. strong_alias(hostlist_next_range, slurm_hostlist_next_range);
  103. strong_alias(hostlist_nth, slurm_hostlist_nth);
  104. strong_alias(hostlist_pop, slurm_hostlist_pop);
  105. strong_alias(hostlist_pop_range, slurm_hostlist_pop_range);
  106. strong_alias(hostlist_push, slurm_hostlist_push);
  107. strong_alias(hostlist_push_host_dims, slurm_hostlist_push_host_dims);
  108. strong_alias(hostlist_push_host, slurm_hostlist_push_host);
  109. strong_alias(hostlist_push_list, slurm_hostlist_push_list);
  110. strong_alias(hostlist_ranged_string_dims,
  111. slurm_hostlist_ranged_string_dims);
  112. strong_alias(hostlist_ranged_string, slurm_hostlist_ranged_string);
  113. strong_alias(hostlist_ranged_string_malloc,
  114. slurm_hostlist_ranged_string_malloc);
  115. strong_alias(hostlist_ranged_string_xmalloc_dims,
  116. slurm_hostlist_ranged_string_xmalloc_dims);
  117. strong_alias(hostlist_ranged_string_xmalloc,
  118. slurm_hostlist_ranged_string_xmalloc);
  119. strong_alias(hostlist_remove, slurm_hostlist_remove);
  120. strong_alias(hostlist_shift, slurm_hostlist_shift);
  121. strong_alias(hostlist_shift_range, slurm_hostlist_shift_range);
  122. strong_alias(hostlist_sort, slurm_hostlist_soft);
  123. strong_alias(hostlist_uniq, slurm_hostlist_uniq);
  124. strong_alias(hostset_copy, slurm_hostset_copy);
  125. strong_alias(hostset_count, slurm_hostset_count);
  126. strong_alias(hostset_create, slurm_hostset_create);
  127. strong_alias(hostset_delete, slurm_hostset_delete);
  128. strong_alias(hostset_destroy, slurm_hostset_destroy);
  129. strong_alias(hostset_find, slurm_hostset_find);
  130. strong_alias(hostset_insert, slurm_hostset_insert);
  131. strong_alias(hostset_shift, slurm_hostset_shift);
  132. strong_alias(hostset_shift_range, slurm_hostset_shift_range);
  133. strong_alias(hostset_within, slurm_hostset_within);
  134. strong_alias(hostset_nth, slurm_hostset_nth);
  135. /*
  136. * lsd_fatal_error : fatal error macro
  137. */
  138. #ifdef WITH_LSD_FATAL_ERROR_FUNC
  139. # undef lsd_fatal_error
  140. extern void lsd_fatal_error(char *file, int line, char *mesg);
  141. #else /* !WITH_LSD_FATAL_ERROR_FUNC */
  142. # ifndef lsd_fatal_error
  143. # define lsd_fatal_error(file, line, mesg) \
  144. do { \
  145. fprintf(stderr, "ERROR: [%s:%d] %s: %s\n", \
  146. file, line, mesg, strerror(errno)); \
  147. } while (0)
  148. # endif /* !lsd_fatal_error */
  149. #endif /* !WITH_LSD_FATAL_ERROR_FUNC */
  150. /*
  151. * lsd_nonmem_error
  152. */
  153. #ifdef WITH_LSD_NOMEM_ERROR_FUNC
  154. # undef lsd_nomem_error
  155. extern void * lsd_nomem_error(char *file, int line, char *mesg);
  156. #else /* !WITH_LSD_NOMEM_ERROR_FUNC */
  157. # ifndef lsd_nomem_error
  158. # define lsd_nomem_error(file, line, mesg) (NULL)
  159. # endif /* !lsd_nomem_error */
  160. #endif /* !WITH_LSD_NOMEM_ERROR_FUNC */
  161. /*
  162. * OOM helper function
  163. * Automatically call lsd_nomem_error with appropriate args
  164. * and set errno to ENOMEM
  165. */
  166. #define out_of_memory(mesg) \
  167. do { \
  168. fatal("malloc failure"); \
  169. errno = ENOMEM; \
  170. return(lsd_nomem_error(__FILE__, __LINE__, mesg)); \
  171. } while (0)
  172. /*
  173. * Some constants and tunables:
  174. */
  175. /* number of elements to allocate when extending the hostlist array */
  176. #define HOSTLIST_CHUNK 16
  177. /* max host range: anything larger will be assumed to be an error */
  178. #define MAX_RANGE (64*1024) /* 64K Hosts */
  179. /* max number of ranges that will be processed between brackets */
  180. #define MAX_RANGES (12*1024) /* 12K Ranges */
  181. /* size of internal hostname buffer (+ some slop), hostnames will probably
  182. * be truncated if longer than MAXHOSTNAMELEN */
  183. #ifndef MAXHOSTNAMELEN
  184. #define MAXHOSTNAMELEN 64
  185. #endif
  186. /* ----[ Internal Data Structures ]---- */
  187. /* hostname type: A convenience structure used in parsing single hostnames */
  188. struct hostname_components {
  189. char *hostname; /* cache of initialized hostname */
  190. char *prefix; /* hostname prefix */
  191. unsigned long num; /* numeric suffix */
  192. /* string representation of numeric suffix
  193. * points into `hostname' */
  194. char *suffix;
  195. };
  196. typedef struct hostname_components *hostname_t;
  197. /* hostrange type: A single prefix with `hi' and `lo' numeric suffix values */
  198. struct hostrange_components {
  199. char *prefix; /* alphanumeric prefix: */
  200. /* beginning (lo) and end (hi) of suffix range */
  201. unsigned long lo, hi;
  202. /* width of numeric output format
  203. * (pad with zeros up to this width) */
  204. int width;
  205. /* If singlehost is 1, `lo' and `hi' are invalid */
  206. unsigned singlehost:1;
  207. };
  208. typedef struct hostrange_components *hostrange_t;
  209. /* The hostlist type: An array based list of hostrange_t's */
  210. struct hostlist {
  211. #ifndef NDEBUG
  212. #define HOSTLIST_MAGIC 57005
  213. int magic;
  214. #endif
  215. #if WITH_PTHREADS
  216. pthread_mutex_t mutex;
  217. #endif /* WITH_PTHREADS */
  218. /* current number of elements available in array */
  219. int size;
  220. /* current number of ranges stored in array */
  221. int nranges;
  222. /* current number of hosts stored in hostlist */
  223. int nhosts;
  224. /* pointer to hostrange array */
  225. hostrange_t *hr;
  226. /* list of iterators */
  227. struct hostlist_iterator *ilist;
  228. };
  229. /* a hostset is a wrapper around a hostlist */
  230. struct hostset {
  231. hostlist_t hl;
  232. };
  233. struct hostlist_iterator {
  234. #ifndef NDEBUG
  235. int magic;
  236. #endif
  237. /* hostlist we are traversing */
  238. hostlist_t hl;
  239. /* current index of iterator in hl->hr[] */
  240. int idx;
  241. /* current hostrange object in list hl, i.e. hl->hr[idx] */
  242. hostrange_t hr;
  243. /* current depth we've traversed into range hr */
  244. int depth;
  245. /* next ptr for lists of iterators */
  246. struct hostlist_iterator *next;
  247. };
  248. struct _range {
  249. unsigned long lo, hi;
  250. int width;
  251. };
  252. /* ---- ---- */
  253. /* Multi-dimension system stuff here */
  254. char *alpha_num = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  255. /* logic for block node description */
  256. /* to speed things up we will do some calculations once to avoid
  257. * having to do it multiple times. We need to calculate the size of
  258. * the maximum sized array for each dimension. This way we can be
  259. * prepared for any size coming in.
  260. */
  261. static bool grid[HIGHEST_BASE*HIGHEST_BASE*HIGHEST_BASE*HIGHEST_BASE*HIGHEST_BASE];
  262. static int grid_start[HIGHEST_DIMENSIONS];
  263. static int grid_end[HIGHEST_DIMENSIONS];
  264. static int offset[HIGHEST_DIMENSIONS];
  265. static int dim_grid_size = -1;
  266. /* used to protect the above grid, grid_start, and grid_end. */
  267. static pthread_mutex_t multi_dim_lock = PTHREAD_MUTEX_INITIALIZER;
  268. static int _tell_if_used(int dim, int curr,
  269. int *start,
  270. int *end,
  271. int *last,
  272. int *found, int dims);
  273. static int _get_next_box(int *start, int *end, int dims);
  274. static int _get_boxes(char *buf, int max_len, int dims, int brackets);
  275. static void _set_box_in_grid(int dim, int curr,
  276. int *start,
  277. int *end,
  278. bool value, int dims);
  279. static int _add_box_ranges(int dim, int curr,
  280. int *start,
  281. int *end,
  282. int *pos,
  283. struct _range *ranges,
  284. int len, int *count, int dims);
  285. static void _set_min_max_of_grid(int dim, int curr,
  286. int *start,
  287. int *end,
  288. int *min,
  289. int *max,
  290. int *pos, int dims);
  291. static void _set_grid(unsigned long start, unsigned long end, int dims);
  292. static bool _test_box_in_grid(int dim, int curr,
  293. int *start,
  294. int *end, int dims);
  295. static bool _test_box(int *start, int *end, int dims);
  296. /* ------[ static function prototypes ]------ */
  297. static void _error(char *file, int line, char *mesg, ...)
  298. __attribute__ ((format (printf, 3, 4)));
  299. static char * _next_tok(char *, char **);
  300. static int _zero_padded(unsigned long, int);
  301. static int _width_equiv(unsigned long, int *, unsigned long, int *);
  302. static int host_prefix_end(const char *, int dims);
  303. static hostname_t hostname_create(const char *);
  304. static void hostname_destroy(hostname_t);
  305. static int hostname_suffix_is_valid(hostname_t);
  306. static int hostname_suffix_width(hostname_t);
  307. static hostrange_t hostrange_new(void);
  308. static hostrange_t hostrange_create_single(const char *);
  309. static hostrange_t hostrange_create(char *, unsigned long, unsigned long,
  310. int);
  311. static unsigned long hostrange_count(hostrange_t);
  312. static hostrange_t hostrange_copy(hostrange_t);
  313. static void hostrange_destroy(hostrange_t);
  314. static hostrange_t hostrange_delete_host(hostrange_t, unsigned long);
  315. static int hostrange_cmp(hostrange_t, hostrange_t);
  316. static int hostrange_prefix_cmp(hostrange_t, hostrange_t);
  317. static int hostrange_within_range(hostrange_t, hostrange_t);
  318. static int hostrange_width_combine(hostrange_t, hostrange_t);
  319. static int hostrange_empty(hostrange_t);
  320. static char * hostrange_pop(hostrange_t);
  321. static char * hostrange_shift(hostrange_t);
  322. static int hostrange_join(hostrange_t, hostrange_t);
  323. static hostrange_t hostrange_intersect(hostrange_t, hostrange_t);
  324. static int hostrange_hn_within(hostrange_t, hostname_t);
  325. static size_t hostrange_to_string(hostrange_t hr, size_t, char *,
  326. char *, int);
  327. static size_t hostrange_numstr(hostrange_t, size_t, char *, int);
  328. static hostlist_t hostlist_new(void);
  329. static hostlist_t _hostlist_create_bracketed(const char *, char *,
  330. char *, int);
  331. static int hostlist_resize(hostlist_t, size_t);
  332. static int hostlist_expand(hostlist_t);
  333. static int hostlist_push_range(hostlist_t, hostrange_t);
  334. static int hostlist_push_hr(hostlist_t, char *, unsigned long,
  335. unsigned long, int);
  336. static int hostlist_insert_range(hostlist_t, hostrange_t, int);
  337. static void hostlist_delete_range(hostlist_t, int n);
  338. static void hostlist_coalesce(hostlist_t hl);
  339. static void hostlist_collapse(hostlist_t hl);
  340. static hostlist_t _hostlist_create(const char *, char *, char *, int);
  341. static void hostlist_shift_iterators(hostlist_t, int, int, int);
  342. static int _attempt_range_join(hostlist_t, int);
  343. static int _is_bracket_needed(hostlist_t, int);
  344. static hostlist_iterator_t hostlist_iterator_new(void);
  345. static void _iterator_advance(hostlist_iterator_t);
  346. static void _iterator_advance_range(hostlist_iterator_t);
  347. static int hostset_find_host(hostset_t, const char *);
  348. /* ------[ macros ]------ */
  349. #ifdef WITH_PTHREADS
  350. # define mutex_init(mutex) \
  351. do { \
  352. int e = pthread_mutex_init(mutex, NULL); \
  353. if (e) { \
  354. errno = e; \
  355. lsd_fatal_error(__FILE__, __LINE__, "hostlist mutex init:"); \
  356. abort(); \
  357. } \
  358. } while (0)
  359. # define mutex_lock(mutex) \
  360. do { \
  361. int e = pthread_mutex_lock(mutex); \
  362. if (e) { \
  363. errno = e; \
  364. lsd_fatal_error(__FILE__, __LINE__, "hostlist mutex lock:"); \
  365. abort(); \
  366. } \
  367. } while (0)
  368. # define mutex_unlock(mutex) \
  369. do { \
  370. int e = pthread_mutex_unlock(mutex); \
  371. if (e) { \
  372. errno = e; \
  373. lsd_fatal_error(__FILE__, __LINE__, "hostlist mutex unlock:"); \
  374. abort(); \
  375. } \
  376. } while (0)
  377. # define mutex_destroy(mutex) \
  378. do { \
  379. int e = pthread_mutex_destroy(mutex); \
  380. if (e) { \
  381. errno = e; \
  382. lsd_fatal_error(__FILE__, __LINE__, "hostlist mutex destroy:"); \
  383. abort(); \
  384. } \
  385. } while (0)
  386. #else /* !WITH_PTHREADS */
  387. # define mutex_init(mutex)
  388. # define mutex_lock(mutex)
  389. # define mutex_unlock(mutex)
  390. # define mutex_destroy(mutex)
  391. #endif /* WITH_PTHREADS */
  392. #define LOCK_HOSTLIST(_hl) \
  393. do { \
  394. assert(_hl != NULL); \
  395. mutex_lock(&(_hl)->mutex); \
  396. assert((_hl)->magic == HOSTLIST_MAGIC); \
  397. } while (0)
  398. #define UNLOCK_HOSTLIST(_hl) \
  399. do { \
  400. mutex_unlock(&(_hl)->mutex); \
  401. } while (0)
  402. #define seterrno_ret(_errno, _rc) \
  403. do { \
  404. errno = _errno; \
  405. return _rc; \
  406. } while (0)
  407. /* ------[ Function Definitions ]------ */
  408. /* ----[ general utility functions ]---- */
  409. /*
  410. * Varargs capable error reporting via lsd_fatal_error()
  411. */
  412. static void _error(char *file, int line, char *msg, ...)
  413. {
  414. va_list ap;
  415. char buf[1024];
  416. int len = 0;
  417. va_start(ap, msg);
  418. len = vsnprintf(buf, 1024, msg, ap);
  419. if ((len < 0) || (len > 1024))
  420. buf[1023] = '\0';
  421. lsd_fatal_error(file, line, buf);
  422. va_end(ap);
  423. return;
  424. }
  425. /*
  426. * Helper function for host list string parsing routines
  427. * Returns a pointer to the next token; additionally advance *str
  428. * to the next separator.
  429. *
  430. * next_tok was taken directly from pdsh courtesy of Jim Garlick.
  431. * (with modifications to support bracketed hostlists, i.e.:
  432. * xxx[xx,xx,xx] is a single token)
  433. *
  434. */
  435. static char * _next_tok(char *sep, char **str)
  436. {
  437. char *tok;
  438. /* push str past any leading separators */
  439. while ((**str != '\0') && (strchr(sep, **str) != NULL))
  440. (*str)++;
  441. if (**str == '\0')
  442. return NULL;
  443. /* assign token ptr */
  444. tok = *str;
  445. /* push str past token and leave pointing to first separator */
  446. while ((**str != '\0') && (strchr(sep, **str) == NULL))
  447. (*str)++;
  448. /* if _single_ opening bracket exists b/w tok and str,
  449. * push str past first closing bracket */
  450. if ((memchr(tok, '[', *str - tok) != NULL) &&
  451. (memchr(tok, ']', *str - tok) == NULL)) {
  452. char *q = strchr(*str, ']');
  453. if (q && (memchr(*str, '[', q - *str) == NULL))
  454. *str = ++q;
  455. /* push str past token and leave pointing to next separator */
  456. while ((**str != '\0') && (strchr(sep, **str) == NULL))
  457. (*str)++;
  458. /* if _second_ opening bracket exists b/w tok and str,
  459. * push str past second closing bracket */
  460. if ((**str != '\0') && q &&
  461. (memchr(tok, '[', *str - q) != NULL) &&
  462. (memchr(tok, ']', *str - q) == NULL)) {
  463. q = strchr(*str, ']');
  464. if (q && (memchr(*str, '[', q - *str) == NULL))
  465. *str = q + 1;
  466. }
  467. }
  468. /* nullify consecutive separators and push str beyond them */
  469. while ((**str != '\0') && (strchr(sep, **str) != '\0'))
  470. *(*str)++ = '\0';
  471. return tok;
  472. }
  473. /*
  474. * return the number of zeros needed to pad "num" to "width"
  475. */
  476. static int _zero_padded(unsigned long num, int width)
  477. {
  478. int n = 1;
  479. while (num /= 10L)
  480. n++;
  481. return (width > n) ? (width - n) : 0;
  482. }
  483. /*
  484. * test whether two format `width' parameters are "equivalent"
  485. * The width arguments "wn" and "wm" for integers "n" and "m"
  486. * are equivalent if:
  487. *
  488. * o wn == wm OR
  489. *
  490. * o applying the same format width (either wn or wm) to both of
  491. * 'n' and 'm' will not change the zero padding of *either* 'm' nor 'n'.
  492. *
  493. * If this function returns 1 (or true), the appropriate width value
  494. * (either 'wm' or 'wn') will have been adjusted such that both format
  495. * widths are equivalent.
  496. */
  497. static int _width_equiv(unsigned long n, int *wn, unsigned long m, int *wm)
  498. {
  499. int npad, nmpad, mpad, mnpad;
  500. if (*wn == *wm)
  501. return 1;
  502. npad = _zero_padded(n, *wn);
  503. nmpad = _zero_padded(n, *wm);
  504. mpad = _zero_padded(m, *wm);
  505. mnpad = _zero_padded(m, *wn);
  506. if ((npad != nmpad) && (mpad != mnpad))
  507. return 0;
  508. else if (npad != nmpad) /* mpad == mnpad: adjust wm */
  509. *wm = *wn;
  510. else /* npad == nmpad: adjust wn */
  511. *wn = *wm;
  512. return 1;
  513. }
  514. /* ----[ hostname_t functions ]---- */
  515. /*
  516. * return the location of the last char in the hostname prefix
  517. */
  518. static int host_prefix_end(const char *hostname, int dims)
  519. {
  520. int idx;
  521. assert(hostname != NULL);
  522. if (!dims)
  523. dims = slurmdb_setup_cluster_name_dims();
  524. idx = strlen(hostname) - 1;
  525. if (dims > 1) {
  526. while ((idx >= 0) &&
  527. (isdigit((int)hostname[idx]) ||
  528. isupper((int)hostname[idx])))
  529. idx--;
  530. } else {
  531. while ((idx >= 0) && isdigit((int)hostname[idx]))
  532. idx--;
  533. }
  534. return idx;
  535. }
  536. static hostname_t hostname_create_dims(const char *hostname, int dims)
  537. {
  538. hostname_t hn = NULL;
  539. char *p = '\0';
  540. int idx = 0;
  541. int hostlist_base;
  542. assert(hostname != NULL);
  543. if (!dims)
  544. dims = slurmdb_setup_cluster_name_dims();
  545. hostlist_base = hostlist_get_base(dims);
  546. if (!(hn = (hostname_t) malloc(sizeof(*hn))))
  547. out_of_memory("hostname create");
  548. idx = host_prefix_end(hostname, dims);
  549. if (!(hn->hostname = strdup(hostname))) {
  550. free(hn);
  551. out_of_memory("hostname create");
  552. }
  553. hn->num = 0;
  554. hn->prefix = NULL;
  555. hn->suffix = NULL;
  556. if (idx == (strlen(hostname) - 1)) {
  557. if ((hn->prefix = strdup(hostname)) == NULL) {
  558. hostname_destroy(hn);
  559. out_of_memory("hostname prefix create");
  560. }
  561. return hn;
  562. }
  563. hn->suffix = hn->hostname + idx + 1;
  564. if((dims > 1) && (strlen(hn->suffix) != dims))
  565. hostlist_base = 10;
  566. hn->num = strtoul(hn->suffix, &p, hostlist_base);
  567. if (*p == '\0') {
  568. if (!(hn->prefix = malloc((idx + 2) * sizeof(char)))) {
  569. hostname_destroy(hn);
  570. out_of_memory("hostname prefix create");
  571. }
  572. memcpy(hn->prefix, hostname, idx + 1);
  573. hn->prefix[idx + 1] = '\0';
  574. } else {
  575. if (!(hn->prefix = strdup(hostname))) {
  576. hostname_destroy(hn);
  577. out_of_memory("hostname prefix create");
  578. }
  579. hn->suffix = NULL;
  580. }
  581. return hn;
  582. }
  583. /*
  584. * create a hostname_t object from a string hostname
  585. */
  586. static hostname_t hostname_create(const char *hostname)
  587. {
  588. int dims = slurmdb_setup_cluster_name_dims();
  589. return hostname_create_dims(hostname, dims);
  590. }
  591. /* free a hostname object
  592. */
  593. static void hostname_destroy(hostname_t hn)
  594. {
  595. if (hn == NULL)
  596. return;
  597. hn->suffix = NULL;
  598. if (hn->hostname)
  599. free(hn->hostname);
  600. if (hn->prefix)
  601. free(hn->prefix);
  602. free(hn);
  603. }
  604. /* return true if the hostname has a valid numeric suffix
  605. */
  606. static int hostname_suffix_is_valid(hostname_t hn)
  607. {
  608. if (!hn)
  609. return false;
  610. return hn->suffix != NULL;
  611. }
  612. /* return the width (in characters) of the numeric part of the hostname
  613. */
  614. static int hostname_suffix_width(hostname_t hn)
  615. {
  616. if (!hn)
  617. return -1;
  618. assert(hn->suffix != NULL);
  619. return (int) strlen(hn->suffix);
  620. }
  621. /* ----[ hostrange_t functions ]---- */
  622. /* allocate a new hostrange object
  623. */
  624. static hostrange_t hostrange_new(void)
  625. {
  626. hostrange_t new = (hostrange_t) malloc(sizeof(*new));
  627. if (!new)
  628. out_of_memory("hostrange create");
  629. return new;
  630. }
  631. /* Create a hostrange_t containing a single host without a valid suffix
  632. * hr->prefix will represent the entire hostname.
  633. */
  634. static hostrange_t hostrange_create_single(const char *prefix)
  635. {
  636. hostrange_t new;
  637. assert(prefix != NULL);
  638. if ((new = hostrange_new()) == NULL)
  639. goto error1;
  640. if ((new->prefix = strdup(prefix)) == NULL)
  641. goto error2;
  642. new->singlehost = 1;
  643. new->lo = 0L;
  644. new->hi = 0L;
  645. new->width = 0;
  646. return new;
  647. error2:
  648. free(new);
  649. error1:
  650. out_of_memory("hostrange create single");
  651. }
  652. /* Create a hostrange object with a prefix, hi, lo, and format width
  653. */
  654. static hostrange_t
  655. hostrange_create(char *prefix, unsigned long lo, unsigned long hi, int width)
  656. {
  657. hostrange_t new;
  658. assert(prefix != NULL);
  659. if ((new = hostrange_new()) == NULL)
  660. goto error1;
  661. if ((new->prefix = strdup(prefix)) == NULL)
  662. goto error2;
  663. new->lo = lo;
  664. new->hi = hi;
  665. new->width = width;
  666. new->singlehost = 0;
  667. return new;
  668. error2:
  669. free(new);
  670. error1:
  671. out_of_memory("hostrange create");
  672. }
  673. /* Return the number of hosts stored in the hostrange object
  674. */
  675. static unsigned long hostrange_count(hostrange_t hr)
  676. {
  677. assert(hr != NULL);
  678. if (hr->singlehost)
  679. return 1;
  680. else
  681. return hr->hi - hr->lo + 1;
  682. }
  683. /* Copy a hostrange object
  684. */
  685. static hostrange_t hostrange_copy(hostrange_t hr)
  686. {
  687. assert(hr != NULL);
  688. if (hr->singlehost)
  689. return hostrange_create_single(hr->prefix);
  690. else
  691. return hostrange_create(hr->prefix, hr->lo, hr->hi,
  692. hr->width);
  693. }
  694. /* free memory allocated by the hostrange object
  695. */
  696. static void hostrange_destroy(hostrange_t hr)
  697. {
  698. if (hr == NULL)
  699. return;
  700. if (hr->prefix)
  701. free(hr->prefix);
  702. free(hr);
  703. }
  704. /* hostrange_delete_host() deletes a specific host from the range.
  705. * If the range is split into two, the greater range is returned,
  706. * and `hi' of the lesser range is adjusted accordingly. If the
  707. * highest or lowest host is deleted from a range, NULL is returned
  708. * and the hostrange hr is adjusted properly.
  709. */
  710. static hostrange_t hostrange_delete_host(hostrange_t hr, unsigned long n)
  711. {
  712. hostrange_t new = NULL;
  713. assert(hr != NULL);
  714. assert(n >= hr->lo && n <= hr->hi);
  715. if (n == hr->lo)
  716. hr->lo++;
  717. else if (n == hr->hi)
  718. hr->hi--;
  719. else {
  720. if (!(new = hostrange_copy(hr)))
  721. out_of_memory("hostrange copy");
  722. hr->hi = n - 1;
  723. new->lo = n + 1;
  724. }
  725. return new;
  726. }
  727. /* hostrange_cmp() is used to sort hostrange objects. It will
  728. * sort based on the following (in order):
  729. * o result of strcmp on prefixes
  730. * o if widths are compatible, then:
  731. * sort based on lowest suffix in range
  732. * else
  733. * sort based on width */
  734. static int hostrange_cmp(hostrange_t h1, hostrange_t h2)
  735. {
  736. int retval;
  737. assert(h1 != NULL);
  738. assert(h2 != NULL);
  739. if ((retval = hostrange_prefix_cmp(h1, h2)) == 0)
  740. retval = hostrange_width_combine(h1, h2) ?
  741. h1->lo - h2->lo : h1->width - h2->width;
  742. return retval;
  743. }
  744. /* compare the prefixes of two hostrange objects.
  745. * returns:
  746. * < 0 if h1 prefix is less than h2 OR h2 == NULL.
  747. *
  748. * 0 if h1's prefix and h2's prefix match,
  749. * UNLESS, either h1 or h2 (NOT both) do not have a valid suffix.
  750. *
  751. * > 0 if h1's prefix is greater than h2's OR h1 == NULL. */
  752. static int hostrange_prefix_cmp(hostrange_t h1, hostrange_t h2)
  753. {
  754. int retval;
  755. if (h1 == NULL)
  756. return 1;
  757. if (h2 == NULL)
  758. return -1;
  759. retval = strcmp(h1->prefix, h2->prefix);
  760. return retval == 0 ? h2->singlehost - h1->singlehost : retval;
  761. }
  762. /* returns true if h1 and h2 would be included in the same bracketed hostlist.
  763. * h1 and h2 will be in the same bracketed list iff:
  764. *
  765. * 1. h1 and h2 have same prefix
  766. * 2. neither h1 nor h2 are singlet hosts (i.e. invalid suffix)
  767. *
  768. * (XXX: Should incompatible widths be placed in the same bracketed list?
  769. * There's no good reason not to, except maybe aesthetics)
  770. */
  771. static int hostrange_within_range(hostrange_t h1, hostrange_t h2)
  772. {
  773. if (hostrange_prefix_cmp(h1, h2) == 0)
  774. return h1->singlehost || h2->singlehost ? 0 : 1;
  775. else
  776. return 0;
  777. }
  778. /* compare two hostrange objects to determine if they are width
  779. * compatible, returns:
  780. * 1 if widths can safely be combined
  781. * 0 if widths cannot be safely combined
  782. */
  783. static int hostrange_width_combine(hostrange_t h0, hostrange_t h1)
  784. {
  785. assert(h0 != NULL);
  786. assert(h1 != NULL);
  787. return _width_equiv(h0->lo, &h0->width, h1->lo, &h1->width);
  788. }
  789. /* Return true if hostrange hr contains no hosts, i.e. hi < lo
  790. */
  791. static int hostrange_empty(hostrange_t hr)
  792. {
  793. assert(hr != NULL);
  794. return ((hr->hi < hr->lo) || (hr->hi == (unsigned long) -1));
  795. }
  796. /* return the string representation of the last host in hostrange hr
  797. * and remove that host from the range (i.e. decrement hi if possible)
  798. *
  799. * Returns NULL if malloc fails OR there are no more hosts left
  800. */
  801. static char *hostrange_pop(hostrange_t hr)
  802. {
  803. size_t size = 0;
  804. char *host = NULL;
  805. int dims = slurmdb_setup_cluster_name_dims();
  806. assert(hr != NULL);
  807. if (hr->singlehost) {
  808. hr->lo++; /* effectively set count == 0 */
  809. host = strdup(hr->prefix);
  810. if (host == NULL)
  811. out_of_memory("hostrange pop");
  812. } else if (hostrange_count(hr) > 0) {
  813. size = strlen(hr->prefix) + hr->width + 16;
  814. if (!(host = (char *) malloc(size * sizeof(char))))
  815. out_of_memory("hostrange pop");
  816. if ((dims > 1) && (hr->width == dims)) {
  817. int len = 0;
  818. int i2 = 0;
  819. int coord[dims];
  820. hostlist_parse_int_to_array(hr->hi, coord, dims, 0);
  821. len = snprintf(host, size, "%s", hr->prefix);
  822. if (len >= 0 && len + dims < size) {
  823. while (i2 < dims)
  824. host[len++] = alpha_num[coord[i2++]];
  825. host[len] = '\0';
  826. }
  827. hr->hi--;
  828. } else {
  829. snprintf(host, size, "%s%0*lu", hr->prefix,
  830. hr->width, hr->hi--);
  831. }
  832. }
  833. return host;
  834. }
  835. /* Same as hostrange_pop(), but remove host from start of range */
  836. static char *hostrange_shift(hostrange_t hr)
  837. {
  838. size_t size = 0;
  839. char *host = NULL;
  840. int dims = slurmdb_setup_cluster_name_dims();
  841. assert(hr != NULL);
  842. if (hr->singlehost) {
  843. hr->lo++;
  844. if (!(host = strdup(hr->prefix)))
  845. out_of_memory("hostrange shift");
  846. } else if (hostrange_count(hr) > 0) {
  847. size = strlen(hr->prefix) + hr->width + 16;
  848. if (!(host = (char *) malloc(size * sizeof(char))))
  849. out_of_memory("hostrange shift");
  850. if ((dims > 1) && (hr->width == dims)) {
  851. int len = 0;
  852. int i2 = 0;
  853. int coord[dims];
  854. hostlist_parse_int_to_array(hr->lo, coord, dims, 0);
  855. len = snprintf(host, size, "%s", hr->prefix);
  856. if (len >= 0 && len + dims < size) {
  857. while (i2 < dims)
  858. host[len++] = alpha_num[coord[i2++]];
  859. host[len] = '\0';
  860. }
  861. hr->lo++;
  862. } else {
  863. snprintf(host, size, "%s%0*lu", hr->prefix,
  864. hr->width, hr->lo++);
  865. }
  866. }
  867. return host;
  868. }
  869. /* join two hostrange objects.
  870. *
  871. * returns:
  872. *
  873. * -1 if ranges do not overlap (including incompatible zero padding)
  874. * 0 if ranges join perfectly
  875. * >0 number of hosts that were duplicated in h1 and h2
  876. *
  877. * h2 will be coalesced into h1 if rc >= 0
  878. *
  879. * it is assumed that h1->lo <= h2->lo, i.e. hr1 <= hr2
  880. *
  881. */
  882. static int hostrange_join(hostrange_t h1, hostrange_t h2)
  883. {
  884. int duplicated = -1;
  885. assert(h1 != NULL);
  886. assert(h2 != NULL);
  887. assert(hostrange_cmp(h1, h2) <= 0);
  888. if (hostrange_prefix_cmp(h1, h2) == 0 &&
  889. hostrange_width_combine(h1, h2)) {
  890. if (h1->singlehost && h2->singlehost) { /* matching singlets */
  891. duplicated = 1;
  892. } else if (h1->hi == h2->lo - 1) { /* perfect join */
  893. h1->hi = h2->hi;
  894. duplicated = 0;
  895. } else if (h1->hi >= h2->lo) { /* some duplication */
  896. if (h1->hi < h2->hi) {
  897. duplicated = h1->hi - h2->lo + 1;
  898. h1->hi = h2->hi;
  899. } else
  900. duplicated = hostrange_count(h2);
  901. }
  902. }
  903. return duplicated;
  904. }
  905. /* hostrange intersect returns the intersection (common hosts)
  906. * of hostrange objects h1 and h2. If there is no intersection,
  907. * NULL is returned.
  908. *
  909. * It is assumed that h1 <= h2 (i.e. h1->lo <= h2->lo)
  910. */
  911. static hostrange_t hostrange_intersect(hostrange_t h1, hostrange_t h2)
  912. {
  913. hostrange_t new = NULL;
  914. assert(h1 != NULL);
  915. assert(h2 != NULL);
  916. if (h1->singlehost || h2->singlehost)
  917. return NULL;
  918. assert(hostrange_cmp(h1, h2) <= 0);
  919. if ((hostrange_prefix_cmp(h1, h2) == 0)
  920. && (h1->hi > h2->lo)
  921. && (hostrange_width_combine(h1, h2))) {
  922. if (!(new = hostrange_copy(h1)))
  923. return NULL;
  924. new->lo = h2->lo;
  925. new->hi = h2->hi < h1->hi ? h2->hi : h1->hi;
  926. }
  927. return new;
  928. }
  929. /* return 1 if hostname hn is within the hostrange hr
  930. * 0 if not.
  931. */
  932. static int hostrange_hn_within(hostrange_t hr, hostname_t hn)
  933. {
  934. if (hr->singlehost) {
  935. /*
  936. * If the current hostrange [hr] is a `singlehost' (no valid
  937. * numeric suffix (lo and hi)), then the hostrange [hr]
  938. * stores just one host with name == hr->prefix.
  939. *
  940. * Thus the full hostname in [hn] must match hr->prefix, in
  941. * which case we return true. Otherwise, there is no
  942. * possibility that [hn] matches [hr].
  943. */
  944. if (strcmp (hn->hostname, hr->prefix) == 0)
  945. return 1;
  946. else
  947. return 0;
  948. }
  949. /*
  950. * Now we know [hr] is not a "singlehost", so hostname
  951. * better have a valid numeric suffix, or there is no
  952. * way we can match
  953. */
  954. if (!hostname_suffix_is_valid (hn))
  955. return 0;
  956. /*
  957. * If hostrange and hostname prefixes don't match, then
  958. * there is way the hostname falls within the range [hr].
  959. */
  960. if (strcmp(hr->prefix, hn->prefix) != 0) {
  961. int len1, len2, ldiff;
  962. int dims = slurmdb_setup_cluster_name_dims();
  963. if (dims != 1)
  964. return 0;
  965. /* Below logic was added since primarily for a cray
  966. * where people typically drop
  967. * leading zeros into the prefix so you can do
  968. * something like nid0000[2-7]. But doing this messes
  969. * up the hostlist_find since when someone queries
  970. * against nid00002 the prefixes don't match. The
  971. * below code is there to make sure get the best
  972. * chance for comparison.
  973. */
  974. /* First see if by taking some of the leading digits of the
  975. * suffix of hn and moving it to the end of the prefix if it
  976. * would be a match.
  977. */
  978. len1 = strlen(hr->prefix);
  979. len2 = strlen(hn->prefix);
  980. ldiff = len1 - len2;
  981. if (ldiff > 0 && isdigit(hr->prefix[len1-1])
  982. && (strlen(hn->suffix) >= ldiff)) {
  983. char *p = '\0';
  984. /* Tack on ldiff of the hostname's suffix to that of
  985. * it's prefix */
  986. hn->prefix = realloc(hn->prefix, len2+ldiff+1);
  987. strncat(hn->prefix, hn->suffix, ldiff);
  988. /* Now adjust the suffix of the hostname object. */
  989. hn->suffix += ldiff;
  990. /* And the numeric representation just incase
  991. * whatever we just tacked on to the prefix
  992. * had something other than 0 in it.
  993. *
  994. * Since we are only going through this logic for
  995. * single dimension systems we will always use
  996. * the base 10.
  997. */
  998. hn->num = strtoul(hn->suffix, &p, 10);
  999. /* Now compare them and see if they match */
  1000. if (strcmp(hr->prefix, hn->prefix) != 0)
  1001. return 0;
  1002. } else
  1003. return 0;
  1004. }
  1005. /*
  1006. * Finally, check whether [hn], with a valid numeric suffix,
  1007. * falls within the range of [hr].
  1008. */
  1009. if (hn->num <= hr->hi && hn->num >= hr->lo) {
  1010. int width = hostname_suffix_width(hn);
  1011. int num = hn->num;
  1012. return (_width_equiv(hr->lo, &hr->width, num, &width));
  1013. }
  1014. return 0;
  1015. }
  1016. /* copy a string representation of the hostrange hr into buffer buf,
  1017. * writing at most n chars including NUL termination
  1018. */
  1019. static size_t
  1020. hostrange_to_string(hostrange_t hr, size_t n, char *buf,
  1021. char *separator, int dims)
  1022. {
  1023. unsigned long i;
  1024. int ret, len = 0;
  1025. char sep = separator == NULL ? ',' : separator[0];
  1026. if (!dims)
  1027. dims = slurmdb_setup_cluster_name_dims();
  1028. if (n == 0)
  1029. return 0;
  1030. assert(hr != NULL);
  1031. if (hr->singlehost) {
  1032. ret = snprintf(buf, n, "%s", hr->prefix);
  1033. if (ret < 0 || ret >= n)
  1034. goto truncated;
  1035. return ret;
  1036. }
  1037. for (i = hr->lo; i <= hr->hi; i++) {
  1038. if (i > hr->lo)
  1039. buf[len++] = sep;
  1040. if (len >= n)
  1041. goto truncated;
  1042. if ((dims > 1) && (hr->width == dims)) {
  1043. int i2 = 0;
  1044. int coord[dims];
  1045. hostlist_parse_int_to_array(i, coord, dims, 0);
  1046. ret = snprintf(buf + len, n - len, "%s", hr->prefix);
  1047. if (ret < 0 || (len += ret) >= n || len + dims >= n)
  1048. goto truncated;
  1049. while (i2 < dims)
  1050. buf[len++] = alpha_num[coord[i2++]];
  1051. } else {
  1052. ret = snprintf(buf + len, n - len, "%s%0*lu",
  1053. hr->prefix, hr->width, i);
  1054. if (ret < 0 || (len += ret) >= n)
  1055. goto truncated;
  1056. }
  1057. }
  1058. buf[len] = '\0';
  1059. return len;
  1060. truncated:
  1061. buf[n-1] = '\0';
  1062. return -1;
  1063. }
  1064. /* Place the string representation of the numeric part of hostrange into buf
  1065. * writing at most n chars including NUL termination. The width argument
  1066. * controls the number of leading zeroes.
  1067. */
  1068. static size_t hostrange_numstr(hostrange_t hr, size_t n, char *buf, int width)
  1069. {
  1070. int len = 0;
  1071. int dims = slurmdb_setup_cluster_name_dims();
  1072. assert(buf != NULL);
  1073. assert(hr != NULL);
  1074. if (hr->singlehost || n == 0)
  1075. return 0;
  1076. if (n <= dims)
  1077. return -1;
  1078. if (width < 0 || width > hr->width)
  1079. width = hr->width;
  1080. if ((dims > 1) && (hr->width == dims)) {
  1081. int i2 = 0;
  1082. int coord[dims];
  1083. hostlist_parse_int_to_array(hr->lo, coord, dims, 0);
  1084. while (i2 < dims)
  1085. buf[len++] = alpha_num[coord[i2++]];
  1086. buf[len] = '\0';
  1087. } else {
  1088. len = snprintf(buf, n, "%0*lu", hr->width - width, hr->lo);
  1089. if (len < 0 || len >= n)
  1090. return -1;
  1091. }
  1092. if (hr->lo < hr->hi) {
  1093. if (n < len + dims + 2) /* '-' plus 'dims' digits, plus '\0' */
  1094. return -1;
  1095. if ((dims > 1) && (hr->width == dims)) {
  1096. int i2 = 0;
  1097. int coord[dims];
  1098. hostlist_parse_int_to_array(hr->hi, coord, dims, 0);
  1099. buf[len++] = '-';
  1100. while (i2 < dims)
  1101. buf[len++] = alpha_num[coord[i2++]];
  1102. buf[len] = '\0';
  1103. } else {
  1104. int len2 = snprintf(buf + len, n - len, "-%0*lu",
  1105. hr->width - width, hr->hi);
  1106. if (len2 < 0 || (len += len2) >= n)
  1107. return -1;
  1108. }
  1109. }
  1110. return len;
  1111. }
  1112. /* ----[ hostlist functions ]---- */
  1113. /* Create a new hostlist object.
  1114. * Returns an empty hostlist, or NULL if memory allocation fails.
  1115. */
  1116. static hostlist_t hostlist_new(void)
  1117. {
  1118. int i;
  1119. hostlist_t new = (hostlist_t) malloc(sizeof(*new));
  1120. if (!new)
  1121. goto fail1;
  1122. assert(new->magic = HOSTLIST_MAGIC);
  1123. mutex_init(&new->mutex);
  1124. new->hr = (hostrange_t *) malloc(HOSTLIST_CHUNK * sizeof(hostrange_t));
  1125. if (!new->hr)
  1126. goto fail2;
  1127. /* set entries in hostrange array to NULL */
  1128. for (i = 0; i < HOSTLIST_CHUNK; i++)
  1129. new->hr[i] = NULL;
  1130. new->size = HOSTLIST_CHUNK;
  1131. new->nranges = 0;
  1132. new->nhosts = 0;
  1133. new->ilist = NULL;
  1134. return new;
  1135. fail2:
  1136. free(new);
  1137. fail1:
  1138. out_of_memory("hostlist_new");
  1139. }
  1140. /* Resize the internal array used to store the list of hostrange objects.
  1141. *
  1142. * returns 1 for a successful resize,
  1143. * 0 if call to _realloc fails
  1144. *
  1145. * It is assumed that the caller has the hostlist hl locked
  1146. */
  1147. static int hostlist_resize(hostlist_t hl, size_t newsize)
  1148. {
  1149. int i;
  1150. size_t oldsize;
  1151. assert(hl != NULL);
  1152. assert(hl->magic == HOSTLIST_MAGIC);
  1153. oldsize = hl->size;
  1154. hl->size = newsize;
  1155. hl->hr = realloc((void *) hl->hr, hl->size*sizeof(hostrange_t));
  1156. if (!(hl->hr))
  1157. return 0;
  1158. for (i = oldsize; i < newsize; i++)
  1159. hl->hr[i] = NULL;
  1160. return 1;
  1161. }
  1162. /* Resize hostlist by one HOSTLIST_CHUNK
  1163. * Assumes that hostlist hl is locked by caller
  1164. */
  1165. static int hostlist_expand(hostlist_t hl)
  1166. {
  1167. if (!hostlist_resize(hl, hl->size + HOSTLIST_CHUNK))
  1168. return 0;
  1169. else
  1170. return 1;
  1171. }
  1172. /* Push a hostrange object onto hostlist hl
  1173. * Returns the number of hosts successfully pushed onto hl
  1174. * or -1 if there was an error allocating memory
  1175. */
  1176. static int hostlist_push_range(hostlist_t hl, hostrange_t hr)
  1177. {
  1178. hostrange_t tail;
  1179. int retval;
  1180. assert(hr != NULL);
  1181. LOCK_HOSTLIST(hl);
  1182. tail = (hl->nranges > 0) ? hl->hr[hl->nranges-1] : hl->hr[0];
  1183. if (hl->size == hl->nranges && !hostlist_expand(hl))
  1184. goto error;
  1185. if (hl->nranges > 0
  1186. && hostrange_prefix_cmp(tail, hr) == 0
  1187. && tail->hi == hr->lo - 1
  1188. && hostrange_width_combine(tail, hr)) {
  1189. tail->hi = hr->hi;
  1190. } else {
  1191. hostrange_t new = hostrange_copy(hr);
  1192. if (new == NULL)
  1193. goto error;
  1194. hl->hr[hl->nranges++] = new;
  1195. }
  1196. retval = hl->nhosts += hostrange_count(hr);
  1197. UNLOCK_HOSTLIST(hl);
  1198. return retval;
  1199. error:
  1200. UNLOCK_HOSTLIST(hl);
  1201. return -1;
  1202. }
  1203. /* Same as hostlist_push_range() above, but prefix, lo, hi, and width
  1204. * are passed as args
  1205. */
  1206. static int
  1207. hostlist_push_hr(hostlist_t hl, char *prefix, unsigned long lo,
  1208. unsigned long hi, int width)
  1209. {
  1210. hostrange_t hr = hostrange_create(prefix, lo, hi, width);
  1211. int retval = hostlist_push_range(hl, hr);
  1212. hostrange_destroy(hr);
  1213. return retval;
  1214. }
  1215. /* Insert a range object hr into position n of the hostlist hl
  1216. * Assumes that hl->mutex is already held by calling process
  1217. */
  1218. static int hostlist_insert_range(hostlist_t hl, hostrange_t hr, int n)
  1219. {
  1220. int i;
  1221. hostrange_t tmp;
  1222. hostlist_iterator_t hli;
  1223. assert(hl != NULL);
  1224. assert(hl->magic == HOSTLIST_MAGIC);
  1225. assert(hr != NULL);
  1226. if (n > hl->nranges)
  1227. return 0;
  1228. if (hl->size == hl->nranges && !hostlist_expand(hl))
  1229. return 0;
  1230. /* copy new hostrange into slot "n" in array */
  1231. tmp = hl->hr[n];
  1232. hl->hr[n] = hostrange_copy(hr);
  1233. /* push remaining hostrange entries up */
  1234. for (i = n + 1; i < hl->nranges + 1; i++) {
  1235. hostrange_t last = hl->hr[i];
  1236. hl->hr[i] = tmp;
  1237. tmp = last;
  1238. }
  1239. hl->nranges++;
  1240. /* adjust hostlist iterators if needed */
  1241. for (hli = hl->ilist; hli; hli = hli->next) {
  1242. if (hli->idx >= n)
  1243. hli->hr = hli->hl->hr[++hli->idx];
  1244. }
  1245. return 1;
  1246. }
  1247. /* Delete the range at position n in the range array
  1248. * Assumes the hostlist lock is already held.
  1249. */
  1250. static void hostlist_delete_range(hostlist_t hl, int n)
  1251. {
  1252. int i;
  1253. hostrange_t old;
  1254. assert(hl != NULL);
  1255. assert(hl->magic == HOSTLIST_MAGIC);
  1256. assert(n < hl->nranges && n >= 0);
  1257. old = hl->hr[n];
  1258. for (i = n; i < hl->nranges - 1; i++)
  1259. hl->hr[i] = hl->hr[i + 1];
  1260. hl->nranges--;
  1261. hl->hr[hl->nranges] = NULL;
  1262. hostlist_shift_iterators(hl, n, 0, 1);
  1263. /* XXX caller responsible for adjusting nhosts */
  1264. /* hl->nhosts -= hostrange_count(old) */
  1265. hostrange_destroy(old);
  1266. }
  1267. #if WANT_RECKLESS_HOSTRANGE_EXPANSION
  1268. /* The reckless hostrange expansion function.
  1269. * See comment in hostlist.h:hostlist_create() for more info on
  1270. * the different choices for hostlist notation.
  1271. */
  1272. hostlist_t _hostlist_create(const char *hostlist, char *sep, char *r_op,
  1273. int dims)
  1274. {
  1275. char *str, *orig;
  1276. char *tok, *cur;
  1277. int high, low, fmt = 0;
  1278. char prefix[256] = "";
  1279. int pos = 0;
  1280. int error = 0;
  1281. int hostlist_base;
  1282. char range_op = r_op[0];/* XXX support > 1 char range ops in future? */
  1283. hostlist_t new = hostlist_new();
  1284. if (hostlist == NULL)
  1285. return new;
  1286. if (dims > 1)
  1287. fatal("WANT_RECKLESS_HOSTRANGE_EXPANSION does not "
  1288. "work on multi-dimensional systems!!!!");
  1289. hostlist_base = hostlist_get_base(1);
  1290. orig = str = strdup(hostlist);
  1291. /* return an empty list if an empty string was passed in */
  1292. if (str == NULL || strlen(str) == 0)
  1293. goto done;
  1294. /* Use hostlist_create_bracketed if we see "[" */
  1295. if (strchr(str, '[') != NULL)
  1296. return _hostlist_create_bracketed(hostlist, sep, r_op, dims);
  1297. while ((tok = _next_tok(sep, &str)) != NULL) {
  1298. /* save the current string for error messages */
  1299. cur = tok;
  1300. high = low = 0;
  1301. /* find end of alpha part
  1302. * do this by finding last occurence of range_op in str */
  1303. pos = strlen(tok) - 1;
  1304. if (strstr(tok, r_op) != '\0') {
  1305. while (pos >= 0 && (char) tok[pos] != range_op)
  1306. pos--;
  1307. }
  1308. /* now back up past any digits */
  1309. while (pos >= 0 && isdigit((char) tok[--pos])) {;}
  1310. /* Check for valid x-y range (x must be a digit)
  1311. * Reset pos if the range is not valid */
  1312. if (!isdigit((char) tok[++pos]))
  1313. pos = strlen(tok) - 1;
  1314. /* create prefix string
  1315. * if prefix will be zero length, but prefix already exists
  1316. * use the previous prefix and fmt
  1317. */
  1318. if ((pos > 0) || (prefix[0] == '\0')) {
  1319. memcpy(prefix, tok, (size_t) pos * sizeof(char));
  1320. prefix[pos] = '\0';
  1321. /* push pointer past prefix */
  1322. tok += pos;
  1323. /* count number of digits for ouput fmt */
  1324. for (fmt = 0; isdigit(tok[fmt]); ++fmt) {;}
  1325. if (fmt == 0)
  1326. error = 1;
  1327. } else
  1328. tok += pos;
  1329. /* get lower bound */
  1330. low = strtoul(tok, (char **) &tok, hostlist_base);
  1331. if (*tok == range_op) { /* now get range upper bound */
  1332. /* push pointer past range op */
  1333. ++tok;
  1334. /* find length of alpha part */
  1335. for (pos = 0; tok[pos] && !isdigit(tok[pos]); ++pos) {;}
  1336. /* alpha part must match prefix or error
  1337. * this could mean we've got something like "rtr1-a2"
  1338. * so just record an error
  1339. */
  1340. if (pos > 0) {
  1341. if (pos != strlen(prefix) ||
  1342. strncmp(prefix, tok, pos) != 0)
  1343. error = 1;
  1344. }
  1345. if (*tok != '\0')
  1346. tok += pos;
  1347. /* make sure we have digits to the end */
  1348. for (pos = 0;
  1349. tok[pos] && isdigit((char) tok[pos]);
  1350. ++pos) {;}
  1351. if (pos > 0) { /* we have digits to process */
  1352. high = strtoul(tok, (char **) &tok,
  1353. hostlist_base);
  1354. } else { /* bad boy, no digits */
  1355. error = 1;
  1356. }
  1357. if ((low > high) || (high - low > MAX_RANGE))
  1358. error = 1;
  1359. } else { /* single value */
  1360. high = 0; /* special case, ugh. */
  1361. }
  1362. /* error if:
  1363. * 1. we are not at end of string
  1364. * 2. upper bound equals lower bound
  1365. */
  1366. if (*tok != '\0' || high == low)
  1367. error = 1;
  1368. if (error) { /* assume this is not a range on any error */
  1369. hostlist_push_host_dims(new, cur, dims);
  1370. } else {
  1371. if (high < low)
  1372. high = low;
  1373. hostlist_push_hr(new, prefix, low, high, fmt);
  1374. }
  1375. error = 0;
  1376. }
  1377. done:
  1378. if(orig)
  1379. free(orig);
  1380. return new;
  1381. }
  1382. #else /* !WANT_RECKLESS_HOSTRANGE_EXPANSION */
  1383. hostlist_t _hostlist_create(const char *hostlist, char *sep,
  1384. char *r_op, int dims)
  1385. {
  1386. return _hostlist_create_bracketed(hostlist, sep, r_op, dims);
  1387. }
  1388. #endif /* WANT_RECKLESS_HOSTRANGE_EXPANSION */
  1389. static int _parse_box_range(char *str, struct _range *ranges,
  1390. int len, int *count, int dims)
  1391. {
  1392. int start[dims], end[dims],
  1393. pos[dims];
  1394. char coord[dims+1];
  1395. char coord2[dims+1];
  1396. int i, a;
  1397. if(dims <= 1)
  1398. fatal("Unsupported dimensions count %d", dims);
  1399. if ((str[dims] != 'x') ||
  1400. (str[(dims * 2) + 1] != '\0'))
  1401. return 0;
  1402. for(i = 0; i<dims; i++) {
  1403. if ((str[i] >= '0') && (str[i] <= '9'))
  1404. start[i] = str[i] - '0';
  1405. else if ((str[i] >= 'A') && (str[i] <= 'Z'))
  1406. start[i] = str[i] - 'A' + 10;
  1407. else
  1408. return 0;
  1409. a = i + dims + 1;
  1410. if ((str[a] >= '0') && (str[a] <= '9'))
  1411. end[i] = str[a] - '0';
  1412. else if ((str[a] >= 'A') && (str[a] <= 'Z'))
  1413. end[i] = str[a] - 'A' + 10;
  1414. else
  1415. return 0;
  1416. }
  1417. memset(coord, 0, sizeof(coord));
  1418. memset(coord2, 0, sizeof(coord2));
  1419. for(i = 0; i<dims; i++) {
  1420. coord[i] = alpha_num[start[i]];
  1421. coord2[i] = alpha_num[end[i]];
  1422. }
  1423. /* info("adding ranges in %sx%s", coord, coord2); */
  1424. return _add_box_ranges(0, 0, start, end, pos, ranges, len, count, dims);
  1425. }
  1426. /* Grab a single range from str
  1427. * returns 1 if str contained a valid number or range,
  1428. * 0 if conversion of str to a range failed.
  1429. */
  1430. static int _parse_single_range(const char *str, struct _range *range, int dims)
  1431. {
  1432. char *p, *q;
  1433. char *orig = strdup(str);
  1434. int hostlist_base = hostlist_get_base(dims);
  1435. if (!orig)
  1436. seterrno_ret(ENOMEM, 0);
  1437. if ((p = strchr(str, 'x')))
  1438. goto error; /* do NOT allow boxes here */
  1439. if ((p = strchr(str, '-'))) {
  1440. *p++ = '\0';
  1441. if (*p == '-') /* do NOT allow negative numbers */
  1442. goto error;
  1443. }
  1444. range->width = strlen(str);
  1445. if(dims > 1) {
  1446. /* If we get something here where the width is not
  1447. SYSTEM_DIMENSIONS we need to treat it as a regular number
  1448. since that is how it will be treated in the future.
  1449. */
  1450. if(range->width != dims)
  1451. hostlist_base = 10;
  1452. }
  1453. range->lo = strtoul(str, &q, hostlist_base);
  1454. if (q == str)
  1455. goto error;
  1456. range->hi = (p && *p) ? strtoul(p, &q, hostlist_base) : range->lo;
  1457. if (q == p || *q != '\0')
  1458. goto error;
  1459. if (range->lo > range->hi)
  1460. goto error;
  1461. if (range->hi - range->lo + 1 > MAX_RANGE ) {
  1462. _error(__FILE__, __LINE__, "Too many hosts in range `%s'\n",
  1463. orig);
  1464. free(orig);
  1465. seterrno_ret(ERANGE, 0);
  1466. }
  1467. free(orig);
  1468. return 1;
  1469. error:
  1470. errno = EINVAL;
  1471. _error(__FILE__, __LINE__, "Invalid range: `%s'", orig);
  1472. free(orig);
  1473. return 0;
  1474. }
  1475. /*
  1476. * Convert 'str' containing comma separated digits and ranges into an array
  1477. * of struct _range types (max 'len' elements).
  1478. *
  1479. * Return number of ranges created, or -1 on error.
  1480. */
  1481. static int _parse_range_list(char *str, struct _range *ranges,
  1482. int len, int dims)
  1483. {
  1484. char *p;
  1485. int count = 0;
  1486. while (str) {
  1487. if (count == len) {
  1488. errno = EINVAL;
  1489. _error(__FILE__, __LINE__,
  1490. "Too many ranges, can't process "
  1491. "entire list");
  1492. return -1;
  1493. }
  1494. if ((p = strchr(str, ',')))
  1495. *p++ = '\0';
  1496. /* info("looking at %s", str); */
  1497. if ((dims > 1) &&
  1498. (str[dims] == 'x') &&
  1499. (strlen(str) == (dims * 2 + 1))) {
  1500. if (!_parse_box_range(str, ranges, len, &count, dims))
  1501. return -1;
  1502. } else {
  1503. if (!_parse_single_range(str, &ranges[count++], dims))
  1504. return -1;
  1505. }
  1506. str = p;
  1507. }
  1508. return count;
  1509. }
  1510. /* Validate prefix and push with the numeric suffix onto the hostlist
  1511. * The prefix can contain a up to one range expresseion (e.g. "rack[1-4]_").
  1512. * RET 0 on success, -1 on failure (invalid prefix) */
  1513. static int
  1514. _push_range_list(hostlist_t hl, char *prefix, struct _range *range,
  1515. int n, int dims)
  1516. {
  1517. int i, k, nr;
  1518. char *p, *q;
  1519. char new_prefix[1024], tmp_prefix[1024];
  1520. strncpy(tmp_prefix, prefix, sizeof(tmp_prefix));
  1521. if (((p = strrchr(tmp_prefix, '[')) != NULL) &&
  1522. ((q = strrchr(p, ']')) != NULL)) {
  1523. struct _range prefix_range[MAX_RANGES];
  1524. struct _range *saved_range = range, *pre_range = prefix_range;
  1525. unsigned long j, prefix_cnt = 0;
  1526. *p++ = '\0';
  1527. *q++ = '\0';
  1528. if (strrchr(tmp_prefix, '[') != NULL)
  1529. return -1; /* third range is illegal */
  1530. nr = _parse_range_list(p, prefix_range, MAX_RANGES, dims);
  1531. if (nr < 0)
  1532. return -1; /* bad numeric expression */
  1533. for (i = 0; i < nr; i++) {
  1534. prefix_cnt += pre_range->hi - pre_range->lo + 1;
  1535. if (prefix_cnt > MAX_PREFIX_CNT) {
  1536. /* Prevent overflow of memory with user input
  1537. * of something like "a[0-999999999].b[0-9]" */
  1538. return -1;
  1539. }
  1540. for (j = pre_range->lo; j <= pre_range->hi; j++) {
  1541. snprintf(new_prefix, sizeof(new_prefix),
  1542. "%s%0*lu%s", tmp_prefix,
  1543. pre_range->width, j, q);
  1544. range = saved_range;
  1545. for (k = 0; k < n; k++) {
  1546. hostlist_push_hr(hl, new_prefix,
  1547. range->lo, range->hi,
  1548. range->width);
  1549. range++;
  1550. }
  1551. }
  1552. pre_range++;
  1553. }
  1554. return 0;
  1555. }
  1556. for (k = 0; k < n; k++) {
  1557. hostlist_push_hr(hl, prefix,
  1558. range->lo, range->hi, range->width);
  1559. range++;
  1560. }
  1561. return 0;
  1562. }
  1563. /*
  1564. * Create a hostlist from a string with brackets '[' ']' to aid
  1565. * detection of ranges and compressed lists
  1566. */
  1567. static hostlist_t
  1568. _hostlist_create_bracketed(const char *hostlist, char *sep,
  1569. char *r_op, int dims)
  1570. {
  1571. hostlist_t new = hostlist_new();
  1572. struct _range ranges[MAX_RANGES];
  1573. int nr, err;
  1574. char *p, *tok, *str, *orig;
  1575. char cur_tok[1024];
  1576. if (hostlist == NULL)
  1577. return new;
  1578. if (!(orig = str = strdup(hostlist))) {
  1579. hostlist_destroy(new);
  1580. return NULL;
  1581. }
  1582. while ((tok = _next_tok(sep, &str)) != NULL) {
  1583. strncpy(cur_tok, tok, 1024);
  1584. if ((p = strrchr(tok, '[')) != NULL) {
  1585. char *q, *prefix = tok;
  1586. *p++ = '\0';
  1587. if ((q = strchr(p, ']'))) {
  1588. if ((q[1] != ',') && (q[1] != '\0'))
  1589. goto error;
  1590. *q = '\0';
  1591. nr = _parse_range_list(p, ranges,
  1592. MAX_RANGES, dims);
  1593. if (nr < 0)
  1594. goto error;
  1595. if (_push_range_list(
  1596. new, prefix, ranges, nr, dims))
  1597. goto error;
  1598. } else {
  1599. /* The hostname itself contains a '['
  1600. * (no ']' found).
  1601. * Not likely what the user
  1602. * wanted. We will just tack one on
  1603. * the end. */
  1604. strcat(cur_tok, "]");
  1605. if(prefix && prefix[0])
  1606. hostlist_push_host_dims(
  1607. new, cur_tok, dims);
  1608. else
  1609. hostlist_push_host_dims(new, p, dims);
  1610. }
  1611. } else
  1612. hostlist_push_host_dims(new, cur_tok, dims);
  1613. }
  1614. free(orig);
  1615. return new;
  1616. error:
  1617. err = errno = EINVAL;
  1618. hostlist_destroy(new);
  1619. free(orig);
  1620. seterrno_ret(err, NULL);
  1621. }
  1622. hostlist_t hostlist_create_dims(const char *str, int dims)
  1623. {
  1624. if (!dims)
  1625. dims = slurmdb_setup_cluster_name_dims();
  1626. return _hostlist_create(str, "\t, ", "-", dims);
  1627. }
  1628. hostlist_t hostlist_create(const char *str)
  1629. {
  1630. int dims = slurmdb_setup_cluster_name_dims();
  1631. return hostlist_create_dims(str, dims);
  1632. }
  1633. hostlist_t hostlist_copy(const hostlist_t hl)
  1634. {
  1635. int i;
  1636. hostlist_t new;
  1637. if (!hl)
  1638. return NULL;
  1639. LOCK_HOSTLIST(hl);
  1640. if (!(new = hostlist_new()))
  1641. goto done;
  1642. new->nranges = hl->nranges;
  1643. new->nhosts = hl->nhosts;
  1644. if (new->nranges > new->size)
  1645. hostlist_resize(new, new->nranges);
  1646. for (i = 0; i < hl->nranges; i++)
  1647. new->hr[i] = hostrange_copy(hl->hr[i]);
  1648. done:
  1649. UNLOCK_HOSTLIST(hl);
  1650. return new;
  1651. }
  1652. void hostlist_destroy(hostlist_t hl)
  1653. {
  1654. int i;
  1655. if (!hl)
  1656. return;
  1657. LOCK_HOSTLIST(hl);
  1658. while (hl->ilist) {
  1659. mutex_unlock(&hl->mutex);
  1660. hostlist_iterator_destroy(hl->ilist);
  1661. mutex_lock(&hl->mutex);
  1662. }
  1663. for (i = 0; i < hl->nranges; i++)
  1664. hostrange_destroy(hl->hr[i]);
  1665. free(hl->hr);
  1666. assert(hl->magic = 0x1);
  1667. UNLOCK_HOSTLIST(hl);
  1668. mutex_destroy(&hl->mutex);
  1669. free(hl);
  1670. }
  1671. int hostlist_push(hostlist_t hl, const char *hosts)
  1672. {
  1673. hostlist_t new;
  1674. int retval;
  1675. if (!hosts || !hl)
  1676. return 0;
  1677. new = hostlist_create(hosts);
  1678. if (!new)
  1679. return 0;
  1680. mutex_lock(&new->mutex);
  1681. retval = new->nhosts;
  1682. mutex_unlock(&new->mutex);
  1683. hostlist_push_list(hl, new);
  1684. hostlist_destroy(new);
  1685. return retval;
  1686. }
  1687. int hostlist_push_host_dims(hostlist_t hl, const char *str, int dims)
  1688. {
  1689. hostrange_t hr;
  1690. hostname_t hn;
  1691. if (!str || !hl)
  1692. return 0;
  1693. if (!dims)
  1694. dims = slurmdb_setup_cluster_name_dims();
  1695. hn = hostname_create_dims(str, dims);
  1696. if (hostname_suffix_is_valid(hn))
  1697. hr = hostrange_create(hn->prefix, hn->num, hn->num,
  1698. hostname_suffix_width(hn));
  1699. else
  1700. hr = hostrange_create_single(str);
  1701. hostlist_push_range(hl, hr);
  1702. hostrange_destroy(hr);
  1703. hostname_destroy(hn);
  1704. return 1;
  1705. }
  1706. int hostlist_push_host(hostlist_t hl, const char *str)
  1707. {
  1708. int dims = slurmdb_setup_cluster_name_dims();
  1709. return hostlist_push_host_dims(hl, str, dims);
  1710. }
  1711. int hostlist_push_list(hostlist_t h1, hostlist_t h2)
  1712. {
  1713. int i, n = 0;
  1714. if (!h2 || !h1)
  1715. return 0;
  1716. LOCK_HOSTLIST(h2);
  1717. for (i = 0; i < h2->nranges; i++)
  1718. n += hostlist_push_range(h1, h2->hr[i]);
  1719. UNLOCK_HOSTLIST(h2);
  1720. return n;
  1721. }
  1722. char *hostlist_pop(hostlist_t hl)
  1723. {
  1724. char *host = NULL;
  1725. if (!hl) {
  1726. error("hostlist_pop: no hostlist given");
  1727. return NULL;
  1728. }
  1729. LOCK_HOSTLIST(hl);
  1730. if (hl->nhosts > 0) {
  1731. hostrange_t hr = hl->hr[hl->nranges - 1];
  1732. host = hostrange_pop(hr);
  1733. hl->nhosts--;
  1734. if (hostrange_empty(hr)) {
  1735. hostrange_destroy(hl->hr[--hl->nranges]);
  1736. hl->hr[hl->nranges] = NULL;
  1737. }
  1738. }
  1739. UNLOCK_HOSTLIST(hl);
  1740. return host;
  1741. }
  1742. /* find all iterators affected by a shift (or deletion) at
  1743. * hl->hr[idx], depth, with the deletion of n ranges */
  1744. static void
  1745. hostlist_shift_iterators(hostlist_t hl, int idx, int depth, int n)
  1746. {
  1747. hostlist_iterator_t i;
  1748. if(!hl) {
  1749. error("hostlist_shift_iterators: no hostlist given");
  1750. return;
  1751. }
  1752. for (i = hl->ilist; i; i = i->next) {
  1753. if (n == 0) {
  1754. if (i->idx == idx && i->depth >= depth)
  1755. i->depth = i->depth > -1 ? i->depth - 1 : -1;
  1756. } else {
  1757. if (i->idx >= idx) {
  1758. if ((i->idx -= n) >= 0)
  1759. i->hr = i->hl->hr[i->idx];
  1760. else
  1761. hostlist_iterator_reset(i);
  1762. }
  1763. }
  1764. }
  1765. }
  1766. char *hostlist_shift(hostlist_t hl)
  1767. {
  1768. char *host = NULL;
  1769. if(!hl){
  1770. error("hostlist_shift: no hostlist given");
  1771. return NULL;
  1772. }
  1773. LOCK_HOSTLIST(hl);
  1774. if (hl->nhosts > 0) {
  1775. hostrange_t hr = hl->hr[0];
  1776. host = hostrange_shift(hr);
  1777. hl->nhosts--;
  1778. if (hostrange_empty(hr)) {
  1779. hostlist_delete_range(hl, 0);
  1780. /* hl->nranges--; */
  1781. } else
  1782. hostlist_shift_iterators(hl, 0, 0, 0);
  1783. }
  1784. UNLOCK_HOSTLIST(hl);
  1785. return host;
  1786. }
  1787. char *hostlist_pop_range(hostlist_t hl)
  1788. {
  1789. int i;
  1790. char *buf;
  1791. hostlist_t hltmp;
  1792. hostrange_t tail;
  1793. if(!hl)
  1794. return NULL;
  1795. LOCK_HOSTLIST(hl);
  1796. if (hl->nranges < 1 || !(hltmp = hostlist_new())) {
  1797. UNLOCK_HOSTLIST(hl);
  1798. return NULL;
  1799. }
  1800. i = hl->nranges - 2;
  1801. tail = hl->hr[hl->nranges - 1];
  1802. while (i >= 0 && hostrange_within_range(tail, hl->hr[i]))
  1803. i--;
  1804. for (i++; i < hl->nranges; i++) {
  1805. hostlist_push_range(hltmp, hl->hr[i]);
  1806. hostrange_destroy(hl->hr[i]);
  1807. hl->hr[i] = NULL;
  1808. }
  1809. hl->nhosts -= hltmp->nhosts;
  1810. hl->nranges -= hltmp->nranges;
  1811. UNLOCK_HOSTLIST(hl);
  1812. buf = hostlist_ranged_string_malloc(hltmp);
  1813. hostlist_destroy(hltmp);
  1814. return buf;
  1815. }
  1816. char *hostlist_shift_range(hostlist_t hl)
  1817. {
  1818. int i;
  1819. char *buf;
  1820. hostlist_t hltmp = hostlist_new();
  1821. if (!hltmp || !hl)
  1822. return NULL;
  1823. LOCK_HOSTLIST(hl);
  1824. if (hl->nranges == 0) {
  1825. hostlist_destroy(hltmp);
  1826. UNLOCK_HOSTLIST(hl);
  1827. return NULL;
  1828. }
  1829. i = 0;
  1830. do {
  1831. hostlist_push_range(hltmp, hl->hr[i]);
  1832. hostrange_destroy(hl->hr[i]);
  1833. } while ( (++i < hl->nranges)
  1834. && hostrange_within_range(hltmp->hr[0], hl->hr[i]) );
  1835. hostlist_shift_iterators(hl, i, 0, hltmp->nranges);
  1836. /* shift rest of ranges back in hl */
  1837. for (; i < hl->nranges; i++) {
  1838. hl->hr[i - hltmp->nranges] = hl->hr[i];
  1839. hl->hr[i] = NULL;
  1840. }
  1841. hl->nhosts -= hltmp->nhosts;
  1842. hl->nranges -= hltmp->nranges;
  1843. UNLOCK_HOSTLIST(hl);
  1844. buf = hostlist_ranged_string_malloc(hltmp);
  1845. hostlist_destroy(hltmp);
  1846. return buf;
  1847. }
  1848. /* XXX: Note: efficiency improvements needed */
  1849. int hostlist_delete(hostlist_t hl, const char *hosts)
  1850. {
  1851. int n = 0;
  1852. char *hostname = NULL;
  1853. hostlist_t hltmp;
  1854. if(!hl)
  1855. return -1;
  1856. if (!(hltmp = hostlist_create(hosts)))
  1857. seterrno_ret(EINVAL, 0);
  1858. while ((hostname = hostlist_pop(hltmp)) != NULL) {
  1859. n += hostlist_delete_host(hl, hostname);
  1860. free(hostname);
  1861. }
  1862. hostlist_destroy(hltmp);
  1863. return n;
  1864. }
  1865. /* XXX watch out! poor implementation follows! (fix it at some point) */
  1866. int hostlist_delete_host(hostlist_t hl, const char *hostname)
  1867. {
  1868. int n;
  1869. if(!hl)
  1870. return -1;
  1871. n = hostlist_find(hl, hostname);
  1872. if (n >= 0)
  1873. hostlist_delete_nth(hl, n);
  1874. return n >= 0 ? 1 : 0;
  1875. }
  1876. static char *
  1877. _hostrange_string(hostrange_t hr, int depth)
  1878. {
  1879. char buf[MAXHOSTNAMELEN + 16];
  1880. const int size = sizeof(buf);
  1881. int len = snprintf(buf, size, "%s", hr->prefix);
  1882. int dims = slurmdb_setup_cluster_name_dims();
  1883. if (len < 0 || len + dims >= size)
  1884. return NULL;
  1885. if (!hr->singlehost) {
  1886. if ((dims > 1) && (hr->width == dims)) {
  1887. int i2 = 0;
  1888. int coord[dims];
  1889. hostlist_parse_int_to_array(
  1890. hr->lo + depth, coord, dims, 0);
  1891. while (i2 < dims)
  1892. buf[len++] = alpha_num[coord[i2++]];
  1893. buf[len] = '\0';
  1894. } else {
  1895. len = snprintf(buf + len, size - len, "%0*lu",
  1896. hr->width, hr->lo + depth);
  1897. if (len < 0 || len >= size)
  1898. return NULL;
  1899. }
  1900. }
  1901. return strdup(buf);
  1902. }
  1903. char * hostlist_nth(hostlist_t hl, int n)
  1904. {
  1905. char *host = NULL;
  1906. int i, count;
  1907. if(!hl)
  1908. return NULL;
  1909. LOCK_HOSTLIST(hl);
  1910. count = 0;
  1911. for (i = 0; i < hl->nranges; i++) {
  1912. int num_in_range = hostrange_count(hl->hr[i]);
  1913. if (n <= (num_in_range - 1 + count)) {
  1914. host = _hostrange_string(hl->hr[i], n - count);
  1915. break;
  1916. } else
  1917. count += num_in_range;
  1918. }
  1919. UNLOCK_HOSTLIST(hl);
  1920. return host;
  1921. }
  1922. int hostlist_delete_nth(hostlist_t hl, int n)
  1923. {
  1924. int i, count;
  1925. if(!hl)
  1926. return -1;
  1927. LOCK_HOSTLIST(hl);
  1928. assert(n >= 0 && n <= hl->nhosts);
  1929. count = 0;
  1930. for (i = 0; i < hl->nranges; i++) {
  1931. int num_in_range = hostrange_count(hl->hr[i]);
  1932. hostrange_t hr = hl->hr[i];
  1933. if (n <= (num_in_range - 1 + count)) {
  1934. unsigned long num = hr->lo + n - count;
  1935. hostrange_t new;
  1936. if (hr->singlehost) { /* this wasn't a range */
  1937. hostlist_delete_range(hl, i);
  1938. } else if ((new = hostrange_delete_host(hr, num))) {
  1939. hostlist_insert_range(hl, new, i + 1);
  1940. hostrange_destroy(new);
  1941. } else if (hostrange_empty(hr))
  1942. hostlist_delete_range(hl, i);
  1943. goto done;
  1944. } else
  1945. count += num_in_range;
  1946. }
  1947. done:
  1948. UNLOCK_HOSTLIST(hl);
  1949. hl->nhosts--;
  1950. return 1;
  1951. }
  1952. int hostlist_count(hostlist_t hl)
  1953. {
  1954. int retval;
  1955. if(!hl)
  1956. return -1;
  1957. LOCK_HOSTLIST(hl);
  1958. retval = hl->nhosts;
  1959. UNLOCK_HOSTLIST(hl);
  1960. return retval;
  1961. }
  1962. int hostlist_find(hostlist_t hl, const char *hostname)
  1963. {
  1964. int i, count, ret = -1;
  1965. hostname_t hn;
  1966. if (!hostname || !hl)
  1967. return -1;
  1968. hn = hostname_create(hostname);
  1969. LOCK_HOSTLIST(hl);
  1970. for (i = 0, count = 0; i < hl->nranges; i++) {
  1971. if (hostrange_hn_within(hl->hr[i], hn)) {
  1972. if (hostname_suffix_is_valid(hn))
  1973. ret = count + hn->num - hl->hr[i]->lo;
  1974. else
  1975. ret = count;
  1976. goto done;
  1977. } else
  1978. count += hostrange_count(hl->hr[i]);
  1979. }
  1980. done:
  1981. UNLOCK_HOSTLIST(hl);
  1982. hostname_destroy(hn);
  1983. return ret;
  1984. }
  1985. /* hostrange compare with void * arguments to allow use with
  1986. * libc qsort()
  1987. */
  1988. int _cmp(const void *hr1, const void *hr2)
  1989. {
  1990. hostrange_t *h1 = (hostrange_t *) hr1;
  1991. hostrange_t *h2 = (hostrange_t *) hr2;
  1992. return hostrange_cmp((hostrange_t) * h1, (hostrange_t) * h2);
  1993. }
  1994. void hostlist_sort(hostlist_t hl)
  1995. {
  1996. hostlist_iterator_t i;
  1997. LOCK_HOSTLIST(hl);
  1998. if (hl->nranges <= 1) {
  1999. UNLOCK_HOSTLIST(hl);
  2000. return;
  2001. }
  2002. qsort(hl->hr, hl->nranges, sizeof(hostrange_t), &_cmp);
  2003. /* reset all iterators */
  2004. for (i = hl->ilist; i; i = i->next)
  2005. hostlist_iterator_reset(i);
  2006. UNLOCK_HOSTLIST(hl);
  2007. hostlist_coalesce(hl);
  2008. }
  2009. /* search through hostlist for ranges that can be collapsed
  2010. * does =not= delete any hosts
  2011. */
  2012. static void hostlist_collapse(hostlist_t hl)
  2013. {
  2014. int i;
  2015. LOCK_HOSTLIST(hl);
  2016. for (i = hl->nranges - 1; i > 0; i--) {
  2017. hostrange_t hprev = hl->hr[i - 1];
  2018. hostrange_t hnext = hl->hr[i];
  2019. if (hostrange_prefix_cmp(hprev, hnext) == 0 &&
  2020. hprev->hi == hnext->lo - 1 &&
  2021. hostrange_width_combine(hprev, hnext)) {
  2022. hprev->hi = hnext->hi;
  2023. hostlist_delete_range(hl, i);
  2024. }
  2025. }
  2026. UNLOCK_HOSTLIST(hl);
  2027. }
  2028. /* search through hostlist (hl) for intersecting ranges
  2029. * split up duplicates and coalesce ranges where possible
  2030. */
  2031. static void hostlist_coalesce(hostlist_t hl)
  2032. {
  2033. int i, j;
  2034. hostrange_t new;
  2035. LOCK_HOSTLIST(hl);
  2036. for (i = hl->nranges - 1; i > 0; i--) {
  2037. new = hostrange_intersect(hl->hr[i - 1], hl->hr[i]);
  2038. if (new) {
  2039. hostrange_t hprev = hl->hr[i - 1];
  2040. hostrange_t hnext = hl->hr[i];
  2041. j = i;
  2042. if (new->hi < hprev->hi)
  2043. hnext->hi = hprev->hi;
  2044. hprev->hi = new->lo;
  2045. hnext->lo = new->hi;
  2046. if (hostrange_empty(hprev))
  2047. hostlist_delete_range(hl, i);
  2048. while (new->lo <= new->hi) {
  2049. hostrange_t hr = hostrange_create( new->prefix,
  2050. new->lo, new->lo,
  2051. new->width );
  2052. if (new->lo > hprev->hi)
  2053. hostlist_insert_range(hl, hr, j++);
  2054. if (new->lo < hnext->lo)
  2055. hostlist_insert_range(hl, hr, j++);
  2056. hostrange_destroy(hr);
  2057. new->lo++;
  2058. }
  2059. i = hl->nranges;
  2060. hostrange_destroy(new);
  2061. }
  2062. }
  2063. UNLOCK_HOSTLIST(hl);
  2064. hostlist_collapse(hl);
  2065. }
  2066. /* attempt to join ranges at loc and loc-1 in a hostlist */
  2067. /* delete duplicates, return the number of hosts deleted */
  2068. /* assumes that the hostlist hl has been locked by caller */
  2069. /* returns -1 if no range join occured */
  2070. static int _attempt_range_join(hostlist_t hl, int loc)
  2071. {
  2072. int ndup;
  2073. assert(hl != NULL);
  2074. assert(hl->magic == HOSTLIST_MAGIC);
  2075. assert(loc > 0);
  2076. assert(loc < hl->nranges);
  2077. ndup = hostrange_join(hl->hr[loc - 1], hl->hr[loc]);
  2078. if (ndup >= 0) {
  2079. hostlist_delete_range(hl, loc);
  2080. hl->nhosts -= ndup;
  2081. }
  2082. return ndup;
  2083. }
  2084. void hostlist_uniq(hostlist_t hl)
  2085. {
  2086. int i = 1;
  2087. hostlist_iterator_t hli;
  2088. LOCK_HOSTLIST(hl);
  2089. if (hl->nranges <= 1) {
  2090. UNLOCK_HOSTLIST(hl);
  2091. return;
  2092. }
  2093. qsort(hl->hr, hl->nranges, sizeof(hostrange_t), &_cmp);
  2094. while (i < hl->nranges) {
  2095. if (_attempt_range_join(hl, i) < 0) /* No range join occurred */
  2096. i++;
  2097. }
  2098. /* reset all iterators */
  2099. for (hli = hl->ilist; hli; hli = hli->next)
  2100. hostlist_iterator_reset(hli);
  2101. UNLOCK_HOSTLIST(hl);
  2102. }
  2103. char *hostlist_deranged_string_malloc(hostlist_t hl)
  2104. {
  2105. int buf_size = 8192;
  2106. char *buf = malloc(buf_size);
  2107. while (buf && (hostlist_deranged_string(hl, buf_size, buf) < 0)) {
  2108. buf_size *= 2;
  2109. buf = realloc(buf, buf_size);
  2110. }
  2111. return buf;
  2112. }
  2113. char *hostlist_deranged_string_xmalloc_dims(hostlist_t hl, int dims)
  2114. {
  2115. int buf_size = 8192;
  2116. char *buf = xmalloc(buf_size);
  2117. if (!dims)
  2118. dims = slurmdb_setup_cluster_name_dims();
  2119. while (hostlist_deranged_string_dims(hl, buf_size, buf, dims) < 0) {
  2120. buf_size *= 2;
  2121. xrealloc(buf, buf_size);
  2122. }
  2123. return buf;
  2124. }
  2125. char *hostlist_deranged_string_xmalloc(hostlist_t hl)
  2126. {
  2127. int dims = slurmdb_setup_cluster_name_dims();
  2128. return hostlist_deranged_string_xmalloc_dims(hl, dims);
  2129. }
  2130. ssize_t hostlist_deranged_string_dims(
  2131. hostlist_t hl, size_t n, char *buf, int dims)
  2132. {
  2133. int i;
  2134. int len = 0, ret;
  2135. LOCK_HOSTLIST(hl);
  2136. for (i = 0; i < hl->nranges && len < n; i++) {
  2137. if (i)
  2138. buf[len++] = ',';
  2139. if (len >= n)
  2140. goto truncated;
  2141. ret = hostrange_to_string(hl->hr[i], n - len, buf + len, ",", dims);
  2142. if (ret < 0)
  2143. goto truncated;
  2144. len += ret;
  2145. }
  2146. UNLOCK_HOSTLIST(hl);
  2147. return len;
  2148. truncated:
  2149. UNLOCK_HOSTLIST(hl);
  2150. buf[n-1] = '\0';
  2151. return -1;
  2152. }
  2153. ssize_t hostlist_deranged_string(hostlist_t hl, size_t n, char *buf)
  2154. {
  2155. int dims = slurmdb_setup_cluster_name_dims();
  2156. return hostlist_deranged_string_dims(hl, n, buf, dims);
  2157. }
  2158. /* convert 'in' polynomial of base 'base' to 'out' array of 'dim' dimensions */
  2159. void hostlist_parse_int_to_array(int in, int *out, int dims, int base)
  2160. {
  2161. int hostlist_base = base ? base : hostlist_get_base(dims);
  2162. for ( ; --dims >= 0; in /= hostlist_base)
  2163. out[dims] = in % hostlist_base;
  2164. }
  2165. /* return true if a bracket is needed for the range at i in hostlist hl */
  2166. static int _is_bracket_needed(hostlist_t hl, int i)
  2167. {
  2168. hostrange_t h1 = hl->hr[i];
  2169. hostrange_t h2 = i < hl->nranges - 1 ? hl->hr[i + 1] : NULL;
  2170. return hostrange_count(h1) > 1 || hostrange_within_range(h1, h2);
  2171. }
  2172. /* write the next bracketed hostlist, i.e. prefix[n-m,k,...]
  2173. * into buf, writing at most n chars including the terminating '\0'
  2174. *
  2175. * leaves start pointing to one past last range object in bracketed list,
  2176. * and returns the number of bytes written into buf.
  2177. *
  2178. * Assumes hostlist is locked.
  2179. */
  2180. static int
  2181. _get_bracketed_list(hostlist_t hl, int *start, const size_t n, char *buf)
  2182. {
  2183. hostrange_t *hr = hl->hr;
  2184. int i = *start;
  2185. int m, len = 0;
  2186. int bracket_needed = _is_bracket_needed(hl, i);
  2187. int zeropad = 0;
  2188. uint32_t cluster_flags = slurmdb_setup_cluster_flags();
  2189. if (cluster_flags & CLUSTER_FLAG_CRAYXT) {
  2190. /*
  2191. * Find minimum common zero-padding prefix. Cray has nid%05u
  2192. * syntax, factoring this out makes host strings much shorter.
  2193. */
  2194. zeropad = _zero_padded(hr[i]->hi, hr[i]->width);
  2195. /* Find the minimum common zero-padding prefix. */
  2196. for (m = i + 1; zeropad && m < hl->nranges; m++) {
  2197. int pad = 0;
  2198. if (!hostrange_within_range(hr[m], hr[m-1]))
  2199. break;
  2200. if (hl->hr[m]->width == hl->hr[m-1]->width)
  2201. pad = _zero_padded(hr[m]->hi, hr[m]->width);
  2202. if (pad < zeropad)
  2203. zeropad = pad;
  2204. }
  2205. }
  2206. if (zeropad)
  2207. len = snprintf(buf, n, "%s%0*u", hr[i]->prefix, zeropad, 0);
  2208. else
  2209. len = snprintf(buf, n, "%s", hr[i]->prefix);
  2210. if (len < 0 || len + 4 >= n) /* min: '[', <digit>, ']', '\0' */
  2211. return n; /* truncated, buffer filled */
  2212. if (bracket_needed)
  2213. buf[len++] = '[';
  2214. do {
  2215. if (i > *start)
  2216. buf[len++] = ',';
  2217. m = hostrange_numstr(hr[i], n - len, buf + len, zeropad);
  2218. if (m < 0 || (len += m) >= n - 1) /* insufficient space */
  2219. return n;
  2220. } while (++i < hl->nranges && hostrange_within_range(hr[i], hr[i-1]));
  2221. if (bracket_needed)
  2222. buf[len++] = ']';
  2223. buf[len] = '\0';
  2224. *start = i;
  2225. return len;
  2226. }
  2227. static int _tell_if_used(int dim, int curr,
  2228. int *start,
  2229. int *end,
  2230. int *last, int *found, int dims)
  2231. {
  2232. int rc = 1;
  2233. int start_curr = curr;
  2234. /* int i; */
  2235. /* char coord[dims+1]; */
  2236. /* memset(coord, 0, sizeof(coord)); */
  2237. for (last[dim]=start[dim]; last[dim]<=grid_end[dim]; last[dim]++) {
  2238. curr = start_curr + (last[dim] * offset[dim]);
  2239. if(dim == (dims-1)) {
  2240. if (!grid[curr]) {
  2241. /* for(i = 0; i<dims; i++) { */
  2242. /* coord[i] = alpha_num[last[i]]; */
  2243. /* } */
  2244. /* info("%s not used", coord); */
  2245. if((*found) == -1)
  2246. continue;
  2247. else if(end[dim] < grid_end[dim]) {
  2248. /* try to get a box out of
  2249. this slice. */
  2250. grid_end[dim] = end[dim];
  2251. goto end_it;
  2252. } else
  2253. return 0;
  2254. }
  2255. /* for(i = 0; i<dims; i++) { */
  2256. /* coord[i] = alpha_num[last[i]]; */
  2257. /* } */
  2258. /* info("%s used", coord); */
  2259. if((*found) == -1) {
  2260. /* for(i = 0; i<dims; i++) { */
  2261. /* coord[i] = alpha_num[last[i]]; */
  2262. /* } */
  2263. /* info("box starts at %s", coord); */
  2264. memcpy(start, last, dim_grid_size);
  2265. memcpy(end, last, dim_grid_size);
  2266. (*found) = dims;
  2267. } else if((*found) >= dim) {
  2268. /* for(i = 0; i<dims; i++) { */
  2269. /* coord[i] = alpha_num[last[i]]; */
  2270. /* } */
  2271. /* info("first end %d here %s", dim, coord); */
  2272. memcpy(end, last, dim_grid_size);
  2273. (*found) = dim;
  2274. }
  2275. } else {
  2276. if((rc = _tell_if_used(dim+1, curr,
  2277. start, end,
  2278. last, found, dims)) != 1) {
  2279. return rc;
  2280. }
  2281. if((*found) >= dim) {
  2282. /* for(i = 0; i<dims; i++) { */
  2283. /* coord[i] = alpha_num[last[i]]; */
  2284. /* } */
  2285. /* info("%d here %s", dim, coord); */
  2286. memcpy(end, last, dim_grid_size);
  2287. (*found) = dim;
  2288. } else if((*found) == -1)
  2289. start[dim] = grid_start[dim];
  2290. }
  2291. }
  2292. end_it:
  2293. last[dim]--;
  2294. return rc;
  2295. }
  2296. static int _get_next_box(int *start, int *end, int dims)
  2297. {
  2298. int hostlist_base = hostlist_get_base(dims);
  2299. static int orig_grid_end[HIGHEST_DIMENSIONS];
  2300. static int last[HIGHEST_DIMENSIONS];
  2301. int pos[dims];
  2302. /* int i; */
  2303. /* char coord[dims+1]; */
  2304. /* char coord2[dims+1]; */
  2305. int found = -1;
  2306. int rc = 0;
  2307. int new_min[dims];
  2308. int new_max[dims];
  2309. /* memset(coord, 0, sizeof(coord)); */
  2310. /* memset(coord2, 0, sizeof(coord2)); */
  2311. again:
  2312. if(start[0] == -1) {
  2313. memcpy(start, grid_start, dim_grid_size);
  2314. /* We need to keep track of this to make sure we get
  2315. all the nodes marked since this could change based
  2316. on the boxes we are able to make.
  2317. */
  2318. memcpy(orig_grid_end, grid_end, dim_grid_size);
  2319. } else
  2320. memcpy(start, last, dim_grid_size);
  2321. memcpy(end, start, dim_grid_size);
  2322. /* for(i = 0; i<dims; i++) { */
  2323. /* coord[i] = alpha_num[start[i]]; */
  2324. /* } */
  2325. /* info("beginning with %s dims %d", coord, dims); */
  2326. _tell_if_used(0, 0, start, end, last, &found, dims);
  2327. /* for(i = 0; i<dims; i++) { */
  2328. /* coord[i] = alpha_num[grid_start[i]]; */
  2329. /* coord2[i] = alpha_num[grid_end[i]]; */
  2330. /* } */
  2331. /* info("current grid is %sx%s", coord, coord2); */
  2332. /* remove what we just did */
  2333. _set_box_in_grid(0, 0, start, end, false, dims);
  2334. /* set the new min max of the grid */
  2335. memset(new_min, hostlist_base, dim_grid_size);
  2336. memset(new_max, -1, dim_grid_size);
  2337. /* send the orid_grid_end so we don't miss anything that was set. */
  2338. _set_min_max_of_grid(0, 0, grid_start, orig_grid_end,
  2339. new_min, new_max, pos, dims);
  2340. if(new_max[0] != -1) {
  2341. /* for(i = 0; i<dims; i++) { */
  2342. /* coord[i] = alpha_num[new_min[i]]; */
  2343. /* coord2[i] = alpha_num[new_max[i]]; */
  2344. /* } */
  2345. /* info("here with %sx%s", coord, coord2); */
  2346. memcpy(grid_start, new_min, dim_grid_size);
  2347. memcpy(grid_end, new_max, dim_grid_size);
  2348. memcpy(last, grid_start, dim_grid_size);
  2349. /* for(i = 0; i<dims; i++) */
  2350. /* coord[i] = alpha_num[last[i]]; */
  2351. /* info("next start %s", coord); */
  2352. if(found == -1) {
  2353. /* There are still nodes set in the grid, so we need
  2354. to go through them again to make sure we got all
  2355. the nodes that weren't included in the boxes of
  2356. previous runs. */
  2357. goto again;
  2358. }
  2359. }
  2360. if(found != -1)
  2361. rc = 1;
  2362. return rc;
  2363. }
  2364. /* logic for block node description */
  2365. /* write the next bracketed hostlist, i.e. prefix[n-m,k,...]
  2366. * into buf, writing at most n chars including the terminating '\0'
  2367. *
  2368. * leaves start pointing to one past last range object in bracketed list,
  2369. * and returns the number of bytes written into buf.
  2370. *
  2371. * Assumes hostlist is locked.
  2372. */
  2373. static int
  2374. _get_boxes(char *buf, int max_len, int dims, int brackets)
  2375. {
  2376. int len=0, i;
  2377. int curr_min[dims], curr_max[dims];
  2378. /* char coord[dims+1]; */
  2379. /* char coord2[dims+1]; */
  2380. /* memset(coord, 0, sizeof(coord)); */
  2381. /* memset(coord2, 0, sizeof(coord2)); */
  2382. /* this means we are at the beginning */
  2383. curr_min[0] = -1;
  2384. /* for(i=0; i<HOSTLIST_BASE*HOSTLIST_BASE*HOSTLIST_BASE*HOSTLIST_BASE; i++) { */
  2385. /* if(grid[i]) */
  2386. /* info("got one at %d", i); */
  2387. /* } */
  2388. while(_get_next_box(curr_min, curr_max, dims)) {
  2389. /* for(i = 0; i<dims; i++) { */
  2390. /* coord[i] = alpha_num[curr_min[i]]; */
  2391. /* coord2[i] = alpha_num[curr_max[i]]; */
  2392. /* } */
  2393. /* info("%sx%s is a box", coord, coord2); */
  2394. if(!memcmp(curr_min, curr_max, dim_grid_size)) {
  2395. for(i = 0; i<dims; i++) {
  2396. if(len >= max_len)
  2397. goto end_it;
  2398. buf[len++] = alpha_num[curr_min[i]];
  2399. }
  2400. if(len >= max_len)
  2401. goto end_it;
  2402. buf[len++] = ',';
  2403. } else {
  2404. for(i = 0; i<dims; i++) {
  2405. if(len >= max_len)
  2406. goto end_it;
  2407. buf[len++] = alpha_num[curr_min[i]];
  2408. }
  2409. if(len >= max_len)
  2410. goto end_it;
  2411. buf[len++] = 'x';
  2412. for(i = 0; i<dims; i++) {
  2413. if(len >= max_len)
  2414. goto end_it;
  2415. buf[len++] = alpha_num[curr_max[i]];
  2416. }
  2417. if(len >= max_len)
  2418. goto end_it;
  2419. buf[len++] = ',';
  2420. }
  2421. }
  2422. if (brackets)
  2423. buf[len - 1] = ']';
  2424. else
  2425. buf[len - 1] = '\0';
  2426. end_it:
  2427. /* NUL terminate for safety, but do not add terminator to len */
  2428. buf[len] = '\0';
  2429. return len;
  2430. }
  2431. static void
  2432. _set_box_in_grid(int dim, int curr, int *start,
  2433. int *end, bool value, int dims)
  2434. {
  2435. int i;
  2436. int start_curr = curr;
  2437. for (i=start[dim]; i<=end[dim]; i++) {
  2438. curr = start_curr + (i * offset[dim]);
  2439. if(dim == (dims-1))
  2440. grid[curr] = value;
  2441. else
  2442. _set_box_in_grid(dim+1, curr, start, end, value, dims);
  2443. }
  2444. }
  2445. static int _add_box_ranges(int dim, int curr,
  2446. int *start,
  2447. int *end,
  2448. int *pos,
  2449. struct _range *ranges,
  2450. int len, int *count, int dims)
  2451. {
  2452. int i;
  2453. int start_curr = curr;
  2454. for (pos[dim]=start[dim]; pos[dim]<=end[dim]; pos[dim]++) {
  2455. curr = start_curr + (pos[dim] * offset[dim]);
  2456. if(dim == (dims-2)) {
  2457. char new_str[(dims*2)+2];
  2458. memset(new_str, 0, sizeof(new_str));
  2459. if (*count == len) {
  2460. errno = EINVAL;
  2461. _error(__FILE__, __LINE__,
  2462. "Too many ranges, can't process "
  2463. "entire list");
  2464. return 0;
  2465. }
  2466. new_str[dims] = '-';
  2467. for(i = 0; i<(dims-1); i++) {
  2468. new_str[i] = alpha_num[pos[i]];
  2469. new_str[dims+i+1] =
  2470. alpha_num[pos[i]];
  2471. }
  2472. new_str[i] = alpha_num[start[i]];
  2473. new_str[dims+i+1] = alpha_num[end[i]];
  2474. /* info("got %s", new_str); */
  2475. if (!_parse_single_range(
  2476. new_str, &ranges[*count], dims))
  2477. return 0;
  2478. (*count)++;
  2479. } else
  2480. if(!_add_box_ranges(dim+1, curr, start, end, pos,
  2481. ranges, len, count, dims))
  2482. return 0;
  2483. }
  2484. return 1;
  2485. }
  2486. static void _set_min_max_of_grid(int dim, int curr,
  2487. int *start,
  2488. int *end,
  2489. int *min,
  2490. int *max,
  2491. int *pos,
  2492. int dims)
  2493. {
  2494. int i;
  2495. int start_curr = curr;
  2496. for (pos[dim]=start[dim]; pos[dim]<=end[dim]; pos[dim]++) {
  2497. curr = start_curr + (pos[dim] * offset[dim]);
  2498. if(dim == (dims-1)) {
  2499. if(!grid[curr])
  2500. continue;
  2501. for(i = 0; i<dims; i++) {
  2502. min[i] = MIN(min[i], pos[i]);
  2503. max[i] = MAX(max[i], pos[i]);
  2504. }
  2505. } else
  2506. _set_min_max_of_grid(dim+1, curr, start, end,
  2507. min, max, pos, dims);
  2508. }
  2509. }
  2510. static void
  2511. _set_grid(unsigned long start, unsigned long end, int dims)
  2512. {
  2513. int sent_start[dims], sent_end[dims];
  2514. int i;
  2515. /* char coord[dims+1]; */
  2516. /* char coord2[dims+1]; */
  2517. /* memset(coord, 0, sizeof(coord)); */
  2518. /* memset(coord2, 0, sizeof(coord2)); */
  2519. hostlist_parse_int_to_array(start, sent_start, dims, 0);
  2520. hostlist_parse_int_to_array(end, sent_end, dims, 0);
  2521. for(i = 0; i<dims; i++) {
  2522. grid_start[i] = MIN(grid_start[i], sent_start[i]);
  2523. grid_end[i] = MAX(grid_end[i], sent_end[i]);
  2524. /* coord[i] = alpha_num[sent_start[i]]; */
  2525. /* coord2[i] = alpha_num[sent_end[i]]; */
  2526. }
  2527. /* info("going to set %sx%s", coord, coord2); */
  2528. _set_box_in_grid(0, 0, sent_start, sent_end, true, dims);
  2529. }
  2530. static bool
  2531. _test_box_in_grid(int dim, int curr,
  2532. int *start, int *end, int dims)
  2533. {
  2534. int i;
  2535. int start_curr = curr;
  2536. for (i=start[dim]; i<=end[dim]; i++) {
  2537. curr = start_curr + (i * offset[dim]);
  2538. if(dim == (dims-1)) {
  2539. if(!grid[curr])
  2540. return false;
  2541. } else {
  2542. if(!_test_box_in_grid(dim+1, curr, start, end, dims))
  2543. return false;
  2544. }
  2545. }
  2546. return true;
  2547. }
  2548. static bool
  2549. _test_box(int *start, int *end, int dims)
  2550. {
  2551. int i;
  2552. if (!memcmp(start, end, dim_grid_size)) /* single node */
  2553. return false;
  2554. for (i = 0; i<dims; i++)
  2555. if (start[i] > end[i])
  2556. return false;
  2557. return _test_box_in_grid(0, 0, start, end, dims);
  2558. }
  2559. char *hostlist_ranged_string_malloc(hostlist_t hl)
  2560. {
  2561. int buf_size = 8192;
  2562. char *buf = malloc(buf_size);
  2563. while (buf && (hostlist_ranged_string(hl, buf_size, buf) < 0)) {
  2564. buf_size *= 2;
  2565. buf = realloc(buf, buf_size);
  2566. }
  2567. return buf;
  2568. }
  2569. char *hostlist_ranged_string_xmalloc_dims(
  2570. hostlist_t hl, int dims, int brackets)
  2571. {
  2572. int buf_size = 8192;
  2573. char *buf = xmalloc(buf_size);
  2574. while (hostlist_ranged_string_dims(
  2575. hl, buf_size, buf, dims, brackets) < 0) {
  2576. buf_size *= 2;
  2577. xrealloc(buf, buf_size);
  2578. }
  2579. return buf;
  2580. }
  2581. char *hostlist_ranged_string_xmalloc(hostlist_t hl)
  2582. {
  2583. int dims = slurmdb_setup_cluster_name_dims();
  2584. return hostlist_ranged_string_xmalloc_dims(hl, dims, 1);
  2585. }
  2586. ssize_t hostlist_ranged_string_dims(hostlist_t hl, size_t n,
  2587. char *buf, int dims, int brackets)
  2588. {
  2589. int i = 0;
  2590. int len = 0;
  2591. int truncated = 0;
  2592. bool box = false;
  2593. int hostlist_base;
  2594. static int last_dims = -1;
  2595. DEF_TIMERS;
  2596. if (!dims)
  2597. dims = slurmdb_setup_cluster_name_dims();
  2598. hostlist_base = hostlist_get_base(dims);
  2599. START_TIMER;
  2600. LOCK_HOSTLIST(hl);
  2601. if (dims > 1 && hl->nranges) { /* logic for block node description */
  2602. slurm_mutex_lock(&multi_dim_lock);
  2603. /* compute things that only need to be calculated once
  2604. * (unless you change the dimensions of the
  2605. * hostlist. This can happen on a BGQ system.
  2606. */
  2607. if ((last_dims != dims) || (dim_grid_size == -1)) {
  2608. last_dims = dims;
  2609. dim_grid_size = sizeof(int) * dims;
  2610. /* the last one is always 1 */
  2611. offset[dims-1] = 1;
  2612. for (i=(dims-2); i>=0; i--)
  2613. offset[i] = offset[i+1] * hostlist_base;
  2614. }
  2615. memset(grid, 0, sizeof(grid));
  2616. memset(grid_start, hostlist_base, dim_grid_size);
  2617. memset(grid_end, -1, dim_grid_size);
  2618. for (i=0; i<hl->nranges; i++) {
  2619. /* info("got %s %d %d-%d", hl->hr[i]->prefix, */
  2620. /* hl->hr[i]->width, hl->hr[i]->lo, */
  2621. /* hl->hr[i]->hi); */
  2622. if (hl->hr[i]->width != dims) {
  2623. /* We use this logic to build task
  2624. * list ranges, so this does not
  2625. * necessarily contain a dims dimensional
  2626. * host list. It could just be numeric values */
  2627. if (hl->hr[i]->prefix[0]) {
  2628. debug4("This node is not in %dD "
  2629. "format. Prefix of range %d "
  2630. "is %s and suffix is "
  2631. "%d chars long",
  2632. dims, i,
  2633. hl->hr[i]->prefix,
  2634. hl->hr[i]->width);
  2635. } else {
  2636. debug3("This node is not in %dD "
  2637. "format. "
  2638. "No prefix for range %d but "
  2639. "suffix is %d chars long",
  2640. dims, i, hl->hr[i]->width);
  2641. }
  2642. goto notbox;
  2643. }
  2644. _set_grid(hl->hr[i]->lo, hl->hr[i]->hi, dims);
  2645. }
  2646. if (!memcmp(grid_start, grid_end, dim_grid_size)) {
  2647. len = snprintf(buf, n, "%s", hl->hr[0]->prefix);
  2648. if (len < 0 || ((len + dims) >= n))
  2649. goto too_long;
  2650. for (i = 0; i < dims; i++)
  2651. buf[len++] = alpha_num[grid_start[i]];
  2652. } else if (!_test_box(grid_start, grid_end, dims)) {
  2653. len = snprintf(buf, n, "%s", hl->hr[0]->prefix);
  2654. if (len < 0 || (len+1) >= n)
  2655. goto too_long;
  2656. if (brackets)
  2657. buf[len++] = '[';
  2658. len += _get_boxes(buf + len, (n-len), dims, brackets);
  2659. } else {
  2660. len = snprintf(buf, n, "%s", hl->hr[0]->prefix);
  2661. if (len < 0 || ((len + 3 + (dims * 2)) >= n))
  2662. goto too_long;
  2663. if (brackets)
  2664. buf[len++] = '[';
  2665. for (i = 0; i < dims; i++)
  2666. buf[len++] = alpha_num[grid_start[i]];
  2667. buf[len++] = 'x';
  2668. for (i = 0; i < dims; i++)
  2669. buf[len++] = alpha_num[grid_end[i]];
  2670. if (brackets)
  2671. buf[len++] = ']';
  2672. }
  2673. if ((len < 0) || (len > n))
  2674. too_long:
  2675. len = n; /* truncated */
  2676. box = true;
  2677. notbox:
  2678. slurm_mutex_unlock(&multi_dim_lock);
  2679. }
  2680. if (!box) {
  2681. for (i = 0; i < hl->nranges && len < n;) {
  2682. if (i)
  2683. buf[len++] = ',';
  2684. len += _get_bracketed_list(hl, &i, n - len, buf + len);
  2685. }
  2686. }
  2687. UNLOCK_HOSTLIST(hl);
  2688. /* NUL terminate */
  2689. if (len >= n) {
  2690. truncated = 1;
  2691. if (n > 0)
  2692. buf[n-1] = '\0';
  2693. } else
  2694. buf[len] = '\0';
  2695. END_TIMER;
  2696. // info("time was %s", TIME_STR);
  2697. return truncated ? -1 : len;
  2698. }
  2699. ssize_t hostlist_ranged_string(hostlist_t hl, size_t n, char *buf)
  2700. {
  2701. int dims = slurmdb_setup_cluster_name_dims();
  2702. return hostlist_ranged_string_dims(hl, n, buf, dims, 1);
  2703. }
  2704. /* ----[ hostlist iterator functions ]---- */
  2705. static hostlist_iterator_t hostlist_iterator_new(void)
  2706. {
  2707. hostlist_iterator_t i = (hostlist_iterator_t) malloc(sizeof(*i));
  2708. if (!i)
  2709. return NULL;
  2710. i->hl = NULL;
  2711. i->hr = NULL;
  2712. i->idx = 0;
  2713. i->depth = -1;
  2714. i->next = i;
  2715. assert(i->magic = HOSTLIST_MAGIC);
  2716. return i;
  2717. }
  2718. hostlist_iterator_t hostlist_iterator_create(hostlist_t hl)
  2719. {
  2720. hostlist_iterator_t i;
  2721. if (!(i = hostlist_iterator_new()))
  2722. out_of_memory("hostlist_iterator_create");
  2723. LOCK_HOSTLIST(hl);
  2724. i->hl = hl;
  2725. i->hr = hl->hr[0];
  2726. i->next = hl->ilist;
  2727. hl->ilist = i;
  2728. UNLOCK_HOSTLIST(hl);
  2729. return i;
  2730. }
  2731. hostlist_iterator_t hostset_iterator_create(hostset_t set)
  2732. {
  2733. return hostlist_iterator_create(set->hl);
  2734. }
  2735. void hostlist_iterator_reset(hostlist_iterator_t i)
  2736. {
  2737. assert(i != NULL);
  2738. assert(i->magic == HOSTLIST_MAGIC);
  2739. i->idx = 0;
  2740. i->hr = i->hl->hr[0];
  2741. i->depth = -1;
  2742. return;
  2743. }
  2744. void hostlist_iterator_destroy(hostlist_iterator_t i)
  2745. {
  2746. hostlist_iterator_t *pi;
  2747. if (i == NULL)
  2748. return;
  2749. assert(i != NULL);
  2750. assert(i->magic == HOSTLIST_MAGIC);
  2751. LOCK_HOSTLIST(i->hl);
  2752. for (pi = &i->hl->ilist; *pi; pi = &(*pi)->next) {
  2753. assert((*pi)->magic == HOSTLIST_MAGIC);
  2754. if (*pi == i) {
  2755. *pi = (*pi)->next;
  2756. break;
  2757. }
  2758. }
  2759. UNLOCK_HOSTLIST(i->hl);
  2760. assert(i->magic = 0x1);
  2761. free(i);
  2762. }
  2763. static void _iterator_advance(hostlist_iterator_t i)
  2764. {
  2765. assert(i != NULL);
  2766. assert(i->magic == HOSTLIST_MAGIC);
  2767. if (i->idx > i->hl->nranges - 1)
  2768. return;
  2769. if (++(i->depth) > (i->hr->hi - i->hr->lo)) {
  2770. i->depth = 0;
  2771. i->hr = i->hl->hr[++i->idx];
  2772. }
  2773. }
  2774. /* advance iterator to end of current range (meaning within "[" "]")
  2775. * i.e. advance iterator past all range objects that could be represented
  2776. * in on bracketed hostlist.
  2777. */
  2778. static void _iterator_advance_range(hostlist_iterator_t i)
  2779. {
  2780. int nr, j;
  2781. hostrange_t *hr;
  2782. assert(i != NULL);
  2783. assert(i->magic == HOSTLIST_MAGIC);
  2784. nr = i->hl->nranges;
  2785. hr = i->hl->hr;
  2786. j = i->idx;
  2787. if (++i->depth > 0) {
  2788. while (++j < nr && hostrange_within_range(i->hr, hr[j])) {;}
  2789. i->idx = j;
  2790. i->hr = i->hl->hr[i->idx];
  2791. i->depth = 0;
  2792. }
  2793. }
  2794. char *hostlist_next_dims(hostlist_iterator_t i, int dims)
  2795. {
  2796. char buf[MAXHOSTNAMELEN + 16];
  2797. const int size = sizeof(buf);
  2798. int len = 0;
  2799. assert(i != NULL);
  2800. assert(i->magic == HOSTLIST_MAGIC);
  2801. LOCK_HOSTLIST(i->hl);
  2802. _iterator_advance(i);
  2803. if (!dims)
  2804. dims = slurmdb_setup_cluster_name_dims();
  2805. if (i->idx > i->hl->nranges - 1)
  2806. goto no_next;
  2807. len = snprintf(buf, size, "%s", i->hr->prefix);
  2808. if (len < 0 || len + dims >= size)
  2809. goto no_next;
  2810. if (!i->hr->singlehost) {
  2811. if ((dims > 1) && (i->hr->width == dims)) {
  2812. int i2 = 0;
  2813. int coord[dims];
  2814. hostlist_parse_int_to_array(i->hr->lo + i->depth,
  2815. coord, dims, 0);
  2816. while (i2 < dims)
  2817. buf[len++] = alpha_num[coord[i2++]];
  2818. buf[len] = '\0';
  2819. } else {
  2820. len = snprintf(buf + len, size - len, "%0*lu",
  2821. i->hr->width, i->hr->lo + i->depth);
  2822. if (len < 0 || len >= size)
  2823. goto no_next;
  2824. }
  2825. }
  2826. UNLOCK_HOSTLIST(i->hl);
  2827. return strdup(buf);
  2828. no_next:
  2829. UNLOCK_HOSTLIST(i->hl);
  2830. return NULL;
  2831. }
  2832. char *hostlist_next(hostlist_iterator_t i)
  2833. {
  2834. int dims = slurmdb_setup_cluster_name_dims();
  2835. return hostlist_next_dims(i, dims);
  2836. }
  2837. char *hostlist_next_range(hostlist_iterator_t i)
  2838. {
  2839. int j, buf_size;
  2840. char *buf;
  2841. assert(i != NULL);
  2842. assert(i->magic == HOSTLIST_MAGIC);
  2843. LOCK_HOSTLIST(i->hl);
  2844. _iterator_advance_range(i);
  2845. if (i->idx > i->hl->nranges - 1) {
  2846. UNLOCK_HOSTLIST(i->hl);
  2847. return NULL;
  2848. }
  2849. j = i->idx;
  2850. buf_size = 8192;
  2851. buf = malloc(buf_size);
  2852. if (buf &&
  2853. (_get_bracketed_list(i->hl, &j, buf_size, buf) == buf_size)) {
  2854. buf_size *= 2;
  2855. buf = realloc(buf, buf_size);
  2856. }
  2857. UNLOCK_HOSTLIST(i->hl);
  2858. return buf;
  2859. }
  2860. int hostlist_remove(hostlist_iterator_t i)
  2861. {
  2862. hostrange_t new;
  2863. assert(i != NULL);
  2864. assert(i->magic == HOSTLIST_MAGIC);
  2865. LOCK_HOSTLIST(i->hl);
  2866. new = hostrange_delete_host(i->hr, i->hr->lo + i->depth);
  2867. if (new) {
  2868. hostlist_insert_range(i->hl, new, i->idx + 1);
  2869. hostrange_destroy(new);
  2870. i->hr = i->hl->hr[++i->idx];
  2871. i->depth = -1;
  2872. } else if (hostrange_empty(i->hr)) {
  2873. hostlist_delete_range(i->hl, i->idx);
  2874. /* i->hr = i->hl->hr[i->idx];
  2875. i->depth = -1; */
  2876. } else
  2877. i->depth--;
  2878. i->hl->nhosts--;
  2879. UNLOCK_HOSTLIST(i->hl);
  2880. return 1;
  2881. }
  2882. /* ----[ hostset functions ]---- */
  2883. hostset_t hostset_create(const char *hostlist)
  2884. {
  2885. hostset_t new;
  2886. if (!(new = (hostset_t) malloc(sizeof(*new))))
  2887. goto error1;
  2888. if (!(new->hl = hostlist_create(hostlist)))
  2889. goto error2;
  2890. hostlist_uniq(new->hl);
  2891. return new;
  2892. error2:
  2893. free(new);
  2894. error1:
  2895. return NULL;
  2896. }
  2897. hostset_t hostset_copy(const hostset_t set)
  2898. {
  2899. hostset_t new;
  2900. if (!(new = (hostset_t) malloc(sizeof(*new))))
  2901. goto error1;
  2902. if (!(new->hl = hostlist_copy(set->hl)))
  2903. goto error2;
  2904. return new;
  2905. error2:
  2906. free(new);
  2907. error1:
  2908. return NULL;
  2909. }
  2910. void hostset_destroy(hostset_t set)
  2911. {
  2912. if (set == NULL)
  2913. return;
  2914. hostlist_destroy(set->hl);
  2915. free(set);
  2916. }
  2917. /* inserts a single range object into a hostset
  2918. * Assumes that the set->hl lock is already held
  2919. * Updates hl->nhosts
  2920. */
  2921. static int hostset_insert_range(hostset_t set, hostrange_t hr)
  2922. {
  2923. int i = 0;
  2924. int inserted = 0;
  2925. int nhosts = 0;
  2926. int ndups = 0;
  2927. hostlist_t hl;
  2928. hl = set->hl;
  2929. if (hl->size == hl->nranges && !hostlist_expand(hl))
  2930. return 0;
  2931. nhosts = hostrange_count(hr);
  2932. for (i = 0; i < hl->nranges; i++) {
  2933. if (hostrange_cmp(hr, hl->hr[i]) <= 0) {
  2934. if ((ndups = hostrange_join(hr, hl->hr[i])) >= 0)
  2935. hostlist_delete_range(hl, i);
  2936. else if (ndups < 0)
  2937. ndups = 0;
  2938. hostlist_insert_range(hl, hr, i);
  2939. /* now attempt to join hr[i] and hr[i-1] */
  2940. if (i > 0) {
  2941. int m;
  2942. if ((m = _attempt_range_join(hl, i)) > 0)
  2943. ndups += m;
  2944. }
  2945. hl->nhosts += nhosts - ndups;
  2946. inserted = 1;
  2947. break;
  2948. }
  2949. }
  2950. if (inserted == 0) {
  2951. hl->hr[hl->nranges++] = hostrange_copy(hr);
  2952. hl->nhosts += nhosts;
  2953. if (hl->nranges > 1) {
  2954. if ((ndups = _attempt_range_join(hl, hl->nranges - 1)) <= 0)
  2955. ndups = 0;
  2956. }
  2957. }
  2958. /*
  2959. * Return the number of unique hosts inserted
  2960. */
  2961. return nhosts - ndups;
  2962. }
  2963. int hostset_insert(hostset_t set, const char *hosts)
  2964. {
  2965. int i, n = 0;
  2966. hostlist_t hl = hostlist_create(hosts);
  2967. if (!hl)
  2968. return 0;
  2969. hostlist_uniq(hl);
  2970. LOCK_HOSTLIST(set->hl);
  2971. for (i = 0; i < hl->nranges; i++)
  2972. n += hostset_insert_range(set, hl->hr[i]);
  2973. UNLOCK_HOSTLIST(set->hl);
  2974. hostlist_destroy(hl);
  2975. return n;
  2976. }
  2977. /* linear search through N ranges for hostname "host"
  2978. * */
  2979. static int hostset_find_host(hostset_t set, const char *host)
  2980. {
  2981. int i;
  2982. int retval = 0;
  2983. hostname_t hn;
  2984. LOCK_HOSTLIST(set->hl);
  2985. hn = hostname_create(host);
  2986. for (i = 0; i < set->hl->nranges; i++) {
  2987. if (hostrange_hn_within(set->hl->hr[i], hn)) {
  2988. retval = 1;
  2989. goto done;
  2990. }
  2991. }
  2992. done:
  2993. UNLOCK_HOSTLIST(set->hl);
  2994. hostname_destroy(hn);
  2995. return retval;
  2996. }
  2997. int hostset_intersects(hostset_t set, const char *hosts)
  2998. {
  2999. int retval = 0;
  3000. hostlist_t hl;
  3001. char *hostname;
  3002. assert(set->hl->magic == HOSTLIST_MAGIC);
  3003. hl = hostlist_create(hosts);
  3004. if (!hl) /* malloc failure */
  3005. return retval;
  3006. while ((hostname = hostlist_pop(hl)) != NULL) {
  3007. retval += hostset_find_host(set, hostname);
  3008. free(hostname);
  3009. if (retval)
  3010. break;
  3011. }
  3012. hostlist_destroy(hl);
  3013. return retval;
  3014. }
  3015. int hostset_within(hostset_t set, const char *hosts)
  3016. {
  3017. int nhosts, nfound;
  3018. hostlist_t hl;
  3019. char *hostname;
  3020. assert(set->hl->magic == HOSTLIST_MAGIC);
  3021. if (!(hl = hostlist_create(hosts)))
  3022. return (0);
  3023. nhosts = hostlist_count(hl);
  3024. nfound = 0;
  3025. while ((hostname = hostlist_pop(hl)) != NULL) {
  3026. nfound += hostset_find_host(set, hostname);
  3027. free(hostname);
  3028. }
  3029. hostlist_destroy(hl);
  3030. return (nhosts == nfound);
  3031. }
  3032. int hostset_delete(hostset_t set, const char *hosts)
  3033. {
  3034. return hostlist_delete(set->hl, hosts);
  3035. }
  3036. int hostset_delete_host(hostset_t set, const char *hostname)
  3037. {
  3038. return hostlist_delete_host(set->hl, hostname);
  3039. }
  3040. char *hostset_shift(hostset_t set)
  3041. {
  3042. return hostlist_shift(set->hl);
  3043. }
  3044. char *hostset_pop(hostset_t set)
  3045. {
  3046. return hostlist_pop(set->hl);
  3047. }
  3048. char *hostset_shift_range(hostset_t set)
  3049. {
  3050. return hostlist_shift_range(set->hl);
  3051. }
  3052. char *hostset_pop_range(hostset_t set)
  3053. {
  3054. return hostlist_pop_range(set->hl);
  3055. }
  3056. int hostset_count(hostset_t set)
  3057. {
  3058. return hostlist_count(set->hl);
  3059. }
  3060. ssize_t hostset_ranged_string(hostset_t set, size_t n, char *buf)
  3061. {
  3062. return hostlist_ranged_string(set->hl, n, buf);
  3063. }
  3064. ssize_t hostset_deranged_string(hostset_t set, size_t n, char *buf)
  3065. {
  3066. return hostlist_deranged_string(set->hl, n, buf);
  3067. }
  3068. char * hostset_nth(hostset_t set, int n)
  3069. {
  3070. return hostlist_nth(set->hl, n);
  3071. }
  3072. int hostset_find(hostset_t set, const char *hostname)
  3073. {
  3074. return hostlist_find(set->hl, hostname);
  3075. }
  3076. #if TEST_MAIN
  3077. int hostlist_nranges(hostlist_t hl)
  3078. {
  3079. return hl->nranges;
  3080. }
  3081. int hostset_nranges(hostset_t set)
  3082. {
  3083. return set->hl->nranges;
  3084. }
  3085. /* test iterator functionality on the list of hosts represented
  3086. * by list
  3087. */
  3088. int iterator_test(char *list)
  3089. {
  3090. int j;
  3091. char *buf;
  3092. hostlist_t hl = hostlist_create(list);
  3093. hostset_t set = hostset_create(list);
  3094. hostlist_iterator_t i = hostlist_iterator_create(hl);
  3095. hostlist_iterator_t seti = hostset_iterator_create(set);
  3096. hostlist_iterator_t i2 = hostlist_iterator_create(hl);
  3097. char *host;
  3098. buf = hostlist_ranged_string_malloc(hl);
  3099. printf("iterator_test: hl = `%s' passed in `%s'\n", buf, list);
  3100. free(buf);
  3101. host = hostlist_next(i);
  3102. printf("first host in list hl = `%s'\n", host);
  3103. free(host);
  3104. /* forge ahead three hosts with i2 */
  3105. for (j = 0; j < 4; j++) {
  3106. host = hostlist_next(i2);
  3107. free(host);
  3108. }
  3109. host = hostlist_shift(hl);
  3110. printf("result of shift(hl) = `%s'\n", host);
  3111. free(host);
  3112. host = hostlist_next(i);
  3113. printf("next host in list hl = `%s'\n", host);
  3114. free(host);
  3115. host = hostlist_next(i2);
  3116. printf("next host for i2 = `%s'\n", host);
  3117. free(host);
  3118. hostlist_iterator_destroy(i);
  3119. hostlist_destroy(hl);
  3120. hostset_destroy(set);
  3121. return 1;
  3122. }
  3123. int main(int ac, char **av)
  3124. {
  3125. char buf[1024000];
  3126. int i;
  3127. char *str;
  3128. hostlist_t hl1, hl2, hl3;
  3129. hostset_t set, set1;
  3130. hostlist_iterator_t iter, iter2;
  3131. if (ac < 2)
  3132. printf("Recommended usage: %s [hostlist]\n\n", av[0]);
  3133. if (!(hl1 = hostlist_create(ac > 1 ? av[1] : NULL))) {
  3134. perror("hostlist_create");
  3135. exit(1);
  3136. }
  3137. /* build a temporary hostlist, remove duplicates,
  3138. * use it to make the hostset */
  3139. if (!(hl2 = hostlist_create(ac > 1 ? av[1] : NULL))) {
  3140. perror("hostlist_create");
  3141. exit(1);
  3142. }
  3143. hostlist_uniq(hl2);
  3144. hostlist_ranged_string(hl2, 102400, buf);
  3145. if (!(set = hostset_create(buf))) {
  3146. perror("hostset_create");
  3147. exit(1);
  3148. }
  3149. hostlist_destroy(hl2);
  3150. hl3 = hostlist_create("f[0-5]");
  3151. hostlist_delete(hl3, "f[1-3]");
  3152. hostlist_ranged_string(hl3, 102400, buf);
  3153. printf("after delete = `%s'\n", buf);
  3154. hostlist_destroy(hl3);
  3155. hl3 = hostlist_create("bg[012x123]");
  3156. hostlist_ranged_string(hl3, 102400, buf);
  3157. printf("bg[012x123] == `%s'\n", buf);
  3158. i = hostlist_count(hl3);
  3159. assert(i == 8);
  3160. hostlist_ranged_string(hl3, 102400, buf);
  3161. hostlist_destroy(hl3);
  3162. for (i = 2; i < ac; i++) {
  3163. hostlist_push(hl1, av[i]);
  3164. hostset_insert(set, av[i]);
  3165. }
  3166. hostlist_ranged_string(hl1, 102400, buf);
  3167. printf("ranged = `%s'\n", buf);
  3168. iterator_test(buf);
  3169. hostlist_deranged_string(hl1, 10240, buf);
  3170. printf("deranged = `%s'\n", buf);
  3171. hostset_ranged_string(set, 1024, buf);
  3172. printf("hostset = `%s'\n", buf);
  3173. hostlist_sort(hl1);
  3174. hostlist_ranged_string(hl1, 10240, buf);
  3175. printf("sorted = `%s'\n", buf);
  3176. hostlist_uniq(hl1);
  3177. hostlist_ranged_string(hl1, 10240, buf);
  3178. printf("uniqed = `%s'\n", buf);
  3179. hl2 = hostlist_copy(hl1);
  3180. printf("pop_range: ");
  3181. while ((str = hostlist_pop_range(hl2))) {
  3182. printf("`%s' ", str);
  3183. free(str);
  3184. }
  3185. hostlist_destroy(hl2);
  3186. printf("\n");
  3187. hl2 = hostlist_copy(hl1);
  3188. printf("shift_range: ");
  3189. while ((str = hostlist_shift_range(hl2))) {
  3190. printf("`%s' ", str);
  3191. free(str);
  3192. }
  3193. hostlist_destroy(hl2);
  3194. printf("\n");
  3195. iter = hostset_iterator_create(set);
  3196. iter2 = hostset_iterator_create(set);
  3197. hostlist_iterator_destroy(iter2);
  3198. printf("next: ");
  3199. while ((str = hostlist_next(iter))) {
  3200. printf("`%s' ", str);
  3201. free(str);
  3202. }
  3203. printf("\n");
  3204. hostlist_iterator_reset(iter);
  3205. printf("next_range: ");
  3206. while ((str = hostlist_next_range(iter))) {
  3207. printf("`%s' ", str);
  3208. free(str);
  3209. }
  3210. printf("\n");
  3211. printf("nranges = %d\n", hostset_nranges(set));
  3212. hostset_ranged_string(set, 1024, buf);
  3213. printf("set = %s\n", buf);
  3214. hostset_destroy(set);
  3215. hostlist_destroy(hl1);
  3216. return 0;
  3217. }
  3218. #endif /* TEST_MAIN */