spiped 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/ext/spiped/extconf.rb +3 -0
  3. data/ext/spiped/spiped-source/BUILDING +46 -0
  4. data/ext/spiped/spiped-source/CHANGELOG +44 -0
  5. data/ext/spiped/spiped-source/COPYRIGHT +33 -0
  6. data/ext/spiped/spiped-source/Makefile +47 -0
  7. data/ext/spiped/spiped-source/Makefile.POSIX +27 -0
  8. data/ext/spiped/spiped-source/Makefile.inc +20 -0
  9. data/ext/spiped/spiped-source/Makefile.prog +23 -0
  10. data/ext/spiped/spiped-source/POSIX/README +10 -0
  11. data/ext/spiped/spiped-source/POSIX/posix-cflags.sh +10 -0
  12. data/ext/spiped/spiped-source/POSIX/posix-clock_realtime.c +3 -0
  13. data/ext/spiped/spiped-source/POSIX/posix-l.c +1 -0
  14. data/ext/spiped/spiped-source/POSIX/posix-l.sh +14 -0
  15. data/ext/spiped/spiped-source/POSIX/posix-msg_nosignal.c +3 -0
  16. data/ext/spiped/spiped-source/README +198 -0
  17. data/ext/spiped/spiped-source/STYLE +151 -0
  18. data/ext/spiped/spiped-source/lib/dnsthread/dnsthread.c +464 -0
  19. data/ext/spiped/spiped-source/lib/dnsthread/dnsthread.h +45 -0
  20. data/ext/spiped/spiped-source/libcperciva/alg/sha256.c +442 -0
  21. data/ext/spiped/spiped-source/libcperciva/alg/sha256.h +95 -0
  22. data/ext/spiped/spiped-source/libcperciva/cpusupport/Build/cpusupport-X86-AESNI.c +13 -0
  23. data/ext/spiped/spiped-source/libcperciva/cpusupport/Build/cpusupport-X86-CPUID.c +8 -0
  24. data/ext/spiped/spiped-source/libcperciva/cpusupport/Build/cpusupport.sh +37 -0
  25. data/ext/spiped/spiped-source/libcperciva/cpusupport/cpusupport.h +63 -0
  26. data/ext/spiped/spiped-source/libcperciva/cpusupport/cpusupport_x86_aesni.c +30 -0
  27. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes.c +166 -0
  28. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes.h +31 -0
  29. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes_aesni.c +229 -0
  30. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes_aesni.h +31 -0
  31. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aesctr.c +124 -0
  32. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aesctr.h +41 -0
  33. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh.c +293 -0
  34. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh.h +43 -0
  35. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh_group14.c +46 -0
  36. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh_group14.h +9 -0
  37. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_entropy.c +215 -0
  38. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_entropy.h +14 -0
  39. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_verify_bytes.c +21 -0
  40. data/ext/spiped/spiped-source/libcperciva/crypto/crypto_verify_bytes.h +14 -0
  41. data/ext/spiped/spiped-source/libcperciva/datastruct/elasticarray.c +276 -0
  42. data/ext/spiped/spiped-source/libcperciva/datastruct/elasticarray.h +167 -0
  43. data/ext/spiped/spiped-source/libcperciva/datastruct/mpool.h +85 -0
  44. data/ext/spiped/spiped-source/libcperciva/datastruct/ptrheap.c +334 -0
  45. data/ext/spiped/spiped-source/libcperciva/datastruct/ptrheap.h +89 -0
  46. data/ext/spiped/spiped-source/libcperciva/datastruct/timerqueue.c +241 -0
  47. data/ext/spiped/spiped-source/libcperciva/datastruct/timerqueue.h +60 -0
  48. data/ext/spiped/spiped-source/libcperciva/events/events.c +203 -0
  49. data/ext/spiped/spiped-source/libcperciva/events/events.h +106 -0
  50. data/ext/spiped/spiped-source/libcperciva/events/events_immediate.c +149 -0
  51. data/ext/spiped/spiped-source/libcperciva/events/events_internal.h +95 -0
  52. data/ext/spiped/spiped-source/libcperciva/events/events_network.c +347 -0
  53. data/ext/spiped/spiped-source/libcperciva/events/events_network_selectstats.c +106 -0
  54. data/ext/spiped/spiped-source/libcperciva/events/events_timer.c +273 -0
  55. data/ext/spiped/spiped-source/libcperciva/network/network.h +95 -0
  56. data/ext/spiped/spiped-source/libcperciva/network/network_accept.c +103 -0
  57. data/ext/spiped/spiped-source/libcperciva/network/network_connect.c +258 -0
  58. data/ext/spiped/spiped-source/libcperciva/network/network_read.c +155 -0
  59. data/ext/spiped/spiped-source/libcperciva/network/network_write.c +188 -0
  60. data/ext/spiped/spiped-source/libcperciva/util/asprintf.c +49 -0
  61. data/ext/spiped/spiped-source/libcperciva/util/asprintf.h +16 -0
  62. data/ext/spiped/spiped-source/libcperciva/util/daemonize.c +134 -0
  63. data/ext/spiped/spiped-source/libcperciva/util/daemonize.h +10 -0
  64. data/ext/spiped/spiped-source/libcperciva/util/entropy.c +76 -0
  65. data/ext/spiped/spiped-source/libcperciva/util/entropy.h +13 -0
  66. data/ext/spiped/spiped-source/libcperciva/util/imalloc.h +33 -0
  67. data/ext/spiped/spiped-source/libcperciva/util/insecure_memzero.c +19 -0
  68. data/ext/spiped/spiped-source/libcperciva/util/insecure_memzero.h +33 -0
  69. data/ext/spiped/spiped-source/libcperciva/util/monoclock.c +52 -0
  70. data/ext/spiped/spiped-source/libcperciva/util/monoclock.h +14 -0
  71. data/ext/spiped/spiped-source/libcperciva/util/noeintr.c +54 -0
  72. data/ext/spiped/spiped-source/libcperciva/util/noeintr.h +14 -0
  73. data/ext/spiped/spiped-source/libcperciva/util/sock.c +472 -0
  74. data/ext/spiped/spiped-source/libcperciva/util/sock.h +56 -0
  75. data/ext/spiped/spiped-source/libcperciva/util/sock_internal.h +14 -0
  76. data/ext/spiped/spiped-source/libcperciva/util/sock_util.c +271 -0
  77. data/ext/spiped/spiped-source/libcperciva/util/sock_util.h +51 -0
  78. data/ext/spiped/spiped-source/libcperciva/util/sysendian.h +146 -0
  79. data/ext/spiped/spiped-source/libcperciva/util/warnp.c +76 -0
  80. data/ext/spiped/spiped-source/libcperciva/util/warnp.h +59 -0
  81. data/ext/spiped/spiped-source/proto/proto_conn.c +362 -0
  82. data/ext/spiped/spiped-source/proto/proto_conn.h +25 -0
  83. data/ext/spiped/spiped-source/proto/proto_crypt.c +396 -0
  84. data/ext/spiped/spiped-source/proto/proto_crypt.h +102 -0
  85. data/ext/spiped/spiped-source/proto/proto_handshake.c +330 -0
  86. data/ext/spiped/spiped-source/proto/proto_handshake.h +30 -0
  87. data/ext/spiped/spiped-source/proto/proto_pipe.c +202 -0
  88. data/ext/spiped/spiped-source/proto/proto_pipe.h +23 -0
  89. data/ext/spiped/spiped-source/spipe/Makefile +90 -0
  90. data/ext/spiped/spiped-source/spipe/README +24 -0
  91. data/ext/spiped/spiped-source/spipe/main.c +178 -0
  92. data/ext/spiped/spiped-source/spipe/pushbits.c +101 -0
  93. data/ext/spiped/spiped-source/spipe/pushbits.h +10 -0
  94. data/ext/spiped/spiped-source/spipe/spipe.1 +60 -0
  95. data/ext/spiped/spiped-source/spiped/Makefile +98 -0
  96. data/ext/spiped/spiped-source/spiped/README +62 -0
  97. data/ext/spiped/spiped-source/spiped/dispatch.c +214 -0
  98. data/ext/spiped/spiped-source/spiped/dispatch.h +27 -0
  99. data/ext/spiped/spiped-source/spiped/main.c +267 -0
  100. data/ext/spiped/spiped-source/spiped/spiped.1 +112 -0
  101. data/lib/spiped.rb +3 -0
  102. metadata +143 -0
