int uu_check_name(const char *name, uint32_t flags) { const char *end = name + strlen(name); const char *p; if (flags & ~(UU_NAME_DOMAIN | UU_NAME_PATH)) { uu_set_error(UU_ERROR_UNKNOWN_FLAG); return (-1); } if (!(flags & UU_NAME_PATH)) { if (!is_valid_component(name, end, flags)) goto bad; return (0); } while ((p = strchr(name, '/')) != NULL) { if (!is_valid_component(name, p - 1, flags)) goto bad; name = p + 1; } if (!is_valid_component(name, end, flags)) goto bad; return (0); bad: uu_set_error(UU_ERROR_INVALID_ARGUMENT); return (-1); }
uu_list_t * uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags) { uu_list_t *lp, *next, *prev; if (flags & ~(UU_LIST_DEBUG | UU_LIST_SORTED)) { uu_set_error(UU_ERROR_UNKNOWN_FLAG); return (NULL); } if ((flags & UU_LIST_SORTED) && pp->ulp_cmp == NULL) { if (pp->ulp_debug) uu_panic("uu_list_create(%p, ...): requested " "UU_LIST_SORTED, but pool has no comparison func\n", (void *)pp); uu_set_error(UU_ERROR_NOT_SUPPORTED); return (NULL); } lp = uu_zalloc(sizeof (*lp)); if (lp == NULL) { uu_set_error(UU_ERROR_NO_MEMORY); return (NULL); } lp->ul_pool = pp; lp->ul_parent_enc = UU_PTR_ENCODE(parent); lp->ul_offset = pp->ulp_nodeoffset; lp->ul_debug = pp->ulp_debug || (flags & UU_LIST_DEBUG); lp->ul_sorted = (flags & UU_LIST_SORTED); lp->ul_numnodes = 0; lp->ul_index = (pp->ulp_last_index = INDEX_NEXT(pp->ulp_last_index)); lp->ul_null_node.uln_next = &lp->ul_null_node; lp->ul_null_node.uln_prev = &lp->ul_null_node; lp->ul_null_walk.ulw_next = &lp->ul_null_walk; lp->ul_null_walk.ulw_prev = &lp->ul_null_walk; (void) pthread_mutex_lock(&pp->ulp_lock); next = &pp->ulp_null_list; prev = UU_PTR_DECODE(next->ul_prev_enc); lp->ul_next_enc = UU_PTR_ENCODE(next); lp->ul_prev_enc = UU_PTR_ENCODE(prev); next->ul_prev_enc = UU_PTR_ENCODE(lp); prev->ul_next_enc = UU_PTR_ENCODE(lp); (void) pthread_mutex_unlock(&pp->ulp_lock); return (lp); }
uu_dprintf_t * uu_dprintf_create(const char *name, uu_dprintf_severity_t severity, uint_t flags) { uu_dprintf_t *D; if (uu_check_name(name, UU_NAME_DOMAIN) == -1) { uu_set_error(UU_ERROR_INVALID_ARGUMENT); return (NULL); } if ((D = uu_zalloc(sizeof (uu_dprintf_t))) == NULL) return (NULL); if (name != NULL) { D->uud_name = strdup(name); if (D->uud_name == NULL) { uu_free(D); return (NULL); } } else { D->uud_name = NULL; } D->uud_severity = severity; D->uud_flags = flags; return (D); }
uu_avl_pool_t * uu_avl_pool_create(const char *name, size_t objsize, size_t nodeoffset, uu_compare_fn_t *compare_func, uint32_t flags) { uu_avl_pool_t *pp, *next, *prev; if (name == NULL || uu_check_name(name, UU_NAME_DOMAIN) == -1 || nodeoffset + sizeof (uu_avl_node_t) > objsize || compare_func == NULL) { uu_set_error(UU_ERROR_INVALID_ARGUMENT); return (NULL); } if (flags & ~UU_AVL_POOL_DEBUG) { uu_set_error(UU_ERROR_UNKNOWN_FLAG); return (NULL); } pp = uu_zalloc(sizeof (uu_avl_pool_t)); if (pp == NULL) { uu_set_error(UU_ERROR_NO_MEMORY); return (NULL); } (void) strlcpy(pp->uap_name, name, sizeof (pp->uap_name)); pp->uap_nodeoffset = nodeoffset; pp->uap_objsize = objsize; pp->uap_cmp = compare_func; if (flags & UU_AVL_POOL_DEBUG) pp->uap_debug = 1; pp->uap_last_index = 0; (void) pthread_mutex_init(&pp->uap_lock, NULL); pp->uap_null_avl.ua_next_enc = UU_PTR_ENCODE(&pp->uap_null_avl); pp->uap_null_avl.ua_prev_enc = UU_PTR_ENCODE(&pp->uap_null_avl); (void) pthread_mutex_lock(&uu_apool_list_lock); pp->uap_next = next = &uu_null_apool; pp->uap_prev = prev = next->uap_prev; next->uap_prev = pp; prev->uap_next = pp; (void) pthread_mutex_unlock(&uu_apool_list_lock); return (pp); }
uu_avl_walk_t * uu_avl_walk_start(uu_avl_t *ap, uint32_t flags) { uu_avl_walk_t *wp; if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) { uu_set_error(UU_ERROR_UNKNOWN_FLAG); return (NULL); } wp = uu_zalloc(sizeof (*wp)); if (wp == NULL) { uu_set_error(UU_ERROR_NO_MEMORY); return (NULL); } _avl_walk_init(wp, ap, flags); return (wp); }
uu_avl_t * uu_avl_create(uu_avl_pool_t *pp, void *parent, uint32_t flags) { uu_avl_t *ap, *next, *prev; if (flags & ~UU_AVL_DEBUG) { uu_set_error(UU_ERROR_UNKNOWN_FLAG); return (NULL); } ap = uu_zalloc(sizeof (*ap)); if (ap == NULL) { uu_set_error(UU_ERROR_NO_MEMORY); return (NULL); } ap->ua_pool = pp; ap->ua_parent_enc = UU_PTR_ENCODE(parent); ap->ua_debug = pp->uap_debug || (flags & UU_AVL_DEBUG); ap->ua_index = (pp->uap_last_index = INDEX_NEXT(pp->uap_last_index)); avl_create(&ap->ua_tree, &uu_avl_node_compare, pp->uap_objsize, pp->uap_nodeoffset); ap->ua_null_walk.uaw_next = &ap->ua_null_walk; ap->ua_null_walk.uaw_prev = &ap->ua_null_walk; (void) pthread_mutex_lock(&pp->uap_lock); next = &pp->uap_null_avl; prev = UU_PTR_DECODE(next->ua_prev_enc); ap->ua_next_enc = UU_PTR_ENCODE(next); ap->ua_prev_enc = UU_PTR_ENCODE(prev); next->ua_prev_enc = UU_PTR_ENCODE(ap); prev->ua_next_enc = UU_PTR_ENCODE(ap); (void) pthread_mutex_unlock(&pp->uap_lock); return (ap); }
static int strtoint(const char *s_arg, uint64_t *out, uint32_t base, int sign) { const unsigned char *s = (const unsigned char *)s_arg; uint64_t val = 0; uint64_t multmax; unsigned c, i; int neg = 0; int bad_digit = 0; int bad_char = 0; int overflow = 0; if (s == NULL || base == 1 || base > MAX_BASE) { uu_set_error(UU_ERROR_INVALID_ARGUMENT); return (-1); } while ((c = *s) != 0 && isspace(c)) s++; switch (c) { case '-': if (!sign) overflow = 1; /* becomes underflow below */ neg = 1; /*FALLTHRU*/ case '+': c = *++s; break; default: break; } if (c == '\0') { uu_set_error(UU_ERROR_EMPTY); return (-1); } if (base == 0) { if (c != '0') base = 10; else if (s[1] == 'x' || s[1] == 'X') base = 16; else base = 8; } if (base == 16 && c == '0' && (s[1] == 'x' || s[1] == 'X')) c = *(s += 2); if ((val = CTOI(c)) >= base) { if (IS_DIGIT(c)) bad_digit = 1; else bad_char = 1; val = 0; } multmax = (uint64_t)UINT64_MAX / (uint64_t)base; for (c = *++s; c != '\0'; c = *++s) { if ((i = CTOI(c)) >= base) { if (isspace(c)) break; if (IS_DIGIT(c)) bad_digit = 1; else bad_char = 1; i = 0; } if (val > multmax) overflow = 1; val *= base; if ((uint64_t)UINT64_MAX - val < (uint64_t)i) overflow = 1; val += i; } while ((c = *s) != 0) { if (!isspace(c)) bad_char = 1; s++; } if (sign) { if (neg) { if (val > -(uint64_t)INT64_MIN) overflow = 1; } else { if (val > INT64_MAX) overflow = 1; } } if (neg) val = -val; if (bad_char | bad_digit | overflow) { if (bad_char) uu_set_error(UU_ERROR_INVALID_CHAR); else if (bad_digit) uu_set_error(UU_ERROR_INVALID_DIGIT); else if (overflow) { if (neg) uu_set_error(UU_ERROR_UNDERFLOW); else uu_set_error(UU_ERROR_OVERFLOW); } return (-1); } *out = val; return (0); }
int uu_strtouint(const char *s, void *v, size_t sz, int base, uint64_t min, uint64_t max) { uint64_t val; if (min > max) goto bad_argument; switch (sz) { case 1: if (max > UINT8_MAX) goto bad_argument; break; case 2: if (max > UINT16_MAX) goto bad_argument; break; case 4: if (max > UINT32_MAX) goto bad_argument; break; case 8: if (max > UINT64_MAX) goto bad_argument; break; default: goto bad_argument; } if (min == 0 && max == 0) { /* we have to be careful, since << can overflow */ max = (1ULL << (8 * sz - 1)) * 2 - 1; } if (strtoint(s, &val, base, 0) == -1) return (-1); if (val < min) { uu_set_error(UU_ERROR_UNDERFLOW); return (-1); } else if (val > max) { uu_set_error(UU_ERROR_OVERFLOW); return (-1); } switch (sz) { case 1: *(uint8_t *)v = val; return (0); case 2: *(uint16_t *)v = val; return (0); case 4: *(uint32_t *)v = val; return (0); case 8: *(uint64_t *)v = val; return (0); default: break; /* shouldn't happen, fall through */ } bad_argument: uu_set_error(UU_ERROR_INVALID_ARGUMENT); return (-1); }
int uu_strtoint(const char *s, void *v, size_t sz, int base, int64_t min, int64_t max) { uint64_t val_u; int64_t val; if (min > max) goto bad_argument; switch (sz) { case 1: if (max > INT8_MAX || min < INT8_MIN) goto bad_argument; break; case 2: if (max > INT16_MAX || min < INT16_MIN) goto bad_argument; break; case 4: if (max > INT32_MAX || min < INT32_MIN) goto bad_argument; break; case 8: if (max > INT64_MAX || min < INT64_MIN) goto bad_argument; break; default: goto bad_argument; } if (min == 0 && max == 0) { min = -(1ULL << (8 * sz - 1)); max = (1ULL << (8 * sz - 1)) - 1; } if (strtoint(s, &val_u, base, 1) == -1) return (-1); val = (int64_t)val_u; if (val < min) { uu_set_error(UU_ERROR_UNDERFLOW); return (-1); } else if (val > max) { uu_set_error(UU_ERROR_OVERFLOW); return (-1); } switch (sz) { case 1: *(int8_t *)v = val; return (0); case 2: *(int16_t *)v = val; return (0); case 4: *(int32_t *)v = val; return (0); case 8: *(int64_t *)v = val; return (0); default: break; /* fall through to bad_argument */ } bad_argument: uu_set_error(UU_ERROR_INVALID_ARGUMENT); return (-1); }