xref: /csrg-svn/libexec/talkd/talkd.c (revision 16360)
1 /* $Header: talkd.c 1.5 83/05/10 13:57:29 moore Exp $ */
2 
3 /* The top level of the daemon, the format is heavily borrowed
4    from rwhod.c. Basically: find out who and where you are;
5    disconnect all descriptors and ttys, and then endless
6    loop on waiting for and processing requests
7  */
8 
9 #include "ctl.h"
10 
11 #include <stdio.h>
12 #include <errno.h>
13 #include <sgtty.h>
14 #include <sys/ioctl.h>
15 
16 #define MAX_ERR 20	/* Number of times to attempt to open the
17 			   control socket */
18 
19 extern	errno;
20 
21 struct	sockaddr_in sin = { AF_INET };
22 
23 CTL_MSG request;
24 CTL_RESPONSE response;
25 int sockt;
26 char hostname[HOST_NAME_LENGTH];
27 
28 struct hostent *gethostbyname();
29 struct servent *getservbyname();
30 
31 int debug = 0;
32 
33 main(argc)
34 int argc;
35 {
36     struct sockaddr_in from;
37     int from_size;
38     int cc;
39     int name_length = sizeof(hostname);
40     struct servent *sp;
41     struct hostent *hp;
42 
43 
44     if ( argc > 1 ) {
45 	debug = 1;
46     }
47 
48     if ( !debug ) {
49 	if (fork()) {
50 	    exit(0);
51 	}
52     }
53 
54     gethostname(hostname, &name_length);
55 
56     hp = gethostbyname(hostname);
57     if (hp == (struct hostent *) 0) {
58 	    fprintf(stderr, "talkd: Cannot obtain local address\n");
59 	    exit(1);
60     }
61 
62 #ifdef NTALK
63     sp = getservbyname("ntalk", "udp");
64 #else
65     sp = getservbyname("talk", "udp");
66 #endif
67 
68     if (sp == 0) {
69 	    fprintf(stderr, "talkd: udp/talk: unknown service\n");
70 	    exit(1);
71     }
72 
73     if (getuid()) {
74 	fprintf(stderr, "Talkd : not super user\n");
75 	exit(1);
76     }
77 
78     setup_desc();
79 
80     sin.sin_port = sp->s_port;
81     sockt = socket(AF_INET, SOCK_DGRAM, 0, 0);
82     if (sockt < 0) {
83 	    print_error("talkd: socket");
84 	    exit(1);
85     }
86 
87     if (bind(sockt, (caddr_t)&sin, sizeof (sin), 0) < 0) {
88 	print_error("bind");
89 	exit(1);
90     }
91 
92     for (;;) {
93 
94 	from_size = sizeof(from);
95 	cc = recvfrom(sockt, (char *)&request, sizeof (request), 0,
96 		      &from, &from_size);
97 
98 	if (cc != sizeof(request)) {
99 	    if (cc < 0 && errno != EINTR) {
100 		print_error("receive");
101 	    }
102 	} else {
103 
104 	    if (debug) printf("Request received : \n");
105 	    if (debug) print_request(&request);
106 
107 	    process_request(&request, &response);
108 
109 	    if (debug) printf("Response sent : \n");
110 	    if (debug) print_response(&response);
111 
112 		/* can block here, is this what I want? */
113 
114 	    cc = sendto(sockt, (char *) &response, sizeof(response), 0,
115 			&request.ctl_addr, sizeof(request.ctl_addr));
116 
117 	    if (cc != sizeof(response)) {
118 		print_error("Send");
119 	    }
120 	}
121     }
122 }
123 
124     /* disconnect all descriptors, remove ourself from the process
125      * group that spawned us
126      */
127 
128 setup_desc()
129 {
130     int s;
131 
132     if (debug) return;
133 
134     for (s = 0; s < 10; s++) {
135 	(void) close(s);
136     }
137 
138     (void) open("/dev/null", 0);
139     (void) dup2(0, 1);
140     (void) dup2(0, 2);
141 
142     s = open("/dev/tty", 2);
143 
144     if (s >= 0) {
145 	ioctl(s, TIOCNOTTY, (struct sgttyb *) 0);
146 	(void) close(s);
147     }
148 
149     (void) chdir("/dev");
150 }
151 
152 extern int sys_nerr;
153 extern char *sys_errlist[];
154 
155 print_error(string)
156 char *string;
157 {
158     FILE *cons;
159     char *err_dev = "/dev/console";
160     char *sys;
161     int val, pid;
162 
163     if (debug) err_dev = "/dev/tty";
164 
165     sys = "Unknown error";
166 
167     if(errno < sys_nerr) {
168 	sys = sys_errlist[errno];
169     }
170 
171 	/* don't ever open tty's directly, let a child do it */
172     if ((pid = fork()) == 0) {
173 	cons = fopen(err_dev, "a");
174 	if (cons != NULL) {
175 	    fprintf(cons, "Talkd : %s : %s(%d)\n\r", string, sys,
176 		    errno);
177 	    fclose(cons);
178 	}
179 	exit(0);
180     } else {
181 	    /* wait for the child process to return */
182 	do {
183 	    val = wait(0);
184 	    if (val == -1) {
185 		if (errno == EINTR) {
186 		    continue;
187 		} else if (errno == ECHILD) {
188 		    break;
189 		}
190 	    }
191 	} while (val != pid);
192     }
193 }
194