/*~f w_io_result_t w_io_read (w_io_t *stream, void *buffer, size_t count) * * Reads up to `count` bytes from the an input `stream`, placing the data in * in memory starting at `buffer`. * * Passing a `count` of zero always succeeds and has no side effects. * * If reading succeeds, the amount of bytes read may be smaller than the * requested `count`. The reason may be that the end-of-file marker has been * reached (and it will be notified at the next attempt of reading data), or * because no more data is available for reading at the moment. */ w_io_result_t w_io_read (w_io_t *io, void *buf, size_t len) { w_assert (io); w_io_result_t r = W_IO_RESULT (0); if (w_unlikely (len == 0)) return r; w_assert (buf); /* Handle the putback character... makes things a bit messier */ if (w_unlikely (io->backch != W_IO_EOF)) { *((char*) buf) = io->backch; buf = (char*) buf + 1; io->backch = W_IO_EOF; /* Check whether more characters are to be read */ if (!--len) return W_IO_RESULT (1); } if (w_likely (io->read != NULL)) { r = (*io->read) (io, buf, len); } else { r = W_IO_RESULT_ERROR (errno = EBADF); } return r; }
static int _parse_gids (char *s, uidgid_t *u) { char *pos = NULL; gid_t gid; w_assert (s); w_assert (u); if (u->ngid >= DMON_GID_COUNT) { w_printerr ("more than $L groups given, ignoring additional ones\n", DMON_GID_COUNT); return 0; } pos = strchr (s, ':'); if (pos != NULL) *pos = '\0'; if (name_to_gid (s, &gid)) { if (pos != NULL) *pos = ':'; return 1; } if (pos != NULL) *pos = ':'; u->gids[u->ngid++] = gid; return (pos == NULL) ? 0 : _parse_gids (pos + 1, u); }
int name_to_gid (const char *str, gid_t *result) { struct group *grp; unsigned long num; char *dummy; w_assert (str); w_assert (result); num = strtoul (str, &dummy, 0); if (num == ULONG_MAX && errno == ERANGE) return 1; if (!dummy || *dummy == '\0') { *result = (gid_t) num; return 0; } if ((grp = getgrnam (str)) == NULL) return 1; *result = grp->gr_gid; return 0; }
int parse_uidgids (char *s, uidgid_t *u) { char *pos = NULL; w_assert (s); w_assert (u); memset (u, 0x00, sizeof (uidgid_t)); pos = strchr (s, ':'); if (pos != NULL) *pos = '\0'; if (name_to_uidgid (s, &u->uid, &u->gid)) { if (pos != NULL) *pos = ':'; return 1; } if (pos != NULL) *pos = ':'; else return 0; return (pos == NULL) ? 0 : _parse_gids (pos + 1, u); }
static bool _parse_limit_number (const char *sval, long *rval) { w_assert (sval != NULL); w_assert (rval != NULL); return !(sscanf (sval, "%li", rval) == 1); }
bool w_str_time_period (const char *str, unsigned long long *val) { unsigned long long v = 0; char *endpos; w_assert (str); w_assert (val); v = strtoull (str, &endpos, 0); if (v == ULLONG_MAX && errno == ERANGE) return false; if (endpos) { switch (*endpos) { case 'y': v *= 60 * 60 * 24 * 365; break; /* years */ case 'M': v *= 60 * 60 * 24 * 30; break; /* months */ case 'w': v *= 60 * 60 * 24 * 7; break; /* weeks */ case 'd': v *= 60 * 60 * 24; break; /* days */ case 'h': v *= 60 * 60; break; /* hours */ case 'm': v *= 60; break; /* minutes */ case 's': case '\0': break; /* seconds */ default : return false; } } return (*val = v, true); }
bool w_str_size_bytes (const char *str, unsigned long long *val) { unsigned long long v = 0; char *endpos; w_assert (str); w_assert (val); v = strtoull (str, &endpos, 0); if (v == ULLONG_MAX && errno == ERANGE) return false; if (endpos) { switch (*endpos) { case 'g': case 'G': v *= 1024 * 1024 * 1024; break; /* gigabytes */ case 'm': case 'M': v *= 1024 * 1024; break; /* megabytes */ case 'k': case 'K': v *= 1024; break; /* kilobytes */ case 'b': case 'B': case '\0': break; /* bytes */ default : return false; } } return (*val = v, true); }
int parse_limit_arg (const char *str, int *what, long *value) { unsigned i; w_assert (str != NULL); w_assert (what != NULL); w_assert (value != NULL); if (!strcmp (str, "help")) { for (i = 0; i < w_lengthof (rlimit_specs); i++) { w_print ("$s -- $s\n", rlimit_specs[i].name, rlimit_specs[i].desc); } return -1; } for (i = 0; i < w_lengthof (rlimit_specs); i++) { unsigned nlen = strlen (rlimit_specs[i].name); if (!strncmp (str, rlimit_specs[i].name, nlen) && str[nlen] == '=') { *what = rlimit_specs[i].what; return ((*rlimit_specs[i].parse) (str + nlen + 1, value)); } } return 1; }
int name_to_uidgid (const char *str, uid_t *uresult, gid_t *gresult) { struct passwd *pw; unsigned long num; char *dummy; w_assert (str); w_assert (uresult); w_assert (gresult); num = strtoul (str, &dummy, 0); if (num == ULONG_MAX && errno == ERANGE) return 1; if (!dummy || *dummy == '\0') { if ((pw = getpwuid ((uid_t) num)) == NULL) return 1; } else { if ((pw = getpwnam (str)) == NULL) return 1; } *uresult = pw->pw_uid; *gresult = pw->pw_gid; return 0; }
static inline const w_opt_t* _opt_lookup_long (const w_opt_t *opt, const char *str) { w_assert (opt != NULL); w_assert (str != NULL); for (; opt->string != NULL; opt++) if (!strcmp (opt->string, str)) return opt; return NULL; }
static bool _parse_limit_bytes (const char *sval, long *rval) { w_assert (sval != NULL); w_assert (rval != NULL); unsigned long long val; bool failed = w_str_size_bytes (sval, &val); *rval = val; return failed || (val > LONG_MAX); }
int replace_args_string (const char *str, int *pargc, char ***pargv) { int ch; char *s = NULL; int maxarg = REPLACE_ARGS_VCHUNK; int numarg = 0; int quotes = 0; int smax = 0; int slen = 0; char **argv = w_alloc (char*, maxarg); w_assert (str); w_assert (pargc); w_assert (pargv); /* Copy argv[0] pointer */ argv[numarg++] = (*pargv)[0]; while ((ch = *str++) != '\0') { if (!quotes && isspace (ch)) { if (!slen) { /* * Got spaces not inside a quote, and the current argument * is empty: skip spaces at the left side of an argument. */ continue; } /* * Not inside quotes, got space: add '\0', split and reset */ if (numarg >= maxarg) { maxarg += REPLACE_ARGS_VCHUNK; argv = w_resize (argv, char*, maxarg); } /* Add terminating "\0" */ if (slen >= smax) { smax += REPLACE_ARGS_SCHUNK; s = w_resize (s, char, smax); } /* Save string in array. */ s[slen] = '\0'; argv[numarg++] = s; /* Reset stuff */ smax = slen = 0; s = NULL; continue; }
w_io_result_t w_tnetstr_write_buffer (w_io_t *io, const w_buf_t *value) { w_assert (io); w_assert (value); if (w_unlikely (w_buf_size (value) > _W_TNS_MAX_PAYLOAD)) return W_IO_RESULT_ERROR (EINVAL); return w_io_format (io, "$L:$B,", w_buf_size (value), value); }
w_io_result_t w_tnetstr_write_string (w_io_t *io, const char *value) { w_assert (io); w_assert (value); size_t len = strlen (value); if (w_unlikely ((len) > _W_TNS_MAX_PAYLOAD)) return W_IO_RESULT_ERROR (EINVAL); return w_io_format (io, "$L:$S,", len, len, value); }
static w_opt_status_t _config_option (const w_opt_context_t *ctx) { w_assert (ctx); w_assert (ctx->argv); w_assert (ctx->argv[0]); w_printerr ("$s: Option --config/-C must be the first one specified\n", ctx->argv[0]); return W_OPT_EXIT_FAIL; }
w_opt_status_t W_OPT_TIME_PERIOD (const w_opt_context_t *ctx) { w_assert (ctx); w_assert (ctx->option); w_assert (ctx->option->extra); w_assert (ctx->option->narg == 1); return (!w_str_time_period (ctx->argument[0], ctx->option->extra)) ? W_OPT_BAD_ARG : W_OPT_OK; }
w_opt_status_t W_OPT_DATA_SIZE (const w_opt_context_t *ctx) { w_assert (ctx); w_assert (ctx->option); w_assert (ctx->option->extra); w_assert (ctx->option->narg == 1); return (!w_str_size_bytes (ctx->argument[0], ctx->option->extra)) ? W_OPT_BAD_ARG : W_OPT_OK; }
/*~f w_io_result_t w_io_format (w_io_t *stream, const char *format, ...) * * Writes data with a given `format` to an output `stream`. * The amount of consumed arguments depends on the `format` string. * * See :ref:`formatted-output` for more information. */ w_io_result_t w_io_format (w_io_t *io, const char *fmt, ...) { w_assert (io); w_assert (fmt); va_list args; va_start (args, fmt); w_io_result_t r = w_io_formatv (io, fmt, args); va_end (args); return r; }
static w_opt_status_t _store_uidgids_option (const w_opt_context_t *ctx) { w_assert (ctx); w_assert (ctx->userdata); w_assert (ctx->argument); w_assert (ctx->argument[0]); return (parse_uidgids (ctx->argument[0], ctx->option->extra)) ? W_OPT_BAD_ARG : W_OPT_OK; }
w_io_result_t w_tnetstr_dump_string (w_buf_t *buffer, const char *value) { w_assert (buffer); w_assert (value); size_t len = strlen (value); if (w_unlikely (len > _W_TNS_MAX_PAYLOAD)) return W_IO_RESULT_ERROR (EINVAL); return w_buf_format (buffer, "$L:$S,", len, len, value); }
bool w_str_float(const char *str, float *val) { float v; char *chkstr; w_assert(str != NULL); w_assert(val != NULL); v = strtof(str, &chkstr); if (((v == HUGE_VALF) || (v == -HUGE_VALF)) && (errno == ERANGE)) return false; return (*val = v, true); }
w_io_result_t w_tnetstr_dump_list (w_buf_t *buffer, const w_list_t *value) { w_assert (buffer); w_assert (value); w_buf_t buf = W_BUF; w_io_result_t r; w_list_foreach (item, value) { r = w_tnetstr_dump (&buf, (w_variant_t*) *item); if (w_unlikely (w_io_failed (r))) break; }
bool w_str_double(const char *str, double *val) { double v; char *chkstr; w_assert(str != NULL); w_assert(val != NULL); v = strtod(str, &chkstr); if (((v == HUGE_VAL) || (v == -HUGE_VAL)) && (errno == ERANGE)) return false; return (*val = v, true); }
/* * This one goes for simple string assignment. Note that memory may be * leaked, as a copy of the arguments is made. It's up to the programmer * taking care of freeing that. */ w_opt_status_t W_OPT_STRING (const w_opt_context_t *context) { unsigned i; w_assert (context != NULL); w_assert (context->option != NULL); w_assert (context->option->narg > 0); w_assert (context->option->extra != NULL); for (i = 0; i < context->option->narg; i++) ((char**) context->option->extra)[i] = w_str_dup (context->argument[i]); return W_OPT_OK; }
bool w_str_long(const char *str, long *val) { long v; char *chkstr; w_assert(str != NULL); w_assert(val != NULL); v = strtol(str, &chkstr, 0); if ((*str != '\0') && (*chkstr == '\0') && !((v == LONG_MAX || v == LONG_MIN) && (errno == ERANGE))) return (*val = v, true); return false; }
bool w_str_ulong(const char *str, unsigned long *val) { unsigned long v; char *chkstr; w_assert(str != NULL); w_assert(val != NULL); v = strtoul(str, &chkstr, 0); if ((*str != '\0') && (*chkstr == '\0') && !(v == ULONG_MAX && errno == ERANGE)) return (*val = v, true); return false; }
/*~f void w_io_mem_init (w_io_mem_t *stream, uint8_t *address, size_t size) * * Initializes a `stream` object (possibly located in the stack) to be used * with a region of memory of a given `size` located at `address`. */ void w_io_mem_init (w_io_mem_t *io, uint8_t *data, size_t size) { w_assert (io); w_assert (data); w_io_init ((w_io_t*) io); io->parent.close = w_io_mem_close; io->parent.write = w_io_mem_write; io->parent.read = w_io_mem_read; io->data = data; io->size = size; io->pos = 0; }
ssize_t w_io_fscan (w_io_t *io, const char *fmt, ...) { ssize_t ret; va_list args; w_assert (io); w_assert (fmt); va_start (args, fmt); ret = w_io_fscanv (io, fmt, args); va_end (args); return ret; }
static inline const w_opt_t* _opt_lookup_fuzz (const w_opt_t *opt, const char *str, const char *prg) { size_t len; const w_opt_t *ret; w_assert (opt != NULL); w_assert (str != NULL); w_assert (prg != NULL); len = strlen (str); for (; opt->string != NULL; opt++) if (!strncmp (opt->string, str, len)) break; if (opt->string == NULL) return NULL; ret = opt++; /* Check wether the option string is not ambiguous. */ for (; opt->string != NULL; opt++) if (!strncmp (opt->string, str, len)) break; /* If we reach the end, no other prefix is equal -> ok. */ if (opt->string == NULL) return ret; /* ...otherwise, we are in trouble. */ W_IO_NORESULT (w_io_format (w_stderr, "$s: option '$s' is ambiguous, possibilities:\n", prg, str)); for (; ret->string != NULL; ret++) { if (!strncmp (ret->string, str, len)) { W_IO_NORESULT (w_io_format (w_stderr, " --$s\n", ret->string)); } } W_IO_NORESULT (w_io_format (w_stderr, "Hint: try '$s --help'\n", prg)); exit (EXIT_FAILURE); return NULL; /* Never reached -- but keeps compiler happy =) */ }
/*~f w_io_result_t w_io_putchar (w_io_t *stream, int character) * * Writes a `character` to an output `stream`. */ w_io_result_t w_io_putchar (w_io_t *io, int ch) { w_assert (io); char bch = ch; return w_io_write (io, &bch, 1); }