Mercurial > illumos > onarm
annotate usr/src/cmd/cvcd/sparc/sun4u/starfire/cvcd.c @ 4:1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Mon, 31 Aug 2009 14:38:03 +0900 |
parents | c9caec207d52 |
children |
rev | line source |
---|---|
0 | 1 /* |
2 * CDDL HEADER START | |
3 * | |
4 * The contents of this file are subject to the terms of the | |
5 * Common Development and Distribution License, Version 1.0 only | |
6 * (the "License"). You may not use this file except in compliance | |
7 * with the License. | |
8 * | |
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
10 * or http://www.opensolaris.org/os/licensing. | |
11 * See the License for the specific language governing permissions | |
12 * and limitations under the License. | |
13 * | |
14 * When distributing Covered Code, include this CDDL HEADER in each | |
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
16 * If applicable, add the following below this CDDL HEADER, with the | |
17 * fields enclosed by brackets "[]" replaced with your own identifying | |
18 * information: Portions Copyright [yyyy] [name of copyright owner] | |
19 * | |
20 * CDDL HEADER END | |
21 */ | |
22 /* | |
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. | |
24 * Use is subject to license terms. | |
25 */ | |
26 | |
27 | |
28 /* | |
29 * This code implements the Starfire Virtual Console host daemon | |
30 * (see cvcd(1M)). It accepts a connection from netcon_server | |
31 * and transfers console I/O to/from the SSP across the | |
32 * network via TLI. The I/O is sent to the cvcredir device | |
33 * on the host (see cvc(7) and cvcredir(7)). It also sends | |
34 * disconnect and break ioctl's to the kernel CVC drivers. | |
35 */ | |
36 | |
4
1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
Koji Uno <koji.uno@sun.com>
parents:
0
diff
changeset
|
37 #pragma ident "%Z%%M% %I% %E% SMI" |
0 | 38 |
39 | |
40 #include <stdio.h> | |
41 #include <stdarg.h> | |
42 #include <syslog.h> | |
43 #include <stdlib.h> | |
44 #include <tiuser.h> | |
45 #include <sys/timod.h> | |
46 #include <fcntl.h> | |
47 #include <sys/param.h> | |
48 #include <sys/utsname.h> | |
49 #include <sys/stat.h> | |
50 #include <unistd.h> | |
51 #include <stropts.h> | |
52 #include <sys/conf.h> | |
53 #include <pwd.h> | |
54 #include <errno.h> | |
55 #include <sys/socket.h> | |
56 #include <arpa/inet.h> | |
57 #include <locale.h> | |
58 #include <termio.h> | |
59 #include <signal.h> | |
60 #include <sys/cvc.h> | |
61 | |
62 #include <string.h> | |
63 | |
64 #include <sys/ioctl.h> | |
65 #include <sys/file.h> | |
66 #include <sys/sockio.h> | |
67 | |
68 #include <sys/tihdr.h> | |
69 | |
70 #include <netdb.h> | |
71 #include <net/if.h> | |
72 #include <netinet/if_ether.h> | |
73 | |
74 #include <inet/common.h> | |
75 #include <sys/systeminfo.h> | |
76 | |
77 /* Process priority control */ | |
78 #include <sys/priocntl.h> | |
79 #include <sys/tspriocntl.h> | |
80 #include <sys/rtpriocntl.h> | |
81 | |
82 /* | |
83 * Misc. defines. | |
84 */ | |
85 #define CONREF "connection request from illegal host" | |
86 #define SSPHOSTNAMEFILE "/etc/ssphostname" | |
87 #define NODENAME "/etc/nodename" | |
88 #define MAXIFS 256 | |
89 | |
90 /* | |
91 * Function prototypes | |
92 */ | |
93 static void cvcd_connect(int fd, struct pollfd *); | |
94 static void cvcd_reject(int fd); | |
95 static void cvcd_read(struct pollfd *); | |
96 static void cvcd_write(char *data, int size); | |
97 static void cvcd_status(int fd); | |
98 static void cvcd_winch(int, char *, int); | |
99 static void cvcd_ioctl(int fd, int cmd); | |
100 static void cvcd_err(int code, char *format, ...); | |
101 static void usage(void); | |
102 static id_t schedinfo(char *name, short *maxpri); | |
103 static void cvcd_setopt(int fd, int name); | |
104 | |
105 /* | |
106 * Globals | |
107 */ | |
108 static int rconsfd; /* Console redirection driver */ | |
109 static char progname[MAXPATHLEN]; | |
110 static char ssphostname[MAXPATHLEN]; | |
111 static int debug = 0; | |
112 static int connected = 0; | |
113 static int peercheck = 1; | |
114 static char nic_name[32]; | |
115 | |
116 int | |
117 main(int argc, char **argv) | |
118 { | |
119 int opt; | |
120 int tport = 0; | |
121 char *hostname; | |
122 struct utsname utsname; | |
123 struct t_info tinfo; | |
124 int cvcd_ssp; | |
125 int nfd; | |
126 struct pollfd *cvcd_pfd; | |
127 int i; | |
128 int j; | |
129 struct servent *se; | |
130 struct sockaddr_in *sin; | |
131 struct t_bind *reqb; | |
132 struct t_bind *retb; | |
133 struct t_optmgmt *topt, *tropt; | |
134 struct opthdr *sockopt; | |
135 int on = 1; | |
136 int tmperr = 0; | |
137 int event; | |
138 char prefix[256]; | |
139 pcparms_t pcparms; | |
140 tsparms_t *tsparmsp; | |
141 id_t pid, tsID; | |
142 short tsmaxpri; | |
143 static int netcon_fail = 0; | |
144 | |
145 (void) setlocale(LC_ALL, ""); | |
146 (void) strcpy(progname, argv[0]); | |
147 (void) memset(ssphostname, 0, MAXPATHLEN); | |
148 | |
149 if ((cvcd_ssp = open(SSPHOSTNAMEFILE, O_RDONLY)) < 0) { | |
150 /* | |
151 * If there is no /etc/ssphostname disable peer check after | |
152 * issuing warning. | |
153 */ | |
154 tmperr = errno; | |
155 peercheck = 0; | |
156 } else { | |
157 if ((i = read(cvcd_ssp, ssphostname, MAXPATHLEN)) < 0) { | |
158 cvcd_err(LOG_ERR, "failed to read ssphostname"); | |
159 } | |
160 /* | |
161 * The ssp-config(1M) command newline terminates the | |
162 * ssphostname in the /etc/ssphostname file | |
163 */ | |
164 ssphostname[i-1] = '\0'; | |
165 (void) close(cvcd_ssp); | |
166 | |
167 (void) memset(nic_name, 0, sizeof (nic_name)); | |
168 } | |
169 | |
170 #if defined(DEBUG) | |
171 while ((opt = getopt(argc, argv, "dp:r:")) != EOF) { | |
172 #else | |
173 while ((opt = getopt(argc, argv, "r:")) != EOF) { | |
174 #endif /* DEBUG */ | |
175 switch (opt) { | |
176 | |
177 #if defined(DEBUG) | |
178 case 'd' : debug = 1; | |
179 break; | |
180 | |
181 case 'p' : tport = atoi(optarg); | |
182 break; | |
183 #endif /* DEBUG */ | |
184 | |
185 case 'r' : (void) strcpy(ssphostname, optarg); | |
186 break; | |
187 | |
188 default : usage(); | |
189 exit(1); | |
190 } | |
191 } | |
192 | |
193 if (uname(&utsname) == -1) { | |
194 perror("HOSTNAME not defined"); | |
195 exit(1); | |
196 } | |
197 hostname = utsname.nodename; | |
198 | |
199 /* | |
200 * hostname may still be NULL, depends on when cvcd was started | |
201 * in the boot sequence. If it is NULL, try one more time | |
202 * to get a hostname -> look in the /etc/nodename file. | |
203 */ | |
204 if (!strlen(hostname)) { | |
205 /* | |
206 * try to get the hostname from the /etc/nodename file | |
207 * we reuse the utsname.nodename buffer here! hostname | |
208 * already points to it. | |
209 */ | |
210 if ((nfd = open(NODENAME, O_RDONLY)) > 0) { | |
211 if ((i = read(nfd, utsname.nodename, SYS_NMLN)) <= 0) { | |
212 cvcd_err(LOG_WARNING, | |
213 "failed to acquire hostname"); | |
214 } | |
215 utsname.nodename[i-1] = '\0'; | |
216 (void) close(nfd); | |
217 } | |
218 } | |
219 | |
220 /* | |
221 * Must be root. | |
222 */ | |
223 if (debug == 0 && geteuid() != 0) { | |
224 fprintf(stderr, "cvcd: Must be root"); | |
225 exit(1); | |
226 } | |
227 | |
228 /* | |
229 * Daemonize... | |
230 */ | |
231 if (debug == 0) { | |
232 for (i = 0; i < NOFILE; i++) { | |
233 (void) close(i); | |
234 } | |
235 (void) chdir("/"); | |
236 (void) umask(0); | |
237 if (fork() != 0) { | |
238 exit(0); | |
239 } | |
240 (void) setpgrp(); | |
241 (void) sprintf(prefix, "%s-(HOSTNAME:%s)", progname, hostname); | |
242 openlog(prefix, LOG_CONS | LOG_NDELAY, LOG_LOCAL0); | |
243 } | |
244 if (peercheck == 0) { | |
245 cvcd_err(LOG_ERR, "open(SSPHOSTNAMEFILE):%s", | |
246 strerror(tmperr)); | |
247 } | |
248 | |
249 cvcd_pfd = (struct pollfd *)malloc(3*sizeof (struct pollfd)); | |
250 if (cvcd_pfd == (struct pollfd *)NULL) { | |
251 cvcd_err(LOG_ERR, "malloc:", strerror(errno)); | |
252 exit(1); | |
253 } | |
254 (void) memset((void *)cvcd_pfd, 0, 3*sizeof (struct pollfd)); | |
255 cvcd_pfd[0].fd = -1; | |
256 cvcd_pfd[1].fd = -1; | |
257 cvcd_pfd[2].fd = -1; | |
258 | |
259 /* SPR 94004 */ | |
260 (void) sigignore(SIGTERM); | |
261 | |
262 /* | |
263 * SPR 83644: cvc and kadb are not compatible under heavy loads. | |
264 * Fix: will give cvcd highest TS priority at execution time. | |
265 */ | |
266 pid = getpid(); | |
267 pcparms.pc_cid = PC_CLNULL; | |
268 tsparmsp = (tsparms_t *)pcparms.pc_clparms; | |
269 | |
270 /* Get scheduler properties for this PID */ | |
271 if (priocntl(P_PID, pid, PC_GETPARMS, (caddr_t)&pcparms) == -1L) { | |
272 cvcd_err(LOG_ERR, | |
273 "cvcd: GETPARMS failed. Warning: can't get ", | |
274 "TS priorities."); | |
275 } else { | |
276 /* Get class IDs and maximum priorities for a TS process */ | |
277 if ((tsID = schedinfo("TS", &tsmaxpri)) == -1) { | |
278 cvcd_err(LOG_ERR, "cvcd: Warning, can't get ", | |
279 "TS scheduler info."); | |
280 } else { | |
281 if (debug) { /* Print priority info */ | |
282 if (pcparms.pc_cid == tsID) { | |
283 cvcd_err(LOG_DEBUG, "%s%d%s%d%s%d\n", | |
284 "cvcd:: PID:", pid, | |
285 ", TS priority:", | |
286 tsparmsp->ts_upri, | |
287 ", TS max_pri:", tsmaxpri); | |
288 } | |
289 } | |
290 /* Change proc's priority to maxtspri */ | |
291 pcparms.pc_cid = tsID; | |
292 tsparmsp = (struct tsparms *)pcparms.pc_clparms; | |
293 tsparmsp->ts_upri = tsmaxpri; | |
294 tsparmsp->ts_uprilim = tsmaxpri; | |
295 | |
296 if (priocntl(P_PID, pid, PC_SETPARMS, | |
297 (caddr_t)&pcparms) == -1L) { | |
298 cvcd_err(LOG_ERR, "cvcd: Warning, ", | |
299 "can't set TS maximum priority."); | |
300 } | |
301 /* Done */ | |
302 if (debug) { /* Get new scheduler properties for PID */ | |
303 if (priocntl(P_PID, pid, PC_GETPARMS, | |
304 (caddr_t)&pcparms) == -1L) { | |
305 cvcd_err(LOG_DEBUG, "GETPARMS failed"); | |
306 exit(1); | |
307 } else { | |
308 cvcd_err(LOG_DEBUG, "%s%d%s%d%s%d\n", | |
309 "cvcd:: PID:", pid, | |
310 ", New TS priority:", | |
311 tsparmsp->ts_upri, | |
312 ", TS max_pri:", tsmaxpri); | |
313 } | |
314 } | |
315 } | |
316 } | |
317 | |
318 if (debug == 1) { | |
319 cvcd_err(LOG_DEBUG, "tport = %d, debug = %d", tport, debug); | |
320 } | |
321 | |
322 if (tport == 0) { | |
323 if ((se = getservbyname(CVCD_SERVICE, "tcp")) == NULL) { | |
324 cvcd_err(LOG_ERR, "getservbyname(%s) not found", | |
325 CVCD_SERVICE); | |
326 exit(1); | |
327 } | |
328 tport = se->s_port; | |
329 } | |
330 | |
331 cvcd_ssp = t_open(TCP_DEV, O_RDWR, &tinfo); | |
332 if (cvcd_ssp == -1) { | |
333 cvcd_err(LOG_ERR, "t_open: %s", t_errlist[t_errno]); | |
334 exit(1); | |
335 } | |
336 | |
337 /* | |
338 * Set the SO_REUSEADDR option for this TLI endpoint. | |
339 */ | |
340 cvcd_setopt(cvcd_ssp, SO_REUSEADDR); | |
341 | |
342 /* | |
343 * Set the SO_DONTROUTE option for this TLI endpoint, if | |
344 * /etc/ssphostname exists. | |
345 */ | |
346 if (peercheck == 1) | |
347 cvcd_setopt(cvcd_ssp, SO_DONTROUTE); | |
348 | |
349 /* | |
350 * Bind it. | |
351 */ | |
352 if (((reqb = (struct t_bind *)t_alloc(cvcd_ssp, T_BIND, T_ALL)) | |
353 == (struct t_bind *)NULL)) { | |
354 cvcd_err(LOG_ERR, "%s", t_errlist[t_errno]); | |
355 exit(1); | |
356 } | |
357 if (((retb = (struct t_bind *)t_alloc(cvcd_ssp, T_BIND, T_ALL)) | |
358 == (struct t_bind *)NULL)) { | |
359 cvcd_err(LOG_ERR, "%s", t_errlist[t_errno]); | |
360 exit(1); | |
361 } | |
362 reqb->qlen = 1; | |
363 reqb->addr.len = sizeof (struct sockaddr_in); | |
364 sin = (struct sockaddr_in *)reqb->addr.buf; | |
365 (void) memset((void *)sin, 0, sizeof (struct sockaddr_in)); | |
366 sin->sin_family = AF_INET; | |
367 | |
368 | |
369 sin->sin_addr.s_addr = htonl(INADDR_ANY); | |
370 sin->sin_port = htons(tport); | |
371 if (t_bind(cvcd_ssp, reqb, retb) == -1) { | |
372 cvcd_err(LOG_ERR, "t_bind: %s", t_errlist[t_errno]); | |
373 exit(1); | |
374 } | |
375 sin = (struct sockaddr_in *)retb->addr.buf; | |
376 if (sin->sin_port != htons(tport)) { | |
377 cvcd_err(LOG_ERR, "t_bind: bound to wrong port"); | |
378 cvcd_err(LOG_ERR, "Wanted %d, got %d", tport, | |
379 ntohs(sin->sin_port)); | |
380 exit(1); | |
381 } | |
382 | |
383 t_free((char *)reqb, T_BIND); | |
384 t_free((char *)retb, T_BIND); | |
385 | |
386 | |
387 /* | |
388 * Wait for connect from OBP. | |
389 */ | |
390 cvcd_pfd[2].fd = cvcd_ssp; | |
391 cvcd_pfd[2].events = POLLIN|POLLPRI; | |
392 if ((event = poll(&cvcd_pfd[2], 1, -1)) == -1) { | |
393 cvcd_err(LOG_ERR, "poll: %s", strerror(errno)); | |
394 exit(1); | |
395 } | |
396 /* | |
397 * cvcd_connect sets global | |
398 * connected = 1 if successful. | |
399 */ | |
400 cvcd_connect(cvcd_ssp, cvcd_pfd); | |
401 | |
402 /* | |
403 * Now set up the Network Console redirection driver. | |
404 */ | |
405 rconsfd = open(CVCREDIR_DEV, O_RDWR|O_NDELAY); | |
406 if (rconsfd < 0) { | |
407 cvcd_err(LOG_ERR, "open: %s", strerror(errno)); | |
408 exit(1); | |
409 } | |
410 | |
411 /* | |
412 * cvcd_pfd holds three file descriptors we need to poll from: | |
413 * 0 will be connected to in_cvcd; 1 is the CVC Redirection driver; | |
414 * and 2 is the listen endpoint for new connections. | |
415 */ | |
416 cvcd_pfd[1].fd = rconsfd; | |
417 cvcd_pfd[1].events = POLLIN; | |
418 /* | |
419 * Loop through main service routine. We check for inbound in.cvcd | |
420 * connection and data xfer between host and in.cvcd. | |
421 */ | |
422 for (;;) { | |
423 | |
424 char buf[MAXPKTSZ]; | |
425 | |
426 /* | |
427 * Check for in_cvcd connect requests. | |
428 */ | |
429 switch ((event = t_look(cvcd_ssp))) { | |
430 case -1 : | |
431 cvcd_err(LOG_ERR, "%s", t_errlist[t_errno]); | |
432 exit(1); | |
433 /* NOTREACHED */ | |
434 break; | |
435 case 0 : /* Nothing to do */ | |
436 break; | |
437 case T_LISTEN : | |
438 if (connected == 1) { | |
439 /* | |
440 * Someone already connected. | |
441 */ | |
442 cvcd_reject(cvcd_ssp); | |
443 } else { | |
444 /* | |
445 * cvcd_connect sets global | |
446 * connected = 1 if successful. | |
447 */ | |
448 cvcd_connect(cvcd_ssp, cvcd_pfd); | |
449 | |
450 /* | |
451 * Re-open the cvcredir driver if | |
452 * the netcon_fail is true. This | |
453 * indicates there was a previous | |
454 * network connection that got closed. | |
455 */ | |
456 if (netcon_fail) { | |
457 rconsfd = open(CVCREDIR_DEV, | |
458 O_RDWR|O_NDELAY); | |
459 if (rconsfd < 0) { | |
460 cvcd_err(LOG_ERR, | |
461 "open: %s", | |
462 strerror(errno)); | |
463 exit(1); | |
464 } | |
465 cvcd_pfd[1].fd = rconsfd; | |
466 cvcd_pfd[1].events = POLLIN; | |
467 netcon_fail = 0; | |
468 } | |
469 } | |
470 break; | |
471 default : | |
472 cvcd_err(LOG_ERR, | |
473 "Illegal event %d for cvcd_ssp", event); | |
474 exit(1); | |
475 } | |
476 /* | |
477 * Take a look for console I/O or connect request. | |
478 */ | |
479 if ((event = poll(cvcd_pfd, 3, -1)) == -1) { | |
480 cvcd_err(LOG_ERR, "poll: %s", strerror(errno)); | |
481 exit(1); | |
482 } | |
483 | |
484 /* | |
485 * The following for loop is to detect any bad | |
486 * things(ie hangup,errors,invalid fd) have happened | |
487 * to the file descriptors we're interested in. | |
488 * If so, disconnect current network console connection. | |
489 */ | |
490 for (j = 0; j < 3; j++) { | |
491 if (cvcd_pfd[j].revents & (POLLERR|POLLHUP|POLLNVAL)) { | |
492 cvcd_err(LOG_WARNING, | |
493 "poll: status on %s fd:%s%s%s", | |
494 ((j == 2) ? "listen" : | |
495 ((j == 0) ? "network" : "redir")), | |
496 (cvcd_pfd[j].revents & POLLERR) ? | |
497 " error" : "", | |
498 (cvcd_pfd[j].revents & POLLHUP) ? | |
499 " hangup" : "", | |
500 (cvcd_pfd[j].revents & POLLNVAL) ? | |
501 " bad fd" : ""); | |
502 | |
503 (void) t_close(cvcd_pfd[0].fd); | |
504 cvcd_pfd[0].fd = -1; | |
505 | |
506 (void) close(cvcd_pfd[1].fd); | |
507 cvcd_pfd[1].fd = -1; | |
508 connected = 0; | |
509 netcon_fail = 1; | |
510 break; | |
511 } | |
512 } | |
513 | |
514 /* | |
515 * Check if dummy netcon_fail flag is set, if set returns | |
516 * to the beginning of the main service routine. | |
517 */ | |
518 if (netcon_fail) | |
519 continue; | |
520 | |
521 if (event != 0) { | |
522 if (cvcd_pfd[0].revents == POLLIN) { | |
523 /* | |
524 * Process cvcd_ssp data and commands. | |
525 */ | |
526 cvcd_read(cvcd_pfd); | |
527 } | |
528 if (cvcd_pfd[1].revents == POLLIN) { | |
529 int s; | |
530 | |
531 if ((s = read(rconsfd, buf, MAXPKTSZ)) == -1) { | |
532 cvcd_err(LOG_ERR, "read: %s", | |
533 strerror(errno)); | |
534 exit(1); | |
535 } | |
536 if ((s > 0) && (connected == 1)) { | |
537 if (write(cvcd_pfd[0].fd, buf, s) != | |
538 s) { | |
539 cvcd_err(LOG_ERR, | |
540 "lost data output"); | |
541 } | |
542 } | |
543 } | |
544 } | |
545 } /* End forever loop */ | |
546 | |
547 #ifdef lint | |
548 /* NOTREACHED */ | |
549 return (1); | |
550 #endif /* lint */ | |
551 } | |
552 | |
553 static void | |
554 cvcd_reject(int fd) | |
555 { | |
556 struct t_call *tcall; | |
557 | |
558 tcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL); | |
559 if (tcall == (struct t_call *)NULL) { | |
560 cvcd_err(LOG_ERR, "cvcd_reject: t_alloc: %s", | |
561 t_errlist[t_errno]); | |
562 return; | |
563 } | |
564 if (t_listen(fd, tcall) == -1) { | |
565 if (t_errno == TNODATA) { | |
566 cvcd_err(LOG_ERR, "cvcd_reject: No client data!"); | |
567 } | |
568 cvcd_err(LOG_ERR, "cvcd_reject: t_listen: %s", | |
569 t_errlist[t_errno]); | |
570 t_free((char *)tcall, T_CALL); | |
571 return; | |
572 } | |
573 if (t_snddis(fd, tcall) < 0) { | |
574 cvcd_err(LOG_ERR, "cvcd_reject: t_snddis: %s", | |
575 t_errlist[t_errno]); | |
576 } | |
577 t_free((char *)tcall, T_CALL); | |
578 } | |
579 | |
580 static void | |
581 cvcd_connect(int fd, struct pollfd *pfd) | |
582 { | |
583 struct t_call *tcall; | |
584 int newfd; | |
585 struct sockaddr_in *peer; | |
586 int badpeer = 1; | |
587 struct hostent *he; | |
588 struct netbuf netbuf; | |
589 char addr[100]; | |
590 ulong_t tmpaddr; /* network byte order */ | |
591 char **pp; | |
592 | |
593 tcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL); | |
594 if (tcall == (struct t_call *)NULL) { | |
595 cvcd_err(LOG_ERR, "cvcd_connect: t_alloc: %s", | |
596 t_errlist[t_errno]); | |
597 return; | |
598 } | |
599 if (t_listen(fd, tcall) == -1) { | |
600 if (t_errno == TNODATA) { | |
601 cvcd_err(LOG_ERR, "cvcd_connect: No client data!"); | |
602 } | |
603 cvcd_err(LOG_ERR, "cnctip_connect: t_listen: %s", | |
604 t_errlist[t_errno]); | |
605 t_free((char *)tcall, T_CALL); | |
606 return; | |
607 } | |
608 if (pfd[0].fd != -1) { | |
609 cvcd_err(LOG_ERR, "cvcd_connect: no free file descriptors!"); | |
610 t_free((char *)tcall, T_CALL); | |
611 return; | |
612 } | |
613 newfd = t_open(TCP_DEV, O_RDWR|O_NDELAY, NULL); | |
614 if (newfd == -1) { | |
615 cvcd_err(LOG_ERR, "cvcd_connect: t_open: %s", | |
616 t_errlist[t_errno]); | |
617 t_free((char *)tcall, T_CALL); | |
618 return; | |
619 } | |
620 if (t_accept(fd, newfd, tcall) < 0) { | |
621 cvcd_err(LOG_ERR, "cvcd_connect: t_accept: %s", | |
622 t_errlist[t_errno]); | |
623 t_close(newfd); | |
624 t_free((char *)tcall, T_CALL); | |
625 return; | |
626 } | |
627 t_free((char *)tcall, T_CALL); | |
628 | |
629 /* | |
630 * If /etc/ssphostname doesnt exists, dont bother verifying | |
631 * peer since we cant do gethostbyname. | |
632 */ | |
633 if (peercheck == 1) { | |
634 he = gethostbyname(ssphostname); | |
635 if (he == NULL) { | |
636 cvcd_err(LOG_ERR, "gethostbyname: %s", | |
637 strerror(h_errno)); | |
638 cvcd_err(LOG_ERR, "unable to get SSP name %s!", | |
639 ssphostname); | |
640 exit(1); | |
641 } | |
642 /* | |
643 * Verify peer is from specified host by comparing the | |
644 * address (in network byte order) of the TLI endpoint | |
645 * and the address (in network byte order) of the ssp | |
646 * (using the hostname found in /etc/ssphostname). | |
647 */ | |
648 (void) memset(addr, 0, 100); | |
649 netbuf.buf = addr; | |
650 netbuf.len = 0; | |
651 netbuf.maxlen = 100; | |
652 if (ioctl(newfd, TI_GETPEERNAME, &netbuf) < 0) { | |
653 cvcd_err(LOG_ERR, "ioctl(TI_GETPEERNAME): %s", | |
654 strerror(errno)); | |
655 t_close(newfd); | |
656 return; | |
657 } | |
658 | |
659 /* | |
660 * cvcd doesn't check multi-homed ssphostname | |
661 * properly (only checks 1st address) | |
662 */ | |
663 peer = (struct sockaddr_in *)addr; | |
664 for (pp = he->h_addr_list; *pp != 0; pp++) { | |
665 tmpaddr = htonl(*(ulong_t *)*pp); | |
666 if (memcmp(&peer->sin_addr.s_addr, &tmpaddr, | |
667 he->h_length) == 0) { | |
668 badpeer = 0; | |
669 break; | |
670 } | |
671 } | |
672 | |
673 if (badpeer) { | |
674 cvcd_err(LOG_ERR, CONREF); | |
675 cvcd_err(LOG_ERR, "remote host = %s.", | |
676 inet_ntoa(peer->sin_addr)); | |
677 t_close(newfd); | |
678 return; | |
679 } | |
680 } | |
681 pfd[0].fd = newfd; | |
682 pfd[0].events = POLLIN; | |
683 connected = 1; | |
684 } | |
685 | |
686 /* | |
687 * Read in data from client. | |
688 */ | |
689 static void | |
690 cvcd_read(struct pollfd *pd) | |
691 { | |
692 register char *data; | |
693 register int fd = pd[0].fd; | |
694 char buf[MAXPKTSZ]; | |
695 int flags = 0; | |
696 | |
697 data = buf; | |
698 | |
699 if (pd[0].revents & POLLIN) { | |
700 int n; | |
701 | |
702 if ((n = t_rcv(fd, data, MAXPKTSZ, &flags)) == -1) { | |
703 cvcd_err(LOG_ERR, "cvcd_read: t_rcv: %s", | |
704 t_errlist[t_errno]); | |
705 (void) t_close(pd[0].fd); | |
706 pd[0].fd = -1; | |
707 connected = 0; | |
708 return; | |
709 } | |
710 if (flags & T_EXPEDITED) { | |
711 if (n != 1) { | |
712 cvcd_err(LOG_ERR, | |
713 "cvcd_read: %d bytes EXD!!", | |
714 n); | |
715 } | |
716 /* | |
717 * Deal with cvcd_ssp_commands. | |
718 */ | |
719 switch (data[n-1]) { | |
720 case CVC_CONN_BREAK : | |
721 cvcd_ioctl(rconsfd, CVC_BREAK); | |
722 break; | |
723 | |
724 case CVC_CONN_DIS : | |
725 (void) t_close(pd[0].fd); | |
726 pd[0].fd = -1; | |
727 cvcd_ioctl(rconsfd, CVC_DISCONNECT); | |
728 connected = 0; | |
729 break; | |
730 | |
731 case CVC_CONN_STAT : | |
732 cvcd_status(fd); | |
733 break; | |
734 | |
735 default : | |
736 cvcd_err(LOG_ERR, | |
737 "Illegal cmd 0x%x", buf[n-1]); | |
738 break; | |
739 } | |
740 } else { | |
741 if (((data[0] & 0377) == 0377) && | |
742 ((data[1] & 0377) == 0377)) { | |
743 /* | |
744 * Pass on window size changes (TIOCSWINSZ). | |
745 */ | |
746 cvcd_winch(rconsfd, data, n); | |
747 (void) memset(data, 0, n); | |
748 } else { | |
749 cvcd_write(buf, n); | |
750 } | |
751 } | |
752 } | |
753 | |
754 } | |
755 | |
756 static void | |
757 cvcd_ioctl(int fd, int flags) | |
758 { | |
759 struct strioctl cmd; | |
760 | |
761 cmd.ic_cmd = flags; | |
762 cmd.ic_timout = 0; | |
763 cmd.ic_len = 0; | |
764 cmd.ic_dp = NULL; | |
765 | |
766 if (ioctl(fd, I_STR, &cmd) == -1) { | |
767 cvcd_err(LOG_ERR, "cvcd_ioctl: %s", strerror(errno)); | |
768 exit(1); | |
769 } | |
770 } | |
771 | |
772 | |
773 /* ARGSUSED */ | |
774 static void | |
775 cvcd_status(int fd) | |
776 { | |
777 } | |
778 | |
779 | |
780 /* | |
781 * Write input to console - called from cvcd_read. | |
782 */ | |
783 static void | |
784 cvcd_write(char *data, int size) | |
785 { | |
786 int n; | |
787 | |
788 if ((n = write(rconsfd, data, size)) == -1) { | |
789 cvcd_err(LOG_ERR, "cvcd_write: write: %s", strerror(errno)); | |
790 exit(1); | |
791 } | |
792 if (n != size) { | |
793 cvcd_err(LOG_ERR, "cvcd_write: wrote %d of %d bytes", n, size); | |
794 } | |
795 } | |
796 | |
797 static void | |
798 usage() | |
799 { | |
800 #if defined(DEBUG) | |
801 (void) printf("%s [-d] [-p port]\n", progname); | |
802 #else | |
803 (void) printf("%s -r [ssp host]\n", progname); | |
804 #endif /* DEBUG */ | |
805 } | |
806 | |
807 /* | |
808 * cvcd_err () | |
809 * | |
810 * Description: | |
811 * Log messages via syslog daemon. | |
812 * | |
813 * Input: | |
814 * code - logging code | |
815 * format - messages to log | |
816 * | |
817 * Output: | |
818 * void | |
819 * | |
820 */ | |
821 static void | |
822 cvcd_err(int code, char *format, ...) | |
823 { | |
824 va_list varg_ptr; | |
825 char buf[MAXPKTSZ]; | |
826 | |
827 va_start(varg_ptr, format); | |
828 (void) vsprintf(buf, format, varg_ptr); | |
829 va_end(varg_ptr); | |
830 | |
831 if (debug == 0) | |
832 syslog(code, buf); | |
833 else | |
834 (void) fprintf(stderr, "%s: %s\n", progname, buf); | |
835 } | |
836 | |
837 /* | |
838 * Handle a "control" request (signaled by magic being present) | |
839 * in the data stream. For now, we are only willing to handle | |
840 * window size changes. | |
841 */ | |
842 void | |
843 cvcd_winch(int pty, char *cp, int n) | |
844 { | |
845 struct winsize w; | |
846 | |
847 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') | |
848 return; | |
849 (void) memcpy(&w, cp + 4, sizeof (w)); | |
850 w.ws_row = ntohs(w.ws_row); | |
851 w.ws_col = ntohs(w.ws_col); | |
852 w.ws_xpixel = ntohs(w.ws_xpixel); | |
853 w.ws_ypixel = ntohs(w.ws_ypixel); | |
854 (void) ioctl(pty, TIOCSWINSZ, &w); | |
855 } | |
856 | |
857 | |
858 /* | |
859 * Return class ID and maximum priority of it. | |
860 * Input: | |
861 * name: is class name (either TS or RT). | |
862 * maxpri: maximum priority for the class, returned in *maxpri. | |
863 * Output: | |
864 * pc_cid: class ID | |
865 */ | |
866 static id_t | |
867 schedinfo(char *name, short *maxpri) | |
868 { | |
869 pcinfo_t info; | |
870 tsinfo_t *tsinfop; | |
871 rtinfo_t *rtinfop; | |
872 | |
873 (void) strcpy(info.pc_clname, name); | |
874 if (priocntl(0L, 0L, PC_GETCID, (caddr_t)&info) == -1L) { | |
875 return (-1); | |
876 } | |
877 if (strcmp(name, "TS") == 0) { /* Time Shared */ | |
878 tsinfop = (struct tsinfo *)info.pc_clinfo; | |
879 *maxpri = tsinfop->ts_maxupri; | |
880 } else if (strcmp(name, "RT") == 0) { /* Real Time */ | |
881 rtinfop = (struct rtinfo *)info.pc_clinfo; | |
882 *maxpri = rtinfop->rt_maxpri; | |
883 } else { | |
884 return (-1); | |
885 } | |
886 return (info.pc_cid); | |
887 } | |
888 | |
889 | |
890 /* | |
891 * set the tli options for the given endpoint represented by fd | |
892 */ | |
893 static void | |
894 cvcd_setopt(int fd, int name) | |
895 { | |
896 struct t_optmgmt *topt, *tropt; | |
897 struct opthdr *sockopt; | |
898 int on = 1; | |
899 | |
900 topt = (struct t_optmgmt *)t_alloc(fd, T_OPTMGMT, 0); | |
901 if (topt == NULL) { | |
902 cvcd_err(LOG_ERR, "t_alloc: %s", t_errlist[t_errno]); | |
903 exit(1); | |
904 } | |
905 tropt = (struct t_optmgmt *)t_alloc(fd, T_OPTMGMT, 0); | |
906 if (tropt == NULL) { | |
907 cvcd_err(LOG_ERR, "t_alloc: %s", t_errlist[t_errno]); | |
908 exit(1); | |
909 } | |
910 topt->opt.buf = (char *)malloc(sizeof (struct opthdr) + sizeof (int)); | |
911 topt->opt.maxlen = 0; | |
912 topt->opt.len = sizeof (struct opthdr) + sizeof (int); | |
913 topt->flags = T_NEGOTIATE; | |
914 sockopt = (struct opthdr *)topt->opt.buf; | |
915 sockopt->level = SOL_SOCKET; | |
916 sockopt->name = name; | |
917 sockopt->len = sizeof (int); | |
918 (void) memcpy((char *)(topt->opt.buf + sizeof (struct opthdr)), | |
919 (char *)&on, sizeof (on)); | |
920 tropt->opt.buf = (char *)malloc(sizeof (struct opthdr) + sizeof (int)); | |
921 tropt->opt.maxlen = sizeof (struct opthdr) + sizeof (int); | |
922 | |
923 if (t_optmgmt(fd, topt, tropt) == -1) { | |
924 t_error("t_optmgmt"); | |
925 exit(1); | |
926 } | |
927 | |
928 t_free((char *)topt, T_OPTMGMT); | |
929 t_free((char *)tropt, T_OPTMGMT); | |
930 } |