summaryrefslogtreecommitdiff
path: root/src/shim
diff options
context:
space:
mode:
Diffstat (limited to 'src/shim')
-rw-r--r--src/shim/Makefile20
-rw-r--r--src/shim/mkjson/LICENSE21
-rw-r--r--src/shim/mkjson/makefile30
-rw-r--r--src/shim/mkjson/mkjson.c307
-rw-r--r--src/shim/mkjson/mkjson.h50
-rw-r--r--src/shim/vyshim.c287
6 files changed, 715 insertions, 0 deletions
diff --git a/src/shim/Makefile b/src/shim/Makefile
new file mode 100644
index 000000000..c8487e3c2
--- /dev/null
+++ b/src/shim/Makefile
@@ -0,0 +1,20 @@
+DEBUG = 0
+
+CC := gcc
+CFLAGS := -I./mkjson -L./mkjson/lib -DDEBUG=${DEBUG}
+LIBS := -lmkjson -lzmq
+
+.PHONY: vyshim
+vyshim: vyshim.c libmkjson
+ $(CC) $(CFLAGS) -o $@ $< $(LIBS)
+
+.PHONY: libmkjson
+libmkjson:
+ $(MAKE) -C mkjson
+
+all: vyshim
+
+.PHONY: clean
+clean:
+ $(MAKE) -C mkjson clean
+ rm -f vyshim
diff --git a/src/shim/mkjson/LICENSE b/src/shim/mkjson/LICENSE
new file mode 100644
index 000000000..8c4284c91
--- /dev/null
+++ b/src/shim/mkjson/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Jacek Wieczorek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/shim/mkjson/makefile b/src/shim/mkjson/makefile
new file mode 100644
index 000000000..ba75399d2
--- /dev/null
+++ b/src/shim/mkjson/makefile
@@ -0,0 +1,30 @@
+CFLAGS = -Wall -Os -I.
+CC = gcc
+AR = ar
+
+#USE_ASPRINTF make flag can be used in order to encourage asprintf use inside the library
+ifeq ($(USE_ASPRINTF),1)
+CFLAGS += -D_GNU_SOURCE
+endif
+
+#Builds object and a static library file
+all: clean force
+ $(CC) $(CFLAGS) -c mkjson.c -o obj/mkjson.o
+ $(AR) -cvq lib/libmkjson.a obj/mkjson.o
+ $(AR) -t lib/libmkjson.a
+
+#Normal cleanup
+clean:
+ -rm -rf obj
+ -rm -rf lib
+
+#Environment init
+force:
+ -mkdir obj
+ -mkdir lib
+
+#Build the example snippet
+example: all
+ gcc -o example examples/example.c -I. -Llib -lmkjson
+
+
diff --git a/src/shim/mkjson/mkjson.c b/src/shim/mkjson/mkjson.c
new file mode 100644
index 000000000..1172664fb
--- /dev/null
+++ b/src/shim/mkjson/mkjson.c
@@ -0,0 +1,307 @@
+/* mkjson.c - a part of mkjson library
+ *
+ * Copyright (C) 2018 Jacek Wieczorek
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+#include <mkjson.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+// Works like asprintf, but it's always there
+// I don't want the name to collide with anything
+static int allsprintf( char **strp, const char *fmt, ... )
+{
+ int len;
+ va_list ap;
+ va_start( ap, fmt );
+
+ #ifdef _GNU_SOURCE
+ // Just hand everything to vasprintf, if it's available
+ len = vasprintf( strp, fmt, ap );
+ #else
+ // Or do it the manual way
+ char *buf;
+ len = vsnprintf( NULL, 0, fmt, ap );
+ if ( len >= 0 )
+ {
+ buf = malloc( ++len );
+ if ( buf != NULL )
+ {
+ // Hopefully, that's the right way to do it
+ va_end( ap );
+ va_start( ap, fmt );
+
+ // Write and return the data
+ len = vsnprintf( buf, len, fmt, ap );
+ if ( len >= 0 )
+ {
+ *strp = buf;
+ }
+ else
+ {
+ free( buf );
+ }
+ }
+ }
+ #endif
+
+ va_end( ap );
+ return len;
+}
+
+// Return JSON string built from va_arg arguments
+// If no longer needed, should be passed to free() by user
+char *mkjson( enum mkjson_container_type otype, int count, ... )
+{
+ int i, len, goodchunks = 0, failure = 0;
+ char *json, *prefix, **chunks, ign;
+
+ // Value - type and data
+ enum mkjson_value_type vtype;
+ const char *key;
+ long long int intval;
+ long double dblval;
+ const char *strval;
+
+ // Since v0.9 count cannot be a negative value and datatype is indicated by a separate argument
+ // Since I'm not sure whether it's right to put assertions in libraries, the next line is commented out
+ // assert( count >= 0 && "After v0.9 negative count is prohibited; please use otype argument instead" );
+ if ( count < 0 || ( otype != MKJSON_OBJ && otype != MKJSON_ARR ) ) return NULL;
+
+ // Allocate chunk pointer array - on standard platforms each one should be NULL
+ chunks = calloc( count, sizeof( char* ) );
+ if ( chunks == NULL ) return NULL;
+
+ // This should rather be at the point of no return
+ va_list ap;
+ va_start( ap, count );
+
+ // Create chunks
+ for ( i = 0; i < count && !failure; i++ )
+ {
+ // Get value type
+ vtype = va_arg( ap, enum mkjson_value_type );
+
+ // Get key
+ if ( otype == MKJSON_OBJ )
+ {
+ key = va_arg( ap, char* );
+ if ( key == NULL )
+ {
+ failure = 1;
+ break;
+ }
+ }
+ else key = "";
+
+ // Generate prefix
+ if ( allsprintf( &prefix, "%s%s%s",
+ otype == MKJSON_OBJ ? "\"" : "", // Quote before key
+ key, // Key
+ otype == MKJSON_OBJ ? "\": " : "" ) == -1 ) // Quote and colon after key
+ {
+ failure = 1;
+ break;
+ }
+
+ // Depending on value type
+ ign = 0;
+ switch ( vtype )
+ {
+ // Ignore string / JSON data
+ case MKJSON_IGN_STRING:
+ case MKJSON_IGN_JSON:
+ (void) va_arg( ap, const char* );
+ ign = 1;
+ break;
+
+ // Ignore string / JSON data and pass the pointer to free
+ case MKJSON_IGN_STRING_FREE:
+ case MKJSON_IGN_JSON_FREE:
+ free( va_arg( ap, char* ) );
+ ign = 1;
+ break;
+
+ // Ignore int / long long int
+ case MKJSON_IGN_INT:
+ case MKJSON_IGN_LLINT:
+ if ( vtype == MKJSON_IGN_INT )
+ (void) va_arg( ap, int );
+ else
+ (void) va_arg( ap, long long int );
+ ign = 1;
+ break;
+
+ // Ignore double / long double
+ case MKJSON_IGN_DOUBLE:
+ case MKJSON_IGN_LDOUBLE:
+ if ( vtype == MKJSON_IGN_DOUBLE )
+ (void) va_arg( ap, double );
+ else
+ (void) va_arg( ap, long double );
+ ign = 1;
+ break;
+
+ // Ignore boolean
+ case MKJSON_IGN_BOOL:
+ (void) va_arg( ap, int );
+ ign = 1;
+ break;
+
+ // Ignore null value
+ case MKJSON_IGN_NULL:
+ ign = 1;
+ break;
+
+ // A null-terminated string
+ case MKJSON_STRING:
+ case MKJSON_STRING_FREE:
+ strval = va_arg( ap, const char* );
+
+ // If the pointer points to NULL, the string will be replaced with JSON null value
+ if ( strval == NULL )
+ {
+ if ( allsprintf( chunks + i, "%snull", prefix ) == -1 )
+ chunks[i] = NULL;
+ }
+ else
+ {
+ if ( allsprintf( chunks + i, "%s\"%s\"", prefix, strval ) == -1 )
+ chunks[i] = NULL;
+ }
+
+ // Optional free
+ if ( vtype == MKJSON_STRING_FREE )
+ free( (char*) strval );
+ break;
+
+ // Embed JSON data
+ case MKJSON_JSON:
+ case MKJSON_JSON_FREE:
+ strval = va_arg( ap, const char* );
+
+ // If the pointer points to NULL, the JSON data is replaced with null value
+ if ( allsprintf( chunks + i, "%s%s", prefix, strval == NULL ? "null" : strval ) == -1 )
+ chunks[i] = NULL;
+
+ // Optional free
+ if ( vtype == MKJSON_JSON_FREE )
+ free( (char*) strval );
+ break;
+
+ // int / long long int
+ case MKJSON_INT:
+ case MKJSON_LLINT:
+ if ( vtype == MKJSON_INT )
+ intval = va_arg( ap, int );
+ else
+ intval = va_arg( ap, long long int );
+
+ if ( allsprintf( chunks + i, "%s%Ld", prefix, intval ) == -1 ) chunks[i] = NULL;
+ break;
+
+ // double / long double
+ case MKJSON_DOUBLE:
+ case MKJSON_LDOUBLE:
+ if ( vtype == MKJSON_DOUBLE )
+ dblval = va_arg( ap, double );
+ else
+ dblval = va_arg( ap, long double );
+
+ if ( allsprintf( chunks + i, "%s%Lf", prefix, dblval ) == -1 ) chunks[i] = NULL;
+ break;
+
+ // double / long double
+ case MKJSON_SCI_DOUBLE:
+ case MKJSON_SCI_LDOUBLE:
+ if ( vtype == MKJSON_SCI_DOUBLE )
+ dblval = va_arg( ap, double );
+ else
+ dblval = va_arg( ap, long double );
+
+ if ( allsprintf( chunks + i, "%s%Le", prefix, dblval ) == -1 ) chunks[i] = NULL;
+ break;
+
+ // Boolean
+ case MKJSON_BOOL:
+ intval = va_arg( ap, int );
+ if ( allsprintf( chunks + i, "%s%s", prefix, intval ? "true" : "false" ) == -1 ) chunks[i] = NULL;
+ break;
+
+ // JSON null
+ case MKJSON_NULL:
+ if ( allsprintf( chunks + i, "%snull", prefix ) == -1 ) chunks[i] = NULL;
+ break;
+
+ // Bad type specifier
+ default:
+ chunks[i] = NULL;
+ break;
+ }
+
+ // Free prefix memory
+ free( prefix );
+
+ // NULL chunk without ignore flag indicates failure
+ if ( !ign && chunks[i] == NULL ) failure = 1;
+
+ // NULL chunk now indicates ignore flag
+ if ( ign ) chunks[i] = NULL;
+ else goodchunks++;
+ }
+
+ // We won't use ap anymore
+ va_end( ap );
+
+ // If everything is fine, merge chunks and create full JSON table
+ if ( !failure )
+ {
+ // Get total length (this is without NUL byte)
+ len = 0;
+ for ( i = 0; i < count; i++ )
+ if ( chunks[i] != NULL )
+ len += strlen( chunks[i] );
+
+ // Total length = Chunks length + 2 brackets + separators
+ if ( goodchunks == 0 ) goodchunks = 1;
+ len = len + 2 + ( goodchunks - 1 ) * 2;
+
+ // Allocate memory for the whole thing
+ json = calloc( len + 1, sizeof( char ) );
+ if ( json != NULL )
+ {
+ // Merge chunks (and do not overwrite the first bracket)
+ for ( i = 0; i < count; i++ )
+ {
+ // Add separators:
+ // - not on the begining
+ // - always after valid chunk
+ // - between two valid chunks
+ // - between valid and ignored chunk if the latter isn't the last one
+ if ( i != 0 && chunks[i - 1] != NULL && ( chunks[i] != NULL || ( chunks[i] == NULL && i != count - 1 ) ) )
+ strcat( json + 1, ", ");
+
+ if ( chunks[i] != NULL )
+ strcat( json + 1, chunks[i] );
+ }
+
+ // Add proper brackets
+ json[0] = otype == MKJSON_OBJ ? '{' : '[';
+ json[len - 1] = otype == MKJSON_OBJ ? '}' : ']';
+ }
+ }
+ else json = NULL;
+
+ // Free chunks
+ for ( i = 0; i < count; i++ )
+ free( chunks[i] );
+ free( chunks );
+
+ return json;
+}
+
diff --git a/src/shim/mkjson/mkjson.h b/src/shim/mkjson/mkjson.h
new file mode 100644
index 000000000..38cc07b26
--- /dev/null
+++ b/src/shim/mkjson/mkjson.h
@@ -0,0 +1,50 @@
+/* mkjson.h - a part of mkjson library
+ *
+ * Copyright (C) 2018 Jacek Wieczorek
+ *
+ * This software may be modified and distributed under the terms
+ * of the MIT license. See the LICENSE file for details.
+ */
+
+#ifndef MKJSON_H
+#define MKJSON_H
+
+// JSON container types
+enum mkjson_container_type
+{
+ MKJSON_ARR = 0, // An array
+ MKJSON_OBJ = 1 // An object (hash or whatever you call it)
+};
+
+// JSON data types
+enum mkjson_value_type
+{
+ MKJSON_STRING = (int)('s'), // const char* - String data
+ MKJSON_STRING_FREE = (int)('f'), // char* - String data, but pointer is freed
+ MKJSON_JSON = (int)('r'), // const char* - JSON data (like string, but no quotes)
+ MKJSON_JSON_FREE = (int)('j'), // char* - JSON data, but pointer is freed
+ MKJSON_INT = (int)('i'), // int - An integer
+ MKJSON_LLINT = (int)('I'), // long long int - A long integer
+ MKJSON_DOUBLE = (int)('d'), // double - A double
+ MKJSON_LDOUBLE = (int)('D'), // long double - A long double
+ MKJSON_SCI_DOUBLE = (int)('e'), // double - A double with scientific notation
+ MKJSON_SCI_LDOUBLE = (int)('E'), // long double - A long double with scientific notation
+ MKJSON_BOOL = (int)('b'), // int - A boolean value
+ MKJSON_NULL = (int)('n'), // -- - JSON null value
+
+ // These cause one argument of certain type to be ignored
+ MKJSON_IGN_STRING = (-MKJSON_STRING),
+ MKJSON_IGN_STRING_FREE = (-MKJSON_STRING_FREE),
+ MKJSON_IGN_JSON = (-MKJSON_JSON),
+ MKJSON_IGN_JSON_FREE = (-MKJSON_JSON_FREE),
+ MKJSON_IGN_INT = (-MKJSON_INT),
+ MKJSON_IGN_LLINT = (-MKJSON_LLINT),
+ MKJSON_IGN_DOUBLE = (-MKJSON_DOUBLE),
+ MKJSON_IGN_LDOUBLE = (-MKJSON_LDOUBLE),
+ MKJSON_IGN_BOOL = (-MKJSON_BOOL),
+ MKJSON_IGN_NULL = (-MKJSON_NULL)
+};
+
+extern char *mkjson( enum mkjson_container_type otype, int count, ... );
+
+#endif
diff --git a/src/shim/vyshim.c b/src/shim/vyshim.c
new file mode 100644
index 000000000..8b6feab99
--- /dev/null
+++ b/src/shim/vyshim.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2020 VyOS maintainers and contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or later as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <zmq.h>
+#include "mkjson.h"
+
+/*
+ *
+ *
+ */
+
+#if DEBUG
+#define DEBUG_ON 1
+#else
+#define DEBUG_ON 0
+#endif
+#define debug_print(fmt, ...) \
+ do { if (DEBUG_ON) fprintf(stderr, fmt, ##__VA_ARGS__); } while (0)
+#define debug_call(f) \
+ do { if (DEBUG_ON) f; } while (0)
+
+#define SOCKET_PATH "ipc:///run/vyos-configd.sock"
+
+#define GET_ACTIVE "cli-shell-api --show-active-only --show-show-defaults --show-ignore-edit showConfig"
+#define GET_SESSION "cli-shell-api --show-working-only --show-show-defaults --show-ignore-edit showConfig"
+
+#define COMMIT_MARKER "/var/tmp/initial_in_commit"
+
+enum {
+ SUCCESS = 1 << 0,
+ ERROR_COMMIT = 1 << 1,
+ ERROR_DAEMON = 1 << 2,
+ PASS = 1 << 3
+};
+
+volatile int init_alarm = 0;
+volatile int timeout = 0;
+
+int initialization(void *);
+int pass_through(char **, int);
+void timer_handler(int);
+
+double get_posix_clock_time(void);
+
+int main(int argc, char* argv[])
+{
+ // string for node data: conf_mode script and tagnode, if applicable
+ char string_node_data[256];
+ string_node_data[0] = '\0';
+
+ void *context = zmq_ctx_new();
+ void *requester = zmq_socket(context, ZMQ_REQ);
+
+ int init_timeout = 0;
+
+ debug_print("Connecting to vyos-configd ...\n");
+ zmq_connect(requester, SOCKET_PATH);
+
+ if (access(COMMIT_MARKER, F_OK) != -1) {
+ init_timeout = initialization(requester);
+ if (!init_timeout) remove(COMMIT_MARKER);
+ }
+
+ int end = argc > 3 ? 2 : argc - 1;
+
+ // if initial communication failed, pass through execution of script
+ if (init_timeout) {
+ int ret = pass_through(argv, end);
+ return ret;
+ }
+
+ for (int i = end; i > 0 ; i--) {
+ strncat(&string_node_data[0], argv[i], 127);
+ }
+
+ char error_code[1];
+ debug_print("Sending node data ...\n");
+ char *string_node_data_msg = mkjson(MKJSON_OBJ, 2,
+ MKJSON_STRING, "type", "node",
+ MKJSON_STRING, "data", &string_node_data[0]);
+
+ zmq_send(requester, string_node_data_msg, strlen(string_node_data_msg), 0);
+ zmq_recv(requester, error_code, 1, 0);
+ debug_print("Received node data receipt\n");
+
+ int err = (int)error_code[0];
+
+ free(string_node_data_msg);
+
+ zmq_close(requester);
+ zmq_ctx_destroy(context);
+
+ if (err & PASS) {
+ debug_print("Received PASS\n");
+ int ret = pass_through(argv, end);
+ return ret;
+ }
+
+ if (err & ERROR_DAEMON) {
+ debug_print("Received ERROR_DAEMON\n");
+ int ret = pass_through(argv, end);
+ return ret;
+ }
+
+ if (err & ERROR_COMMIT) {
+ debug_print("Received ERROR_COMMIT\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int initialization(void* Requester)
+{
+ char *active_str = NULL;
+ size_t active_len = 0;
+
+ char *session_str = NULL;
+ size_t session_len = 0;
+
+ char *empty_string = "\n";
+
+ char buffer[16];
+
+ struct sigaction sa;
+ struct itimerval timer, none_timer;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = &timer_handler;
+ sigaction(SIGALRM, &sa, NULL);
+
+ timer.it_value.tv_sec = 0;
+ timer.it_value.tv_usec = 10000;
+ timer.it_interval.tv_sec = timer.it_interval.tv_usec = 0;
+ none_timer.it_value.tv_sec = none_timer.it_value.tv_usec = 0;
+ none_timer.it_interval.tv_sec = none_timer.it_interval.tv_usec = 0;
+
+ double prev_time_value, time_value;
+ double time_diff;
+
+ debug_print("Sending init announcement\n");
+ char *init_announce = mkjson(MKJSON_OBJ, 1,
+ MKJSON_STRING, "type", "init");
+
+ // check for timeout on initial contact
+ while (!init_alarm) {
+ debug_call(prev_time_value = get_posix_clock_time());
+
+ setitimer(ITIMER_REAL, &timer, NULL);
+
+ zmq_send(Requester, init_announce, strlen(init_announce), 0);
+ zmq_recv(Requester, buffer, 16, 0);
+
+ setitimer(ITIMER_REAL, &none_timer, &timer);
+
+ debug_call(time_value = get_posix_clock_time());
+
+ debug_print("Received init receipt\n");
+ debug_call(time_diff = time_value - prev_time_value);
+ debug_print("time elapse %f\n", time_diff);
+
+ break;
+ }
+
+ free(init_announce);
+
+ if (timeout) return -1;
+
+ FILE *fp_a = popen(GET_ACTIVE, "r");
+ getdelim(&active_str, &active_len, '\0', fp_a);
+ int ret = pclose(fp_a);
+
+ if (!ret) {
+ debug_print("Sending active config\n");
+ zmq_send(Requester, active_str, active_len - 1, 0);
+ zmq_recv(Requester, buffer, 16, 0);
+ debug_print("Received active receipt\n");
+ } else {
+ debug_print("Sending empty active config\n");
+ zmq_send(Requester, empty_string, 0, 0);
+ zmq_recv(Requester, buffer, 16, 0);
+ debug_print("Received active receipt\n");
+ }
+
+ free(active_str);
+
+ FILE *fp_s = popen(GET_SESSION, "r");
+ getdelim(&session_str, &session_len, '\0', fp_s);
+ pclose(fp_s);
+
+ debug_print("Sending session config\n");
+ zmq_send(Requester, session_str, session_len - 1, 0);
+ zmq_recv(Requester, buffer, 16, 0);
+ debug_print("Received session receipt\n");
+
+ free(session_str);
+
+ return 0;
+}
+
+int pass_through(char **argv, int end)
+{
+ char *newargv[] = { NULL, NULL };
+ pid_t child_pid;
+
+ newargv[0] = argv[end];
+ if (end > 1) {
+ putenv(argv[end - 1]);
+ }
+
+ debug_print("pass-through invoked\n");
+
+ if ((child_pid=fork()) < 0) {
+ debug_print("fork() failed\n");
+ return -1;
+ } else if (child_pid == 0) {
+ if (-1 == execv(argv[end], newargv)) {
+ debug_print("pass_through execve failed %s: %s\n",
+ argv[end], strerror(errno));
+ return -1;
+ }
+ } else if (child_pid > 0) {
+ int status;
+ pid_t wait_pid = waitpid(child_pid, &status, 0);
+ if (wait_pid < 0) {
+ debug_print("waitpid() failed\n");
+ return -1;
+ } else if (wait_pid == child_pid) {
+ if (WIFEXITED(status)) {
+ debug_print("child exited with code %d\n",
+ WEXITSTATUS(status));
+ return WEXITSTATUS(status);
+ }
+ }
+ }
+
+ return 0;
+}
+
+void timer_handler(int signum)
+{
+ debug_print("timer_handler invoked\n");
+ timeout = 1;
+ init_alarm = 1;
+
+ return;
+}
+
+#ifdef _POSIX_MONOTONIC_CLOCK
+double get_posix_clock_time(void)
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ return (double) (ts.tv_sec + ts.tv_nsec / 1000000000.0);
+ } else {
+ return 0;
+ }
+}
+#else
+double get_posix_clock_time(void)
+{return (double)0;}
+#endif