@@ -0,0 +1,188 @@
1
+ #include <sys/socket.h>
2
+
3
+ #include <assert.h>
4
+ #include <errno.h>
5
+ #include <limits.h>
6
+ #include <signal.h>
7
+ #include <stdint.h>
8
+ #include <stdlib.h>
9
+ #include <unistd.h>
10
+
11
+ #include "events.h"
12
+ #include "warnp.h"
13
+
14
+ #include "network.h"
15
+
16
+ /**
17
+ * POSIX.1-2008 requires that MSG_NOSIGNAL be defined as a flag for send(2)
18
+ * which has the effect of preventing SIGPIPE from being raised when writing
19
+ * to a descriptor which has been shut down. Unfortunately there are some
20
+ * platforms which are not POSIX.1-2008 compliant; we provide a workaround
21
+ * (-DPOSIXFAIL_MSG_NOSIGNAL) which instead blocks the SIGPIPE signal on such
22
+ * platforms.
23
+ *
24
+ * (This workaround could be used automatically, but requiring that it be
25
+ * explicitly enabled helps to get platforms fixed.)
26
+ */
27
+ #ifdef POSIXFAIL_MSG_NOSIGNAL
28
+ #ifndef MSG_NOSIGNAL
29
+ #define MSG_NOSIGNAL 0
30
+ #endif
31
+ #endif
32
+
33
+ struct network_write_cookie {
34
+ int (*callback)(void *, ssize_t);
35
+ void * cookie;
36
+ int fd;
37
+ const uint8_t * buf;
38
+ size_t buflen;
39
+ size_t minlen;
40
+ size_t bufpos;
41
+ };
42
+
43
+ /* Invoke the callback, clean up, and return the callback's status. */
44
+ static int
45
+ docallback(struct network_write_cookie * C, ssize_t nbytes)
46
+ {
47
+ int rc;
48
+
49
+ /* Invoke the callback. */
50
+ rc = (C->callback)(C->cookie, nbytes);
51
+
52
+ /* Clean up. */
53
+ free(C);
54
+
55
+ /* Return the callback's status. */
56
+ return (rc);
57
+ }
58
+
59
+ /* The socket is ready for reading/writing. */
60
+ static int
61
+ callback_buf(void * cookie)
62
+ {
63
+ struct network_write_cookie * C = cookie;
64
+ size_t oplen;
65
+ ssize_t len;
66
+ #ifdef POSIXFAIL_MSG_NOSIGNAL
67
+ void (*oldsig)(int);
68
+ #endif
69
+
70
+ /* If we don't have MSG_NOSIGNAL, catch SIGPIPE. */
71
+ #ifdef POSIXFAIL_MSG_NOSIGNAL
72
+ if ((oldsig = signal(SIGPIPE, SIG_IGN)) == SIG_ERR) {
73
+ warnp("signal(SIGPIPE)");
74
+ goto failed;
75
+ }
76
+ #endif
77
+
78
+ /* Attempt to read/write data to/from the buffer. */
79
+ oplen = C->buflen - C->bufpos;
80
+ len = send(C->fd, C->buf + C->bufpos, oplen, MSG_NOSIGNAL);
81
+
82
+ /* We should never see a send length of zero. */
83
+ assert(len != 0);
84
+
85
+ /* If we set a SIGPIPE handler, restore the old one. */
86
+ #ifdef POSIXFAIL_MSG_NOSIGNAL
87
+ if (signal(SIGPIPE, oldsig) == SIG_ERR) {
88
+ warnp("signal(SIGPIPE)");
89
+ goto failed;
90
+ }
91
+ #endif
92
+
93
+ /* Failure? */
94
+ if (len == -1) {
95
+ /* Was it really an error, or just a try-again? */
96
+ if ((errno == EAGAIN) ||
97
+ (errno == EWOULDBLOCK) ||
98
+ (errno == EINTR))
99
+ goto tryagain;
100
+
101
+ /* Something went wrong. */
102
+ goto failed;
103
+ }
104
+
105
+ /* We processed some data. Do we need to keep going? */
106
+ if ((C->bufpos += len) < C->minlen)
107
+ goto tryagain;
108
+
109
+ /* Invoke the callback and return. */
110
+ return (docallback(C, C->bufpos));
111
+
112
+ tryagain:
113
+ /* Reset the event. */
114
+ if (events_network_register(callback_buf, C, C->fd,
115
+ EVENTS_NETWORK_OP_WRITE))
116
+ goto failed;
117
+
118
+ /* Callback was reset. */
119
+ return (0);
120
+
121
+ failed:
122
+ /* Invoke the callback with a failure status and return. */
123
+ return (docallback(C, -1));
124
+ }
125
+
126
+ /**
127
+ * network_write(fd, buf, buflen, minwrite, callback, cookie):
128
+ * Asynchronously write up to ${buflen} bytes of data from ${buf} to ${fd}.
129
+ * When at least ${minwrite} bytes have been written or on error, invoke
130
+ * ${callback}(${cookie}, lenwrit), where lenwrit is -1 on error and the
131
+ * number of bytes written (between ${minwrite} and ${buflen} inclusive)
132
+ * otherwise. Return a cookie which can be passed to network_write_cancel in
133
+ * order to cancel the write.
134
+ */
135
+ void *
136
+ network_write(int fd, const uint8_t * buf, size_t buflen, size_t minwrite,
137
+ int (* callback)(void *, ssize_t), void * cookie)
138
+ {
139
+ struct network_write_cookie * C;
140
+
141
+ /* Make sure buflen is non-zero. */
142
+ assert(buflen != 0);
143
+
144
+ /* Sanity-check: # bytes must fit into a ssize_t. */
145
+ assert(buflen <= SSIZE_MAX);
146
+
147
+ /* Bake a cookie. */
148
+ if ((C = malloc(sizeof(struct network_write_cookie))) == NULL)
149
+ goto err0;
150
+ C->callback = callback;
151
+ C->cookie = cookie;
152
+ C->fd = fd;
153
+ C->buf = buf;
154
+ C->buflen = buflen;
155
+ C->minlen = minwrite;
156
+ C->bufpos = 0;
157
+
158
+ /* Register a callback for network readiness. */
159
+ if (events_network_register(callback_buf, C, C->fd,
160
+ EVENTS_NETWORK_OP_WRITE))
161
+ goto err1;
162
+
163
+ /* Success! */
164
+ return (C);
165
+
166
+ err1:
167
+ free(C);
168
+ err0:
169
+ /* Failure! */
170
+ return (NULL);
171
+ }
172
+
173
+ /**
174
+ * network_write_cancel(cookie):
175
+ * Cancel the buffer write for which the cookie ${cookie} was returned by
176
+ * network_write. Do not invoke the callback associated with the write.
177
+ */
178
+ void
179
+ network_write_cancel(void * cookie)
180
+ {
181
+ struct network_write_cookie * C = cookie;
182
+
183
+ /* Kill the network event. */
184
+ events_network_cancel(C->fd, EVENTS_NETWORK_OP_WRITE);
185
+
186
+ /* Free the cookie. */
187
+ free(C);
188
+ }
@@ -0,0 +1,49 @@
1
+ #include <stdarg.h>
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+
5
+ #include "asprintf.h"
6
+
7
+ /**
8
+ * asprintf(ret, format, ...):
9
+ * Do asprintf(3) like GNU and BSD do.
10
+ */
11
+ int
12
+ asprintf(char ** ret, const char * format, ...)
13
+ {
14
+ va_list ap;
15
+ int len;
16
+ size_t buflen;
17
+
18
+ /* Figure out how long the string needs to be. */
19
+ va_start(ap, format);
20
+ len = vsnprintf(NULL, 0, format, ap);
21
+ va_end(ap);
22
+
23
+ /* Did we fail? */
24
+ if (len < 0)
25
+ goto err0;
26
+ buflen = (size_t)(len) + 1;
27
+
28
+ /* Allocate memory. */
29
+ if ((*ret = malloc(buflen)) == NULL)
30
+ goto err0;
31
+
32
+ /* Actually generate the string. */
33
+ va_start(ap, format);
34
+ len = vsnprintf(*ret, buflen, format, ap);
35
+ va_end(ap);
36
+
37
+ /* Did we fail? */
38
+ if (len < 0)
39
+ goto err1;
40
+
41
+ /* Success! */
42
+ return (len);
43
+
44
+ err1:
45
+ free(*ret);
46
+ err0:
47
+ /* Failure! */
48
+ return (-1);
49
+ }
@@ -0,0 +1,16 @@
1
+ #ifndef _ASPRINTF_H_
2
+ #define _ASPRINTF_H_
3
+
4
+ /* Avoid namespace collisions with BSD/GNU asprintf. */
5
+ #ifdef asprintf
6
+ #undef asprintf
7
+ #endif
8
+ #define asprintf libcperciva_asprintf
9
+
10
+ /**
11
+ * asprintf(ret, format, ...):
12
+ * Do asprintf(3) like GNU and BSD do.
13
+ */
14
+ int asprintf(char **, const char *, ...);
15
+
16
+ #endif /* !_ASPRINTF_H_ */
@@ -0,0 +1,134 @@
1
+ #include <errno.h>
2
+ #include <stdio.h>
3
+ #include <unistd.h>
4
+
5
+ #include "noeintr.h"
6
+ #include "warnp.h"
7
+
8
+ #include "daemonize.h"
9
+
10
+ /**
11
+ * daemonize(spid):
12
+ * Daemonize and write the process ID in decimal to a file named ${spid}.
13
+ * The parent process will exit only after the child has written its pid.
14
+ * On success, the child will return 0; on failure, the parent will return
15
+ * -1.
16
+ */
17
+ int
18
+ daemonize(const char * spid)
19
+ {
20
+ FILE * f;
21
+ int fd[2];
22
+ char dummy = 0;
23
+
24
+ /*
25
+ * Create a pipe for the child to notify the parent when it has
26
+ * finished daemonizing.
27
+ */
28
+ if (pipe(fd)) {
29
+ warnp("pipe");
30
+ goto err0;
31
+ }
32
+
33
+ /*
34
+ * Fork into the parent process (which waits for a poke and exits)
35
+ * and the child process (which keeps going).
36
+ */
37
+ switch (fork()) {
38
+ case -1:
39
+ /* Fork failed. */
40
+ warnp("fork");
41
+ goto err2;
42
+ case 0:
43
+ /* In child process. */
44
+ break;
45
+ default:
46
+ /*
47
+ * In parent process. Close write end of pipe so that if the
48
+ * client dies we will notice the pipe being reset.
49
+ */
50
+ while (close(fd[1])) {
51
+ if (errno == EINTR)
52
+ continue;
53
+ warnp("close");
54
+ goto err1;
55
+ }
56
+ do {
57
+ switch (read(fd[0], &dummy, 1)) {
58
+ case -1:
59
+ /* Error in read. */
60
+ break;
61
+ case 0:
62
+ /* EOF -- the child died without poking us. */
63
+ goto err1;
64
+ case 1:
65
+ /* We have been poked by the child. Exit. */
66
+ _exit(0);
67
+ }
68
+
69
+ /* Anything other than EINTR is bad. */
70
+ if (errno != EINTR) {
71
+ warnp("read");
72
+ goto err1;
73
+ }
74
+ } while (1);
75
+ }
76
+
77
+ /* Set ourselves to be a session leader. */
78
+ if (setsid() == -1) {
79
+ warnp("setsid");
80
+ goto die;
81
+ }
82
+
83
+ /* Write out our pid file. */
84
+ if ((f = fopen(spid, "w")) == NULL) {
85
+ warnp("fopen(%s)", spid);
86
+ goto die;
87
+ }
88
+ if (fprintf(f, "%d", getpid()) < 0) {
89
+ warnp("fprintf");
90
+ goto die;
91
+ }
92
+ if (fclose(f)) {
93
+ warnp("fclose");
94
+ goto die;
95
+ }
96
+
97
+ /* Tell the parent to suicide. */
98
+ if (noeintr_write(fd[1], &dummy, 1) == -1) {
99
+ warnp("write");
100
+ goto die;
101
+ }
102
+
103
+ /* Close the pipe. */
104
+ while (close(fd[0])) {
105
+ if (errno == EINTR)
106
+ continue;
107
+ warnp("close");
108
+ goto die;
109
+ }
110
+ while (close(fd[1])) {
111
+ if (errno == EINTR)
112
+ continue;
113
+ warnp("close");
114
+ goto die;
115
+ }
116
+
117
+ /* Success! */
118
+ return (0);
119
+
120
+ err2:
121
+ close(fd[1]);
122
+ err1:
123
+ close(fd[0]);
124
+ err0:
125
+ /* Failure! */
126
+ return (-1);
127
+
128
+ die:
129
+ /*
130
+ * We're in the child and something bad happened; the parent will be
131
+ * notified when we die thanks to the pipe being closed.
132
+ */
133
+ _exit(0);
134
+ }
@@ -0,0 +1,10 @@
1
+ #ifndef _DAEMONIZE_H_
2
+ #define _DAEMONIZE_H_
3
+
4
+ /**
5
+ * daemonize(spid):
6
+ * Daemonize and write the process ID in decimal to a file named ${spid}.
7
+ */
8
+ int daemonize(const char *);
9
+
10
+ #endif /* !_DAEMONIZE_H_ */
@@ -0,0 +1,76 @@
1
+ #include <fcntl.h>
2
+ #include <limits.h>
3
+ #include <stdint.h>
4
+ #include <unistd.h>
5
+
6
+ #include "warnp.h"
7
+
8
+ #include "entropy.h"
9
+
10
+ /**
11
+ * XXX Portability
12
+ * XXX We obtain random bytes from the operating system by opening
13
+ * XXX /dev/urandom and reading them from that device; this works on
14
+ * XXX modern UNIX-like operating systems but not on systems like
15
+ * XXX win32 where there is no concept of /dev/urandom.
16
+ */
17
+
18
+ /**
19
+ * entropy_read(buf, buflen):
20
+ * Fill the given buffer with random bytes provided by the operating system.
21
+ */
22
+ int
23
+ entropy_read(uint8_t * buf, size_t buflen)
24
+ {
25
+ int fd;
26
+ ssize_t lenread;
27
+
28
+ /* Sanity-check the buffer size. */
29
+ if (buflen > SSIZE_MAX) {
30
+ warn0("Programmer error: "
31
+ "Trying to read insane amount of random data: %zu",
32
+ buflen);
33
+ goto err0;
34
+ }
35
+
36
+ /* Open /dev/urandom. */
37
+ if ((fd = open("/dev/urandom", O_RDONLY)) == -1) {
38
+ warnp("open(/dev/urandom)");
39
+ goto err0;
40
+ }
41
+
42
+ /* Read bytes until we have filled the buffer. */
43
+ while (buflen > 0) {
44
+ if ((lenread = read(fd, buf, buflen)) == -1) {
45
+ warnp("read(/dev/urandom)");
46
+ goto err1;
47
+ }
48
+
49
+ /* The random device should never EOF. */
50
+ if (lenread == 0) {
51
+ warn0("EOF on /dev/urandom?");
52
+ goto err1;
53
+ }
54
+
55
+ /* We've filled a portion of the buffer. */
56
+ buf += lenread;
57
+ buflen -= lenread;
58
+ }
59
+
60
+ /* Close the device. */
61
+ while (close(fd) == -1) {
62
+ if (errno != EINTR) {
63
+ warnp("close(/dev/urandom)");
64
+ goto err0;
65
+ }
66
+ }
67
+
68
+ /* Success! */
69
+ return (0);
70
+
71
+ err1:
72
+ close(fd);
73
+ err0:
74
+ /* Failure! */
75
+ return (-1);
76
+ }