diff options
author | 2005-12-06 12:28:25 +0000 | |
---|---|---|
committer | 2005-12-06 12:28:25 +0000 | |
commit | f62636483b16222c394fa17c635d74017cf215ba (patch) | |
tree | 22039adb2bfc850dd02b1a2508f5f0c975b56f91 | |
parent | fix openvz /proc handling; cleanup (diff) | |
download | baselayout-vserver-f62636483b16222c394fa17c635d74017cf215ba.tar.gz baselayout-vserver-f62636483b16222c394fa17c635d74017cf215ba.tar.bz2 baselayout-vserver-f62636483b16222c394fa17c635d74017cf215ba.zip |
Importing latest baselayout/trunk changes. Merging revision 1773.
svn path=/baselayout-vserver/trunk/; revision=160
45 files changed, 5873 insertions, 4006 deletions
@@ -1,6 +1,14 @@ # ChangeLog for Gentoo System Intialization ("rc") scripts # Copyright 1999-2005 Gentoo Foundation; Distributed under the GPLv2 + 06 Dec 2005; Roy Marples <uberlord@gentoo.org>: + + ppp documentation updated, #114551. + + 05 Dec 2005; Roy Marples <uberlord@gentoo.org>: + + Fix dhcp options, #114519. + 29 Nov 2005; Martin Schlemmer <azarah@gentoo.org>: Add po/Makefile, based mostly on work done by Rach Holmes <Rach.Holmes@GMX.net> diff --git a/ChangeLog.vserver b/ChangeLog.vserver index 8a43657..a93785b 100644 --- a/ChangeLog.vserver +++ b/ChangeLog.vserver @@ -1,6 +1,56 @@ # ChangeLog for Gentoo System Intialization ("rc") scripts # Copyright 1999-2005 Gentoo Foundation; Distributed under the GPLv2 + 06 Dec 2005; Christian Heim <phreak@gentoo.org>: + Importing latest baselayout/trunk changes. Merging revision 1773. + + ChangeLog | 8 + ChangeLog.vserver | 50 + net-scripts/conf.d/net.example | 5 + net-scripts/net.modules.d/dhclient | 10 + net-scripts/net.modules.d/dhcpcd | 18 + net-scripts/net.modules.d/helpers.d/dhcp | 11 + net-scripts/net.modules.d/helpers.d/dhcpcd-wrapper | 4 + net-scripts/net.modules.d/pump | 9 + net-scripts/net.modules.d/udhcpc | 8 + src/core/Makefile.am | 4 + src/core/configure.ac | 55 + src/core/librcscripts/Makefile.am | 31 + src/core/librcscripts/api/debug.h | 136 + + src/core/librcscripts/api/depend.h | 76 + src/core/librcscripts/api/dynbuf.h | 63 + src/core/librcscripts/api/list.h | 446 +++++ + src/core/librcscripts/api/misc.h | 106 + + src/core/librcscripts/api/parse.h | 84 + + src/core/librcscripts/api/rctypes.h | 43 + src/core/librcscripts/api/runlevels.h | 44 + src/core/librcscripts/api/scripts.h | 43 + src/core/librcscripts/api/simple-regex.h | 87 + + src/core/librcscripts/api/str_list.h | 212 ++ + src/core/librcscripts/debug.c | 297 +++ + src/core/librcscripts/debug.h | 85 - + src/core/librcscripts/depend.c | 973 ++++++------ + src/core/librcscripts/depend.h | 75 + src/core/librcscripts/dynbuf.c | 332 ++++ + src/core/librcscripts/list.h | 446 ----- + src/core/librcscripts/misc.c | 916 +++++------ + src/core/librcscripts/misc.h | 282 --- + src/core/librcscripts/parse.c | 1439 ++++++++---------- + src/core/librcscripts/parse.h | 100 - + src/core/librcscripts/rcscripts.h | 26 + src/core/librcscripts/runlevels.c | 218 ++ + src/core/librcscripts/scripts.c | 256 +++ + src/core/librcscripts/simple-regex.c | 1232 +++++++-------- + src/core/librcscripts/simple-regex.h | 86 - + src/core/src/depscan.c | 433 ++--- + src/core/src/runscript.c | 381 ++-- + src/core/tests/Makefile.am | 25 + src/core/tests/test-dynbuf.c | 139 + + src/core/tests/test-mmap.c | 46 + src/core/tests/test-regex.c | 97 - + src/core/tests/test-runlevels.c | 70 + 45 files changed, 5687 insertions(+), 3820 deletions(-) + 02 Dec 2005; Christian Heim <phreak@gentoo.org>: Import the latest baselayout changes. Merging revision 1658. diff --git a/net-scripts/conf.d/net.example b/net-scripts/conf.d/net.example index 77482b7..ec6e056 100644 --- a/net-scripts/conf.d/net.example +++ b/net-scripts/conf.d/net.example @@ -358,6 +358,9 @@ #cd /etc/init.d #ln -s net.lo net.ppp0 # +# We have to instruct ppp0 to actually use ppp +#config_ppp0=( "ppp" ) +# # Each PPP interface requires an interface to use as a "Link" #link_ppp0="/dev/ttyS0" # Most PPP links will use a serial port #link_ppp0="eth0" # PPPoE requires an ethernet interface @@ -387,7 +390,7 @@ # "debug" # Enables syslog debugging # "noauth" # Do not require the peer to authenticate itself # "defaultroute" # Make this PPP interface the default route -# "userpeerdns" # Use the DNS settings provided by PPP +# "usepeerdns" # Use the DNS settings provided by PPP # # On demand options # "demand" # Enable dial on demand diff --git a/net-scripts/net.modules.d/dhclient b/net-scripts/net.modules.d/dhclient index 37861b0..25e8d85 100644 --- a/net-scripts/net.modules.d/dhclient +++ b/net-scripts/net.modules.d/dhclient @@ -45,10 +45,12 @@ dhclient_stop() { local pid=$( < "${pidfile}" ) local ifvar=$( bash_variable "${iface}" ) - d="dhcp_${ifvar}[@]" + d="dhcp_${ifvar}" + d=" ${!d} " + [[ ${d} == " " ]] && d=" ${dhcp} " ebegin "Stopping dhclient on ${iface}" - if [[ " ${!d} " == *" release "* ]]; then + if [[ ${d} == *" release "* ]]; then local r=$( dhclient -q -r -pf "${pidfile}" \ -sf "${MODULES_DIR}/helpers.d/dhclient-wrapper" "${iface}" ) [[ ${r} == "deconfig" ]] @@ -115,9 +117,11 @@ dhclient_start() { fi d="dhcp_${ifvar}" + d=" ${!d} " + [[ ${d} == " " ]] && d=" ${dhcp} " # Send our hostname by editing cffile - if ${edit} && [[ -e ${cffile} && " ${!d} " != *" nosendhost "* ]] ; then + if ${edit} && [[ -e ${cffile} && ${d} != *" nosendhost "* ]] ; then local hname=$( hostname ) if [[ ${hname} != "(none)" && ${hname} != "localhost" ]]; then sed -i '/^[ \t]*send[ \t]*host-name[ \t]*/d' "${cffile}" diff --git a/net-scripts/net.modules.d/dhcpcd b/net-scripts/net.modules.d/dhcpcd index 9d8aa14..70a6bcc 100644 --- a/net-scripts/net.modules.d/dhcpcd +++ b/net-scripts/net.modules.d/dhcpcd @@ -52,7 +52,7 @@ dhcpcd_get_vars() { # Returns 0 (true) when a DHCP address dropped # otherwise return 1 dhcpcd_stop() { - local iface=$1 count signal pidfile="/var/run/dhcpcd-$1.pid" opts + local iface=$1 count signal pidfile="/var/run/dhcpcd-$1.pid" d [[ ! -f ${pidfile} ]] && return 0 @@ -60,9 +60,11 @@ dhcpcd_stop() { local pid=$( < "${pidfile}" ) local ifvar=$( bash_variable "${iface}" ) - opts="dhcp_${ifvar}" + d="dhcp_${ifvar}" + d=" ${!d} " + [[ ${d} == " " ]] && d=" ${dhcp} " - if [[ " ${!opts} " == *" release "* ]]; then + if [[ ${d} == *" release "* ]]; then signal="HUP" else signal="TERM" @@ -91,10 +93,12 @@ dhcpcd_start() { # Map some generic options to dhcpcd d="dhcp_${ifvar}" - [[ " ${d} " == *" nodns "* ]] && opts="${opts} -R" - [[ " ${d} " == *" nontp "* ]] && opts="${opts} -N" - [[ " ${d} " == *" nonis "* ]] && opts="${opts} -Y" - [[ " ${d} " == *" nogateway "* ]] && opts="${opts} -G" + d=" ${!d} " + [[ ${d} == " " ]] && d=" ${dhcp} " + [[ ${d} == *" nodns "* ]] && opts="${opts} -R" + [[ ${d} == *" nontp "* ]] && opts="${opts} -N" + [[ ${d} == *" nonis "* ]] && opts="${opts} -Y" + [[ ${d} == *" nogateway "* ]] && opts="${opts} -G" # We transmit the hostname by default:q if [[ " ${d} " != *" nosendhost "* && " ${opts} " != *" -h "* ]]; then diff --git a/net-scripts/net.modules.d/helpers.d/dhcp b/net-scripts/net.modules.d/helpers.d/dhcp index bfde3b1..52998ca 100755 --- a/net-scripts/net.modules.d/helpers.d/dhcp +++ b/net-scripts/net.modules.d/helpers.d/dhcp @@ -92,8 +92,11 @@ echo "${ip}" > "/var/cache/dhcp-${interface}.lease" chmod 600 "/var/cache/dhcp-${interface}.lease" d="dhcp_${ifvar}" +d=" ${!d} " +[[ ${d} == " " ]] && d=" ${dhcp} " + # Configure our default route - we only have 1 default route -if [[ " ${!d} " != *" nogateway "* ]]; then +if [[ ${d} != *" nogateway "* ]]; then for r in ${routers}; do interface_default_route "${interface}" "${r}" "${metric:-0}" && break done @@ -110,9 +113,9 @@ fi # Only setup the information we're told to # By default that's everything -[[ " ${!d} " != *" nodns "* ]] && system_dns "${interface}" -[[ " ${!d} " != *" nontp "* ]] && system_ntp "${interface}" -[[ " ${!d} " != *" nonis "* ]] && system_nis "${interface}" +[[ ${d} != *" nodns "* ]] && system_dns "${interface}" +[[ ${d} != *" nontp "* ]] && system_ntp "${interface}" +[[ ${d} != *" nonis "* ]] && system_nis "${interface}" if [[ ${RC_AUTO_INTERFACE} == "yes" ]]; then best_interface=$( select_best_interface ) diff --git a/net-scripts/net.modules.d/helpers.d/dhcpcd-wrapper b/net-scripts/net.modules.d/helpers.d/dhcpcd-wrapper index 4b4774f..f5e5a9c 100755 --- a/net-scripts/net.modules.d/helpers.d/dhcpcd-wrapper +++ b/net-scripts/net.modules.d/helpers.d/dhcpcd-wrapper @@ -31,9 +31,11 @@ ifvar=$( bash_variable "${interface}" ) if [[ ${action} == "up" ]]; then d="dhcp_${ifvar}" + d=" ${!d} " + [[ ${d} == " " ]] && d=" ${dhcp} " resolv="${statedir}/${interface}/resolv.conf" - if [[ " ${!d} " != *" nodns "* ]]; then + if [[ ${d} != *" nodns "* ]]; then search="dns_search_${ifvar}" if [[ -n ${!search} ]]; then tmp="${resolv}.$$" diff --git a/net-scripts/net.modules.d/pump b/net-scripts/net.modules.d/pump index bb8be39..5c81b2c 100644 --- a/net-scripts/net.modules.d/pump +++ b/net-scripts/net.modules.d/pump @@ -67,10 +67,11 @@ pump_start() { # Map some generic options to pump d="dhcp_${ifvar}" - [[ " ${!d} " == " " ]] && d=" ${dhcp} " - [[ " ${!d} " == *" nodns "* ]] && opts="${opts} --no-dns" - [[ " ${!d} " == *" nogateway "* ]] && opts="${opts} --no-gateway" - [[ " ${!d} " == *" nontp "* ]] && opts="${opts} --no-ntp" + d=" ${!d} " + [[ ${d} == " " ]] && d=" ${dhcp} " + [[ ${d} == *" nodns "* ]] && opts="${opts} --no-dns" + [[ ${d} == *" nogateway "* ]] && opts="${opts} --no-gateway" + [[ ${d} == *" nontp "* ]] && opts="${opts} --no-ntp" search="dns_search_${ifvar}" [[ -n ${!search} ]] && opts="${opts} --search-path='"${!search}"'" diff --git a/net-scripts/net.modules.d/udhcpc b/net-scripts/net.modules.d/udhcpc index 69598e3..a0661a0 100644 --- a/net-scripts/net.modules.d/udhcpc +++ b/net-scripts/net.modules.d/udhcpc @@ -43,8 +43,10 @@ udhcpc_stop() { local ifvar=$( bash_variable "${iface}" ) d="dhcp_${ifvar}" + d=" ${!d} " + [[ ${d} == " " ]] && d=" ${dhcp} " - if [[ " ${!d} " == *" release "* ]]; then + if [[ ${d} == *" release "* ]]; then kill -s USR2 "${pid}" &>/dev/null [[ -f "/var/cache/dhcp-${iface}.lease" ]] \ && rm "/var/cache/dhcp-${iface}.lease" @@ -75,8 +77,10 @@ udhcpc_start() { opts="${!opts}" d="dhcp_${ifvar}" + d=" ${!d} " + [[ ${d} == " " ]] && d=" ${dhcp} " - if [[ " ${!d} " != *" nosendhost "* ]]; then + if [[ " ${d} " != *" nosendhost "* ]]; then if [[ ! " ${opts}" =~ " -([hH] |-hostname=)" ]]; then local hname=$( hostname ) [[ -n ${hname} && ${hname} != "(none)" && ${hname} != "localhost" ]] \ diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 9ab959a..c27343f 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -7,4 +7,6 @@ SUBDIRS = \ src \ tests -EXTRA_DIST = ChangeLog.0 +EXTRA_DIST = \ + autogen.sh \ + ChangeLog.0 diff --git a/src/core/configure.ac b/src/core/configure.ac index e22d9ae..1528b38 100644 --- a/src/core/configure.ac +++ b/src/core/configure.ac @@ -36,31 +36,60 @@ dnl Checks for library functions. AC_FUNC_FORK AC_FUNC_LSTAT AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK -AC_FUNC_MALLOC -AC_FUNC_REALLOC AC_TYPE_SIGNAL AC_FUNC_STAT +AC_CHECK_FUNCS([remove]) + +dnl Check if gcc provides va_copy or __va_copy +AC_MSG_CHECKING([for va_copy]) +AC_TRY_COMPILE([ + #include <stdarg.h> + ], [ + va_list ap, aq; + va_copy(ap, aq); + ], + [va_copy="va_copy"], + [AC_TRY_COMPILE([ + #include <stdarg.h> + ], [ + va_list ap, aq; + __va_copy(ap, aq); + ], + [va_copy="__va_copy"], + [AC_MSG_ERROR([Unable to determine name of va_copy macro])] + )] +) +AC_MSG_RESULT([$va_copy]) +if test x"$va_copy" != xva_copy ; then + AC_DEFINE_UNQUOTED([va_copy], [$va_copy], + [va_copy macro proviced by gcc (undefined if its va_copy, else defined + to proper name)] + ) +fi dnl check if we have 32bit or 64bit output AC_ARG_ENABLE([debug], - AS_HELP_STRING([--enable-debug], - [enable debugging - very verbose (default=disabled)]), - [enable_debug="$enableval"], - [enable_debug="no"] + AS_HELP_STRING([--enable-debug], + [enable debugging - very verbose (default=disabled)]), + [enable_debug="$enableval"], + [enable_debug="no"] ) if test x"$enable_debug" != xno ; then - CFLAGS="$CFLAGS -ggdb -DRC_DEBUG" + CFLAGS="$CFLAGS -ggdb -DRC_DEBUG -Wshadow -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs" fi +CFLAGS="$CFLAGS -Wall" + RCSCRIPTS_DEFINES='-DETCDIR="\"$(sysconfdir)\"" -DLIBDIR="\"$(libdir)\"" -DBINDIR="\"$(bindir)\"" -DSBINDIR="\"$(sbindir)\""' AC_SUBST([RCSCRIPTS_DEFINES]) AC_OUTPUT([ - Makefile - scripts/Makefile - data/Makefile - librcscripts/Makefile - src/Makefile - tests/Makefile + Makefile + scripts/Makefile + data/Makefile + librcscripts/Makefile + src/Makefile + tests/Makefile ]) + diff --git a/src/core/librcscripts/Makefile.am b/src/core/librcscripts/Makefile.am index 8e6b509..27da323 100644 --- a/src/core/librcscripts/Makefile.am +++ b/src/core/librcscripts/Makefile.am @@ -5,14 +5,23 @@ INCLUDES = $(RCSCRIPTS_DEFINES) lib_LTLIBRARIES = librcscripts.la librcscripts_la_SOURCES = \ - rcscripts.h \ - debug.h \ - depend.c \ - depend.h \ - list.h \ - misc.c \ - misc.h \ - parse.c \ - parse.h \ - simple-regex.c \ - simple-regex.h + rcscripts.h \ + api/rctypes.h \ + debug.c \ + api/debug.h \ + misc.c \ + api/misc.h \ + api/list.h \ + api/str_list.h \ + dynbuf.c \ + api/dynbuf.h \ + simple-regex.c \ + api/simple-regex.h \ + scripts.c \ + api/scripts.h \ + runlevels.c \ + api/runlevels.h \ + parse.c \ + api/parse.h \ + depend.c \ + api/depend.h diff --git a/src/core/librcscripts/api/debug.h b/src/core/librcscripts/api/debug.h new file mode 100644 index 0000000..a0b798f --- /dev/null +++ b/src/core/librcscripts/api/debug.h @@ -0,0 +1,136 @@ +/* + * debug.h + * + * Simle debugging/logging macro's and functions. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#ifndef __DEBUG_H__ +#define __DEBUG_H__ + +#include <errno.h> +#include <stdio.h> + +#define save_errno() int old_errno = errno; +#define restore_errno() errno = old_errno; +#define saved_errno old_errno + +void +debug_message (const char *file, const char *func, int line, + const char *format, ...); + +#define DBG_MSG(_format, _arg...) \ + do { \ + debug_message (__FILE__, __FUNCTION__, __LINE__, _format, ## _arg); \ + } while (0) + +#define FATAL_ERROR() \ + do { \ + save_errno (); \ + fprintf(stderr, "ERROR: file '%s', function '%s', line %i.\n", \ + __FILE__, __FUNCTION__, __LINE__); \ + restore_errno (); \ + if (0 != errno) \ + { \ + perror("ERROR"); \ + } \ + exit(EXIT_FAILURE); \ + } while (0) + +#define NEG_FATAL_ERROR(_x) \ + do { \ + if (-1 == _x) \ + { \ + FATAL_ERROR(); \ + } \ + } while (0) + +#define NULL_FATAL_ERROR(_x) \ + do { \ + if (NULL == _x) \ + { \ + FATAL_ERROR(); \ + } \ + } while (0) + +/* + * Functions to check validity of some types. + * They do not set errno. + */ + +inline bool check_ptr (const void *ptr); +inline bool check_str (const char *str); +inline bool check_strv (char **str); +inline bool check_fd (int fd); +inline bool check_fp (FILE * fp); + +/* + * Functions and macro's to check validity of some types. + * They DO set errno to EINVAL. + */ + +inline bool __check_arg_ptr (const void *ptr, const char *file, const char *func, + size_t line); +inline bool __check_arg_str (const char *str, const char *file, const char *func, + size_t line); +inline bool __check_arg_strv (char **str, const char *file, const char *func, + size_t line); +inline bool __check_arg_fd (int fd, const char *file, const char *func, + size_t line); +inline bool __check_arg_fp (FILE * fp, const char *file, const char *func, + size_t line); + +#define check_arg_ptr(_ptr) \ + __check_arg_ptr (_ptr, __FILE__, __FUNCTION__, __LINE__) +#define check_arg_str(_str) \ + __check_arg_str (_str, __FILE__, __FUNCTION__, __LINE__) +#define check_arg_strv(_str) \ + __check_arg_strv (_str, __FILE__, __FUNCTION__, __LINE__) +#define check_arg_fd(_fd) \ + __check_arg_fd (_fd, __FILE__, __FUNCTION__, __LINE__) +#define check_arg_fp(_fp) \ + __check_arg_fp (_fp, __FILE__, __FUNCTION__, __LINE__) + +/* + * Various memory allocation functions and macro's. + * They set errno to ENOMEM and print debug info. + */ + +inline void *__xcalloc (size_t nmemb, size_t size, const char *file, + const char *func, size_t line); +inline void *__xmalloc (size_t size, const char *file, const char *func, + size_t line); +inline void *__xrealloc (void *ptr, size_t size, const char *file, + const char *func, size_t line); + +#define xcalloc(_nmemb, _size) \ + __xcalloc (_nmemb, _size, __FILE__, __FUNCTION__, __LINE__) +#define xmalloc(_size) \ + __xmalloc (_size, __FILE__, __FUNCTION__, __LINE__) +#define xrealloc(_ptr, _size) \ + __xrealloc (_ptr, _size, __FILE__, __FUNCTION__, __LINE__) + +inline char *__xstrndup (const char *str, size_t size, const char *file, + const char *func, size_t line); + +#define xstrndup(_str, _size) \ + __xstrndup (_str, _size, __FILE__, __FUNCTION__, __LINE__) + +#endif /* __DEBUG_H__ */ diff --git a/src/core/librcscripts/api/depend.h b/src/core/librcscripts/api/depend.h new file mode 100644 index 0000000..d6662c6 --- /dev/null +++ b/src/core/librcscripts/api/depend.h @@ -0,0 +1,76 @@ +/* + * depend.h + * + * Dependancy engine for Gentoo style rc-scripts. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#ifndef __DEPEND_H__ +#define __DEPEND_H__ + +/* Dependency types supported or still to be implemented */ +typedef enum +{ + NEED, /* All dependencies needed by specified service */ + NEED_ME, /* All dependencies that need specified service */ + USE, /* All dependencies used by specified service */ + USE_ME, /* All dependencies that use specified service */ + BEFORE, /* All services started before specified service */ + AFTER, /* All services started after specified service */ + BROKEN, /* All dependencies of type NEED missing for + specified service */ + PROVIDE, /* All virtual services provided by specified service */ + ALL_SERVICE_TYPE_T +} service_type_t; + +/* Names for above service types (service_type_t). + * Note that this should sync with above service_type_t */ +extern char *service_type_names[]; + +typedef struct +{ + struct list_head node; + + char *name; /* Name of service */ + char **depend_info[ALL_SERVICE_TYPE_T]; /* String lists for each service + type */ + char *provide; /* Name of virtual service it + provides. This is only valid + after we resolving - thus after + service_resolve_dependencies() */ + time_t mtime; /* Modification time of script */ +} service_info_t; + +struct list_head service_info_list; + +service_info_t *service_get_info (char *servicename); +int service_add (char *servicename); +int service_is_dependency (char *servicename, char *dependency, + service_type_t type); +int service_add_dependency (char *servicename, char *dependency, + service_type_t type); +int service_del_dependency (char *servicename, char *dependency, + service_type_t type); +service_info_t *service_get_virtual (char *virtual); +int service_add_virtual (char *servicename, char *virtual); +int service_set_mtime (char *servicename, time_t mtime); +int service_resolve_dependencies (void); + +#endif /* __DEPEND_H__ */ diff --git a/src/core/librcscripts/api/dynbuf.h b/src/core/librcscripts/api/dynbuf.h new file mode 100644 index 0000000..3b0049e --- /dev/null +++ b/src/core/librcscripts/api/dynbuf.h @@ -0,0 +1,63 @@ +/* + * dynbuf.h + * + * Dynamic allocated buffers. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#ifndef __DYNBUF_H__ +#define __DYNBUF_H__ + +#define DYNAMIC_BUFFER_SIZE (sizeof (char) * 2 * 1024) + +typedef struct +{ + char *data; /* Actual data */ + size_t length; /* Length of data block */ + size_t rd_index; /* Current read index */ + size_t wr_index; /* Current write index */ +} dyn_buf_t; + +dyn_buf_t *new_dyn_buf (void); + +void free_dyn_buf (dyn_buf_t * dynbuf); + +int write_dyn_buf (dyn_buf_t * dynbuf, const char *buf, size_t length); + +int write_dyn_buf_from_fd (int fd, dyn_buf_t * dynbuf, size_t length); + +int sprintf_dyn_buf (dyn_buf_t * dynbuf, const char *format, ...); + +int read_dyn_buf (dyn_buf_t * dynbuf, char *buf, size_t length); + +int read_dyn_buf_to_fd (int fd, dyn_buf_t * dynbuf, size_t length); + +char *read_line_dyn_buf (dyn_buf_t *dynbuf); + +bool dyn_buf_rd_eof (dyn_buf_t *dynbuf); + +inline bool check_dyn_buf (dyn_buf_t *dynbuf); +inline bool __check_arg_dyn_buf (dyn_buf_t *dynbuf, const char *file, + const char *func, size_t line); + +#define check_arg_dyn_buf(_dynbuf) \ + __check_arg_dyn_buf (_dynbuf, __FILE__, __FUNCTION__, __LINE__) + +#endif /* __DYNBUF_H__ */ diff --git a/src/core/librcscripts/api/list.h b/src/core/librcscripts/api/list.h new file mode 100644 index 0000000..e4c7a74 --- /dev/null +++ b/src/core/librcscripts/api/list.h @@ -0,0 +1,446 @@ +/* + * Copied from the Linux kernel source tree, version 2.6.0-test1. + * + * Licensed under the GPL v2 as per the whole kernel source tree. + * + * Ripped out the rcu stuff, as it's not needed. + * + * $Header$ + */ + +#ifndef __LINUX_LIST_H__ +#define __LINUX_LIST_H__ + +//#include <linux/stddef.h> +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +//#include <linux/prefetch.h> +static inline void prefetch(const void *x) {;} + +//#include <asm/system.h> + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(struct list_head *head) +{ + return head->next == head; +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + prefetch(pos->member.prev); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member), \ + prefetch(pos->member.prev)) + + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) + +static __inline__ int hlist_unhashed(struct hlist_node *h) +{ + return !h->pprev; +} + +static __inline__ int hlist_empty(struct hlist_head *h) +{ + return !h->first; +} + +static __inline__ void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static __inline__ void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +static __inline__ void hlist_del_init(struct hlist_node *n) +{ + if (n->pprev) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +static __inline__ void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +static __inline__ void hlist_add_before(struct hlist_node *n, struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static __inline__ void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + *(next->pprev) = n; + n->next = next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +/* Cannot easily do prefetch unfortunately */ +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; n = pos ? pos->next : 0, pos; \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + +#endif diff --git a/src/core/librcscripts/api/misc.h b/src/core/librcscripts/api/misc.h new file mode 100644 index 0000000..effaa50 --- /dev/null +++ b/src/core/librcscripts/api/misc.h @@ -0,0 +1,106 @@ +/* + * misc.h + * + * Miscellaneous macro's and functions. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#ifndef __MISC_H__ +#define __MISC_H__ + +#include <stdio.h> + +#include "config.h" + +/* Gentoo style e* printing macro's */ +#define EINFO(_args...) \ + do { \ + save_errno (); \ + printf (" \033[32;01m*\033[0m " _args); \ + restore_errno (); \ + } while (0) + +#define EWARN(_args...) \ + do { \ + save_errno (); \ + printf (" \033[33;01m*\033[0m " _args); \ + restore_errno (); \ + } while (0) + +#define EERROR(_args...) \ + do { \ + save_errno (); \ + fprintf (stderr, " \033[31;01m*\033[0m " _args); \ + restore_errno (); \ + } while (0) + +/* Return true if filename '_name' ends in '_ext' */ +#define CHECK_FILE_EXTENSION(_name, _ext) \ + ((check_str (_name)) && (check_str (_ext)) \ + && (strlen (_name) > strlen (_ext)) \ + && (0 == strncmp (&(_name[strlen(_name) - strlen(_ext)]), \ + _ext, strlen(_ext)))) + +/* String functions. Return a string on success, or NULL on error + * or no action taken. On error errno will be set.*/ +char *memrepchr (char **str, char old, char _new, size_t size); +/* Concat two paths adding '/' if needed. Memory will be allocated + * with the malloc() call. */ +char *strcatpaths (const char *pathname1, const char *pathname2); + +/* Compat functions for GNU extensions */ +char *strndup (const char *str, size_t size); +/* Same as basename(3), but do not modify path */ +char *gbasename (const char *path); + +/* The following functions do not care about errors - they only return + * 1 if 'pathname' exist, and is the type requested, or else 0. + * This is only if pathname is valid ... They also might clear errno */ +int exists (const char *pathname); +int is_file (const char *pathname, int follow_link); +int is_link (const char *pathname); +int is_dir (const char *pathname, int follow_link); + +/* The following function do not care about errors - it only returns + * the mtime of 'pathname' if it exists, and is the type requested, + * or else 0. It also might clear errno */ +time_t get_mtime (const char *pathname, int follow_link); + +/* The following functions return 0 on success, or -1 with errno set on error. */ +#if !defined(HAVE_REMOVE) +int remove (const char *pathname); +#endif +int mktree (const char *pathname, mode_t mode); +int rmtree (const char *pathname); + +/* The following return a pointer on success, or NULL with errno set on error. + * If it returned NULL, but errno is not set, then there was no error, but + * there is nothing to return. */ +char **ls_dir (const char *pathname, int hidden); +char *get_cnf_entry (const char *pathname, const char *entry); + +/* Below three functions (file_map, file_unmap and buf_get_line) are from + * udev-050 (udev_utils.c). Please see misc.c for copyright info. + * (Some are slightly modified, please check udev for originals.) */ +int file_map (const char *filename, char **buf, size_t * bufsize); +void file_unmap (char *buf, size_t bufsize); +size_t buf_get_line (char *buf, size_t buflen, size_t cur); + +#endif /* __MISC_H__ */ diff --git a/src/core/librcscripts/api/parse.h b/src/core/librcscripts/api/parse.h new file mode 100644 index 0000000..911793c --- /dev/null +++ b/src/core/librcscripts/api/parse.h @@ -0,0 +1,84 @@ +/* + * parse.h + * + * Parser for Gentoo style rc-scripts. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#ifndef __PARSE_H__ +#define __PARSE_H__ + +#define LEGACY_CACHE_FILE_NAME "deptree" + +#define FIELD_RCSCRIPT "RCSCRIPT" +#define FIELD_NEED "NEED" +#define FIELD_USE "USE" +#define FIELD_BEFORE "BEFORE" +#define FIELD_AFTER "AFTER" +#define FIELD_PROVIDE "PROVIDE" +#define FIELD_FAILED "FAILED" + +size_t generate_stage1 (dyn_buf_t * data); +size_t generate_stage2 (dyn_buf_t * data); +size_t read_stage2 (char **data); +int write_stage2 (FILE * outfile); +size_t generate_stage3 (char **data); +size_t read_stage3 (char **data); +int write_stage3 (FILE * outfile); +int write_legacy_stage3 (FILE * output); +int parse_cache (const dyn_buf_t * data); + +/* + * get_rcscripts() + * | + * V + * check_rcscripts_mtime() ------------------------------> read_stage3() + * | | + * | | + * V V + * generate_stage1() (Called by generate_stage2()) parse_cache() + * | | + * | | + * V | + * generate_stage2() ----> write_stage2() (Debugging) | + * | | + * | | + * | === parse_cache() | + * V | | | + * generate_stage3() ==| | | + * | | | | + * | | V | + * | === service_resolve_dependencies() | + * | | + * | | + * |-------> write_legacy_stage3() (Proof of Concept | + * | or Debugging) | + * | | + * V | + * write_stage3() | + * | | + * | V + * |<------------------------------------------------------- + * | + * V + * + */ + +#endif /* __PARSE_H__ */ diff --git a/src/core/librcscripts/api/rctypes.h b/src/core/librcscripts/api/rctypes.h new file mode 100644 index 0000000..6efab4a --- /dev/null +++ b/src/core/librcscripts/api/rctypes.h @@ -0,0 +1,43 @@ +/* + * rctypes.h + * + * Misc types and macro's. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#ifndef __RCTYPES_H__ +#define __RCTYPES_H__ + +/* Min/Max macro's */ +#ifdef MAX +# undef MAX +#endif +#define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) +#ifdef MIN +# undef MIN +#endif +#define MIN(_a, _b) ((_a) > (_b) ? (_b) : (_a)) + +typedef enum { + FALSE, + TRUE +} bool; + +#endif /* __RCTYPES_H__ */ diff --git a/src/core/librcscripts/api/runlevels.h b/src/core/librcscripts/api/runlevels.h new file mode 100644 index 0000000..59906af --- /dev/null +++ b/src/core/librcscripts/api/runlevels.h @@ -0,0 +1,44 @@ +/* + * runlevels.h + * + * Functions dealing with runlevels. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#ifndef __RUNLEVELS_H__ +#define __RUNLEVELS_H__ + +typedef struct +{ + struct list_head node; + + char *dirname; /* Name of this runlevel */ + struct list_head entries; /* rcscript_info_t list of rc-scripts */ +} runlevel_info_t; + +struct list_head runlevel_list; + +int get_runlevels (void); + +runlevel_info_t * get_runlevel_info (const char *runlevel); + +bool is_runlevel (const char *runlevel); + +#endif /* __RUNLEVELS_H__ */ diff --git a/src/core/librcscripts/api/scripts.h b/src/core/librcscripts/api/scripts.h new file mode 100644 index 0000000..75003b4 --- /dev/null +++ b/src/core/librcscripts/api/scripts.h @@ -0,0 +1,43 @@ +/* + * scripts.h + * + * Get info etc for Gentoo style rc-scripts. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#ifndef __SCRIPTS_H__ +#define __SCRIPTS_H__ + +typedef struct +{ + struct list_head node; + + char *filename; + time_t mtime; + time_t confd_mtime; +} rcscript_info_t; + +struct list_head rcscript_list; + +int get_rcscripts (void); +int check_rcscripts_mtime (const char *cachefile); +rcscript_info_t *get_rcscript_info (const char *scriptname); + +#endif /* __SCRIPTS_H__ */ diff --git a/src/core/librcscripts/api/simple-regex.h b/src/core/librcscripts/api/simple-regex.h new file mode 100644 index 0000000..1ae746f --- /dev/null +++ b/src/core/librcscripts/api/simple-regex.h @@ -0,0 +1,87 @@ +/* + * simple_regex.h + * + * Simle regex library. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#ifndef __SIMPLE_REGEX_H__ +#define __SIMPLE_REGEX_H__ + +#define REGEX_NO_MATCH 0 /* We have no match */ +#define REGEX_PARTIAL_MATCH 1 /* Some of the string matches the regex */ +#define REGEX_FULL_MATCH 2 /* The whole string matches the regex */ + +/* Macro to fill in .data and .regex */ +#define FILL_REGEX_DATA(_regex_data, _string, _regex) \ + do { \ + _regex_data.data = _string; \ + _regex_data.regex = _regex; \ + } while (0) + +/* Fill in _regex_data with _data and _regex, on failure goto _error */ +#define DO_REGEX(_regex_data, _data, _regex, _error) \ + do { \ + FILL_REGEX_DATA(_regex_data, _data, _regex); \ + if (-1 == match(&_regex_data)) \ + { \ + DBG_MSG("Could not do regex match!\n"); \ + goto _error; \ + } \ + } while (0) + +/* Evaluate to true if we have some kind of match */ +#define REGEX_MATCH(_regex_data) \ + ((REGEX_FULL_MATCH == _regex_data.match) \ + || (REGEX_PARTIAL_MATCH == _regex_data.match)) + +/* Same as above, but for use when _regex_data is a pointer */ +#define REGEX_MATCH_P(_regex_data) \ + ((REGEX_FULL_MATCH == _regex_data->match) \ + || (REGEX_PARTIAL_MATCH == _regex_data->match)) + +typedef struct +{ + char *data; /* String to perform regex operation on */ + char *regex; /* String containing regex to use */ + int match; /* Will be set if there was a match. Check + * REGEX_*_MATCH above for possible values */ + char *where; /* Pointer to where match starts in data */ + size_t count; /* Count characters from data matched by regex */ + size_t r_count; /* Count characters of regex used for match. This + * should normally be the lenght of regex, but might + * not be for some internal functions ... */ +} regex_data_t; + +/* + * Return: + * + * 0 - There was no error. If there was a match, regex_data->match + * - will be > 0 (this is the definitive check - if not true, the + * - other values of the struct may be bogus), regex_data->count + * - will be the amount of data that was matched (might be 0 for + * - some wildcards), and regex_data->r_count will be > 0. + * + * -1 - An error occured. Check errno for more info. + * + */ +int match (regex_data_t * regex_data); + +#endif /* __SIMPLE_REGEX_H__ */ diff --git a/src/core/librcscripts/api/str_list.h b/src/core/librcscripts/api/str_list.h new file mode 100644 index 0000000..538ab82 --- /dev/null +++ b/src/core/librcscripts/api/str_list.h @@ -0,0 +1,212 @@ +/* + * str_list.h + * + * String list macros. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#ifndef __STR_LIST_H__ +#define __STR_LIST_H__ + +/* Add a new item to a string list. If the pointer to the list is NULL, + * allocate enough memory for the amount of entries needed. Ditto for + * when it already exists, but we add one more entry than it can + * contain. The list is NULL terminated. + * NOTE: _only_ memory for the list are allocated, and not for the items - that + * should be done by relevant code (unlike str_list_del_item() that will + * free the memory) */ +#define str_list_add_item(_string_list, _item, _error) \ + do { \ + char **_tmp_p; \ + int _i = 0; \ + if (!check_str (_item)) \ + { \ + goto _error; \ + } \ + while ((NULL != _string_list) && (NULL != _string_list[_i])) \ + { \ + _i++; \ + } \ + /* Amount of entries + new + terminator */ \ + _tmp_p = xrealloc (_string_list, sizeof (char *) * (_i + 2)); \ + if (NULL == _tmp_p) \ + { \ + goto _error; \ + } \ + _string_list = _tmp_p; \ + _string_list[_i] = _item; \ + /* Terminator */ \ + _string_list[_i+1] = NULL; \ + } while (0) + +/* Add a new item to a string list (foundamental the same as above), but make + * sure we have all the items alphabetically sorted. */ +#define str_list_add_item_sorted(_string_list, _item, _error) \ + do { \ + char **_tmp_p; \ + char *_str_p1; \ + char *_str_p2; \ + int _i = 0; \ + if (!check_str (_item)) \ + { \ + goto _error; \ + } \ + while ((NULL != _string_list) && (NULL != _string_list[_i])) \ + { \ + _i++; \ + } \ + /* Amount of entries + new + terminator */ \ + _tmp_p = xrealloc (_string_list, sizeof (char *) * (_i + 2)); \ + if (NULL == _tmp_p) \ + { \ + goto _error; \ + } \ + _string_list = _tmp_p; \ + if (0 == _i) \ + { \ + /* Needed so that the end NULL will propagate + * (iow, make sure our 'NULL != _str_p1' test below + * do not fail) */ \ + _string_list[_i] = NULL; \ + } \ + /* Actual terminator that needs adding */ \ + _string_list[_i+1] = NULL; \ + _i = 0; \ + /* See where we should insert the new item to have it all \ + * alphabetically sorted */ \ + while (NULL != _string_list[_i]) \ + { \ + if (strcmp (_string_list[_i], _item) > 0) \ + { \ + break; \ + } \ + _i++; \ + } \ + /* Now just insert the new item, and shift the rest one over. + * '_str_p2' is temporary storage to swap the indexes in a loop, + * and 'str_p1' is used to store the old value across the loop */ \ + _str_p1 = _string_list[_i]; \ + _string_list[_i] = _item; \ + do { \ + _i++;\ + _str_p2 = _string_list[_i]; \ + _string_list[_i] = _str_p1; \ + _str_p1 = _str_p2; \ + } while (NULL != _str_p1); \ + } while (0) + +/* Delete one entry from the string list, and shift the rest down if the entry + * was not at the end. For now we do not resize the amount of entries the + * string list can contain, and free the memory for the matching item */ +#define str_list_del_item(_string_list, _item, _error) \ + do { \ + int _i = 0; \ + if (!check_str (_item)) \ + { \ + goto _error; \ + } \ + if (NULL == _string_list) \ + { \ + errno = EINVAL; \ + DBG_MSG ("Invalid string list passed!\n"); \ + goto _error; \ + } \ + while (NULL != _string_list[_i]) \ + { \ + if (0 == strcmp (_item, _string_list[_i])) \ + { \ + break; \ + } \ + else \ + { \ + _i++; \ + } \ + } \ + if (NULL == _string_list[_i]) \ + { \ + errno = EINVAL; \ + DBG_MSG ("Invalid string list item passed!\n"); \ + goto _error; \ + } \ + free (_string_list[_i]); \ + /* Shift all the following items one forward */ \ + do { \ + _string_list[_i] = _string_list[_i+1]; \ + /* This stupidity is to shutup gcc */ \ + _i++; \ + } while (NULL != _string_list[_i]); \ + } while (0) + +/* Step through each entry in the string list, setting '_pos' to the + * beginning of the entry. '_counter' is used by the macro as index, + * but should not be used by code as index (or if really needed, then + * it should usually by +1 from what you expect, and should only be + * used in the scope of the macro) */ +#define str_list_for_each_item(_string_list, _pos, _counter) \ + if ((NULL != _string_list) && (0 == (_counter = 0))) \ + while (NULL != (_pos = _string_list[_counter++])) + +/* Same as above (with the same warning about '_counter'). Now we just + * have '_next' that are also used for indexing. Once again rather refrain + * from using it if not absolutely needed. The major difference to above, + * is that it should be safe from having the item removed from under you. */ +#define str_list_for_each_item_safe(_string_list, _pos, _next, _counter) \ + if ((NULL != _string_list) && (0 == (_counter = 0))) \ + /* First part of the while checks if this is the + * first loop, and if so setup _pos and _next + * and increment _counter */ \ + while ((((0 == _counter) \ + && (NULL != (_pos = _string_list[_counter])) \ + && (_pos != (_next = _string_list[++_counter]))) \ + /* Second part is when it is not the first loop + * and _pos was not removed from under us. We + * just increment _counter, and setup _pos and + * _next */ \ + || ((0 != _counter) \ + && (_pos == _string_list[_counter-1]) \ + && (_next == _string_list[_counter]) \ + && (NULL != (_pos = _string_list[_counter])) \ + && (_pos != (_next = _string_list[++_counter]))) \ + /* Last part is when _pos was removed from under + * us. We basically just setup _pos and _next, + * but leave _counter alone */ \ + || ((0 != _counter) \ + && (_pos != _string_list[_counter-1]) \ + && (_next == _string_list[_counter-1]) \ + && (NULL != (_pos = _string_list[_counter-1])) \ + && (_pos != (_next = _string_list[_counter]))))) + +/* Just free the whole string list */ +#define str_list_free(_string_list) \ + do { \ + if (NULL != _string_list) \ + { \ + int _i = 0; \ + while (NULL != _string_list[_i]) \ + { \ + free (_string_list[_i]); \ + _string_list[_i++] = NULL; \ + } \ + free (_string_list); \ + _string_list = NULL; \ + } \ + } while (0) + +#endif /* __STR_LIST_H__ */ diff --git a/src/core/librcscripts/debug.c b/src/core/librcscripts/debug.c new file mode 100644 index 0000000..959ddf9 --- /dev/null +++ b/src/core/librcscripts/debug.c @@ -0,0 +1,297 @@ +/* + * debug.c + * + * Simle debugging/logging macro's and functions. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#include "rcscripts.h" + +static char log_domain[] = "rcscripts"; + +void +debug_message (const char *file, const char *func, int line, + const char *format, ...) +{ + va_list arg; + char *format_str; + int length; + + save_errno (); + + length = strlen (log_domain) + strlen ("(): ") + 1; + /* Do not use xmalloc() here, else we may have recursive issues */ + format_str = malloc (length); + if (NULL == format_str) + { + fprintf (stderr, "(%s) error: in %s, function %s(), line %i:\n", + log_domain, __FILE__, __FUNCTION__, __LINE__); + fprintf (stderr, "(%s) Failed to allocate buffer!\n", + log_domain); + abort (); + } + + snprintf (format_str, length, "(%s) ", log_domain); + + va_start (arg, format); + +#if !defined(RC_DEBUG) + /* Bit of a hack, as how we do things tend to cause seek + * errors when reading the parent/child pipes */ + /* if ((0 != errno) && (ESPIPE != errno)) { */ + if (0 != saved_errno) + { +#endif + if (0 != saved_errno) + fprintf (stderr, "(%s) error: ", log_domain); + else + fprintf (stderr, "(%s) debug: ", log_domain); + + fprintf (stderr, "in %s, function %s(), line %i:\n", file, func, line); + + fprintf (stderr, "%s ", format_str); + vfprintf (stderr, format, arg); + +#if defined(RC_DEBUG) + if (0 != saved_errno) + { +#endif + perror (format_str); +#if defined(RC_DEBUG) + } +#endif +#if !defined(RC_DEBUG) + } +#endif + + va_end (arg); + + free (format_str); + restore_errno (); +} + +inline bool +check_ptr (const void *ptr) +{ + if (NULL == ptr) + return FALSE; + + return TRUE; +} + +inline bool +check_str (const char *str) +{ + if ((NULL == str) || (0 == strlen (str))) + return FALSE; + + return TRUE; +} + +inline bool +check_strv (char **str) +{ + if ((NULL == str) || (NULL == *str) || (0 == strlen (*str))) + return FALSE; + + return TRUE; +} + +inline bool +check_fd (int fd) +{ + if ((0 >= fd) || (-1 == fcntl (fd, F_GETFL))) + return FALSE; + + return TRUE; +} + +inline bool +check_fp (FILE *fp) +{ + if ((NULL == fp) || (-1 == fileno (fp))) + return FALSE; + + return TRUE; +} + +inline bool +__check_arg_ptr (const void *ptr, const char *file, const char *func, size_t line) +{ + if (!check_ptr (ptr)) + { + errno = EINVAL; + + debug_message (file, func, line, "Invalid pointer passed!\n"); + + return FALSE; + } + + return TRUE; +} + +inline bool +__check_arg_str (const char *str, const char *file, const char *func, size_t line) +{ + if (!check_str (str)) + { + errno = EINVAL; + + debug_message (file, func, line, "Invalid string passed!\n"); + + return FALSE; + } + + return TRUE; +} + +inline bool +__check_arg_strv (char **str, const char *file, const char *func, size_t line) +{ + if (!check_strv (str)) + { + errno = EINVAL; + + debug_message (file, func, line, "Invalid string array passed!\n"); + + return FALSE; + } + + return TRUE; +} + +inline bool +__check_arg_fd (int fd, const char *file, const char *func, size_t line) +{ + if (!check_fd (fd)) + { + errno = EBADF; + + debug_message (file, func, line, "Invalid file descriptor passed!\n"); + + return FALSE; + } + + return TRUE; +} + +inline bool +__check_arg_fp (FILE *fp, const char *file, const char *func, size_t line) +{ + if (!check_fp (fp)) + { + errno = EBADF; + + debug_message (file, func, line, "Invalid file descriptor passed!\n"); + + return FALSE; + } + + return TRUE; +} + +inline void * +__xcalloc(size_t nmemb, size_t size, const char *file, + const char *func, size_t line) +{ + void *new_ptr; + + new_ptr = calloc (nmemb, size); + if (NULL == new_ptr) + { + /* Set errno in case specific malloc() implementation does not */ + errno = ENOMEM; + + debug_message (file, func, line, "Failed to allocate buffer!\n"); + + return NULL; + } + + return new_ptr; +} + +inline void * +__xmalloc (size_t size, const char *file, const char *func, size_t line) +{ + void *new_ptr; + + new_ptr = malloc (size); + if (NULL == new_ptr) + { + /* Set errno in case specific malloc() implementation does not */ + errno = ENOMEM; + + debug_message (file, func, line, "Failed to allocate buffer!\n"); + + return NULL; + } + + return new_ptr; +} + +inline void * +__xrealloc (void *ptr, size_t size, const char *file, + const char *func, size_t line) +{ + void *new_ptr; + + new_ptr = realloc (ptr, size); + if (NULL == new_ptr) + { + /* Set errno in case specific realloc() implementation does not */ + errno = ENOMEM; + + debug_message (file, func, line, "Failed to reallocate buffer!\n"); + + return NULL; + } + + return new_ptr; +} + +inline char * +__xstrndup (const char *str, size_t size, const char *file, + const char *func, size_t line) +{ + char *new_ptr; + + new_ptr = strndup (str, size); + if (NULL == new_ptr) + { + /* Set errno in case specific realloc() implementation does not */ + errno = ENOMEM; + + debug_message (file, func, line, + "Failed to duplicate string via strndup() !\n"); + + return NULL; + } + + return new_ptr; +} + diff --git a/src/core/librcscripts/debug.h b/src/core/librcscripts/debug.h index 997e92f..e69de29 100644 --- a/src/core/librcscripts/debug.h +++ b/src/core/librcscripts/debug.h @@ -1,85 +0,0 @@ -/* - * debug.h - * - * Simle debugging/logging macro's and functions. - * - * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> - * - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Header$ - */ - -#ifndef _DEBUG_H -#define _DEBUG_H - -#if defined(RC_DEBUG) -# define DBG_MSG(_format, _arg...) \ - do { \ - int old_errno = errno; \ - fprintf(stderr, "DEBUG(1): in %s, function %s(), line %i:\n", __FILE__, \ - __FUNCTION__, __LINE__); \ - fprintf(stderr, "DEBUG(2): " _format, ## _arg); \ - errno = old_errno; \ - if (0 != errno) { \ - perror("DEBUG(3)"); \ - /* perror() for some reason sets errno to ESPIPE */ \ - errno = old_errno; \ - } \ - } while (0) -#else -# define DBG_MSG(_format, _arg...) \ - do { \ - int old_errno = errno; \ - /* Bit of a hack, as how we do things tend to cause seek - * errors when reading the parent/child pipes */ \ - /* if ((0 != errno) && (ESPIPE != errno)) { */ \ - if (0 != errno) { \ - fprintf(stderr, "DEBUG(1): in %s, function %s(), line %i:\n", \ - __FILE__, __FUNCTION__, __LINE__); \ - fprintf(stderr, "DEBUG(2): " _format, ## _arg); \ - errno = old_errno; \ - perror("DEBUG(3)"); \ - /* perror() for some reason sets errno to ESPIPE */ \ - errno = old_errno; \ - } \ - } while (0) -#endif - -#define FATAL_ERROR() \ - do { \ - int old_errno = errno; \ - fprintf(stderr, "ERROR: file '%s', function '%s', line %i.\n", \ - __FILE__, __FUNCTION__, __LINE__); \ - errno = old_errno; \ - if (0 != errno) \ - perror("ERROR"); \ - exit(EXIT_FAILURE); \ - } while (0) - -#define NEG_FATAL_ERROR(_x) \ - do { \ - if (-1 == _x) \ - FATAL_ERROR(); \ - } while (0) - -#define NULL_FATAL_ERROR(_x) \ - do { \ - if (NULL == _x) \ - FATAL_ERROR(); \ - } while (0) - -#endif /* _DEBUG_H */ - diff --git a/src/core/librcscripts/depend.c b/src/core/librcscripts/depend.c index 4946326..c3a41c8 100644 --- a/src/core/librcscripts/depend.c +++ b/src/core/librcscripts/depend.c @@ -28,530 +28,645 @@ #include <stdio.h> #include <stdlib.h> -#include "debug.h" -#include "depend.h" -#include "list.h" -#include "misc.h" +#include "rcscripts.h" -LIST_HEAD(service_info_list); +LIST_HEAD (service_info_list); /* Names for service types (service_type_t) in depend.h. * Note that this should sync with service_type_t */ char *service_type_names[] = { - "NEED", - "NEED_ME", - "USE", - "USE_ME", - "BEFORE", - "AFTER", - "BROKEN", - "PROVIDE", - NULL + "NEED", + "NEED_ME", + "USE", + "USE_ME", + "BEFORE", + "AFTER", + "BROKEN", + "PROVIDE", + NULL }; -int __service_resolve_dependency(char *servicename, char *dependency, service_type_t type); +static char * +service_is_recursive_dependency (char *servicename, char *dependency, + bool checkuse); +static int __service_resolve_dependency (char *servicename, char *dependency, + service_type_t type); -service_info_t *service_get_info(char *servicename) +service_info_t * +service_get_info (char *servicename) { - service_info_t *info; + service_info_t *info; - if ((NULL == servicename) || (0 == strlen(servicename))) { - DBG_MSG("Invalid argument passed!\n"); - return NULL; - } - - list_for_each_entry(info, &service_info_list, node) { - if (NULL != info->name) - if (0 == strcmp(info->name, servicename)) - return info; - } + if (!check_arg_str (servicename)) + return NULL; + + list_for_each_entry (info, &service_info_list, node) + { + if (NULL != info->name) + if (0 == strcmp (info->name, servicename)) + return info; + } + + /* We use this to check if a service exists, so rather do not + * add debugging, otherwise it is very noisy! */ + /* DBG_MSG("Invalid service name '%s'!\n", servicename); */ - /* We use this to check if a service exists, so rather do not - * add debugging, otherwise it is very noisy! */ - /* DBG_MSG("Invalid service name '%s'!\n", servicename); */ - - return NULL; + return NULL; } -int service_add(char *servicename) +int +service_add (char *servicename) { - service_info_t *info; - service_info_t *sorted; - int count; - - if ((NULL == servicename) || (0 == strlen(servicename))) { - DBG_MSG("Invalid argument passed!\n"); - return -1; - } + service_info_t *info; + service_info_t *sorted; + int count; - info = service_get_info(servicename); - if (NULL == info) { - DBG_MSG("Adding service '%s'.\n", servicename); - - info = malloc(sizeof(service_info_t)); - if (NULL == info) { - DBG_MSG("Failed to allocate service_info_t!\n"); - return -1; - } - - info->name = strndup(servicename, strlen(servicename)); - if (NULL == info->name) { - DBG_MSG("Failed to allocate buffer!\n"); - free(info); - return -1; - } - - for (count = 0; count < ALL_SERVICE_TYPE_T; count++) - info->depend_info[count] = NULL; - info->provide = NULL; - - /* We want to keep the list sorted */ - list_for_each_entry(sorted, &service_info_list, node) { - if (strcmp(sorted->name, servicename) > 0) { - break; - } - } - - list_add_tail(&info->node, &sorted->node); - - return 0; - } else { - DBG_MSG("Tried to add duplicate service '%s'!\n", servicename); - } - + if (!check_arg_str (servicename)) + return -1; + + info = service_get_info (servicename); + if (NULL == info) + { + DBG_MSG ("Adding service '%s'.\n", servicename); + + info = xmalloc (sizeof (service_info_t)); + if (NULL == info) return -1; -} -int service_is_dependency(char *servicename, char *dependency, service_type_t type) -{ - service_info_t *info; - char *service; - int count = 0; - - if ((NULL == servicename) - || (0 == strlen(servicename)) - || (NULL == dependency) - || (0 == strlen(dependency))) { - DBG_MSG("Invalid argument passed!\n"); - return -1; + info->name = xstrndup (servicename, strlen (servicename)); + if (NULL == info->name) + { + free (info); + return -1; } - info = service_get_info(servicename); - if (NULL != info) { - STRING_LIST_FOR_EACH(info->depend_info[type], service, count) { - if (0 == strcmp(dependency, service)) - return 0; - } - } else { - DBG_MSG("Invalid service name '%s'!\n", servicename); + for (count = 0; count < ALL_SERVICE_TYPE_T; count++) + info->depend_info[count] = NULL; + info->provide = NULL; + + /* We want to keep the list sorted */ + list_for_each_entry (sorted, &service_info_list, node) + { + if (strcmp (sorted->name, servicename) > 0) + { + break; + } } - - return -1; + + list_add_tail (&info->node, &sorted->node); + + return 0; + } + else + { + DBG_MSG ("Tried to add duplicate service '%s'!\n", servicename); + } + + return -1; } -int service_add_dependency(char *servicename, char *dependency, service_type_t type) +int +service_is_dependency (char *servicename, char *dependency, + service_type_t type) { - service_info_t *info; - char *tmp_buf; - - if ((NULL == servicename) - || (0 == strlen(servicename)) - || (NULL == dependency) - || (0 == strlen(dependency))) { - DBG_MSG("Invalid argument passed!\n"); - return -1; + service_info_t *info; + char *service; + int count = 0; + + if ((!check_arg_str (servicename)) || (!check_arg_str (dependency))) + return -1; + + info = service_get_info (servicename); + if (NULL != info) + { + str_list_for_each_item (info->depend_info[type], service, count) + { + if (0 == strcmp (dependency, service)) + return 0; } + } + else + { + DBG_MSG ("Invalid service name '%s'!\n", servicename); + } - info = service_get_info(servicename); - if (NULL != info) { - /* Do not add duplicates */ - if (-1 == service_is_dependency(servicename, dependency, type)) { - DBG_MSG("Adding dependency '%s' of service '%s', type '%s'.\n", - dependency, servicename, service_type_names[type]); - - tmp_buf = strndup(dependency, strlen(dependency)); - if (NULL == tmp_buf) { - DBG_MSG("Failed to allocate buffer!\n"); - return -1; - } - - STRING_LIST_ADD_SORT(info->depend_info[type], tmp_buf, error); - } else { - DBG_MSG("Duplicate dependency '%s' for service '%s', type '%s'!\n", - dependency, servicename, service_type_names[type]); - /* Rather do not fail here, as we add a lot of doubles - * during resolving of dependencies */ - } - - return 0; - } else { - DBG_MSG("Invalid service name '%s'!\n", servicename); - } - -error: - return -1; + return -1; } -int service_del_dependency(char *servicename, char *dependency, service_type_t type) +char * +service_is_recursive_dependency (char *servicename, char *dependency, + bool checkuse) { - service_info_t *info; - - if ((NULL == servicename) - || (0 == strlen(servicename)) - || (NULL == dependency) - || (0 == strlen(dependency))) { - DBG_MSG("Invalid argument passed!\n"); - return -1; + service_info_t *info; + char *depend; + int count = 0; + + if ((!check_arg_str (servicename)) || (!check_arg_str (dependency))) + return NULL; + + info = service_get_info (dependency); + if (NULL != info) + { + str_list_for_each_item (info->depend_info[NEED_ME], depend, count) + { + if ((0 == service_is_dependency (servicename, depend, NEED)) + || (0 == service_is_dependency (servicename, depend, USE))) + return depend; } - - if (-1 == service_is_dependency(servicename, dependency, type)) { - DBG_MSG("Tried to remove invalid dependency '%s'!\n", dependency); - return -1; + if (checkuse) + { + str_list_for_each_item (info->depend_info[USE_ME], depend, count) + { + if ((0 == service_is_dependency (servicename, depend, NEED)) + || (0 == service_is_dependency (servicename, depend, USE))) + return depend; + } } + } + else + { + DBG_MSG ("Invalid service name '%s'!\n", servicename); + } - info = service_get_info(servicename); - if (NULL != info) { - DBG_MSG("Removing dependency '%s' of service '%s', type '%s'.\n", - dependency , servicename, service_type_names[type]); + return NULL; +} - STRING_LIST_DEL(info->depend_info[type], dependency, error); - return 0; - } else { - DBG_MSG("Invalid service name '%s'!\n", servicename); +int +service_add_dependency (char *servicename, char *dependency, + service_type_t type) +{ + service_info_t *info; + char *tmp_buf; + + if ((!check_arg_str (servicename)) || (!check_arg_str (dependency))) + return -1; + + info = service_get_info (servicename); + if (NULL != info) + { + /* Do not add duplicates */ + if (-1 == service_is_dependency (servicename, dependency, type)) + { + DBG_MSG ("Adding dependency '%s' of service '%s', type '%s'.\n", + dependency, servicename, service_type_names[type]); + + tmp_buf = xstrndup (dependency, strlen (dependency)); + if (NULL == tmp_buf) + return -1; + + str_list_add_item_sorted (info->depend_info[type], tmp_buf, error); } + else + { + DBG_MSG ("Duplicate dependency '%s' for service '%s', type '%s'!\n", + dependency, servicename, service_type_names[type]); + /* Rather do not fail here, as we add a lot of doubles + * during resolving of dependencies */ + } + + return 0; + } + else + { + DBG_MSG ("Invalid service name '%s'!\n", servicename); + } error: - return -1; + return -1; } -service_info_t *service_get_virtual(char *virtual) +int +service_del_dependency (char *servicename, char *dependency, + service_type_t type) { - service_info_t *info; - - if ((NULL == virtual) || (0 == strlen(virtual))) { - DBG_MSG("Invalid argument passed!\n"); - return NULL; - } - - list_for_each_entry(info, &service_info_list, node) { - if (NULL != info->provide) - if (0 == strcmp(info->provide, virtual)) - return info; - } - - /* We use this to check if a virtual exists, so rather do not - * add debugging, otherwise it is very noisy! */ - /* DBG_MSG("Invalid service name '%s'!\n", virtual); */ - - return NULL; + service_info_t *info; + + if ((!check_arg_str (servicename)) || (!check_arg_str (dependency))) + return -1; + + if (-1 == service_is_dependency (servicename, dependency, type)) + { + DBG_MSG ("Tried to remove invalid dependency '%s'!\n", dependency); + return -1; + } + + info = service_get_info (servicename); + if (NULL != info) + { + DBG_MSG ("Removing dependency '%s' of service '%s', type '%s'.\n", + dependency, servicename, service_type_names[type]); + + str_list_del_item (info->depend_info[type], dependency, error); + return 0; + } + else + { + DBG_MSG ("Invalid service name '%s'!\n", servicename); + } + +error: + return -1; } -int service_add_virtual(char *servicename, char* virtual) +service_info_t * +service_get_virtual (char *virtual) { - service_info_t *info; - - if ((NULL == servicename) - || (0 == strlen(servicename)) - || (NULL == virtual ) - || (0 == strlen(virtual))) { - DBG_MSG("Invalid argument passed!\n"); - return -1; - } + service_info_t *info; - if (NULL != service_get_info(virtual)) { - EERROR(" Cannot add provide '%s', as a service with the same name exists!\n", - virtual); - /* Do not fail here as we do have a service that resolves - * the virtual */ - } + if (!check_arg_str (virtual)) + return NULL; + + list_for_each_entry (info, &service_info_list, node) + { + if (NULL != info->provide) + if (0 == strcmp (info->provide, virtual)) + return info; + } + + /* We use this to check if a virtual exists, so rather do not + * add debugging, otherwise it is very noisy! */ + /* DBG_MSG("Invalid service name '%s'!\n", virtual); */ + + return NULL; +} - info = service_get_virtual(virtual); - if (NULL != info) { - /* We cannot have more than one service Providing a virtual */ - EWARN(" Service '%s' already provides '%s'!;\n", - info->name, virtual); - EWARN(" Not adding service '%s'...\n", servicename); - /* Do not fail here as we do have a service that resolves - * the virtual */ - } else { - info = service_get_info(servicename); - if (NULL != info) { - DBG_MSG("Adding virtual '%s' of service '%s'.\n", - virtual, servicename); - - info->provide = strndup(virtual, strlen(virtual)); - if (NULL == info->provide) { - DBG_MSG("Failed to allocate buffer!\n"); - return -1; - } - } else { - DBG_MSG("Invalid service name '%s'!\n", servicename); - return -1; - } +int +service_add_virtual (char *servicename, char *virtual) +{ + service_info_t *info; + + if ((!check_arg_str (servicename)) || (!check_arg_str (virtual))) + return -1; + + if (NULL != service_get_info (virtual)) + { + EERROR + (" Cannot add provide '%s', as a service with the same name exists!\n", + virtual); + /* Do not fail here as we do have a service that resolves + * the virtual */ + } + + info = service_get_virtual (virtual); + if (NULL != info) + { + /* We cannot have more than one service Providing a virtual */ + EWARN (" Service '%s' already provides '%s'!;\n", info->name, virtual); + EWARN (" Not adding service '%s'...\n", servicename); + /* Do not fail here as we do have a service that resolves + * the virtual */ + } + else + { + info = service_get_info (servicename); + if (NULL != info) + { + DBG_MSG ("Adding virtual '%s' of service '%s'.\n", + virtual, servicename); + + info->provide = xstrndup (virtual, strlen (virtual)); + if (NULL == info->provide) + return -1; + } + else + { + DBG_MSG ("Invalid service name '%s'!\n", servicename); + return -1; } + } - return 0; + return 0; } -int service_set_mtime(char *servicename, time_t mtime) +int +service_set_mtime (char *servicename, time_t mtime) { - service_info_t *info; + service_info_t *info; - if ((NULL == servicename) || (0 == strlen(servicename))) { - DBG_MSG("Invalid argument passed!\n"); - return -1; - } + if (!check_arg_str (servicename)) + return -1; - info = service_get_info(servicename); - if (NULL != info) { - DBG_MSG("Setting mtime '%li' of service '%s'.\n", - mtime, servicename); - - info->mtime = mtime; + info = service_get_info (servicename); + if (NULL != info) + { + DBG_MSG ("Setting mtime '%li' of service '%s'.\n", mtime, servicename); - return 0; - } else { - DBG_MSG("Invalid service name '%s'!\n", servicename); - } - - return -1; + info->mtime = mtime; + + return 0; + } + else + { + DBG_MSG ("Invalid service name '%s'!\n", servicename); + } + + return -1; } -int __service_resolve_dependency(char *servicename, char *dependency, service_type_t type) +int +__service_resolve_dependency (char *servicename, char *dependency, + service_type_t type) { - service_info_t *info; - int retval; - - if ((NULL == servicename) - || (0 == strlen(servicename)) - || (NULL == dependency) - || (0 == strlen(dependency))) { - DBG_MSG("Invalid argument passed!\n"); - return -1; + service_info_t *info; + int retval; + + if ((!check_arg_str (servicename)) || (!check_arg_str (dependency))) + return -1; + + info = service_get_info (servicename); + if (NULL == info) + { + DBG_MSG ("Invalid service name passed!\n"); + return -1; + } + + DBG_MSG ("Checking dependency '%s' of service '%s', type '%s'.\n", + dependency, servicename, service_type_names[type]); + + /* If there are no existing service 'dependency', try to resolve + * possible virtual services */ + info = service_get_info (dependency); + if (NULL == info) + { + info = service_get_virtual (dependency); + if (NULL != info) + { + DBG_MSG ("Virtual '%s' -> '%s' for service '%s', type '%s'.\n", + dependency, info->name, servicename, + service_type_names[type]); + + retval = service_del_dependency (servicename, dependency, type); + if (-1 == retval) + { + DBG_MSG ("Failed to delete dependency!\n"); + return -1; + } + + /* Add the actual service name for the virtual */ + dependency = info->name; + retval = service_add_dependency (servicename, dependency, type); + if (-1 == retval) + { + DBG_MSG ("Failed to add dependency!\n"); + return -1; + } + } + } + + /* Handle 'need', as it is the only dependency type that should + * handle invalid database entries currently. */ + if (NULL == info) + { + if ((type == NEED) || (type == NEED_ME)) + { + EWARN (" Can't find service '%s' needed by '%s'; continuing...\n", + dependency, servicename); + + retval = service_add_dependency (servicename, dependency, BROKEN); + if (-1 == retval) + { + DBG_MSG ("Failed to add dependency!\n"); + return -1; + } + + /* Delete invalid entry */ + goto remove; } - info = service_get_info(servicename); - if (NULL == info) { - DBG_MSG("Invalid service name passed!\n"); - return -1; + /* For the rest, if the dependency is not 'net', just silently + * die without error. Should not be needed as we add a 'net' + * service manually before we start, but you never know ... */ + if (0 != strcmp (dependency, "net")) + { + /* Delete invalid entry */ + goto remove; + } + } + + /* Ugly bug ... if a service depends on itself, it creates a + * 'mini fork bomb' effect, and breaks things horribly ... */ + if (0 == strcmp (servicename, dependency)) + { + /* Dont work too well with the '*' before and after */ + if ((type != BEFORE) && (type != AFTER)) + EWARN (" Service '%s' can't depend on itself; continuing...\n", + servicename); + + /* Delete invalid entry */ + goto remove; + } + + /* Currently only these depend/order types are supported */ + if ((type == NEED) || (type == USE) || (type == BEFORE) || (type == AFTER)) + { + if (type == BEFORE) + { + char *depend; + + /* NEED and USE override BEFORE + * ('servicename' BEFORE 'dependency') */ + if ((0 == service_is_dependency (servicename, dependency, NEED)) + || (0 == service_is_dependency (servicename, dependency, USE))) + { + /* Delete invalid entry */ + goto remove; + } + + depend = service_is_recursive_dependency (servicename, dependency, + TRUE); + if (NULL != depend) + { + EWARN (" Service '%s' should be BEFORE service '%s', but '%s'\n", + servicename, dependency, depend); + EWARN (" needed by '%s', depends in return on '%s'!\n", + servicename, dependency); + + /* Delete invalid entry */ + goto remove; + } } - DBG_MSG("Checking dependency '%s' of service '%s', type '%s'.\n", - dependency, servicename, service_type_names[type]); - - /* If there are no existing service 'dependency', try to resolve - * possible virtual services */ - info = service_get_info(dependency); - if (NULL == info) { - info = service_get_virtual(dependency); - if (NULL != info) { - DBG_MSG("Virtual '%s' -> '%s' for service '%s', type '%s'.\n", - dependency, info->name, servicename, - service_type_names[type]); - - retval = service_del_dependency(servicename, dependency, type); - if (-1 == retval) { - DBG_MSG("Failed to delete dependency!\n"); - return -1; - } - - /* Add the actual service name for the virtual */ - dependency = info->name; - retval = service_add_dependency(servicename, dependency, type); - if (-1 == retval) { - DBG_MSG("Failed to add dependency!\n"); - return -1; - } - } + if (type == AFTER) + { + char *depend; + + /* NEED and USE override AFTER + * ('servicename' AFTER 'dependency') */ + if ((0 == service_is_dependency (dependency, servicename, NEED)) + || (0 == service_is_dependency (dependency, servicename, USE))) + { + /* Delete invalid entry */ + goto remove; + } + + depend = service_is_recursive_dependency (dependency, servicename, + TRUE); + if (NULL != depend) + { + EWARN (" Service '%s' should be AFTER service '%s', but '%s'\n", + servicename, dependency, depend); + EWARN (" needed by '%s', depends in return on '%s'!\n", + dependency, servicename); + + /* Delete invalid entry */ + goto remove; + } } - - /* Handle 'need', as it is the only dependency type that should - * handle invalid database entries currently. */ - if (NULL == info) { - if ((type == NEED) || (type == NEED_ME)) { - EWARN(" Can't find service '%s' needed by '%s'; continuing...\n", - dependency, servicename); - - retval = service_add_dependency(servicename, dependency, BROKEN); - if (-1 == retval) { - DBG_MSG("Failed to add dependency!\n"); - return -1; - } - - /* Delete invalid entry */ - goto remove; - } - - /* For the rest, if the dependency is not 'net', just silently - * die without error. Should not be needed as we add a 'net' - * service manually before we start, but you never know ... */ - if (0 != strcmp(dependency, "net")) { - /* Delete invalid entry */ - goto remove; - } + + /* We do not want to add circular dependencies ... */ + if (0 == service_is_dependency (dependency, servicename, type)) + { + EWARN (" Services '%s' and '%s' have circular\n", + servicename, dependency); + EWARN (" dependency of type '%s'; continuing...\n", + service_type_names[type]); + + /* For now remove this dependency */ + goto remove; } - /* Ugly bug ... if a service depends on itself, it creates a - * 'mini fork bomb' effect, and breaks things horribly ... */ - if (0 == strcmp(servicename, dependency)) { - /* Dont work too well with the '*' before and after */ - if ((type != BEFORE) && (type != AFTER)) - EWARN(" Service '%s' can't depend on itself; continuing...\n", - servicename); + /* Reverse mapping */ + if (type == NEED) + { + retval = service_add_dependency (dependency, servicename, NEED_ME); + if (-1 == retval) + { + DBG_MSG ("Failed to add dependency!\n"); + return -1; + } + } - /* Delete invalid entry */ - goto remove; + /* Reverse mapping */ + if (type == USE) + { + retval = service_add_dependency (dependency, servicename, USE_ME); + if (-1 == retval) + { + DBG_MSG ("Failed to add dependency!\n"); + return -1; + } } - /* Currently only these depend/order types are supported */ - if ((type == NEED) - || (type == USE) - || (type == BEFORE) - || (type == AFTER)) { - if (type == BEFORE) { - /* NEED and USE override BEFORE - * ('servicename' BEFORE 'dependency') */ - if ((0 == service_is_dependency(servicename, dependency, NEED)) - || (0 == service_is_dependency(servicename, dependency, USE))) { - /* Delete invalid entry */ - goto remove; - } - } - - if (type == AFTER) { - /* NEED and USE override AFTER - * ('servicename' AFTER 'dependency') */ - if ((0 == service_is_dependency(dependency, servicename, NEED)) - || (0 == service_is_dependency(dependency, servicename, USE))) { - /* Delete invalid entry */ - goto remove; - } - } - - /* We do not want to add circular dependencies ... */ - if (0 == service_is_dependency(dependency, servicename, type)) { - EWARN(" Services '%s' and '%s' have circular\n", - servicename, dependency); - EWARN(" dependency of type '%s'; continuing...\n", - service_type_names[type]); - - /* For now remove this dependency */ - goto remove; - } - - /* Reverse mapping */ - if (type == NEED) { - retval = service_add_dependency(dependency, servicename, NEED_ME); - if (-1 == retval) { - DBG_MSG("Failed to add dependency!\n"); - return -1; - } - } - - /* Reverse mapping */ - if (type == USE) { - retval = service_add_dependency(dependency, servicename, USE_ME); - if (-1 == retval) { - DBG_MSG("Failed to add dependency!\n"); - return -1; - } - } - - /* Reverse mapping */ - if (type == BEFORE) { - retval = service_add_dependency(dependency, servicename, AFTER); - if (-1 == retval) { - DBG_MSG("Failed to add dependency!\n"); - return -1; - } - } - - /* Reverse mapping */ - if (type == AFTER) { - retval = service_add_dependency(dependency, servicename, BEFORE); - if (-1 == retval) { - DBG_MSG("Failed to add dependency!\n"); - return -1; - } - } + /* Reverse mapping */ + if (type == BEFORE) + { + retval = service_add_dependency (dependency, servicename, AFTER); + if (-1 == retval) + { + DBG_MSG ("Failed to add dependency!\n"); + return -1; + } } - return 0; - -remove: - /* Delete invalid entry */ - DBG_MSG("Removing invalid dependency '%s' of service '%s', type '%s'.\n", - dependency, servicename, service_type_names[type]); - - retval = service_del_dependency(servicename, dependency, type); - if (-1 == retval) { - DBG_MSG("Failed to delete dependency!\n"); - return -1; + /* Reverse mapping */ + if (type == AFTER) + { + retval = service_add_dependency (dependency, servicename, BEFORE); + if (-1 == retval) + { + DBG_MSG ("Failed to add dependency!\n"); + return -1; + } } + } - /* Here we should not die with error */ - return 0; + return 0; + +remove: + /* Delete invalid entry */ + DBG_MSG ("Removing invalid dependency '%s' of service '%s', type '%s'.\n", + dependency, servicename, service_type_names[type]); + + retval = service_del_dependency (servicename, dependency, type); + if (-1 == retval) + { + DBG_MSG ("Failed to delete dependency!\n"); + return -1; + } + + /* Here we should not die with error */ + return 0; } -int service_resolve_dependencies(void) +int +service_resolve_dependencies (void) { - service_info_t *info; - char *service; - char *next = NULL; - int count; - - /* Add our 'net' service */ - if (NULL == service_get_info("net")) { - if (-1 == service_add("net")) { - DBG_MSG("Failed to add virtual!\n"); - return -1; - } - service_set_mtime("net", 0); + service_info_t *info; + char *service; + char *next = NULL; + int count; + + /* Add our 'net' service */ + if (NULL == service_get_info ("net")) + { + if (-1 == service_add ("net")) + { + DBG_MSG ("Failed to add virtual!\n"); + return -1; } - - /* Calculate all virtuals */ - list_for_each_entry(info, &service_info_list, node) { - STRING_LIST_FOR_EACH_SAFE(info->depend_info[PROVIDE], service, next, count) - if (-1 == service_add_virtual(info->name, service)) { - DBG_MSG("Failed to add virtual!\n"); - return -1; - } + service_set_mtime ("net", 0); + } + + /* Calculate all virtuals */ + list_for_each_entry (info, &service_info_list, node) + { + str_list_for_each_item_safe (info->depend_info[PROVIDE], service, next, + count) + { + if (-1 == service_add_virtual (info->name, service)) + { + DBG_MSG ("Failed to add virtual!\n"); + return -1; + } } - - /* Now do NEED, USE, BEFORE and AFTER */ - list_for_each_entry(info, &service_info_list, node) { - STRING_LIST_FOR_EACH_SAFE(info->depend_info[NEED], service, next, count) { - if (-1 == __service_resolve_dependency(info->name, service, NEED)) { - DBG_MSG("Failed to resolve dependency!\n"); - return -1; - } - } + } + + /* Now do NEED, USE, BEFORE and AFTER */ + list_for_each_entry (info, &service_info_list, node) + { + str_list_for_each_item_safe (info->depend_info[NEED], service, next, count) + { + if (-1 == __service_resolve_dependency (info->name, service, NEED)) + { + DBG_MSG ("Failed to resolve dependency!\n"); + return -1; + } } - list_for_each_entry(info, &service_info_list, node) { - STRING_LIST_FOR_EACH_SAFE(info->depend_info[USE], service, next, count) { - if (-1 == __service_resolve_dependency(info->name, service, USE)) { - DBG_MSG("Failed to resolve dependency!\n"); - return -1; - } - } + } + list_for_each_entry (info, &service_info_list, node) + { + str_list_for_each_item_safe (info->depend_info[USE], service, next, count) + { + if (-1 == __service_resolve_dependency (info->name, service, USE)) + { + DBG_MSG ("Failed to resolve dependency!\n"); + return -1; + } } - list_for_each_entry(info, &service_info_list, node) { - STRING_LIST_FOR_EACH_SAFE(info->depend_info[BEFORE], service, next, count) { - if (-1 == __service_resolve_dependency(info->name, service, BEFORE)) { - DBG_MSG("Failed to resolve dependency!\n"); - return -1; - } - } + } + list_for_each_entry (info, &service_info_list, node) + { + str_list_for_each_item_safe (info->depend_info[BEFORE], service, next, + count) + { + if (-1 == __service_resolve_dependency (info->name, service, BEFORE)) + { + DBG_MSG ("Failed to resolve dependency!\n"); + return -1; + } } - list_for_each_entry(info, &service_info_list, node) { - STRING_LIST_FOR_EACH_SAFE(info->depend_info[AFTER], service, next, count) { - if (-1 == __service_resolve_dependency(info->name, service, AFTER)) { - DBG_MSG("Failed to resolve dependency!\n"); - return -1; - } - } + } + list_for_each_entry (info, &service_info_list, node) + { + str_list_for_each_item_safe (info->depend_info[AFTER], service, next, count) + { + if (-1 == __service_resolve_dependency (info->name, service, AFTER)) + { + DBG_MSG ("Failed to resolve dependency!\n"); + return -1; + } } + } - return 0; + return 0; } - diff --git a/src/core/librcscripts/depend.h b/src/core/librcscripts/depend.h index 2a7ff77..e69de29 100644 --- a/src/core/librcscripts/depend.h +++ b/src/core/librcscripts/depend.h @@ -1,75 +0,0 @@ -/* - * depend.h - * - * Dependancy engine for Gentoo style rc-scripts. - * - * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> - * - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Header$ - */ - -#ifndef _DEPEND_H -#define _DEPEND_H - -#include <sys/types.h> -#include "list.h" - -/* Dependency types supported or still to be implemented */ -typedef enum { - NEED, /* All dependencies needed by specified service */ - NEED_ME, /* All dependencies that need specified service */ - USE, /* All dependencies used by specified service */ - USE_ME, /* All dependencies that use specified service */ - BEFORE, /* All services started before specified service */ - AFTER, /* All services started after specified service */ - BROKEN, /* All dependencies of type NEED missing for - specified service */ - PROVIDE, /* All virtual services provided by specified service */ - ALL_SERVICE_TYPE_T -} service_type_t; - -/* Names for above service types (service_type_t). - * Note that this should sync with above service_type_t */ -extern char *service_type_names[]; - -typedef struct { - struct list_head node; - - char *name; /* Name of service */ - char **depend_info[ALL_SERVICE_TYPE_T]; /* String lists for each service - type */ - char *provide; /* Name of virtual service it - provides. This is only valid - after we resolving - thus after - service_resolve_dependencies() */ - time_t mtime; /* Modification time of script */ -} service_info_t; - -struct list_head service_info_list; - -service_info_t *service_get_info(char *servicename); -int service_add(char *servicename); -int service_is_dependency(char *servicename, char *dependency, service_type_t type); -int service_add_dependency(char *servicename, char *dependency, service_type_t type); -int service_del_dependency(char *servicename, char *dependency, service_type_t type); -service_info_t *service_get_virtual(char *virtual); -int service_add_virtual(char *servicename, char* virtual); -int service_set_mtime(char *servicename, time_t mtime); -int service_resolve_dependencies(void); - -#endif /* _DEPEND_H */ - diff --git a/src/core/librcscripts/dynbuf.c b/src/core/librcscripts/dynbuf.c new file mode 100644 index 0000000..65e8a43 --- /dev/null +++ b/src/core/librcscripts/dynbuf.c @@ -0,0 +1,332 @@ +/* + * dynbuf.c + * + * Dynamic allocated buffers. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "rcscripts.h" + +static dyn_buf_t *reallocate_dyn_buf (dyn_buf_t * dynbuf, size_t needed); + +dyn_buf_t * +new_dyn_buf (void) +{ + dyn_buf_t *dynbuf = NULL; + + dynbuf = xmalloc (sizeof (dyn_buf_t)); + if (NULL == dynbuf) + return NULL; + + dynbuf->data = xmalloc (DYNAMIC_BUFFER_SIZE); + if (NULL == dynbuf->data) + { + free (dynbuf); + return NULL; + } + + dynbuf->length = DYNAMIC_BUFFER_SIZE; + dynbuf->rd_index = 0; + dynbuf->wr_index = 0; + + return dynbuf; +} + +dyn_buf_t * +reallocate_dyn_buf (dyn_buf_t * dynbuf, size_t needed) +{ + int len; + + if (!check_arg_dyn_buf (dynbuf)) + return NULL; + + len = sizeof (char) * (dynbuf->wr_index + needed + 1); + + if (dynbuf->length < len) + { + char *new_ptr; + + /* Increase size in chunks to minimize reallocations */ + if (len < (dynbuf->length + DYNAMIC_BUFFER_SIZE)) + len = dynbuf->length + DYNAMIC_BUFFER_SIZE; + + new_ptr = xrealloc (dynbuf->data, len); + if (NULL == new_ptr) + return NULL; + + dynbuf->data = new_ptr; + dynbuf->length = len; + } + + return dynbuf; +} + +void +free_dyn_buf (dyn_buf_t * dynbuf) +{ + if (NULL == dynbuf) + return; + + if (NULL != dynbuf->data) + { + free (dynbuf->data); + dynbuf->data = NULL; + } + + dynbuf->length = 0; + dynbuf->rd_index = 0; + dynbuf->wr_index = 0; + + free (dynbuf); + dynbuf = NULL; +} + +int +write_dyn_buf (dyn_buf_t * dynbuf, const char *buf, size_t length) +{ + int len; + + if (!check_arg_dyn_buf (dynbuf)) + return -1; + + if (!check_arg_ptr ((char *) buf)) + return -1; + + if (NULL == reallocate_dyn_buf (dynbuf, length)) + { + DBG_MSG ("Could not reallocate dynamic buffer!\n"); + return -1; + } + + len = snprintf ((dynbuf->data + dynbuf->wr_index), length + 1, "%s", buf); + + /* If len is less than length, it means the string was shorter than + * given length */ + if (length > len) + length = len; + + if (0 < length) + dynbuf->wr_index += length; + + if (-1 == length) + DBG_MSG ("Failed to write to dynamic buffer!\n"); + + return length; +} + +int write_dyn_buf_from_fd (int fd, dyn_buf_t * dynbuf, size_t length) +{ + int len = length; + + if (!check_arg_dyn_buf (dynbuf)) + return -1; + + if (!check_arg_fd (fd)) + return -1; + + if (NULL == reallocate_dyn_buf (dynbuf, length)) + { + DBG_MSG ("Could not reallocate dynamic buffer!\n"); + return -1; + } + + len = read (fd, (dynbuf->data + dynbuf->wr_index), len); + + if (length > len) + length = len; + + if (0 < length) + dynbuf->wr_index += length; + + dynbuf->data[dynbuf->wr_index] = '\0'; + + if (-1 == length) + DBG_MSG ("Failed to write to dynamic buffer!\n"); + + return length; +} + +int +sprintf_dyn_buf (dyn_buf_t * dynbuf, const char *format, ...) +{ + va_list arg1, arg2; + char test_str[10]; + int needed, written = 0; + + if (!check_arg_dyn_buf (dynbuf)) + return -1; + + va_start (arg1, format); + va_copy (arg2, arg1); + + /* XXX: Lame way to try and figure out how much space we need */ + needed = vsnprintf (test_str, sizeof (test_str), format, arg2); + va_end (arg2); + + if (NULL == reallocate_dyn_buf (dynbuf, needed)) + { + DBG_MSG ("Could not reallocate dynamic buffer!\n"); + return -1; + } + + written = vsnprintf ((dynbuf->data + dynbuf->wr_index), needed + 1, + format, arg1); + va_end (arg1); + + if (0 < written) + dynbuf->wr_index += written; + + if (-1 == written) + DBG_MSG ("Failed to write to dynamic buffer!\n"); + + return written; +} + +int +read_dyn_buf (dyn_buf_t * dynbuf, char *buf, size_t length) +{ + int len = length; + + if (!check_arg_dyn_buf (dynbuf)) + return -1; + + if (!check_arg_ptr (buf)) + return -1; + + if (dynbuf->rd_index >= dynbuf->length) + return 0; + + if (dynbuf->wr_index < (dynbuf->rd_index + length)) + len = dynbuf->wr_index - dynbuf->rd_index; + + len = snprintf (buf, len + 1, "%s", (dynbuf->data + dynbuf->rd_index)); + + /* If len is less than length, it means the string was shorter than + * given length */ + if (length > len) + length = len; + + if (0 < length) + dynbuf->rd_index += length; + + if (-1 == length) + DBG_MSG ("Failed to write from dynamic buffer!\n"); + + return length; +} + +int +read_dyn_buf_to_fd (int fd, dyn_buf_t * dynbuf, size_t length) +{ + int len = length; + + if (!check_arg_dyn_buf (dynbuf)) + return -1; + + if (!check_arg_fd (fd)) + return -1; + + if (dynbuf->rd_index >= dynbuf->length) + return 0; + + if (dynbuf->wr_index < (dynbuf->rd_index + length)) + len = dynbuf->wr_index - dynbuf->rd_index; + + len = write (fd, (dynbuf->data + dynbuf->rd_index), len); + if (length > len) + length = len; + + if (0 < length) + dynbuf->rd_index += length; + + if (-1 == length) + DBG_MSG ("Failed to write from dynamic buffer!\n"); + + return length; +} + +char * +read_line_dyn_buf (dyn_buf_t *dynbuf) +{ + char *buf = NULL; + size_t count = 0; + + if (!check_arg_dyn_buf (dynbuf)) + return NULL; + + for (count = dynbuf->rd_index; count < dynbuf->wr_index && dynbuf->data[count] != '\n'; count++); + + if (count > dynbuf->rd_index) + { + buf = xstrndup ((dynbuf->data + dynbuf->rd_index), + (count - dynbuf->rd_index)); + if (NULL == buf) + return NULL; + + /* Also skip the '\n' .. */ + dynbuf->rd_index = count + 1; + } + + return buf; +} + +bool +dyn_buf_rd_eof (dyn_buf_t *dynbuf) +{ + if (!check_arg_dyn_buf (dynbuf)) + return FALSE; + + if (dynbuf->rd_index >= dynbuf->wr_index) + return TRUE; + + return FALSE; +} + +inline bool +check_dyn_buf (dyn_buf_t *dynbuf) +{ + if ((NULL == dynbuf) || (NULL == dynbuf->data) || (0 == dynbuf->length)) + return FALSE; + + return TRUE; +} + +inline bool +__check_arg_dyn_buf (dyn_buf_t *dynbuf, const char *file, const char *func, + size_t line) +{ + if (!check_dyn_buf (dynbuf)) + { + errno = EINVAL; + + debug_message (file, func, line, "Invalid dynamic buffer passed!\n"); + + return FALSE; + } + + return TRUE; +} + diff --git a/src/core/librcscripts/list.h b/src/core/librcscripts/list.h index 5c478bc..e69de29 100644 --- a/src/core/librcscripts/list.h +++ b/src/core/librcscripts/list.h @@ -1,446 +0,0 @@ -/* - * Copied from the Linux kernel source tree, version 2.6.0-test1. - * - * Licensed under the GPL v2 as per the whole kernel source tree. - * - * Ripped out the rcu stuff, as it's not needed. - * - * $Header$ - */ - -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -//#include <linux/stddef.h> -/** - * container_of - cast a member of a structure out to the containing structure - * - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -//#include <linux/prefetch.h> -static inline void prefetch(const void *x) {;} - -//#include <asm/system.h> - -/* - * These are non-NULL pointers that will result in page faults - * under normal circumstances, used to verify that nobody uses - * non-initialized list entries. - */ -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -#define INIT_LIST_HEAD(ptr) do { \ - (ptr)->next = (ptr); (ptr)->prev = (ptr); \ -} while (0) - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(struct list_head *head) -{ - return head->next == head; -} - -static inline void __list_splice(struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(struct list_head *list, struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next, prefetch(pos->next); pos != (head); \ - pos = pos->next, prefetch(pos->next)) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ - pos = pos->prev, prefetch(pos->prev)) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop counter. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - prefetch(pos->member.next); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member), \ - prefetch(pos->member.next)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - prefetch(pos->member.prev); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member), \ - prefetch(pos->member.prev)) - - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop counter. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/* - * Double linked lists with a single pointer list head. - * Mostly useful for hash tables where the two pointer list head is - * too wasteful. - * You lose the ability to access the tail in O(1). - */ - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -#define HLIST_HEAD_INIT { .first = NULL } -#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } -#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) - -static __inline__ int hlist_unhashed(struct hlist_node *h) -{ - return !h->pprev; -} - -static __inline__ int hlist_empty(struct hlist_head *h) -{ - return !h->first; -} - -static __inline__ void __hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; -} - -static __inline__ void hlist_del(struct hlist_node *n) -{ - __hlist_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; -} - -static __inline__ void hlist_del_init(struct hlist_node *n) -{ - if (n->pprev) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } -} - -static __inline__ void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; -} - -/* next must be != NULL */ -static __inline__ void hlist_add_before(struct hlist_node *n, struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; -} - -static __inline__ void hlist_add_after(struct hlist_node *n, - struct hlist_node *next) -{ - next->next = n->next; - *(next->pprev) = n; - n->next = next; -} - -#define hlist_entry(ptr, type, member) container_of(ptr,type,member) - -/* Cannot easily do prefetch unfortunately */ -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ - pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; n = pos ? pos->next : 0, pos; \ - pos = n) - -/** - * hlist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; \ - pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from existing point - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && ({ prefetch(pos->next); 1;}) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop counter. - * @pos: the &struct hlist_node to use as a loop counter. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = n) - -#endif diff --git a/src/core/librcscripts/misc.c b/src/core/librcscripts/misc.c index c589143..b08a3a6 100644 --- a/src/core/librcscripts/misc.c +++ b/src/core/librcscripts/misc.c @@ -34,553 +34,545 @@ #include <unistd.h> #include <fcntl.h> -#include "debug.h" -#include "misc.h" +#include "rcscripts.h" -char *memrepchr(char **str, char old, char new, size_t size) +char * +memrepchr (char **str, char old, char new, size_t size) { - char *str_p; - - if ((NULL == str) - || (NULL == *str) - || (0 == strlen(*str))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return NULL; - } + char *str_p; - str_p = memchr(*str, old, size); - - while (NULL != str_p) { - str_p[0] = new; - str_p = memchr(&str_p[1], old, size - (str_p - *str) - 1); - } + if (!check_arg_strv (str)) + return NULL; - return *str; -} - -char *strcatpaths(const char *pathname1, const char *pathname2) -{ - char *new_path = NULL; - int lenght; - - if ((NULL == pathname1) - || (0 == strlen(pathname1)) - || (NULL == pathname2) - || (0 == strlen(pathname2))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return NULL; - } + str_p = memchr (*str, old, size); - /* Lenght of pathname1 + lenght of pathname2 + '/' if needed */ - lenght = strlen(pathname1) + strlen(pathname2) + 1; - /* lenght + '\0' */ - new_path = malloc(lenght + 1); - if (NULL == new_path) { - DBG_MSG("Failed to allocate buffer!\n"); - return NULL; - } + while (NULL != str_p) + { + str_p[0] = new; + str_p = memchr (&str_p[1], old, size - (str_p - *str) - 1); + } - strncpy(new_path, pathname1, lenght); - /* Should we add a '/' ? */ - if (new_path[strlen(new_path)-1] != '/') - strncat(new_path, "/", lenght - strlen(new_path)); - strncat(new_path, pathname2, lenght - strlen(new_path)); + return *str; +} - return new_path; +char * +strcatpaths (const char *pathname1, const char *pathname2) +{ + char *new_path = NULL; + int lenght; + + if ((!check_arg_str (pathname1)) || (!check_arg_str (pathname2))) + return 0; + + /* Lenght of pathname1 + lenght of pathname2 + '/' if needed */ + lenght = strlen (pathname1) + strlen (pathname2) + 1; + /* lenght + '\0' */ + new_path = xmalloc (lenght + 1); + if (NULL == new_path) + return NULL; + + strncpy (new_path, pathname1, lenght); + /* Should we add a '/' ? */ + if (new_path[strlen (new_path) - 1] != '/') + strncat (new_path, "/", lenght - strlen (new_path)); + strncat (new_path, pathname2, lenght - strlen (new_path)); + + return new_path; } -char *strndup(const char *str, size_t size) +char * +strndup (const char *str, size_t size) { - char *new_str = NULL; - size_t len; + char *new_str = NULL; + size_t len; - if (NULL == str) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return NULL; - } + if (!check_arg_str (str)) + return NULL; - /* Check lenght of str without breaching the size limit */ - for (len = 0; (len < size) && ('\0' != str[len]); len++); + /* Check lenght of str without breaching the size limit */ + for (len = 0; (len < size) && ('\0' != str[len]); len++); - new_str = malloc(len + 1); - if (NULL == new_str) { - DBG_MSG("Failed to allocate buffer!\n"); - return NULL; - } + new_str = xmalloc (len + 1); + if (NULL == new_str) + return NULL; + + /* Make sure our string is NULL terminated */ + new_str[len] = '\0'; - /* Make sure our string is NULL terminated */ - new_str[len] = '\0'; - - return (char *)memcpy(new_str, str, len); + return (char *) memcpy (new_str, str, len); } -char *gbasename(const char *path) +char * +gbasename (const char *path) { - char *new_path = NULL; - - if ((NULL == path) || (0 == strlen(path))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return NULL; - } + char *new_path = NULL; - /* Copied from glibc */ - new_path = strrchr (path, '/'); - return new_path ? new_path + 1 : (char *)path; + if (!check_arg_str (path)) + return NULL; + + /* Copied from glibc */ + new_path = strrchr (path, '/'); + return new_path ? new_path + 1 : (char *) path; } - -int exists(const char *pathname) + +int +exists (const char *pathname) { - struct stat buf; - int retval; + struct stat buf; + int retval; - if ((NULL == pathname) || (0 == strlen(pathname))) { - DBG_MSG("Invalid argument passed!\n"); - return 0; - } + if (!check_arg_str (pathname)) + return -1; - retval = lstat(pathname, &buf); - if (-1 != retval) - return 1; + retval = lstat (pathname, &buf); + if (-1 != retval) + return 1; - /* Clear errno, as we do not want debugging to trigger */ - errno = 0; + /* Clear errno, as we do not want debugging to trigger */ + errno = 0; - return 0; + return 0; } -int is_file(const char *pathname, int follow_link) +int +is_file (const char *pathname, int follow_link) { - struct stat buf; - int retval; + struct stat buf; + int retval; - if ((NULL == pathname) || (0 == strlen(pathname))) { - DBG_MSG("Invalid argument passed!\n"); - return 0; - } + if (!check_arg_str (pathname)) + return -1; - retval = follow_link ? stat(pathname, &buf) : lstat(pathname, &buf); - if ((-1 != retval) && (S_ISREG(buf.st_mode))) - return 1; + retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf); + if ((-1 != retval) && (S_ISREG (buf.st_mode))) + return 1; - /* Clear errno, as we do not want debugging to trigger */ - errno = 0; + /* Clear errno, as we do not want debugging to trigger */ + errno = 0; - return 0; + return 0; } -int is_link(const char *pathname) +int +is_link (const char *pathname) { - struct stat buf; - int retval; + struct stat buf; + int retval; - if ((NULL == pathname) || (0 == strlen(pathname))) { - DBG_MSG("Invalid argument passed!\n"); - return 0; - } + if (!check_arg_str (pathname)) + return -1; - retval = lstat(pathname, &buf); - if ((-1 != retval) && (S_ISLNK(buf.st_mode))) - return 1; + retval = lstat (pathname, &buf); + if ((-1 != retval) && (S_ISLNK (buf.st_mode))) + return 1; - /* Clear errno, as we do not want debugging to trigger */ - errno = 0; + /* Clear errno, as we do not want debugging to trigger */ + errno = 0; - return 0; + return 0; } -int is_dir(const char *pathname, int follow_link) +int +is_dir (const char *pathname, int follow_link) { - struct stat buf; - int retval; + struct stat buf; + int retval; - if ((NULL == pathname) || (0 == strlen(pathname))) { - DBG_MSG("Invalid argument passed!\n"); - return 0; - } + if (!check_arg_str (pathname)) + return -1; - retval = follow_link ? stat(pathname, &buf) : lstat(pathname, &buf); - if ((-1 != retval) && (S_ISDIR(buf.st_mode))) - return 1; + retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf); + if ((-1 != retval) && (S_ISDIR (buf.st_mode))) + return 1; - /* Clear errno, as we do not want debugging to trigger */ - errno = 0; + /* Clear errno, as we do not want debugging to trigger */ + errno = 0; - return 0; + return 0; } -time_t get_mtime(const char *pathname, int follow_link) +time_t +get_mtime (const char *pathname, int follow_link) { - struct stat buf; - int retval; + struct stat buf; + int retval; - if ((NULL == pathname) || (0 == strlen(pathname))) { - DBG_MSG("Invalid argument passed!\n"); - return 0; - } + if (!check_arg_str (pathname)) + return -1; - retval = follow_link ? stat(pathname, &buf) : lstat(pathname, &buf); - if (-1 != retval) - return buf.st_mtime; + retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf); + if (-1 != retval) + return buf.st_mtime; - /* Clear errno, as we do not want debugging to trigger */ - errno = 0; + /* Clear errno, as we do not want debugging to trigger */ + errno = 0; - return 0; + return 0; } -#ifdef __KLIBC__ -int remove(const char *pathname) +#if !defined(HAVE_REMOVE) +int +remove (const char *pathname) { - int retval; - - if ((NULL == pathname) || (0 == strlen(pathname))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return -1; - } + int retval; + + if (!check_arg_str (pathname)) + return -1; - if (1 == is_dir(pathname, 0)) - retval = rmdir(pathname); - else - retval = unlink(pathname); + if (1 == is_dir (pathname, 0)) + retval = rmdir (pathname); + else + retval = unlink (pathname); - return retval; + return retval; } #endif -int mktree(const char *pathname, mode_t mode) +int +mktree (const char *pathname, mode_t mode) { - char *temp_name = NULL; - char *temp_token = NULL; - char *token_p; - char *token; - int retval; - int lenght; - - if ((NULL == pathname) || (0 == strlen(pathname))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return -1; - } - - /* Lenght of 'pathname' + extra for "./" if needed */ - lenght = strlen(pathname) + 2; - /* lenght + '\0' */ - temp_name = malloc(lenght + 1); - if (NULL == temp_name) { - DBG_MSG("Failed to allocate temporary buffer!\n"); - return -1; - } - - temp_token = strndup(pathname, strlen(pathname)); - if (NULL == temp_token) { - DBG_MSG("Failed to allocate temporary buffer!\n"); - goto error; - } - token_p = temp_token; - - if (pathname[0] == '/') - temp_name[0] = '\0'; - else - /* If not an absolute path, make it local */ - strncpy(temp_name, ".", lenght); - - token = strsep(&token_p, "/"); - /* First token might be "", but that is OK as it will be when the - * pathname starts with '/' */ - while (NULL != token) { - strncat(temp_name, "/", lenght - strlen(temp_name)); - strncat(temp_name, token, lenght - strlen(temp_name)); - - /* If it does not exist, create the dir. If it does exit, - * but is not a directory, we will catch it below. */ - if (1 != exists(temp_name)) { - retval = mkdir(temp_name, mode); - if (-1 == retval) { - DBG_MSG("Failed to create directory!\n"); - goto error; - } - /* Not a directory or symlink pointing to a directory */ - } else if (1 != is_dir(temp_name, 1)) { - DBG_MSG("Component in pathname is not a directory!\n"); - errno = ENOTDIR; - goto error; - } - - do { - token = strsep(&token_p, "/"); - /* The first "" was Ok, but rather skip double '/' after that */ - } while ((NULL != token) && (0 == strlen(token))); - } - - free(temp_name); - free(temp_token); - - return 0; + char *temp_name = NULL; + char *temp_token = NULL; + char *token_p; + char *token; + int retval; + int lenght; + + if (!check_arg_str (pathname)) + return -1; + + /* Lenght of 'pathname' + extra for "./" if needed */ + lenght = strlen (pathname) + 2; + /* lenght + '\0' */ + temp_name = xmalloc (lenght + 1); + if (NULL == temp_name) + return -1; + + temp_token = xstrndup (pathname, strlen (pathname)); + if (NULL == temp_token) + goto error; + + token_p = temp_token; + + if (pathname[0] == '/') + temp_name[0] = '\0'; + else + /* If not an absolute path, make it local */ + strncpy (temp_name, ".", lenght); + + token = strsep (&token_p, "/"); + /* First token might be "", but that is OK as it will be when the + * pathname starts with '/' */ + while (NULL != token) + { + strncat (temp_name, "/", lenght - strlen (temp_name)); + strncat (temp_name, token, lenght - strlen (temp_name)); + + /* If it does not exist, create the dir. If it does exit, + * but is not a directory, we will catch it below. */ + if (1 != exists (temp_name)) + { + retval = mkdir (temp_name, mode); + if (-1 == retval) + { + DBG_MSG ("Failed to create directory!\n"); + goto error; + } + /* Not a directory or symlink pointing to a directory */ + } + else if (1 != is_dir (temp_name, 1)) + { + errno = ENOTDIR; + DBG_MSG ("Component in pathname is not a directory!\n"); + goto error; + } + + do + { + token = strsep (&token_p, "/"); + /* The first "" was Ok, but rather skip double '/' after that */ + } + while ((NULL != token) && (0 == strlen (token))); + } + + free (temp_name); + free (temp_token); + + return 0; error: - free(temp_name); - free(temp_token); - - return -1; + free (temp_name); + free (temp_token); + + return -1; } -int rmtree(const char *pathname) +int +rmtree (const char *pathname) { - char **dirlist = NULL; - int i = 0; - - if ((NULL == pathname) || (0 == strlen(pathname))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return -1; - } - - if (1 != exists(pathname)) { - DBG_MSG("'%s' does not exists!\n", pathname); - errno = ENOENT; - return -1; - } - - dirlist = ls_dir(pathname, 1); - if ((NULL == dirlist) && (0 != errno)) { - DBG_MSG("Could not get listing for '%s'!\n", pathname); - return -1; - } - - while ((NULL != dirlist) && (NULL != dirlist[i])) { - /* If it is a directory, call rmtree() again with - * it as argument */ - if (1 == is_dir(dirlist[i], 0)) { - if (-1 == rmtree(dirlist[i])) { - DBG_MSG("Failed to delete sub directory!\n"); - goto error; - } - } - - /* Now actually remove it. Note that if it was a directory, - * it should already be removed by above rmtree() call */ - if ((1 == exists(dirlist[i]) && (-1 == remove(dirlist[i])))) { - DBG_MSG("Failed to remove '%s'!\n", dirlist[i]); - goto error; - } - i++; - } - - STRING_LIST_FREE(dirlist); - - /* Now remove the parent */ - if (-1 == remove(pathname)) { - DBG_MSG("Failed to remove '%s'!\n", pathname); - goto error; - } - - return 0; + char **dirlist = NULL; + int i = 0; + + if (!check_arg_str (pathname)) + return -1; + + if (1 != exists (pathname)) + { + errno = ENOENT; + DBG_MSG ("'%s' does not exists!\n", pathname); + return -1; + } + + dirlist = ls_dir (pathname, 1); + if ((NULL == dirlist) && (0 != errno)) + { + /* Do not error out - caller should decide itself if it + * it is an issue */ + DBG_MSG ("Could not get listing for '%s'!\n", pathname); + return -1; + } + + while ((NULL != dirlist) && (NULL != dirlist[i])) + { + /* If it is a directory, call rmtree() again with + * it as argument */ + if (1 == is_dir (dirlist[i], 0)) + { + if (-1 == rmtree (dirlist[i])) + { + DBG_MSG ("Failed to delete sub directory!\n"); + goto error; + } + } + + /* Now actually remove it. Note that if it was a directory, + * it should already be removed by above rmtree() call */ + if ((1 == exists (dirlist[i]) && (-1 == remove (dirlist[i])))) + { + DBG_MSG ("Failed to remove '%s'!\n", dirlist[i]); + goto error; + } + i++; + } + + str_list_free (dirlist); + + /* Now remove the parent */ + if (-1 == remove (pathname)) + { + DBG_MSG ("Failed to remove '%s'!\n", pathname); + goto error; + } + + return 0; error: - STRING_LIST_FREE(dirlist); + str_list_free (dirlist); - return -1; + return -1; } -char **ls_dir(const char *pathname, int hidden) +char ** +ls_dir (const char *pathname, int hidden) { - DIR *dirfd; - struct dirent *dir_entry; - char **dirlist = NULL; - - if ((NULL == pathname) || (0 == strlen(pathname))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return NULL; - } - - dirfd = opendir(pathname); - if (NULL == dirfd) { - DBG_MSG("Failed to call opendir()!\n"); - /* errno will be set by opendir() */ - goto error; - } - - do { - /* Clear errno to distinguish between EOF and error */ - errno = 0; - dir_entry = readdir(dirfd); - /* Only an error if 'errno' != 0, else EOF */ - if ((NULL == dir_entry) && (0 != errno)) { - DBG_MSG("Failed to call readdir()!\n"); - goto error; - } - if ((NULL != dir_entry) && - /* Should we display hidden files? */ - (hidden ? 1 : dir_entry->d_name[0] != '.')) - { - char *d_name = dir_entry->d_name; - char *tmp_p; - - /* Do not list current or parent entries */ - if ((0 == strcmp(d_name, ".")) || - (0 == strcmp(d_name, ".."))) - continue; - - tmp_p = strcatpaths(pathname, d_name); - if (NULL == tmp_p) { - DBG_MSG("Failed to allocate buffer!\n"); - goto error; - } - - STRING_LIST_ADD(dirlist, tmp_p, error); - } - } while (NULL != dir_entry); - - if ((NULL == dirlist) || (NULL == dirlist[0])) - DBG_MSG("Directory is empty.\n"); - - closedir(dirfd); - - return dirlist; + DIR *dp; + struct dirent *dir_entry; + char **dirlist = NULL; + + if (!check_arg_str (pathname)) + return NULL; + + dp = opendir (pathname); + if (NULL == dp) + { + DBG_MSG ("Failed to call opendir()!\n"); + /* errno will be set by opendir() */ + goto error; + } + + do + { + /* Clear errno to distinguish between EOF and error */ + errno = 0; + dir_entry = readdir (dp); + /* Only an error if 'errno' != 0, else EOF */ + if ((NULL == dir_entry) && (0 != errno)) + { + DBG_MSG ("Failed to call readdir()!\n"); + goto error; + } + if ((NULL != dir_entry) + /* Should we display hidden files? */ + && (hidden ? 1 : dir_entry->d_name[0] != '.')) + { + char *d_name = dir_entry->d_name; + char *tmp_p; + + /* Do not list current or parent entries */ + if ((0 == strcmp (d_name, ".")) || (0 == strcmp (d_name, ".."))) + continue; + + tmp_p = strcatpaths (pathname, d_name); + if (NULL == tmp_p) + { + DBG_MSG ("Failed to allocate buffer!\n"); + goto error; + } + + str_list_add_item (dirlist, tmp_p, error); + } + } + while (NULL != dir_entry); + + if (!check_strv (dirlist)) + { + if (NULL != dirlist) + str_list_free (dirlist); + + DBG_MSG ("Directory is empty.\n"); + } + + closedir (dp); + + return dirlist; error: - /* Free dirlist on error */ - STRING_LIST_FREE(dirlist); - - if (NULL != dirfd) { - int old_errno = errno; - closedir(dirfd); - /* closedir() might have changed it */ - errno = old_errno; - } - - return NULL; + /* Free dirlist on error */ + str_list_free (dirlist); + + if (NULL != dp) + { + save_errno (); + closedir (dp); + /* closedir() might have changed it */ + restore_errno (); + } + + return NULL; } /* This handles simple 'entry="bar"' type variables. If it is more complex * ('entry="$(pwd)"' or such), it will obviously not work, but current behaviour * should be fine for the type of variables we want. */ -char *get_cnf_entry(const char *pathname, const char *entry) +char * +get_cnf_entry (const char *pathname, const char *entry) { - char *buf = NULL; - char *tmp_buf = NULL; - char *tmp_p; - char *value = NULL; - char *token; - size_t lenght; - int count; - int current = 0; - - - if ((NULL == pathname) - || (0 == strlen(pathname)) - || (NULL == entry) - || (0 == strlen(entry))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return NULL; - } - - /* If it is not a file or symlink pointing to a file, bail */ - if (1 != is_file(pathname, 1)) { - DBG_MSG("Given pathname is not a file or do not exist!\n"); - /* FIXME: Might need to set this to something better? */ - errno = ENOENT; - return NULL; - } + char *buf = NULL; + char *tmp_buf = NULL; + char *tmp_p; + char *value = NULL; + char *token; + size_t lenght; + int count; + int current = 0; + + + if ((!check_arg_str (pathname)) || (!check_arg_str (entry))) + return NULL; + + /* If it is not a file or symlink pointing to a file, bail */ + if (1 != is_file (pathname, 1)) + { + errno = ENOENT; + DBG_MSG ("Given pathname is not a file or do not exist!\n"); + return NULL; + } + + if (-1 == file_map (pathname, &buf, &lenght)) + { + DBG_MSG ("Could not open config file for reading!\n"); + return NULL; + } + + while (current < lenght) + { + count = buf_get_line (buf, lenght, current); + + tmp_buf = xstrndup (&buf[current], count); + if (NULL == tmp_buf) + goto error; + + tmp_p = tmp_buf; + + /* Strip leading spaces/tabs */ + while ((tmp_p[0] == ' ') || (tmp_p[0] == '\t')) + tmp_p++; + + /* Get entry and value */ + token = strsep (&tmp_p, "="); + /* Bogus entry or value */ + if (NULL == token) + goto _continue; + + /* Make sure we have a string that is larger than 'entry', and + * the first part equals 'entry' */ + if ((strlen (token) > 0) && (0 == strcmp (entry, token))) + { + do + { + /* Bash variables are usually quoted */ + token = strsep (&tmp_p, "\"\'"); + /* If quoted, the first match will be "" */ + } + while ((NULL != token) && (0 == strlen (token))); + + /* We have a 'entry='. We respect bash rules, so NULL + * value for now (if not already) */ + if (NULL == token) + { + /* We might have 'entry=' and later 'entry="bar"', + * so just continue for now ... we will handle + * it below when 'value == NULL' */ + if (NULL != value) + { + free (value); + value = NULL; + } + goto _continue; + } - if (-1 == file_map(pathname, &buf, &lenght)) { - DBG_MSG("Could not open config file for reading!\n"); - return NULL; - } + /* If we have already allocated 'value', free it */ + if (NULL != value) + free (value); - while (current < lenght) { - count = buf_get_line(buf, lenght, current); + value = xstrndup (token, strlen (token)); + if (NULL == value) + goto error; - tmp_buf = strndup(&buf[current], count); - if (NULL == tmp_buf) { - DBG_MSG("Failed to allocate temporary buffer!\n"); - goto error; - } - tmp_p = tmp_buf; - - /* Strip leading spaces/tabs */ - while ((tmp_p[0] == ' ') || (tmp_p[0] == '\t')) - tmp_p++; - - /* Get entry and value */ - token = strsep(&tmp_p, "="); - /* Bogus entry or value */ - if (NULL == token) - goto _continue; - - /* Make sure we have a string that is larger than 'entry', and - * the first part equals 'entry' */ - if ((strlen(token) > 0) && (0 == strcmp(entry, token))) - { - do { - /* Bash variables are usually quoted */ - token = strsep(&tmp_p, "\"\'"); - /* If quoted, the first match will be "" */ - } while ((NULL != token) && (0 == strlen(token))); - - /* We have a 'entry='. We respect bash rules, so NULL - * value for now (if not already) */ - if (NULL == token) { - /* We might have 'entry=' and later 'entry="bar"', - * so just continue for now ... we will handle - * it below when 'value == NULL' */ - if (NULL != value) { - free(value); - value = NULL; - } - goto _continue; - } - - /* If we have already allocated 'value', free it */ - if (NULL != value) - free(value); - - value = strndup(token, strlen(token)); - if (NULL == value) { - DBG_MSG("Failed to allocate temporary buffer!\n"); - goto error; - } - - /* We do not break, as there might be more than one entry - * defined, and as bash uses the last, so should we */ - /* break; */ - } + /* We do not break, as there might be more than one entry + * defined, and as bash uses the last, so should we */ + /* break; */ + } _continue: - current += count + 1; - free(tmp_buf); - /* Set to NULL in case we error out above and have - * to free below */ - tmp_buf = NULL; - } - + current += count + 1; + free (tmp_buf); + /* Set to NULL in case we error out above and have + * to free below */ + tmp_buf = NULL; + } - if (NULL == value) - DBG_MSG("Failed to get value for config entry '%s'!\n", entry); - file_unmap(buf, lenght); + if (NULL == value) + DBG_MSG ("Failed to get value for config entry '%s'!\n", entry); - return value; + file_unmap (buf, lenght); -error: - free(tmp_buf); - free(value); - - if (NULL != buf) { - int old_errno = errno; - file_unmap(buf, lenght); - /* unmmap() might have changed it */ - errno = old_errno; - } + return value; - return NULL; +error: + free (tmp_buf); + free (value); + + if (NULL != buf) + { + save_errno (); + file_unmap (buf, lenght); + /* unmmap() might have changed it */ + restore_errno (); + } + + return NULL; } @@ -606,54 +598,72 @@ error: * */ -int file_map(const char *filename, char **buf, size_t *bufsize) +int +file_map (const char *filename, char **buf, size_t * bufsize) { - struct stat stats; - int fd; - int old_errno; - - fd = open(filename, O_RDONLY); - if (fd < 0) { - DBG_MSG("Failed to open file!\n"); - return -1; - } - - if (fstat(fd, &stats) < 0) { - DBG_MSG("Failed to stat file!\n"); - old_errno = errno; - close(fd); - /* close() might have changed it */ - errno = old_errno; - return -1; - } - - *buf = mmap(NULL, stats.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (*buf == MAP_FAILED) { - DBG_MSG("Failed to mmap file!\n"); - old_errno = errno; - close(fd); - /* close() might have changed it */ - errno = old_errno; - return -1; - } - *bufsize = stats.st_size; - - close(fd); - - return 0; + struct stat stats; + int fd; + + fd = open (filename, O_RDONLY); + if (fd < 0) + { + DBG_MSG ("Failed to open file!\n"); + return -1; + } + + if (fstat (fd, &stats) < 0) + { + DBG_MSG ("Failed to stat file!\n"); + + save_errno (); + close (fd); + restore_errno (); + + return -1; + } + + if (0 == stats.st_size) + { + errno = EINVAL; + DBG_MSG ("Failed to mmap file with 0 size!\n"); + + save_errno (); + close (fd); + restore_errno (); + + return -1; + } + + *buf = mmap (NULL, stats.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (*buf == MAP_FAILED) + { + DBG_MSG ("Failed to mmap file!\n"); + + save_errno (); + close (fd); + restore_errno (); + + return -1; + } + *bufsize = stats.st_size; + + close (fd); + + return 0; } -void file_unmap(char *buf, size_t bufsize) +void +file_unmap (char *buf, size_t bufsize) { - munmap(buf, bufsize); + munmap (buf, bufsize); } -size_t buf_get_line(char *buf, size_t buflen, size_t cur) +size_t +buf_get_line (char *buf, size_t buflen, size_t cur) { - size_t count = 0; + size_t count = 0; - for (count = cur; count < buflen && buf[count] != '\n'; count++); + for (count = cur; count < buflen && buf[count] != '\n'; count++); - return count - cur; + return count - cur; } - diff --git a/src/core/librcscripts/misc.h b/src/core/librcscripts/misc.h index 400e580..e69de29 100644 --- a/src/core/librcscripts/misc.h +++ b/src/core/librcscripts/misc.h @@ -1,282 +0,0 @@ -/* - * misc.h - * - * Miscellaneous macro's and functions. - * - * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> - * - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Header$ - */ - -#ifndef _MISC_H -#define _MISC_H - -#include <sys/stat.h> -#include <sys/types.h> - -/* Gentoo style e* printing macro's */ -#define EINFO(_args...) \ - do { \ - int old_errno = errno; \ - printf(" \033[32;01m*\033[0m " _args); \ - errno = old_errno; \ - } while (0) - -#define EWARN(_args...) \ - do { \ - int old_errno = errno; \ - printf(" \033[33;01m*\033[0m " _args); \ - errno = old_errno; \ - } while (0) - -#define EERROR(_args...) \ - do { \ - int old_errno = errno; \ - fprintf(stderr, " \033[31;01m*\033[0m " _args); \ - errno = old_errno; \ - } while (0) - -/* Min/Max macro's */ -#ifdef MAX -# undef MAX -#endif -#define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) -#ifdef MIN -# undef MIN -#endif -#define MIN(_a, _b) ((_a) > (_b) ? (_b) : (_a)) - -/* Return true if filename '_name' ends in '_ext' */ -#define CHECK_FILE_EXTENSION(_name, _ext) \ - ((strlen(_name) > strlen(_ext)) \ - && (0 == strncmp(&(_name[strlen(_name) - strlen(_ext)]), \ - _ext, strlen(_ext)))) - -/* Add a new item to a string list. If the pointer to the list is NULL, - * allocate enough memory for the amount of entries needed. Ditto for - * when it already exists, but we add one more entry than it can - * contain. The list is NULL terminated. - * NOTE: _only_ memory for the list are allocated, and not for the items - that - * should be done by relevant code (unlike STRING_LIST_DEL that will - * free the memory) */ -#define STRING_LIST_ADD(_string_list, _item, _error) \ - do { \ - char **_tmp_p; \ - int _i = 0; \ - if ((NULL == _item) || (0 == strlen(_item))) { \ - DBG_MSG("Invalid argument passed!\n"); \ - errno = EINVAL; \ - goto _error; \ - } \ - while ((NULL != _string_list) && (NULL != _string_list[_i])) { \ - _i++; \ - } \ - /* Amount of entries + new + terminator */ \ - _tmp_p = realloc(_string_list, sizeof(char *) * (_i + 2)); \ - if (NULL == _tmp_p) { \ - DBG_MSG("Failed to reallocate list!\n"); \ - goto _error; \ - } \ - _string_list = _tmp_p; \ - _string_list[_i] = _item; \ - /* Terminator */ \ - _string_list[_i+1] = NULL; \ - } while (0) - -/* Add a new item to a string list (foundamental the same as above), but make - * sure we have all the items alphabetically sorted. */ -#define STRING_LIST_ADD_SORT(_string_list, _item, _error) \ - do { \ - char **_tmp_p; \ - char *_str_p1; \ - char *_str_p2; \ - int _i = 0; \ - if ((NULL == _item) || (0 == strlen(_item))) { \ - DBG_MSG("Invalid argument passed!\n"); \ - errno = EINVAL; \ - goto _error; \ - } \ - while ((NULL != _string_list) && (NULL != _string_list[_i])) \ - _i++; \ - /* Amount of entries + new + terminator */ \ - _tmp_p = realloc(_string_list, sizeof(char *) * (_i + 2)); \ - if (NULL == _tmp_p) { \ - DBG_MSG("Failed to reallocate list!\n"); \ - goto _error; \ - } \ - _string_list = _tmp_p; \ - if (0 == _i) \ - /* Needed so that the end NULL will propagate - * (iow, make sure our 'NULL != _str_p1' test below - * do not fail) */ \ - _string_list[_i] = NULL; \ - /* Actual terminator that needs adding */ \ - _string_list[_i+1] = NULL; \ - _i = 0; \ - /* See where we should insert the new item to have it all \ - * alphabetically sorted */ \ - while (NULL != _string_list[_i]) { \ - if (strcmp(_string_list[_i], _item) > 0) { \ - break; \ - } \ - _i++; \ - } \ - /* Now just insert the new item, and shift the rest one over. - * '_str_p2' is temporary storage to swap the indexes in a loop, - * and 'str_p1' is used to store the old value across the loop */ \ - _str_p1 = _string_list[_i]; \ - _string_list[_i] = _item; \ - do { \ - _i++;\ - _str_p2 = _string_list[_i]; \ - _string_list[_i] = _str_p1; \ - _str_p1 = _str_p2; \ - } while (NULL != _str_p1); \ - } while (0) - -/* Delete one entry from the string list, and shift the rest down if the entry - * was not at the end. For now we do not resize the amount of entries the - * string list can contain, and free the memory for the matching item */ -#define STRING_LIST_DEL(_string_list, _item, _error) \ - do { \ - int _i = 0; \ - if ((NULL == _item) \ - || (0 == strlen(_item)) \ - || (NULL == _string_list)) { \ - DBG_MSG("Invalid argument passed!\n"); \ - errno = EINVAL; \ - goto _error; \ - } \ - while (NULL != _string_list[_i]) { \ - if (0 == strcmp(_item, _string_list[_i])) \ - break; \ - else \ - _i++; \ - } \ - if (NULL == _string_list[_i]) { \ - DBG_MSG("Invalid argument passed!\n"); \ - errno = EINVAL; \ - goto _error; \ - } \ - free(_string_list[_i]); \ - /* Shift all the following items one forward */ \ - do { \ - _string_list[_i] = _string_list[_i+1]; \ - /* This stupidity is to shutup gcc */ \ - _i++; \ - } while (NULL != _string_list[_i]); \ - } while (0) - -/* Step through each entry in the string list, setting '_pos' to the - * beginning of the entry. '_counter' is used by the macro as index, - * but should not be used by code as index (or if really needed, then - * it should usually by +1 from what you expect, and should only be - * used in the scope of the macro) */ -#define STRING_LIST_FOR_EACH(_string_list, _pos, _counter) \ - if ((NULL != _string_list) && (0 == (_counter = 0))) \ - while (NULL != (_pos = _string_list[_counter++])) - -/* Same as above (with the same warning about '_counter'). Now we just - * have '_next' that are also used for indexing. Once again rather refrain - * from using it if not absolutely needed. The major difference to above, - * is that it should be safe from having the item removed from under you. */ -#define STRING_LIST_FOR_EACH_SAFE(_string_list, _pos, _next, _counter) \ - if ((NULL != _string_list) \ - && (0 == (_counter = 0))) \ - /* First part of the while checks if this is the - * first loop, and if so setup _pos and _next - * and increment _counter */ \ - while ((((0 == _counter) \ - && (NULL != (_pos = _string_list[_counter])) \ - && (_pos != (_next = _string_list[++_counter]))) \ - /* Second part is when it is not the first loop - * and _pos was not removed from under us. We - * just increment _counter, and setup _pos and - * _next */ \ - || ((0 != _counter) \ - && (_pos == _string_list[_counter-1]) \ - && (_next == _string_list[_counter]) \ - && (NULL != (_pos = _string_list[_counter])) \ - && (_pos != (_next = _string_list[++_counter]))) \ - /* Last part is when _pos was removed from under - * us. We basically just setup _pos and _next, - * but leave _counter alone */ \ - || ((0 != _counter) \ - && (_pos != _string_list[_counter-1]) \ - && (_next == _string_list[_counter-1]) \ - && (NULL != (_pos = _string_list[_counter-1])) \ - && (_pos != (_next = _string_list[_counter]))))) - -/* Just free the whole string list */ -#define STRING_LIST_FREE(_string_list) \ - do { \ - if (NULL != _string_list) { \ - int _i = 0; \ - while (NULL != _string_list[_i]) \ - free(_string_list[_i++]); \ - free(_string_list); \ - _string_list = NULL; \ - } \ - } while (0) - -/* String functions. Return a string on success, or NULL on error - * or no action taken. On error errno will be set.*/ -char *memrepchr(char **str, char old, char _new, size_t size); -/* Concat two paths adding '/' if needed. Memory will be allocated - * with the malloc() call. */ -char *strcatpaths(const char *pathname1, const char *pathname2); - -/* Compat functions for GNU extensions */ -char *strndup(const char *str, size_t size); -/* Same as basename(3), but do not modify path */ -char *gbasename(const char *path); - -/* The following functions do not care about errors - they only return - * 1 if 'pathname' exist, and is the type requested, or else 0. - * They also might clear errno */ -int exists(const char *pathname); -int is_file(const char *pathname, int follow_link); -int is_link(const char *pathname); -int is_dir(const char *pathname, int follow_link); - -/* The following function do not care about errors - it only returns - * the mtime of 'pathname' if it exists, and is the type requested, - * or else 0. It also might clear errno */ -time_t get_mtime(const char *pathname, int follow_link); - -/* The following functions return 0 on success, or -1 with errno set on error. */ -#ifdef __KLIBC__ -int remove(const char *pathname); -#endif -int mktree(const char *pathname, mode_t mode); -int rmtree(const char *pathname); - -/* The following return a pointer on success, or NULL with errno set on error. - * If it returned NULL, but errno is not set, then there was no error, but - * there is nothing to return. */ -char **ls_dir(const char *pathname, int hidden); -char *get_cnf_entry(const char *pathname, const char *entry); - -/* Below three functions (file_map, file_unmap and buf_get_line) are from - * udev-050 (udev_utils.c). Please see misc.c for copyright info. - * (Some are slightly modified, please check udev for originals.) */ -int file_map(const char *filename, char **buf, size_t *bufsize); -void file_unmap(char *buf, size_t bufsize); -size_t buf_get_line(char *buf, size_t buflen, size_t cur); - -#endif /* _MISC_H */ - diff --git a/src/core/librcscripts/parse.c b/src/core/librcscripts/parse.c index 1131c73..caeba5a 100644 --- a/src/core/librcscripts/parse.c +++ b/src/core/librcscripts/parse.c @@ -37,12 +37,6 @@ #include <signal.h> #include "rcscripts.h" -#include "debug.h" -#include "depend.h" -#include "list.h" -#include "misc.h" -#include "parse.h" -#include "simple-regex.h" #define READ_PIPE 0 #define WRITE_PIPE 1 @@ -59,924 +53,783 @@ #define PARSE_BUFFER_SIZE 256 -#define OUTPUT_MAX_LINE_LENGHT 256 -#define OUTPUT_BUFFER_SIZE (60 * 2048) - -/* void PRINT_TO_BUFFER(char **_buf, int _count, label _error, format) */ -#define PRINT_TO_BUFFER(_buf, _count, _error, _output...) \ - do { \ - int _i = 0; \ - /* FIXME: Might do something more dynamic here */ \ - if (OUTPUT_BUFFER_SIZE < (_count + OUTPUT_MAX_LINE_LENGHT)) { \ - errno = ENOMEM; \ - DBG_MSG("Output buffer size too small!\n"); \ - goto _error; \ - } \ - _i = sprintf(&((*_buf)[_count]), _output); \ - if (0 < _i) \ - _count += _i + 1; \ - } while (0) - -LIST_HEAD(rcscript_list); - -size_t parse_rcscript(char *scriptname, char **data, size_t index); - -size_t parse_print_start(char **data, size_t index); -size_t parse_print_header(char *scriptname, char **data, size_t index); -size_t parse_print_body(char *scriptname, char **data, size_t index); - -int get_rcscripts(void) -{ - rcscript_info_t *info; - char **file_list = NULL; - char *rcscript; - char *confd_file = NULL; - int count; - - file_list = ls_dir(RCSCRIPTS_INITDDIR, 0); - if (NULL == file_list) { - DBG_MSG("'%s' is empty!\n", RCSCRIPTS_INITDDIR); - return -1; - } - - STRING_LIST_FOR_EACH(file_list, rcscript, count) { - /* Is it a file? */ - if (!(is_file(rcscript, 1)) - /* Do not process scripts, source or backup files. */ - || (CHECK_FILE_EXTENSION(rcscript, ".c")) - || (CHECK_FILE_EXTENSION(rcscript, ".bak")) - || (CHECK_FILE_EXTENSION(rcscript, "~"))) { - DBG_MSG("'%s' is not a valid rc-script!\n", - gbasename(rcscript)); - } else { - DBG_MSG("Adding rc-script '%s' to list.\n", - gbasename(rcscript)); - - info = malloc(sizeof(rcscript_info_t)); - if (NULL == info) { - DBG_MSG("Failed to allocate rcscript_info_t!\n"); - goto error; - } - - /* Copy the name */ - info->filename = strndup(rcscript, strlen(rcscript)); - if (NULL == info->filename) { - DBG_MSG("Failed to allocate buffer!\n"); - goto loop_error; - } - - /* Get the modification time */ - info->mtime = get_mtime(rcscript, 1); - if (0 == info->mtime) { - DBG_MSG("Failed to get modification time for '%s'!\n", - rcscript); - /* We do not care if it fails - we will pick up - * later if there is a problem with the file */ - } - - /* File name for the conf.d config file (if any) */ - confd_file = strcatpaths(RCSCRIPTS_CONFDDIR, gbasename(rcscript)); - if (NULL == confd_file) { - DBG_MSG("Failed to allocate temporary buffer!\n"); - goto loop_error; - } - - /* Get the modification time of the conf.d file - * (if any exists) */ - info->confd_mtime = get_mtime(confd_file, 1); - if (0 == info->confd_mtime) { - DBG_MSG("Failed to get modification time for '%s'!\n", - confd_file); - /* We do not care that it fails, as not all - * rc-scripts will have conf.d config files */ - } - - free(confd_file); - - list_add_tail(&info->node, &rcscript_list); - - continue; - -loop_error: - if (NULL != info) - free(info->filename); - free(info); - - goto error; - } - } +static size_t parse_rcscript (char *scriptname, dyn_buf_t * data); - /* Final check if we have some entries */ - if ((NULL == file_list) || (NULL == file_list[0])) { - DBG_MSG("No rc-scripts to parse!\n"); - errno = ENOENT; - goto error; - } - - STRING_LIST_FREE(file_list); - - return 0; - -error: - STRING_LIST_FREE(file_list); - - return -1; -} - -/* Returns 0 if we do not need to regen the cache file, else -1 with - * errno set if something went wrong */ -int check_rcscripts_mtime(char *cachefile) -{ - rcscript_info_t *info; - time_t cache_mtime; - time_t rc_conf_mtime; - time_t rc_confd_mtime; - - if ((NULL == cachefile) || (0 == strlen(cachefile))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return -1; - } - - cache_mtime = get_mtime(cachefile, 1); - if (0 == cache_mtime) { - DBG_MSG("Could not get modification time for cache file '%s'!\n", - cachefile); - return -1; - } - - /* Get and compare mtime for RC_CONF_FILE_NAME with that of cachefile */ - rc_conf_mtime = get_mtime(RC_CONF_FILE_NAME, 1); - if (rc_conf_mtime > cache_mtime) { - DBG_MSG("'%s' have a later modification time than '%s'.\n", - RC_CONF_FILE_NAME, cachefile); - return -1; - } - /* Get and compare mtime for RC_CONFD_FILE_NAME with that of cachefile */ - rc_confd_mtime = get_mtime(RC_CONFD_FILE_NAME, 1); - if (rc_confd_mtime > cache_mtime) { - DBG_MSG("'%s' have a later modification time than '%s'.\n", - RC_CONFD_FILE_NAME, cachefile); - return -1; - } - - /* Get and compare mtime for each rc-script and its conf.d config file - * with that of cachefile */ - list_for_each_entry(info, &rcscript_list, node) { - if ((info->mtime > cache_mtime) - || (info->confd_mtime > cache_mtime)) { - DBG_MSG("'%s' have a later modification time than '%s'.\n", - info->filename, cachefile); - return -1; - } - } - - return 0; -} +static size_t parse_print_start (dyn_buf_t * data); +static size_t parse_print_header (char *scriptname, dyn_buf_t * data); +static size_t parse_print_body (char *scriptname, dyn_buf_t * data); /* Return count on success, -1 on error. If it was critical, errno will be set. */ -size_t parse_rcscript(char *scriptname, char **data, size_t index) +size_t +parse_rcscript (char *scriptname, dyn_buf_t * data) { - regex_data_t tmp_data; - char *buf = NULL; - char *tmp_buf = NULL; - size_t write_count = index; - size_t lenght; - int count; - int current = 0; - - if ((NULL == scriptname) || (0 == strlen(scriptname))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return -1; + regex_data_t tmp_data; + char *buf = NULL; + char *tmp_buf = NULL; + size_t write_count = 0; + size_t tmp_count; + size_t lenght; + int count; + int current = 0; + + if (!check_arg_dyn_buf (data)) + return -1; + + if (!check_arg_str (scriptname)) + return -1; + + if (-1 == file_map (scriptname, &buf, &lenght)) + { + DBG_MSG ("Could not open '%s' for reading!\n", gbasename (scriptname)); + return -1; + } + + while (current < lenght) + { + count = buf_get_line (buf, lenght, current); + + tmp_buf = xstrndup (&(buf[current]), count); + if (NULL == tmp_buf) + goto error; + + if (0 == current) + { + DBG_MSG ("Parsing '%s'.\n", gbasename (scriptname)); + + tmp_count = parse_print_header (gbasename (scriptname), data); + if (-1 == tmp_count) + { + DBG_MSG ("Failed to call parse_print_header()!\n"); + goto error; + } + + write_count += tmp_count; + + goto _continue; } - - if (-1 == file_map(scriptname, &buf, &lenght)) { - DBG_MSG("Could not open '%s' for reading!\n", - gbasename(scriptname)); - return -1; + + /* Check for lines with comments, and skip them */ + DO_REGEX (tmp_data, tmp_buf, "^[ \t]*#", error); + if (REGEX_MATCH (tmp_data)) + goto _continue; + + /* If the line contains 'depend()', set 'got_depend' */ + DO_REGEX (tmp_data, tmp_buf, "depend[ \t]*()[ \t]*{?", error); + if (REGEX_MATCH (tmp_data)) + { + DBG_MSG ("Got 'depend()' function.\n"); + + tmp_count = parse_print_body (gbasename (scriptname), data); + if (-1 == tmp_count) + { + DBG_MSG ("Failed to call parse_print_body()!\n"); + goto error; + } + + write_count += tmp_count; + + /* Make sure this is the last loop */ + current += lenght; + goto _continue; } - - while (current < lenght) { - count = buf_get_line(buf, lenght, current); - - tmp_buf = strndup(&(buf[current]), count); - if (NULL == tmp_buf) { - DBG_MSG("Failed to allocate temporary buffer!\n"); - goto error; - } - if (0 == current) { - /* Check if it starts with '#!/sbin/runscript' */ - DO_REGEX(tmp_data, tmp_buf, - "[ \t]*#![ \t]*/sbin/runscript[ \t]*.*", error); - if (REGEX_FULL_MATCH != tmp_data.match) { - DBG_MSG("'%s' is not a valid rc-script!\n", - gbasename(scriptname)); - goto error; - } - - /* We do not want rc-scripts ending in '.sh' */ - if (CHECK_FILE_EXTENSION(scriptname, ".sh")) { - EWARN("'%s' is invalid (should not end with '.sh')!\n", - gbasename(scriptname)); - goto error; - } - DBG_MSG("Parsing '%s'.\n", gbasename(scriptname)); - - write_count = parse_print_header(gbasename(scriptname), - data, write_count); - if (-1 == write_count) { - DBG_MSG("Failed to call parse_print_header()!\n"); - goto error; - } - - goto _continue; - } - - /* Check for lines with comments, and skip them */ - DO_REGEX(tmp_data, tmp_buf, "^[ \t]*#", error); - if (REGEX_MATCH(tmp_data)) - goto _continue; - - /* If the line contains 'depend()', set 'got_depend' */ - DO_REGEX(tmp_data, tmp_buf, "depend[ \t]*()[ \t]*{?", error); - if (REGEX_MATCH(tmp_data)) { - DBG_MSG("Got 'depend()' function.\n"); - - write_count = parse_print_body(gbasename(scriptname), - data, write_count); - if (-1 == write_count) { - DBG_MSG("Failed to call parse_print_body()!\n"); - goto error; - } - - /* Make sure this is the last loop */ - current += lenght; - goto _continue; - } - _continue: - current += count + 1; - free(tmp_buf); - } + current += count + 1; + free (tmp_buf); + } - file_unmap(buf, lenght); - - return write_count; + file_unmap (buf, lenght); -error: - free(tmp_buf); - if (NULL != buf) { - int old_errno = errno; - file_unmap(buf, lenght); - /* file_unmap() might have changed it */ - errno = old_errno; - } + return write_count; - return -1; +error: + free (tmp_buf); + if (NULL != buf) + { + save_errno (); + file_unmap (buf, lenght); + /* file_unmap() might have changed it */ + restore_errno (); + } + + return -1; } -size_t generate_stage1(char **data) +size_t +generate_stage1 (dyn_buf_t * data) { - rcscript_info_t *info; - size_t write_count = 0; - size_t tmp_count; - - write_count = parse_print_start(data, write_count); - if (-1 == write_count) { - DBG_MSG("Failed to call parse_print_start()!\n"); - return -1; + rcscript_info_t *info; + size_t write_count = 0; + size_t tmp_count; + + if (!check_arg_dyn_buf (data)) + return -1; + + write_count = parse_print_start (data); + if (-1 == write_count) + { + DBG_MSG ("Failed to call parse_print_start()!\n"); + return -1; + } + + list_for_each_entry (info, &rcscript_list, node) + { + tmp_count = parse_rcscript (info->filename, data); + if (-1 == tmp_count) + { + DBG_MSG ("Failed to parse '%s'!\n", gbasename (info->filename)); + + /* If 'errno' is set, it is critical (hopefully) */ + if (0 != errno) + return -1; } - - list_for_each_entry(info, &rcscript_list, node) { - tmp_count = parse_rcscript(info->filename, data, write_count); - if (-1 == tmp_count) { - DBG_MSG("Failed to parse '%s'!\n", - gbasename(info->filename)); - - /* If 'errno' is set, it is critical (hopefully) */ - if (0 != errno) - return -1; - } else { - write_count = tmp_count; - } + else + { + write_count += tmp_count; } - - return write_count; + } + + return write_count; } /* Empty signal handler for SIGPIPE */ -static void sig_handler(int signum) +static void +sig_handler (int signum) { - return; + return; } /* Returns data's lenght on success, else -1 on error. */ -size_t generate_stage2(char **data) +size_t +generate_stage2 (dyn_buf_t * data) { - int pipe_fds[2][2] = { { 0, 0 }, { 0, 0 } }; - pid_t child_pid; - size_t write_count = 0; - int old_errno = 0; - - /* Pipe to send data to parent */ - if (-1 == pipe(pipe_fds[0])) { - DBG_MSG("Failed to open pipe!\n"); - goto error; - } - /* Pipe to send data to child */ - if (-1 == pipe(pipe_fds[1])) { - DBG_MSG("Failed to open pipe!\n"); - /* Close parent_pfds */ - goto error; + int pipe_fds[2][2] = { {0, 0}, {0, 0} }; + pid_t child_pid; + size_t write_count = 0; + int old_errno = 0; + + if (!check_arg_dyn_buf (data)) + return -1; + + /* Pipe to send data to parent */ + if (-1 == pipe (pipe_fds[0])) + { + DBG_MSG ("Failed to open pipe!\n"); + goto error; + } + /* Pipe to send data to child */ + if (-1 == pipe (pipe_fds[1])) + { + DBG_MSG ("Failed to open pipe!\n"); + /* Close parent_pfds */ + goto error; + } + + child_pid = fork (); + if (-1 == child_pid) + { + DBG_MSG ("Failed to fork()!\n"); + /* Close all pipes */ + goto error; + } + if (0 == child_pid) + { + /*** + *** In child + ***/ + + char *const argv[] = { + "bash", + "--noprofile", + "--norc", + "--", + NULL + }; + + /* Close the sides of the pipes we do not use */ + close (PARENT_WRITE_PIPE (pipe_fds)); + close (PARENT_READ_PIPE (pipe_fds)); + + /* dup2 child side read pipe to STDIN */ + dup2 (CHILD_READ_PIPE (pipe_fds), STDIN_FILENO); + /* dup2 child side write pipe to STDOUT */ + dup2 (CHILD_WRITE_PIPE (pipe_fds), STDOUT_FILENO); + + /* We need to be in RCSCRIPTS_INITDDIR for 'before'/'after' '*' to work */ + if (-1 == chdir (RCSCRIPTS_INITDDIR)) + { + DBG_MSG ("Failed to chdir to '%s'!\n", RCSCRIPTS_INITDDIR); + exit (EXIT_FAILURE); } - /* Zero data */ - *data = NULL; + if (-1 == execv (SHELL_PARSER, argv)) + { + DBG_MSG ("Failed to execv %s!\n", SHELL_PARSER); + exit (EXIT_FAILURE); + } + } + else + { + /*** + *** In parent + ***/ + + dyn_buf_t *stage1_data; + struct sigaction act_new; + struct sigaction act_old; + struct pollfd poll_fds[2]; + int status = 0; + + DBG_MSG ("Child pid = %i\n", child_pid); + + /* Set signal handler for SIGPIPE to empty in case bash errors + * out. It will then close the write pipe, and instead of us + * getting SIGPIPE, we can handle the write error like normal. + */ + memset (&act_new, 0x00, sizeof (act_new)); + act_new.sa_handler = (void (*)(int)) sig_handler; + sigemptyset (&act_new.sa_mask); + act_new.sa_flags = 0; + sigaction (SIGPIPE, &act_new, &act_old); + + /* Close the sides of the pipes we do not use */ + close (CHILD_WRITE_PIPE (pipe_fds)); + CHILD_WRITE_PIPE (pipe_fds) = 0; + close (CHILD_READ_PIPE (pipe_fds)); + CHILD_READ_PIPE (pipe_fds) = 0; + + stage1_data = new_dyn_buf (); + if (NULL == stage1_data) + { + DBG_MSG ("Failed to allocate dynamic buffer!\n"); + goto error; + } - child_pid = fork(); - if (-1 == child_pid) { - DBG_MSG("Failed to fork()!\n"); - /* Close all pipes */ - goto error; + /* Pipe parse_rcscripts() to bash */ + if (-1 == generate_stage1 (stage1_data)) + { + DBG_MSG ("Failed to generate stage1!\n"); + goto error; } - if (0 == child_pid) { - /*** - *** In child - ***/ - - char *const argv[] = { - "bash", - "--noprofile", - "--norc", - "--", - NULL - }; - - /* Close the sides of the pipes we do not use */ - close(PARENT_WRITE_PIPE(pipe_fds)); - close(PARENT_READ_PIPE(pipe_fds)); - - /* dup2 child side read pipe to STDIN */ - dup2(CHILD_READ_PIPE(pipe_fds), STDIN_FILENO); - /* dup2 child side write pipe to STDOUT */ - dup2(CHILD_WRITE_PIPE(pipe_fds), STDOUT_FILENO); - - /* We need to be in RCSCRIPTS_INITDDIR for 'before'/'after' '*' to work */ - if (-1 == chdir(RCSCRIPTS_INITDDIR)) { - DBG_MSG("Failed to chdir to '%s'!\n", RCSCRIPTS_INITDDIR); - exit(1); - } - if (-1 == execv(SHELL_PARSER, argv)) { - DBG_MSG("Failed to execv %s!\n", SHELL_PARSER); - exit(1); +#if 0 + int tmp_fd = open ("bar", O_CREAT | O_TRUNC | O_RDWR, 0600); + write (tmp_fd, stage1_data->data, stage1_write_count); + close (tmp_fd); +#endif + + do + { + int tmp_count = 0; + int do_write = 0; + int do_read = 0; + + /* Check if we can write or read */ + poll_fds[WRITE_PIPE].fd = PARENT_WRITE_PIPE (pipe_fds); + poll_fds[WRITE_PIPE].events = POLLOUT; + poll_fds[READ_PIPE].fd = PARENT_READ_PIPE (pipe_fds); + poll_fds[READ_PIPE].events = POLLIN | POLLPRI; + if (!dyn_buf_rd_eof (stage1_data)) + { + poll (poll_fds, 2, -1); + if (poll_fds[WRITE_PIPE].revents & POLLOUT) + do_write = 1; + } + else + { + poll (&(poll_fds[READ_PIPE]), 1, -1); + } + if ((poll_fds[READ_PIPE].revents & POLLIN) + || (poll_fds[READ_PIPE].revents & POLLPRI)) + do_read = 1; + + do + { + /* While we can write, or there is nothing to + * read, keep feeding the write pipe */ + if ((dyn_buf_rd_eof (stage1_data)) + || (1 == do_read) + || (1 != do_write)) + break; + + tmp_count = read_dyn_buf_to_fd (PARENT_WRITE_PIPE (pipe_fds), + stage1_data, PARSE_BUFFER_SIZE); + if ((-1 == tmp_count) && (EINTR != errno)) + { + DBG_MSG ("Error writing to PARENT_WRITE_PIPE!\n"); + goto failed; } - } else { - /*** - *** In parent - ***/ - - struct sigaction act_new; - struct sigaction act_old; - struct pollfd poll_fds[2]; - char buf[PARSE_BUFFER_SIZE+1]; - char *stage1_data = NULL; - size_t stage1_write_count = 0; - size_t stage1_written = 0; - int status = 0; - - DBG_MSG("Child pid = %i\n", child_pid); - - /* Set signal handler for SIGPIPE to empty in case bash errors - * out. It will then close the write pipe, and instead of us - * getting SIGPIPE, we can handle the write error like normal. - */ - memset(&act_new, 0x00, sizeof(act_new)); - act_new.sa_handler = (void (*) (int))sig_handler; - sigemptyset (&act_new.sa_mask); - act_new.sa_flags = 0; - sigaction(SIGPIPE, &act_new, &act_old); - - /* Close the sides of the pipes we do not use */ - close(CHILD_WRITE_PIPE(pipe_fds)); - CHILD_WRITE_PIPE(pipe_fds) = 0; - close(CHILD_READ_PIPE(pipe_fds)); - CHILD_READ_PIPE(pipe_fds) = 0; - - stage1_data = malloc(OUTPUT_BUFFER_SIZE + 1); - if (NULL == stage1_data) { - DBG_MSG("Failed to allocate buffer!\n"); - goto error; + /* We were interrupted, try to write again */ + if (-1 == tmp_count) + { + errno = 0; + /* Make sure we retry */ + tmp_count = 1; + continue; } - /* Pipe parse_rcscripts() to bash */ - stage1_write_count = generate_stage1(&stage1_data); - if (-1 == stage1_write_count) { - DBG_MSG("Failed to generate stage1!\n"); - goto error; + /* Close the write pipe if we done + * writing to get a EOF signaled to + * bash */ + if (dyn_buf_rd_eof (stage1_data)) + { + close (PARENT_WRITE_PIPE (pipe_fds)); + PARENT_WRITE_PIPE (pipe_fds) = 0; + } + } + while ((tmp_count > 0) && (!dyn_buf_rd_eof (stage1_data))); + + /* Reset tmp_count for below read loop */ + tmp_count = 0; + + do + { + if (1 != do_read) + continue; + + tmp_count = write_dyn_buf_from_fd (PARENT_READ_PIPE (pipe_fds), + data, PARSE_BUFFER_SIZE); + if ((-1 == tmp_count) && (EINTR != errno)) + { + DBG_MSG ("Error reading PARENT_READ_PIPE!\n"); + goto failed; + } + /* We were interrupted, try to read again */ + if ((-1 == tmp_count) || (0 == tmp_count)) + { + errno = 0; + continue; } -#if 0 - int tmp_fd = open("bar", O_CREAT | O_TRUNC | O_RDWR, 0600); - write(tmp_fd, stage1_data, stage1_write_count); - close(tmp_fd); -#endif - - do { - int tmp_count = 0; - int do_write = 0; - int do_read = 0; - - /* Check if we can write or read */ - poll_fds[WRITE_PIPE].fd = PARENT_WRITE_PIPE(pipe_fds); - poll_fds[WRITE_PIPE].events = POLLOUT; - poll_fds[READ_PIPE].fd = PARENT_READ_PIPE(pipe_fds); - poll_fds[READ_PIPE].events = POLLIN | POLLPRI; - if (stage1_written < stage1_write_count) { - poll(poll_fds, 2, -1); - if (poll_fds[WRITE_PIPE].revents & POLLOUT) - do_write = 1; - } else { - poll(&(poll_fds[READ_PIPE]), 1, -1); - } - if ((poll_fds[READ_PIPE].revents & POLLIN) - || (poll_fds[READ_PIPE].revents & POLLPRI)) - do_read = 1; - - do { - /* If we can write, or there is nothing to - * read, keep feeding the write pipe */ - if ((stage1_written >= stage1_write_count) - || (1 == do_read) - || (1 != do_write)) - break; - - tmp_count = write(PARENT_WRITE_PIPE(pipe_fds), - &stage1_data[stage1_written], - strlen(&stage1_data[stage1_written])); - if ((-1 == tmp_count) && (EINTR != errno)) { - DBG_MSG("Error writing to PARENT_WRITE_PIPE!\n"); - goto failed; - } - /* We were interrupted, try to write again */ - if (-1 == tmp_count) { - errno = 0; - /* Make sure we retry */ - tmp_count = 1; - continue; - } - /* What was written before, plus what - * we wrote now as well as the ending - * '\0' of the line */ - stage1_written += tmp_count + 1; - - /* Close the write pipe if we done - * writing to get a EOF signaled to - * bash */ - if (stage1_written >= stage1_write_count) { - close(PARENT_WRITE_PIPE(pipe_fds)); - PARENT_WRITE_PIPE(pipe_fds) = 0; - } - } while ((tmp_count > 0) && (stage1_written < stage1_write_count)); - - /* Reset tmp_count for below read loop */ - tmp_count = 0; - - do { - char *tmp_p; - - if (1 != do_read) - continue; - - tmp_count = read(PARENT_READ_PIPE(pipe_fds), buf, - PARSE_BUFFER_SIZE); - if ((-1 == tmp_count) && (EINTR != errno)) { - DBG_MSG("Error reading PARENT_READ_PIPE!\n"); - goto failed; - } - /* We were interrupted, try to read again */ - if ((-1 == tmp_count) || (0 == tmp_count)) { - errno = 0; - continue; - } - - tmp_p = realloc(*data, write_count + tmp_count); - if (NULL == tmp_p) { - DBG_MSG("Failed to allocate buffer!\n"); - goto failed; - } - - memcpy(&tmp_p[write_count], buf, tmp_count); - - *data = tmp_p; - write_count += tmp_count; - } while (tmp_count > 0); - } while (!(poll_fds[READ_PIPE].revents & POLLHUP)); + write_count += tmp_count; + } + while (tmp_count > 0); + } + while (!(poll_fds[READ_PIPE].revents & POLLHUP)); failed: - /* Set old_errno to disable child exit code checking below */ - if (0 != errno) - old_errno = errno; - - free(stage1_data); - - if (0 != PARENT_WRITE_PIPE(pipe_fds)) - close(PARENT_WRITE_PIPE(pipe_fds)); - close(PARENT_READ_PIPE(pipe_fds)); - - /* Restore the old signal handler for SIGPIPE */ - sigaction(SIGPIPE, &act_old, NULL); - - /* Wait for bash to finish */ - waitpid(child_pid, &status, 0); - /* If old_errno is set, we had an error in the read loop, so do - * not worry about the child's exit code */ - if (0 == old_errno) { - if ((!WIFEXITED(status)) || (0 != WEXITSTATUS(status))) { - DBG_MSG("Bash failed with status 0x%x!\n", status); - return -1; - } - } else { - /* Right, we had an error, so set errno, and exit */ - errno = old_errno; - return -1; - } + /* Set old_errno to disable child exit code checking below */ + if (0 != errno) + old_errno = errno; + + free_dyn_buf (stage1_data); + + if (0 != PARENT_WRITE_PIPE (pipe_fds)) + close (PARENT_WRITE_PIPE (pipe_fds)); + close (PARENT_READ_PIPE (pipe_fds)); + + /* Restore the old signal handler for SIGPIPE */ + sigaction (SIGPIPE, &act_old, NULL); + + /* Wait for bash to finish */ + waitpid (child_pid, &status, 0); + /* If old_errno is set, we had an error in the read loop, so do + * not worry about the child's exit code */ + if (0 == old_errno) + { + if ((!WIFEXITED (status)) || (0 != WEXITSTATUS (status))) + { + /* FIXME: better errno ? */ + errno = ECANCELED; + DBG_MSG ("Bash failed with status 0x%x!\n", status); + + return -1; + } } + else + { + /* Right, we had an error, so set errno, and exit */ + errno = old_errno; + return -1; + } + } - return write_count; + return write_count; - /* Close parent side pipes */ + /* Close parent side pipes */ error: - /* Close all pipes */ - old_errno = errno; - if (0 != CHILD_READ_PIPE(pipe_fds)) - close(CHILD_READ_PIPE(pipe_fds)); - if (0 != CHILD_WRITE_PIPE(pipe_fds)) - close(CHILD_WRITE_PIPE(pipe_fds)); - if (0 != PARENT_READ_PIPE(pipe_fds)) - close(PARENT_READ_PIPE(pipe_fds)); - if (0 != PARENT_WRITE_PIPE(pipe_fds)) - close(PARENT_WRITE_PIPE(pipe_fds)); - /* close() might have changed it */ - errno = old_errno; - - return -1; + /* Close all pipes */ + old_errno = errno; + if (0 != CHILD_READ_PIPE (pipe_fds)) + close (CHILD_READ_PIPE (pipe_fds)); + if (0 != CHILD_WRITE_PIPE (pipe_fds)) + close (CHILD_WRITE_PIPE (pipe_fds)); + if (0 != PARENT_READ_PIPE (pipe_fds)) + close (PARENT_READ_PIPE (pipe_fds)); + if (0 != PARENT_WRITE_PIPE (pipe_fds)) + close (PARENT_WRITE_PIPE (pipe_fds)); + /* close() might have changed it */ + errno = old_errno; + + return -1; } -int write_legacy_stage3(FILE *output) +int +write_legacy_stage3 (FILE * output) { - service_info_t *info; - char *service; - int count; - int index = 0; - int dep_count; - int i; - - if (-1 == fileno(output)) { - DBG_MSG("Bad output stream!\n"); - return -1; + service_info_t *info; + char *service; + int count; + int sindex = 0; + int dep_count; + int i; + + if (!check_arg_fp (output)) + return -1; + + fprintf (output, "rc_type_ineed=2\n"); + fprintf (output, "rc_type_needsme=3\n"); + fprintf (output, "rc_type_iuse=4\n"); + fprintf (output, "rc_type_usesme=5\n"); + fprintf (output, "rc_type_ibefore=6\n"); + fprintf (output, "rc_type_iafter=7\n"); + fprintf (output, "rc_type_broken=8\n"); + fprintf (output, "rc_type_mtime=9\n"); + fprintf (output, "rc_index_scale=10\n\n"); + fprintf (output, "declare -a RC_DEPEND_TREE\n\n"); + + list_for_each_entry (info, &service_info_list, node) + { + sindex++; + } + if (0 == sindex) + { + EERROR ("No services to generate dependency tree for!\n"); + return -1; + } + + fprintf (output, "RC_DEPEND_TREE[0]=%i\n\n", sindex); + + sindex = 1; + + list_for_each_entry (info, &service_info_list, node) + { + fprintf (output, "RC_DEPEND_TREE[%i]=\"%s\"\n", sindex * 10, info->name); + + for (i = 0; i <= BROKEN; i++) + { + dep_count = 0; + + fprintf (output, "RC_DEPEND_TREE[%i+%i]=", (sindex * 10), (i + 2)); + + str_list_for_each_item (info->depend_info[i], service, count) + { + if (0 == dep_count) + fprintf (output, "\"%s", service); + else + fprintf (output, " %s", service); + + dep_count++; + } + + if (dep_count > 0) + fprintf (output, "\"\n"); + else + fprintf (output, "\n"); } - fprintf(output, "rc_type_ineed=2\n"); - fprintf(output, "rc_type_needsme=3\n"); - fprintf(output, "rc_type_iuse=4\n"); - fprintf(output, "rc_type_usesme=5\n"); - fprintf(output, "rc_type_ibefore=6\n"); - fprintf(output, "rc_type_iafter=7\n"); - fprintf(output, "rc_type_broken=8\n"); - fprintf(output, "rc_type_mtime=9\n"); - fprintf(output, "rc_index_scale=10\n\n"); - fprintf(output, "declare -a RC_DEPEND_TREE\n\n"); - - list_for_each_entry(info, &service_info_list, node) { - index++; - } - if (0 == index) { - EERROR("No services to generate dependency tree for!\n"); - return -1; - } + fprintf (output, "RC_DEPEND_TREE[%i+9]=\"%li\"\n\n", + sindex * 10, info->mtime); + sindex++; + } - fprintf(output, "RC_DEPEND_TREE[0]=%i\n\n", index); - - index = 1; - - list_for_each_entry(info, &service_info_list, node) { - fprintf(output, "RC_DEPEND_TREE[%i]=\"%s\"\n", - index * 10, info->name); - - for (i = 0;i <= BROKEN;i++) { - dep_count = 0; - - fprintf(output, "RC_DEPEND_TREE[%i+%i]=", - (index * 10), (i + 2)); - - STRING_LIST_FOR_EACH(info->depend_info[i], service, count) { - if (0 == dep_count) - fprintf(output, "\"%s", service); - else - fprintf(output, " %s", service); - - dep_count++; - } - - if (dep_count > 0) - fprintf(output, "\"\n"); - else - fprintf(output, "\n"); - } - - fprintf(output, "RC_DEPEND_TREE[%i+9]=\"%li\"\n\n", - index * 10, info->mtime); - index++; - } + fprintf (output, "RC_GOT_DEPTREE_INFO=\"yes\"\n"); - fprintf(output, "RC_GOT_DEPTREE_INFO=\"yes\"\n"); - - info = service_get_virtual("logger"); - if (NULL == info) { - DBG_MSG("No service provides the 'logger' logger virtual!\n"); - fprintf(output, "\nLOGGER_SERVICE=\n"); - } else { - fprintf(output, "\nLOGGER_SERVICE=\"%s\"\n", info->name); - } + info = service_get_virtual ("logger"); + if (NULL == info) + { + DBG_MSG ("No service provides the 'logger' logger virtual!\n"); + fprintf (output, "\nLOGGER_SERVICE=\n"); + } + else + { + fprintf (output, "\nLOGGER_SERVICE=\"%s\"\n", info->name); + } - - return 0; + + return 0; } -int parse_cache(const char *data, size_t lenght) +int +parse_cache (const dyn_buf_t * data) { - service_info_t *info; - service_type_t type = ALL_SERVICE_TYPE_T; - rcscript_info_t *rs_info; - char *tmp_buf = NULL; - char *rc_name = NULL; - char *tmp_p; - char *token; - char *field; - int count; - int current = 0; - int retval; - - if ((NULL == data) || (lenght <= 0)) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - goto error; + service_info_t *info; + service_type_t type = ALL_SERVICE_TYPE_T; + rcscript_info_t *rs_info; + char *tmp_buf = NULL; + char *rc_name = NULL; + char *tmp_p; + char *token; + char *field; + int retval; + + if (!check_arg_dyn_buf ((dyn_buf_t *) data)) + goto error; + + while (NULL != (tmp_buf = read_line_dyn_buf ((dyn_buf_t *) data))) + { + tmp_p = tmp_buf; + + /* Strip leading spaces/tabs */ + while ((tmp_p[0] == ' ') || (tmp_p[0] == '\t')) + tmp_p++; + + /* Get FIELD name and FIELD value */ + token = strsep (&tmp_p, " "); + + /* FIELD name empty/bogus? */ + if ((!check_str (token)) + /* We got an empty FIELD value */ + || (!check_str (tmp_p))) + { + errno = EMSGSIZE; + DBG_MSG ("Parsing stopped due to short read!\n"); + goto error; } - while (current < lenght) { - count = buf_get_line((char *)data, lenght, current); + if (0 == strcmp (token, FIELD_RCSCRIPT)) + { + DBG_MSG ("Field = '%s', value = '%s'\n", token, tmp_p); + + /* Add the service to the list, and initialize all data */ + retval = service_add (tmp_p); + if (-1 == retval) + { + DBG_MSG ("Failed to add %s to service list!\n", tmp_p); + goto error; + } + + info = service_get_info (tmp_p); + if (NULL == info) + { + DBG_MSG ("Failed to get info for '%s'!\n", tmp_p); + goto error; + } + /* Save the rc-script name for next passes of loop */ + rc_name = info->name; + + goto _continue; + } - tmp_buf = strndup(&(data[current]), count); - if (NULL == tmp_buf) { - DBG_MSG("Failed to allocate temporary buffer!\n"); - goto error; - } - tmp_p = tmp_buf; - - /* Strip leading spaces/tabs */ - while ((tmp_p[0] == ' ') || (tmp_p[0] == '\t')) - tmp_p++; - - /* Get FIELD name and FIELD value */ - token = strsep(&tmp_p, " "); - - /* FIELD name empty/bogus? */ - if ((NULL == token) - || (0 == strlen(token)) - /* We got an empty FIELD value */ - || (NULL == tmp_p) - || (0 == strlen(tmp_p))) { - DBG_MSG("Parsing stopped due to short read!\n"); - errno = EMSGSIZE; - goto error; - } + if (NULL == rc_name) + { + DBG_MSG ("Other fields should come after '%s'!\n", FIELD_RCSCRIPT); + goto error; + } - if (0 == strcmp(token, FIELD_RCSCRIPT)) { - DBG_MSG("Field = '%s', value = '%s'\n", token, tmp_p); - - /* Add the service to the list, and initialize all data */ - retval = service_add(tmp_p); - if (-1 == retval) { - DBG_MSG("Failed to add %s to service list!\n", tmp_p); - goto error; - } - - info = service_get_info(tmp_p); - if (NULL == info) { - DBG_MSG("Failed to get info for '%s'!\n", tmp_p); - goto error; - } - /* Save the rc-script name for next passes of loop */ - rc_name = info->name; - - goto _continue; - } + if (0 == strcmp (token, FIELD_NEED)) + type = NEED; + else if (0 == strcmp (token, FIELD_USE)) + type = USE; + else if (0 == strcmp (token, FIELD_BEFORE)) + type = BEFORE; + else if (0 == strcmp (token, FIELD_AFTER)) + type = AFTER; + else if (0 == strcmp (token, FIELD_PROVIDE)) + type = PROVIDE; + else if (0 == strcmp (token, FIELD_FAILED)) + { + type = BROKEN; + + /* FIXME: Need to think about what to do syntax BROKEN + * services */ + EWARN ("'%s' has syntax errors, please correct!\n", rc_name); + } - if (NULL == rc_name) { - DBG_MSG("Other fields should come after '%s'!\n", FIELD_RCSCRIPT); - goto error; + if (type < ALL_SERVICE_TYPE_T) + { + /* Get the first value * + * As the values are passed to a bash function, and we + * then use 'echo $*' to parse them, they should only + * have one space between each value ... */ + token = strsep (&tmp_p, " "); + + /* Get the correct type name */ + field = service_type_names[type]; + + while (NULL != token) + { + DBG_MSG ("Field = '%s', service = '%s', value = '%s'\n", + field, rc_name, token); + + retval = service_add_dependency (rc_name, token, type); + if (-1 == retval) + { + DBG_MSG + ("Failed to add dependency '%s' to service '%s', type '%s'!\n", + token, rc_name, field); + goto error; } - if (0 == strcmp(token, FIELD_NEED)) - type = NEED; - else if (0 == strcmp(token, FIELD_USE)) - type = USE; - else if (0 == strcmp(token, FIELD_BEFORE)) - type = BEFORE; - else if (0 == strcmp(token, FIELD_AFTER)) - type = AFTER; - else if (0 == strcmp(token, FIELD_PROVIDE)) - type = PROVIDE; - else if (0 == strcmp(token, FIELD_FAILED)) { - type = BROKEN; - - /* FIXME: Need to think about what to do syntax BROKEN - * services */ - EWARN("'%s' has syntax errors, please correct!\n", rc_name); - } + /* Get the next value (if any) */ + token = strsep (&tmp_p, " "); + } - if (type < ALL_SERVICE_TYPE_T) { - /* Get the first value * - * As the values are passed to a bash function, and we - * then use 'echo $*' to parse them, they should only - * have one space between each value ... */ - token = strsep(&tmp_p, " "); - - /* Get the correct type name */ - field = service_type_names[type]; - - while (NULL != token) { - DBG_MSG("Field = '%s', service = '%s', value = '%s'\n", - field, rc_name, token); - - retval = service_add_dependency(rc_name, token, type); - if (-1 == retval) { - DBG_MSG("Failed to add dependency '%s' to service '%s', type '%s'!\n", - token, rc_name, field); - goto error; - } - - /* Get the next value (if any) */ - token = strsep(&tmp_p, " "); - } - - goto _continue; - } + goto _continue; + } - /* Fall through */ - DBG_MSG("Unknown FIELD in data!\n"); + /* Fall through */ + DBG_MSG ("Unknown FIELD in data!\n"); _continue: - type = ALL_SERVICE_TYPE_T; - current += count + 1; - free(tmp_buf); - /* Do not free 'rc_name', as it should be consistant - * across loops */ + type = ALL_SERVICE_TYPE_T; + free (tmp_buf); + /* Do not free 'rc_name', as it should be consistant + * across loops */ + } + + /* read_line_dyn_buf() returned NULL with errno set */ + if (0 != errno) + { + DBG_MSG ("Failed to read line from dynamic buffer!\n"); + goto error; + } + + /* Set the mtimes + * FIXME: Can drop this when we no longer need write_legacy_stage3() */ + list_for_each_entry (rs_info, &rcscript_list, node) + { + rc_name = gbasename (rs_info->filename); + if (NULL == service_get_info (rc_name)) + continue; + + retval = service_set_mtime (rc_name, rs_info->mtime); + if (-1 == retval) + { + DBG_MSG ("Failed to set mtime for service '%s'!\n", rc_name); + return -1; } + } - /* Set the mtimes - * FIXME: Can drop this when we no longer need write_legacy_stage3() */ - list_for_each_entry(rs_info, &rcscript_list, node) { - rc_name = gbasename(rs_info->filename); - if (NULL == service_get_info(rc_name)) - continue; - - retval = service_set_mtime(rc_name, rs_info->mtime); - if (-1 == retval) { - DBG_MSG("Failed to set mtime for service '%s'!\n", rc_name); - return -1; - } - } - - return 0; + return 0; error: - free(tmp_buf); - - return -1; + free (tmp_buf); + + return -1; } -size_t parse_print_start(char **data, size_t index) +size_t +parse_print_start (dyn_buf_t * data) { - size_t write_count = index; - - PRINT_TO_BUFFER(data, write_count, error, - ". /sbin/functions.sh\n" - "[ -e /etc/rc.conf ] && . /etc/rc.conf\n" - "\n" - /* "set -e\n" */ - "\n"); - - return write_count; - -error: - return -1; + size_t write_count; + + if (!check_arg_dyn_buf (data)) + return -1; + + write_count = + sprintf_dyn_buf (data, + ". /sbin/functions.sh\n" + "[ -e /etc/rc.conf ] && . /etc/rc.conf\n" + "\n" + /* "set -e\n" */ + "\n"); + + return write_count; } -size_t parse_print_header(char *scriptname, char **data, size_t index) +size_t +parse_print_header (char *scriptname, dyn_buf_t * data) { - size_t write_count = index; - - PRINT_TO_BUFFER(data, write_count, error, - "#*** %s ***\n" - "\n" - "myservice=\"%s\"\n" - "echo \"RCSCRIPT ${myservice}\"\n" - "\n", - scriptname, scriptname); - - return write_count; - -error: - return -1; + size_t write_count; + + if (!check_arg_dyn_buf (data)) + return -1; + + write_count = + sprintf_dyn_buf (data, + "#*** %s ***\n" + "\n" + "myservice=\"%s\"\n" + "echo \"RCSCRIPT ${myservice}\"\n" + "\n", scriptname, scriptname); + + return write_count; } -size_t parse_print_body(char *scriptname, char **data, size_t index) +size_t +parse_print_body (char *scriptname, dyn_buf_t * data) { - size_t write_count = index; - char *tmp_buf = NULL; - char *tmp_ptr; - char *base; - char *ext; - - tmp_buf = strndup(scriptname, strlen(scriptname)); - if (NULL == tmp_buf) { - DBG_MSG("Failed to allocate temporary buffer!\n"); - goto error; - } - - /* - * Rather do the next block in C than bash, in case we want to - * use ash or another shell in the place of bash - */ - - /* bash: base="${myservice%%.*}" */ - base = tmp_buf; - tmp_ptr = strchr(tmp_buf, '.'); - if (NULL != tmp_ptr) { - tmp_ptr[0] = '\0'; - tmp_ptr++; - } else { - tmp_ptr = tmp_buf; - } - /* bash: ext="${myservice##*.}" */ - ext = strrchr(tmp_ptr, '.'); - if (NULL == ext) - ext = tmp_ptr; - - PRINT_TO_BUFFER(data, write_count, error, - "\n" - "(\n" - " # Get settings for rc-script ...\n" - " [ -e \"/etc/conf.d/${myservice}\" ] && \\\n" - " . \"/etc/conf.d/${myservice}\"\n" - " [ -e /etc/conf.d/net ] && \\\n" - " [ \"%s\" = \"net\" ] && \\\n" - " [ \"%s\" != \"${myservice}\" ] && \\\n" - " . /etc/conf.d/net\n" - " depend() {\n" - " return 0\n" - " }\n" - " \n" - " # Actual depend() function ...\n" - " (\n" - " set -e\n" - " . \"/etc/init.d/%s\" >/dev/null 2>&1\n" - " set +e\n" - " \n" - " need() {\n" - " [ \"$#\" -gt 0 ] && echo \"NEED $*\"; return 0\n" - " }\n" - " \n" - " use() {\n" - " [ \"$#\" -gt 0 ] && echo \"USE $*\"; return 0\n" - " }\n" - " \n" - " before() {\n" - " [ \"$#\" -gt 0 ] && echo \"BEFORE $*\"; return 0\n" - " }\n" - " \n" - " after() {\n" - " [ \"$#\" -gt 0 ] && echo \"AFTER $*\"; return 0\n" - " }\n" - " \n" - " provide() {\n" - " [ \"$#\" -gt 0 ] && echo \"PROVIDE $*\"; return 0\n" - " }\n" - " \n" - " depend\n" - " ) || echo \"FAILED ${myservice}\"\n" - ")\n" - "\n\n", - base, ext, scriptname); - - return write_count; - -error: - return -1; + size_t write_count; + char *tmp_buf = NULL; + char *tmp_ptr; + char *base; + char *ext; + + if (!check_arg_dyn_buf (data)) + return -1; + + tmp_buf = xstrndup (scriptname, strlen (scriptname)); + if (NULL == tmp_buf) + return -1; + + /* + * Rather do the next block in C than bash, in case we want to + * use ash or another shell in the place of bash + */ + + /* bash: base="${myservice%%.*}" */ + base = tmp_buf; + tmp_ptr = strchr (tmp_buf, '.'); + if (NULL != tmp_ptr) + { + tmp_ptr[0] = '\0'; + tmp_ptr++; + } + else + { + tmp_ptr = tmp_buf; + } + /* bash: ext="${myservice##*.}" */ + ext = strrchr (tmp_ptr, '.'); + if (NULL == ext) + ext = tmp_ptr; + + write_count = + sprintf_dyn_buf (data, + "\n" + "(\n" + " # Get settings for rc-script ...\n" + " [ -e \"/etc/conf.d/${myservice}\" ] && \\\n" + " . \"/etc/conf.d/${myservice}\"\n" + " [ -e /etc/conf.d/net ] && \\\n" + " [ \"%s\" = \"net\" ] && \\\n" + " [ \"%s\" != \"${myservice}\" ] && \\\n" + " . /etc/conf.d/net\n" + " depend() {\n" + " return 0\n" + " }\n" + " \n" + " # Actual depend() function ...\n" + " (\n" + " set -e\n" + " . \"/etc/init.d/%s\" >/dev/null 2>&1\n" + " set +e\n" + " \n" + " need() {\n" + " [ \"$#\" -gt 0 ] && echo \"NEED $*\"; return 0\n" + " }\n" + " \n" + " use() {\n" + " [ \"$#\" -gt 0 ] && echo \"USE $*\"; return 0\n" + " }\n" + " \n" + " before() {\n" + " [ \"$#\" -gt 0 ] && echo \"BEFORE $*\"; return 0\n" + " }\n" + " \n" + " after() {\n" + " [ \"$#\" -gt 0 ] && echo \"AFTER $*\"; return 0\n" + " }\n" + " \n" + " provide() {\n" + " [ \"$#\" -gt 0 ] && echo \"PROVIDE $*\"; return 0\n" + " }\n" + " \n" + " depend\n" + " ) || echo \"FAILED ${myservice}\"\n" + ")\n" "\n\n", base, ext, scriptname); + + return write_count; } - diff --git a/src/core/librcscripts/parse.h b/src/core/librcscripts/parse.h index 58e7540..e69de29 100644 --- a/src/core/librcscripts/parse.h +++ b/src/core/librcscripts/parse.h @@ -1,100 +0,0 @@ -/* - * parse.h - * - * Parser for Gentoo style rc-scripts. - * - * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> - * - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Header$ - */ - -#ifndef _PARSE_H -#define _PARSE_H - -#include <sys/types.h> -#include "list.h" - -#define LEGACY_CACHE_FILE_NAME "deptree" - -#define FIELD_RCSCRIPT "RCSCRIPT" -#define FIELD_NEED "NEED" -#define FIELD_USE "USE" -#define FIELD_BEFORE "BEFORE" -#define FIELD_AFTER "AFTER" -#define FIELD_PROVIDE "PROVIDE" -#define FIELD_FAILED "FAILED" - -typedef struct { - struct list_head node; - - char *filename; - time_t mtime; - time_t confd_mtime; -} rcscript_info_t; - -struct list_head rcscript_list; - -int get_rcscripts(void); -int check_rcscripts_mtime(char *cachefile); -size_t generate_stage1(char **data); -size_t generate_stage2(char **data); -size_t read_stage2(char **data); -int write_stage2(FILE *outfile); -size_t generate_stage3(char **data); -size_t read_stage3(char **data); -int write_stage3(FILE *outfile); -int write_legacy_stage3(FILE *output); -int parse_cache(const char *data, size_t lenght); - -/* - * get_rcscripts() - * | - * V - * check_rcscripts_mtime() ------------------------------> read_stage3() - * | | - * | | - * V V - * generate_stage1() (Called by generate_stage2()) parse_cache() - * | | - * | | - * V | - * generate_stage2() ----> write_stage2() (Debugging) | - * | | - * | | - * | === parse_cache() | - * V | | | - * generate_stage3() ==| | | - * | | | | - * | | V | - * | === service_resolve_dependencies() | - * | | - * | | - * |-------> write_legacy_stage3() (Proof of Concept | - * | or Debugging) | - * | | - * V | - * write_stage3() | - * | | - * | V - * |<------------------------------------------------------- - * | - * V - * - */ - -#endif /* _PARSE_H */ - diff --git a/src/core/librcscripts/rcscripts.h b/src/core/librcscripts/rcscripts.h index ea1c9c9..3740832 100644 --- a/src/core/librcscripts/rcscripts.h +++ b/src/core/librcscripts/rcscripts.h @@ -22,13 +22,32 @@ * $Header$ */ -#ifndef _RCSCRIPTS_H -#define _RCSCRIPTS_H +#ifndef __RCSCRIPTS_H__ +#define __RCSCRIPTS_H__ + +#include <stddef.h> +#include <sys/types.h> + +#include "config.h" + +#include "api/rctypes.h" +#include "api/debug.h" +#include "api/misc.h" +#include "api/list.h" +#include "api/str_list.h" +#include "api/dynbuf.h" +#include "api/simple-regex.h" +#include "api/scripts.h" +#include "api/runlevels.h" +#include "api/parse.h" +#include "api/depend.h" #define RCSCRIPTS_CONFDDIR ETCDIR "/conf.d" #define RCSCRIPTS_INITDDIR ETCDIR "/init.d" #define RCSCRIPTS_LIBDIR LIBDIR "/rcscripts" +#define RUNLEVELS_DIR ETCDIR "/runlevels" + #define SBIN_RC SBINDIR "/rc" #define PROFILE_ENV ETCDIR "/profile.env" @@ -50,5 +69,4 @@ #define SOFTLEVEL "SOFTLEVEL" -#endif /* _RCSCRIPTS_H */ - +#endif /* __RCSCRIPTS_H__ */ diff --git a/src/core/librcscripts/runlevels.c b/src/core/librcscripts/runlevels.c new file mode 100644 index 0000000..b2d8442 --- /dev/null +++ b/src/core/librcscripts/runlevels.c @@ -0,0 +1,218 @@ +/* + * runlevels.c + * + * Functions dealing with runlevels. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "rcscripts.h" + +static char ** get_runlevel_dirs (void); + +LIST_HEAD (runlevel_list); + +char ** +get_runlevel_dirs (void) +{ + char **dir_list = NULL; + char **runlvl_list = NULL; + char *dir_item; + int count; + + dir_list = ls_dir (RUNLEVELS_DIR, 0); + if (NULL == dir_list) + { + errno = ENOENT; + DBG_MSG ("Failed to get any entries in '%' !\n", RUNLEVELS_DIR); + + return NULL; + } + + str_list_for_each_item (dir_list, dir_item, count) + { + if (is_dir (dir_item, 0)) + { + char *tmp_str; + + tmp_str = xstrndup (dir_item, strlen (dir_item)); + if (NULL == tmp_str) + goto error; + + str_list_add_item (runlvl_list, tmp_str, error); + } + } + + str_list_free (dir_list); + + if (!check_strv (runlvl_list)) + { + if (NULL != runlvl_list) + str_list_free (runlvl_list); + } + + return runlvl_list; + +error: + if (NULL != dir_list) + str_list_free (dir_list); + if (NULL != runlvl_list) + str_list_free (runlvl_list); + + return NULL; +} + +int +get_runlevels (void) +{ + char **runlvl_list = NULL; + char *runlevel; + int count; + + runlvl_list = get_runlevel_dirs (); + if (NULL == runlvl_list) + { + DBG_MSG ("Failed to get any runlevels\n"); + + return -1; + } + + str_list_for_each_item (runlvl_list, runlevel, count) + { + runlevel_info_t *runlevel_info; + char **dir_list = NULL; + char *dir_item; + int dir_count; + + DBG_MSG ("Adding runlevel '%s'\n", gbasename (runlevel)); + + runlevel_info = xmalloc (sizeof (runlevel_info_t)); + if (NULL == runlevel_info) + goto error; + + runlevel_info->dirname = xstrndup (runlevel, strlen (runlevel)); + if (NULL == runlevel_info->dirname) + goto error; + + INIT_LIST_HEAD (&runlevel_info->entries); + + dir_list = ls_dir (runlevel, 0); + if (NULL == dir_list) + { + if (0 != errno) + goto error; + + goto no_entries; + } + + str_list_for_each_item (dir_list, dir_item, dir_count) + { + rcscript_info_t *script_info; + rcscript_info_t *new_script_info = NULL; + + if (!is_link (dir_item)) + { + DBG_MSG ("Skipping non symlink '%s' !\n", dir_item); + continue; + } + + script_info = get_rcscript_info (gbasename (dir_item)); + if (NULL == script_info) + { + DBG_MSG ("Skipping invalid entry '%s' !\n", dir_item); + continue; + } + + new_script_info = xmalloc (sizeof (rcscript_info_t)); + if (NULL == new_script_info) + { + str_list_free (dir_list); + goto error; + } + + DBG_MSG ("Adding '%s' to runlevel '%s'\n", + gbasename (script_info->filename), + gbasename (runlevel)); + + /* Add a copy, as the next and prev pointers will be changed */ + memcpy (new_script_info, script_info, sizeof (rcscript_info_t)); + list_add_tail (&new_script_info->node, &runlevel_info->entries); + } + + str_list_free (dir_list); + +no_entries: + list_add_tail (&runlevel_info->node, &runlevel_list); + } + + str_list_free (runlvl_list); + + return 0; + +error: + if (NULL != runlvl_list) + str_list_free (runlvl_list); + + return -1; +} + +runlevel_info_t * +get_runlevel_info (const char *runlevel) +{ + runlevel_info_t *info; + + if (!check_arg_str (runlevel)) + return NULL; + + list_for_each_entry (info, &runlevel_list, node) + { + if ((strlen (runlevel) == strlen (gbasename (info->dirname))) + && (0 == strncmp (runlevel, gbasename (info->dirname), + strlen (runlevel)))) + return info; + } + + return NULL; +} + +bool +is_runlevel (const char *runlevel) +{ + char *runlevel_dir = NULL; + int len; + + /* strlen (RUNLEVELS_DIR) + strlen (runlevel) + "/" + '\0' */ + len = strlen (RUNLEVELS_DIR) + strlen (runlevel) + 2; + runlevel_dir = xmalloc (sizeof (char) * len); + if (NULL == runlevel_dir) + return FALSE; + + snprintf (runlevel_dir, len, "%s/%s", RUNLEVELS_DIR, runlevel); + + if (is_dir (runlevel_dir, 0)) + return TRUE; + + return FALSE; +} + diff --git a/src/core/librcscripts/scripts.c b/src/core/librcscripts/scripts.c new file mode 100644 index 0000000..88024f9 --- /dev/null +++ b/src/core/librcscripts/scripts.c @@ -0,0 +1,256 @@ +/* + * scripts.c + * + * Get info etc for Gentoo style rc-scripts. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "rcscripts.h" + +LIST_HEAD (rcscript_list); + +int +get_rcscripts (void) +{ + rcscript_info_t *info; + char **file_list = NULL; + char *rcscript; + char *confd_file = NULL; + int count; + + file_list = ls_dir (RCSCRIPTS_INITDDIR, 0); + if (NULL == file_list) + { + errno = ENOENT; + DBG_MSG ("'%s' is empty!\n", RCSCRIPTS_INITDDIR); + return -1; + } + + str_list_for_each_item (file_list, rcscript, count) + { + /* Is it a file? */ + if (!(is_file (rcscript, 1)) + /* Do not process scripts, source or backup files. */ + || (CHECK_FILE_EXTENSION (rcscript, ".c")) + || (CHECK_FILE_EXTENSION (rcscript, ".bak")) + || (CHECK_FILE_EXTENSION (rcscript, "~"))) + { + DBG_MSG ("'%s' is not a valid rc-script!\n", gbasename (rcscript)); + } + else + { + regex_data_t tmp_data; + char *buf = NULL; + char *tmp_buf = NULL; + size_t lenght; + int buf_count; + int current = 0; + + if (-1 == file_map (rcscript, &buf, &lenght)) + { + DBG_MSG ("Could not open '%s' for reading!\n", + gbasename (rcscript)); + goto error; + } + + buf_count = buf_get_line (buf, lenght, current); + + tmp_buf = xstrndup (&(buf[current]), buf_count); + if (NULL == tmp_buf) + { + file_unmap (buf, lenght); + goto error; + } + + file_unmap (buf, lenght); + + /* Check if it starts with '#!/sbin/runscript' */ + DO_REGEX (tmp_data, tmp_buf, "[ \t]*#![ \t]*/sbin/runscript[ \t]*.*", + check_error); + free (tmp_buf); + if (REGEX_FULL_MATCH != tmp_data.match) + { + DBG_MSG ("'%s' is not a valid rc-script!\n", + gbasename (rcscript)); + + continue; + } + + /* We do not want rc-scripts ending in '.sh' */ + if (CHECK_FILE_EXTENSION (rcscript, ".sh")) + { + EWARN ("'%s' is invalid (should not end with '.sh')!\n", + gbasename (rcscript)); + continue; + } + + DBG_MSG ("Adding rc-script '%s' to list.\n", gbasename (rcscript)); + + info = xmalloc (sizeof (rcscript_info_t)); + if (NULL == info) + goto error; + + /* Copy the name */ + info->filename = xstrndup (rcscript, strlen (rcscript)); + if (NULL == info->filename) + goto loop_error; + + /* Get the modification time */ + info->mtime = get_mtime (rcscript, 1); + if (0 == info->mtime) + { + DBG_MSG ("Failed to get modification time for '%s'!\n", rcscript); + /* We do not care if it fails - we will pick up + * later if there is a problem with the file */ + } + + /* File name for the conf.d config file (if any) */ + confd_file = strcatpaths (RCSCRIPTS_CONFDDIR, gbasename (rcscript)); + if (NULL == confd_file) + { + DBG_MSG ("Failed to allocate temporary buffer!\n"); + goto loop_error; + } + + /* Get the modification time of the conf.d file + * (if any exists) */ + info->confd_mtime = get_mtime (confd_file, 1); + if (0 == info->confd_mtime) + { + DBG_MSG ("Failed to get modification time for '%s'!\n", + confd_file); + /* We do not care that it fails, as not all + * rc-scripts will have conf.d config files */ + } + + free (confd_file); + + list_add_tail (&info->node, &rcscript_list); + + continue; + +check_error: + free (tmp_buf); + goto error; + +loop_error: + if (NULL != info) + free (info->filename); + free (info); + + goto error; + } + } + + /* Final check if we have some entries */ + if (!check_strv (file_list)) + { + errno = ENOENT; + DBG_MSG ("No rc-scripts to parse!\n"); + goto error; + } + + str_list_free (file_list); + + return 0; + +error: + str_list_free (file_list); + + return -1; +} + +/* Returns 0 if we do not need to regen the cache file, else -1 with + * errno set if something went wrong */ +int +check_rcscripts_mtime (const char *cachefile) +{ + rcscript_info_t *info; + time_t cache_mtime; + time_t rc_conf_mtime; + time_t rc_confd_mtime; + + if (!check_arg_str (cachefile)) + return -1; + + cache_mtime = get_mtime (cachefile, 1); + if (0 == cache_mtime) + { + DBG_MSG ("Could not get modification time for cache file '%s'!\n", + cachefile); + return -1; + } + + /* Get and compare mtime for RC_CONF_FILE_NAME with that of cachefile */ + rc_conf_mtime = get_mtime (RC_CONF_FILE_NAME, 1); + if (rc_conf_mtime > cache_mtime) + { + DBG_MSG ("'%s' have a later modification time than '%s'.\n", + RC_CONF_FILE_NAME, cachefile); + return -1; + } + /* Get and compare mtime for RC_CONFD_FILE_NAME with that of cachefile */ + rc_confd_mtime = get_mtime (RC_CONFD_FILE_NAME, 1); + if (rc_confd_mtime > cache_mtime) + { + DBG_MSG ("'%s' have a later modification time than '%s'.\n", + RC_CONFD_FILE_NAME, cachefile); + return -1; + } + + /* Get and compare mtime for each rc-script and its conf.d config file + * with that of cachefile */ + list_for_each_entry (info, &rcscript_list, node) + { + if ((info->mtime > cache_mtime) || (info->confd_mtime > cache_mtime)) + { + DBG_MSG ("'%s' have a later modification time than '%s'.\n", + info->filename, cachefile); + return -1; + } + } + + return 0; +} + +rcscript_info_t * +get_rcscript_info (const char *scriptname) +{ + rcscript_info_t *info; + + if (!check_arg_str (scriptname)) + return NULL; + + list_for_each_entry (info, &rcscript_list, node) + { + if ((strlen (scriptname) == strlen (gbasename (info->filename))) + && (0 == strncmp (scriptname, gbasename (info->filename), + strlen (scriptname)))) + return info; + } + + return NULL; +} + diff --git a/src/core/librcscripts/simple-regex.c b/src/core/librcscripts/simple-regex.c index a5a9234..a1dc97d 100644 --- a/src/core/librcscripts/simple-regex.c +++ b/src/core/librcscripts/simple-regex.c @@ -68,36 +68,37 @@ #include <stdlib.h> #include <string.h> -#include "debug.h" -#include "misc.h" -#include "simple-regex.h" +#include "rcscripts.h" /* Macro to check if a regex_data_t pointer is valid */ #define CHECK_REGEX_DATA_P(_regex_data, _on_error) \ - do { \ - if ((NULL == _regex_data) \ - || (NULL == _regex_data->data) \ - /* We do not check for this, as it might still \ - * provide a match ('*' or '?' wildcard) */ \ - /* || (0 == strlen(_regex_data->data)) */ \ - || (NULL == _regex_data->regex) \ - || (0 == strlen(_regex_data->regex))) {\ - DBG_MSG("Invalid argument passed!\n"); \ - goto _on_error; \ - } \ - } while (0) - -size_t get_word(const char *regex, char **r_word); -int match_word(regex_data_t *regex_data); -size_t get_list_size(const char *regex); -size_t get_list(const char *regex, char **r_list); -int __match_list(regex_data_t *regex_data); -int match_list(regex_data_t *regex_data); -size_t get_wildcard(const char *regex, char *r_wildcard); -int __match_wildcard(regex_data_t *regex_data, -int (*match_func)(regex_data_t *regex_data), const char *regex); -int match_wildcard(regex_data_t *regex_data); -int __match(regex_data_t *regex_data); + do { \ + if ((NULL == _regex_data) \ + || (NULL == _regex_data->data) \ + /* We do not check for this, as it might still \ + * provide a match ('*' or '?' wildcard) */ \ + /* || (0 == strlen(_regex_data->data)) */ \ + || (NULL == _regex_data->regex) \ + || (0 == strlen(_regex_data->regex))) \ + { \ + errno = EINVAL; \ + DBG_MSG("Invalid argument passed!\n"); \ + goto _on_error; \ + } \ + } while (0) + +static size_t get_word (const char *regex, char **r_word); +static int match_word (regex_data_t * regex_data); +static size_t get_list_size (const char *regex); +static size_t get_list (const char *regex, char **r_list); +static int __match_list (regex_data_t * regex_data); +static int match_list (regex_data_t * regex_data); +static size_t get_wildcard (const char *regex, char *r_wildcard); +static int __match_wildcard (regex_data_t * regex_data, + int (*match_func) (regex_data_t * regex_data), + const char *regex); +static int match_wildcard (regex_data_t * regex_data); +static int __match (regex_data_t * regex_data); /* * Return values for match_* functions @@ -112,716 +113,757 @@ int __match(regex_data_t *regex_data); * */ -size_t get_word(const char *regex, char **r_word) +size_t +get_word (const char *regex, char **r_word) { - char *r_list; - char *tmp_p; - size_t count = 0; - size_t tmp_count; - - /* NULL string means we do not have a word */ - if ((NULL == regex) || (0 == strlen(regex))) { - DBG_MSG("Invalid argument passed!\n"); - return 0; - } - - *r_word = malloc(strlen(regex) + 1); - if (NULL == r_word) { - DBG_MSG("Failed to allocate buffer!\n"); - return 0; - } - tmp_p = *r_word; - - while (strlen(regex) > 0) { - switch (regex[0]) { - case '*': - case '+': - case '?': - /* If its a wildcard, backup one step */ - *(--tmp_p) = '\0'; - count--; - return count; - case '[': - tmp_count = get_list(regex, &r_list); - free(r_list); - /* In theory should not happen, but you never know - * what may happen in future ... */ - if (-1 == tmp_count) - goto error; - - /* Bail if we have a list */ - if (tmp_count > 0) { - tmp_p[0] = '\0'; - return count; - } - default: - *tmp_p++ = *regex++; - count++; - break; - } + char *r_list; + char *tmp_p; + size_t count = 0; + size_t tmp_count; + + if (!check_arg_str (regex)) + return 0; + + *r_word = xmalloc (strlen (regex) + 1); + if (NULL == r_word) + return 0; + + tmp_p = *r_word; + + while (strlen (regex) > 0) + { + switch (regex[0]) + { + case '*': + case '+': + case '?': + /* If its a wildcard, backup one step */ + *(--tmp_p) = '\0'; + count--; + return count; + case '[': + tmp_count = get_list (regex, &r_list); + free (r_list); + /* In theory should not happen, but you never know + * what may happen in future ... */ + if (-1 == tmp_count) + goto error; + + /* Bail if we have a list */ + if (tmp_count > 0) + { + tmp_p[0] = '\0'; + return count; + } + default: + *tmp_p++ = *regex++; + count++; + break; } + } - tmp_p[0] = '\0'; + tmp_p[0] = '\0'; + + return count; - return count; - error: - free(*r_word); + free (*r_word); - return -1; + return -1; } -int match_word(regex_data_t *regex_data) +int +match_word (regex_data_t * regex_data) { - char *data_p = regex_data->data; - char *r_word = NULL, *r_word_p; - size_t count = 0; - - CHECK_REGEX_DATA_P(regex_data, exit); - - count = get_word(regex_data->regex, &r_word); - if (-1 == count) - goto error; - if (0 == count) - goto exit; - r_word_p = r_word; - - while ((strlen(data_p) > 0) && (strlen(r_word_p) > 0 )) { - /* If 'r_word' is not 100% part of 'string', we do not have - * a match. If its a '.', it matches no matter what. */ - if ((data_p[0] != r_word_p[0]) && ('.' != r_word_p[0])) { - count = 0; - goto exit; - } - - data_p++; - r_word_p++; + char *data_p = regex_data->data; + char *r_word = NULL, *r_word_p; + size_t count = 0; + + CHECK_REGEX_DATA_P (regex_data, exit); + + count = get_word (regex_data->regex, &r_word); + if (-1 == count) + goto error; + if (0 == count) + goto exit; + r_word_p = r_word; + + while ((strlen (data_p) > 0) && (strlen (r_word_p) > 0)) + { + /* If 'r_word' is not 100% part of 'string', we do not have + * a match. If its a '.', it matches no matter what. */ + if ((data_p[0] != r_word_p[0]) && ('.' != r_word_p[0])) + { + count = 0; + goto exit; } - /* If 'string' is shorter than 'r_word', we do not have a match */ - if ((0 == strlen(data_p)) && (0 < strlen(r_word_p))) { - count = 0; - goto exit; - } + data_p++; + r_word_p++; + } + + /* If 'string' is shorter than 'r_word', we do not have a match */ + if ((0 == strlen (data_p)) && (0 < strlen (r_word_p))) + { + count = 0; + goto exit; + } exit: - /* Fill in our structure */ - if (0 == count) - regex_data->match = REGEX_NO_MATCH; - else if (strlen(regex_data->data) == count) - regex_data->match = REGEX_FULL_MATCH; - else - regex_data->match = REGEX_PARTIAL_MATCH; - if (regex_data->match != REGEX_NO_MATCH) - regex_data->where = regex_data->data; - else - regex_data->where = NULL; - regex_data->count = count; - regex_data->r_count = count; - - free(r_word); - return 0; + /* Fill in our structure */ + if (0 == count) + regex_data->match = REGEX_NO_MATCH; + else if (strlen (regex_data->data) == count) + regex_data->match = REGEX_FULL_MATCH; + else + regex_data->match = REGEX_PARTIAL_MATCH; + if (regex_data->match != REGEX_NO_MATCH) + regex_data->where = regex_data->data; + else + regex_data->where = NULL; + regex_data->count = count; + regex_data->r_count = count; + + free (r_word); + return 0; error: - regex_data->match = REGEX_NO_MATCH; - - free(r_word); - return -1; + regex_data->match = REGEX_NO_MATCH; + + free (r_word); + return -1; } -size_t get_list_size(const char *regex) +size_t +get_list_size (const char *regex) { - size_t count = 0; - - /* NULL string means we do not have a list */ - if ((NULL == regex) - || (0 == strlen(regex)) - || ('[' != regex[0])) { - DBG_MSG("Invalid argument passed!\n"); - return 0; + size_t count = 0; + + if (!check_arg_str (regex)) + return 0; + + if ('[' != regex[0]) + { + errno = EINVAL; + DBG_MSG ("Invalid argument passed!\n"); + return 0; + } + + regex++; + + while ((strlen (regex) > 0) && (']' != regex[0])) + { + /* We have a sequence (x-y) */ + if (('-' == regex[0]) + && (']' != regex[1]) + && (strlen (regex) >= 2) && (regex[-1] < regex[1])) + { + /* Add current + diff in sequence */ + count += regex[1] - regex[-1]; + /* Take care of '-' and next char */ + regex += 2; } - - regex++; - - while ((strlen(regex) > 0) && (']' != regex[0])) { - /* We have a sequence (x-y) */ - if (('-' == regex[0]) - && (']' != regex[1]) - && (strlen(regex) >= 2) - && (regex[-1] < regex[1])) - { - /* Add current + diff in sequence */ - count += regex[1] - regex[-1]; - /* Take care of '-' and next char */ - regex += 2; - } else { - regex++; - count++; - } + else + { + regex++; + count++; } + } - return count; + return count; } -size_t get_list(const char *regex, char **r_list) +size_t +get_list (const char *regex, char **r_list) { - char *tmp_buf = NULL; - size_t count = 0; - size_t size; - - /* NULL string means we do not have a list */ - if ((NULL == regex) || (0 == strlen(regex))) { - DBG_MSG("Invalid argument passed!\n"); - return 0; - } - - /* Bail if we do not have a list. Do not add debugging, as - * it is very noisy (used a lot when we call match_list() in - * __match() and match() to test for list matching) */ - if ('[' != regex[0]) - return 0; - - size = get_list_size(regex); - if (0 == size) { - /* Should not be an issue, but just in case */ - DBG_MSG("0 returned by get_list_size.\n"); - return 0; - } - - *r_list = malloc(size + 1); - if (NULL == *r_list) { - DBG_MSG("Failed to allocate buffer!\n"); - return -1; + char *tmp_buf = NULL; + size_t count = 0; + size_t size; + + if (!check_arg_str (regex)) + return 0; + + /* Bail if we do not have a list. Do not add debugging, as + * it is very noisy (used a lot when we call match_list() in + * __match() and match() to test for list matching) */ + if ('[' != regex[0]) + return 0; + + size = get_list_size (regex); + if (0 == size) + { + /* Should not be an issue, but just in case */ + DBG_MSG ("0 returned by get_list_size.\n"); + return 0; + } + + *r_list = xmalloc (size + 1); + if (NULL == *r_list) + return -1; + + tmp_buf = *r_list; + + /* Take care of '[' */ + regex++; + count++; + + while ((strlen (regex) > 0) && (']' != regex[0])) + { + /* We have a sequence (x-y) */ + if (('-' == regex[0]) + && (']' != regex[1]) + && (strlen (regex) >= 2) && (regex[-1] < regex[1])) + { + /* Fill in missing chars in sequence */ + while (tmp_buf[-1] < regex[1]) + { + tmp_buf[0] = (char) (tmp_buf[-1] + 1); + tmp_buf++; + /* We do not increase count */ + } + /* Take care of '-' and next char */ + count += 2; + regex += 2; } - tmp_buf = *r_list; - - /* Take care of '[' */ - regex++; - count++; - - while ((strlen(regex) > 0) && (']' != regex[0])) { - /* We have a sequence (x-y) */ - if (('-' == regex[0]) - && (']' != regex[1]) - && (strlen(regex) >= 2) - && (regex[-1] < regex[1])) { - /* Fill in missing chars in sequence */ - while (tmp_buf[-1] < regex[1]) { - tmp_buf[0] = (char)(tmp_buf[-1] + 1); - tmp_buf++; - /* We do not increase count */ - } - /* Take care of '-' and next char */ - count += 2; - regex += 2; - } else { - *tmp_buf++ = *regex++; - count++; - } + else + { + *tmp_buf++ = *regex++; + count++; } + } - tmp_buf[0] = '\0'; - /* Take care of ']' */ - count++; + tmp_buf[0] = '\0'; + /* Take care of ']' */ + count++; - /* We do not have a list as it does not end in ']' */ - if (']' != regex[0]) { - count = 0; - free(*r_list); - } + /* We do not have a list as it does not end in ']' */ + if (']' != regex[0]) + { + count = 0; + free (*r_list); + } - return count; + return count; } /* If the first is the '^' character, everything but the list is matched * NOTE: We only evaluate _ONE_ data character at a time!! */ -int __match_list(regex_data_t *regex_data) +int +__match_list (regex_data_t * regex_data) { - regex_data_t tmp_data; - char *data_p = regex_data->data; - char *list_p = regex_data->regex; - char test_regex[2] = { '\0', '\0' }; - int invert = 0; - int match; - int retval; - - CHECK_REGEX_DATA_P(regex_data, failed); - - if ('^' == list_p[0]) { - /* We need to invert the match */ - invert = 1; - /* Make sure '^' is not part of our list */ - list_p++; + regex_data_t tmp_data; + char *data_p = regex_data->data; + char *list_p = regex_data->regex; + char test_regex[2] = { '\0', '\0' }; + int invert = 0; + int lmatch; + int retval; + + CHECK_REGEX_DATA_P (regex_data, failed); + + if ('^' == list_p[0]) + { + /* We need to invert the match */ + invert = 1; + /* Make sure '^' is not part of our list */ + list_p++; + } + + if (invert) + /* All should be a match if not in the list */ + lmatch = 1; + else + /* We only have a match if in the list */ + lmatch = 0; + + while (strlen (list_p) > 0) + { + test_regex[0] = list_p[0]; + + FILL_REGEX_DATA (tmp_data, data_p, test_regex); + retval = match_word (&tmp_data); + if (-1 == retval) + goto error; + + if (REGEX_MATCH (tmp_data)) + { + if (invert) + /* If we exclude the list from + * characters we try to match, we + * have a match until one of the + * list is found. */ + lmatch = 0; + else + /* If not, we have to keep looking + * until one from the list match + * before we have a match */ + lmatch = 1; + break; } - - if (invert) - /* All should be a match if not in the list */ - match = 1; - else - /* We only have a match if in the list */ - match = 0; - - while (strlen(list_p) > 0) { - test_regex[0] = list_p[0]; - - FILL_REGEX_DATA(tmp_data, data_p, test_regex); - retval = match_word(&tmp_data); - if (-1 == retval) - goto error; - - if (REGEX_MATCH(tmp_data)) { - if (invert) - /* If we exclude the list from - * characters we try to match, we - * have a match until one of the - * list is found. */ - match = 0; - else - /* If not, we have to keep looking - * until one from the list match - * before we have a match */ - match = 1; - break; - } - list_p++; - } - - /* Fill in our structure */ - if (match) { - regex_data->match = REGEX_PARTIAL_MATCH; - regex_data->where = regex_data->data; - regex_data->count = 1; - /* This one is more cosmetic, as match_list() will - * do the right thing */ - regex_data->r_count = 0; /* strlen(regex_data->regex); */ - } else { + list_p++; + } + + /* Fill in our structure */ + if (lmatch) + { + regex_data->match = REGEX_PARTIAL_MATCH; + regex_data->where = regex_data->data; + regex_data->count = 1; + /* This one is more cosmetic, as match_list() will + * do the right thing */ + regex_data->r_count = 0; /* strlen(regex_data->regex); */ + } + else + { failed: - regex_data->match = REGEX_NO_MATCH; - regex_data->where = NULL; - regex_data->count = 0; - regex_data->r_count = 0; - } + regex_data->match = REGEX_NO_MATCH; + regex_data->where = NULL; + regex_data->count = 0; + regex_data->r_count = 0; + } - return 0; + return 0; error: - regex_data->match = REGEX_NO_MATCH; - - return -1; + regex_data->match = REGEX_NO_MATCH; + + return -1; } -int match_list(regex_data_t *regex_data) +int +match_list (regex_data_t * regex_data) { - regex_data_t tmp_data; - char *data_p = regex_data->data; - char *list_p = regex_data->regex; - char *r_list = NULL; - size_t r_count = 0; - int retval; - - CHECK_REGEX_DATA_P(regex_data, failed); - - r_count = get_list(list_p, &r_list); - if (-1 == r_count) - goto error; - if (0 == r_count) - goto failed; - - FILL_REGEX_DATA(tmp_data, data_p, &list_p[r_count-1]); - retval = __match_wildcard(&tmp_data, __match_list, r_list); - if (-1 == retval) - goto error; - if (REGEX_MATCH(tmp_data)) { - /* This should be 2 ('word' + 'wildcard'), so just remove - * the wildcard */ - tmp_data.r_count--; - goto exit; - } - - FILL_REGEX_DATA(tmp_data, data_p, r_list); - retval = __match_list(&tmp_data); - if (-1 == retval) - goto error; - if (REGEX_MATCH(tmp_data)) - goto exit; + regex_data_t tmp_data; + char *data_p = regex_data->data; + char *list_p = regex_data->regex; + char *r_list = NULL; + size_t r_count = 0; + int retval; + + CHECK_REGEX_DATA_P (regex_data, failed); + + r_count = get_list (list_p, &r_list); + if (-1 == r_count) + goto error; + if (0 == r_count) + goto failed; + + FILL_REGEX_DATA (tmp_data, data_p, &list_p[r_count - 1]); + retval = __match_wildcard (&tmp_data, __match_list, r_list); + if (-1 == retval) + goto error; + if (REGEX_MATCH (tmp_data)) + { + /* This should be 2 ('word' + 'wildcard'), so just remove + * the wildcard */ + tmp_data.r_count--; + goto exit; + } + + FILL_REGEX_DATA (tmp_data, data_p, r_list); + retval = __match_list (&tmp_data); + if (-1 == retval) + goto error; + if (REGEX_MATCH (tmp_data)) + goto exit; failed: - /* We will fill in regex_data below */ - tmp_data.match = REGEX_NO_MATCH; - tmp_data.where = NULL; - tmp_data.count = 0; - tmp_data.r_count = 0; + /* We will fill in regex_data below */ + tmp_data.match = REGEX_NO_MATCH; + tmp_data.where = NULL; + tmp_data.count = 0; + tmp_data.r_count = 0; exit: - /* Fill in our structure */ - regex_data->match = tmp_data.match; - regex_data->where = tmp_data.where; - regex_data->count = tmp_data.count; - if (regex_data->match != REGEX_NO_MATCH) - /* tmp_data.r_count for __match_wildcard will take care of the - * wildcard, and tmp_data.r_count for __match_list will be 0 */ - regex_data->r_count = r_count + tmp_data.r_count; - else - regex_data->r_count = 0; - - free(r_list); - return 0; + /* Fill in our structure */ + regex_data->match = tmp_data.match; + regex_data->where = tmp_data.where; + regex_data->count = tmp_data.count; + if (regex_data->match != REGEX_NO_MATCH) + /* tmp_data.r_count for __match_wildcard will take care of the + * wildcard, and tmp_data.r_count for __match_list will be 0 */ + regex_data->r_count = r_count + tmp_data.r_count; + else + regex_data->r_count = 0; + + free (r_list); + return 0; error: - regex_data->match = REGEX_NO_MATCH; + regex_data->match = REGEX_NO_MATCH; - free(r_list); - return -1; + free (r_list); + return -1; } -size_t get_wildcard(const char *regex, char *r_wildcard) +size_t +get_wildcard (const char *regex, char *r_wildcard) { - /* NULL regex means we do not have a wildcard */ - if ((NULL == regex) || (0 == strlen(regex))) { - DBG_MSG("Invalid argument passed!\n"); - return 0; - } - - r_wildcard[0] = regex[0]; - r_wildcard[2] = '\0'; - - switch (regex[1]) { - case '*': - case '+': - case '?': - r_wildcard[1] = regex[1]; - break; - default: - r_wildcard[0] = '\0'; - return 0; - } - - return strlen(r_wildcard); + if (!check_arg_str (regex)) + return 0; + + r_wildcard[0] = regex[0]; + r_wildcard[2] = '\0'; + + switch (regex[1]) + { + case '*': + case '+': + case '?': + r_wildcard[1] = regex[1]; + break; + default: + r_wildcard[0] = '\0'; + return 0; + } + + return strlen (r_wildcard); } -int __match_wildcard(regex_data_t *regex_data, int (*match_func)(regex_data_t *regex_data), const char *regex) +int +__match_wildcard (regex_data_t * regex_data, + int (*match_func) (regex_data_t * regex_data), + const char *regex) { - regex_data_t tmp_data; - char *data_p = regex_data->data; - char *wildcard_p = regex_data->regex; - char r_wildcard[3]; - size_t count = 0; - size_t r_count = 0; - int is_match = 0; - int retval; - - CHECK_REGEX_DATA_P(regex_data, exit); - - if (NULL == match_func) { - DBG_MSG("NULL match_func was passed!\n"); - goto exit; - } - - r_count = get_wildcard(wildcard_p, r_wildcard); - if (0 == r_count) - goto exit; - - FILL_REGEX_DATA(tmp_data, data_p, (char *)regex); - retval = match_func(&tmp_data); - if (-1 == retval) - goto error; - - switch (r_wildcard[1]) { - case '*': - case '?': - /* '*' and '?' always matches */ - is_match = 1; - case '+': - /* We need to match all of them */ - do { - /* If we have at least one match for '+', or none - * for '*' or '?', check if we have a word or list match. - * We do this because a word weights more than a wildcard */ - if ((strlen(wildcard_p) > 2) - && ((count > 0) - || ('*' == r_wildcard[1]) - || ('?' == r_wildcard[1]))) { - regex_data_t tmp_data2; + regex_data_t tmp_data; + char *data_p = regex_data->data; + char *wildcard_p = regex_data->regex; + char r_wildcard[3]; + size_t count = 0; + size_t r_count = 0; + int is_match = 0; + int retval; + + CHECK_REGEX_DATA_P (regex_data, exit); + + if (NULL == match_func) + { + errno = EINVAL; + DBG_MSG ("NULL match_func was passed!\n"); + goto exit; + } + + r_count = get_wildcard (wildcard_p, r_wildcard); + if (0 == r_count) + goto exit; + + FILL_REGEX_DATA (tmp_data, data_p, (char *) regex); + retval = match_func (&tmp_data); + if (-1 == retval) + goto error; + + switch (r_wildcard[1]) + { + case '*': + case '?': + /* '*' and '?' always matches */ + is_match = 1; + case '+': + /* We need to match all of them */ + do + { + /* If we have at least one match for '+', or none + * for '*' or '?', check if we have a word or list match. + * We do this because a word weights more than a wildcard */ + if ((strlen (wildcard_p) > 2) + && ((count > 0) + || ('*' == r_wildcard[1]) + || ('?' == r_wildcard[1]))) + { + regex_data_t tmp_data2; #if 0 - printf("data_p = %s, wildcard_p = %s\n", data_p, wildcard_p); + printf ("data_p = %s, wildcard_p = %s\n", data_p, wildcard_p); #endif - - FILL_REGEX_DATA(tmp_data2, data_p, &wildcard_p[2]); - retval = match(&tmp_data2); - if (-1 == retval) - goto error; - - if (/* '.' might be a special case ... */ - /* ('.' != wildcard_p[2]) && */ - ((REGEX_MATCH(tmp_data2)) - && (REGEX_FULL_MATCH == tmp_data2.match))) { - goto exit; - } - } - - if (REGEX_MATCH(tmp_data)) { - data_p += tmp_data.count; - count += tmp_data.count; - is_match = 1; - - FILL_REGEX_DATA(tmp_data, data_p, (char *)regex); - retval = match_func(&tmp_data); - if (-1 == retval) - goto error; - } - /* Only once for '?' */ - } while ((REGEX_MATCH(tmp_data)) && ('?' != r_wildcard[1])); - - break; - default: - /* No wildcard */ - break; + + FILL_REGEX_DATA (tmp_data2, data_p, &wildcard_p[2]); + retval = match (&tmp_data2); + if (-1 == retval) + goto error; + + if ( + /* '.' might be a special case ... */ + /* ('.' != wildcard_p[2]) && */ + ((REGEX_MATCH (tmp_data2)) + && (REGEX_FULL_MATCH == tmp_data2.match))) + { + goto exit; + } + } + + if (REGEX_MATCH (tmp_data)) + { + data_p += tmp_data.count; + count += tmp_data.count; + is_match = 1; + + FILL_REGEX_DATA (tmp_data, data_p, (char *) regex); + retval = match_func (&tmp_data); + if (-1 == retval) + goto error; + } + /* Only once for '?' */ } + while ((REGEX_MATCH (tmp_data)) && ('?' != r_wildcard[1])); + + break; + default: + /* No wildcard */ + break; + } exit: - /* Fill in our structure */ - /* We can still have a match ('*' and '?'), although count == 0 */ - if ((0 == count) && (0 == is_match)) - regex_data->match = REGEX_NO_MATCH; - else if (strlen(regex_data->data) == count) - regex_data->match = REGEX_FULL_MATCH; - else - regex_data->match = REGEX_PARTIAL_MATCH; - if (regex_data->match != REGEX_NO_MATCH) - regex_data->where = regex_data->data; - else - regex_data->where = NULL; - regex_data->count = count; - regex_data->r_count = r_count; - - return 0; + /* Fill in our structure */ + /* We can still have a match ('*' and '?'), although count == 0 */ + if ((0 == count) && (0 == is_match)) + regex_data->match = REGEX_NO_MATCH; + else if (strlen (regex_data->data) == count) + regex_data->match = REGEX_FULL_MATCH; + else + regex_data->match = REGEX_PARTIAL_MATCH; + if (regex_data->match != REGEX_NO_MATCH) + regex_data->where = regex_data->data; + else + regex_data->where = NULL; + regex_data->count = count; + regex_data->r_count = r_count; + + return 0; error: - regex_data->match = REGEX_NO_MATCH; + regex_data->match = REGEX_NO_MATCH; - return -1; + return -1; } -int match_wildcard(regex_data_t *regex_data) +int +match_wildcard (regex_data_t * regex_data) { - regex_data_t tmp_data; - char *data_p = regex_data->data; - char *wildcard_p = regex_data->regex; - char r_wildcard[3]; - size_t r_count; - int retval; - - CHECK_REGEX_DATA_P(regex_data, failed); - - /* Invalid wildcard - we need a character + a regex operator */ - if (strlen(wildcard_p) < 2) - goto failed; - - r_count = get_wildcard(wildcard_p, r_wildcard); - if (0 == r_count) - goto failed; - - /* Needed so that match_word() will not bail if it sees the wildcard */ - r_wildcard[1] = '\0'; - - FILL_REGEX_DATA(tmp_data, data_p, wildcard_p); - retval = __match_wildcard(&tmp_data, match_word, r_wildcard); - if (-1 == retval) - goto error; - if (REGEX_MATCH(tmp_data)) - goto exit; + regex_data_t tmp_data; + char *data_p = regex_data->data; + char *wildcard_p = regex_data->regex; + char r_wildcard[3]; + size_t r_count; + int retval; + + CHECK_REGEX_DATA_P (regex_data, failed); + + /* Invalid wildcard - we need a character + a regex operator */ + if (strlen (wildcard_p) < 2) + goto failed; + + r_count = get_wildcard (wildcard_p, r_wildcard); + if (0 == r_count) + goto failed; + + /* Needed so that match_word() will not bail if it sees the wildcard */ + r_wildcard[1] = '\0'; + + FILL_REGEX_DATA (tmp_data, data_p, wildcard_p); + retval = __match_wildcard (&tmp_data, match_word, r_wildcard); + if (-1 == retval) + goto error; + if (REGEX_MATCH (tmp_data)) + goto exit; failed: - /* We will fill in regex_data below */ - tmp_data.match = REGEX_NO_MATCH; - tmp_data.where = NULL; - tmp_data.count = 0; - tmp_data.r_count = 0; + /* We will fill in regex_data below */ + tmp_data.match = REGEX_NO_MATCH; + tmp_data.where = NULL; + tmp_data.count = 0; + tmp_data.r_count = 0; exit: - /* Fill in our structure */ - regex_data->match = tmp_data.match; - regex_data->where = tmp_data.where; - regex_data->count = tmp_data.count; - regex_data->r_count = tmp_data.r_count; + /* Fill in our structure */ + regex_data->match = tmp_data.match; + regex_data->where = tmp_data.where; + regex_data->count = tmp_data.count; + regex_data->r_count = tmp_data.r_count; - return 0; + return 0; error: - regex_data->match = REGEX_NO_MATCH; + regex_data->match = REGEX_NO_MATCH; - return -1; + return -1; } -int __match(regex_data_t *regex_data) +int +__match (regex_data_t * regex_data) { - regex_data_t tmp_data; - char *data_p = regex_data->data; - char *regex_p = regex_data->regex; - size_t count = 0; - size_t r_count = 0; - int match = 0; - int retval; - - CHECK_REGEX_DATA_P(regex_data, failed); - - while (strlen(regex_p) > 0) { + regex_data_t tmp_data; + char *data_p = regex_data->data; + char *regex_p = regex_data->regex; + size_t count = 0; + size_t r_count = 0; + int rmatch = 0; + int retval; + + CHECK_REGEX_DATA_P (regex_data, failed); + + while (strlen (regex_p) > 0) + { #if 0 - printf("data_p = '%s', regex_p = '%s'\n", data_p, regex_p); + printf ("data_p = '%s', regex_p = '%s'\n", data_p, regex_p); #endif - - FILL_REGEX_DATA(tmp_data, data_p, regex_p); - retval = match_list(&tmp_data); - if (-1 == retval) - goto error; - if (REGEX_MATCH(tmp_data)) - goto match; - - FILL_REGEX_DATA(tmp_data, data_p, regex_p); - retval = match_wildcard(&tmp_data); - if (-1 == retval) - goto error; - if (REGEX_MATCH(tmp_data)) - goto match; - - FILL_REGEX_DATA(tmp_data, data_p, regex_p); - retval = match_word(&tmp_data); - if (-1 == retval) - goto error; - if (REGEX_MATCH(tmp_data)) - goto match; - - break; - -match: - data_p += tmp_data.count; - count += tmp_data.count; - regex_p += tmp_data.r_count; - r_count += tmp_data.r_count; - match = 1; - - /* Check that we do not go out of bounds */ - if (((data_p - regex_data->data) > strlen(regex_data->data)) - || ((regex_p - regex_data->regex) > strlen(regex_data->regex))) - goto failed; - } - - /* We could not match the whole regex (data too short?) */ - if (0 != strlen(regex_p)) - goto failed; - goto exit; + FILL_REGEX_DATA (tmp_data, data_p, regex_p); + retval = match_list (&tmp_data); + if (-1 == retval) + goto error; + if (REGEX_MATCH (tmp_data)) + goto have_match; + + FILL_REGEX_DATA (tmp_data, data_p, regex_p); + retval = match_wildcard (&tmp_data); + if (-1 == retval) + goto error; + if (REGEX_MATCH (tmp_data)) + goto have_match; + + FILL_REGEX_DATA (tmp_data, data_p, regex_p); + retval = match_word (&tmp_data); + if (-1 == retval) + goto error; + if (REGEX_MATCH (tmp_data)) + goto have_match; + + break; + +have_match: + data_p += tmp_data.count; + count += tmp_data.count; + regex_p += tmp_data.r_count; + r_count += tmp_data.r_count; + rmatch = 1; + + /* Check that we do not go out of bounds */ + if (((data_p - regex_data->data) > strlen (regex_data->data)) + || ((regex_p - regex_data->regex) > strlen (regex_data->regex))) + goto failed; + } + + /* We could not match the whole regex (data too short?) */ + if (0 != strlen (regex_p)) + goto failed; + + goto exit; failed: - /* We will fill in regex_data below */ - count = 0; - r_count = 0; - match = 0; + /* We will fill in regex_data below */ + count = 0; + r_count = 0; + rmatch = 0; exit: - /* Fill in our structure */ - /* We can still have a match ('*' and '?'), although count == 0 */ - if ((0 == count) && (0 == match)) - regex_data->match = REGEX_NO_MATCH; - else if (strlen(regex_data->data) == count) - regex_data->match = REGEX_FULL_MATCH; - else - regex_data->match = REGEX_PARTIAL_MATCH; - if (regex_data->match != REGEX_NO_MATCH) - regex_data->where = regex_data->data; - else - regex_data->where = NULL; - regex_data->count = count; - regex_data->r_count = r_count; - - return 0; + /* Fill in our structure */ + /* We can still have a match ('*' and '?'), although count == 0 */ + if ((0 == count) && (0 == rmatch)) + regex_data->match = REGEX_NO_MATCH; + else if (strlen (regex_data->data) == count) + regex_data->match = REGEX_FULL_MATCH; + else + regex_data->match = REGEX_PARTIAL_MATCH; + if (regex_data->match != REGEX_NO_MATCH) + regex_data->where = regex_data->data; + else + regex_data->where = NULL; + regex_data->count = count; + regex_data->r_count = r_count; + + return 0; error: - regex_data->match = REGEX_NO_MATCH; + regex_data->match = REGEX_NO_MATCH; - return -1; + return -1; } -int match(regex_data_t *regex_data) +int +match (regex_data_t * regex_data) { - regex_data_t tmp_data; - char *data_p = regex_data->data; - char *regex_p; - char *tmp_buf = NULL; - int from_start = 0; - int to_end = 0; - int retval; - - CHECK_REGEX_DATA_P(regex_data, failed); - - /* We might be modifying regex_p, so make a copy */ - tmp_buf = strndup(regex_data->regex, strlen(regex_data->regex)); - if (NULL == tmp_buf) { - DBG_MSG("Failed to allocate temporary buffer!\n"); - goto error; - } - regex_p = tmp_buf; - - /* Should we only match from the start? */ - if ('^' == regex_p[0]) { - regex_p++; - from_start = 1; - } - - /* Should we match up to the end? */ - if ('$' == regex_p[strlen(regex_p) - 1]) { - regex_p[strlen(regex_p) - 1] = '\0'; - to_end = 1; + regex_data_t tmp_data; + char *data_p = regex_data->data; + char *regex_p; + char *tmp_buf = NULL; + int from_start = 0; + int to_end = 0; + int retval; + + CHECK_REGEX_DATA_P (regex_data, failed); + + /* We might be modifying regex_p, so make a copy */ + tmp_buf = xstrndup (regex_data->regex, strlen (regex_data->regex)); + if (NULL == tmp_buf) + goto error; + + regex_p = tmp_buf; + + /* Should we only match from the start? */ + if ('^' == regex_p[0]) + { + regex_p++; + from_start = 1; + } + + /* Should we match up to the end? */ + if ('$' == regex_p[strlen (regex_p) - 1]) + { + regex_p[strlen (regex_p) - 1] = '\0'; + to_end = 1; + } + + do + { + FILL_REGEX_DATA (tmp_data, data_p, regex_p); + retval = __match (&tmp_data); + if (-1 == retval) + goto error; + } + while ((strlen (data_p++) > 0) + && (!REGEX_MATCH (tmp_data)) && (0 == from_start)); + + /* Compensate for above extra inc */ + data_p--; + + /* Fill in our structure */ + if (REGEX_MATCH (tmp_data)) + { + /* Check if we had an '$' at the end of the regex, and + * verify that we still have a match */ + if ((1 == to_end) && (tmp_data.count != strlen (data_p))) + { + goto failed; } - do { - FILL_REGEX_DATA(tmp_data, data_p, regex_p); - retval = __match(&tmp_data); - if (-1 == retval) - goto error; - } while ((strlen(data_p++) > 0) - && (!REGEX_MATCH(tmp_data)) - && (0 == from_start)); - - /* Compensate for above extra inc */ - data_p--; - - /* Fill in our structure */ - if (REGEX_MATCH(tmp_data)) { - /* Check if we had an '$' at the end of the regex, and - * verify that we still have a match */ - if ((1 == to_end) && (tmp_data.count != strlen(data_p))) { - goto failed; - } - - if ((data_p == regex_data->data) - && (tmp_data.match == REGEX_FULL_MATCH)) - regex_data->match = REGEX_FULL_MATCH; - else - regex_data->match = REGEX_PARTIAL_MATCH; - regex_data->where = data_p; - regex_data->count = tmp_data.count; - regex_data->r_count = tmp_data.r_count; - if (1 == from_start) - regex_data->r_count++; - if (1 == to_end) - regex_data->r_count++; - } else { + if ((data_p == regex_data->data) + && (tmp_data.match == REGEX_FULL_MATCH)) + regex_data->match = REGEX_FULL_MATCH; + else + regex_data->match = REGEX_PARTIAL_MATCH; + regex_data->where = data_p; + regex_data->count = tmp_data.count; + regex_data->r_count = tmp_data.r_count; + if (1 == from_start) + regex_data->r_count++; + if (1 == to_end) + regex_data->r_count++; + } + else + { failed: - regex_data->match = REGEX_NO_MATCH; - regex_data->where = NULL; - regex_data->count = 0; - regex_data->r_count = 0; - } + regex_data->match = REGEX_NO_MATCH; + regex_data->where = NULL; + regex_data->count = 0; + regex_data->r_count = 0; + } - free(tmp_buf); + free (tmp_buf); - return 0; + return 0; error: - regex_data->match = REGEX_NO_MATCH; - free(tmp_buf); + regex_data->match = REGEX_NO_MATCH; + free (tmp_buf); - return -1; + return -1; } - diff --git a/src/core/librcscripts/simple-regex.h b/src/core/librcscripts/simple-regex.h index ad91a58..e69de29 100644 --- a/src/core/librcscripts/simple-regex.h +++ b/src/core/librcscripts/simple-regex.h @@ -1,86 +0,0 @@ -/* - * simple_regex.h - * - * Simle regex library. - * - * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> - * - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Header$ - */ - -#ifndef _SIMPLE_REGEX_H -#define _SIMPLE_REGEX_H - -#define REGEX_NO_MATCH 0 /* We have no match */ -#define REGEX_PARTIAL_MATCH 1 /* Some of the string matches the regex */ -#define REGEX_FULL_MATCH 2 /* The whole string matches the regex */ - -/* Macro to fill in .data and .regex */ -#define FILL_REGEX_DATA(_regex_data, _string, _regex) \ - do { \ - _regex_data.data = _string; \ - _regex_data.regex = _regex; \ - } while (0) - -/* Fill in _regex_data with _data and _regex, on failure goto _error */ -#define DO_REGEX(_regex_data, _data, _regex, _error) \ - do { \ - FILL_REGEX_DATA(_regex_data, _data, _regex); \ - if (-1 == match(&_regex_data)) { \ - DBG_MSG("Could not do regex match!\n"); \ - goto _error; \ - } \ - } while (0) - -/* Evaluate to true if we have some kind of match */ -#define REGEX_MATCH(_regex_data) \ - ((REGEX_FULL_MATCH == _regex_data.match) \ - || (REGEX_PARTIAL_MATCH == _regex_data.match)) - -/* Same as above, but for use when _regex_data is a pointer */ -#define REGEX_MATCH_P(_regex_data) \ - ((REGEX_FULL_MATCH == _regex_data->match) \ - || (REGEX_PARTIAL_MATCH == _regex_data->match)) - -typedef struct { - char *data; /* String to perform regex operation on */ - char *regex; /* String containing regex to use */ - int match; /* Will be set if there was a match. Check - * REGEX_*_MATCH above for possible values */ - char *where; /* Pointer to where match starts in data */ - size_t count; /* Count characters from data matched by regex */ - size_t r_count; /* Count characters of regex used for match. This - * should normally be the lenght of regex, but might - * not be for some internal functions ... */ -} regex_data_t; - -/* - * Return: - * - * 0 - There was no error. If there was a match, regex_data->match - * - will be > 0 (this is the definitive check - if not true, the - * - other values of the struct may be bogus), regex_data->count - * - will be the amount of data that was matched (might be 0 for - * - some wildcards), and regex_data->r_count will be > 0. - * - * -1 - An error occured. Check errno for more info. - * - */ -int match(regex_data_t *regex_data); - -#endif /* _SIMPLE_REGEX_H */ - diff --git a/src/core/src/depscan.c b/src/core/src/depscan.c index 8cc9da8..d5a18a3 100644 --- a/src/core/src/depscan.c +++ b/src/core/src/depscan.c @@ -35,264 +35,287 @@ #include <unistd.h> #include "librcscripts/rcscripts.h" -#include "librcscripts/debug.h" -#include "librcscripts/depend.h" -#include "librcscripts/misc.h" -#include "librcscripts/parse.h" - -char* svcdir_subdirs[] = { - "softscripts", - "snapshot", - "options", - "started", - "starting", - "inactive", - "stopping", - NULL + +char *svcdir_subdirs[] = { + "softscripts", + "snapshot", + "options", + "started", + "starting", + "inactive", + "stopping", + NULL }; char *svcdir_volatile_subdirs[] = { - "snapshot", - "broken", - NULL + "snapshot", + "broken", + NULL }; -int create_directory(const char *name); -int create_var_dirs(const char *svcdir); -int delete_var_dirs(const char *svcdir); - -int create_directory(const char *name) { - if ((NULL == name) || (0 == strlen(name))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return -1; +int create_directory (const char *name); +int create_var_dirs (const char *svcdir); +int delete_var_dirs (const char *svcdir); + +int +create_directory (const char *name) +{ + if (!check_arg_str (name)) + return -1; + + /* Check if directory exist, and is not a symlink */ + if (!is_dir (name, 0)) + { + if (exists (name)) + { + /* Remove it if not a directory */ + if (-1 == unlink (name)) + { + DBG_MSG ("Failed to remove '%s'!\n", name); + return -1; + } } - - /* Check if directory exist, and is not a symlink */ - if (!is_dir(name, 0)) { - if (exists(name)) { - /* Remove it if not a directory */ - if (-1 == unlink(name)) { - DBG_MSG("Failed to remove '%s'!\n", name); - return -1; - } - } - /* Now try to create the directory */ - if (-1 == mktree(name, 0755)) { - DBG_MSG("Failed to create '%s'!\n", name); - return -1; - } + /* Now try to create the directory */ + if (-1 == mktree (name, 0755)) + { + DBG_MSG ("Failed to create '%s'!\n", name); + return -1; } + } - return 0; + return 0; } -int create_var_dirs(const char *svcdir) { - char *tmp_path = NULL; - int i = 0; - - if ((NULL == svcdir) || (0 == strlen(svcdir))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return -1; +int +create_var_dirs (const char *svcdir) +{ + char *tmp_path = NULL; + int i = 0; + + if (!check_arg_str (svcdir)) + return -1; + + /* Check and create svcdir if needed */ + if (-1 == create_directory (svcdir)) + { + DBG_MSG ("Failed to create '%s'!\n", svcdir); + return -1; + } + + while (NULL != svcdir_subdirs[i]) + { + tmp_path = strcatpaths (svcdir, svcdir_subdirs[i]); + if (NULL == tmp_path) + { + DBG_MSG ("Failed to allocate buffer!\n"); + return -1; } - /* Check and create svcdir if needed */ - if (-1 == create_directory(svcdir)) { - DBG_MSG("Failed to create '%s'!\n", svcdir); - return -1; + /* Check and create all the subdirs if needed */ + if (-1 == create_directory (tmp_path)) + { + DBG_MSG ("Failed to create '%s'!\n", tmp_path); + free (tmp_path); + return -1; } - while (NULL != svcdir_subdirs[i]) { - tmp_path = strcatpaths(svcdir, svcdir_subdirs[i]); - if (NULL == tmp_path) { - DBG_MSG("Failed to allocate buffer!\n"); - return -1; - } - - /* Check and create all the subdirs if needed */ - if (-1 == create_directory(tmp_path)) { - DBG_MSG("Failed to create '%s'!\n", tmp_path); - free(tmp_path); - return -1; - } - - free(tmp_path); - i++; - } + free (tmp_path); + i++; + } - return 0; + return 0; } -int delete_var_dirs(const char *svcdir) { - char *tmp_path = NULL; - int i = 0; - - if ((NULL == svcdir) || (0 == strlen(svcdir))) { - DBG_MSG("Invalid argument passed!\n"); - errno = EINVAL; - return -1; +int +delete_var_dirs (const char *svcdir) +{ + char *tmp_path = NULL; + int i = 0; + + if (!check_arg_str (svcdir)) + return -1; + + /* Just quit if svcdir do not exist */ + if (!exists (svcdir)) + { + DBG_MSG ("'%s' does not exist!\n", svcdir); + return 0; + } + + while (NULL != svcdir_volatile_subdirs[i]) + { + tmp_path = strcatpaths (svcdir, svcdir_volatile_subdirs[i]); + if (NULL == tmp_path) + { + DBG_MSG ("Failed to allocate buffer!\n"); + return -1; } - /* Just quit if svcdir do not exist */ - if (!exists(svcdir)) { - DBG_MSG("'%s' does not exist!\n", svcdir); - return 0; + /* Skip the directory if it does not exist */ + if (!exists (tmp_path)) + goto _continue; + + /* Check and delete all files and sub directories if needed */ + if (-1 == rmtree (tmp_path)) + { + DBG_MSG ("Failed to delete '%s'!\n", tmp_path); + free (tmp_path); + return -1; } - while (NULL != svcdir_volatile_subdirs[i]) { - tmp_path = strcatpaths(svcdir, svcdir_volatile_subdirs[i]); - if (NULL == tmp_path) { - DBG_MSG("Failed to allocate buffer!\n"); - return -1; - } - - /* Skip the directory if it does not exist */ - if (!exists(tmp_path)) - goto _continue; - - /* Check and delete all files and sub directories if needed */ - if (-1 == rmtree(tmp_path)) { - DBG_MSG("Failed to delete '%s'!\n", tmp_path); - free(tmp_path); - return -1; - } - _continue: - free(tmp_path); - i++; - } + free (tmp_path); + i++; + } - return 0; + return 0; } #if defined(LEGACY_DEPSCAN) -int main() { - FILE *cachefile_fd = NULL; - char *data = NULL; - char *svcdir = NULL; - char *cachefile = NULL; - char *tmp_cachefile = NULL; - int tmp_cachefile_fd = 0; - int datasize = 0; - - /* Make sure we do not run into locale issues */ +int +main (void) +{ + dyn_buf_t *data; + FILE *cachefile_fd = NULL; + char *svcdir = NULL; + char *cachefile = NULL; + char *tmp_cachefile = NULL; + int tmp_cachefile_fd = 0; + int datasize = 0; + + /* Make sure we do not run into locale issues */ #ifndef __KLIBC__ - setlocale (LC_ALL, "C"); + setlocale (LC_ALL, "C"); #endif - if (0 != getuid()) { - EERROR("Must be root!\n"); - exit(EXIT_FAILURE); + if (0 != getuid ()) + { + EERROR ("Must be root!\n"); + exit (EXIT_FAILURE); + } + + svcdir = get_cnf_entry (RC_CONFD_FILE_NAME, SVCDIR_CONFIG_ENTRY); + if (NULL == svcdir) + { + EERROR ("Failed to get config entry '%s'!\n", SVCDIR_CONFIG_ENTRY); + exit (EXIT_FAILURE); + } + + /* Delete (if needed) volatile directories in svcdir */ + if (-1 == delete_var_dirs (svcdir)) + { + /* XXX: Not 100% accurate below message ... */ + EERROR ("Failed to delete '%s', %s", svcdir, + "or one of its sub directories!\n"); + exit (EXIT_FAILURE); + } + + /* Create all needed directories in svcdir */ + if (-1 == create_var_dirs (svcdir)) + { + EERROR ("Failed to create '%s', %s", svcdir, + "or one of its sub directories!\n"); + exit (EXIT_FAILURE); + } + + cachefile = strcatpaths (svcdir, LEGACY_CACHE_FILE_NAME); + if (NULL == cachefile) + { + DBG_MSG ("Failed to allocate buffer!\n"); + exit (EXIT_FAILURE); + } + + tmp_cachefile = strcatpaths (cachefile, "XXXXXX"); + if (NULL == tmp_cachefile) + { + DBG_MSG ("Failed to allocate buffer!\n"); + exit (EXIT_FAILURE); + } + /* Replace the "/XXXXXX" with ".XXXXXX" + * Yes, I am lazy. */ + tmp_cachefile[strlen (tmp_cachefile) - strlen (".XXXXXX")] = '.'; + + if (-1 == get_rcscripts ()) + { + EERROR ("Failed to get rc-scripts list!\n"); + exit (EXIT_FAILURE); + } + + if (-1 == check_rcscripts_mtime (cachefile)) + { + EINFO ("Caching service dependencies ...\n"); + DBG_MSG ("Regenerating cache file '%s'.\n", cachefile); + + data = new_dyn_buf (); + + datasize = generate_stage2 (data); + if (-1 == datasize) + { + EERROR ("Failed to generate stage2!\n"); + exit (EXIT_FAILURE); } - svcdir = get_cnf_entry(RC_CONFD_FILE_NAME, SVCDIR_CONFIG_ENTRY); - if (NULL == svcdir) { - EERROR("Failed to get config entry '%s'!\n", - SVCDIR_CONFIG_ENTRY); - exit(EXIT_FAILURE); - } +#if 0 + tmp_cachefile_fd = open ("foo", O_CREAT | O_TRUNC | O_RDWR, 0600); + write (tmp_cachefile_fd, data->data, datasize); + close (tmp_cachefile_fd); +#endif - /* Delete (if needed) volatile directories in svcdir */ - if (-1 == delete_var_dirs(svcdir)) { - /* XXX: Not 100% accurate below message ... */ - EERROR("Failed to delete '%s', %s", svcdir, - "or one of its sub directories!\n"); - exit(EXIT_FAILURE); + if (-1 == parse_cache (data)) + { + EERROR ("Failed to parse stage2 output!\n"); + free_dyn_buf (data); + exit (EXIT_FAILURE); } - /* Create all needed directories in svcdir */ - if (-1 == create_var_dirs(svcdir)) { - EERROR("Failed to create '%s', %s", svcdir, - "or one of its sub directories!\n"); - exit(EXIT_FAILURE); - } + free_dyn_buf (data); - cachefile = strcatpaths(svcdir, LEGACY_CACHE_FILE_NAME); - if (NULL == cachefile) { - DBG_MSG("Failed to allocate buffer!\n"); - exit(EXIT_FAILURE); - } - - tmp_cachefile = strcatpaths(cachefile, "XXXXXX"); - if (NULL == tmp_cachefile) { - DBG_MSG("Failed to allocate buffer!\n"); - exit(EXIT_FAILURE); + if (-1 == service_resolve_dependencies ()) + { + EERROR ("Failed to resolve dependencies!\n"); + exit (EXIT_FAILURE); } - /* Replace the "/XXXXXX" with ".XXXXXX" - * Yes, I am lazy. */ - tmp_cachefile[strlen(tmp_cachefile) - strlen(".XXXXXX")] = '.'; - if (-1 == get_rcscripts()) { - EERROR("Failed to get rc-scripts list!\n"); - exit(EXIT_FAILURE); - } - - if (-1 == check_rcscripts_mtime(cachefile)) { - EINFO("Caching service dependencies ...\n"); - DBG_MSG("Regenerating cache file '%s'.\n", cachefile); - - datasize = generate_stage2(&data); - if (-1 == datasize) { - EERROR("Failed to generate stage2!\n"); - exit(EXIT_FAILURE); - } - - if (-1 == parse_cache(data, datasize)) { - EERROR("Failed to parse stage2 output!\n"); - free(data); - exit(EXIT_FAILURE); - } - -#if 0 - tmp_cachefile_fd = open("foo", O_CREAT | O_TRUNC | O_RDWR, 0600); - write(tmp_cachefile_fd, data, datasize); - close(tmp_cachefile_fd); +#ifndef __KLIBC__ + tmp_cachefile_fd = mkstemp (tmp_cachefile); +#else + /* FIXME: Need to add a mkstemp implementation for klibc */ + tmp_cachefile_fd = + open (tmp_cachefile, O_CREAT | O_TRUNC | O_RDWR, 0600); #endif + if (-1 == tmp_cachefile_fd) + { + EERROR ("Could not open temporary file for writing!\n"); + exit (EXIT_FAILURE); + } + + cachefile_fd = fdopen (tmp_cachefile_fd, "w"); + if (NULL == cachefile_fd) + { + EERROR ("Could not open temporary file for writing!\n"); + exit (EXIT_FAILURE); + } - free(data); + write_legacy_stage3 (cachefile_fd); + fclose (cachefile_fd); - if (-1 == service_resolve_dependencies()) { - EERROR("Failed to resolve dependencies!\n"); - exit(EXIT_FAILURE); - } + if ((-1 == unlink (cachefile)) && (exists (cachefile))) + { + EERROR ("Could not remove '%s'!\n", cachefile); + unlink (tmp_cachefile); + exit (EXIT_FAILURE); + } -#ifndef __KLIBC__ - tmp_cachefile_fd = mkstemp(tmp_cachefile); -#else - /* FIXME: Need to add a mkstemp implementation for klibc */ - tmp_cachefile_fd = open(tmp_cachefile, O_CREAT | O_TRUNC | O_RDWR, 0600); -#endif - if (-1 == tmp_cachefile_fd) { - EERROR("Could not open temporary file for writing!\n"); - exit(EXIT_FAILURE); - } - cachefile_fd = fdopen(tmp_cachefile_fd, "w"); - if (NULL == cachefile_fd) { - EERROR("Could not open temporary file for writing!\n"); - exit(EXIT_FAILURE); - } - - write_legacy_stage3(cachefile_fd); - fclose(cachefile_fd); - - if ((-1 == unlink(cachefile)) && (exists(cachefile))) { - EERROR("Could not remove '%s'!\n", cachefile); - unlink(tmp_cachefile); - exit(EXIT_FAILURE); - } - - if (-1 == rename(tmp_cachefile, cachefile)) { - EERROR("Could not move temporary file to '%s'!\n", - cachefile); - unlink(tmp_cachefile); - exit(EXIT_FAILURE); - } + if (-1 == rename (tmp_cachefile, cachefile)) + { + EERROR ("Could not move temporary file to '%s'!\n", cachefile); + unlink (tmp_cachefile); + exit (EXIT_FAILURE); } + } - exit(EXIT_SUCCESS); + exit (EXIT_SUCCESS); } #endif - diff --git a/src/core/src/runscript.c b/src/core/src/runscript.c index dc3ba51..bccd61e 100644 --- a/src/core/src/runscript.c +++ b/src/core/src/runscript.c @@ -17,221 +17,248 @@ #include <dlfcn.h> #include "librcscripts/rcscripts.h" -#include "librcscripts/debug.h" -#include "librcscripts/misc.h" -#define IS_SBIN_RC() ((caller) && (0 == strcmp(caller, SBIN_RC))) +#define IS_SBIN_RC() ((caller) && (0 == strcmp (caller, SBIN_RC))) static void (*selinux_run_init_old) (void); static void (*selinux_run_init_new) (int argc, char **argv); +void setup_selinux (int argc, char **argv); +char ** get_whitelist (char **whitelist, char *filename); +char ** filter_environ (char *caller); + extern char **environ; -void setup_selinux(int argc, char **argv) { - void *lib_handle = NULL; - - lib_handle = dlopen(SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL); - if (NULL != lib_handle) { - selinux_run_init_old = dlsym(lib_handle, "selinux_runscript"); - selinux_run_init_new = dlsym(lib_handle, "selinux_runscript2"); - - /* Use new run_init if it exists, else fall back to old */ - if (NULL != selinux_run_init_new) - selinux_run_init_new(argc, argv); - else if (NULL != selinux_run_init_old) - selinux_run_init_old(); - else { - /* This shouldnt happen... probably corrupt lib */ - fprintf(stderr, "Run_init is missing from runscript_selinux.so!\n"); - exit(127); - } +void +setup_selinux (int argc, char **argv) +{ + void *lib_handle = NULL; + + lib_handle = dlopen (SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL); + if (NULL != lib_handle) + { + selinux_run_init_old = dlsym (lib_handle, "selinux_runscript"); + selinux_run_init_new = dlsym (lib_handle, "selinux_runscript2"); + + /* Use new run_init if it exists, else fall back to old */ + if (NULL != selinux_run_init_new) + selinux_run_init_new (argc, argv); + else if (NULL != selinux_run_init_old) + selinux_run_init_old (); + else + { + /* This shouldnt happen... probably corrupt lib */ + fprintf (stderr, "Run_init is missing from runscript_selinux.so!\n"); + exit (127); } + } } -char **get_whitelist(char **whitelist, char *filename) { - char *buf = NULL; - char *tmp_buf = NULL; - char *tmp_p = NULL; - char *token = NULL; - size_t lenght = 0; - int count = 0; - int current = 0; - - if (-1 == file_map(filename, &buf, &lenght)) - return NULL; - - while (current < lenght) { - count = buf_get_line(buf, lenght, current); - - tmp_buf = strndup(&buf[current], count); - if (NULL == tmp_buf) { - DBG_MSG("Failed to allocate temporary buffer!\n"); - goto error; - } - tmp_p = tmp_buf; - - /* Strip leading spaces/tabs */ - while ((tmp_p[0] == ' ') || (tmp_p[0] == '\t')) - tmp_p++; - - /* Get entry - we do not want comments, and only the first word - * on a line is valid */ - token = strsep(&tmp_p, "# \t"); - if (NULL != token && '\0' != token[0]) { - tmp_p = strndup(token, strlen(token)); - STRING_LIST_ADD(whitelist, tmp_p, error); - } - - current += count + 1; - free(tmp_buf); - /* Set to NULL in case we error out above and have - * to free below */ - tmp_buf = NULL; +char ** +get_whitelist (char **whitelist, char *filename) +{ + char *buf = NULL; + char *tmp_buf = NULL; + char *tmp_p = NULL; + char *token = NULL; + size_t lenght = 0; + int count = 0; + int current = 0; + + if (-1 == file_map (filename, &buf, &lenght)) + return NULL; + + while (current < lenght) + { + count = buf_get_line (buf, lenght, current); + + tmp_buf = xstrndup (&buf[current], count); + if (NULL == tmp_buf) + goto error; + + tmp_p = tmp_buf; + + /* Strip leading spaces/tabs */ + while ((tmp_p[0] == ' ') || (tmp_p[0] == '\t')) + tmp_p++; + + /* Get entry - we do not want comments, and only the first word + * on a line is valid */ + token = strsep (&tmp_p, "# \t"); + if (check_str (token)) + { + tmp_p = xstrndup (token, strlen (token)); + if (NULL == tmp_p) + goto error; + + str_list_add_item (whitelist, tmp_p, error); } - - file_unmap(buf, lenght); + current += count + 1; + free (tmp_buf); + /* Set to NULL in case we error out above and have + * to free below */ + tmp_buf = NULL; + } - return whitelist; + + file_unmap (buf, lenght); + + return whitelist; error: - if (NULL != tmp_buf) - free(tmp_buf); - file_unmap(buf, lenght); - STRING_LIST_FREE(whitelist); + if (NULL != tmp_buf) + free (tmp_buf); + file_unmap (buf, lenght); + str_list_free (whitelist); - return NULL; + return NULL; } -char **filter_environ(char *caller) { - char **myenv = NULL; - char **whitelist = NULL; - char *env_name = NULL; - int check_profile = 1; - int count = 0; - - if (NULL != getenv(SOFTLEVEL) && !IS_SBIN_RC()) - /* Called from /sbin/rc, but not /sbin/rc itself, so current - * environment should be fine */ - return environ; - - if (1 == is_file(SYS_WHITELIST, 1)) - whitelist = get_whitelist(whitelist, SYS_WHITELIST); - else - EWARN("System environment whitelist missing!\n"); - - if (1 == is_file(USR_WHITELIST, 1)) - whitelist = get_whitelist(whitelist, USR_WHITELIST); - - if (NULL == whitelist) - /* If no whitelist is present, revert to old behaviour */ - return environ; - - if (1 != is_file(PROFILE_ENV, 1)) - /* XXX: Maybe warn here? */ - check_profile = 0; - - STRING_LIST_FOR_EACH(whitelist, env_name, count) { - char *env_var = NULL; - char *tmp_p = NULL; - int env_len = 0; - - env_var = getenv(env_name); - if (NULL != env_var) - goto add_entry; - - if (1 == check_profile) { - char *tmp_env_name = NULL; - int tmp_len = 0; - - /* The entries in PROFILE_ENV is of the form: - * export VAR_NAME=value */ - tmp_len = strlen(env_name) + strlen("export ") + 1; - tmp_env_name = calloc(tmp_len, sizeof(char *)); - if (NULL == tmp_env_name) { - DBG_MSG("Failed to allocate temporary buffer!\n"); - goto error; - } - snprintf(tmp_env_name, tmp_len, "export %s", env_name); - - /* Clear errno so that subsequent calls do not trigger - * DBG_MSG */ - errno = 0; - env_var = get_cnf_entry(PROFILE_ENV, tmp_env_name); - free(tmp_env_name); - if (NULL == env_var && ENOMSG != errno) - goto error; - else if (NULL != env_var) - goto add_entry; - } - - continue; - -add_entry: - env_len = strlen(env_name) + strlen(env_var) + 2; - tmp_p = calloc(env_len, sizeof(char *)); - if (NULL == tmp_p) { - DBG_MSG("Failed to allocate temporary buffer!\n"); - goto error; - } - snprintf(tmp_p, env_len, "%s=%s", env_name, env_var); - STRING_LIST_ADD(myenv, tmp_p, error); +char ** +filter_environ (char *caller) +{ + char **myenv = NULL; + char **whitelist = NULL; + char *env_name = NULL; + int check_profile = 1; + int count = 0; + + if (NULL != getenv (SOFTLEVEL) && !IS_SBIN_RC ()) + /* Called from /sbin/rc, but not /sbin/rc itself, so current + * environment should be fine */ + return environ; + + if (1 == is_file (SYS_WHITELIST, 1)) + whitelist = get_whitelist (whitelist, SYS_WHITELIST); + else + EWARN ("System environment whitelist missing!\n"); + + if (1 == is_file (USR_WHITELIST, 1)) + whitelist = get_whitelist (whitelist, USR_WHITELIST); + + if (NULL == whitelist) + /* If no whitelist is present, revert to old behaviour */ + return environ; + + if (1 != is_file (PROFILE_ENV, 1)) + /* XXX: Maybe warn here? */ + check_profile = 0; + + str_list_for_each_item (whitelist, env_name, count) + { + char *env_var = NULL; + char *tmp_p = NULL; + int env_len = 0; + + env_var = getenv (env_name); + if (NULL != env_var) + goto add_entry; + + if (1 == check_profile) + { + char *tmp_env_name = NULL; + int tmp_len = 0; + + /* The entries in PROFILE_ENV is of the form: + * export VAR_NAME=value */ + tmp_len = strlen (env_name) + strlen ("export ") + 1; + tmp_env_name = xcalloc (tmp_len, sizeof (char *)); + if (NULL == tmp_env_name) + goto error; + + snprintf (tmp_env_name, tmp_len, "export %s", env_name); + + env_var = get_cnf_entry (PROFILE_ENV, tmp_env_name); + free (tmp_env_name); + if ((NULL == env_var) && (0 != errno) && (ENOMSG != errno)) + goto error; + else if (NULL != env_var) + goto add_entry; } - STRING_LIST_FREE(whitelist); + continue; + +add_entry: + env_len = strlen (env_name) + strlen (env_var) + 2; + tmp_p = xcalloc (env_len, sizeof (char *)); + if (NULL == tmp_p) + goto error; + + snprintf (tmp_p, env_len, "%s=%s", env_name, env_var); + str_list_add_item (myenv, tmp_p, error); + } + + str_list_free (whitelist); - if (NULL == myenv) - /* If all else fails, just add a default PATH */ - STRING_LIST_ADD(myenv, strdup(DEFAULT_PATH), error); - - return myenv; + if (NULL == myenv) + { + char *tmp_str; + + tmp_str = xstrndup (DEFAULT_PATH, strlen (DEFAULT_PATH)); + if (NULL == tmp_str) + goto error; + + /* If all else fails, just add a default PATH */ + str_list_add_item (myenv, strdup (DEFAULT_PATH), error); + } + + return myenv; error: - STRING_LIST_FREE(myenv); - STRING_LIST_FREE(whitelist); - - return NULL; + str_list_free (myenv); + str_list_free (whitelist); + + return NULL; } -int main(int argc, char *argv[]) { - char *myargs[32]; - char **myenv = NULL; - char *caller = argv[1]; - int new = 1; - - /* Need to be /bin/bash, else BASH is invalid */ - myargs[0] = "/bin/bash"; - while (argv[new] != 0) { - myargs[new] = argv[new]; - new++; - } - myargs[new] = NULL; +int +main (int argc, char *argv[]) +{ + char *myargs[32]; + char **myenv = NULL; + char *caller = argv[1]; + int new = 1; - /* Do not do help for /sbin/rc */ - if (argc < 3 && !IS_SBIN_RC()) { - execv(RCSCRIPT_HELP, myargs); - exit(1); - } + /* Need to be /bin/bash, else BASH is invalid */ + myargs[0] = "/bin/bash"; + while (argv[new] != 0) + { + myargs[new] = argv[new]; + new++; + } + myargs[new] = NULL; - /* Setup a filtered environment according to the whitelist */ - myenv = filter_environ(caller); - if (NULL == myenv) { - EWARN("%s: Failed to filter the environment!\n", caller); - /* XXX: Might think to bail here, but it could mean the system - * is rendered unbootable, so rather not */ - myenv = environ; - } + /* Do not do help for /sbin/rc */ + if (argc < 3 && !IS_SBIN_RC ()) + { + execv (RCSCRIPT_HELP, myargs); + exit (1); + } - /* Ok, we are ready to go, so setup selinux if applicable */ - setup_selinux(argc, argv); + /* Setup a filtered environment according to the whitelist */ + myenv = filter_environ (caller); + if (NULL == myenv) + { + EWARN ("%s: Failed to filter the environment!\n", caller); + /* XXX: Might think to bail here, but it could mean the system + * is rendered unbootable, so rather not */ + myenv = environ; + } - if (!IS_SBIN_RC()) { - if (execve("/sbin/runscript.sh", myargs, myenv) < 0) - exit(1); - } else { - if (execve("/bin/bash", myargs, myenv) < 0) - exit(1); - } + /* Ok, we are ready to go, so setup selinux if applicable */ + setup_selinux (argc, argv); + + if (!IS_SBIN_RC ()) + { + if (execve ("/sbin/runscript.sh", myargs, myenv) < 0) + exit (1); + } + else + { + if (execve ("/bin/bash", myargs, myenv) < 0) + exit (1); + } - return 0; + return 0; } diff --git a/src/core/tests/Makefile.am b/src/core/tests/Makefile.am index e0bfc4d..2fb4ee7 100644 --- a/src/core/tests/Makefile.am +++ b/src/core/tests/Makefile.am @@ -1 +1,24 @@ -EXTRA_DIST = test-regex.c +INCLUDES = -I$(top_srcdir) + +LIBRCSCRIPTS = $(top_builddir)/librcscripts/librcscripts.la + +TESTS = \ + test-dynbuf \ + test-mmap \ + test-regex + +noinst_PROGRAMS = \ + test-runlevels \ + $(TESTS) + +test_dynbuf_LDADD = $(LIBRCSCRIPTS) +test_dynbuf_SOURCES = test-dynbuf.c + +test_mmap_LDADD = $(LIBRCSCRIPTS) +test_mmap_SOURCES = test-mmap.c + +test_regex_LDADD = $(LIBRCSCRIPTS) +test_regex_SOURCES = test-regex.c + +test_runlevels_LDADD = $(LIBRCSCRIPTS) +test_runlevels_SOURCES = test-runlevels.c diff --git a/src/core/tests/test-dynbuf.c b/src/core/tests/test-dynbuf.c new file mode 100644 index 0000000..27ff894 --- /dev/null +++ b/src/core/tests/test-dynbuf.c @@ -0,0 +1,139 @@ +/* + * test-dynbuf.c + * + * Test for the dynamic buffer module. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "librcscripts/rcscripts.h" + +#define TEST_STRING1 "Hello" +#define TEST_STRING2 " " +#define TEST_STRING3 "world" +#define TEST_STRING4 "!\n" +#define TEST_STRING_FULL TEST_STRING1 TEST_STRING2 TEST_STRING3 TEST_STRING4 + +int +main (void) +{ + dyn_buf_t *dynbuf; + char buf[1024 * 4]; + int length, total = 0; + + dynbuf = new_dyn_buf (); + if (NULL == dynbuf) + { + fprintf (stderr, "Failed to allocate dynamic buffer.\n"); + return 1; + } + + length = sprintf_dyn_buf (dynbuf, TEST_STRING1); + if (length != strlen (TEST_STRING1)) + { + fprintf (stderr, "sprintf_dyn_buf() returned wrong length (pass 1)!\n"); + goto error; + } + total += length; + + length = write_dyn_buf (dynbuf, TEST_STRING2, strlen (TEST_STRING2)); + if (length != strlen (TEST_STRING2)) + { + fprintf (stderr, "write_dyn_buf() returned wrong length (pass 1)!\n"); + goto error; + } + total += length; + + length = sprintf_dyn_buf (dynbuf, TEST_STRING3); + if (length != strlen (TEST_STRING3)) + { + fprintf (stderr, "sprintf_dyn_buf() returned wrong length (pass 2)!\n"); + goto error; + } + total += length; + + length = write_dyn_buf (dynbuf, TEST_STRING4, strlen (TEST_STRING4)); + if (length != strlen (TEST_STRING4)) + { + fprintf (stderr, "write_dyn_buf() returned wrong length (pass 2)!\n"); + goto error; + } + total += length; + + length = read_dyn_buf (dynbuf, buf, total / 2); + if (length != total / 2) + { + fprintf (stderr, "read_dyn_buf() returned wrong length (pass 1)!\n"); + goto error; + } + + length = read_dyn_buf (dynbuf, (buf + (total / 2)), total); + if (length != (total - (total / 2))) + { + fprintf (stderr, "read_dyn_buf() returned wrong length (pass 2)!\n"); + goto error; + } + + if (0 != strncmp (buf, TEST_STRING_FULL, strlen (TEST_STRING_FULL))) + { + fprintf (stderr, "Written and read strings differ!\n"); + goto error; + } + + while (strlen (dynbuf->data) < DYNAMIC_BUFFER_SIZE) + { + length = sprintf_dyn_buf (dynbuf, TEST_STRING_FULL); + if (length != strlen (TEST_STRING_FULL)) + { + fprintf (stderr, "sprintf_dyn_buf() returned wrong length (%i)!\n", + (int)dynbuf->length); + goto error; + } + total += length; + + length = write_dyn_buf (dynbuf, TEST_STRING_FULL, + strlen (TEST_STRING_FULL)); + if (length != strlen (TEST_STRING_FULL)) + { + fprintf (stderr, "write_dyn_buf() returned wrong length (%i)!\n", + (int)dynbuf->length); + goto error; + } + total += length; + } + + if (total != strlen (dynbuf->data)) + { + fprintf (stderr, "Written string length should be %i, but is %i!\n", + total, (int)strlen (dynbuf->data)); + goto error; + } + + free_dyn_buf (dynbuf); + + return 0; + +error: + free_dyn_buf (dynbuf); + return 1; +} diff --git a/src/core/tests/test-mmap.c b/src/core/tests/test-mmap.c new file mode 100644 index 0000000..198968f --- /dev/null +++ b/src/core/tests/test-mmap.c @@ -0,0 +1,46 @@ +/* + * test-mmap.c + * + * Test for file_map(). + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#include <stdlib.h> + +#include "librcscripts/rcscripts.h" + +int +main (void) +{ + char *buf; + size_t bufsize; + + if (-1 == file_map ("/etc/fstab", &buf, &bufsize)) + { + DBG_MSG ("Failed to mmap file"); + exit (EXIT_FAILURE); + } + + file_unmap (buf, bufsize); + + return 0; +} + + diff --git a/src/core/tests/test-regex.c b/src/core/tests/test-regex.c index 610a490..b827d3b 100644 --- a/src/core/tests/test-regex.c +++ b/src/core/tests/test-regex.c @@ -22,59 +22,72 @@ * $Header$ */ -#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include "debug.h" -#include "simple-regex.h" +#include "librcscripts/rcscripts.h" char *test_data[] = { - /* string, pattern, match (1 = yes, 0 = no) */ - "ab", "a?[ab]b", "1", - "abb", "a?[ab]b", "1", - "aab", "a?[ab]b", "1", - "a", "a?a?a?a", "1", - "aa", "a?a?a?a", "1", - "aa", "a?a?a?aa", "1", - "aaa", "a?a?a?aa", "1", - "ab", "[ab]*", "1", - "abc", "[ab]*.", "1", - "ab", "[ab]*b+", "1", - "ab", "a?[ab]*b+", "1", - "aaaaaaaaaaaaaaaaaaaaaaa", "a*b", "0", - "aaaaaaaaabaaabbaaaaaa", "a*b+a*b*ba+", "1", - "ababababab", "a.*", "1", - "baaaaaaaab", "a*", "0", - NULL + /* string, pattern, match (1 = yes, 0 = no) */ + "ab", "a?[ab]b", "1", + "abb", "a?[ab]b", "1", + "aab", "a?[ab]b", "1", + "a", "a?a?a?a", "1", + "aa", "a?a?a?a", "1", + "aa", "a?a?a?aa", "1", + "aaa", "a?a?a?aa", "1", + "ab", "[ab]*", "1", + "abc", "[ab]*.", "1", + "ab", "[ab]*b+", "1", + "ab", "a?[ab]*b+", "1", + "aaaaaaaaaaaaaaaaaaaaaaa", "a*b", "0", + "aaaaaaaaabaaabbaaaaaa", "a*b+a*b*ba+", "1", + "ababababab", "a.*", "1", + "baaaaaaaab", "a*", "0", + NULL }; -int main() { - regex_data_t tmp_data; - char buf[256], string[100], regex[100]; - int i; +int +main (void) +{ + regex_data_t tmp_data; + char buf[256], string[100], regex[100]; + int i; - for (i = 0; NULL != test_data[i]; i += 3) { - snprintf(string, 99, "'%s'", test_data[i]); - snprintf(regex, 99, "'%s'", test_data[i + 1]); - snprintf(buf, 255, "string = %s, pattern = %s", string, regex); - printf("%-60s", buf); - DO_REGEX(tmp_data, test_data[i], test_data[i + 1], error); - if (REGEX_MATCH(tmp_data) && (REGEX_FULL_MATCH == tmp_data.match)) { - if (0 != strncmp(test_data[i + 2], "1", 1)) - goto error; - } else { - if (0 != strncmp(test_data[i + 2], "0", 1)) - goto error; - } - - printf("%s\n", "[ \033[32;01mOK\033[0m ]"); + for (i = 0; NULL != test_data[i]; i += 3) + { + snprintf (string, 99, "'%s'", test_data[i]); + snprintf (regex, 99, "'%s'", test_data[i + 1]); + snprintf (buf, 255, "string = %s, pattern = %s", string, regex); +#if TEST_VERBOSE + printf ("%-60s", buf); +#endif + + DO_REGEX (tmp_data, test_data[i], test_data[i + 1], error); + + if (REGEX_MATCH (tmp_data) && (REGEX_FULL_MATCH == tmp_data.match)) + { + if (0 != strncmp (test_data[i + 2], "1", 1)) + goto error; + } + else + { + if (0 != strncmp (test_data[i + 2], "0", 1)) + goto error; } - return 0; +#if TEST_VERBOSE + printf ("%s\n", "[ \033[32;01mOK\033[0m ]"); +#endif + } + + return 0; + error: - printf("%s\n", "[ \033[31;01m!!\033[0m ]"); +#if TEST_VERBOSE + printf ("%s\n", "[ \033[31;01m!!\033[0m ]"); +#endif - return 1; + return 1; } diff --git a/src/core/tests/test-runlevels.c b/src/core/tests/test-runlevels.c new file mode 100644 index 0000000..dde6850 --- /dev/null +++ b/src/core/tests/test-runlevels.c @@ -0,0 +1,70 @@ +/* + * test-runlevels.c + * + * Test for runlevels functionality. + * + * Copyright (C) 2004,2005 Martin Schlemmer <azarah@nosferatu.za.org> + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#include <stdlib.h> + +#include "librcscripts/rcscripts.h" + +int +main (void) +{ + runlevel_info_t *runlevel_info; + rcscript_info_t *script_info; + + if (-1 == get_rcscripts ()) + { + EERROR ("Failed to get rc-scripts list!\n"); + exit (EXIT_FAILURE); + } + + if (-1 == get_runlevels ()) + { + EERROR ("Failed to get runlevel list!\n"); + exit (EXIT_FAILURE); + } + +#if 0 + EINFO ("Scripts:\n"); + + list_for_each_entry (script_info, &rcscript_list, node) + { + printf (" - %s\n", gbasename (script_info->filename)); + } + + printf ("\n"); +#endif + + list_for_each_entry (runlevel_info, &runlevel_list, node) + { + EINFO ("Runlevel %s:\n", gbasename (runlevel_info->dirname)); + + list_for_each_entry (script_info, &runlevel_info->entries, node) + { + printf (" - %s\n", gbasename (script_info->filename)); + } + } + + return 0; +} + |