r18426: use 'family' consistantly instead of mixing 'domain' and 'family'
[Samba.git] / source / lib / socket_wrapper / socket_wrapper.c
blob65e7a8defdfeec23792a31e670b58a3d0264d638
1 /*
2 Socket wrapper library. Passes all socket communication over
3 unix domain sockets if the environment variable SOCKET_WRAPPER_DIR
4 is set.
5 Copyright (C) Jelmer Vernooij 2005
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #ifdef _SAMBA_BUILD_
23 #include "includes.h"
24 #undef SOCKET_WRAPPER
25 #include "system/network.h"
26 #include "system/filesys.h"
27 #else
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/socket.h>
31 #include <errno.h>
32 #include <sys/un.h>
33 #include <netinet/in.h>
34 #include <netinet/tcp.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <stdio.h>
39 #endif
40 #include "lib/util/dlinklist.h"
42 /* LD_PRELOAD doesn't work yet, so REWRITE_CALLS is all we support
43 * for now */
44 #define REWRITE_CALLS
46 #ifdef REWRITE_CALLS
47 #define real_accept accept
48 #define real_connect connect
49 #define real_bind bind
50 #define real_getpeername getpeername
51 #define real_getsockname getsockname
52 #define real_getsockopt getsockopt
53 #define real_setsockopt setsockopt
54 #define real_recvfrom recvfrom
55 #define real_sendto sendto
56 #define real_recv recv
57 #define real_send send
58 #define real_socket socket
59 #define real_close close
60 #endif
62 /* we need to use a very terse format here as IRIX 6.4 silently
63 truncates names to 16 chars, so if we use a longer name then we
64 can't tell which port a packet came from with recvfrom()
66 with this format we have 8 chars left for the directory name
68 #define SOCKET_FORMAT "%c%02X%04X"
69 #define SOCKET_TYPE_CHAR_TCP 'T'
70 #define SOCKET_TYPE_CHAR_UDP 'U'
72 static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
74 struct sockaddr *ret = (struct sockaddr *)malloc(len);
75 memcpy(ret, data, len);
76 return ret;
79 struct socket_info
81 int fd;
83 int family;
84 int type;
85 int protocol;
86 int bound;
87 int bcast;
89 char *path;
90 char *tmp_path;
92 struct sockaddr *myname;
93 socklen_t myname_len;
95 struct sockaddr *peername;
96 socklen_t peername_len;
98 struct socket_info *prev, *next;
101 static struct socket_info *sockets = NULL;
104 static const char *socket_wrapper_dir(void)
106 const char *s = getenv("SOCKET_WRAPPER_DIR");
107 if (s == NULL) {
108 return NULL;
110 if (strncmp(s, "./", 2) == 0) {
111 s += 2;
113 return s;
116 static const char *socket_wrapper_dump_dir(void)
118 const char *s = getenv("SOCKET_WRAPPER_DUMP_DIR");
120 if (!socket_wrapper_dir()) {
121 return NULL;
124 if (s == NULL) {
125 return NULL;
127 if (strncmp(s, "./", 2) == 0) {
128 s += 2;
130 return s;
133 static unsigned int socket_wrapper_default_iface(void)
135 const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
136 if (s) {
137 unsigned int iface;
138 if (sscanf(s, "%u", &iface) == 1) {
139 if (iface >= 1 && iface <= 0xFF) {
140 return iface;
145 return 1;/* 127.0.0.1 */
148 static int convert_un_in(const struct sockaddr_un *un, struct sockaddr_in *in, socklen_t *len)
150 unsigned int iface;
151 unsigned int prt;
152 const char *p;
153 char type;
155 if ((*len) < sizeof(struct sockaddr_in)) {
156 return 0;
159 p = strrchr(un->sun_path, '/');
160 if (p) p++; else p = un->sun_path;
162 if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) {
163 errno = EINVAL;
164 return -1;
167 if (type != SOCKET_TYPE_CHAR_TCP && type != SOCKET_TYPE_CHAR_UDP) {
168 errno = EINVAL;
169 return -1;
172 if (iface == 0 || iface > 0xFF) {
173 errno = EINVAL;
174 return -1;
177 if (prt > 0xFFFF) {
178 errno = EINVAL;
179 return -1;
182 in->sin_family = AF_INET;
183 in->sin_addr.s_addr = htonl((127<<24) | iface);
184 in->sin_port = htons(prt);
186 *len = sizeof(struct sockaddr_in);
187 return 0;
190 static int convert_in_un_remote(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un,
191 int *bcast)
193 char u_type = '\0';
194 char b_type = '\0';
195 char a_type = '\0';
196 char type = '\0';
197 unsigned int addr= ntohl(in->sin_addr.s_addr);
198 unsigned int prt = ntohs(in->sin_port);
199 unsigned int iface;
200 int is_bcast = 0;
202 if (bcast) *bcast = 0;
204 if (prt == 0) {
205 errno = EINVAL;
206 return -1;
209 switch (si->type) {
210 case SOCK_STREAM:
211 u_type = SOCKET_TYPE_CHAR_TCP;
212 break;
213 case SOCK_DGRAM:
214 u_type = SOCKET_TYPE_CHAR_UDP;
215 a_type = SOCKET_TYPE_CHAR_UDP;
216 b_type = SOCKET_TYPE_CHAR_UDP;
217 break;
220 if (a_type && addr == 0xFFFFFFFF) {
221 /* 255.255.255.255 only udp */
222 is_bcast = 2;
223 type = a_type;
224 iface = socket_wrapper_default_iface();
225 } else if (b_type && addr == 0x7FFFFFFF) {
226 /* 127.255.255.255 only udp */
227 is_bcast = 1;
228 type = b_type;
229 iface = socket_wrapper_default_iface();
230 } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
231 /* 127.0.0.X */
232 is_bcast = 0;
233 type = u_type;
234 iface = (addr & 0x000000FF);
235 } else {
236 errno = ENETUNREACH;
237 return -1;
240 if (bcast) *bcast = is_bcast;
242 if (is_bcast) {
243 snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL",
244 socket_wrapper_dir());
245 /* the caller need to do more processing */
246 return 0;
249 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
250 socket_wrapper_dir(), type, iface, prt);
252 return 0;
255 static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un,
256 int *bcast)
258 char u_type = '\0';
259 char d_type = '\0';
260 char b_type = '\0';
261 char a_type = '\0';
262 char type = '\0';
263 unsigned int addr= ntohl(in->sin_addr.s_addr);
264 unsigned int prt = ntohs(in->sin_port);
265 unsigned int iface;
266 struct stat st;
267 int is_bcast = 0;
269 if (bcast) *bcast = 0;
271 switch (si->type) {
272 case SOCK_STREAM:
273 u_type = SOCKET_TYPE_CHAR_TCP;
274 d_type = SOCKET_TYPE_CHAR_TCP;
275 break;
276 case SOCK_DGRAM:
277 u_type = SOCKET_TYPE_CHAR_UDP;
278 d_type = SOCKET_TYPE_CHAR_UDP;
279 a_type = SOCKET_TYPE_CHAR_UDP;
280 b_type = SOCKET_TYPE_CHAR_UDP;
281 break;
284 if (addr == 0) {
285 /* 0.0.0.0 */
286 is_bcast = 0;
287 type = d_type;
288 iface = socket_wrapper_default_iface();
289 } else if (a_type && addr == 0xFFFFFFFF) {
290 /* 255.255.255.255 only udp */
291 is_bcast = 2;
292 type = a_type;
293 iface = socket_wrapper_default_iface();
294 } else if (b_type && addr == 0x7FFFFFFF) {
295 /* 127.255.255.255 only udp */
296 is_bcast = 1;
297 type = b_type;
298 iface = socket_wrapper_default_iface();
299 } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
300 /* 127.0.0.X */
301 is_bcast = 0;
302 type = u_type;
303 iface = (addr & 0x000000FF);
304 } else {
305 errno = EADDRNOTAVAIL;
306 return -1;
309 if (bcast) *bcast = is_bcast;
311 if (prt == 0) {
312 /* handle auto-allocation of ephemeral ports */
313 for (prt = 5001; prt < 10000; prt++) {
314 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
315 socket_wrapper_dir(), type, iface, prt);
316 if (stat(un->sun_path, &st) == 0) continue;
318 ((struct sockaddr_in *)si->myname)->sin_port = htons(prt);
319 return 0;
321 errno = ENFILE;
322 return -1;
325 snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT,
326 socket_wrapper_dir(), type, iface, prt);
327 return 0;
330 static struct socket_info *find_socket_info(int fd)
332 struct socket_info *i;
333 for (i = sockets; i; i = i->next) {
334 if (i->fd == fd)
335 return i;
338 return NULL;
341 static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len,
342 struct sockaddr_un *out_addr, int alloc_sock, int *bcast)
344 if (!out_addr)
345 return 0;
347 out_addr->sun_family = AF_UNIX;
349 switch (in_addr->sa_family) {
350 case AF_INET:
351 switch (si->type) {
352 case SOCK_STREAM:
353 case SOCK_DGRAM:
354 break;
355 default:
356 errno = ESOCKTNOSUPPORT;
357 return -1;
359 if (alloc_sock) {
360 return convert_in_un_alloc(si, (const struct sockaddr_in *)in_addr, out_addr, bcast);
361 } else {
362 return convert_in_un_remote(si, (const struct sockaddr_in *)in_addr, out_addr, bcast);
364 default:
365 break;
368 errno = EAFNOSUPPORT;
369 return -1;
372 static int sockaddr_convert_from_un(const struct socket_info *si,
373 const struct sockaddr_un *in_addr,
374 socklen_t un_addrlen,
375 int family,
376 struct sockaddr *out_addr,
377 socklen_t *_out_addrlen)
379 socklen_t out_addrlen;
381 if (out_addr == NULL || _out_addrlen == NULL)
382 return 0;
384 if (un_addrlen == 0) {
385 *_out_addrlen = 0;
386 return 0;
389 out_addrlen = *_out_addrlen;
390 if (out_addrlen > un_addrlen) {
391 out_addrlen = un_addrlen;
394 switch (family) {
395 case AF_INET:
396 switch (si->type) {
397 case SOCK_STREAM:
398 case SOCK_DGRAM:
399 break;
400 default:
401 errno = ESOCKTNOSUPPORT;
402 return -1;
404 return convert_un_in(in_addr, (struct sockaddr_in *)out_addr, _out_addrlen);
405 default:
406 break;
409 errno = EAFNOSUPPORT;
410 return -1;
413 enum swrap_packet_type {
414 SWRAP_CONNECT,
415 SWRAP_ACCEPT,
416 SWRAP_RECVFROM,
417 SWRAP_SENDTO,
418 SWRAP_RECV,
419 SWRAP_SEND,
420 SWRAP_CLOSE
423 static void swrap_dump_packet(struct socket_info *si, const struct sockaddr *addr,
424 enum swrap_packet_type type,
425 const void *buf, size_t len, ssize_t ret)
427 if (!socket_wrapper_dump_dir()) {
428 return;
433 _PUBLIC_ int swrap_socket(int family, int type, int protocol)
435 struct socket_info *si;
436 int fd;
438 if (!socket_wrapper_dir()) {
439 return real_socket(family, type, protocol);
442 switch (family) {
443 case AF_INET:
444 break;
445 case AF_UNIX:
446 return real_socket(family, type, protocol);
447 default:
448 errno = EAFNOSUPPORT;
449 return -1;
452 fd = real_socket(AF_UNIX, type, 0);
454 if (fd == -1) return -1;
456 si = calloc(1, sizeof(struct socket_info));
458 si->family = family;
459 si->type = type;
460 si->protocol = protocol;
461 si->fd = fd;
463 DLIST_ADD(sockets, si);
465 return si->fd;
468 _PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
470 struct socket_info *parent_si, *child_si;
471 int fd;
472 struct sockaddr_un un_addr;
473 socklen_t un_addrlen = sizeof(un_addr);
474 struct sockaddr_un un_my_addr;
475 socklen_t un_my_addrlen = sizeof(un_my_addr);
476 struct sockaddr my_addr;
477 socklen_t my_addrlen = sizeof(my_addr);
478 int ret;
480 parent_si = find_socket_info(s);
481 if (!parent_si) {
482 return real_accept(s, addr, addrlen);
485 memset(&un_addr, 0, sizeof(un_addr));
486 memset(&un_my_addr, 0, sizeof(un_my_addr));
487 memset(&my_addr, 0, sizeof(my_addr));
489 ret = real_accept(s, (struct sockaddr *)&un_addr, &un_addrlen);
490 if (ret == -1) return ret;
492 fd = ret;
494 ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen,
495 parent_si->family, addr, addrlen);
496 if (ret == -1) return ret;
498 child_si = malloc(sizeof(struct socket_info));
499 memset(child_si, 0, sizeof(*child_si));
501 child_si->fd = fd;
502 child_si->family = parent_si->family;
503 child_si->type = parent_si->type;
504 child_si->protocol = parent_si->protocol;
505 child_si->bound = 1;
507 ret = real_getsockname(fd, (struct sockaddr *)&un_my_addr, &un_my_addrlen);
508 if (ret == -1) return ret;
510 ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen,
511 child_si->family, &my_addr, &my_addrlen);
512 if (ret == -1) return ret;
514 child_si->myname_len = my_addrlen;
515 child_si->myname = sockaddr_dup(&my_addr, my_addrlen);
517 child_si->peername_len = *addrlen;
518 child_si->peername = sockaddr_dup(addr, *addrlen);
520 DLIST_ADD(sockets, child_si);
522 swrap_dump_packet(child_si, addr, SWRAP_ACCEPT, NULL, 0, 0);
524 return fd;
527 /* using sendto() or connect() on an unbound socket would give the
528 recipient no way to reply, as unlike UDP and TCP, a unix domain
529 socket can't auto-assign emphemeral port numbers, so we need to
530 assign it here */
531 static int swrap_auto_bind(struct socket_info *si)
533 struct sockaddr_un un_addr;
534 struct sockaddr_in in;
535 int i;
536 char type;
537 int ret;
538 struct stat st;
540 un_addr.sun_family = AF_UNIX;
542 switch (si->type) {
543 case SOCK_STREAM:
544 type = SOCKET_TYPE_CHAR_TCP;
545 break;
546 case SOCK_DGRAM:
547 type = SOCKET_TYPE_CHAR_UDP;
548 break;
549 default:
550 errno = ESOCKTNOSUPPORT;
551 return -1;
554 for (i=0;i<1000;i++) {
555 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path),
556 "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
557 type, socket_wrapper_default_iface(), i + 10000);
558 if (stat(un_addr.sun_path, &st) == 0) continue;
560 ret = real_bind(si->fd, (struct sockaddr *)&un_addr, sizeof(un_addr));
561 if (ret == -1) return ret;
563 si->tmp_path = strdup(un_addr.sun_path);
564 si->bound = 1;
565 break;
567 if (i == 1000) {
568 errno = ENFILE;
569 return -1;
572 memset(&in, 0, sizeof(in));
573 in.sin_family = AF_INET;
574 in.sin_port = htons(i);
575 in.sin_addr.s_addr = htonl(127<<24 | socket_wrapper_default_iface());
577 si->myname_len = sizeof(in);
578 si->myname = sockaddr_dup(&in, si->myname_len);
579 si->bound = 1;
580 return 0;
584 _PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
586 int ret;
587 struct sockaddr_un un_addr;
588 struct socket_info *si = find_socket_info(s);
590 if (!si) {
591 return real_connect(s, serv_addr, addrlen);
594 if (si->bound == 0) {
595 ret = swrap_auto_bind(si);
596 if (ret == -1) return -1;
599 ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr, 0, NULL);
600 if (ret == -1) return -1;
602 ret = real_connect(s, (struct sockaddr *)&un_addr,
603 sizeof(struct sockaddr_un));
605 /* to give better errors */
606 if (ret == -1 && errno == ENOENT) {
607 errno = EHOSTUNREACH;
610 if (ret == 0) {
611 si->peername_len = addrlen;
612 si->peername = sockaddr_dup(serv_addr, addrlen);
615 swrap_dump_packet(si, serv_addr, SWRAP_CONNECT, NULL, 0, ret);
617 return ret;
620 _PUBLIC_ int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
622 int ret;
623 struct sockaddr_un un_addr;
624 struct socket_info *si = find_socket_info(s);
626 if (!si) {
627 return real_bind(s, myaddr, addrlen);
630 si->myname_len = addrlen;
631 si->myname = sockaddr_dup(myaddr, addrlen);
633 ret = sockaddr_convert_to_un(si, (const struct sockaddr *)myaddr, addrlen, &un_addr, 1, &si->bcast);
634 if (ret == -1) return -1;
636 unlink(un_addr.sun_path);
638 ret = real_bind(s, (struct sockaddr *)&un_addr,
639 sizeof(struct sockaddr_un));
641 if (ret == 0) {
642 si->bound = 1;
645 return ret;
648 _PUBLIC_ int swrap_getpeername(int s, struct sockaddr *name, socklen_t *addrlen)
650 struct socket_info *si = find_socket_info(s);
652 if (!si) {
653 return real_getpeername(s, name, addrlen);
656 if (!si->peername)
658 errno = ENOTCONN;
659 return -1;
662 memcpy(name, si->peername, si->peername_len);
663 *addrlen = si->peername_len;
665 return 0;
668 _PUBLIC_ int swrap_getsockname(int s, struct sockaddr *name, socklen_t *addrlen)
670 struct socket_info *si = find_socket_info(s);
672 if (!si) {
673 return real_getsockname(s, name, addrlen);
676 memcpy(name, si->myname, si->myname_len);
677 *addrlen = si->myname_len;
679 return 0;
682 _PUBLIC_ int swrap_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
684 struct socket_info *si = find_socket_info(s);
686 if (!si) {
687 return real_getsockopt(s, level, optname, optval, optlen);
690 if (level == SOL_SOCKET) {
691 return real_getsockopt(s, level, optname, optval, optlen);
694 errno = ENOPROTOOPT;
695 return -1;
698 _PUBLIC_ int swrap_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
700 struct socket_info *si = find_socket_info(s);
702 if (!si) {
703 return real_setsockopt(s, level, optname, optval, optlen);
706 if (level == SOL_SOCKET) {
707 return real_setsockopt(s, level, optname, optval, optlen);
710 switch (si->family) {
711 case AF_INET:
712 return 0;
713 default:
714 errno = ENOPROTOOPT;
715 return -1;
719 _PUBLIC_ ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
721 struct sockaddr_un un_addr;
722 socklen_t un_addrlen = sizeof(un_addr);
723 int ret;
724 struct socket_info *si = find_socket_info(s);
726 if (!si) {
727 return real_recvfrom(s, buf, len, flags, from, fromlen);
730 /* irix 6.4 forgets to null terminate the sun_path string :-( */
731 memset(&un_addr, 0, sizeof(un_addr));
732 ret = real_recvfrom(s, buf, len, flags, (struct sockaddr *)&un_addr, &un_addrlen);
733 if (ret == -1)
734 return ret;
736 if (sockaddr_convert_from_un(si, &un_addr, un_addrlen,
737 si->family, from, fromlen) == -1) {
738 return -1;
741 swrap_dump_packet(si, from, SWRAP_RECVFROM, buf, len, ret);
743 return ret;
747 _PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
749 struct sockaddr_un un_addr;
750 int ret;
751 struct socket_info *si = find_socket_info(s);
752 int bcast = 0;
754 if (!si) {
755 return real_sendto(s, buf, len, flags, to, tolen);
758 if (si->bound == 0) {
759 ret = swrap_auto_bind(si);
760 if (ret == -1) return -1;
763 ret = sockaddr_convert_to_un(si, to, tolen, &un_addr, 0, &bcast);
764 if (ret == -1) return -1;
766 if (bcast) {
767 struct stat st;
768 unsigned int iface;
769 unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
770 char type;
772 type = SOCKET_TYPE_CHAR_UDP;
774 for(iface=0; iface <= 0xFF; iface++) {
775 snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT,
776 socket_wrapper_dir(), type, iface, prt);
777 if (stat(un_addr.sun_path, &st) != 0) continue;
779 /* ignore the any errors in broadcast sends */
780 real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
783 swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len, len);
785 return len;
788 ret = real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
790 /* to give better errors */
791 if (ret == -1 && errno == ENOENT) {
792 errno = EHOSTUNREACH;
795 swrap_dump_packet(si, to, SWRAP_SENDTO, buf, len, ret);
797 return ret;
800 _PUBLIC_ ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
802 int ret;
803 struct socket_info *si = find_socket_info(s);
805 if (!si) {
806 return real_recv(s, buf, len, flags);
809 ret = real_recv(s, buf, len, flags);
810 if (ret == -1)
811 return ret;
813 swrap_dump_packet(si, NULL, SWRAP_RECV, buf, len, ret);
815 return ret;
819 _PUBLIC_ ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
821 int ret;
822 struct socket_info *si = find_socket_info(s);
824 if (!si) {
825 return real_send(s, buf, len, flags);
828 ret = real_send(s, buf, len, flags);
829 if (ret == -1)
830 return ret;
832 swrap_dump_packet(si, NULL, SWRAP_SEND, buf, len, ret);
834 return ret;
837 _PUBLIC_ int swrap_close(int fd)
839 struct socket_info *si = find_socket_info(fd);
841 if (si) {
842 DLIST_REMOVE(sockets, si);
844 swrap_dump_packet(si, NULL, SWRAP_CLOSE, NULL, 0, 0);
846 free(si->path);
847 free(si->myname);
848 free(si->peername);
849 if (si->tmp_path) {
850 unlink(si->tmp_path);
851 free(si->tmp_path);
853 free(si);
856 return real_close(fd);