Add dhcpcd-online application to ease integration with parallal startup
authorRoy Marples <roy@marples.name>
Tue, 2 Sep 2014 21:18:05 +0000 (21:18 +0000)
committerRoy Marples <roy@marples.name>
Tue, 2 Sep 2014 21:18:05 +0000 (21:18 +0000)
when dhcpcd is not forked but applcation need to depend on it.
systemd could use it for dhcpcd-wait-online.service for example

src/dhcpcd-online/Makefile [new file with mode: 0644]
src/dhcpcd-online/dhcpcd-online.8 [new file with mode: 0644]
src/dhcpcd-online/dhcpcd-online.c [new file with mode: 0644]

diff --git a/src/dhcpcd-online/Makefile b/src/dhcpcd-online/Makefile
new file mode 100644 (file)
index 0000000..6881899
--- /dev/null
@@ -0,0 +1,16 @@
+PROG=          dhcpcd-online
+SRCS=          dhcpcd-online.c
+
+MAN8=          dhcpcd-online.8
+
+TOPDIR=                ../..
+include ${TOPDIR}/iconfig.mk
+
+MAN8=          dhcpcd-online.8
+
+CPPFLAGS+=     -I${TOPDIR}
+
+LDADD+=                ${LIB_DHCPCD} ${LIB_INTL}
+
+include ../libdhcpcd/Makefile.inc
+include ${MKDIR}/prog.mk
diff --git a/src/dhcpcd-online/dhcpcd-online.8 b/src/dhcpcd-online/dhcpcd-online.8
new file mode 100644 (file)
index 0000000..217dcdd
--- /dev/null
@@ -0,0 +1,71 @@
+.\" Copyright (c) 2014 Roy Marples
+.\" All rights reserved
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd September 2, 2014
+.Dt DHCPCD-ONLINE
+.Os
+.Sh NAME
+.Nm dhcpcd-online
+.Nd a utility to work out if
+.Xr dhcpcd 8
+is in the connected state
+.Sh SYNOPSIS
+.Nm
+.Op Fl q
+.Op Fl t Ar timeout
+.Op Fl x
+.Sh DESCRIPTION
+.Nm
+connects to
+.Xr dhcpcd 8
+and waits for a maximum of
+.Ar timeout
+seconds until the status changes to
+.Va connected .
+This tool is intended for use in the startup of the host system
+where
+.Xr dhcpcd 8
+is started in parallel with other services who depend on a network connection
+being available.
+.Pp
+Options:
+.Bl -tag --width flag
+.It Fl q
+Suppresses the reporting of non error messages.
+.It Fl t Ar timeout
+Sets the number of seconds
+.Nm
+waits for
+.Xr dhcpcd 8
+to reach the connected state.
+If not specified, a default value of 30 is used.
+.It Fl x
+Exits immediately if
+.Xr dhcpcd 8
+is not running.
+.El
+.Sh AUTHORS
+.An Roy Marples Aq roy@marples.name
+.Sh BUGS
+Please report them to http://roy.marples.name/projects/dhcpcd-ui
diff --git a/src/dhcpcd-online/dhcpcd-online.c b/src/dhcpcd-online/dhcpcd-online.c
new file mode 100644 (file)
index 0000000..334960c
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * dhcpcd-online
+ * Copyright 2014 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "dhcpcd.h"
+
+#if __GNUC__ > 2 || defined(__INTEL_COMPILER)
+# ifndef __dead
+#  define __dead __attribute__((__noreturn__))
+# endif
+# ifndef __unused
+#  define __unused   __attribute__((__unused__))
+# endif
+#else
+# ifndef __dead
+#  define __dead
+# endif
+# ifndef __unused
+#  define __unused
+# endif
+#endif
+
+static void __dead
+do_exit(DHCPCD_CONNECTION *con, int code)
+{
+
+       dhcpcd_close(con);
+       dhcpcd_free(con);
+       exit(code);
+}
+
+static void
+do_status_cb(DHCPCD_CONNECTION *con, const char *status, void __unused *arg)
+{
+
+       syslog(LOG_INFO, "%s", status);
+       if (strcmp(status, "connected") == 0)
+               do_exit(con, EXIT_SUCCESS);
+}
+
+int
+main(int argc, char **argv)
+{
+       DHCPCD_CONNECTION *con;
+       bool xflag;
+       struct timespec now, end, t;
+       struct pollfd pfd;
+       int timeout, n, lerrno;
+       long lnum;
+       char *lend;
+
+       /* Defaults */
+       timeout = 30;
+
+       xflag = false;
+
+       openlog("dhcpcd-online", LOG_PERROR, 0);
+       setlogmask(LOG_UPTO(LOG_INFO));
+
+       while ((n = getopt(argc, argv, "qt:x")) != -1) {
+               switch (n) {
+               case 'q':
+                       closelog();
+                       openlog("dhcpcd-online", 0, 0);
+                       break;
+               case 't':
+                       lnum = strtol(optarg, &lend, 0);
+                       if (lend == NULL || *lend != '\0' ||
+                           lnum < 0 || lnum > INT_MAX)
+                       {
+                               syslog(LOG_ERR, "-t %s: invalid timeout",
+                                   optarg);
+                               exit(EXIT_FAILURE);
+                       }
+                       timeout = (int)lnum;
+                       break;
+               case 'x':
+                       xflag = true;
+                       break;
+               case '?':
+                       fprintf(stderr, "usage: dhcpcd-online "
+                           "[-q] [-t timeout]\n");
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       if ((con = dhcpcd_new()) == NULL) {
+               syslog(LOG_ERR, "dhcpcd_new: %m");
+               return EXIT_FAILURE;
+       }
+
+       dhcpcd_set_status_callback(con, do_status_cb, NULL);
+
+       if ((pfd.fd = dhcpcd_open(con)) == -1) {
+               lerrno = errno;
+               syslog(LOG_WARNING, "dhcpcd_open: %m");
+               if (xflag)
+                       do_exit(con, EXIT_FAILURE);
+       } else
+               lerrno = 0;
+       pfd.events = POLLIN;
+       pfd.revents = 0;
+
+       /* Work out our timeout time */
+       if (clock_gettime(CLOCK_MONOTONIC, &end) == -1) {
+               syslog(LOG_ERR, "clock_gettime: %m");
+               do_exit(con, EXIT_FAILURE);
+       }
+       end.tv_sec += timeout;
+
+       for (;;) {
+               if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
+                       syslog(LOG_ERR, "clock_gettime: %m");
+                       do_exit(con, EXIT_FAILURE);
+               }
+               if (timespeccmp(&now, &end, >)) {
+                       syslog(LOG_ERR, "timed out");
+                       do_exit(con, EXIT_FAILURE);
+               }
+               if (pfd.fd == -1) {
+                       n = poll(NULL, 0, DHCPCD_RETRYOPEN);
+               } else {
+                       /* poll(2) should really take a timespec */
+                       timespecsub(&end, &now, &t);
+                       if (t.tv_sec > INT_MAX / 1000 ||
+                           (t.tv_sec == INT_MAX / 1000 &&
+                           (t.tv_nsec + 999999) / 1000000 > INT_MAX % 1000000))
+                               timeout = INT_MAX;
+                       else
+                               timeout = (int)t.tv_sec * 1000 +
+                                   (t.tv_nsec + 999999) / 1000000;
+                       n = poll(&pfd, 1, timeout);
+               }
+               if (n == -1) {
+                       syslog(LOG_ERR, "poll: %m");
+                       do_exit(con, EXIT_FAILURE);
+               }
+               if (pfd.fd == -1) {
+                       if ((pfd.fd = dhcpcd_open(con)) == -1) {
+                               if (lerrno != errno) {
+                                       lerrno = errno;
+                                       syslog(LOG_WARNING, "dhcpcd_open: %m");
+                               }
+                       }
+               } else {
+                       if (n > 0 && pfd.revents)
+                               dhcpcd_dispatch(con);
+               }
+       }
+
+       /* Impossible to reach here */
+       do_exit(con, EXIT_FAILURE);
+}