]>
git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/mDNSUNP.c
1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
25 #include <sys/ioctl.h>
30 /* Some weird platforms derived from 4.4BSD Lite (e.g. EFI) need the ALIGN(P)
31 macro, usually defined in <sys/param.h> or someplace like that, to make sure the
32 CMSG_NXTHDR macro is well-formed. On such platforms, the symbol NEED_ALIGN_MACRO
33 should be set to the name of the header to include to get the ALIGN(P) macro.
35 #ifdef NEED_ALIGN_MACRO
36 #include NEED_ALIGN_MACRO
39 /* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
40 other platforms don't even have that include file. So,
41 if we haven't yet got a definition, let's try to find
46 #include <sys/sockio.h>
49 /* sockaddr_dl is only referenced if we're using IP_RECVIF,
50 so only include the header in that case.
54 #include <net/if_dl.h>
57 #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
58 #include <net/if_var.h>
59 #include <netinet/in_var.h>
60 // Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
63 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
65 #include <arpa/inet.h>
67 /* Converts a prefix length to IPv6 network mask */
68 void plen_to_mask(int plen
, char *addr
) {
70 int colons
=7; /* Number of colons in IPv6 address */
71 int bits_in_block
=16; /* Bits per IPv6 block */
72 for(i
=0; i
<=colons
; i
++) {
73 int block
, ones
=0xffff, ones_in_block
;
74 if (plen
>bits_in_block
) ones_in_block
=bits_in_block
;
75 else ones_in_block
=plen
;
76 block
= ones
& (ones
<< (bits_in_block
-ones_in_block
));
77 i
==0 ? sprintf(addr
, "%x", block
) : sprintf(addr
, "%s:%x", addr
, block
);
78 plen
-= ones_in_block
;
82 /* Gets IPv6 interface information from the /proc filesystem in linux*/
83 struct ifi_info
*get_ifi_info_linuxv6(int doaliases
)
85 struct ifi_info
*ifi
, *ifihead
, **ifipnext
, *ifipold
, **ifiptr
;
87 int i
, nitems
, flags
, index
, plen
, scope
;
88 struct addrinfo hints
, *res0
;
92 char ifnameFmt
[16], addrStr
[32 + 7 + 1], ifname
[IFNAMSIZ
], lastname
[IFNAMSIZ
];
98 if ((fp
= fopen(PROC_IFINET6_PATH
, "r")) != NULL
) {
99 sockfd
= socket(AF_INET6
, SOCK_DGRAM
, 0);
104 // Parse /proc/net/if_inet6 according to <https://www.tldp.org/HOWTO/Linux+IPv6-HOWTO/ch11s04.html>.
106 // Create a string specifier with a width of IFNAMSIZ - 1 ("%<IFNAMSIZ - 1>s") to scan the interface name. The
107 // reason why we don't just use the string-ified macro expansion of IFNAMSIZ for the width is because the width
108 // needs to be a decimal string and there's no guarantee that IFNAMSIZ will be defined as a decimal integer. For
109 // example, it could be defined in hexadecimal or as an arithmetic expression.
111 snprintf(ifnameFmt
, sizeof(ifnameFmt
), "%%%ds", IFNAMSIZ
- 1);
113 // Write the seven IPv6 address string colons and NUL terminator, i.e., "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx".
114 // The remaining 32 IPv6 address characters come from /proc/net/if_inet6.
116 for (i
= 4; i
< 39; i
+= 5) addrStr
[i
] = ':';
121 nitems
= fscanf(fp
, " %4c%4c%4c%4c%4c%4c%4c%4c %x %x %x %x",
122 &addrStr
[0], &addrStr
[5], &addrStr
[10], &addrStr
[15],
123 &addrStr
[20], &addrStr
[25], &addrStr
[30], &addrStr
[35],
124 &index
, &plen
, &scope
, &flags
);
125 if (nitems
!= 12) break;
127 nitems
= fscanf(fp
, ifnameFmt
, ifname
);
128 if (nitems
!= 1) break;
130 if (strcmp(lastname
, ifname
) == 0) {
132 continue; /* already processed this interface */
134 memcpy(lastname
, ifname
, IFNAMSIZ
);
135 ifi
= (struct ifi_info
*)calloc(1, sizeof(struct ifi_info
));
140 ifipold
= *ifipnext
; /* need this later */
142 *ifipnext
= ifi
; /* prev points to this new one */
143 ifipnext
= &ifi
->ifi_next
; /* pointer to next one goes here */
145 /* Add address of the interface */
146 memset(&hints
, 0, sizeof(hints
));
147 hints
.ai_family
= AF_INET6
;
148 hints
.ai_flags
= AI_NUMERICHOST
;
149 err
= getaddrinfo(addrStr
, NULL
, &hints
, &res0
);
153 ifi
->ifi_addr
= calloc(1, sizeof(struct sockaddr_in6
));
154 if (ifi
->ifi_addr
== NULL
) {
157 memcpy(ifi
->ifi_addr
, res0
->ai_addr
, sizeof(struct sockaddr_in6
));
159 /* Add netmask of the interface */
160 char ipv6addr
[INET6_ADDRSTRLEN
];
161 plen_to_mask(plen
, ipv6addr
);
162 ifi
->ifi_netmask
= calloc(1, sizeof(struct sockaddr_in6
));
163 if (ifi
->ifi_netmask
== NULL
) {
167 ((struct sockaddr_in6
*)ifi
->ifi_netmask
)->sin6_family
=AF_INET6
;
168 ((struct sockaddr_in6
*)ifi
->ifi_netmask
)->sin6_scope_id
=scope
;
169 inet_pton(AF_INET6
, ipv6addr
, &((struct sockaddr_in6
*)ifi
->ifi_netmask
)->sin6_addr
);
171 /* Add interface name */
172 memcpy(ifi
->ifi_name
, ifname
, IFI_NAME
);
174 /* Add interface index */
175 ifi
->ifi_index
= index
;
177 /* Add interface flags*/
178 memcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
179 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
180 if (errno
== EADDRNOTAVAIL
) {
182 * If the main interface is configured with no IP address but
183 * an alias interface exists with an IP address, you get
184 * EADDRNOTAVAIL for the main interface
187 free(ifi
->ifi_netmask
);
196 ifi
->ifi_flags
= ifr
.ifr_flags
;
204 if (ifihead
!= NULL
) {
205 free_ifi_info(ifihead
);
221 return(ifihead
); /* pointer to first structure in linked list */
223 #endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
225 struct ifi_info
*get_ifi_info(int family
, int doaliases
)
228 struct ifi_info
*ifi
, *ifihead
, **ifipnext
, *ifipold
, **ifiptr
;
229 int sockfd
, sockf6
, len
, lastlen
, flags
, myflags
;
230 #ifdef NOT_HAVE_IF_NAMETOINDEX
233 char *ptr
, *buf
, lastname
[IFNAMSIZ
], *cptr
;
235 struct ifreq
*ifr
, ifrcopy
;
236 struct sockaddr_in
*sinptr
;
238 #if defined(AF_INET6) && HAVE_IPV6
239 struct sockaddr_in6
*sinptr6
;
242 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
243 if (family
== AF_INET6
) return get_ifi_info_linuxv6(doaliases
);
251 sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
257 len
= 100 * sizeof(struct ifreq
); /* initial buffer size guess */
259 buf
= (char*)malloc(len
);
265 if (ioctl(sockfd
, SIOCGIFCONF
, &ifc
) < 0) {
266 if (errno
!= EINVAL
|| lastlen
!= 0) {
270 if (ifc
.ifc_len
== lastlen
)
271 break; /* success, len has not changed */
272 lastlen
= ifc
.ifc_len
;
274 len
+= 10 * sizeof(struct ifreq
); /* increment */
280 /* end get_ifi_info1 */
282 /* include get_ifi_info2 */
283 for (ptr
= buf
; ptr
< buf
+ ifc
.ifc_len
; ) {
284 ifr
= (struct ifreq
*) ptr
;
286 /* Advance to next one in buffer */
287 if (sizeof(struct ifreq
) > sizeof(ifr
->ifr_name
) + GET_SA_LEN(ifr
->ifr_addr
))
288 ptr
+= sizeof(struct ifreq
);
290 ptr
+= sizeof(ifr
->ifr_name
) + GET_SA_LEN(ifr
->ifr_addr
);
292 // fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
294 if (ifr
->ifr_addr
.sa_family
!= family
)
295 continue; /* ignore if not desired address family */
298 if ( (cptr
= strchr(ifr
->ifr_name
, ':')) != NULL
)
299 *cptr
= 0; /* replace colon will null */
300 if (strncmp(lastname
, ifr
->ifr_name
, IFNAMSIZ
) == 0) {
302 continue; /* already processed this interface */
305 memcpy(lastname
, ifr
->ifr_name
, IFNAMSIZ
);
308 if (ioctl(sockfd
, SIOCGIFFLAGS
, &ifrcopy
) < 0) {
312 flags
= ifrcopy
.ifr_flags
;
313 if ((flags
& IFF_UP
) == 0)
314 continue; /* ignore if interface not up */
316 ifi
= (struct ifi_info
*)calloc(1, sizeof(struct ifi_info
));
320 ifipold
= *ifipnext
; /* need this later */
322 *ifipnext
= ifi
; /* prev points to this new one */
323 ifipnext
= &ifi
->ifi_next
; /* pointer to next one goes here */
325 ifi
->ifi_flags
= flags
; /* IFF_xxx values */
326 ifi
->ifi_myflags
= myflags
; /* IFI_xxx values */
327 #ifndef NOT_HAVE_IF_NAMETOINDEX
328 ifi
->ifi_index
= if_nametoindex(ifr
->ifr_name
);
332 if ( 0 >= ioctl(sockfd
, SIOCGIFINDEX
, &ifrcopy
))
333 ifi
->ifi_index
= ifrcopy
.ifr_index
;
336 ifi
->ifi_index
= index
++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
338 memcpy(ifi
->ifi_name
, ifr
->ifr_name
, IFI_NAME
);
339 ifi
->ifi_name
[IFI_NAME
-1] = '\0';
340 /* end get_ifi_info2 */
341 /* include get_ifi_info3 */
342 switch (ifr
->ifr_addr
.sa_family
) {
344 sinptr
= (struct sockaddr_in
*) &ifr
->ifr_addr
;
345 if (ifi
->ifi_addr
== NULL
) {
346 ifi
->ifi_addr
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in
));
347 if (ifi
->ifi_addr
== NULL
) {
350 memcpy(ifi
->ifi_addr
, sinptr
, sizeof(struct sockaddr_in
));
352 #ifdef SIOCGIFNETMASK
353 if (ioctl(sockfd
, SIOCGIFNETMASK
, &ifrcopy
) < 0) {
354 if (errno
== EADDRNOTAVAIL
) {
356 * If the main interface is configured with no IP address but
357 * an alias interface exists with an IP address, you get
358 * EADDRNOTAVAIL for the main interface
370 ifi
->ifi_netmask
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in
));
371 if (ifi
->ifi_netmask
== NULL
) goto gotError
;
372 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_addr
;
373 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
374 #ifndef NOT_HAVE_SA_LEN
375 sinptr
->sin_len
= sizeof(struct sockaddr_in
);
377 sinptr
->sin_family
= AF_INET
;
378 memcpy(ifi
->ifi_netmask
, sinptr
, sizeof(struct sockaddr_in
));
381 #ifdef SIOCGIFBRDADDR
382 if (flags
& IFF_BROADCAST
) {
383 if (ioctl(sockfd
, SIOCGIFBRDADDR
, &ifrcopy
) < 0) {
386 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_broadaddr
;
387 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
388 #ifndef NOT_HAVE_SA_LEN
389 sinptr
->sin_len
= sizeof( struct sockaddr_in
);
391 sinptr
->sin_family
= AF_INET
;
392 ifi
->ifi_brdaddr
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in
));
393 if (ifi
->ifi_brdaddr
== NULL
) {
396 memcpy(ifi
->ifi_brdaddr
, sinptr
, sizeof(struct sockaddr_in
));
400 #ifdef SIOCGIFDSTADDR
401 if (flags
& IFF_POINTOPOINT
) {
402 if (ioctl(sockfd
, SIOCGIFDSTADDR
, &ifrcopy
) < 0) {
405 sinptr
= (struct sockaddr_in
*) &ifrcopy
.ifr_dstaddr
;
406 /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
407 #ifndef NOT_HAVE_SA_LEN
408 sinptr
->sin_len
= sizeof( struct sockaddr_in
);
410 sinptr
->sin_family
= AF_INET
;
411 ifi
->ifi_dstaddr
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in
));
412 if (ifi
->ifi_dstaddr
== NULL
) {
415 memcpy(ifi
->ifi_dstaddr
, sinptr
, sizeof(struct sockaddr_in
));
421 #if defined(AF_INET6) && HAVE_IPV6
423 sinptr6
= (struct sockaddr_in6
*) &ifr
->ifr_addr
;
424 if (ifi
->ifi_addr
== NULL
) {
425 ifi
->ifi_addr
= calloc(1, sizeof(struct sockaddr_in6
));
426 if (ifi
->ifi_addr
== NULL
) {
430 /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
431 /* We need to strip that out */
432 if (IN6_IS_ADDR_LINKLOCAL(&sinptr6
->sin6_addr
))
433 sinptr6
->sin6_addr
.s6_addr
[2] = sinptr6
->sin6_addr
.s6_addr
[3] = 0;
434 memcpy(ifi
->ifi_addr
, sinptr6
, sizeof(struct sockaddr_in6
));
436 #ifdef SIOCGIFNETMASK_IN6
438 struct in6_ifreq ifr6
;
440 sockf6
= socket(AF_INET6
, SOCK_DGRAM
, 0);
441 memset(&ifr6
, 0, sizeof(ifr6
));
442 memcpy(&ifr6
.ifr_name
, &ifr
->ifr_name
, sizeof(ifr6
.ifr_name
));
443 memcpy(&ifr6
.ifr_ifru
.ifru_addr
, &ifr
->ifr_addr
, sizeof(ifr6
.ifr_ifru
.ifru_addr
));
444 if (ioctl(sockf6
, SIOCGIFNETMASK_IN6
, &ifr6
) < 0) {
445 if (errno
== EADDRNOTAVAIL
) {
447 * If the main interface is configured with no IP address but
448 * an alias interface exists with an IP address, you get
449 * EADDRNOTAVAIL for the main interface
460 ifi
->ifi_netmask
= (struct sockaddr
*)calloc(1, sizeof(struct sockaddr_in6
));
461 if (ifi
->ifi_netmask
== NULL
) goto gotError
;
462 sinptr6
= (struct sockaddr_in6
*) &ifr6
.ifr_ifru
.ifru_addr
;
463 memcpy(ifi
->ifi_netmask
, sinptr6
, sizeof(struct sockaddr_in6
));
477 if (ifihead
!= NULL
) {
478 free_ifi_info(ifihead
);
487 junk
= close(sockfd
);
491 junk
= close(sockf6
);
494 return(ifihead
); /* pointer to first structure in linked list */
496 /* end get_ifi_info3 */
498 /* include free_ifi_info */
500 free_ifi_info(struct ifi_info
*ifihead
)
502 struct ifi_info
*ifi
, *ifinext
;
504 for (ifi
= ifihead
; ifi
!= NULL
; ifi
= ifinext
) {
505 if (ifi
->ifi_addr
!= NULL
)
507 if (ifi
->ifi_netmask
!= NULL
)
508 free(ifi
->ifi_netmask
);
509 if (ifi
->ifi_brdaddr
!= NULL
)
510 free(ifi
->ifi_brdaddr
);
511 if (ifi
->ifi_dstaddr
!= NULL
)
512 free(ifi
->ifi_dstaddr
);
513 ifinext
= ifi
->ifi_next
; /* can't fetch ifi_next after free() */
514 free(ifi
); /* the ifi_info{} itself */
517 /* end free_ifi_info */
520 recvfrom_flags(int fd
, void *ptr
, size_t nbytes
, int *flagsp
,
521 struct sockaddr
*sa
, socklen_t
*salenptr
, struct my_in_pktinfo
*pktp
, u_char
*ttl
)
528 struct cmsghdr
*cmptr
;
534 *ttl
= 255; // If kernel fails to provide TTL data then assume the TTL was 255 as it should be
536 msg
.msg_control
= control_un
.control
;
537 msg
.msg_controllen
= sizeof(control_un
.control
);
540 memset(&msg
, 0, sizeof(msg
)); /* make certain msg_accrightslen = 0 */
541 #endif /* CMSG_FIRSTHDR */
543 msg
.msg_name
= (char *) sa
;
544 msg
.msg_namelen
= *salenptr
;
545 iov
[0].iov_base
= (char *)ptr
;
546 iov
[0].iov_len
= nbytes
;
550 if ( (n
= recvmsg(fd
, &msg
, *flagsp
)) < 0)
553 *salenptr
= msg
.msg_namelen
; /* pass back results */
555 /* 0.0.0.0, i/f = -1 */
556 /* We set the interface to -1 so that the caller can
557 tell whether we returned a meaningful value or
558 just some default. Previously this code just
559 set the value to 0, but I'm concerned that 0
560 might be a valid interface value.
562 memset(pktp
, 0, sizeof(struct my_in_pktinfo
));
563 pktp
->ipi_ifindex
= -1;
565 /* end recvfrom_flags1 */
567 /* include recvfrom_flags2 */
568 #ifndef CMSG_FIRSTHDR
569 #warning CMSG_FIRSTHDR not defined. Will not be able to determine destination address, received interface, etc.
570 *flagsp
= 0; /* pass back results */
574 *flagsp
= msg
.msg_flags
; /* pass back results */
575 if (msg
.msg_controllen
< (socklen_t
)sizeof(struct cmsghdr
) ||
576 (msg
.msg_flags
& MSG_CTRUNC
) || pktp
== NULL
)
579 for (cmptr
= CMSG_FIRSTHDR(&msg
); cmptr
!= NULL
;
580 cmptr
= CMSG_NXTHDR(&msg
, cmptr
)) {
583 #if in_pktinfo_definition_is_missing
587 struct in_addr ipi_spec_dst
;
588 struct in_addr ipi_addr
;
591 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
592 cmptr
->cmsg_type
== IP_PKTINFO
) {
593 struct in_pktinfo
*tmp
;
594 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&pktp
->ipi_addr
;
596 tmp
= (struct in_pktinfo
*) CMSG_DATA(cmptr
);
597 sin
->sin_family
= AF_INET
;
598 sin
->sin_addr
= tmp
->ipi_addr
;
600 pktp
->ipi_ifindex
= tmp
->ipi_ifindex
;
605 #ifdef IP_RECVDSTADDR
606 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
607 cmptr
->cmsg_type
== IP_RECVDSTADDR
) {
608 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&pktp
->ipi_addr
;
610 sin
->sin_family
= AF_INET
;
611 sin
->sin_addr
= *(struct in_addr
*)CMSG_DATA(cmptr
);
618 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
619 cmptr
->cmsg_type
== IP_RECVIF
) {
620 struct sockaddr_dl
*sdl
= (struct sockaddr_dl
*) CMSG_DATA(cmptr
);
621 #ifndef HAVE_BROKEN_RECVIF_NAME
622 int nameLen
= (sdl
->sdl_nlen
< IFI_NAME
- 1) ? sdl
->sdl_nlen
: (IFI_NAME
- 1);
623 strncpy(pktp
->ipi_ifname
, sdl
->sdl_data
, nameLen
);
625 pktp
->ipi_ifindex
= sdl
->sdl_index
;
626 #ifdef HAVE_BROKEN_RECVIF_NAME
627 if (sdl
->sdl_index
== 0) {
628 pktp
->ipi_ifindex
= *(uint_t
*)sdl
;
631 assert(pktp
->ipi_ifname
[IFI_NAME
- 1] == 0);
632 // null terminated because of memset above
638 if (cmptr
->cmsg_level
== IPPROTO_IP
&&
639 cmptr
->cmsg_type
== IP_RECVTTL
) {
640 *ttl
= *(u_char
*)CMSG_DATA(cmptr
);
643 else if (cmptr
->cmsg_level
== IPPROTO_IP
&&
644 cmptr
->cmsg_type
== IP_TTL
) { // some implementations seem to send IP_TTL instead of IP_RECVTTL
645 *ttl
= *(int*)CMSG_DATA(cmptr
);
650 #if defined(IPV6_PKTINFO) && HAVE_IPV6
651 if (cmptr
->cmsg_level
== IPPROTO_IPV6
&&
652 cmptr
->cmsg_type
== IPV6_2292_PKTINFO
) {
653 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&pktp
->ipi_addr
;
654 struct in6_pktinfo
*ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmptr
);
656 sin6
->sin6_family
= AF_INET6
;
657 #ifndef NOT_HAVE_SA_LEN
658 sin6
->sin6_len
= sizeof(*sin6
);
660 sin6
->sin6_addr
= ip6_info
->ipi6_addr
;
661 sin6
->sin6_flowinfo
= 0;
662 sin6
->sin6_scope_id
= 0;
664 pktp
->ipi_ifindex
= ip6_info
->ipi6_ifindex
;
669 #if defined(IPV6_HOPLIMIT) && HAVE_IPV6
670 if (cmptr
->cmsg_level
== IPPROTO_IPV6
&&
671 cmptr
->cmsg_type
== IPV6_2292_HOPLIMIT
) {
672 *ttl
= *(int*)CMSG_DATA(cmptr
);
676 assert(0); // unknown ancillary data
679 #endif /* CMSG_FIRSTHDR */
682 // **********************************************************************************************
684 // daemonize the process. Adapted from "Unix Network Programming" vol 1 by Stevens, section 12.4.
685 // Returns 0 on success, -1 on failure.
687 #ifdef NOT_HAVE_DAEMON
689 #include <sys/stat.h>
690 #include <sys/signal.h>
692 int daemon(int nochdir
, int noclose
)
696 case -1: return (-1); // Fork failed
697 case 0: break; // Child -- continue
698 default: _exit(0); // Parent -- exit
701 if (setsid() == -1) return(-1);
703 signal(SIGHUP
, SIG_IGN
);
705 switch (fork()) // Fork again, primarily for reasons of Unix trivia
707 case -1: return (-1); // Fork failed
708 case 0: break; // Child -- continue
709 default: _exit(0); // Parent -- exit
712 if (!nochdir
) (void)chdir("/");
717 int fd
= open("/dev/null", O_RDWR
, 0);
720 // Avoid unnecessarily duplicating a file descriptor to itself
721 if (fd
!= STDIN_FILENO
) (void)dup2(fd
, STDIN_FILENO
);
722 if (fd
!= STDOUT_FILENO
) (void)dup2(fd
, STDOUT_FILENO
);
723 if (fd
!= STDERR_FILENO
) (void)dup2(fd
, STDERR_FILENO
);
724 if (fd
!= STDIN_FILENO
&& fd
!= STDOUT_FILENO
&& fd
!= STDERR_FILENO
)
730 #endif /* NOT_HAVE_DAEMON */