Browse Source

ccan/err: new err.h-replacing module.

Seems like Solaris doesn't have err.h, as discovered by Samba.
Rusty Russell 13 years ago
parent
commit
4776faf17a
3 changed files with 245 additions and 0 deletions
  1. 37 0
      ccan/err/_info
  2. 69 0
      ccan/err/err.h
  3. 139 0
      ccan/err/test/run.c

+ 37 - 0
ccan/err/_info

@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * err - err(), errx(), warn() and warnx(), as per BSD's err.h.
+ *
+ * A few platforms don't provide err.h; for those, this provides replacements.
+ * For most, it simple includes the system err.h.
+ *
+ * Example:
+ *	#include <ccan/err/err.h>
+ *
+ *	int main(int argc, char *argv[])
+ *	{
+ *		if (argc != 1)
+ *			errx(1, "Expect no arguments");
+ *		exit(0);
+ *	}
+ *
+ * License: Public domain
+ * Author: Rusty Russell <rusty@rustcorp.com.au>
+ */
+int main(int argc, char *argv[])
+{
+	if (argc != 2)
+		return 1;
+
+	if (strcmp(argv[1], "depends") == 0) {
+#if !HAVE_ERR_H
+		printf("ccan/compiler\n");
+#endif
+		return 0;
+	}
+
+	return 1;
+}

+ 69 - 0
ccan/err/err.h

@@ -0,0 +1,69 @@
+#ifndef CCAN_ERR_H
+#define CCAN_ERR_H
+#include "config.h"
+
+#if HAVE_ERR_H
+#include <err.h>
+#else
+#include <ccan/compiler/compiler.h>
+
+/**
+ * err - exit(eval) with message based on format and errno.
+ * @eval: the exit code
+ * @fmt: the printf-style format string
+ *
+ * The format string is printed to stderr like so:
+ *	<executable name>: <format>: <strerror(errno)>\n
+ *
+ * Example:
+ *	char *p = strdup("hello");
+ *	if (!p)
+ *		err(1, "Failed to strdup 'hello'");
+ */
+void NORETURN err(int eval, const char *fmt, ...);
+
+/**
+ * errx - exit(eval) with message based on format.
+ * @eval: the exit code
+ * @fmt: the printf-style format string
+ *
+ * The format string is printed to stderr like so:
+ *	<executable name>: <format>\n
+ *
+ * Example:
+ *	if (argc != 1)
+ *		errx(1, "I don't expect any arguments");
+ */
+void NORETURN errx(int eval, const char *fmt, ...);
+
+/**
+ * warn - print a message to stderr based on format and errno.
+ * @eval: the exit code
+ * @fmt: the printf-style format string
+ *
+ * The format string is printed to stderr like so:
+ *	<executable name>: <format>: <strerror(errno)>\n
+ *
+ * Example:
+ *	char *p = strdup("hello");
+ *	if (!p)
+ *		warn("Failed to strdup 'hello'");
+ */
+void warn(const char *fmt, ...);
+
+/**
+ * warnx - print a message to stderr based on format.
+ * @eval: the exit code
+ * @fmt: the printf-style format string
+ *
+ * The format string is printed to stderr like so:
+ *	<executable name>: <format>\n
+ *
+ * Example:
+ *	if (argc != 1)
+ *		warnx("I don't expect any arguments (ignoring)");
+ */
+void warnx(const char *fmt, ...);
+#endif
+
+#endif /* CCAN_ERR_H */

+ 139 - 0
ccan/err/test/run.c

@@ -0,0 +1,139 @@
+#include <ccan/err/err.h>
+#include <ccan/tap/tap.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define BUFFER_MAX 1024
+
+int main(void)
+{
+	int pfd[2];
+
+	plan_tests(20);
+	fflush(stdout);
+
+	/* Test err() in child */
+	pipe(pfd);
+	if (fork()) {
+		char buffer[BUFFER_MAX+1];
+		unsigned int i;
+		int status;
+
+		/* We are parent. */
+		close(pfd[1]);
+		for (i = 0; i < BUFFER_MAX; i++) {
+			if (read(pfd[0], buffer + i, 1) == 0) {
+				buffer[i] = '\0';
+				ok1(strstr(buffer, "running err:"));
+				ok1(strstr(buffer, strerror(ENOENT)));
+				ok1(buffer[i-1] == '\n');
+				break;
+			}
+		}
+		close(pfd[0]);
+		ok1(wait(&status) != -1);
+		ok1(WIFEXITED(status));
+		ok1(WEXITSTATUS(status) == 17);
+	} else {
+		close(pfd[0]);
+		dup2(pfd[1], STDERR_FILENO);
+		errno = ENOENT;
+		err(17, "running %s", "err");
+		abort();
+	}
+
+	/* Test errx() in child */
+	pipe(pfd);
+	fflush(stdout);
+	if (fork()) {
+		char buffer[BUFFER_MAX+1];
+		unsigned int i;
+		int status;
+
+		/* We are parent. */
+		close(pfd[1]);
+		for (i = 0; i < BUFFER_MAX; i++) {
+			if (read(pfd[0], buffer + i, 1) == 0) {
+				buffer[i] = '\0';
+				ok1(strstr(buffer, "running errx\n"));
+				break;
+			}
+		}
+		close(pfd[0]);
+		ok1(wait(&status) != -1);
+		ok1(WIFEXITED(status));
+		ok1(WEXITSTATUS(status) == 17);
+	} else {
+		close(pfd[0]);
+		dup2(pfd[1], STDERR_FILENO);
+		errx(17, "running %s", "errx");
+		abort();
+	}
+
+
+	/* Test warn() in child */
+	pipe(pfd);
+	fflush(stdout);
+	if (fork()) {
+		char buffer[BUFFER_MAX+1];
+		unsigned int i;
+		int status;
+
+		/* We are parent. */
+		close(pfd[1]);
+		for (i = 0; i < BUFFER_MAX; i++) {
+			if (read(pfd[0], buffer + i, 1) == 0) {
+				buffer[i] = '\0';
+				ok1(strstr(buffer, "running warn:"));
+				ok1(strstr(buffer, strerror(ENOENT)));
+				ok1(buffer[i-1] == '\n');
+				break;
+			}
+		}
+		close(pfd[0]);
+		ok1(wait(&status) != -1);
+		ok1(WIFEXITED(status));
+		ok1(WEXITSTATUS(status) == 17);
+	} else {
+		close(pfd[0]);
+		dup2(pfd[1], STDERR_FILENO);
+		errno = ENOENT;
+		warn("running %s", "warn");
+		exit(17);
+	}
+
+	/* Test warnx() in child */
+	pipe(pfd);
+	fflush(stdout);
+	if (fork()) {
+		char buffer[BUFFER_MAX+1];
+		unsigned int i;
+		int status;
+
+		/* We are parent. */
+		close(pfd[1]);
+		for (i = 0; i < BUFFER_MAX; i++) {
+			if (read(pfd[0], buffer + i, 1) == 0) {
+				buffer[i] = '\0';
+				ok1(strstr(buffer, "running warnx\n"));
+				break;
+			}
+		}
+		close(pfd[0]);
+		ok1(wait(&status) != -1);
+		ok1(WIFEXITED(status));
+		ok1(WEXITSTATUS(status) == 17);
+	} else {
+		close(pfd[0]);
+		dup2(pfd[1], STDERR_FILENO);
+		warnx("running %s", "warnx");
+		exit(17);
+	}
+	return exit_status();
+}
+