1 /* this code is protected by the GNU affero GPLv3
2 author:Sylvain BERTRAND <sylvain DOT bertrand AT legeek DOT net>
3 /*----------------------------------------------------------------------------*/
6 /*----------------------------------------------------------------------------*/
8 /*----------------------------------------------------------------------------*/
10 #include <ulinux/compiler_types.h>
11 #include <ulinux/types.h>
12 #include <ulinux/sysc.h>
14 #include <ulinux/file.h>
15 #include <ulinux/socket/socket.h>
17 #include <ulinux/socket/in.h>
19 #include <ulinux/socket/in6.h>
21 #include <ulinux/signal/signal.h>
22 #include <ulinux/error.h>
23 #include <ulinux/epoll.h>
24 #include <ulinux/utils/mem.h>
25 #include <ulinux/utils/endian.h>
26 #include <ulinux/mmap.h>
27 #include <ulinux/time.h>
28 #include <ulinux/select.h>
29 #include <ulinux/stat.h>
31 #include <ulinux/utils/ascii/string/vsprintf.h>
33 #include "ulinux_namespace.h"
34 #include "exit_codes.h"
35 /*----------------------------------------------------------------------------*/
37 /******************************************************************************/
39 /* 32 bits value for the IPv4 address, can be INADDR_ANY */
40 #ifdef CONFIG_LISTENING_IPV4
41 #define LISTENING_IPV4 CONFIG_LISTENING_IPV4
43 #define LISTENING_IPV4 INADDR_ANY
46 static struct ulinux_in6_addr listening_ipv6
;
47 /* 128 bits value for the IPv6 address, is "IN6ADDR_ANY" if all 0 */
48 static void listening_ipv6_init(void)
50 /* yep, at that time, I really did not like initializers */
51 #ifdef CONFIG_LISTENING_IPV6_BYTE_0
52 listening_ipv6
.s6_addr
[0x0] = 0;
54 listening_ipv6
.s6_addr
[0x0] = CONFIG_LISTENING_IPV6_BYTE_0
;
56 #ifdef CONFIG_LISTENING_IPV6_BYTE_1
57 listening_ipv6
.s6_addr
[0x1] = 0;
59 listening_ipv6
.s6_addr
[0x1] = CONFIG_LISTENING_IPV6_BYTE_1
;
61 #ifdef CONFIG_LISTENING_IPV6_BYTE_2
62 listening_ipv6
.s6_addr
[0x2] = 0;
64 listening_ipv6
.s6_addr
[0x2] = CONFIG_LISTENING_IPV6_BYTE_2
;
66 #ifdef CONFIG_LISTENING_IPV6_BYTE_3
67 listening_ipv6
.s6_addr
[0x3] = 0;
69 listening_ipv6
.s6_addr
[0x3] = CONFIG_LISTENING_IPV6_BYTE_3
;
71 #ifdef CONFIG_LISTENING_IPV6_BYTE_4
72 listening_ipv6
.s6_addr
[0x4] = 0;
74 listening_ipv6
.s6_addr
[0x4] = CONFIG_LISTENING_IPV6_BYTE_4
;
76 #ifdef CONFIG_LISTENING_IPV6_BYTE_5
77 listening_ipv6
.s6_addr
[0x5] = 0;
79 listening_ipv6
.s6_addr
[0x5] = CONFIG_LISTENING_IPV6_BYTE_5
;
81 #ifdef CONFIG_LISTENING_IPV6_BYTE_6
82 listening_ipv6
.s6_addr
[0x6] = 0;
84 listening_ipv6
.s6_addr
[0x6] = CONFIG_LISTENING_IPV6_BYTE_6
;
86 #ifdef CONFIG_LISTENING_IPV6_BYTE_7
87 listening_ipv6
.s6_addr
[0x7] = 0;
89 listening_ipv6
.s6_addr
[0x7] = CONFIG_LISTENING_IPV6_BYTE_7
;
91 #ifdef CONFIG_LISTENING_IPV6_BYTE_8
92 listening_ipv6
.s6_addr
[0x8] = 0;
94 listening_ipv6
.s6_addr
[0x8] = CONFIG_LISTENING_IPV6_BYTE_8
;
96 #ifdef CONFIG_LISTENING_IPV6_BYTE_9
97 listening_ipv6
.s6_addr
[0x9] = 0;
99 listening_ipv6
.s6_addr
[0x9] = CONFIG_LISTENING_IPV6_BYTE_9
;
101 #ifdef CONFIG_LISTENING_IPV6_BYTE_A
102 listening_ipv6
.s6_addr
[0xa] = 0;
104 listening_ipv6
.s6_addr
[0xa] = CONFIG_LISTENING_IPV6_BYTE_A
;
106 #ifdef CONFIG_LISTENING_IPV6_BYTE_B
107 listening_ipv6
.s6_addr
[0xb] = 0;
109 listening_ipv6
.s6_addr
[0xb] = CONFIG_LISTENING_IPV6_BYTE_B
;
111 #ifdef CONFIG_LISTENING_IPV6_BYTE_C
112 listening_ipv6
.s6_addr
[0xc] = 0;
114 listening_ipv6
.s6_addr
[0xc] = CONFIG_LISTENING_IPV6_BYTE_C
;
116 #ifdef CONFIG_LISTENING_IPV6_BYTE_D
117 listening_ipv6
.s6_addr
[0xd] = 0;
119 listening_ipv6
.s6_addr
[0xd] = CONFIG_LISTENING_IPV6_BYTE_D
;
121 #ifdef CONFIG_LISTENING_IPV6_BYTE_E
122 listening_ipv6
.s6_addr
[0xe] = 0;
124 listening_ipv6
.s6_addr
[0xe] = CONFIG_LISTENING_IPV6_BYTE_E
;
126 #ifdef CONFIG_LISTENING_IPV6_BYTE_F
127 listening_ipv6
.s6_addr
[0xf] = 0;
129 listening_ipv6
.s6_addr
[0xf] = CONFIG_LISTENING_IPV6_BYTE_F
;
133 /*----------------------------------------------------------------------------*/
134 #define RESP_HDR_FMT (u8*)"\
136 content-length:%u\r\n\r\n"
138 #define RESP_HDR_CONTENT_TYPE_FMT (u8*)"\
140 content-length:%u\r\n\
141 content-type:%s\r\n\r\n"
142 /******************************************************************************/
144 #define SIGBIT(sig) (1<<(sig-1))
146 /*----------------------------------------------------------------------------*/
149 static struct sockaddr_in srv_addr
;
151 static struct sockaddr_in6 srv_addr
;
153 static si srv_sock
; /* the main listening socket */
154 static si cnx_sock
; /* a cnx socket from accept */
156 static ul cnx_sock_fd_set
[FD_SET_ULS_N
];
157 static u8 cnx_sock_fd_set_ul_idx
;
158 static u8 cnx_sock_fd_ul_shift
;
159 /*----------------------------------------------------------------------------*/
161 /*----------------------------------------------------------------------------*/
163 static si sigs_fd
; /* fd for signals */
164 static si epfd
; /* epoll fd */
165 /*----------------------------------------------------------------------------*/
167 /*----------------------------------------------------------------------------*/
168 #define HTTP_METHOD_GET 0
169 #define HTTP_METHOD_HEAD 1
170 static u8 http_method
;
171 /*----------------------------------------------------------------------------*/
173 /*----------------------------------------------------------------------------*/
174 /* the buffer page */
176 static ul page_bytes_rd_n
; /* keep an eye on how much was read */
178 static u8
*method_target_space
;
179 static u8
*target_start
;
180 static u8
*target_end
; /* point the space char right after */
181 /*----------------------------------------------------------------------------*/
183 /*----------------------------------------------------------------------------*/
184 static u8 target_file_is_default
;
185 static si target_file_fd
;
186 static ul target_file_sz
;
187 static u8 target_file_mime
[255 + 1]; /* actually the content-type */
188 /*----------------------------------------------------------------------------*/
190 /*----------------------------------------------------------------------------*/
191 static sl resp_hdr_sz
; /* the generated response header */
192 /*----------------------------------------------------------------------------*/
195 /******************************************************************************/
196 /******************************************************************************/
197 /******************************************************************************/
200 static void epoll_srv_sock_setup(void)
202 struct epoll_event ep_evt
;
205 memset(&ep_evt
, 0, sizeof(ep_evt
));
206 ep_evt
.events
= EPOLLIN
| EPOLLPRI
;
207 ep_evt
.data
.fd
= srv_sock
;
209 r
= epoll_ctl(epfd
, EPOLL_CTL_ADD
, srv_sock
, &ep_evt
);
211 exit(SRV_SOCK_SETUP_EPOLL_CTL_ADD_FAILURE
);
214 /*---------------------------------------------------------------------------*/
215 /* http method can request to close the connexion exiting, we are violent: we close the tcp cnx
216 though we should send a response in order to be rfc correct */
219 /* PAGE_SZ is way bigger than 4 bytes */
220 static u8
http_method_is_get(void)
230 /* PAGE_SZ is way bigger than 4 bytes */
231 static u8
http_method_is_head(void)
241 static u8
http_method_match(void)
243 if (http_method_is_get())
244 http_method
= HTTP_METHOD_GET
;
245 else if (http_method_is_head())
246 http_method
= HTTP_METHOD_HEAD
;
248 return HTTP_CLOSE
; /* garbage or method not handled */
252 /* if we have an error or we time out, notify for socket closing */
253 #define CNX_SOCK_RD_WAIT_FAILURE 1
254 #define fd_set cnx_sock_fd_set
255 #define ul_idx cnx_sock_fd_set_ul_idx
256 #define ul_shift cnx_sock_fd_ul_shift
257 static u8
cnx_sock_rd_wait(void)
262 fd_set
[ul_idx
] = (1UL << ul_shift
); /* was zero-ed in global_init */
264 tv
.sec
= CONFIG_CNX_WAIT_TIMEOUT
;
268 /* pselect6 is common on x86_64 and aarch64 */
269 r
= pselect6(cnx_sock
+ 1, &cnx_sock_fd_set
[0], 0, 0, &tv
,0);
270 /* XXX: to address some concerns: by design for the sake of
271 simplicity we ignore handled signals here. May do state
272 management around epoll_pwait someday. */
277 if (ISERR(r
) || r
== 0) /* r != 1 */
278 return CNX_SOCK_RD_WAIT_FAILURE
;
285 #define CNX_SOCK_RD_FAILURE -1
286 static sl
cnx_sock_rd(void)
291 bytes_rd_n
= read(cnx_sock
, page
+ page_bytes_rd_n
,
292 PAGE_SZ
- page_bytes_rd_n
);
293 if (bytes_rd_n
!= -EINTR
) {
294 if (ISERR(bytes_rd_n
))
295 bytes_rd_n
= CNX_SOCK_RD_FAILURE
;
302 static u8
http_method_rd(void)
312 r
= cnx_sock_rd_wait();
313 if (r
== CNX_SOCK_RD_WAIT_FAILURE
)
316 bytes_rd_n
= cnx_sock_rd();
317 if (bytes_rd_n
== CNX_SOCK_RD_FAILURE
|| bytes_rd_n
== 0)
320 page_bytes_rd_n
+= bytes_rd_n
;
323 if (bytes_rd_n
-- == 0)
327 /* got the space separator:method' 'target */
328 method_target_space
= c
;
335 if (page_bytes_rd_n
== PAGE_SZ
) /* no more page room */
341 /* XXX:must be called with room in the page or it will loop with 0 read bytes
342 till the other end decides to shutdown the connection */
343 #define UNABLE_TO_READ_AT_LEAST_ONE_BYTE 1
344 static u8
http_rd_at_least_one_byte(void)
350 r
= cnx_sock_rd_wait();
351 if (r
== CNX_SOCK_RD_WAIT_FAILURE
)
354 bytes_rd_n
= cnx_sock_rd();
355 if (bytes_rd_n
== CNX_SOCK_RD_FAILURE
|| bytes_rd_n
== 0)
358 if (bytes_rd_n
!= 0) {
359 page_bytes_rd_n
+= bytes_rd_n
;
363 return UNABLE_TO_READ_AT_LEAST_ONE_BYTE
;
366 static u8
http_target_end_locate(void)
370 c
= method_target_space
+ 1;
373 /* need at least 1 more byte to keep going */
374 if (c
== (page
+ page_bytes_rd_n
)) {
377 if (page_bytes_rd_n
== PAGE_SZ
)
378 break;/* but no more room in our page */
380 /* we have still room in our page */
382 r
= http_rd_at_least_one_byte();
383 if (r
== UNABLE_TO_READ_AT_LEAST_ONE_BYTE
)
396 static u8
http_target_file_open(void)
401 /* openat is common to x86_64 and aarch64 */
402 r
= openat(target_start
, O_RDONLY
, 0);
409 target_file_fd
= (si
)r
;
413 static u8
http_target_file_sz_get(void)
415 struct stat target_stat
;
418 memset(&target_stat
, 0, sizeof(target_stat
));
419 r
= fstat(target_file_fd
, &target_stat
);
423 target_file_sz
= target_stat
.size
;
427 /* if we have an error or we time out, notify for socket closing */
428 #define CNX_SOCK_SEND_WAIT_FAILURE 1
429 #define fd_set cnx_sock_fd_set
430 #define ul_idx cnx_sock_fd_set_ul_idx
431 #define ul_shift cnx_sock_fd_ul_shift
432 static u8
cnx_sock_send_wait(void)
437 fd_set
[ul_idx
] = (1UL << ul_shift
); /* was zero-ed in global_init */
439 tv
.sec
= CONFIG_CNX_WAIT_TIMEOUT
;
443 /* pselect6 is common on x86_64 and aarch64 */
444 r
= pselect6(cnx_sock
+ 1, 0, &cnx_sock_fd_set
[0], 0, &tv
, 0);
445 /* XXX: to address some concerns: by design for the sake of
446 simplicity we ignore handled signals here. May do state
447 management around epoll_pwait someday. */
452 if (ISERR(r
) || r
== 0) /* r != 1 */
453 return CNX_SOCK_SEND_WAIT_FAILURE
;
460 #define CNX_SOCK_SEND_RESP_HDR_FAILURE -1
461 static sl
cnx_sock_send_resp_hdr(void)
466 bytes_sent_n
= write(cnx_sock
, page
, resp_hdr_sz
);
467 if (bytes_sent_n
!= -EINTR
) {
468 if (ISERR(bytes_sent_n
))
469 bytes_sent_n
= CNX_SOCK_SEND_RESP_HDR_FAILURE
;
476 static u8
http_resp_hdr_send(void)
478 if (target_file_mime
[0] == 0)
479 resp_hdr_sz
= (sl
)snprintf(page
, PAGE_SZ
, RESP_HDR_FMT
,
482 resp_hdr_sz
= (sl
)snprintf(page
, PAGE_SZ
,
483 RESP_HDR_CONTENT_TYPE_FMT
,
485 &target_file_mime
[0]);
487 if (resp_hdr_sz
== 0)
494 r
= cnx_sock_send_wait();
495 if (r
== CNX_SOCK_SEND_WAIT_FAILURE
)
498 bytes_sent_n
= cnx_sock_send_resp_hdr();
499 if (bytes_sent_n
== CNX_SOCK_SEND_RESP_HDR_FAILURE
)
502 resp_hdr_sz
-= bytes_sent_n
;
504 if (resp_hdr_sz
== 0)
505 return 0; /* resp hrd was sent */
510 #define CNX_SOCK_SENDFILE_FAILURE -1
511 static sl
cnx_sock_sendfile(void)
516 bytes_sent_n
= sendfile(cnx_sock
, target_file_fd
, 0,
518 if (bytes_sent_n
!= -EINTR
) {
519 if (ISERR(bytes_sent_n
))
520 bytes_sent_n
= CNX_SOCK_SENDFILE_FAILURE
;
527 static u8
http_sendfile(void)
533 if (target_file_sz
== 0)
536 r
= cnx_sock_send_wait();
537 if (r
== CNX_SOCK_SEND_WAIT_FAILURE
)
540 bytes_sent_n
= cnx_sock_sendfile();
541 if (bytes_sent_n
== CNX_SOCK_SENDFILE_FAILURE
)
544 target_file_sz
-= bytes_sent_n
;
549 static u8
*http_target_mime_file_path(void)
551 /* We have room in the page. target_end has not be modified */
561 static void http_target_mime_file(void)
566 struct stat mime_file_stat
;
569 if (target_file_is_default
)
570 mime_file_path
= CONFIG_DEFAULT_FILE_MIME
;
572 mime_file_path
= http_target_mime_file_path();
574 /*--------------------------------------------------------------------*/
577 /* openat is common to x86_64 and aarch64 */
578 r
= openat(mime_file_path
, O_RDONLY
, 0);
585 mime_file_fd
= (si
)r
;
586 /*--------------------------------------------------------------------*/
588 /*--------------------------------------------------------------------*/
590 memset(&mime_file_stat
, 0, sizeof(mime_file_stat
));
592 r
= fstat(mime_file_fd
, &mime_file_stat
);
596 /* mime_file_stat.size */
597 /*--------------------------------------------------------------------*/
599 /*--------------------------------------------------------------------*/
601 if ((mime_file_stat
.size
+ 1) > sizeof(target_file_mime
)) {
605 bytes_to_read_n
= mime_file_stat
.size
;
606 /*--------------------------------------------------------------------*/
608 /*--------------------------------------------------------------------*/
611 r
= read(mime_file_fd
, &target_file_mime
[0]
612 + mime_file_stat
.size
- bytes_to_read_n
,
616 goto close_mime_file
;
618 bytes_to_read_n
-= r
;
620 if (bytes_to_read_n
== 0)
624 /*--------------------------------------------------------------------*/
626 target_file_mime
[mime_file_stat
.size
] = 0;
633 target_file_mime
[0] = 0; /* no mime */
636 /*---------------------------------------------------------------------------*/
638 static void cnx_handle(void)
644 /* read till we find the first space */
645 r
= http_method_rd();
649 /* is this space defining a reasonable method name? */
650 if (method_target_space
== (page
+ PAGE_SZ
)) /* huge method name */
653 r
= http_method_match();
657 r
= http_target_end_locate();
661 /* now we check we have room for the ".mime" extension */
662 if ((target_end
- 1 + sizeof(".mime")) >= (page
+ PAGE_SZ
))
665 /* target is exactly "/" or prepare the path */
666 if ((target_end
- (method_target_space
+ 1)) == 1
667 && method_target_space
[1] == '/') {
668 target_file_is_default
= 1;
669 target_start
= CONFIG_DEFAULT_FILE
;
671 target_file_is_default
= 0;
672 target_start
= method_target_space
+ 1;
676 r
= http_target_file_open();
680 r
= http_target_file_sz_get();
682 goto close_target_file
;
684 http_target_mime_file();
686 r
= http_resp_hdr_send();
688 goto close_target_file
;
690 if (http_method
== HTTP_METHOD_GET
)
691 (void)http_sendfile();
694 close(target_file_fd
);
699 static void cnx_sock_close(void)
705 if (r
!= -EINTR
) /* ignores errors */
710 static void cnx_sock_fd_set_params(void)
714 ul_bits_n
= 8 * sizeof(ul
);
716 cnx_sock_fd_set_ul_idx
= cnx_sock
/ ul_bits_n
;
717 cnx_sock_fd_ul_shift
= cnx_sock
% ul_bits_n
;
720 static void cnxs_consume(void)
725 struct sockaddr_in peer
;
727 struct sockaddr_in6 peer
;
731 peer_len
= sizeof(peer
);
733 r
= accept(srv_sock
, &peer
, &peer_len
);
734 if (r
!= -EINTR
&& r
!= ECONNABORTED
) /* based on man page */
736 /* SIGSTOP will generate a EINTR */
739 if (r
!= -EAGAIN
&& ISERR(r
))
740 exit(CNXS_CONSUME_ACCEPT_GENERIC_FAILURE
);
741 if (peer_len
!= sizeof(peer
))
742 exit(CNXS_CONSUME_ACCEPT_WRONG_PEER
);
744 break; /* no more connexion pending */
748 cnx_sock_fd_set_params();
755 static void sigs_consume(void)
757 struct signalfd_siginfo info
;
763 memset(&info
, 0, sizeof(info
));
764 r
= read(sigs_fd
, &info
, sizeof(info
));
768 if (r
!= -EAGAIN
&& ((ISERR(r
) || (r
> 0
769 && r
!= sizeof(info
)))))
770 exit(SIGS_CONSUME_SIGINFO_READ_FAILURE
);
771 if (r
== 0 || r
== -EAGAIN
)
774 switch (info
.ssi_signo
) {
778 /* please, do add the ones you like */
783 static void main_loop(void)
786 struct epoll_event evts
[2]; /*sigs_fd and srv_sock */
791 memset(evts
, 0, sizeof(evts
));
792 /* epoll_pwait is common to aarch64 and x86_64 */
793 r
= epoll_pwait(epfd
, evts
, 2, -1, 0);
798 exit(MAIN_LOOP_EPOLL_WAIT_GENERIC_FAILURE
);
805 if (evts
[j
].data
.fd
== sigs_fd
) {
806 if(evts
[j
].events
& EPOLLIN
)
809 exit(MAIN_LOOP_EPOLL_WAIT_SIGS_FD_EVENT_IS_NOT_EPOLLIN
);
810 } else if (evts
[j
].data
.fd
== srv_sock
) {
811 if (evts
[j
].events
& (EPOLLERR
| EPOLLHUP
| EPOLLPRI
))
812 exit(MAIN_LOOP_EPOLL_WAIT_SRV_SOCK_UNEXPECTED_EVENT
);
813 else if (evts
[j
].events
& EPOLLIN
)
816 exit(MAIN_LOOP_EPOLL_WAIT_SRV_SOCK_UNKNOWN_FAILURE
);
824 static void srv_sock_create(void)
830 r
= socket(AF_INET
, SOCK_STREAM
| SOCK_NONBLOCK
, 0);
832 r
= socket(AF_INET6
, SOCK_STREAM
| SOCK_NONBLOCK
, 0);
835 exit(SRV_SOCK_CREATE_FAILURE
);
839 r
= setsockopt(srv_sock
, SOL_SOCKET
, SO_REUSEADDR
, &bool_true
,
842 exit(SRV_SOCK_SET_SOCK_OPTION_FAILURE
);
844 r
= bind(srv_sock
, &srv_addr
, sizeof(srv_addr
));
846 exit(SRV_SOCK_BIND_FAILURE
);
848 r
= listen(srv_sock
, 0);
850 exit(SRV_SOCK_LISTEN_FAILURE
);
853 static void epoll_sigs_setup(void)
855 struct epoll_event ep_evt
;
858 memset(&ep_evt
, 0, sizeof(ep_evt
));
859 ep_evt
.events
= EPOLLET
| EPOLLIN
;
860 ep_evt
.data
.fd
= sigs_fd
;
861 r
= epoll_ctl(epfd
, EPOLL_CTL_ADD
, sigs_fd
, &ep_evt
);
863 exit(EPOLL_SIGS_SETUP_EPOLL_ADD_FAILURE
);
866 static void sigs_setup(void)
867 {/* synchronous treatement of signals with signalfd
868 cannot change SIGKILL, neither SIGSTOP */
873 r
= rt_sigprocmask(SIG_BLOCK
, &mask
, 0, sizeof(mask
));
875 exit(SIGS_SETUP_BLOCKING_FAILURE
);
877 mask
= SIGBIT(SIGTERM
) | SIGBIT(SIGCHLD
);
878 sigs_fd
= (si
)signalfd4(-1, &mask
, sizeof(mask
), SFD_NONBLOCK
);
880 exit(SIGS_SETUP_HANDLERS_FAILURE
);
883 static void page_mmap(void)
887 addr
= mmap(PAGE_SZ
, RD
| WR
, PRIVATE
| ANONYMOUS
);
888 if(addr
== 0 || ISERR(addr
))
889 exit(RCV_PAGE_MMAP_FAILURE
);
894 static void setup(void)
898 epfd
=(si
)epoll_create1(0);
900 exit(SETUP_EPOLL_CREATE_FAILURE
);
904 epoll_srv_sock_setup();
909 static void globals_init(void)
912 srv_addr
.family
= AF_INET
;
914 /* big endian port */
915 srv_addr
.port
= cpu_to_be16(CONFIG_LISTENING_PORT
);
916 srv_addr
.addr
= cpu_to_be32(LISTENING_IPV4
);
918 srv_addr
.sin6_family
= AF_INET6
;
920 /* big endian port */
921 srv_addr
.sin6_port
= cpu_to_be16(CONFIG_LISTENING_PORT
);
922 listening_ipv6_init();
923 srv_addr
.sin6_addr
= listening_ipv6
; /* C compiler block copy */
926 srv_sock
= -1; /* our listening socket */
927 cnx_sock
= -1; /* a cnx socket from accept */
929 sigs_fd
= -1; /* fd for signals */
930 epfd
= -1; /* epoll fd */
932 memset(&cnx_sock_fd_set
[0], 0, sizeof(cnx_sock_fd_set
));
935 static void chroot_do(void)
939 r
= chroot(CONFIG_CHROOT_PATH
);
941 exit(CHROOT_FAILURE
);
949 /******************************************************************************/
950 /******************************************************************************/
951 /******************************************************************************/
954 /* XXX:may do the daemonic stuff if _really_ we need it */