PageRenderTime 31ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/src/common/hostlist.c

https://code.google.com/
C | 2508 lines | 1658 code | 472 blank | 378 comment | 459 complexity | 15540c5efd6b0cb1da882e391ad4b16d MD5 | raw file
Possible License(s): GPL-2.0
  1. /*****************************************************************************\
  2. * $Id: hostlist.c 9950 2010-08-31 21:57:35Z grondo $
  3. *****************************************************************************
  4. * $LSDId: hostlist.c 9950 2010-08-31 21:57:35Z grondo $
  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. * UCRL-CODE-2002-040.
  10. *
  11. * This file is part of SLURM, a resource management program.
  12. * For details, see <http://www.llnl.gov/linux/slurm/>.
  13. *
  14. * SLURM is free software; you can redistribute it and/or modify it under
  15. * the terms of the GNU General Public License as published by the Free
  16. * Software Foundation; either version 2 of the License, or (at your option)
  17. * any later version.
  18. *
  19. * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
  20. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  21. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  22. * details.
  23. *
  24. * You should have received a copy of the GNU General Public License along
  25. * with SLURM; if not, write to the Free Software Foundation, Inc.,
  26. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  27. \*****************************************************************************/
  28. #ifdef HAVE_CONFIG_H
  29. # include "config.h"
  30. # if HAVE_STRING_H
  31. # include <string.h>
  32. # endif
  33. # if HAVE_PTHREAD_H
  34. # include <pthread.h>
  35. # endif
  36. #else /* !HAVE_CONFIG_H */
  37. # include <string.h>
  38. # include <pthread.h>
  39. #endif /* HAVE_CONFIG_H */
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <stdarg.h>
  43. #include <assert.h>
  44. #include <errno.h>
  45. #include <ctype.h>
  46. #include <sys/param.h>
  47. #include <unistd.h>
  48. #include "hostlist.h"
  49. /*
  50. * lsd_fatal_error : fatal error macro
  51. */
  52. #ifdef WITH_LSD_FATAL_ERROR_FUNC
  53. # undef lsd_fatal_error
  54. extern void lsd_fatal_error(char *file, int line, char *mesg);
  55. #else /* !WITH_LSD_FATAL_ERROR_FUNC */
  56. # ifndef lsd_fatal_error
  57. # define lsd_fatal_error(file, line, mesg) \
  58. do { \
  59. fprintf(stderr, "ERROR: [%s:%d] %s: %s\n", \
  60. file, line, mesg, strerror(errno)); \
  61. } while (0)
  62. # endif /* !lsd_fatal_error */
  63. #endif /* !WITH_LSD_FATAL_ERROR_FUNC */
  64. /*
  65. * lsd_nomem_error
  66. */
  67. #ifdef WITH_LSD_NOMEM_ERROR_FUNC
  68. # undef lsd_nomem_error
  69. extern void * lsd_nomem_error(char *file, int line, char *mesg);
  70. #else /* !WITH_LSD_NOMEM_ERROR_FUNC */
  71. # ifndef lsd_nomem_error
  72. # define lsd_nomem_error(file, line, mesg) (NULL)
  73. # endif /* !lsd_nomem_error */
  74. #endif /* !WITH_LSD_NOMEM_ERROR_FUNC */
  75. /*
  76. * OOM helper function
  77. * Automatically call lsd_nomem_error with appropriate args
  78. * and set errno to ENOMEM
  79. */
  80. #define out_of_memory(mesg) \
  81. do { \
  82. errno = ENOMEM; \
  83. return(lsd_nomem_error(__FILE__, __LINE__, mesg)); \
  84. } while (0)
  85. /*
  86. * Some constants and tunables:
  87. */
  88. /* number of elements to allocate when extending the hostlist array */
  89. #define HOSTLIST_CHUNK 16
  90. /* max host range: anything larger will be assumed to be an error */
  91. #define MAX_RANGE 16384 /* 16K Hosts */
  92. /* max host suffix value */
  93. #define MAX_HOST_SUFFIX 1<<25
  94. /* max number of ranges that will be processed between brackets */
  95. #define MAX_RANGES 10240 /* 10K Ranges */
  96. /* size of internal hostname buffer (+ some slop), hostnames will probably
  97. * be truncated if longer than MAXHOSTNAMELEN */
  98. #ifndef MAXHOSTNAMELEN
  99. #define MAXHOSTNAMELEN 64
  100. #endif
  101. /* max size of internal hostrange buffer */
  102. #define MAXHOSTRANGELEN 1024
  103. /* ----[ Internal Data Structures ]---- */
  104. /* hostname type: A convenience structure used in parsing single hostnames */
  105. struct hostname_components {
  106. char *hostname; /* cache of initialized hostname */
  107. char *prefix; /* hostname prefix */
  108. unsigned long num; /* numeric suffix */
  109. /* string representation of numeric suffix
  110. * points into `hostname' */
  111. char *suffix;
  112. };
  113. typedef struct hostname_components *hostname_t;
  114. /* hostrange type: A single prefix with `hi' and `lo' numeric suffix values */
  115. struct hostrange_components {
  116. char *prefix; /* alphanumeric prefix: */
  117. /* beginning (lo) and end (hi) of suffix range */
  118. unsigned long lo, hi;
  119. /* width of numeric output format
  120. * (pad with zeros up to this width) */
  121. int width;
  122. /* If singlehost is 1, `lo' and `hi' are invalid */
  123. unsigned singlehost:1;
  124. };
  125. typedef struct hostrange_components *hostrange_t;
  126. /* The hostlist type: An array based list of hostrange_t's */
  127. struct hostlist {
  128. #ifndef NDEBUG
  129. #define HOSTLIST_MAGIC 57005
  130. int magic;
  131. #endif
  132. #if WITH_PTHREADS
  133. pthread_mutex_t mutex;
  134. #endif /* WITH_PTHREADS */
  135. /* current number of elements available in array */
  136. int size;
  137. /* current number of ranges stored in array */
  138. int nranges;
  139. /* current number of hosts stored in hostlist */
  140. int nhosts;
  141. /* pointer to hostrange array */
  142. hostrange_t *hr;
  143. /* list of iterators */
  144. struct hostlist_iterator *ilist;
  145. };
  146. /* a hostset is a wrapper around a hostlist */
  147. struct hostset {
  148. hostlist_t hl;
  149. };
  150. struct hostlist_iterator {
  151. #ifndef NDEBUG
  152. int magic;
  153. #endif
  154. /* hostlist we are traversing */
  155. hostlist_t hl;
  156. /* current index of iterator in hl->hr[] */
  157. int idx;
  158. /* current hostrange object in list hl, i.e. hl->hr[idx] */
  159. hostrange_t hr;
  160. /* current depth we've traversed into range hr */
  161. int depth;
  162. /* next ptr for lists of iterators */
  163. struct hostlist_iterator *next;
  164. };
  165. /* ---- ---- */
  166. /* ------[ static function prototypes ]------ */
  167. static void _error(char *file, int line, char *mesg, ...);
  168. static char * _next_tok(char *, char **);
  169. static int _zero_padded(unsigned long, int);
  170. static int _width_equiv(unsigned long, int *, unsigned long, int *);
  171. static int host_prefix_end(const char *);
  172. static hostname_t hostname_create(const char *);
  173. static void hostname_destroy(hostname_t);
  174. static int hostname_suffix_is_valid(hostname_t);
  175. static int hostname_suffix_width(hostname_t);
  176. static hostrange_t hostrange_new(void);
  177. static hostrange_t hostrange_create_single(const char *);
  178. static hostrange_t hostrange_create(char *, unsigned long, unsigned long, int);
  179. static unsigned long hostrange_count(hostrange_t);
  180. static hostrange_t hostrange_copy(hostrange_t);
  181. static void hostrange_destroy(hostrange_t);
  182. static hostrange_t hostrange_delete_host(hostrange_t, unsigned long);
  183. static int hostrange_cmp(hostrange_t, hostrange_t);
  184. static int hostrange_prefix_cmp(hostrange_t, hostrange_t);
  185. static int hostrange_within_range(hostrange_t, hostrange_t);
  186. static int hostrange_width_combine(hostrange_t, hostrange_t);
  187. static int hostrange_empty(hostrange_t);
  188. static char * hostrange_pop(hostrange_t);
  189. static char * hostrange_shift(hostrange_t);
  190. static int hostrange_join(hostrange_t, hostrange_t);
  191. static hostrange_t hostrange_intersect(hostrange_t, hostrange_t);
  192. static int hostrange_hn_within(hostrange_t, hostname_t);
  193. static size_t hostrange_to_string(hostrange_t hr, size_t, char *, char *);
  194. static size_t hostrange_numstr(hostrange_t, size_t, char *);
  195. static hostlist_t hostlist_new(void);
  196. static hostlist_t _hostlist_create_bracketed(const char *, char *, char *);
  197. static int hostlist_resize(hostlist_t, size_t);
  198. static int hostlist_expand(hostlist_t);
  199. static int hostlist_push_range(hostlist_t, hostrange_t);
  200. static int hostlist_push_hr(hostlist_t, char *, unsigned long,
  201. unsigned long, int);
  202. static int hostlist_insert_range(hostlist_t, hostrange_t, int);
  203. static void hostlist_delete_range(hostlist_t, int n);
  204. static void hostlist_coalesce(hostlist_t hl);
  205. static void hostlist_collapse(hostlist_t hl);
  206. static hostlist_t _hostlist_create(const char *, char *, char *);
  207. static void hostlist_shift_iterators(hostlist_t, int, int, int);
  208. static int _attempt_range_join(hostlist_t, int);
  209. static int _is_bracket_needed(hostlist_t, int);
  210. static hostlist_iterator_t hostlist_iterator_new(void);
  211. static void _iterator_advance(hostlist_iterator_t);
  212. static void _iterator_advance_range(hostlist_iterator_t);
  213. static int hostset_find_host(hostset_t, const char *);
  214. /* ------[ macros ]------ */
  215. #ifdef WITH_PTHREADS
  216. # define mutex_init(mutex) \
  217. do { \
  218. int e = pthread_mutex_init(mutex, NULL); \
  219. if (e) { \
  220. errno = e; \
  221. lsd_fatal_error(__FILE__, __LINE__, "hostlist mutex init:"); \
  222. abort(); \
  223. } \
  224. } while (0)
  225. # define mutex_lock(mutex) \
  226. do { \
  227. int e = pthread_mutex_lock(mutex); \
  228. if (e) { \
  229. errno = e; \
  230. lsd_fatal_error(__FILE__, __LINE__, "hostlist mutex lock:"); \
  231. abort(); \
  232. } \
  233. } while (0)
  234. # define mutex_unlock(mutex) \
  235. do { \
  236. int e = pthread_mutex_unlock(mutex); \
  237. if (e) { \
  238. errno = e; \
  239. lsd_fatal_error(__FILE__, __LINE__, "hostlist mutex unlock:"); \
  240. abort(); \
  241. } \
  242. } while (0)
  243. # define mutex_destroy(mutex) \
  244. do { \
  245. int e = pthread_mutex_destroy(mutex); \
  246. if (e) { \
  247. errno = e; \
  248. lsd_fatal_error(__FILE__, __LINE__, "hostlist mutex destroy:"); \
  249. abort(); \
  250. } \
  251. } while (0)
  252. #else /* !WITH_PTHREADS */
  253. # define mutex_init(mutex)
  254. # define mutex_lock(mutex)
  255. # define mutex_unlock(mutex)
  256. # define mutex_destroy(mutex)
  257. #endif /* WITH_PTHREADS */
  258. #define LOCK_HOSTLIST(_hl) \
  259. do { \
  260. assert(_hl != NULL); \
  261. mutex_lock(&(_hl)->mutex); \
  262. assert((_hl)->magic == HOSTLIST_MAGIC); \
  263. } while (0)
  264. #define UNLOCK_HOSTLIST(_hl) \
  265. do { \
  266. mutex_unlock(&(_hl)->mutex); \
  267. } while (0)
  268. #define seterrno_ret(_errno, _rc) \
  269. do { \
  270. errno = _errno; \
  271. return _rc; \
  272. } while (0)
  273. /* ------[ Function Definitions ]------ */
  274. /* ----[ general utility functions ]---- */
  275. /*
  276. * Varargs capable error reporting via lsd_fatal_error()
  277. */
  278. static void _error(char *file, int line, char *msg, ...)
  279. {
  280. va_list ap;
  281. char buf[1024];
  282. int len = 0;
  283. va_start(ap, msg);
  284. len = vsnprintf(buf, 1024, msg, ap);
  285. if ((len < 0) || (len > 1024))
  286. buf[1023] = '\0';
  287. lsd_fatal_error(file, line, buf);
  288. va_end(ap);
  289. return;
  290. }
  291. /*
  292. * Helper function for host list string parsing routines
  293. * Returns a pointer to the next token; additionally advance *str
  294. * to the next separator.
  295. *
  296. * next_tok was taken directly from pdsh courtesy of Jim Garlick.
  297. * (with modifications to support bracketed hostlists, i.e.:
  298. * xxx[xx,xx,xx] is a single token)
  299. *
  300. * _next_tok now handles multiple brackets within the same token,
  301. * e.g. node[01-30]-[1-2,6].
  302. */
  303. static char * _next_tok(char *sep, char **str)
  304. {
  305. char *tok;
  306. int level = 0;
  307. /* push str past any leading separators */
  308. while (**str != '\0' && strchr(sep, **str) != '\0')
  309. (*str)++;
  310. if (**str == '\0')
  311. return NULL;
  312. /* assign token ptr */
  313. tok = *str;
  314. while ( **str != '\0' &&
  315. (level != 0 || strchr(sep, **str) == NULL) ) {
  316. if ( **str == '[' ) level++;
  317. else if ( **str == ']' ) level--;
  318. (*str)++;
  319. }
  320. /* nullify consecutive separators and push str beyond them */
  321. while (**str != '\0' && strchr(sep, **str) != '\0')
  322. *(*str)++ = '\0';
  323. return tok;
  324. }
  325. /* return the number of zeros needed to pad "num" to "width"
  326. */
  327. static int _zero_padded(unsigned long num, int width)
  328. {
  329. int n = 1;
  330. while (num /= 10L)
  331. n++;
  332. return width > n ? width - n : 0;
  333. }
  334. /* test whether two format `width' parameters are "equivalent"
  335. * The width arguments "wn" and "wm" for integers "n" and "m"
  336. * are equivalent if:
  337. *
  338. * o wn == wm OR
  339. *
  340. * o applying the same format width (either wn or wm) to both of
  341. * 'n' and 'm' will not change the zero padding of *either* 'm' nor 'n'.
  342. *
  343. * If this function returns 1 (or true), the appropriate width value
  344. * (either 'wm' or 'wn') will have been adjusted such that both format
  345. * widths are equivalent.
  346. */
  347. static int _width_equiv(unsigned long n, int *wn, unsigned long m, int *wm)
  348. {
  349. int npad, nmpad, mpad, mnpad;
  350. if (wn == wm)
  351. return 1;
  352. npad = _zero_padded(n, *wn);
  353. nmpad = _zero_padded(n, *wm);
  354. mpad = _zero_padded(m, *wm);
  355. mnpad = _zero_padded(m, *wn);
  356. if (npad != nmpad && mpad != mnpad)
  357. return 0;
  358. if (npad != nmpad) {
  359. if (mpad == mnpad) {
  360. *wm = *wn;
  361. return 1;
  362. } else
  363. return 0;
  364. } else { /* mpad != mnpad */
  365. if (npad == nmpad) {
  366. *wn = *wm;
  367. return 1;
  368. } else
  369. return 0;
  370. }
  371. /* not reached */
  372. }
  373. /* ----[ hostname_t functions ]---- */
  374. /*
  375. * return the location of the last char in the hostname prefix
  376. */
  377. static int host_prefix_end(const char *hostname)
  378. {
  379. int idx = strlen(hostname) - 1;
  380. while (idx >= 0 && isdigit((char) hostname[idx]))
  381. idx--;
  382. return idx;
  383. }
  384. static hostname_t hostname_create_with_suffix (const char *hostname, int idx)
  385. {
  386. hostname_t hn = NULL;
  387. char *p = '\0';
  388. assert(hostname != NULL);
  389. if (!(hn = (hostname_t) malloc(sizeof(*hn))))
  390. out_of_memory("hostname create");
  391. if (!(hn->hostname = strdup(hostname))) {
  392. free(hn);
  393. out_of_memory("hostname create");
  394. }
  395. hn->num = 0;
  396. hn->prefix = NULL;
  397. hn->suffix = NULL;
  398. if (idx == strlen(hostname) - 1) {
  399. if ((hn->prefix = strdup(hostname)) == NULL) {
  400. hostname_destroy(hn);
  401. out_of_memory("hostname prefix create");
  402. }
  403. return hn;
  404. }
  405. hn->suffix = hn->hostname + idx + 1;
  406. hn->num = strtoul(hn->suffix, &p, 10);
  407. if ((*p == '\0') && (hn->num <= MAX_HOST_SUFFIX)) {
  408. if (!(hn->prefix = malloc((idx + 2) * sizeof(char)))) {
  409. hostname_destroy(hn);
  410. out_of_memory("hostname prefix create");
  411. }
  412. memcpy(hn->prefix, hostname, idx + 1);
  413. hn->prefix[idx + 1] = '\0';
  414. } else {
  415. if (!(hn->prefix = strdup(hostname))) {
  416. hostname_destroy(hn);
  417. out_of_memory("hostname prefix create");
  418. }
  419. hn->suffix = NULL;
  420. }
  421. return hn;
  422. }
  423. /*
  424. * create a hostname_t object from a string hostname
  425. */
  426. static hostname_t hostname_create(const char *hostname)
  427. {
  428. int idx = host_prefix_end (hostname);
  429. return hostname_create_with_suffix (hostname, idx);
  430. }
  431. /* free a hostname object
  432. */
  433. static void hostname_destroy(hostname_t hn)
  434. {
  435. if (hn == NULL)
  436. return;
  437. hn->suffix = NULL;
  438. if (hn->hostname)
  439. free(hn->hostname);
  440. if (hn->prefix)
  441. free(hn->prefix);
  442. free(hn);
  443. }
  444. /* return true if the hostname has a valid numeric suffix
  445. */
  446. static int hostname_suffix_is_valid(hostname_t hn)
  447. {
  448. return hn->suffix != NULL;
  449. }
  450. /* return the width (in characters) of the numeric part of the hostname
  451. */
  452. static int hostname_suffix_width(hostname_t hn)
  453. {
  454. assert(hn->suffix != NULL);
  455. return (int) strlen(hn->suffix);
  456. }
  457. /* ----[ hostrange_t functions ]---- */
  458. /* allocate a new hostrange object
  459. */
  460. static hostrange_t hostrange_new(void)
  461. {
  462. hostrange_t new = (hostrange_t) malloc(sizeof(*new));
  463. if (!new)
  464. out_of_memory("hostrange create");
  465. return new;
  466. }
  467. /* Create a hostrange_t containing a single host without a valid suffix
  468. * hr->prefix will represent the entire hostname.
  469. */
  470. static hostrange_t hostrange_create_single(const char *prefix)
  471. {
  472. hostrange_t new;
  473. assert(prefix != NULL);
  474. if ((new = hostrange_new()) == NULL)
  475. goto error1;
  476. if ((new->prefix = strdup(prefix)) == NULL)
  477. goto error2;
  478. new->singlehost = 1;
  479. new->lo = 0L;
  480. new->hi = 0L;
  481. new->width = 0;
  482. return new;
  483. error2:
  484. free(new);
  485. error1:
  486. out_of_memory("hostrange create single");
  487. }
  488. /* Create a hostrange object with a prefix, hi, lo, and format width
  489. */
  490. static hostrange_t
  491. hostrange_create(char *prefix, unsigned long lo, unsigned long hi, int width)
  492. {
  493. hostrange_t new;
  494. assert(prefix != NULL);
  495. if ((new = hostrange_new()) == NULL)
  496. goto error1;
  497. if ((new->prefix = strdup(prefix)) == NULL)
  498. goto error2;
  499. new->lo = lo;
  500. new->hi = hi;
  501. new->width = width;
  502. new->singlehost = 0;
  503. return new;
  504. error2:
  505. free(new);
  506. error1:
  507. out_of_memory("hostrange create");
  508. }
  509. /* Return the number of hosts stored in the hostrange object
  510. */
  511. static unsigned long hostrange_count(hostrange_t hr)
  512. {
  513. assert(hr != NULL);
  514. if (hr->singlehost)
  515. return 1;
  516. else
  517. return hr->hi - hr->lo + 1;
  518. }
  519. /* Copy a hostrange object
  520. */
  521. static hostrange_t hostrange_copy(hostrange_t hr)
  522. {
  523. assert(hr != NULL);
  524. if (hr->singlehost)
  525. return hostrange_create_single(hr->prefix);
  526. else
  527. return hostrange_create(hr->prefix, hr->lo, hr->hi,
  528. hr->width);
  529. }
  530. /* free memory allocated by the hostrange object
  531. */
  532. static void hostrange_destroy(hostrange_t hr)
  533. {
  534. if (hr == NULL)
  535. return;
  536. if (hr->prefix)
  537. free(hr->prefix);
  538. free(hr);
  539. }
  540. /* hostrange_delete_host() deletes a specific host from the range.
  541. * If the range is split into two, the greater range is returned,
  542. * and `hi' of the lesser range is adjusted accordingly. If the
  543. * highest or lowest host is deleted from a range, NULL is returned
  544. * and the hostrange hr is adjusted properly.
  545. */
  546. static hostrange_t hostrange_delete_host(hostrange_t hr, unsigned long n)
  547. {
  548. hostrange_t new = NULL;
  549. assert(hr != NULL);
  550. assert(n >= hr->lo && n <= hr->hi);
  551. if (n == hr->lo)
  552. hr->lo++;
  553. else if (n == hr->hi)
  554. hr->hi--;
  555. else {
  556. if (!(new = hostrange_copy(hr)))
  557. out_of_memory("hostrange copy");
  558. hr->hi = n - 1;
  559. new->lo = n + 1;
  560. }
  561. return new;
  562. }
  563. /* hostrange_cmp() is used to sort hostrange objects. It will
  564. * sort based on the following (in order):
  565. * o result of strcmp on prefixes
  566. * o if widths are compatible, then:
  567. * sort based on lowest suffix in range
  568. * else
  569. * sort based on width */
  570. static int hostrange_cmp(hostrange_t h1, hostrange_t h2)
  571. {
  572. int retval;
  573. assert(h1 != NULL);
  574. assert(h2 != NULL);
  575. if ((retval = hostrange_prefix_cmp(h1, h2)) == 0)
  576. retval = hostrange_width_combine(h1, h2) ?
  577. h1->lo - h2->lo : h1->width - h2->width;
  578. return retval;
  579. }
  580. /* compare the prefixes of two hostrange objects.
  581. * returns:
  582. * < 0 if h1 prefix is less than h2 OR h1 == NULL.
  583. *
  584. * 0 if h1's prefix and h2's prefix match,
  585. * UNLESS, either h1 or h2 (NOT both) do not have a valid suffix.
  586. *
  587. * > 0 if h1's prefix is greater than h2's OR h2 == NULL. */
  588. static int hostrange_prefix_cmp(hostrange_t h1, hostrange_t h2)
  589. {
  590. int retval;
  591. if (h1 == NULL)
  592. return 1;
  593. if (h2 == NULL)
  594. return -1;
  595. retval = strcmp(h1->prefix, h2->prefix);
  596. return retval == 0 ? h2->singlehost - h1->singlehost : retval;
  597. }
  598. /* returns true if h1 and h2 would be included in the same bracketed hostlist.
  599. * h1 and h2 will be in the same bracketed list iff:
  600. *
  601. * 1. h1 and h2 have same prefix
  602. * 2. neither h1 nor h2 are singlet hosts (i.e. invalid suffix)
  603. *
  604. * (XXX: Should incompatible widths be placed in the same bracketed list?
  605. * There's no good reason not to, except maybe aesthetics)
  606. */
  607. static int hostrange_within_range(hostrange_t h1, hostrange_t h2)
  608. {
  609. if (hostrange_prefix_cmp(h1, h2) == 0)
  610. return h1->singlehost || h2->singlehost ? 0 : 1;
  611. else
  612. return 0;
  613. }
  614. /* compare two hostrange objects to determine if they are width
  615. * compatible, returns:
  616. * 1 if widths can safely be combined
  617. * 0 if widths cannot be safely combined
  618. */
  619. static int hostrange_width_combine(hostrange_t h0, hostrange_t h1)
  620. {
  621. assert(h0 != NULL);
  622. assert(h1 != NULL);
  623. return _width_equiv(h0->lo, &h0->width, h1->lo, &h1->width);
  624. }
  625. /* Return true if hostrange hr contains no hosts, i.e. hi < lo
  626. */
  627. static int hostrange_empty(hostrange_t hr)
  628. {
  629. assert(hr != NULL);
  630. return ((hr->hi < hr->lo) || (hr->hi == (unsigned long) -1));
  631. }
  632. /* return the string representation of the last host in hostrange hr
  633. * and remove that host from the range (i.e. decrement hi if possible)
  634. *
  635. * Returns NULL if malloc fails OR there are no more hosts left
  636. */
  637. static char *hostrange_pop(hostrange_t hr)
  638. {
  639. size_t size = 0;
  640. char *host = NULL;
  641. assert(hr != NULL);
  642. if (hr->singlehost) {
  643. hr->lo++; /* effectively set count == 0 */
  644. host = strdup(hr->prefix);
  645. } else if (hostrange_count(hr) > 0) {
  646. size = strlen(hr->prefix) + hr->width + 16;
  647. if (!(host = (char *) malloc(size * sizeof(char))))
  648. out_of_memory("hostrange pop");
  649. snprintf(host, size, "%s%0*lu", hr->prefix,
  650. hr->width, hr->hi--);
  651. }
  652. return host;
  653. }
  654. /* Same as hostrange_pop(), but remove host from start of range */
  655. static char *hostrange_shift(hostrange_t hr)
  656. {
  657. size_t size = 0;
  658. char *host = NULL;
  659. assert(hr != NULL);
  660. if (hr->singlehost) {
  661. hr->lo++;
  662. if (!(host = strdup(hr->prefix)))
  663. out_of_memory("hostrange shift");
  664. } else if (hostrange_count(hr) > 0) {
  665. size = strlen(hr->prefix) + hr->width + 16;
  666. if (!(host = (char *) malloc(size * sizeof(char))))
  667. out_of_memory("hostrange shift");
  668. snprintf(host, size, "%s%0*lu", hr->prefix,
  669. hr->width, hr->lo++);
  670. }
  671. return host;
  672. }
  673. /* join two hostrange objects.
  674. *
  675. * returns:
  676. *
  677. * -1 if ranges do not overlap (including incompatible zero padding)
  678. * 0 if ranges join perfectly
  679. * >0 number of hosts that were duplicated in h1 and h2
  680. *
  681. * h2 will be coalesced into h1 if rc >= 0
  682. *
  683. * it is assumed that h1->lo <= h2->lo, i.e. hr1 <= hr2
  684. *
  685. */
  686. static int hostrange_join(hostrange_t h1, hostrange_t h2)
  687. {
  688. int duplicated = -1;
  689. assert(h1 != NULL);
  690. assert(h2 != NULL);
  691. assert(hostrange_cmp(h1, h2) <= 0);
  692. if (hostrange_prefix_cmp(h1, h2) == 0 &&
  693. hostrange_width_combine(h1, h2)) {
  694. if (h1->singlehost && h2->singlehost) { /* matching singlets */
  695. duplicated = 1;
  696. } else if (h1->hi == h2->lo - 1) { /* perfect join */
  697. h1->hi = h2->hi;
  698. duplicated = 0;
  699. } else if (h1->hi >= h2->lo) { /* some duplication */
  700. if (h1->hi < h2->hi) {
  701. duplicated = h1->hi - h2->lo + 1;
  702. h1->hi = h2->hi;
  703. } else
  704. duplicated = hostrange_count(h2);
  705. }
  706. }
  707. return duplicated;
  708. }
  709. /* hostrange intersect returns the intersection (common hosts)
  710. * of hostrange objects h1 and h2. If there is no intersection,
  711. * NULL is returned.
  712. *
  713. * It is assumed that h1 <= h2 (i.e. h1->lo <= h2->lo)
  714. */
  715. static hostrange_t hostrange_intersect(hostrange_t h1, hostrange_t h2)
  716. {
  717. hostrange_t new = NULL;
  718. assert(h1 != NULL);
  719. assert(h2 != NULL);
  720. if (h1->singlehost || h2->singlehost)
  721. return NULL;
  722. assert(hostrange_cmp(h1, h2) <= 0);
  723. if ((hostrange_prefix_cmp(h1, h2) == 0)
  724. && (h1->hi > h2->lo)
  725. && (hostrange_width_combine(h1, h2))) {
  726. if (!(new = hostrange_copy(h1)))
  727. return NULL;
  728. new->lo = h2->lo;
  729. new->hi = h2->hi < h1->hi ? h2->hi : h1->hi;
  730. }
  731. return new;
  732. }
  733. /* return offset of hn if it is in the hostlist or
  734. * -1 if not.
  735. */
  736. static int hostrange_hn_within(hostrange_t hr, hostname_t hn)
  737. {
  738. int len_hr;
  739. int len_hn;
  740. int width;
  741. if (hr->singlehost) {
  742. /*
  743. * If the current hostrange [hr] is a `singlehost' (no valid
  744. * numeric suffix (lo and hi)), then the hostrange [hr]
  745. * stores just one host with name == hr->prefix.
  746. *
  747. * Thus the full hostname in [hn] must match hr->prefix, in
  748. * which case we return true. Otherwise, there is no
  749. * possibility that [hn] matches [hr].
  750. */
  751. if (strcmp (hn->hostname, hr->prefix) == 0)
  752. return 0;
  753. else
  754. return -1;
  755. }
  756. /*
  757. * Now we know [hr] is not a "singlehost", so hostname
  758. * better have a valid numeric suffix, or there is no
  759. * way we can match
  760. */
  761. if (!hostname_suffix_is_valid (hn))
  762. return -1;
  763. len_hn = strlen (hn->prefix);
  764. /*
  765. * If hostrange and hostname prefixes don't match to at least
  766. * the length of the hostname object (which will have the min
  767. * possible prefix length), then there is no way the hostname
  768. * falls within the range [hr].
  769. */
  770. if (strncmp (hr->prefix, hn->prefix, len_hn) != 0)
  771. return -1;
  772. /*
  773. * Now we know hostrange and hostname prefixes match up to the
  774. * length of the hostname prefix. If the hostrange and hostname
  775. * prefix lengths do not match (specifically if the hostname prefix
  776. * length is less than the hostrange prefix length) and the
  777. * hostrange prefix contains trailing digits, then it might be
  778. * the case that the hostrange was created by forcing the prefix
  779. * to contain digits a la f00[1-2]. So we try adjusting the
  780. * hostname with the longer prefix and calling this function
  781. * again with the new hostname. (Yes, this is ugly, sorry)
  782. */
  783. len_hr = strlen (hr->prefix);
  784. width = hostname_suffix_width (hn);
  785. if ((len_hn < len_hr)
  786. && (width > 1)
  787. && (isdigit (hr->prefix [len_hr - 1]))
  788. && (hr->prefix [len_hn] == hn->suffix[0]) ) {
  789. int rc;
  790. /*
  791. * Create new hostname object with its prefix offset by one
  792. */
  793. hostname_t h = hostname_create_with_suffix (hn->hostname, len_hn);
  794. /*
  795. * Recursive call :-o
  796. */
  797. rc = hostrange_hn_within (hr, h);
  798. hostname_destroy (h);
  799. return rc;
  800. }
  801. /*
  802. * Finally, check whether [hn], with a valid numeric suffix,
  803. * falls within the range of [hr].
  804. */
  805. if (hn->num <= hr->hi && hn->num >= hr->lo) {
  806. int width = hostname_suffix_width (hn);
  807. if (!_width_equiv(hr->lo, &hr->width, hn->num, &width))
  808. return -1;
  809. return (hn->num - hr->lo);
  810. }
  811. return -1;
  812. }
  813. /* copy a string representation of the hostrange hr into buffer buf,
  814. * writing at most n chars including NUL termination
  815. */
  816. static size_t
  817. hostrange_to_string(hostrange_t hr, size_t n, char *buf, char *separator)
  818. {
  819. unsigned long i;
  820. int truncated = 0;
  821. int len = 0;
  822. char sep = separator == NULL ? ',' : separator[0];
  823. if (n == 0)
  824. return 0;
  825. if (hr->singlehost)
  826. return snprintf(buf, n, "%s", hr->prefix);
  827. for (i = hr->lo; i <= hr->hi; i++) {
  828. size_t m = (n - len) <= n ? n - len : 0; /* check for < 0 */
  829. int ret = snprintf(buf + len, m, "%s%0*lu",
  830. hr->prefix, hr->width, i);
  831. if (ret < 0 || ret >= m) {
  832. len = n;
  833. truncated = 1;
  834. break;
  835. }
  836. len+=ret;
  837. buf[len++] = sep;
  838. }
  839. if (truncated) {
  840. buf[n-1] = '\0';
  841. return -1;
  842. } else {
  843. /* back up over final separator */
  844. buf[--len] = '\0';
  845. return len;
  846. }
  847. }
  848. /* Place the string representation of the numeric part of hostrange into buf
  849. * writing at most n chars including NUL termination.
  850. */
  851. static size_t hostrange_numstr(hostrange_t hr, size_t n, char *buf)
  852. {
  853. int len = 0;
  854. assert(buf != NULL);
  855. if (hr->singlehost || n == 0)
  856. return 0;
  857. len = snprintf(buf, n, "%0*lu", hr->width, hr->lo);
  858. if ((len >= 0) && (len < n) && (hr->lo < hr->hi)) {
  859. int len2 = snprintf(buf+len, n-len, "-%0*lu", hr->width, hr->hi);
  860. if (len2 < 0)
  861. len = -1;
  862. else
  863. len += len2;
  864. }
  865. return len;
  866. }
  867. /* ----[ hostlist functions ]---- */
  868. /* Create a new hostlist object.
  869. * Returns an empty hostlist, or NULL if memory allocation fails.
  870. */
  871. static hostlist_t hostlist_new(void)
  872. {
  873. int i;
  874. hostlist_t new = (hostlist_t) malloc(sizeof(*new));
  875. if (!new)
  876. goto fail1;
  877. assert(new->magic = HOSTLIST_MAGIC);
  878. mutex_init(&new->mutex);
  879. new->hr = (hostrange_t *) malloc(HOSTLIST_CHUNK * sizeof(hostrange_t));
  880. if (!new->hr)
  881. goto fail2;
  882. /* set entries in hostrange array to NULL */
  883. for (i = 0; i < HOSTLIST_CHUNK; i++)
  884. new->hr[i] = NULL;
  885. new->size = HOSTLIST_CHUNK;
  886. new->nranges = 0;
  887. new->nhosts = 0;
  888. new->ilist = NULL;
  889. return new;
  890. fail2:
  891. free(new);
  892. fail1:
  893. out_of_memory("hostlist_create");
  894. }
  895. /* Resize the internal array used to store the list of hostrange objects.
  896. *
  897. * returns 1 for a successful resize,
  898. * 0 if call to _realloc fails
  899. *
  900. * It is assumed that the caller has the hostlist hl locked
  901. */
  902. static int hostlist_resize(hostlist_t hl, size_t newsize)
  903. {
  904. int i;
  905. size_t oldsize;
  906. assert(hl != NULL);
  907. assert(hl->magic == HOSTLIST_MAGIC);
  908. oldsize = hl->size;
  909. hl->size = newsize;
  910. hl->hr = realloc((void *) hl->hr, hl->size*sizeof(hostrange_t));
  911. if (!(hl->hr))
  912. return 0;
  913. for (i = oldsize; i < newsize; i++)
  914. hl->hr[i] = NULL;
  915. return 1;
  916. }
  917. /* Resize hostlist by one HOSTLIST_CHUNK
  918. * Assumes that hostlist hl is locked by caller
  919. */
  920. static int hostlist_expand(hostlist_t hl)
  921. {
  922. if (!hostlist_resize(hl, hl->size + HOSTLIST_CHUNK))
  923. return 0;
  924. else
  925. return 1;
  926. }
  927. /* Push a hostrange object onto hostlist hl
  928. * Returns the number of hosts successfully pushed onto hl
  929. * or -1 if there was an error allocating memory
  930. */
  931. static int hostlist_push_range(hostlist_t hl, hostrange_t hr)
  932. {
  933. hostrange_t tail;
  934. int retval;
  935. assert(hr != NULL);
  936. LOCK_HOSTLIST(hl);
  937. tail = (hl->nranges > 0) ? hl->hr[hl->nranges-1] : hl->hr[0];
  938. if (hl->size == hl->nranges && !hostlist_expand(hl))
  939. goto error;
  940. if (hl->nranges > 0
  941. && hostrange_prefix_cmp(tail, hr) == 0
  942. && tail->hi == hr->lo - 1
  943. && hostrange_width_combine(tail, hr)) {
  944. tail->hi = hr->hi;
  945. } else {
  946. if ((hl->hr[hl->nranges++] = hostrange_copy(hr)) == NULL)
  947. goto error;
  948. }
  949. retval = hl->nhosts += hostrange_count(hr);
  950. UNLOCK_HOSTLIST(hl);
  951. return retval;
  952. error:
  953. UNLOCK_HOSTLIST(hl);
  954. return -1;
  955. }
  956. /* Same as hostlist_push_range() above, but prefix, lo, hi, and width
  957. * are passed as args
  958. */
  959. static int
  960. hostlist_push_hr(hostlist_t hl, char *prefix, unsigned long lo,
  961. unsigned long hi, int width)
  962. {
  963. hostrange_t hr = hostrange_create(prefix, lo, hi, width);
  964. int retval = hostlist_push_range(hl, hr);
  965. hostrange_destroy(hr);
  966. return retval;
  967. }
  968. /* Insert a range object hr into position n of the hostlist hl
  969. * Assumes that hl->mutex is already held by calling process
  970. */
  971. static int hostlist_insert_range(hostlist_t hl, hostrange_t hr, int n)
  972. {
  973. int i;
  974. hostrange_t tmp;
  975. hostlist_iterator_t hli;
  976. assert(hl != NULL);
  977. assert(hl->magic == HOSTLIST_MAGIC);
  978. assert(hr != NULL);
  979. if (n > hl->nranges)
  980. return 0;
  981. if (hl->size == hl->nranges && !hostlist_expand(hl))
  982. return 0;
  983. /* copy new hostrange into slot "n" in array */
  984. tmp = hl->hr[n];
  985. hl->hr[n] = hostrange_copy(hr);
  986. /* push remaining hostrange entries up */
  987. for (i = n + 1; i < hl->nranges + 1; i++) {
  988. hostrange_t last = hl->hr[i];
  989. hl->hr[i] = tmp;
  990. tmp = last;
  991. }
  992. hl->nranges++;
  993. /* adjust hostlist iterators if needed */
  994. for (hli = hl->ilist; hli; hli = hli->next) {
  995. if (hli->idx >= n)
  996. hli->hr = hli->hl->hr[++hli->idx];
  997. }
  998. return 1;
  999. }
  1000. /* Delete the range at position n in the range array
  1001. * Assumes the hostlist lock is already held.
  1002. */
  1003. static void hostlist_delete_range(hostlist_t hl, int n)
  1004. {
  1005. int i;
  1006. hostrange_t old;
  1007. assert(hl != NULL);
  1008. assert(hl->magic == HOSTLIST_MAGIC);
  1009. assert(n < hl->nranges && n >= 0);
  1010. old = hl->hr[n];
  1011. for (i = n; i < hl->nranges - 1; i++)
  1012. hl->hr[i] = hl->hr[i + 1];
  1013. hl->nranges--;
  1014. hl->hr[hl->nranges] = NULL;
  1015. hostlist_shift_iterators(hl, n, 0, 1);
  1016. /* XXX caller responsible for adjusting nhosts */
  1017. /* hl->nhosts -= hostrange_count(old) */
  1018. hostrange_destroy(old);
  1019. }
  1020. #if WANT_RECKLESS_HOSTRANGE_EXPANSION
  1021. /* The reckless hostrange expansion function.
  1022. * See comment in hostlist.h:hostlist_create() for more info on
  1023. * the different choices for hostlist notation.
  1024. */
  1025. hostlist_t _hostlist_create(const char *hostlist, char *sep, char *r_op)
  1026. {
  1027. char *str, *orig;
  1028. char *tok, *cur;
  1029. int high, low, fmt = 0;
  1030. char prefix[256] = "";
  1031. int pos = 0;
  1032. int error = 0;
  1033. char range_op = r_op[0];/* XXX support > 1 char range ops in future? */
  1034. hostlist_t new = hostlist_new();
  1035. orig = str = strdup(hostlist);
  1036. /* return an empty list if an empty string was passed in */
  1037. if (str == NULL || strlen(str) == 0)
  1038. goto done;
  1039. /* Use hostlist_create_bracketed if we see "[" */
  1040. if (strchr(str, '[') != NULL)
  1041. return _hostlist_create_bracketed(hostlist, sep, r_op);
  1042. while ((tok = _next_tok(sep, &str)) != NULL) {
  1043. /* save the current string for error messages */
  1044. cur = tok;
  1045. high = low = 0;
  1046. /* find end of alpha part
  1047. * do this by finding last occurence of range_op in str */
  1048. pos = strlen(tok) - 1;
  1049. if (strstr(tok, r_op) != '\0') {
  1050. while (pos >= 0 && (char) tok[pos] != range_op)
  1051. pos--;
  1052. }
  1053. /* now back up past any digits */
  1054. while (pos >= 0 && isdigit((char) tok[--pos])) {;}
  1055. /* Check for valid x-y range (x must be a digit)
  1056. * Reset pos if the range is not valid */
  1057. if (!isdigit((char) tok[++pos]))
  1058. pos = strlen(tok) - 1;
  1059. /* create prefix string
  1060. * if prefix will be zero length, but prefix already exists
  1061. * use the previous prefix and fmt
  1062. */
  1063. if ((pos > 0) || (prefix[0] == '\0')) {
  1064. memcpy(prefix, tok, (size_t) pos * sizeof(char));
  1065. prefix[pos] = '\0';
  1066. /* push pointer past prefix */
  1067. tok += pos;
  1068. /* count number of digits for ouput fmt */
  1069. for (fmt = 0; isdigit(tok[fmt]); ++fmt) {;}
  1070. if (fmt == 0)
  1071. error = 1;
  1072. } else
  1073. tok += pos;
  1074. /* get lower bound */
  1075. low = strtoul(tok, (char **) &tok, 10);
  1076. if (*tok == range_op) { /* now get range upper bound */
  1077. /* push pointer past range op */
  1078. ++tok;
  1079. /* find length of alpha part */
  1080. for (pos = 0; tok[pos] && !isdigit(tok[pos]); ++pos) {;}
  1081. /* alpha part must match prefix or error
  1082. * this could mean we've got something like "rtr1-a2"
  1083. * so just record an error
  1084. */
  1085. if (pos > 0) {
  1086. if (pos != strlen(prefix) ||
  1087. strncmp(prefix, tok, pos) != 0)
  1088. error = 1;
  1089. }
  1090. if (*tok != '\0')
  1091. tok += pos;
  1092. /* make sure we have digits to the end */
  1093. for (pos = 0; tok[pos] && isdigit((char) tok[pos]); ++pos) {;}
  1094. if (pos > 0) { /* we have digits to process */
  1095. high = strtoul(tok, (char **) &tok, 10);
  1096. } else { /* bad boy, no digits */
  1097. error = 1;
  1098. }
  1099. if ((low > high) || (high - low > MAX_RANGE))
  1100. error = 1;
  1101. } else { /* single value */
  1102. high = 0; /* special case, ugh. */
  1103. }
  1104. /* error if:
  1105. * 1. we are not at end of string
  1106. * 2. upper bound equals lower bound
  1107. */
  1108. if (*tok != '\0' || high == low)
  1109. error = 1;
  1110. if (error) { /* assume this is not a range on any error */
  1111. hostlist_push_host(new, cur);
  1112. } else {
  1113. if (high < low)
  1114. high = low;
  1115. hostlist_push_hr(new, prefix, low, high, fmt);
  1116. }
  1117. error = 0;
  1118. }
  1119. done:
  1120. free(orig);
  1121. return new;
  1122. }
  1123. #else /* !WANT_RECKLESS_HOSTRANGE_EXPANSION */
  1124. hostlist_t _hostlist_create(const char *hostlist, char *sep, char *r_op)
  1125. {
  1126. return _hostlist_create_bracketed(hostlist, sep, r_op);
  1127. }
  1128. #endif /* WANT_RECKLESS_HOSTRANGE_EXPANSION */
  1129. struct _range {
  1130. unsigned long lo, hi;
  1131. int width;
  1132. };
  1133. /* Grab a single range from str
  1134. * returns 1 if str contained a valid number or range,
  1135. * 0 if conversion of str to a range failed.
  1136. */
  1137. static int _parse_single_range(const char *str, struct _range *range)
  1138. {
  1139. char *p, *q;
  1140. char *orig = strdup(str);
  1141. if (!orig)
  1142. seterrno_ret(ENOMEM, 0);
  1143. if ((p = strchr(str, '-'))) {
  1144. *p++ = '\0';
  1145. if (*p == '-') /* do NOT allow negative numbers */
  1146. goto error;
  1147. }
  1148. range->lo = strtoul(str, &q, 10);
  1149. if (q == str)
  1150. goto error;
  1151. range->hi = (p && *p) ? strtoul(p, &q, 10) : range->lo;
  1152. if (q == p || *q != '\0')
  1153. goto error;
  1154. if (range->lo > range->hi)
  1155. goto error;
  1156. if (range->hi - range->lo + 1 > MAX_RANGE ) {
  1157. _error(__FILE__, __LINE__, "Too many hosts in range `%s'", orig);
  1158. free(orig);
  1159. seterrno_ret(ERANGE, 0);
  1160. }
  1161. free(orig);
  1162. range->width = strlen(str);
  1163. return 1;
  1164. error:
  1165. _error(__FILE__, __LINE__, "Invalid range: `%s'", orig);
  1166. free(orig);
  1167. seterrno_ret(EINVAL, 0);
  1168. }
  1169. /*
  1170. * Convert 'str' containing comma separated digits and ranges into an array
  1171. * of struct _range types (max 'len' elements).
  1172. *
  1173. * Return number of ranges created, or -1 on error.
  1174. */
  1175. static int _parse_range_list(char *str, struct _range *ranges, int len)
  1176. {
  1177. char *p;
  1178. int count = 0;
  1179. while (str) {
  1180. if (count == len)
  1181. return -1;
  1182. if ((p = strchr(str, ',')))
  1183. *p++ = '\0';
  1184. if (!_parse_single_range(str, &ranges[count++]))
  1185. return -1;
  1186. str = p;
  1187. }
  1188. return count;
  1189. }
  1190. static void
  1191. _push_range_list(hostlist_t hl, char *pfx, struct _range *rng,
  1192. int n)
  1193. {
  1194. int i;
  1195. for (i = 0; i < n; i++) {
  1196. hostlist_push_hr(hl, pfx, rng->lo, rng->hi, rng->width);
  1197. rng++;
  1198. }
  1199. }
  1200. static void
  1201. _push_range_list_with_suffix(hostlist_t hl, char *pfx, char *sfx,
  1202. struct _range *rng, int n)
  1203. {
  1204. int i;
  1205. unsigned long j;
  1206. for (i = 0; i < n; i++) {
  1207. for (j = rng->lo; j <= rng->hi; j++) {
  1208. char host[4096];
  1209. hostrange_t hr;
  1210. snprintf (host, 4096, "%s%0*lu%s", pfx, rng->width, j, sfx);
  1211. hr = hostrange_create_single (host);
  1212. hostlist_push_range (hl, hr);
  1213. /*
  1214. * hr is copied in hostlist_push_range. Need to free here.
  1215. */
  1216. hostrange_destroy (hr);
  1217. }
  1218. rng++;
  1219. }
  1220. }
  1221. /*
  1222. * Create a hostlist from a string with brackets '[' ']' to aid
  1223. * detection of ranges and compressed lists
  1224. */
  1225. static hostlist_t
  1226. _hostlist_create_bracketed(const char *hostlist, char *sep, char *r_op)
  1227. {
  1228. hostlist_t new = hostlist_new();
  1229. struct _range ranges[MAX_RANGES];
  1230. int nr, err;
  1231. char *p, *tok, *str, *orig;
  1232. char cur_tok[1024];
  1233. if (hostlist == NULL)
  1234. return new;
  1235. if (!(orig = str = strdup(hostlist))) {
  1236. hostlist_destroy(new);
  1237. return NULL;
  1238. }
  1239. while ((tok = _next_tok(sep, &str)) != NULL) {
  1240. strncpy(cur_tok, tok, 1024);
  1241. if ((p = strchr(tok, '[')) != NULL) {
  1242. char *q, *prefix = tok;
  1243. *p++ = '\0';
  1244. if ((q = strchr(p, ']'))) {
  1245. *q = '\0';
  1246. nr = _parse_range_list(p, ranges, MAX_RANGES);
  1247. if (nr < 0)
  1248. goto error;
  1249. if (*(++q) != '\0')
  1250. _push_range_list_with_suffix (new, prefix, q, ranges, nr);
  1251. else
  1252. _push_range_list(new, prefix, ranges, nr);
  1253. } else
  1254. hostlist_push_host(new, cur_tok);
  1255. } else
  1256. hostlist_push_host(new, cur_tok);
  1257. }
  1258. free(orig);
  1259. return new;
  1260. error:
  1261. err = errno;
  1262. hostlist_destroy(new);
  1263. free(orig);
  1264. seterrno_ret(err, NULL);
  1265. }
  1266. hostlist_t hostlist_create(const char *str)
  1267. {
  1268. return _hostlist_create(str, "\t, ", "-");
  1269. }
  1270. hostlist_t hostlist_copy(const hostlist_t hl)
  1271. {
  1272. int i;
  1273. hostlist_t new;
  1274. if (hl == NULL)
  1275. return NULL;
  1276. LOCK_HOSTLIST(hl);
  1277. if (!(new = hostlist_new()))
  1278. goto done;
  1279. new->nranges = hl->nranges;
  1280. new->nhosts = hl->nhosts;
  1281. if (new->nranges > new->size)
  1282. hostlist_resize(new, new->nranges);
  1283. for (i = 0; i < hl->nranges; i++)
  1284. new->hr[i] = hostrange_copy(hl->hr[i]);
  1285. done:
  1286. UNLOCK_HOSTLIST(hl);
  1287. return new;
  1288. }
  1289. void hostlist_destroy(hostlist_t hl)
  1290. {
  1291. int i;
  1292. if (hl == NULL)
  1293. return;
  1294. LOCK_HOSTLIST(hl);
  1295. while (hl->ilist) {
  1296. mutex_unlock(&hl->mutex);
  1297. hostlist_iterator_destroy(hl->ilist);
  1298. mutex_lock(&hl->mutex);
  1299. }
  1300. for (i = 0; i < hl->nranges; i++)
  1301. hostrange_destroy(hl->hr[i]);
  1302. free(hl->hr);
  1303. assert(hl->magic = 0x1);
  1304. UNLOCK_HOSTLIST(hl);
  1305. mutex_destroy(&hl->mutex);
  1306. free(hl);
  1307. }
  1308. int hostlist_push(hostlist_t hl, const char *hosts)
  1309. {
  1310. hostlist_t new;
  1311. int retval;
  1312. if (hosts == NULL)
  1313. return 0;
  1314. new = hostlist_create(hosts);
  1315. if (!new)
  1316. return 0;
  1317. mutex_lock(&new->mutex);
  1318. retval = new->nhosts;
  1319. mutex_unlock(&new->mutex);
  1320. hostlist_push_list(hl, new);
  1321. hostlist_destroy(new);
  1322. return retval;
  1323. }
  1324. int hostlist_push_host(hostlist_t hl, const char *str)
  1325. {
  1326. hostrange_t hr;
  1327. hostname_t hn;
  1328. if (str == NULL)
  1329. return 0;
  1330. hn = hostname_create(str);
  1331. if (hostname_suffix_is_valid(hn)) {
  1332. hr = hostrange_create(hn->prefix, hn->num, hn->num,
  1333. hostname_suffix_width(hn));
  1334. } else
  1335. hr = hostrange_create_single(str);
  1336. hostlist_push_range(hl, hr);
  1337. hostrange_destroy(hr);
  1338. hostname_destroy(hn);
  1339. return 1;
  1340. }
  1341. int hostlist_push_list(hostlist_t h1, hostlist_t h2)
  1342. {
  1343. int i, n = 0;
  1344. if (h2 == NULL)
  1345. return 0;
  1346. LOCK_HOSTLIST(h2);
  1347. for (i = 0; i < h2->nranges; i++)
  1348. n += hostlist_push_range(h1, h2->hr[i]);
  1349. UNLOCK_HOSTLIST(h2);
  1350. return n;
  1351. }
  1352. char *hostlist_pop(hostlist_t hl)
  1353. {
  1354. char *host = NULL;
  1355. LOCK_HOSTLIST(hl);
  1356. if (hl->nhosts > 0) {
  1357. hostrange_t hr = hl->hr[hl->nranges - 1];
  1358. host = hostrange_pop(hr);
  1359. hl->nhosts--;
  1360. if (hostrange_empty(hr)) {
  1361. hostrange_destroy(hl->hr[--hl->nranges]);
  1362. hl->hr[hl->nranges] = NULL;
  1363. }
  1364. }
  1365. UNLOCK_HOSTLIST(hl);
  1366. return host;
  1367. }
  1368. /* find all iterators affected by a shift (or deletion) at
  1369. * hl->hr[idx], depth, with the deletion of n ranges */
  1370. static void
  1371. hostlist_shift_iterators(hostlist_t hl, int idx, int depth, int n)
  1372. {
  1373. hostlist_iterator_t i;
  1374. for (i = hl->ilist; i; i = i->next) {
  1375. if (n == 0) {
  1376. if (i->idx == idx && i->depth >= depth)
  1377. i->depth = i->depth > -1 ? i->depth - 1 : -1;
  1378. } else {
  1379. if (i->idx >= idx) {
  1380. if ((i->idx -= n) >= 0)
  1381. i->hr = i->hl->hr[i->idx];
  1382. else
  1383. hostlist_iterator_reset(i);
  1384. }
  1385. }
  1386. }
  1387. }
  1388. char *hostlist_shift(hostlist_t hl)
  1389. {
  1390. char *host = NULL;
  1391. LOCK_HOSTLIST(hl);
  1392. if (hl->nhosts > 0) {
  1393. hostrange_t hr = hl->hr[0];
  1394. host = hostrange_shift(hr);
  1395. hl->nhosts--;
  1396. if (hostrange_empty(hr)) {
  1397. hostlist_delete_range(hl, 0);
  1398. /* hl->nranges--; */
  1399. } else
  1400. hostlist_shift_iterators(hl, 0, 0, 0);
  1401. }
  1402. UNLOCK_HOSTLIST(hl);
  1403. return host;
  1404. }
  1405. char *hostlist_pop_range(hostlist_t hl)
  1406. {
  1407. int i;
  1408. char buf[MAXHOSTRANGELEN + 1];
  1409. hostlist_t hltmp;
  1410. hostrange_t tail;
  1411. LOCK_HOSTLIST(hl);
  1412. if (hl->nranges < 1 || !(hltmp = hostlist_new())) {
  1413. UNLOCK_HOSTLIST(hl);
  1414. return NULL;
  1415. }
  1416. i = hl->nranges - 2;
  1417. tail = hl->hr[hl->nranges - 1];
  1418. while (i >= 0 && hostrange_within_range(tail, hl->hr[i]))
  1419. i--;
  1420. for (i++; i < hl->nranges; i++) {
  1421. hostlist_push_range(hltmp, hl->hr[i]);
  1422. hostrange_destroy(hl->hr[i]);
  1423. hl->hr[i] = NULL;
  1424. }
  1425. hl->nhosts -= hltmp->nhosts;
  1426. hl->nranges -= hltmp->nranges;
  1427. UNLOCK_HOSTLIST(hl);
  1428. hostlist_ranged_string(hltmp, MAXHOSTRANGELEN, buf);
  1429. hostlist_destroy(hltmp);
  1430. return strdup(buf);
  1431. }
  1432. char *hostlist_shift_range(hostlist_t hl)
  1433. {
  1434. int i;
  1435. char buf[1024];
  1436. hostlist_t hltmp = hostlist_new();
  1437. if (!hltmp)
  1438. return NULL;
  1439. LOCK_HOSTLIST(hl);
  1440. if (hl->nranges == 0) {
  1441. hostlist_destroy(hltmp);
  1442. UNLOCK_HOSTLIST(hl);
  1443. return NULL;
  1444. }
  1445. i = 0;
  1446. do {
  1447. hostlist_push_range(hltmp, hl->hr[i]);
  1448. hostrange_destroy(hl->hr[i]);
  1449. } while ( (++i < hl->nranges)
  1450. && hostrange_within_range(hltmp->hr[0], hl->hr[i]) );
  1451. hostlist_shift_iterators(hl, i, 0, hltmp->nranges);
  1452. /* shift rest of ranges back in hl */
  1453. for (; i < hl->nranges; i++) {
  1454. hl->hr[i - hltmp->nranges] = hl->hr[i];
  1455. hl->hr[i] = NULL;
  1456. }
  1457. hl->nhosts -= hltmp->nhosts;
  1458. hl->nranges -= hltmp->nranges;
  1459. UNLOCK_HOSTLIST(hl);
  1460. hostlist_ranged_string(hltmp, 1024, buf);
  1461. hostlist_destroy(hltmp);
  1462. return strdup(buf);
  1463. }
  1464. /* XXX: Note: efficiency improvements needed */
  1465. int hostlist_delete(hostlist_t hl, const char *hosts)
  1466. {
  1467. int n = 0;
  1468. char *hostname = NULL;
  1469. hostlist_t hltmp;
  1470. if (!(hltmp = hostlist_create(hosts)))
  1471. seterrno_ret(EINVAL, 0);
  1472. while ((hostname = hostlist_pop(hltmp)) != NULL) {
  1473. n += hostlist_delete_host(hl, hostname);
  1474. free(hostname);
  1475. }
  1476. hostlist_destroy(hltmp);
  1477. return n;
  1478. }
  1479. /* XXX watch out! poor implementation follows! (fix it at some point) */
  1480. int hostlist_delete_host(hostlist_t hl, const char *hostname)
  1481. {
  1482. int n = hostlist_find(hl, hostname);
  1483. if (n >= 0)
  1484. hostlist_delete_nth(hl, n);
  1485. return n >= 0 ? 1 : 0;
  1486. }
  1487. static char *
  1488. _hostrange_string(hostrange_t hr, int depth)
  1489. {
  1490. char buf[MAXHOSTNAMELEN + 16];
  1491. int len = snprintf(buf, MAXHOSTNAMELEN + 15, "%s", hr->prefix);
  1492. if (!hr->singlehost)
  1493. snprintf(buf+len, MAXHOSTNAMELEN+15 - len, "%0*lu",
  1494. hr->width, hr->lo + depth);
  1495. return strdup(buf);
  1496. }
  1497. char * hostlist_nth(hostlist_t hl, int n)
  1498. {
  1499. char *host = NULL;
  1500. int i, count;
  1501. LOCK_HOSTLIST(hl);
  1502. count = 0;
  1503. for (i = 0; i < hl->nranges; i++) {
  1504. int num_in_range = hostrange_count(hl->hr[i]);
  1505. if (n <= (num_in_range - 1 + count)) {
  1506. host = _hostrange_string(hl->hr[i], n - count);
  1507. break;
  1508. } else
  1509. count += num_in_range;
  1510. }
  1511. UNLOCK_HOSTLIST(hl);
  1512. return host;
  1513. }
  1514. int hostlist_delete_nth(hostlist_t hl, int n)
  1515. {
  1516. int i, count;
  1517. LOCK_HOSTLIST(hl);
  1518. assert(n >= 0 && n <= hl->nhosts);
  1519. count = 0;
  1520. for (i = 0; i < hl->nranges; i++) {
  1521. int num_in_range = hostrange_count(hl->hr[i]);
  1522. hostrange_t hr = hl->hr[i];
  1523. if (n <= (num_in_range - 1 + count)) {
  1524. unsigned long num = hr->lo + n - count;
  1525. hostrange_t new;
  1526. if (hr->singlehost) { /* this wasn't a range */
  1527. hostlist_delete_range(hl, i);
  1528. } else if ((new = hostrange_delete_host(hr, num))) {
  1529. hostlist_insert_range(hl, new, i + 1);
  1530. hostrange_destroy(new);
  1531. } else if (hostrange_empty(hr))
  1532. hostlist_delete_range(hl, i);
  1533. goto done;
  1534. } else
  1535. count += num_in_range;
  1536. }
  1537. done:
  1538. hl->nhosts--;
  1539. UNLOCK_HOSTLIST(hl);
  1540. return 1;
  1541. }
  1542. int hostlist_count(hostlist_t hl)
  1543. {
  1544. int retval;
  1545. LOCK_HOSTLIST(hl);
  1546. retval = hl->nhosts;
  1547. UNLOCK_HOSTLIST(hl);
  1548. return retval;
  1549. }
  1550. int hostlist_find(hostlist_t hl, const char *hostname)
  1551. {
  1552. int i, count, ret = -1;
  1553. hostname_t hn;
  1554. if (!hostname)
  1555. return -1;
  1556. hn = hostname_create(hostname);
  1557. LOCK_HOSTLIST(hl);
  1558. for (i = 0, count = 0; i < hl->nranges; i++) {
  1559. int offset = hostrange_hn_within(hl->hr[i], hn);
  1560. if (offset >= 0) {
  1561. ret = count + offset;
  1562. break;
  1563. }
  1564. else
  1565. count += hostrange_count(hl->hr[i]);
  1566. }
  1567. UNLOCK_HOSTLIST(hl);
  1568. hostname_destroy(hn);
  1569. return ret;
  1570. }
  1571. /* hostrange compare with void * arguments to allow use with
  1572. * libc qsort()
  1573. */
  1574. int _cmp(const void *hr1, const void *hr2)
  1575. {
  1576. hostrange_t *h1 = (hostrange_t *) hr1;
  1577. hostrange_t *h2 = (hostrange_t *) hr2;
  1578. return hostrange_cmp((hostrange_t) * h1, (hostrange_t) * h2);
  1579. }
  1580. void hostlist_sort(hostlist_t hl)
  1581. {
  1582. hostlist_iterator_t i;
  1583. LOCK_HOSTLIST(hl);
  1584. if (hl->nranges <= 1) {
  1585. UNLOCK_HOSTLIST(hl);
  1586. return;
  1587. }
  1588. qsort(hl->hr, hl->nranges, sizeof(hostrange_t), &_cmp);
  1589. /* reset all iterators */
  1590. for (i = hl->ilist; i; i = i->next)
  1591. hostlist_iterator_reset(i);
  1592. UNLOCK_HOSTLIST(hl);
  1593. hostlist_coalesce(hl);
  1594. }
  1595. /* search through hostlist for ranges that can be collapsed
  1596. * does =not= delete any hosts
  1597. */
  1598. static void hostlist_collapse(hostlist_t hl)
  1599. {
  1600. int i;
  1601. LOCK_HOSTLIST(hl);
  1602. for (i = hl->nranges - 1; i > 0; i--) {
  1603. hostrange_t hprev = hl->hr[i - 1];
  1604. hostrange_t hnext = hl->hr[i];
  1605. if (hostrange_prefix_cmp(hprev, hnext) == 0 &&
  1606. hprev->hi == hnext->lo - 1 &&
  1607. hostrange_width_combine(hprev, hnext)) {
  1608. hprev->hi = hnext->hi;
  1609. hostlist_delete_range(hl, i);
  1610. }
  1611. }
  1612. UNLOCK_HOSTLIST(hl);
  1613. }
  1614. /* search through hostlist (hl) for intersecting ranges
  1615. * split up duplicates and coalesce ranges where possible
  1616. */
  1617. static void hostlist_coalesce(hostlist_t hl)
  1618. {
  1619. int i, j;
  1620. hostrange_t new;
  1621. LOCK_HOSTLIST(hl);
  1622. for (i = hl->nranges - 1; i > 0; i--) {
  1623. new = hostrange_intersect(hl->hr[i - 1], hl->hr[i]);
  1624. if (new) {
  1625. hostrange_t hprev = hl->hr[i - 1];
  1626. hostrange_t hnext = hl->hr[i];
  1627. j = i;
  1628. if (new->hi < hprev->hi)
  1629. hnext->hi = hprev->hi;
  1630. hprev->hi = new->lo;
  1631. hnext->lo = new->hi;
  1632. if (hostrange_empty(hprev))
  1633. hostlist_delete_range(hl, i);
  1634. while (new->lo <= new->hi) {
  1635. hostrange_t hr = hostrange_create( new->prefix,
  1636. new->lo, new->lo,
  1637. new->width );
  1638. if (new->lo > hprev->hi)
  1639. hostlist_insert_range(hl, hr, j++);
  1640. if (new->lo < hnext->lo)
  1641. hostlist_insert_range(hl, hr, j++);
  1642. hostrange_destroy(hr);
  1643. new->lo++;
  1644. }
  1645. i = hl->nranges;
  1646. hostrange_destroy(new);
  1647. }
  1648. }
  1649. UNLOCK_HOSTLIST(hl);
  1650. hostlist_collapse(hl);
  1651. }
  1652. /* attempt to join ranges at loc and loc-1 in a hostlist */
  1653. /* delete duplicates, return the number of hosts deleted */
  1654. /* assumes that the hostlist hl has been locked by caller */
  1655. /* returns -1 if no range join occurred */
  1656. static int _attempt_range_join(hostlist_t hl, int loc)
  1657. {
  1658. int ndup;
  1659. assert(hl != NULL);
  1660. assert(hl->magic == HOSTLIST_MAGIC);
  1661. assert(loc > 0);
  1662. assert(loc < hl->nranges);
  1663. ndup = hostrange_join(hl->hr[loc - 1], hl->hr[loc]);
  1664. if (ndup >= 0) {
  1665. hostlist_delete_range(hl, loc);
  1666. hl->nhosts -= ndup;
  1667. }
  1668. return ndup;
  1669. }
  1670. void hostlist_uniq(hostlist_t hl)
  1671. {
  1672. int i = 1;
  1673. hostlist_iterator_t hli;
  1674. LOCK_HOSTLIST(hl);
  1675. if (hl->nranges <= 1) {
  1676. UNLOCK_HOSTLIST(hl);
  1677. return;
  1678. }
  1679. qsort(hl->hr, hl->nranges, sizeof(hostrange_t), &_cmp);
  1680. while (i < hl->nranges) {
  1681. if (_attempt_range_join(hl, i) < 0) /* No range join occurred */
  1682. i++;
  1683. }
  1684. /* reset all iterators */
  1685. for (hli = hl->ilist; hli; hli = hli->next)
  1686. hostlist_iterator_reset(hli);
  1687. UNLOCK_HOSTLIST(hl);
  1688. }
  1689. ssize_t hostlist_deranged_string(hostlist_t hl, size_t n, char *buf)
  1690. {
  1691. int i;
  1692. int len = 0;
  1693. int truncated = 0;
  1694. LOCK_HOSTLIST(hl);
  1695. for (i = 0; i < hl->nranges; i++) {
  1696. size_t m = (n - len) <= n ? n - len : 0;
  1697. int ret = hostrange_to_string(hl->hr[i], m, buf + len, ",");
  1698. if (ret < 0 || ret > m) {
  1699. len = n;
  1700. truncated = 1;
  1701. break;
  1702. }
  1703. len+=ret;
  1704. buf[len++] = ',';
  1705. }
  1706. UNLOCK_HOSTLIST(hl);
  1707. buf[len > 0 ? --len : 0] = '\0';
  1708. if (len == n)
  1709. truncated = 1;
  1710. return truncated ? -1 : len;
  1711. }
  1712. /* return true if a bracket is needed for the range at i in hostlist hl */
  1713. static int _is_bracket_needed(hostlist_t hl, int i)
  1714. {
  1715. hostrange_t h1 = hl->hr[i];
  1716. hostrange_t h2 = i < hl->nranges - 1 ? hl->hr[i + 1] : NULL;
  1717. return hostrange_count(h1) > 1 || hostrange_within_range(h1, h2);
  1718. }
  1719. /* write the next bracketed hostlist, i.e. prefix[n-m,k,...]
  1720. * into buf, writing at most n chars including the terminating '\0'
  1721. *
  1722. * leaves start pointing to one past last range object in bracketed list,
  1723. * and returns the number of bytes written into buf.
  1724. *
  1725. * Assumes hostlist is locked.
  1726. */
  1727. static int
  1728. _get_bracketed_list(hostlist_t hl, int *start, const size_t n, char *buf)
  1729. {
  1730. hostrange_t *hr = hl->hr;
  1731. int i = *start;
  1732. int m, len = 0;
  1733. int bracket_needed = _is_bracket_needed(hl, i);
  1734. len = snprintf(buf, n, "%s", hr[i]->prefix);
  1735. if ((len < 0) || (len > n))
  1736. return n; /* truncated, buffer filled */
  1737. if (bracket_needed && len < n && len >= 0)
  1738. buf[len++] = '[';
  1739. do {
  1740. m = (n - len) <= n ? n - len : 0;
  1741. len += hostrange_numstr(hr[i], m, buf + len);
  1742. if (len >= n)
  1743. break;
  1744. if (bracket_needed) /* Only need commas inside brackets */
  1745. buf[len++] = ',';
  1746. } while (++i < hl->nranges && hostrange_within_range(hr[i], hr[i-1]));
  1747. if (bracket_needed && len < n && len > 0) {
  1748. /* Add trailing bracket (change trailing "," from above to "]" */
  1749. buf[len - 1] = ']';
  1750. /* NUL terminate for safety, but do not add terminator to len */
  1751. buf[len] = '\0';
  1752. } else if (len >= n) {
  1753. if (n > 0)
  1754. buf[n-1] = '\0';
  1755. } else {
  1756. /* If len is > 0, NUL terminate (but do not add to len) */
  1757. buf[len > 0 ? len : 0] = '\0';
  1758. }
  1759. *start = i;
  1760. return len;
  1761. }
  1762. ssize_t hostlist_ranged_string(hostlist_t hl, size_t n, char *buf)
  1763. {
  1764. int i = 0;
  1765. int len = 0;
  1766. int truncated = 0;
  1767. LOCK_HOSTLIST(hl);
  1768. while (i < hl->nranges && len < n) {
  1769. len += _get_bracketed_list(hl, &i, n - len, buf + len);
  1770. if ((len > 0) && (len < n) && (i < hl->nranges))
  1771. buf[len++] = ',';
  1772. }
  1773. UNLOCK_HOSTLIST(hl);
  1774. /* NUL terminate */
  1775. if (len >= n) {
  1776. truncated = 1;
  1777. if (n > 0)
  1778. buf[n-1] = '\0';
  1779. } else
  1780. buf[len > 0 ? len : 0] = '\0';
  1781. return truncated ? -1 : len;
  1782. }
  1783. /* ----[ hostlist iterator functions ]---- */
  1784. static hostlist_iterator_t hostlist_iterator_new(void)
  1785. {
  1786. hostlist_iterator_t i = (hostlist_iterator_t) malloc(sizeof(*i));
  1787. if (!i)
  1788. return NULL;
  1789. i->hl = NULL;
  1790. i->hr = NULL;
  1791. i->idx = 0;
  1792. i->depth = -1;
  1793. i->next = i;
  1794. assert(i->magic = HOSTLIST_MAGIC);
  1795. return i;
  1796. }
  1797. hostlist_iterator_t hostlist_iterator_create(hostlist_t hl)
  1798. {
  1799. hostlist_iterator_t i;
  1800. if (!(i = hostlist_iterator_new()))
  1801. out_of_memory("hostlist_iterator_create");
  1802. LOCK_HOSTLIST(hl);
  1803. i->hl = hl;
  1804. i->hr = hl->hr[0];
  1805. i->next = hl->ilist;
  1806. hl->ilist = i;
  1807. UNLOCK_HOSTLIST(hl);
  1808. return i;
  1809. }
  1810. hostlist_iterator_t hostset_iterator_create(hostset_t set)
  1811. {
  1812. return hostlist_iterator_create(set->hl);
  1813. }
  1814. void hostlist_iterator_reset(hostlist_iterator_t i)
  1815. {
  1816. assert(i != NULL);
  1817. assert(i->magic == HOSTLIST_MAGIC);
  1818. i->idx = 0;
  1819. i->hr = i->hl->hr[0];
  1820. i->depth = -1;
  1821. return;
  1822. }
  1823. void hostlist_iterator_destroy(hostlist_iterator_t i)
  1824. {
  1825. hostlist_iterator_t *pi;
  1826. if (i == NULL)
  1827. return;
  1828. assert(i != NULL);
  1829. assert(i->magic == HOSTLIST_MAGIC);
  1830. LOCK_HOSTLIST(i->hl);
  1831. for (pi = &i->hl->ilist; *pi; pi = &(*pi)->next) {
  1832. assert((*pi)->magic == HOSTLIST_MAGIC);
  1833. if (*pi == i) {
  1834. *pi = (*pi)->next;
  1835. break;
  1836. }
  1837. }
  1838. UNLOCK_HOSTLIST(i->hl);
  1839. assert(i->magic = 0x1);
  1840. free(i);
  1841. }
  1842. static void _iterator_advance(hostlist_iterator_t i)
  1843. {
  1844. assert(i != NULL);
  1845. assert(i->magic == HOSTLIST_MAGIC);
  1846. if (i->idx > i->hl->nranges - 1)
  1847. return;
  1848. if (++(i->depth) > (i->hr->hi - i->hr->lo)) {
  1849. i->depth = 0;
  1850. i->hr = i->hl->hr[++i->idx];
  1851. }
  1852. }
  1853. /* advance iterator to end of current range (meaning within "[" "]")
  1854. * i.e. advance iterator past all range objects that could be represented
  1855. * in on bracketed hostlist.
  1856. */
  1857. static void _iterator_advance_range(hostlist_iterator_t i)
  1858. {
  1859. int nr, j;
  1860. hostrange_t *hr;
  1861. assert(i != NULL);
  1862. assert(i->magic == HOSTLIST_MAGIC);
  1863. nr = i->hl->nranges;
  1864. hr = i->hl->hr;
  1865. j = i->idx;
  1866. if (++i->depth > 0) {
  1867. while (++j < nr && hostrange_within_range(i->hr, hr[j])) {;}
  1868. i->idx = j;
  1869. i->hr = i->hl->hr[i->idx];
  1870. i->depth = 0;
  1871. }
  1872. }
  1873. char *hostlist_next(hostlist_iterator_t i)
  1874. {
  1875. char *buf = NULL;
  1876. char suffix[16];
  1877. int len = 0;
  1878. assert(i != NULL);
  1879. assert(i->magic == HOSTLIST_MAGIC);
  1880. LOCK_HOSTLIST(i->hl);
  1881. _iterator_advance(i);
  1882. if (i->idx > i->hl->nranges - 1) {
  1883. UNLOCK_HOSTLIST(i->hl);
  1884. return NULL;
  1885. }
  1886. suffix[0] = '\0';
  1887. if (!i->hr->singlehost)
  1888. snprintf (suffix, 15, "%0*lu", i->hr->width, i->hr->lo + i->depth);
  1889. len = strlen (i->hr->prefix) + strlen (suffix) + 1;
  1890. if (!(buf = malloc (len)))
  1891. out_of_memory("hostlist_next");
  1892. buf[0] = '\0';
  1893. strcat (buf, i->hr->prefix);
  1894. strcat (buf, suffix);
  1895. UNLOCK_HOSTLIST(i->hl);
  1896. return (buf);
  1897. }
  1898. char *hostlist_next_range(hostlist_iterator_t i)
  1899. {
  1900. char buf[MAXHOSTRANGELEN + 1];
  1901. int j;
  1902. assert(i != NULL);
  1903. assert(i->magic == HOSTLIST_MAGIC);
  1904. LOCK_HOSTLIST(i->hl);
  1905. _iterator_advance_range(i);
  1906. if (i->idx > i->hl->nranges - 1) {
  1907. UNLOCK_HOSTLIST(i->hl);
  1908. return NULL;
  1909. }
  1910. j = i->idx;
  1911. _get_bracketed_list(i->hl, &j, MAXHOSTRANGELEN, buf);
  1912. UNLOCK_HOSTLIST(i->hl);
  1913. return strdup(buf);
  1914. }
  1915. int hostlist_remove(hostlist_iterator_t i)
  1916. {
  1917. hostrange_t new;
  1918. assert(i != NULL);
  1919. assert(i->magic == HOSTLIST_MAGIC);
  1920. LOCK_HOSTLIST(i->hl);
  1921. new = hostrange_delete_host(i->hr, i->hr->lo + i->depth);
  1922. if (new) {
  1923. hostlist_insert_range(i->hl, new, i->idx + 1);
  1924. hostrange_destroy(new);
  1925. i->hr = i->hl->hr[++i->idx];
  1926. i->depth = -1;
  1927. } else if (hostrange_empty(i->hr)) {
  1928. hostlist_delete_range(i->hl, i->idx);
  1929. } else
  1930. i->depth--;
  1931. i->hl->nhosts--;
  1932. UNLOCK_HOSTLIST(i->hl);
  1933. return 1;
  1934. }
  1935. /* ----[ hostset functions ]---- */
  1936. hostset_t hostset_create(const char *hostlist)
  1937. {
  1938. hostset_t new;
  1939. if (!(new = (hostset_t) malloc(sizeof(*new))))
  1940. goto error1;
  1941. if (!(new->hl = hostlist_create(hostlist)))
  1942. goto error2;
  1943. hostlist_uniq(new->hl);
  1944. return new;
  1945. error2:
  1946. free(new);
  1947. error1:
  1948. return NULL;
  1949. }
  1950. hostset_t hostset_copy(const hostset_t set)
  1951. {
  1952. hostset_t new;
  1953. if (!(new = (hostset_t) malloc(sizeof(*new))))
  1954. goto error1;
  1955. if (!(new->hl = hostlist_copy(set->hl)))
  1956. goto error2;
  1957. return new;
  1958. error2:
  1959. free(new);
  1960. error1:
  1961. return NULL;
  1962. }
  1963. void hostset_destroy(hostset_t set)
  1964. {
  1965. if (set == NULL)
  1966. return;
  1967. hostlist_destroy(set->hl);
  1968. free(set);
  1969. }
  1970. /* inserts a single range object into a hostset
  1971. * Assumes that the set->hl lock is already held
  1972. * Updates hl->nhosts
  1973. */
  1974. static int hostset_insert_range(hostset_t set, hostrange_t hr)
  1975. {
  1976. int i = 0;
  1977. int inserted = 0;
  1978. int nhosts = 0;
  1979. int ndups = 0;
  1980. hostlist_t hl;
  1981. hl = set->hl;
  1982. if (hl->size == hl->nranges && !hostlist_expand(hl))
  1983. return 0;
  1984. nhosts = hostrange_count(hr);
  1985. for (i = 0; i < hl->nranges; i++) {
  1986. if (hostrange_cmp(hr, hl->hr[i]) <= 0) {
  1987. if ((ndups = hostrange_join(hr, hl->hr[i])) >= 0)
  1988. hostlist_delete_range(hl, i);
  1989. else if (ndups < 0)
  1990. ndups = 0;
  1991. hostlist_insert_range(hl, hr, i);
  1992. /* now attempt to join hr[i] and hr[i-1] */
  1993. if (i > 0) {
  1994. int m;
  1995. if ((m = _attempt_range_join(hl, i)) > 0)
  1996. ndups += m;
  1997. }
  1998. hl->nhosts += nhosts - ndups;
  1999. inserted = 1;
  2000. break;
  2001. }
  2002. }
  2003. if (inserted == 0) {
  2004. hl->hr[hl->nranges++] = hostrange_copy(hr);
  2005. hl->nhosts += nhosts;
  2006. if (hl->nranges > 1) {
  2007. if ((ndups = _attempt_range_join(hl, hl->nranges - 1)) <= 0)
  2008. ndups = 0;
  2009. }
  2010. }
  2011. /*
  2012. * Return the number of unique hosts inserted
  2013. */
  2014. return nhosts - ndups;
  2015. }
  2016. int hostset_insert(hostset_t set, const char *hosts)
  2017. {
  2018. int i, n = 0;
  2019. hostlist_t hl = hostlist_create(hosts);
  2020. if (!hl)
  2021. return 0;
  2022. hostlist_uniq(hl);
  2023. LOCK_HOSTLIST(set->hl);
  2024. for (i = 0; i < hl->nranges; i++)
  2025. n += hostset_insert_range(set, hl->hr[i]);
  2026. UNLOCK_HOSTLIST(set->hl);
  2027. hostlist_destroy(hl);
  2028. return n;
  2029. }
  2030. /* linear search through N ranges for hostname "host"
  2031. * */
  2032. static int hostset_find_host(hostset_t set, const char *host)
  2033. {
  2034. int i;
  2035. int retval = 0;
  2036. hostname_t