diff options
Diffstat (limited to 'src/libmowgli/ext')
-rw-r--r-- | src/libmowgli/ext/Makefile | 25 | ||||
-rw-r--r-- | src/libmowgli/ext/confparse.c | 436 | ||||
-rw-r--r-- | src/libmowgli/ext/confparse.h | 45 | ||||
-rw-r--r-- | src/libmowgli/ext/error_backtrace.c | 109 | ||||
-rw-r--r-- | src/libmowgli/ext/error_backtrace.h | 38 | ||||
-rw-r--r-- | src/libmowgli/ext/getopt_long.c | 461 | ||||
-rw-r--r-- | src/libmowgli/ext/getopt_long.h | 69 | ||||
-rw-r--r-- | src/libmowgli/ext/global_storage.c | 69 | ||||
-rw-r--r-- | src/libmowgli/ext/global_storage.h | 32 | ||||
-rw-r--r-- | src/libmowgli/ext/proctitle.c | 311 | ||||
-rw-r--r-- | src/libmowgli/ext/proctitle.h | 23 | ||||
-rw-r--r-- | src/libmowgli/ext/program_opts.c | 191 | ||||
-rw-r--r-- | src/libmowgli/ext/program_opts.h | 50 |
13 files changed, 1859 insertions, 0 deletions
diff --git a/src/libmowgli/ext/Makefile b/src/libmowgli/ext/Makefile new file mode 100644 index 0000000..d7466b6 --- /dev/null +++ b/src/libmowgli/ext/Makefile @@ -0,0 +1,25 @@ +include ../../../extra.mk + +STATIC_PIC_LIB_NOINST = ${LIBMOWGLI_SHARED_EXT} +STATIC_LIB_NOINST = ${LIBMOWGLI_STATIC_EXT} + +SRCS = confparse.c \ + error_backtrace.c \ + getopt_long.c \ + global_storage.c \ + program_opts.c \ + proctitle.c + +INCLUDES = confparse.h \ + error_backtrace.h \ + getopt_long.h \ + global_storage.h \ + program_opts.h \ + proctitle.h + +include ../../../buildsys.mk + +includesubdir = $(PACKAGE_NAME)/ext + +CPPFLAGS += -I. -I.. -I../../.. -DMOWGLI_CORE + diff --git a/src/libmowgli/ext/confparse.c b/src/libmowgli/ext/confparse.c new file mode 100644 index 0000000..898ba8c --- /dev/null +++ b/src/libmowgli/ext/confparse.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2005-2011 Atheme Project (http://www.atheme.org) + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Description of config files parsed by this: + * + * configfile = *WS *configentry + * configentry = value [1*WS value] [1*WS "{" *(configentry 1*WS) "}" ] *WS ";" + * value = 1*achar / DQUOTE *qchar DQUOTE + * achar = <any CHAR except WS or DQUOTE> + * qchar = <any CHAR except DQUOTE or \> / "\\" / "\" DQUOTE + * comment = "/" "*" <anything except * /> "*" "/" / + * "#" *CHAR %0x0A / + * "//" *CHAR %0x0A + * WS = %x09 / %x0A / %x0D / SPACE / "=" / comment + * + * A value of "include" for toplevel configentries causes a file to be + * included. The included file is logically appended to the current file, + * no matter where the include directive is. Include files must have balanced + * braces. + */ +/* + * Original idea from the csircd config parser written by Fred Jacobs + * and Chris Behrens. + */ + +#include "mowgli.h" +#include <sys/stat.h> +#include <limits.h> + +#define MAX_INCLUDE_NESTING 16 + +static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char *confdata); +static void mowgli_config_file_entry_free(mowgli_config_file_entry_t *ceptr); +static mowgli_config_file_t *mowgli_config_file_load_internal(mowgli_config_file_t *parent, const char *filename); + +#define CF_ERRORED(cf) ((cf)->curline <= 0) + +static void mowgli_config_file_error(mowgli_config_file_t *cf, const char *format, ...) +{ + va_list ap; + char buffer[1024]; + char *ptr; + + va_start(ap, format); + vsnprintf(buffer, sizeof buffer, format, ap); + va_end(ap); + + if ((ptr = strchr(buffer, '\n')) != NULL) + *ptr = '\0'; + + if (cf != NULL) + { + if (cf->curline < 0) + cf->curline = -cf->curline; + + mowgli_log("%s:%d: %s", cf->filename, cf->curline, buffer); + + /* mark config parse as failed */ + cf->curline = -cf->curline; + } + else + mowgli_log("mowgli_config_file_parse(): %s", buffer); +} + +static void skip_ws(char **pos, mowgli_config_file_t *cf) +{ + int startline; + + for (;;) + { + switch (**pos) + { + case ' ': + case '\t': + case '\r': + case '=': /* XXX */ + break; + case '\n': + cf->curline++; + break; + case '/': + if ((*pos)[1] == '*') + { + startline = cf->curline; + (*pos)++; + (*pos)++; + while (**pos != '\0' && (**pos != '*' || (*pos)[1] != '/')) + { + if (**pos == '\n') + cf->curline++; + (*pos)++; + } + if (**pos == '\0') + mowgli_config_file_error(cf, "File ends inside comment starting at line %d", startline); + else + (*pos)++; /* skip '*' */ + } + else if ((*pos)[1] == '/') + { + while (**pos != '\0' && **pos != '\n' && **pos != '\r') + (*pos)++; + continue; + } + else + return; + break; + case '#': + while (**pos != '\0' && **pos != '\n' && **pos != '\r') + (*pos)++; + continue; + default: + return; + } + if (**pos == '\0') + return; + (*pos)++; + } +} + +static char *get_value(char **pos, mowgli_config_file_t *cf, char *skipped) +{ + char *p = *pos; + char *q; + char *start; + + *skipped = '\0'; + if (*p == '"') + { + p++; + start = p; + q = p; + while (*p != '\0' && *p != '\r' && *p != '\n' && *p != '"') + { + if (*p == '\\' && (p[1] == '"' || p[1] == '\\')) + p++; + *q++ = *p++; + } + if (*p == '\0') + { + mowgli_config_file_error(cf, "File ends inside quoted string"); + return NULL; + } + if (*p == '\r' || *p == '\n') + { + mowgli_config_file_error(cf, "Newline inside quoted string"); + return NULL; + } + if (*p != '"') + { + mowgli_config_file_error(cf, "Weird character terminating quoted string (BUG)"); + return NULL; + } + p++; + *q = '\0'; + *pos = p; + skip_ws(pos, cf); + return start; + } + else + { + start = p; + while (*p != '\0' && *p != '\t' && *p != '\r' && *p != '\n' && + *p != ' ' && *p != '/' && *p != '#' && + *p != ';' && *p != '{' && *p != '}') + p++; + if (p == start) + return NULL; + *pos = p; + skip_ws(pos, cf); + if (p == *pos) + *skipped = *p; + *p = '\0'; + if (p == *pos) + (*pos)++; + return start; + } +} + +static mowgli_config_file_t *mowgli_config_file_parse(const char *filename, char *confdata) +{ + mowgli_config_file_t *cf, *subcf, *lastcf; + mowgli_config_file_entry_t **pprevce, *ce, *upce; + char *p, *val; + char c; + + cf = mowgli_alloc(sizeof *cf); + cf->filename = mowgli_strdup(filename); + cf->curline = 1; + cf->mem = confdata; + lastcf = cf; + pprevce = &cf->entries; + upce = NULL; + p = confdata; + while (*p != '\0') + { + skip_ws(&p, cf); + if (*p == '\0' || CF_ERRORED(cf)) + break; + if (*p == '}') + { + if (upce == NULL) + { + mowgli_config_file_error(cf, "Extraneous closing brace"); + break; + } + ce = upce; + ce->sectlinenum = cf->curline; + pprevce = &ce->next; + upce = ce->prevlevel; + p++; + skip_ws(&p, cf); + if (CF_ERRORED(cf)) + break; + if (*p != ';') + { + mowgli_config_file_error(cf, "Missing semicolon after closing brace for section ending at line %d", ce->sectlinenum); + break; + } + ce = NULL; + p++; + continue; + } + val = get_value(&p, cf, &c); + if (CF_ERRORED(cf)) + break; + if (val == NULL) + { + mowgli_config_file_error(cf, "Unexpected character trying to read variable name"); + break; + } + ce = mowgli_alloc(sizeof *ce); + ce->fileptr = cf; + ce->varlinenum = cf->curline; + ce->varname = val; + ce->prevlevel = upce; + *pprevce = ce; + pprevce = &ce->next; + if (c == '\0' && (*p == '{' || *p == ';')) + c = *p++; + if (c == '{') + { + pprevce = &ce->entries; + upce = ce; + ce = NULL; + } + else if (c == ';') + { + ce = NULL; + } + else if (c != '\0') + { + mowgli_config_file_error(cf, "Unexpected characters after unquoted string %s", ce->varname); + break; + } + else + { + val = get_value(&p, cf, &c); + if (CF_ERRORED(cf)) + break; + if (val == NULL) + { + mowgli_config_file_error(cf, "Unexpected character trying to read value for %s", ce->varname); + break; + } + ce->vardata = val; + if (c == '\0' && (*p == '{' || *p == ';')) + c = *p++; + if (c == '{') + { + pprevce = &ce->entries; + upce = ce; + ce = NULL; + } + else if (c == ';') + { + if (upce == NULL && !strcasecmp(ce->varname, "include")) + { + subcf = mowgli_config_file_load_internal(cf, ce->vardata); + if (subcf == NULL) + { + mowgli_config_file_error(cf, "Error in file included from here"); + break; + } + lastcf->next = subcf; + while (lastcf->next != NULL) + lastcf = lastcf->next; + } + ce = NULL; + } + else + { + mowgli_config_file_error(cf, "Unexpected characters after value %s %s", ce->varname, ce->vardata); + break; + } + } + } + if (!CF_ERRORED(cf) && upce != NULL) + { + mowgli_config_file_error(cf, "One or more sections not closed"); + ce = upce; + while (ce->prevlevel != NULL) + ce = ce->prevlevel; + if (ce->vardata != NULL) + mowgli_config_file_error(cf, "First unclosed section is %s %s at line %d", + ce->varname, ce->vardata, ce->varlinenum); + else + mowgli_config_file_error(cf, "First unclosed section is %s at line %d", + ce->varname, ce->varlinenum); + } + if (CF_ERRORED(cf)) + { + mowgli_config_file_free(cf); + cf = NULL; + } + return cf; +} + +static void mowgli_config_file_entry_free(mowgli_config_file_entry_t *ceptr) +{ + mowgli_config_file_entry_t *nptr; + + for (; ceptr; ceptr = nptr) + { + nptr = ceptr->next; + if (ceptr->entries) + mowgli_config_file_entry_free(ceptr->entries); + /* ce_varname and ce_vardata are inside cf_mem */ + mowgli_free(ceptr); + } +} + +void mowgli_config_file_free(mowgli_config_file_t *cfptr) +{ + mowgli_config_file_t *nptr; + + for (; cfptr; cfptr = nptr) + { + nptr = cfptr->next; + if (cfptr->entries) + mowgli_config_file_entry_free(cfptr->entries); + mowgli_free(cfptr->filename); + mowgli_free(cfptr->mem); + mowgli_free(cfptr); + } +} + +static mowgli_config_file_t *mowgli_config_file_load_internal(mowgli_config_file_t *parent, const char *filename) +{ + struct stat sb; + FILE *fp; + size_t ret; + char *buf = NULL; + mowgli_config_file_t *cfptr; + static int nestcnt; + + if (nestcnt > MAX_INCLUDE_NESTING) + { + mowgli_config_file_error(parent, "Includes nested too deep \"%s\"\n", filename); + return NULL; + } + + fp = fopen(filename, "rb"); + if (!fp) + { + mowgli_config_file_error(parent, "Couldn't open \"%s\": %s\n", filename, strerror(errno)); + return NULL; + } + if (stat(filename, &sb) == -1) + { + mowgli_config_file_error(parent, "Couldn't fstat \"%s\": %s\n", filename, strerror(errno)); + fclose(fp); + return NULL; + } + if (!S_ISREG(sb.st_mode)) + { + mowgli_config_file_error(parent, "Not a regular file: \"%s\"\n", filename); + fclose(fp); + return NULL; + } + if (sb.st_size > SSIZE_MAX - 1) + { + mowgli_config_file_error(parent, "File too large: \"%s\"\n", filename); + fclose(fp); + return NULL; + } + buf = (char *) mowgli_alloc(sb.st_size + 1); + if (sb.st_size) + { + errno = 0; + ret = fread(buf, 1, sb.st_size, fp); + if (ret != (size_t)sb.st_size) + { + mowgli_config_file_error(parent, "Error reading \"%s\": %s\n", filename, strerror(errno ? errno : EFAULT)); + mowgli_free(buf); + fclose(fp); + return NULL; + } + } + else + ret = 0; + buf[ret] = '\0'; + fclose(fp); + nestcnt++; + cfptr = mowgli_config_file_parse(filename, buf); + nestcnt--; + /* buf is owned by cfptr or freed now */ + return cfptr; +} + +mowgli_config_file_t *mowgli_config_file_load(const char *filename) +{ + return mowgli_config_file_load_internal(NULL, filename); +} + +/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs + * vim:ts=8 + * vim:sw=8 + * vim:noexpandtab + */ diff --git a/src/libmowgli/ext/confparse.h b/src/libmowgli/ext/confparse.h new file mode 100644 index 0000000..d498b87 --- /dev/null +++ b/src/libmowgli/ext/confparse.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2005-2008 William Pitcock, et al. + * Rights to this code are as documented in doc/LICENSE. + * + * Config file parser. + * + */ + +#ifndef CONFPARSE_H +#define CONFPARSE_H + +typedef struct _mowgli_configfile mowgli_config_file_t; +typedef struct _mowgli_configentry mowgli_config_file_entry_t; + +struct _mowgli_configfile +{ + char *filename; + mowgli_config_file_entry_t *entries; + mowgli_config_file_t *next; + int curline; + char *mem; +}; + +struct _mowgli_configentry +{ + mowgli_config_file_t *fileptr; + + int varlinenum; + char *varname; + char *vardata; + int sectlinenum; /* line containing closing brace */ + + mowgli_config_file_entry_t *entries; + mowgli_config_file_entry_t *prevlevel; + mowgli_config_file_entry_t *next; +}; + +/* confp.c */ +extern void mowgli_config_file_free(mowgli_config_file_t *cfptr); +extern mowgli_config_file_t *mowgli_config_file_load(const char *filename); + +#endif + +/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs ts=8 sw=8 noexpandtab + */ diff --git a/src/libmowgli/ext/error_backtrace.c b/src/libmowgli/ext/error_backtrace.c new file mode 100644 index 0000000..6c28c22 --- /dev/null +++ b/src/libmowgli/ext/error_backtrace.c @@ -0,0 +1,109 @@ +/* + * libmowgli: A collection of useful routines for programming. + * error_backtrace.c: Print errors and explain how they were reached. + * + * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +void +mowgli_error_context_display(mowgli_error_context_t *e, const char *delim) +{ + mowgli_node_t *n; + char *bt_msg; + + return_if_fail(e != NULL); + return_if_fail(delim != NULL); + + if (MOWGLI_LIST_LENGTH(&e->bt) == 0) + mowgli_throw_exception(mowgli.error_backtrace.no_backtrace); + + MOWGLI_LIST_FOREACH(n, e->bt.head) + { + bt_msg = (char *) n->data; + + fprintf(stderr, "%s%s", bt_msg, n->next != NULL ? delim : "\n"); + } +} + +void +mowgli_error_context_destroy(mowgli_error_context_t *e) +{ + mowgli_node_t *n, *tn; + + return_if_fail(e != NULL); + + if (MOWGLI_LIST_LENGTH(&e->bt) == 0) + { + mowgli_free(e); + return; + } + + MOWGLI_LIST_FOREACH_SAFE(n, tn, e->bt.head) + { + mowgli_free(n->data); + + mowgli_node_delete(n, &e->bt); + mowgli_node_free(n); + } + + mowgli_free(e); +} + +void +mowgli_error_context_display_with_error(mowgli_error_context_t *e, const char *delim, const char *error) +{ + mowgli_error_context_display(e, delim); + fprintf(stderr, "Error: %s\n", error); + + _exit(EXIT_FAILURE); +} + +void +mowgli_error_context_push(mowgli_error_context_t *e, const char *msg, ...) +{ + char buf[65535]; + va_list va; + + return_if_fail(e != NULL); + return_if_fail(msg != NULL); + + va_start(va, msg); + vsnprintf(buf, 65535, msg, va); + va_end(va); + + mowgli_node_add(mowgli_strdup(buf), mowgli_node_create(), &e->bt); +} + +void +mowgli_error_context_pop(mowgli_error_context_t *e) +{ + return_if_fail(e != NULL); + + mowgli_node_delete(e->bt.tail, &e->bt); +} + +mowgli_error_context_t * +mowgli_error_context_create(void) +{ + mowgli_error_context_t *out = (mowgli_error_context_t *) mowgli_alloc(sizeof(mowgli_error_context_t)); + + return out; +} diff --git a/src/libmowgli/ext/error_backtrace.h b/src/libmowgli/ext/error_backtrace.h new file mode 100644 index 0000000..d7da7cf --- /dev/null +++ b/src/libmowgli/ext/error_backtrace.h @@ -0,0 +1,38 @@ +/* + * libmowgli: A collection of useful routines for programming. + * error_backtrace.h: Print errors and explain how they were reached. + * + * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_ERROR_BACKTRACE_H__ +#define __MOWGLI_ERROR_BACKTRACE_H__ + +typedef struct mowgli_error_context_ { + mowgli_list_t bt; +} mowgli_error_context_t; + +extern void mowgli_error_context_display(mowgli_error_context_t *e, const char *delim); +extern void mowgli_error_context_display_with_error(mowgli_error_context_t *e, const char *delim, const char *error); +extern void mowgli_error_context_destroy(mowgli_error_context_t *e); +extern void mowgli_error_context_push(mowgli_error_context_t *e, const char *msg, ...); +extern void mowgli_error_context_pop(mowgli_error_context_t *e); +extern mowgli_error_context_t *mowgli_error_context_create(void); + +#endif diff --git a/src/libmowgli/ext/getopt_long.c b/src/libmowgli/ext/getopt_long.c new file mode 100644 index 0000000..adf64e5 --- /dev/null +++ b/src/libmowgli/ext/getopt_long.c @@ -0,0 +1,461 @@ +/* $NetBSD: getopt_long.c,v 1.25 2009/03/20 14:05:54 joerg Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <mowgli.h> + +#include "getopt_long.h" + +int mowgli_opterr = 1; /* if error message should be printed */ +int mowgli_optind = 1; /* index into parent argv vector */ +int mowgli_optopt = '?'; /* character checked for validity */ +int mowgli_optreset = 0; /* reset getopt */ +char *mowgli_optarg = NULL; /* argument associated with option */ + +/* XXX: suppress const warnings */ +#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) + +#define IGNORE_FIRST (*options == '-' || *options == '+') +#define PRINT_ERROR ((mowgli_opterr) && ((*options != ':') \ + || (IGNORE_FIRST && options[1] != ':'))) +#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) +#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) +/* XXX: GNU ignores PC if *options == '-' */ +#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((IGNORE_FIRST && options[1] == ':') \ + || (*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#define EMSG "" + +static inline void +warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +static int getopt_internal(int, char **, const char *); +static int gcd(int, int); +static void permute_args(int, int, int, char **); + +static const char *place = EMSG; /* option letter processing */ + +/* XXX: set mowgli_optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return b; +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, char **nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + return_if_fail(nargv != NULL); + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + nargv[pos] = nargv[cstart]; + nargv[cstart] = swap; + } + } +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + * Returns -2 if -- is found (can be long option or end of options marker). + */ +static int +getopt_internal(int nargc, char **nargv, const char *options) +{ + char *oli; /* option letter list index */ + int optchar; + + return_val_if_fail(nargv != NULL, -1); + return_val_if_fail(options != NULL, -1); + + mowgli_optarg = NULL; + + /* + * XXX Some programs (like rsyncd) expect to be able to + * XXX re-initialize mowgli_optind to 0 and have getopt_long(3) + * XXX properly function again. Work around this braindamage. + */ + if (mowgli_optind == 0) + mowgli_optind = 1; + + if (mowgli_optreset) + nonopt_start = nonopt_end = -1; +start: + if (mowgli_optreset || !*place) { /* update scanning pointer */ + mowgli_optreset = 0; + if (mowgli_optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + mowgli_optind, nargv); + mowgli_optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set mowgli_optind + * to the first of them. + */ + mowgli_optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return -1; + } + if ((*(place = nargv[mowgli_optind]) != '-') + || (place[1] == '\0')) { /* found non-option */ + place = EMSG; + if (IN_ORDER) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + mowgli_optarg = nargv[mowgli_optind++]; + return INORDER; + } + if (!PERMUTE) { + /* + * if no permutation wanted, stop parsing + * at first non-option + */ + return -1; + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = mowgli_optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + mowgli_optind, nargv); + nonopt_start = mowgli_optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + mowgli_optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = mowgli_optind; + if (place[1] && *++place == '-') { /* found "--" */ + place++; + return -2; + } + } + if ((optchar = (int)*place++) == (int)':' || + (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { + /* option letter unknown or ':' */ + if (!*place) + ++mowgli_optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + mowgli_optopt = optchar; + return BADCH; + } + if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ + /* XXX: what if no long options provided (called by getopt)? */ + if (*place) + return -2; + + if (++mowgli_optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + mowgli_optopt = optchar; + return BADARG; + } else /* white space */ + place = nargv[mowgli_optind]; + /* + * Handle -W arg the same as --arg (which causes getopt to + * stop parsing). + */ + return -2; + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++mowgli_optind; + } else { /* takes (optional) argument */ + mowgli_optarg = NULL; + if (*place) /* no white space */ + mowgli_optarg = __UNCONST(place); + /* XXX: disable test for :: if PC? (GNU doesn't) */ + else if (oli[1] != ':') { /* arg not optional */ + if (++mowgli_optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + mowgli_optopt = optchar; + return BADARG; + } else + mowgli_optarg = nargv[mowgli_optind]; + } + place = EMSG; + ++mowgli_optind; + } + /* dump back option letter */ + return optchar; +} + +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the real getopt] + */ +int +mowgli_getopt(nargc, nargv, options) + int nargc; + char * const *nargv; + const char *options; +{ + int retval; + + return_val_if_fail(nargv != NULL, -1); + return_val_if_fail(options != NULL, -1); + + retval = getopt_internal(nargc, __UNCONST(nargv), options); + if (retval == -2) { + ++mowgli_optind; + /* + * We found an option (--), so if we skipped non-options, + * we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, mowgli_optind, + __UNCONST(nargv)); + mowgli_optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + retval = -1; + } + return retval; +} + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +mowgli_getopt_long(int nargc, char * const *nargv, const char *options, + const mowgli_getopt_option_t *long_options, int *idx) +{ + int retval; + +#define IDENTICAL_INTERPRETATION(_x, _y) \ + (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ + long_options[(_x)].flag == long_options[(_y)].flag && \ + long_options[(_x)].val == long_options[(_y)].val) + + return_val_if_fail(nargv != NULL, -1); + return_val_if_fail(options != NULL, -1); + return_val_if_fail(long_options != NULL, -1); + /* idx may be NULL */ + + retval = getopt_internal(nargc, __UNCONST(nargv), options); + if (retval == -2) { + char *current_argv, *has_equal; + size_t current_argv_len; + int i, ambiguous, match; + + current_argv = __UNCONST(place); + match = -1; + ambiguous = 0; + + mowgli_optind++; + place = EMSG; + + if (*current_argv == '\0') { /* found "--" */ + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + mowgli_optind, __UNCONST(nargv)); + mowgli_optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return -1; + } + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == + (unsigned)current_argv_len) { + /* exact match */ + match = i; + ambiguous = 0; + break; + } + if (match == -1) /* partial match */ + match = i; + else if (!IDENTICAL_INTERPRETATION(i, match)) + ambiguous = 1; + } + if (ambiguous) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + mowgli_optopt = 0; + return BADCH; + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets mowgli_optopt to val regardless of + * flag + */ + if (long_options[match].flag == NULL) + mowgli_optopt = long_options[match].val; + else + mowgli_optopt = 0; + return BADARG; + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + mowgli_optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use + * next nargv + */ + mowgli_optarg = nargv[mowgli_optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (mowgli_optarg == NULL)) { + /* + * Missing argument; leading ':' + * indicates no error should be generated + */ + if (PRINT_ERROR) + warnx(recargstring, current_argv); + /* + * XXX: GNU sets mowgli_optopt to val regardless + * of flag + */ + if (long_options[match].flag == NULL) + mowgli_optopt = long_options[match].val; + else + mowgli_optopt = 0; + --mowgli_optind; + return BADARG; + } + } else { /* unknown option */ + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + mowgli_optopt = 0; + return BADCH; + } + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + retval = 0; + } else + retval = long_options[match].val; + if (idx) + *idx = match; + } + return retval; +#undef IDENTICAL_INTERPRETATION +} diff --git a/src/libmowgli/ext/getopt_long.h b/src/libmowgli/ext/getopt_long.h new file mode 100644 index 0000000..94c90a9 --- /dev/null +++ b/src/libmowgli/ext/getopt_long.h @@ -0,0 +1,69 @@ +/* $NetBSD: getopt.h,v 1.11 2008/04/28 20:22:54 martin Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +/* + * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions + */ +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +typedef struct { + /* name of long option */ + const char *name; + /* + * one of no_argument, required_argument, and optional_argument: + * whether option takes an argument + */ + int has_arg; + /* if not NULL, set *flag to val when option found */ + int *flag; + /* if flag not NULL, value to set *flag to; else return value */ + int val; + /* internal value */ + int iflag; +} mowgli_getopt_option_t; + +extern int mowgli_getopt(int nargc, char * const *nargv, const char *options); + +extern int mowgli_getopt_long(int, char * const *, const char *, + const mowgli_getopt_option_t *, int *); + +extern int mowgli_opterr; +extern int mowgli_optind; +extern int mowgli_optopt; +extern int mowgli_optreset; +extern char *mowgli_optarg; + +#endif /* !_GETOPT_H_ */ diff --git a/src/libmowgli/ext/global_storage.c b/src/libmowgli/ext/global_storage.c new file mode 100644 index 0000000..4fec74d --- /dev/null +++ b/src/libmowgli/ext/global_storage.c @@ -0,0 +1,69 @@ +/* + * libmowgli: A collection of useful routines for programming. + * global_storage.c: Simple key->value global storage tool. + * + * Copyright (c) 2007, 2011 William Pitcock <nenolod@dereferenced.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +static mowgli_patricia_t *mowgli_global_storage_dict = NULL; +static mowgli_mutex_t mowgli_global_storage_lock; + +static void _storage_key_canon(char *key) +{ + +} + +void +mowgli_global_storage_bootstrap(void) +{ + mowgli_global_storage_dict = mowgli_patricia_create(_storage_key_canon); + + mowgli_mutex_init(&mowgli_global_storage_lock); +} + +void * +mowgli_global_storage_get(char *name) +{ + void *ret; + + mowgli_mutex_lock(&mowgli_global_storage_lock); + ret = mowgli_patricia_retrieve(mowgli_global_storage_dict, name); + mowgli_mutex_unlock(&mowgli_global_storage_lock); + + return ret; +} + +void +mowgli_global_storage_put(char *name, void *value) +{ + mowgli_mutex_lock(&mowgli_global_storage_lock); + mowgli_patricia_add(mowgli_global_storage_dict, name, value); + mowgli_mutex_unlock(&mowgli_global_storage_lock); +} + +void +mowgli_global_storage_free(char *name) +{ + mowgli_mutex_lock(&mowgli_global_storage_lock); + mowgli_patricia_delete(mowgli_global_storage_dict, name); + mowgli_mutex_unlock(&mowgli_global_storage_lock); +} + diff --git a/src/libmowgli/ext/global_storage.h b/src/libmowgli/ext/global_storage.h new file mode 100644 index 0000000..a26e699 --- /dev/null +++ b/src/libmowgli/ext/global_storage.h @@ -0,0 +1,32 @@ +/* + * libmowgli: A collection of useful routines for programming. + * global_storage.h: Simple key->value global storage tool. + * + * Copyright (c) 2007 William Pitcock <nenolod -at- sacredspiral.co.uk> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MOWGLI_GLOBAL_STORAGE_H +#define MOWGLI_GLOBAL_STORAGE_H + +extern void mowgli_global_storage_bootstrap(void); +extern void *mowgli_global_storage_get(char *name); +extern void mowgli_global_storage_put(char *name, void *value); +extern void mowgli_global_storage_free(char *name); + +#endif diff --git a/src/libmowgli/ext/proctitle.c b/src/libmowgli/ext/proctitle.c new file mode 100644 index 0000000..91885d5 --- /dev/null +++ b/src/libmowgli/ext/proctitle.c @@ -0,0 +1,311 @@ +/* + * Code has been calqued from PostgreSQL 9.1 by Elizabeth J. Myers. + * Below is their copyright header. + * + * Do note I've made extensive changes to this code, including adding + * Linux (and Irix?) prctl support. + */ + +/*-------------------------------------------------------------------- + * ps_status.c + * + * Routines to support changing the ps display of PostgreSQL backends + * to contain some useful information. Mechanism differs wildly across + * platforms. + * + * src/backend/utils/misc/ps_status.c + * + * Copyright (c) 2000-2011, PostgreSQL Global Development Group + * various details abducted from various places + *-------------------------------------------------------------------- + */ + +#include "mowgli.h" + +#ifdef HAVE_SYS_PSTAT_H +#include <sys/pstat.h> /* for HP-UX */ +#endif +#ifdef HAVE_PS_STRINGS +#include <machine/vmparam.h> /* for old BSD */ +#include <sys/exec.h> +#endif +#if defined(__darwin__) +#include <crt_externs.h> +#endif +#ifdef HAVE_SYS_PRCTL_H +#include <sys/prctl.h> +#endif + +extern char **environ; + +/* + * Alternative ways of updating ps display: + * + * MOWGLI_SETPROC_USE_SETPROCTITLE + * use the function setproctitle(const char *, ...) + * (newer BSD systems) + * MOWGLI_SETPROC_USE_PSTAT + * use the pstat(PSTAT_SETCMD, ) + * (HPUX) + * MOWGLI_SETPROC_USE_PS_STRINGS + * assign PS_STRINGS->ps_argvstr = "string" + * (some BSD systems) + * MOWGLI_SETPROC_USE_PRCTL + * use prctl(PR_SET_NAME, ...) + * (Newer Linux and possibly Irix? -- Note some utilities don't use this name) + * MOWGLI_SETPROC_USE_CHANGE_ARGV + * assign argv[0] = "string" + * (some other BSD systems) + * MOWGLI_SETPROC_USE_CLOBBER_ARGV + * write over the argv and environment area + * (Old Linux and most SysV-like systems) + * MOWGLI_SETPROC_USE_WIN32 + * push the string out as the name of a Windows event + * MOWGLI_SETPROC_USE_NONE + * don't update ps display + * (This is the default, as it is safest.) + */ +#if defined(HAVE_SETPROCTITLE) +#define MOWGLI_SETPROC_USE_SETPROCTITLE +#elif defined(PR_SET_NAME) && defined(HAVE_SYS_PRCTL_H) +#define MOWGLI_SETPROC_USE_PRCTL +#elif defined(HAVE_PSTAT) && defined(PSTAT_SETCMD) +#define MOWGLI_SETPROC_USE_PSTAT +#elif defined(HAVE_PS_STRINGS) +#define MOWGLI_SETPROC_USE_PS_STRINGS +#elif (defined(BSD) || defined(__bsdi__) || defined(__hurd__)) && !defined(__darwin__) +#define MOWGLI_SETPROC_USE_CHANGE_ARGV +#elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(ultrix) || defined(__ksr__) || defined(__osf__) || defined(__svr4__) || defined(__svr5__) || defined(__darwin__) +#define MOWGLI_SETPROC_USE_CLOBBER_ARGV +#elif defined(WIN32) +#define MOWGLI_SETPROC_USE_WIN32 +#else +#define MOWGLI_SETPROC_USE_NONE +#endif + + +/* Different systems want the buffer padded differently */ +#if defined(_AIX) || defined(__linux__) || defined(__svr4__) || defined(__darwin__) +#define PS_PADDING '\0' +#else +#define PS_PADDING ' ' +#endif + + +#ifndef MOWGLI_SETPROC_USE_CLOBBER_ARGV +/* all but one option need a buffer to write their ps line in */ +#define PS_BUFFER_SIZE 256 +static char ps_buffer[PS_BUFFER_SIZE]; +static const size_t ps_buffer_size = PS_BUFFER_SIZE; +#else /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */ +static char *ps_buffer; /* will point to argv area */ +static size_t ps_buffer_size; /* space determined at run time */ +#endif /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */ + +static size_t ps_buffer_fixed_size; +static size_t ps_buffer_cur_len; /* nominal strlen(ps_buffer) */ + +/* save the original argv[] location here */ +static int save_argc; +static char **save_argv; + +/* + * Call this early in startup to save the original argc/argv values. + * If needed, we make a copy of the original argv[] array to preserve it + * from being clobbered by subsequent ps_display actions. + * + * (The original argv[] will not be overwritten by this routine, but may be + * overwritten during mowgli_proctitle_set. Also, the physical location of the + * environment strings may be moved, so this should be called before any code + * that might try to hang onto a getenv() result.) + */ +char ** +mowgli_proctitle_init(int argc, char **argv) +{ + save_argc = argc; + save_argv = argv; + +#if defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV) + + /* + * If we're going to overwrite the argv area, count the available space. + * Also move the environment to make additional room. + */ + char *end_of_area = NULL; + char **new_environ; + int i; + + /* + * check for contiguous argv strings + */ + for (i = 0; i < argc; i++) + { + if (i == 0 || end_of_area + 1 == argv[i]) + end_of_area = argv[i] + strlen(argv[i]); + } + + if (end_of_area == NULL) /* probably can't happen? */ + { + ps_buffer = NULL; + ps_buffer_size = 0; + return argv; + } + + /* + * check for contiguous environ strings following argv + */ + for (i = 0; environ[i] != NULL; i++) + { + if (end_of_area + 1 == environ[i]) + end_of_area = environ[i] + strlen(environ[i]); + } + + ps_buffer = argv[0]; + ps_buffer_size = end_of_area - argv[0]; + + /* + * move the environment out of the way + */ + new_environ = (char **) mowgli_alloc((i + 1) * sizeof(char *)); + for (i = 0; environ[i] != NULL; i++) + new_environ[i] = mowgli_strdup(environ[i]); + new_environ[i] = NULL; + environ = new_environ; + +#endif /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */ + +#if defined(MOWGLI_SETPROC_USE_CHANGE_ARGV) || defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV) + + /* + * If we're going to change the original argv[] then make a copy for + * argument parsing purposes. + * + * (NB: do NOT think to remove the copying of argv[]. + * On some platforms, getopt() keeps pointers into the argv array, and will + * get horribly confused when it is re-called to analyze a subprocess' + * argument string if the argv storage has been clobbered meanwhile. Other + * platforms have other dependencies on argv[]. + */ + + char **new_argv; + int i; + + new_argv = (char **) mowgli_alloc((argc + 1) * sizeof(char *)); + for (i = 0; i < argc; i++) + new_argv[i] = mowgli_strdup(argv[i]); + new_argv[argc] = NULL; + +#if defined(__darwin__) + /* + * Darwin (and perhaps other NeXT-derived platforms?) has a static + * copy of the argv pointer, which we may fix like so: + */ + *_NSGetArgv() = new_argv; +#endif + + argv = new_argv; + +#endif /* MOWGLI_SETPROC_USE_CHANGE_ARGV or MOWGLI_SETPROC_USE_CLOBBER_ARGV */ + + return argv; +} + +void +mowgli_proctitle_set(const char *fmt, ...) +{ +#ifndef MOWGLI_SETPROC_USE_NONE + va_list va; + +#if defined(MOWGLI_SETPROC_USE_CHANGE_ARGV) || defined(MOWGLI_SETPROC_USE_CLOBBER_ARGV) + if (!save_argv) + return; +#endif + + va_start(va, fmt); + vsnprintf(ps_buffer, ps_buffer_size, fmt, va); + va_end(va); + + return_if_fail(*ps_buffer == '\0'); + + ps_buffer_cur_len = ps_buffer_fixed_size = strlen(ps_buffer); + +#ifdef MOWGLI_SETPROC_USE_CHANGE_ARGV + save_argv[0] = ps_buffer; + save_argv[1] = NULL; +#endif + +#ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV + for (int i = 1; i < save_argc; i++) + save_argv[i] = ps_buffer + ps_buffer_size; + + /* Pad unused bytes */ + printf("%d %d\n", ps_buffer_size, ps_buffer_cur_len); + memset(ps_buffer + ps_buffer_cur_len, PS_PADDING, ps_buffer_size - ps_buffer_cur_len + 1); +#endif + +#ifdef MOWGLI_SETPROC_USE_SETPROCTITLE + setproctitle("%s", ps_buffer); +#endif + +#ifdef MOWGLI_SETPROC_USE_PRCTL + /* Limit us to 16 chars to be safe */ + char procbuf[16]; + mowgli_strlcpy(procbuf, ps_buffer, sizeof(procbuf)); + prctl(PR_SET_NAME, procbuf, 0, 0, 0); + printf("%s\n", procbuf); +#endif + +#ifdef MOWGLI_SETPROC_USE_PSTAT + union pstun pst; + + pst.pst_command = ps_buffer; + pstat(PSTAT_SETCMD, pst, ps_buffer_cur_len, 0, 0); +#endif /* MOWGLI_SETPROC_USE_PSTAT */ + +#ifdef MOWGLI_SETPROC_USE_PS_STRINGS + PS_STRINGS->ps_nargvstr = 1; + PS_STRINGS->ps_argvstr = ps_buffer; +#endif /* MOWGLI_SETPROC_USE_PS_STRINGS */ + +#ifdef MOWGLI_SETPROC_USE_WIN32 + /* + * Win32 does not support showing any changed arguments. To make it at + * all possible to track which backend is doing what, we create a + * named object that can be viewed with for example Process Explorer. + */ + static HANDLE ident_handle = INVALID_HANDLE_VALUE; + char name[PS_BUFFER_SIZE + 32]; + + if (ident_handle != INVALID_HANDLE_VALUE) + CloseHandle(ident_handle); + + sprintf(name, "mowgli_ident(%d): %s", getpid(), ps_buffer); + + ident_handle = CreateEvent(NULL, TRUE, FALSE, name); +#endif /* MOWGLI_SETPROC_USE_WIN32 */ +#endif /* not MOWGLI_SETPROC_USE_NONE */ +} + + +/* + * Returns what's currently in the ps display, in case someone needs + * it. Note that only the activity part is returned. On some platforms + * the string will not be null-terminated, so return the effective + * length into *displen. + */ +const char * +mowgli_proctitle_get(int *displen) +{ +#ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV + /* If ps_buffer is a pointer, it might still be null */ + if (!ps_buffer) + { + *displen = 0; + return ""; + } +#endif + + *displen = (int) (ps_buffer_cur_len - ps_buffer_fixed_size); + + return ps_buffer + ps_buffer_fixed_size; +} diff --git a/src/libmowgli/ext/proctitle.h b/src/libmowgli/ext/proctitle.h new file mode 100644 index 0000000..479ee84 --- /dev/null +++ b/src/libmowgli/ext/proctitle.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------- + * + * ps_status.h + * + * Declarations for backend/utils/misc/ps_status.c + * + * src/include/utils/ps_status.h + * + *------------------------------------------------------------------------- + */ + +#ifndef __PS_STATUS_H__ +#define __PS_STATUS_H__ + +extern bool mowgli_proctitle_update; + +extern char **mowgli_proctitle_init(int argc, char **argv); + +extern void mowgli_proctitle_set(const char *fmt, ...); + +extern const char *mowgli_proctitle_get(int *displen); + +#endif /* __PS_STATUS_H__ */ diff --git a/src/libmowgli/ext/program_opts.c b/src/libmowgli/ext/program_opts.c new file mode 100644 index 0000000..75acd53 --- /dev/null +++ b/src/libmowgli/ext/program_opts.c @@ -0,0 +1,191 @@ +/* + * libmowgli: A collection of useful routines for programming. + * program_opts.h: Replacement for GNU getopt(). + * + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#include "ext/getopt_long.h" + +void +mowgli_program_opts_consumer_str(const char *arg, void *userdata) +{ + return_if_fail(arg != NULL); + return_if_fail(userdata != NULL); + + *(char **) userdata = mowgli_strdup(arg); +} + +void +mowgli_program_opts_consumer_int(const char *arg, void *userdata) +{ + return_if_fail(arg != NULL); + return_if_fail(userdata != NULL); + + *(int *) userdata = atoi(arg); +} + +void +mowgli_program_opts_consumer_bool(const char *arg, void *userdata) +{ + return_if_fail(arg != NULL); + return_if_fail(userdata != NULL); + + *(bool *) userdata = true; +} + +static inline mowgli_program_opts_t * +mowgli_program_opts_lookup_name(mowgli_program_opts_t *opts, size_t opts_size, const char *name) +{ + size_t i; + + if (strlen(name) > 1) + { + for (i = 0; i < opts_size; i++) + { + if (!strcasecmp(name, opts[i].longopt)) + return &opts[i]; + } + } + else + { + for (i = 0; i < opts_size; i++) + { + if (*name == opts[i].smallopt) + return &opts[i]; + } + } + + return NULL; +} + +static inline mowgli_getopt_option_t * +mowgli_program_opts_convert(const mowgli_program_opts_t *opts, size_t opts_size) +{ + mowgli_getopt_option_t *g_opts; + size_t i; + + return_val_if_fail(opts != NULL, NULL); + + g_opts = mowgli_alloc_array(sizeof(mowgli_getopt_option_t), opts_size); + + for (i = 0; i < opts_size; i++) + { + if (opts[i].longopt == NULL) + continue; + + g_opts[i].name = opts[i].longopt; + g_opts[i].iflag = i; + if (opts[i].has_param) + g_opts[i].has_arg = 1; + } + + return g_opts; +} + +static inline const char * +mowgli_program_opts_compute_optstr(const mowgli_program_opts_t *opts, size_t opts_size) +{ + static char buf[256]; + char *p = buf; + size_t i; + + return_val_if_fail(opts != NULL, NULL); + + memset(buf, '\0', sizeof buf); + + for (i = 0; i < opts_size; i++) + { + if (!opts[i].smallopt) + continue; + + *p++ = opts[i].smallopt; + if (opts[i].has_param) + *p++ = ':'; + } + + *p = '\0'; + + return buf; +} + +static inline void +mowgli_program_opts_dispatch(const mowgli_program_opts_t *opt, const char *optarg) +{ + return_if_fail(opt != NULL); + + if (opt->has_param && optarg == NULL) + { + fprintf(stderr, "no optarg for option %s", opt->longopt); + return; + } + + opt->consumer(optarg, opt->userdata); +} + +void +mowgli_program_opts_parse(const mowgli_program_opts_t *opts, size_t opts_size, int *argc, char ***argv) +{ + mowgli_getopt_option_t *g_opts; + const char *shortops; + int c; + size_t i; + int opt_index; + + return_if_fail(opts != NULL); + return_if_fail(opts_size > 0); + return_if_fail(argc != NULL); + return_if_fail(argv != NULL); + + g_opts = mowgli_program_opts_convert(opts, opts_size); + shortops = mowgli_program_opts_compute_optstr(opts, opts_size); + + for (;;) + { + const mowgli_program_opts_t *opt = NULL; + + c = mowgli_getopt_long(*argc, *argv, shortops, g_opts, &opt_index); + if (c == -1) + break; + + switch (c) + { + case 0: + /* long-option was provided, resolve it. */ + opt = &opts[g_opts[opt_index].iflag]; + break; + default: + for (i = 0; i < opts_size; i++) + { + if (opts[i].smallopt == c) + { + opt = &opts[i]; + break; + } + } + break; + } + + mowgli_program_opts_dispatch(opt, mowgli_optarg); + } + + mowgli_free(g_opts); +} diff --git a/src/libmowgli/ext/program_opts.h b/src/libmowgli/ext/program_opts.h new file mode 100644 index 0000000..f418b96 --- /dev/null +++ b/src/libmowgli/ext/program_opts.h @@ -0,0 +1,50 @@ +/* + * libmowgli: A collection of useful routines for programming. + * program_opts.h: Replacement for GNU getopt(). + * + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MOWGLI_PROGRAM_OPTS_H__ +#define __MOWGLI_PROGRAM_OPTS_H__ + +typedef void (*mowgli_program_opts_consumer_t)(const char *arg, void *userdata); + +typedef struct { + const char *longopt; + const char smallopt; + bool has_param; + mowgli_program_opts_consumer_t consumer; + void *userdata; + + /* optional data */ + const char *description; + const char *paramname; +} mowgli_program_opts_t; + +/* use when has_param is true */ +extern void mowgli_program_opts_consumer_str(const char *arg, void *userdata); +extern void mowgli_program_opts_consumer_int(const char *arg, void *userdata); + +/* use when has_param is false */ +extern void mowgli_program_opts_consumer_bool(const char *arg, void *userdata); + +extern void mowgli_program_opts_parse(const mowgli_program_opts_t *opts, size_t opts_size, int *argc, char ***argv); + +#endif |