diff options
-rw-r--r-- | btime/Makefile | 48 | ||||
-rw-r--r-- | btime/btime.c | 111 | ||||
-rw-r--r-- | btime/btime.h | 10 | ||||
-rw-r--r-- | btime/btime_int.h | 12 | ||||
-rw-r--r-- | btime/btimec.c | 28 | ||||
-rw-r--r-- | btime/btimed.c | 271 |
6 files changed, 480 insertions, 0 deletions
diff --git a/btime/Makefile b/btime/Makefile new file mode 100644 index 0000000..6a2a454 --- /dev/null +++ b/btime/Makefile @@ -0,0 +1,48 @@ +include ../../make/defines.mk + +.PHONY: clean clobber uninstall + +CC = gcc +AR = ar +#CFLAGS += -g + +all: libbtime.a btimed btimec + +btimed: btimed.c btime_int.h + $(CC) $(CFLAGS) -o btimed btimed.c + +btimec: btimec.c libbtime.a + $(CC) $(CFLAGS) -L. -o btimec btimec.c -lbtime + +libbtime.a: btime.c btime_int.h + $(CC) $(CFLAGS) -c btime.c + $(AR) -rc libbtime.a btime.o + +install: btimed btimec libbtime.a + @echo "Installing btime deamon and test client" + @install -d ${STSDIR}/bin/ + @install btimed ${STSDIR}/bin + @install btimec ${STSDIR}/bin + + @echo "Installing btime library" + @install -d ${STSDIR}/lib/ + @install libbtime.a ${STSDIR}/lib + + @echo "Installing btime header" + @install -d ${STSDIR}/include/ + @install btime.h ${STSDIR}/include + + +uninstall: + ${UNINSTALL} btimed ${STSDIR}/bin + ${UNINSTALL} btimec ${STSDIR}/bin + + +clean: + /bin/rm -f *.o + +clobber: + /bin/rm -f btimec + /bin/rm -f btimed + /bin/rm -f *.a *.o + diff --git a/btime/btime.c b/btime/btime.c new file mode 100644 index 0000000..f22c08b --- /dev/null +++ b/btime/btime.c @@ -0,0 +1,111 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <netdb.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "btime_int.h" + +/* + * btime -- + * + * Return the boot time of a remote host if that host is running the + * btimed deamon. + * + * Returns: + * btime, or 0 on failure. + */ + +unsigned int +btime(const char *host) +{ + int sd; + char msg[BTIME_MSGLEN]; + struct sockaddr_in serv_addr; + struct sockaddr_in my_addr; + int serv_addr_len; + struct hostent *hostent; + in_addr_t inaddr; + unsigned int btime; + ssize_t nbytes; + int retry; + + if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + fprintf(stderr, "Could not create socket: %s\n", + strerror(errno)); + return 0; + } + + memset(&serv_addr, 0, sizeof serv_addr); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(BTIME_PORT); + + if ((inaddr = inet_addr(host)) != INADDR_NONE) { + memcpy(&serv_addr.sin_addr, &inaddr, sizeof inaddr); + } else { + if ((hostent = gethostbyname(host)) == NULL) { + return 0; + } + + memcpy(&serv_addr.sin_addr, hostent->h_addr, hostent->h_length); + } + + memset(&my_addr, 0, sizeof my_addr); + my_addr.sin_family = AF_INET; + my_addr.sin_addr.s_addr = htonl(INADDR_ANY); + my_addr.sin_port = htons(0); + if (bind(sd, (struct sockaddr *)&my_addr, sizeof my_addr) < 0) { + fprintf(stderr, "Could not bind to local address: %s\n", + strerror(errno)); + return 0; + } + + memset(msg, 0, BTIME_MSGLEN); + for (retry = 0; retry < MAX_RETRY; retry++) { + serv_addr_len = sizeof serv_addr; + if ((nbytes = sendto(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT, + (struct sockaddr *)&serv_addr, serv_addr_len)) < 0) { + if (errno == EAGAIN) { + usleep(retry * 100); + } else { + /* Non EAGAIN error... */ + break; + } + } else { + break; + } + } + + + memset(msg, 0, BTIME_MSGLEN); + for (retry = 0; retry < MAX_RETRY; retry++) { + serv_addr_len = sizeof serv_addr; + if ((nbytes = recvfrom(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT, + (struct sockaddr *)&serv_addr, &serv_addr_len)) < 0) { + if (errno == EAGAIN) { + usleep(retry * 100); + } else { + /* Non EAGAIN error... */ + break; + } + } else { + break; + } + } + + if (nbytes == 0) { + btime = 0; + } else { + btime = strtoul(msg, (char **)NULL, 10); + } + + close(sd); + + return btime; +} diff --git a/btime/btime.h b/btime/btime.h new file mode 100644 index 0000000..41d3e39 --- /dev/null +++ b/btime/btime.h @@ -0,0 +1,10 @@ +/* + * btime.h -- + */ + +#ifndef __BTIME_H +#define __BTIME_H + +extern unsigned int btime(const char *host); + +#endif /* __BTIME_H */ diff --git a/btime/btime_int.h b/btime/btime_int.h new file mode 100644 index 0000000..b2cafcd --- /dev/null +++ b/btime/btime_int.h @@ -0,0 +1,12 @@ +/* + * btime_int.h -- + */ + +#ifndef __BTIME_INT_H +#define __BTIME_INT_H + +#define BTIME_PORT 23456 +#define BTIME_MSGLEN 128 +#define MAX_RETRY 5 + +#endif /* __BTIME_INT_H */ diff --git a/btime/btimec.c b/btime/btimec.c new file mode 100644 index 0000000..02c29bc --- /dev/null +++ b/btime/btimec.c @@ -0,0 +1,28 @@ +/* + * btimec.c -- + * + * Example program for libbtime + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "btime.h" + +int +main(int argc, char **argv) +{ + unsigned int bt; + char *btimedhost; + + if (argc != 2) { + fprintf(stderr, "USAGE: %s <host>\n", argv[0]); + exit(2); + } + + btimedhost = argv[1]; + bt = btime(btimedhost); + printf("%s: %u\n", btimedhost, bt); + + exit(0); +} diff --git a/btime/btimed.c b/btime/btimed.c new file mode 100644 index 0000000..259c8aa --- /dev/null +++ b/btime/btimed.c @@ -0,0 +1,271 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <syslog.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "btime_int.h" + +static void (*btimed_error)(int level, const char *fmt, ...); + +static void btimed(void); +static unsigned int get_btime(void); +static int daemon_init(void); +static void btimed_perror(int level, const char *fmt, ...); +static void sigchld_hdlr(int sig); +static void usage(const char *progname); + + +int +main(int argc, char **argv) +{ + struct sigaction sa; + int debug = 0; + int c; + + while ((c = getopt(argc, argv, "hd")) != -1) { + switch (c) { + case 'd': + debug = 1; + break; + case 'h': + case '?': + default: + usage(argv[0]); + exit(2); + } + } + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = sigchld_hdlr; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; + sigaction(SIGCHLD, &sa, NULL); + + if (debug) { + btimed_error = btimed_perror; + } else { + btimed_error = syslog; + daemon_init(); + } + + btimed(); + + return 0; +} + + +/* + *--------------------------------------------------------------------------- + * + * btimed -- + * + * The main loop of the deamon. It listens on its well know port for + * messages, responds to the request via a child process. + * + * Returns: + * Never returns. + * + * Side effects: + * Child processes are created. + *--------------------------------------------------------------------------- + */ + +static void +btimed(void) +{ + int sd; + char msg[BTIME_MSGLEN]; + struct sockaddr_in cli_addr; + int cli_addr_len; + struct sockaddr_in my_addr; + pid_t pid; + ssize_t nbytes; + + if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + btimed_error(LOG_ERR, "Could not create socket: %s\n", + strerror(errno)); + exit(1); + } + + memset(&my_addr, 0, sizeof my_addr); + my_addr.sin_family = AF_INET; + my_addr.sin_addr.s_addr = htonl(INADDR_ANY); + my_addr.sin_port = htons(BTIME_PORT); + if (bind(sd, (struct sockaddr *)&my_addr, sizeof my_addr) < 0) { + btimed_error(LOG_ERR, "Could not bind to local address: %s\n", + strerror(errno)); + exit(1); + } + + for (;;) { + memset(&cli_addr, 0, sizeof cli_addr); + cli_addr_len = sizeof cli_addr; + nbytes = recvfrom(sd, &msg, BTIME_MSGLEN, MSG_WAITALL, + (struct sockaddr *)&cli_addr, &cli_addr_len); + + if ((pid = fork()) < 0) { + btimed_error(LOG_ERR, "Could not fork(): %s\n", strerror(errno)); + exit(1); + } + + if (pid == 0) { + memset(msg, 0, BTIME_MSGLEN); + sprintf(msg, "%u\n", get_btime()); + sendto(sd, &msg, BTIME_MSGLEN, MSG_DONTWAIT, + (struct sockaddr *)&cli_addr, cli_addr_len); + + exit(0); + } + } + + close(sd); +} + + + +/* + *--------------------------------------------------------------------------- + * + * get_btime -- + * + * Return machine's boot time. + * + * Returns: + * 0 on failure + * non-zero on success. + * + *--------------------------------------------------------------------------- + */ + +static unsigned int +get_btime(void) +{ + FILE *statf; + char line[1024]; + unsigned int btime = 0; + + if ((statf = fopen("/proc/stat", "r")) == NULL) { + btimed_error(LOG_ERR, "/proc/stat open failure: %s\n", + strerror(errno)); + exit(1); + } + + while (fgets(line, 1024, statf) != NULL) { + if (strstr(line, "btime") != NULL) { + sscanf(line, "%*s%u", &btime); + } + + } + + fclose(statf); + + return btime; +} + + +/* + *--------------------------------------------------------------------------- + * + * daemon_init -- + * + * Set up a basic daemon environment + * + * Returns: + * 0 on success + * non-zero on failure. + * + * Side effects: + * All fds are closed and process is now a session leader. + * + *--------------------------------------------------------------------------- + */ + +static int +daemon_init(void) +{ + pid_t pid; + int fd; + int maxfd = sysconf(_SC_OPEN_MAX); + + if ((pid = fork()) < 0) { + return(-1); + } else if (pid != 0) { + exit(0); /* Exit in parent */ + } + + /* + * Child sets up daemon environment + */ + + setsid(); /* Become session leader */ + chdir("/"); + umask(0); + for (fd = 0; fd < maxfd; fd++) { + close(fd); + } + errno = 0; /* probably set to EBADFD from above loop, reset */ + + openlog("btimed", LOG_PID, LOG_USER); + + return 0; +} + + +/* + *--------------------------------------------------------------------------- + * + * btimed_perror -- + * + * Print error messages to stderr, level is not used, it is there + * to have the same calling args as syslog(3) so we can use either + * based on debug level. + * + * Returns: + * NA + * + * Side effects: + * None + *--------------------------------------------------------------------------- + */ + +static void +btimed_perror(int level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + + +static void +sigchld_hdlr(int sig) +{ + int status; + + wait(&status); + return; +} + + +static void +usage(const char *progname) +{ + fprintf(stderr, "Usage: %s [OPTION]...\n" + "-h\tPrint this help and exit.\n" + "-d\tDon't daemonize, send output to stderr.\n", + progname); + + return; +} |