modules/up/src/Core/sys/File.cc
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- private_strerror
- File
- File
- setHandlers
- read
- write
- DatagramSocket
- DatagramSocket
- recvFrom
- sendTo
- defaultInterface
- RawSocket
- RawSocket
- recvFrom
- sendTo
- join
- MulticastSocket
- MulticastSocket
- defaultInterface
- setTTL
- StreamSocket
- StreamSocket
- StreamSocket
- ListenSocket
- ListenSocket
- accept
- DiskFile
- DiskFile
- seekTo
- seekEnd
- lock
- truncate
- createDir
- openPidFile
- closePidFile
- daemonize
1 //
2 // $Id: File.cc,v 1.1.1.1 2000/03/10 16:32:20 engin Exp $
3 //
4 // system.cc
5 // Author: Ramesh Govindan <govindan@isi.edu>
6 //
7 // Abstracted OS facilities for file system access and
8 // for communication primitives. This file contains implementations of:
9 // - network addresses (Address class)
10 // - OS file descriptors and descriptor sets
11 // - a common time representation
12 //
13
14 #ifdef HAVE_CONFIG_H
15 #include <config.h>
16 #endif
17
18 #include <cstdio>
19 #include <cstdlib>
20 #include <cerrno>
21
22 extern "C" {
23 #if HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif // HAVE_UNISTD_H
26
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <sys/time.h>
30 #include <sys/file.h>
31 #include <sys/resource.h>
32 #include <sys/termios.h>
33 #include <sys/ioctl.h>
34 #include <netinet/in.h>
35 #include <sys/socket.h>
36 #include <arpa/inet.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <signal.h>
40
41 #ifdef HOST_OS_IS_SOLARIS
42 #include <sys/systeminfo.h>
43 #include <netdb.h>
44 #endif
45 }
46
47 #include "util/Types.hh"
48 #include "util/List.hh"
49 #include "util/Handler.hh"
50 #include "util/Trail.hh"
51
52 #include "sys/Address.hh"
53 #include "sys/File.hh"
54 #include "sys/Signal.hh"
55 #include "sched/Dispatcher.hh"
56 #include "network/Headers.hh"
57
58 // Added by wlee to port to FreeBSD and BSDI
59 #ifndef INADDR_LOOPBACK
60 #define INADDR_LOOPBACK (u_long)0x7F000001
61 #endif
62
63 extern "C" {
64 #ifndef STDC_HEADERS
65 extern int socket(...);
66 extern int bind(...);
67 extern int connect(...);
68 extern int read(...);
69 extern int write(...);
70 extern int setsockopt(...);
71 extern int getsockname(...);
72 extern int close(...);
73 extern int recvfrom(...);
74 extern int sendto(...);
75 extern int listen(...);
76 extern int accept(...);
77 extern off_t lseek(...);
78 extern int flock(...);
79 extern int ftruncate(...);
80 extern int stat(...);
81 #endif
82 }
83
84 // For printing out system error messages: from GNU textutils lib
85 #if HAVE_STRERROR
86 #ifndef strerror
87 extern "C" char *strerror(int);
88 #endif
89 #else
90 extern int sys_nerr;
91 extern char* sys_errlist[];
92
93 static char*
94 private_strerror(int errnum)
/* [<][>][^][v][top][bottom][index][help] */
95 {
96 if (errnum > 0 && errnum <= sys_nerr)
97 return sys_errlist[errnum];
98 return "Unknown system error";
99 }
100 #define strerror private_strerror
101 #endif // HAVE_STRERROR
102
103 #ifdef ACCEPT_USES_SOCKLEN_T
104 #define SOCKLEN_T socklen_t
105 #elif ACCEPT_USES_SIZE_T
106 #define SOCKLEN_T size_t
107 #else
108 #define SOCKLEN_T int
109 #endif
110
111 // File local variables
112 static TraceCode traceFile("file");
113 static Handler nullHandler(NULL, NULL);
114 static int pidDescriptor = -1;
115
116 File::File(int fd,
/* [<][>][^][v][top][bottom][index][help] */
117 FileMode m,
118 const Handler& rh,
119 const Handler& wh)
120 : ListNode()
121 {
122 descriptor_ = fd;
123 mode_ = m;
124
125 if (descriptor_ < 0) {
126 FATAL("couldn't open file descriptor: %s\n",
127 strerror(errno));
128 // NotReached
129 }
130
131 readHandler = rh;
132 writeHandler = wh;
133 dispatcher.files.inset(this);
134 }
135
136 File::~File()
/* [<][>][^][v][top][bottom][index][help] */
137 {
138 TRACE(traceFile,
139 "closing file %d\n",
140 descriptor_);
141 close(descriptor_);
142 dispatcher.files.outset(this);
143 }
144
145 void
146 File::setHandlers(Handler& rh,
/* [<][>][^][v][top][bottom][index][help] */
147 Handler& wh)
148 {
149 dispatcher.files.outset(this);
150 readHandler = rh;
151 writeHandler = wh;
152 dispatcher.files.inset(this);
153 }
154
155 int
156 File::read(char *buffer,
/* [<][>][^][v][top][bottom][index][help] */
157 int bufferLength)
158 {
159 int retval;
160
161 if (mode_ != FileModeReadOnly
162 && mode_ != FileModeReadWrite) {
163 ERROR("illegal attempt to read from descriptor\n");
164 return FileOpHardError;
165 }
166
167 TRACE(traceFile,
168 "read file %d length %d\n",
169 descriptor_,
170 bufferLength);
171
172 retval = ::read(descriptor_,
173 buffer,
174 bufferLength);
175 if (retval < 0) {
176 switch (errno) {
177 case EWOULDBLOCK:
178 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
179 case EAGAIN:
180 #endif
181 case EINTR:
182 return FileOpSoftError;
183 default:
184 return FileOpHardError;
185 }
186 }
187 return retval;
188 }
189
190 int
191 File::write(char *buffer,
/* [<][>][^][v][top][bottom][index][help] */
192 int bufferLength)
193 {
194 int retval;
195
196 if (mode_ != FileModeReadWrite) {
197 ERROR("attempt to write on read-only file descriptor\n");
198 return FileOpHardError;
199 }
200
201 TRACE(traceFile,
202 "write file %d length %d\n",
203 descriptor_,
204 bufferLength);
205
206 retval = ::write(descriptor_,
207 buffer,
208 bufferLength);
209 if (retval < 0) {
210 switch (errno) {
211 case EWOULDBLOCK:
212 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
213 case EAGAIN:
214 #endif
215 case EINTR:
216 return FileOpSoftError;
217 default:
218 return FileOpHardError;
219 }
220 }
221 return retval;
222 }
223
224 DatagramSocket::DatagramSocket(const Handler& rh,
/* [<][>][^][v][top][bottom][index][help] */
225 const Handler& wh)
226 : File(::socket(AF_INET, SOCK_DGRAM, 0),
227 FileModeReadWrite,
228 rh,
229 wh)
230 {
231 // Empty
232 }
233
234 DatagramSocket::~DatagramSocket()
/* [<][>][^][v][top][bottom][index][help] */
235 {
236 // Empty
237 }
238
239 int
240 DatagramSocket::recvFrom(char* buffer,
/* [<][>][^][v][top][bottom][index][help] */
241 int bufferLength,
242 Address& addr,
243 Port *port)
244 {
245 struct sockaddr_in sin;
246 int retval;
247 size_t socklen = sizeof(sin);
248
249 retval = ::recvfrom(descriptor_,
250 buffer,
251 bufferLength,
252 0,
253 (struct sockaddr *) &sin,
254 (SOCKLEN_T*)&socklen);
255
256 if (retval < 0) {
257 switch (errno) {
258 case EWOULDBLOCK:
259 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
260 case EAGAIN:
261 #endif
262 case EINTR:
263 return FileOpSoftError;
264 default:
265 return FileOpHardError;
266 }
267 }
268
269 addr.set((U32) ntohl(sin.sin_addr.s_addr));
270 *port = ntohs(sin.sin_port);
271 TRACE(traceFile,
272 "read %d bytes on socket %d from %s\n",
273 retval,
274 descriptor_,
275 addr.name());
276 return retval;
277 }
278
279 int
280 DatagramSocket::sendTo(char* buffer,
/* [<][>][^][v][top][bottom][index][help] */
281 int bufferLength,
282 Address& addr,
283 Port port)
284 {
285 struct sockaddr_in sin;
286 int retval;
287
288 sin.sin_family = AF_INET;
289 sin.sin_addr.s_addr = htonl(addr.get());
290 sin.sin_port = htons(port);
291 retval = ::sendto(descriptor_,
292 buffer,
293 bufferLength,
294 0,
295 (struct sockaddr *) &sin,
296 sizeof(sin));
297 if (retval < 0) {
298 switch (errno) {
299 case EWOULDBLOCK:
300 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
301 case EAGAIN:
302 #endif
303 case EINTR:
304 return FileOpSoftError;
305 default:
306 return FileOpHardError;
307 }
308 }
309
310 TRACE(traceFile,
311 "wrote %d bytes on socket %d from %s\n",
312 retval,
313 descriptor_,
314 addr.name());
315
316 return retval;
317 }
318
319 int
320 DatagramSocket::defaultInterface(Address& localAddress, const Address &dst) {
/* [<][>][^][v][top][bottom][index][help] */
321 #ifndef ALLOW_MULTIPLE_IFACES
322 static bool hashed= false;
323 static Address myOnlyIface;
324 if (hashed)
325 localAddress.set(myOnlyIface.get());
326 return FileOpOK;
327 #endif
328 int sock;
329 struct sockaddr_in sin;
330 size_t socklen = sizeof(sin);
331
332 sin.sin_family = AF_INET;
333 sin.sin_addr.s_addr = htonl(dst.get());
334 //xxx: sin.sin_port = htons(port); // We can then use write
335
336 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
337 ERROR("couldn't open socket for getting local address: %s\n",
338 strerror(errno));
339 return FileOpHardError;
340 }
341
342 if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
343 ERROR("couldn't connect for getting local address: %s\n",
344 strerror(errno));
345 return FileOpHardError;
346 }
347
348 if (getsockname(sock,
349 (struct sockaddr *) &sin,
350 (SOCKLEN_T*)&socklen) < 0) {
351 ERROR("couldn't get local address: %s\n",
352 strerror(errno));
353 return FileOpHardError;
354 }
355
356 #ifdef HOST_OS_IS_SOLARIS
357 if (sin.sin_addr.s_addr == 0) {
358 char myhostname[256];
359 struct hostent *hp;
360 int error;
361
362 error = sysinfo(SI_HOSTNAME, myhostname, sizeof(myhostname));
363 if (error == -1) {
364 ERROR("failed on sysinfo: %s\n",
365 strerror(errno));
366 exit(-1);
367 }
368
369 hp = gethostbyname(myhostname);
370 if (hp == NULL || hp->h_addrtype != AF_INET ||
371 hp->h_length != sizeof(sin.sin_addr)) {
372 ERROR("failed on gethostbyname: %s\n",
373 strerror(errno));
374 exit(-1);
375 }
376 memcpy((char *)&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
377 }
378 #endif
379
380 localAddress.set(ntohl(sin.sin_addr.s_addr));
381 close(sock);
382 TRACE(traceFile,
383 "default interface for dst %s is %s\n",
384 dst.name(),
385 localAddress.name());
386 #ifndef ALLOW_MULTIPLE_IFACES
387 myOnlyIface= localAddress.get();
388 hashed= true;
389 #endif
390 return FileOpOK;
391 }
392
393 RawSocket::RawSocket(Handler& rh,
/* [<][>][^][v][top][bottom][index][help] */
394 Handler& wh,
395 RawSocketType type)
396 : File(::socket(AF_INET, SOCK_RAW, type),
397 FileModeReadWrite,
398 rh,
399 wh)
400 {
401 int bufSize = 48*1024;
402 int bval = 1;
403
404 #ifdef IP_HDRINCL
405 if(setsockopt(descriptor_, IPPROTO_IP, IP_HDRINCL,
406 (char *)&bval, sizeof(bval)) < 0) {
407 FATAL("setsockopt IP_HDRINCL %u", bval);
408 // Not Reached
409 }
410 #endif
411 if(setsockopt(descriptor_, SOL_SOCKET, SO_RCVBUF, (char *)&bufSize,
412 sizeof(bufSize)) < 0) {
413 FATAL("setsockopt SO_RCVBUF %u", bufSize);
414 // Not Reached
415 }
416 }
417
418 RawSocket::~RawSocket()
/* [<][>][^][v][top][bottom][index][help] */
419 {
420 // Empty
421 }
422
423 int
424 RawSocket::recvFrom(char* buffer,
/* [<][>][^][v][top][bottom][index][help] */
425 int bufferLength,
426 Address& addr,
427 Port *port)
428 {
429 struct sockaddr_in sin;
430 int retval;
431 size_t socklen = sizeof(sin);
432
433 retval = ::recvfrom(descriptor_,
434 buffer,
435 bufferLength,
436 0,
437 (struct sockaddr *) &sin,
438 (SOCKLEN_T*)&socklen);
439 if (retval < 0) {
440 switch (errno) {
441 case EWOULDBLOCK:
442 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
443 case EAGAIN:
444 #endif
445 case EINTR:
446 return FileOpSoftError;
447 default:
448 return FileOpHardError;
449 }
450 }
451
452 addr.set((U32) ntohl(sin.sin_addr.s_addr));
453 *port = ntohs(sin.sin_port);
454 TRACE(traceFile,
455 "read %d bytes on raw socket %d from %s\n",
456 retval,
457 descriptor_,
458 addr.name());
459 #ifdef HOST_OS_IS_FREEBSD
460 IP* iph= (IP*) buffer;
461 iph->totalLength+= sizeof(IP);
462 #endif
463 return retval;
464 }
465
466 int
467 RawSocket::sendTo(char* buffer,
/* [<][>][^][v][top][bottom][index][help] */
468 int bufferLength,
469 Address& addr,
470 Port port) const
471 {
472 struct sockaddr_in sin;
473 int retval;
474
475 sin.sin_family = AF_INET;
476 sin.sin_addr.s_addr = htonl(addr.get());
477 sin.sin_port = htons(port);
478 retval = ::sendto(descriptor_,
479 buffer,
480 bufferLength,
481 0,
482 (struct sockaddr *) &sin,
483 sizeof(sin));
484 if (retval < 0) {
485 switch (errno) {
486 case EWOULDBLOCK:
487 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
488 case EAGAIN:
489 #endif
490 case EINTR:
491 return FileOpSoftError;
492 default:
493 return FileOpHardError;
494 }
495 }
496
497 TRACE(traceFile,
498 "wrote %d bytes on socket %d from %s\n",
499 retval,
500 descriptor_,
501 addr.name());
502
503 return retval;
504 }
505
506 int
507 RawSocket::join(Address& group)
/* [<][>][^][v][top][bottom][index][help] */
508 {
509 struct ip_mreq mreq;
510
511 mreq.imr_multiaddr.s_addr = htonl(group.get());
512 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
513
514 TRACE(traceFile,
515 "joining group %s on %d\n",
516 group.name(),
517 descriptor_);
518
519 if (::setsockopt(descriptor_,
520 IPPROTO_IP,
521 IP_ADD_MEMBERSHIP,
522 (char *) &mreq,
523 sizeof(mreq)) < 0) {
524 FATAL("failed group join on %d: %s\n",
525 descriptor_,
526 strerror(errno));
527 // NotReached
528 }
529
530 return FileOpOK;
531 }
532
533 MulticastSocket::MulticastSocket(const Address& addr,
/* [<][>][^][v][top][bottom][index][help] */
534 Port localPort,
535 const Handler& rh,
536 const Handler& wh)
537 : DatagramSocket(rh, wh)
538 {
539 struct ip_mreq mreq;
540 struct sockaddr_in sin;
541 char loop;
542
543 group = addr;
544 port = localPort;
545 sin.sin_family = AF_INET;
546 sin.sin_port = htons(localPort);
547 sin.sin_addr.s_addr = htonl(INADDR_ANY);
548
549 TRACE(traceFile,
550 "binding socket %d to port %d\n",
551 descriptor_,
552 localPort);
553
554 if (::bind(descriptor_,
555 (struct sockaddr *) &sin,
556 sizeof(sin)) < 0) {
557 FATAL("failed bind on %d: %s\n",
558 descriptor_,
559 strerror(errno));
560 // NotReached
561 }
562
563 mreq.imr_multiaddr.s_addr = htonl(group.get());
564 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
565
566 TRACE(traceFile,
567 "joining group %s on %d\n",
568 group.name(),
569 descriptor_);
570
571 if (::setsockopt(descriptor_,
572 IPPROTO_IP,
573 IP_ADD_MEMBERSHIP,
574 (char *) &mreq,
575 sizeof(mreq)) < 0) {
576 FATAL("failed group join on %d: %s\n",
577 descriptor_,
578 strerror(errno));
579 // NotReached
580 }
581
582 // Disable loopback of packets
583 loop = 0;
584 if (::setsockopt(descriptor_,
585 IPPROTO_IP,
586 IP_MULTICAST_LOOP,
587 &loop,
588 sizeof(loop)) < 0) {
589 FATAL("unable to disable multicast loopback on %d: %s\n",
590 descriptor_,
591 strerror(errno));
592 // NotReached
593 }
594 }
595
596 MulticastSocket::~MulticastSocket()
/* [<][>][^][v][top][bottom][index][help] */
597 {
598 struct ip_mreq mreq;
599
600 mreq.imr_multiaddr.s_addr = htonl(group.get());
601 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
602
603 TRACE(traceFile,
604 "deleting multicast socket for group %s on %d\n",
605 group.name(),
606 descriptor_);
607
608 (void) ::setsockopt(descriptor_,
609 IPPROTO_IP,
610 IP_DROP_MEMBERSHIP,
611 (char *) &mreq,
612 sizeof(mreq));
613 return;
614 }
615
616 int
617 MulticastSocket::defaultInterface(Address& localAddress)
/* [<][>][^][v][top][bottom][index][help] */
618 {
619 int sock;
620 struct sockaddr_in sin;
621 size_t socklen = sizeof(sin);
622
623 sin.sin_family = AF_INET;
624 sin.sin_addr.s_addr = htonl(group.get());
625 sin.sin_port = htons(port); // We can then use write
626
627 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
628 ERROR("couldn't open socket for getting local address: %s\n",
629 strerror(errno));
630 return FileOpHardError;
631 }
632
633 if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
634 ERROR("couldn't connect for getting local address: %s\n",
635 strerror(errno));
636 return FileOpHardError;
637 }
638
639 if (getsockname(sock,
640 (struct sockaddr *) &sin,
641 (SOCKLEN_T*)&socklen) < 0) {
642 ERROR("couldn't get local address: %s\n",
643 strerror(errno));
644 return FileOpHardError;
645 }
646
647 #ifdef HOST_OS_IS_SOLARIS
648 if (sin.sin_addr.s_addr == 0) {
649 char myhostname[256];
650 struct hostent *hp;
651 int error;
652
653 error = sysinfo(SI_HOSTNAME, myhostname, sizeof(myhostname));
654 if (error == -1) {
655 ERROR("failed on sysinfo: %s\n",
656 strerror(errno));
657 exit(-1);
658 }
659
660 hp = gethostbyname(myhostname);
661 if (hp == NULL || hp->h_addrtype != AF_INET ||
662 hp->h_length != sizeof(sin.sin_addr)) {
663 ERROR("failed on gethostbyname: %s\n",
664 strerror(errno));
665 exit(-1);
666 }
667 memcpy((char *)&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
668 }
669 #endif
670
671 localAddress.set(ntohl(sin.sin_addr.s_addr));
672 close(sock);
673 TRACE(traceFile,
674 "default interface for group %s is %s\n",
675 group.name(),
676 localAddress.name());
677
678 return FileOpOK;
679 }
680
681 int
682 MulticastSocket::setTTL(int ttl)
/* [<][>][^][v][top][bottom][index][help] */
683 {
684 char t = ttl;
685
686 TRACE(traceFile,
687 "setting ttl %d on %d\n",
688 ttl,
689 descriptor_);
690
691 if (::setsockopt(descriptor_,
692 IPPROTO_IP,
693 IP_MULTICAST_TTL,
694 (char *) &t,
695 sizeof(t)) < 0) {
696 ERROR("failed ttl set on %d: %s\n",
697 descriptor_,
698 strerror(errno));
699 return FileOpHardError;
700 }
701 return FileOpOK;
702 }
703
704 StreamSocket::StreamSocket(Address& addr,
/* [<][>][^][v][top][bottom][index][help] */
705 Port port,
706 Handler& rh,
707 Handler& wh)
708 : File(::socket(AF_INET, SOCK_STREAM, 0),
709 FileModeReadWrite,
710 rh,
711 wh)
712 {
713 struct sockaddr_in sin;
714 int retval;
715
716 // Only stream sockets are non-blocking
717 if (fcntl(descriptor_,
718 F_SETFL,
719 O_NDELAY) < 0) {
720 FATAL("non-blocking descriptor error: %s\n",
721 strerror(errno));
722 // Not Reached
723 }
724
725 sin.sin_family = AF_INET;
726 sin.sin_addr.s_addr = htonl(addr.get());
727 sin.sin_port = htons(port);
728
729 retval = ::connect(descriptor_,
730 (struct sockaddr *) &sin,
731 sizeof(sin));
732 // ASSERT((retval < 0) && (errno == EWOULDBLOCK)); // XXX
733 }
734
735 StreamSocket::StreamSocket(int d,
/* [<][>][^][v][top][bottom][index][help] */
736 Handler& rh,
737 Handler& wh)
738 : File(d, FileModeReadWrite, rh, wh)
739 {
740 // Only stream sockets are non-blocking
741 if (fcntl(descriptor_,
742 F_SETFL,
743 O_NDELAY) < 0) {
744 FATAL("non-blocking descriptor error: %s\n",
745 strerror(errno));
746 // Not Reached
747 }
748 }
749
750 StreamSocket::~StreamSocket()
/* [<][>][^][v][top][bottom][index][help] */
751 {
752 // Empty
753 }
754
755 ListenSocket::ListenSocket(Port port,
/* [<][>][^][v][top][bottom][index][help] */
756 Handler& lh,
757 Boolean local)
758 : File(::socket(AF_INET, SOCK_STREAM, 0),
759 FileModeReadWrite,
760 lh,
761 nullHandler)
762 {
763 int retval;
764 int reuse;
765 sockaddr_in sin;
766
767 sin.sin_family = AF_INET;
768 sin.sin_port = htons(port);
769 if (local) {
770 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
771 } else {
772 sin.sin_addr.s_addr = htonl(INADDR_ANY);
773 }
774
775 TRACE(traceFile,
776 "binding socket %d to port %d\n",
777 descriptor_,
778 port);
779
780 reuse = 1;
781 if (::setsockopt(descriptor_,
782 SOL_SOCKET,
783 SO_REUSEADDR,
784 (char*) &reuse,
785 sizeof(reuse)) < 0) {
786 FATAL("failed to set %d to be reusable: %s\n",
787 descriptor_,
788 strerror(errno));
789 // NotReached
790 }
791
792 if (::bind(descriptor_,
793 (struct sockaddr *) &sin,
794 sizeof(sin)) < 0) {
795 FATAL("failed bind on %d: %s\n",
796 descriptor_,
797 strerror(errno));
798 // NotReached
799 }
800
801 TRACE(traceFile,
802 "setting file %d to listen\n",
803 descriptor_);
804
805 retval = ::listen(descriptor_, 5);
806 if (retval < 0) {
807 FATAL("listen failed on file %d\n",
808 descriptor_);
809 // NotReached
810 }
811 return;
812 }
813
814 ListenSocket::~ListenSocket()
/* [<][>][^][v][top][bottom][index][help] */
815 {
816 // Empty
817 }
818
819 int
820 ListenSocket::accept(StreamSocket** sock,
/* [<][>][^][v][top][bottom][index][help] */
821 Address& remote,
822 Port *remotePort,
823 Handler& read,
824 Handler& write)
825 {
826 int retval;
827 struct sockaddr_in sin;
828 size_t socklen;
829
830 TRACE(traceFile,
831 "accepting incoming connection on file %d\n",
832 descriptor_);
833
834 socklen = sizeof(sin);
835 retval = ::accept(descriptor_,
836 (struct sockaddr *) &sin,
837 (SOCKLEN_T*)&socklen);
838 if (retval < 0) {
839 switch (errno) {
840 case EWOULDBLOCK:
841 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
842 case EAGAIN:
843 #endif
844 case EINTR:
845 return FileOpSoftError;
846 default:
847 return FileOpHardError;
848 }
849 }
850
851 remote.set(ntohl(sin.sin_addr.s_addr));
852 *remotePort = ntohs(sin.sin_port);
853
854 *sock = new StreamSocket(retval, read, write);
855 return FileOpOK;
856 }
857
858 DiskFile::DiskFile(char* fileName,
/* [<][>][^][v][top][bottom][index][help] */
859 Boolean readOnly,
860 Handler& rh,
861 Handler& wh)
862 : File(::open(fileName,
863 (readOnly) ? O_RDONLY : (O_CREAT | O_RDWR),
864 0644),
865 (readOnly) ? FileModeReadOnly : FileModeReadWrite,
866 rh,
867 wh)
868 {
869 // Empty
870 }
871
872 DiskFile::~DiskFile()
/* [<][>][^][v][top][bottom][index][help] */
873 {
874 // Empty
875 }
876
877 int
878 DiskFile::seekTo(u_long offset)
/* [<][>][^][v][top][bottom][index][help] */
879 {
880 int retval;
881
882 TRACE(traceFile,
883 "seeking to off %u on descriptor %d\n",
884 offset,
885 descriptor_);
886
887 retval = ::lseek(descriptor_, (off_t) offset, SEEK_SET);
888 if (retval < 0) {
889 return FileOpHardError;
890 }
891 return retval;
892 }
893
894 int
895 DiskFile::seekEnd()
/* [<][>][^][v][top][bottom][index][help] */
896 {
897 int retval;
898
899 TRACE(traceFile,
900 "seeking to end on descriptor %d\n",
901 descriptor_);
902
903 retval = ::lseek(descriptor_, (off_t) 0, SEEK_END);
904 if (retval < 0) {
905 return FileOpHardError;
906 }
907 return retval;
908 }
909
910 int
911 DiskFile::lock()
/* [<][>][^][v][top][bottom][index][help] */
912 {
913 int retval;
914
915 #ifdef HAVE_FLOCK
916 retval = ::flock(descriptor_, LOCK_EX|LOCK_NB);
917 #elif HAVE_LOCKF
918 retval = ::lockf(descriptor_, F_LOCK, 0);
919 #else
920 retval = 0;
921 #endif
922
923 if (retval < 0) {
924 switch (errno) {
925 case EWOULDBLOCK:
926 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
927 case EAGAIN:
928 #endif
929 TRACE(traceFile,
930 "descriptor %d already locked\n",
931 descriptor_);
932
933 return FileOpSoftError;
934 default:
935 break;
936 }
937 return FileOpHardError;
938 }
939
940 TRACE(traceFile,
941 "descriptor %d not locked by another process\n",
942 descriptor_);
943
944 return FileOpOK;
945 }
946
947 int
948 DiskFile::truncate(u_int size)
/* [<][>][^][v][top][bottom][index][help] */
949 {
950 int retval;
951
952 retval = ::ftruncate(descriptor_, size);
953 if (retval < 0) {
954 return FileOpHardError;
955 }
956
957 TRACE(traceFile,
958 "truncated descriptor %d to size %u\n",
959 descriptor_,
960 size);
961 return FileOpOK;
962 }
963
964 void
965 createDir(char* name)
/* [<][>][^][v][top][bottom][index][help] */
966 {
967 int retval;
968 struct stat statbuf;
969
970 retval = stat(name, &statbuf);
971 if (retval < 0) { // Name doesn't exist
972 retval = mkdir(name, 0755);
973 if (retval < 0) {
974 FATAL("couldn't create directory %s: %s\n", name,
975 strerror(errno));
976 // NotReached
977 }
978 return;
979 }
980 if (!S_ISDIR(statbuf.st_mode)) {
981 FATAL("expected %s to be a directory, it isn't\n",
982 name);
983 // NotReached
984 }
985 }
986
987 static char* pidFileName = NULL;
988
989 void
990 openPidFile(const char* name)
/* [<][>][^][v][top][bottom][index][help] */
991 {
992 int retval;
993 char buf[20];
994 int pid;
995 int len;
996
997 pidFileName = new char[strlen(name) + 1];
998 memcpy(pidFileName, name, strlen(name) + 1);
999
1000 pidDescriptor = open(name, O_RDWR | O_CREAT |
1001 #ifdef HOST_OS_IS_FREEBSD
1002 O_FSYNC
1003 #else
1004 O_SYNC
1005 #endif
1006 , 0664);
1007 if (pidDescriptor < 0) {
1008 ERROR("couldn't open pid file %s: %s\n", name, strerror(errno));
1009 exit(2);
1010 }
1011
1012 #ifdef HAVE_FLOCK
1013 retval = ::flock(pidDescriptor, LOCK_EX|LOCK_NB);
1014 #elif HAVE_LOCKF
1015 retval = ::lockf(pidDescriptor, F_LOCK, 0);
1016 #else
1017 retval = 0;
1018 #endif
1019
1020 if (retval < 0) {
1021 switch (errno) {
1022 case EWOULDBLOCK:
1023 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
1024 case EAGAIN:
1025 #endif
1026 len = read(pidDescriptor, buf, sizeof buf);
1027 if (len > 0 && (pid = atoi(buf))) {
1028 ERROR("another already running, pid %d\n",
1029 pid);
1030 } else {
1031 ERROR("is some other %s running?");
1032 }
1033 break;
1034
1035 default:
1036 ERROR("flock failed: %s\n", strerror(errno));
1037 }
1038 close(pidDescriptor);
1039 pidDescriptor = -1;
1040 exit(2);
1041 }
1042
1043 (void) sprintf(buf, "%d\n", getpid());
1044 len = strlen(buf);
1045
1046 #ifndef SEEK_SET
1047 #define SEEK_SET L_SET
1048 #endif /* SEEK_SET */
1049 /* Back up to the beginning and truncate the file */
1050 if (lseek(pidDescriptor, (off_t) 0, SEEK_SET) < 0
1051 || ftruncate(pidDescriptor, (off_t) 0) < 0
1052 || write(pidDescriptor, buf, len) != len) {
1053 ERROR("couldn't write to %s: %s\n", name, strerror(errno));
1054 exit(2);
1055 }
1056
1057 return;
1058 }
1059
1060 void
1061 closePidFile()
/* [<][>][^][v][top][bottom][index][help] */
1062 {
1063 if (!pidFileName) {
1064 return;
1065 }
1066
1067 if (pidDescriptor > -1) {
1068 if (close(pidDescriptor) == -1
1069 || unlink(pidFileName) == -1) {
1070 ERROR("could not close or remove %s: %s\n",
1071 pidFileName, strerror(errno));
1072 exit(2);
1073 }
1074 pidDescriptor = -1;
1075 }
1076
1077 delete [] pidFileName;
1078 return;
1079 }
1080
1081 void
1082 daemonize()
/* [<][>][^][v][top][bottom][index][help] */
1083 {
1084 int t;
1085 Signal* sig;
1086
1087 // Ignore several signals
1088 sig = new Signal("ttou", NULL);
1089 sig = new Signal("ttin", NULL);
1090 sig = new Signal("tstp", NULL);
1091
1092 // Fork once
1093 switch (fork()) {
1094 case 0:
1095 break;
1096 case -1:
1097 perror("daemonize: fork");
1098 exit(1);
1099 default:
1100 exit(0);
1101 }
1102
1103 #ifdef SETPGRP_VOID
1104 t = setpgrp();
1105 if (t < 0) {
1106 perror("daemonize: setprgp");
1107 exit(1);
1108 }
1109
1110 sig = new Signal("hup", NULL);
1111
1112 switch (fork()) {
1113 case 0:
1114 break;
1115 case -1:
1116 perror("daemonize: fork");
1117 exit(1);
1118 default:
1119 exit(0);
1120 }
1121 #else // SETPRGP_VOID
1122 t = setpgrp(0, getpid());
1123 if (t < 0) {
1124 perror("daemonize: setpgrp");
1125 exit(1);
1126 }
1127
1128 while ((t = open("/dev/tty", O_RDWR, 0)) == -1 && errno == EINTR);
1129 if (t >= 0) {
1130 if (ioctl(t, TIOCNOTTY, (caddr_t) 0) < 0) {
1131 perror("daemonize: ioctl(TIOCNOTTY)");
1132 exit(1);
1133 }
1134 close(t);
1135 }
1136 #endif // SETPGRP_VOID
1137
1138 // Can close all open files, and reset umask
1139 {
1140 #ifndef NOFILE
1141 #ifdef _NFILE
1142 #define NOFILE _NFILE
1143 #else /* _NFILE */
1144 #ifdef OPEN_MAX
1145 #define NOFILE OPEN_MAX
1146 #else /* OPEN_MAX */
1147 #define NOFILE 20
1148 #endif /* OPEN_MAX */
1149 #endif /* _NFILE */
1150 #endif /* NOFILE */
1151 t = NOFILE;
1152 do {
1153 (void) close(t);
1154 } while (--t);
1155
1156 }
1157
1158 /* Reset umask */
1159 umask(022);
1160 }
1161
1162 //
1163 // Copyright (c) 1994 by the University of Southern California.
1164 // All rights reserved.
1165 //
1166 // Permission to use, copy, modify, and distribute this software and
1167 // its documentation in source and binary forms for lawful
1168 // non-commercial purposes and without fee is hereby granted, provided
1169 // that the above copyright notice appear in all copies and that both
1170 // the copyright notice and this permission notice appear in supporting
1171 // documentation, and that any documentation, advertising materials,
1172 // and other materials related to such distribution and use acknowledge
1173 // that the software was developed by the University of Southern
1174 // California and/or Information Sciences Institute.
1175 // The name of the University of Southern California may not
1176 // be used to endorse or promote products derived from this software
1177 // without specific prior written permission.
1178 //
1179 // THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
1180 // ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
1181 // PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
1182 // INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1183 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
1184 // NON-INFRINGEMENT.
1185 //
1186 // IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
1187 // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
1188 // TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
1189 // THE USE OR PERFORMANCE OF THIS SOFTWARE.
1190 //
1191 // Questions concerning this software should be directed to
1192 // info-ra@isi.edu.
1193 //