Print this page
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/zoneadmd/zcons.c
+++ new/usr/src/cmd/zoneadmd/zcons.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 * Copyright 2015 Joyent, Inc.
26 26 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 27 */
28 28
29 29 /*
30 30 * Console support for zones requires a significant infrastructure. The
31 31 * core pieces are contained in this file, but other portions of note
32 32 * are in the zlogin(1M) command, the zcons(7D) driver, and in the
33 33 * devfsadm(1M) misc_link generator.
34 34 *
35 35 * Care is taken to make the console behave in an "intuitive" fashion for
36 36 * administrators. Essentially, we try as much as possible to mimic the
37 37 * experience of using a system via a tip line and system controller.
38 38 *
39 39 * The zone console architecture looks like this:
40 40 *
41 41 * Global Zone | Non-Global Zone
42 42 * .--------------. |
43 43 * .-----------. | zoneadmd -z | | .--------. .---------.
44 44 * | zlogin -C | | myzone | | | ttymon | | syslogd |
45 45 * `-----------' `--------------' | `--------' `---------'
46 46 * | | | | | | |
47 47 * User | | | | | V V
48 48 * - - - - - - - - -|- - - -|- - - -|-|- - - - - - -|- - /dev/zconsole - - -
49 49 * Kernel V V | | |
50 50 * [AF_UNIX Socket] | `--------. .-------------'
51 51 * | | |
52 52 * | V V
53 53 * | +-----------+
54 54 * | | ldterm, |
55 55 * | | etc. |
56 56 * | +-----------+
57 57 * | +-[Anchor]--+
58 58 * | | ptem |
59 59 * V +-----------+
60 60 * +---master---+---slave---+
61 61 * | |
62 62 * | zcons driver |
63 63 * | zonename="myzone" |
64 64 * +------------------------+
65 65 *
66 66 * There are basically two major tasks which the console subsystem in
67 67 * zoneadmd accomplishes:
68 68 *
69 69 * - Setup and teardown of zcons driver instances. One zcons instance
70 70 * is maintained per zone; we take advantage of the libdevice APIs
71 71 * to online new instances of zcons as needed. Care is taken to
72 72 * prune and manage these appropriately; see init_console_dev() and
73 73 * destroy_console_dev(). The end result is the creation of the
74 74 * zcons(7D) instance and an open file descriptor to the master side.
75 75 * zcons instances are associated with zones via their zonename device
76 76 * property. This the console instance to persist across reboots,
77 77 * and while the zone is halted.
78 78 *
79 79 * - Acting as a server for 'zlogin -C' instances. When zlogin -C is
80 80 * run, zlogin connects to zoneadmd via unix domain socket. zoneadmd
81 81 * functions as a two-way proxy for console I/O, relaying user input
82 82 * to the master side of the console, and relaying output from the
83 83 * zone to the user.
84 84 */
85 85
86 86 #include <sys/types.h>
87 87 #include <sys/socket.h>
88 88 #include <sys/stat.h>
89 89 #include <sys/termios.h>
90 90 #include <sys/zcons.h>
91 91 #include <sys/mkdev.h>
92 92
93 93 #include <assert.h>
94 94 #include <ctype.h>
95 95 #include <errno.h>
96 96 #include <fcntl.h>
97 97 #include <stdarg.h>
98 98 #include <stdio.h>
99 99 #include <stdlib.h>
100 100 #include <strings.h>
101 101 #include <stropts.h>
102 102 #include <thread.h>
103 103 #include <ucred.h>
104 104 #include <unistd.h>
105 105 #include <zone.h>
106 106
107 107 #include <libdevinfo.h>
108 108 #include <libdevice.h>
109 109 #include <libzonecfg.h>
110 110
111 111 #include <syslog.h>
112 112 #include <sys/modctl.h>
113 113
114 114 #include "zoneadmd.h"
115 115
116 116 #define ZCONSNEX_DEVTREEPATH "/pseudo/zconsnex@1"
117 117 #define ZCONSNEX_FILEPATH "/devices/pseudo/zconsnex@1"
118 118
119 119 #define CONSOLE_SOCKPATH ZONES_TMPDIR "/%s.console_sock"
120 120
121 121 #define ZCONS_RETRY 10
122 122
123 123 static int serverfd = -1; /* console server unix domain socket fd */
124 124 char boot_args[BOOTARGS_MAX];
125 125
126 126 /*
127 127 * The eventstream is a simple one-directional flow of messages from the
128 128 * door server to the console subsystem, implemented with a pipe.
129 129 * It is used to wake up the console poller when it needs to take action,
130 130 * message the user, die off, etc.
131 131 */
132 132 static int eventstream[2];
133 133
134 134 /* flag used to cope with race creating master zcons devlink */
135 135 static boolean_t master_zcons_failed = B_FALSE;
136 136 /* flag to track if we've seen a state change when there is no master zcons */
137 137 static boolean_t state_changed = B_FALSE;
138 138
139 139 int
140 140 eventstream_init()
141 141 {
142 142 if (pipe(eventstream) == -1)
143 143 return (-1);
144 144 return (0);
145 145 }
146 146
147 147 void
148 148 eventstream_write(zone_evt_t evt)
149 149 {
150 150 (void) write(eventstream[0], &evt, sizeof (evt));
151 151 }
152 152
153 153 static zone_evt_t
154 154 eventstream_read(void)
155 155 {
156 156 zone_evt_t evt = Z_EVT_NULL;
157 157
158 158 (void) read(eventstream[1], &evt, sizeof (evt));
159 159 return (evt);
160 160 }
161 161
162 162 /*
163 163 * count_console_devs() and its helper count_cb() do a walk of the
164 164 * subtree of the device tree where zone console nodes are represented.
165 165 * The goal is to count zone console instances already setup for a zone
166 166 * with the given name. More than 1 is anomolous, and our caller will
167 167 * have to deal with that if we find that's the case.
168 168 *
169 169 * Note: this algorithm is a linear search of nodes in the zconsnex subtree
170 170 * of the device tree, and could be a scalability problem, but I don't see
171 171 * how to avoid it.
172 172 */
173 173
174 174 /*
175 175 * cb_data is shared by count_cb and destroy_cb for simplicity.
176 176 */
177 177 struct cb_data {
178 178 zlog_t *zlogp;
179 179 int found;
180 180 int killed;
181 181 };
182 182
183 183 static int
184 184 count_cb(di_node_t node, void *arg)
185 185 {
186 186 struct cb_data *cb = (struct cb_data *)arg;
187 187 char *prop_data;
188 188
189 189 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zonename",
190 190 &prop_data) != -1) {
191 191 assert(prop_data != NULL);
192 192 if (strcmp(prop_data, zone_name) == 0) {
193 193 cb->found++;
194 194 return (DI_WALK_CONTINUE);
195 195 }
196 196 }
197 197 return (DI_WALK_CONTINUE);
198 198 }
199 199
200 200 static int
201 201 count_console_devs(zlog_t *zlogp)
202 202 {
203 203 di_node_t root;
204 204 struct cb_data cb;
205 205
206 206 bzero(&cb, sizeof (cb));
207 207 cb.zlogp = zlogp;
208 208
209 209 if ((root = di_init(ZCONSNEX_DEVTREEPATH, DINFOCPYALL)) ==
210 210 DI_NODE_NIL) {
211 211 zerror(zlogp, B_TRUE, "%s failed", "di_init");
212 212 return (-1);
213 213 }
214 214
215 215 (void) di_walk_node(root, DI_WALK_CLDFIRST, (void *)&cb, count_cb);
216 216 di_fini(root);
217 217 return (cb.found);
218 218 }
219 219
220 220 /*
221 221 * destroy_console_devs() and its helper destroy_cb() tears down any console
222 222 * instances associated with this zone. If things went very wrong, we
223 223 * might have more than one console instance hanging around. This routine
224 224 * hunts down and tries to remove all of them. Of course, if the console
225 225 * is open, the instance will not detach, which is a potential issue.
226 226 */
227 227 static int
228 228 destroy_cb(di_node_t node, void *arg)
229 229 {
230 230 struct cb_data *cb = (struct cb_data *)arg;
231 231 char *prop_data;
232 232 char *tmp;
233 233 char devpath[MAXPATHLEN];
234 234 devctl_hdl_t hdl;
235 235
236 236 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "zonename",
237 237 &prop_data) == -1)
238 238 return (DI_WALK_CONTINUE);
239 239
240 240 assert(prop_data != NULL);
241 241 if (strcmp(prop_data, zone_name) != 0) {
242 242 /* this is the console for a different zone */
243 243 return (DI_WALK_CONTINUE);
244 244 }
245 245
246 246 cb->found++;
247 247 tmp = di_devfs_path(node);
248 248 (void) snprintf(devpath, sizeof (devpath), "/devices/%s", tmp);
249 249 di_devfs_path_free(tmp);
250 250
251 251 if ((hdl = devctl_device_acquire(devpath, 0)) == NULL) {
252 252 zerror(cb->zlogp, B_TRUE, "WARNING: console %s found, "
253 253 "but it could not be controlled.", devpath);
254 254 return (DI_WALK_CONTINUE);
255 255 }
256 256 if (devctl_device_remove(hdl) == 0) {
257 257 cb->killed++;
258 258 } else {
259 259 zerror(cb->zlogp, B_TRUE, "WARNING: console %s found, "
260 260 "but it could not be removed.", devpath);
261 261 }
262 262 devctl_release(hdl);
263 263 return (DI_WALK_CONTINUE);
264 264 }
265 265
266 266 static int
267 267 destroy_console_devs(zlog_t *zlogp)
268 268 {
269 269 char conspath[MAXPATHLEN];
270 270 di_node_t root;
271 271 struct cb_data cb;
272 272 int masterfd;
273 273 int slavefd;
274 274
275 275 /*
276 276 * Signal the master side to release its handle on the slave side by
277 277 * issuing a ZC_RELEASESLAVE ioctl.
278 278 */
279 279 (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
280 280 zone_name, ZCONS_MASTER_NAME);
281 281 if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
282 282 (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
283 283 zone_name, ZCONS_SLAVE_NAME);
284 284 if ((slavefd = open(conspath, O_RDWR | O_NOCTTY)) != -1) {
285 285 if (ioctl(masterfd, ZC_RELEASESLAVE,
286 286 (caddr_t)(intptr_t)slavefd) != 0)
287 287 zerror(zlogp, B_TRUE, "WARNING: error while "
288 288 "releasing slave handle of zone console for"
289 289 " %s", zone_name);
290 290 (void) close(slavefd);
291 291 } else {
292 292 zerror(zlogp, B_TRUE, "WARNING: could not open slave "
293 293 "side of zone console for %s to release slave "
294 294 "handle", zone_name);
295 295 }
296 296 (void) close(masterfd);
297 297 } else {
298 298 zerror(zlogp, B_TRUE, "WARNING: could not open master side of "
299 299 "zone console for %s to release slave handle", zone_name);
300 300 }
301 301
302 302 bzero(&cb, sizeof (cb));
303 303 cb.zlogp = zlogp;
304 304
305 305 if ((root = di_init(ZCONSNEX_DEVTREEPATH, DINFOCPYALL)) ==
306 306 DI_NODE_NIL) {
307 307 zerror(zlogp, B_TRUE, "%s failed", "di_init");
308 308 return (-1);
309 309 }
310 310
311 311 (void) di_walk_node(root, DI_WALK_CLDFIRST, (void *)&cb, destroy_cb);
312 312 if (cb.found > 1) {
313 313 zerror(zlogp, B_FALSE, "WARNING: multiple zone console "
314 314 "instances detected for zone '%s'; %d of %d "
315 315 "successfully removed.",
316 316 zone_name, cb.killed, cb.found);
317 317 }
318 318
|
↓ open down ↓ |
318 lines elided |
↑ open up ↑ |
319 319 di_fini(root);
320 320 return (0);
321 321 }
322 322
323 323 /*
324 324 * init_console_dev() drives the device-tree configuration of the zone
325 325 * console device. The general strategy is to use the libdevice (devctl)
326 326 * interfaces to instantiate a new zone console node. We do a lot of
327 327 * sanity checking, and are careful to reuse a console if one exists.
328 328 *
329 - * Once the device is in the device tree, we kick devfsadm via di_devlink_init()
329 + * Once the device is in the device tree, we kick devfsadm via di_init_devs()
330 330 * to ensure that the appropriate symlinks (to the master and slave console
331 331 * devices) are placed in /dev in the global zone.
332 332 */
333 333 static int
334 334 init_console_dev(zlog_t *zlogp)
335 335 {
336 336 char conspath[MAXPATHLEN];
337 337 devctl_hdl_t bus_hdl = NULL;
338 338 devctl_hdl_t dev_hdl = NULL;
339 339 devctl_ddef_t ddef_hdl = NULL;
340 340 di_devlink_handle_t dl = NULL;
341 341 int rv = -1;
342 342 int ndevs;
343 343 int masterfd;
344 344 int slavefd;
345 345 int i;
346 346
347 347 /*
348 348 * Don't re-setup console if it is working and ready already; just
349 349 * skip ahead to making devlinks, which we do for sanity's sake.
350 350 */
351 351 ndevs = count_console_devs(zlogp);
352 352 if (ndevs == 1) {
353 353 goto devlinks;
354 354 } else if (ndevs > 1 || ndevs == -1) {
355 355 /*
356 356 * For now, this seems like a reasonable but harsh punishment.
357 357 * If needed, we could try to get clever and delete all but
358 358 * the console which is pointed at by the current symlink.
359 359 */
360 360 if (destroy_console_devs(zlogp) == -1) {
361 361 goto error;
362 362 }
363 363 }
364 364
365 365 /*
366 366 * Time to make the consoles!
367 367 */
368 368 if ((bus_hdl = devctl_bus_acquire(ZCONSNEX_FILEPATH, 0)) == NULL) {
369 369 zerror(zlogp, B_TRUE, "%s failed", "devctl_bus_acquire");
370 370 goto error;
371 371 }
372 372 if ((ddef_hdl = devctl_ddef_alloc("zcons", 0)) == NULL) {
373 373 zerror(zlogp, B_TRUE, "failed to allocate ddef handle");
374 374 goto error;
375 375 }
376 376 /*
377 377 * Set three properties on this node; the first is the name of the
378 378 * zone; the second is a flag which lets pseudo know that it is
379 379 * OK to automatically allocate an instance # for this device;
380 380 * the third tells the device framework not to auto-detach this
381 381 * node-- we need the node to still be there when we ask devfsadmd
382 382 * to make links, and when we need to open it.
383 383 */
384 384 if (devctl_ddef_string(ddef_hdl, "zonename", zone_name) == -1) {
385 385 zerror(zlogp, B_TRUE, "failed to create zonename property");
386 386 goto error;
387 387 }
388 388 if (devctl_ddef_int(ddef_hdl, "auto-assign-instance", 1) == -1) {
389 389 zerror(zlogp, B_TRUE, "failed to create auto-assign-instance "
390 390 "property");
391 391 goto error;
392 392 }
393 393 if (devctl_ddef_int(ddef_hdl, "ddi-no-autodetach", 1) == -1) {
394 394 zerror(zlogp, B_TRUE, "failed to create ddi-no-auto-detach "
395 395 "property");
396 396 goto error;
397 397 }
398 398 if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl) == -1) {
399 399 zerror(zlogp, B_TRUE, "failed to create console node");
400 400 goto error;
401 401 }
402 402
403 403 devlinks:
404 404 if ((dl = di_devlink_init("zcons", DI_MAKE_LINK)) != NULL) {
405 405 (void) di_devlink_fini(&dl);
406 406 } else {
407 407 zerror(zlogp, B_TRUE, "failed to create devlinks");
408 408 goto error;
409 409 }
410 410
411 411 /*
412 412 * Open the master side of the console and issue the ZC_HOLDSLAVE ioctl,
|
↓ open down ↓ |
73 lines elided |
↑ open up ↑ |
413 413 * which will cause the master to retain a reference to the slave.
414 414 * This prevents ttymon from blowing through the slave's STREAMS anchor.
415 415 *
416 416 * In very rare cases the open returns ENOENT if devfs doesn't have
417 417 * everything setup yet due to heavy zone startup load. Wait for
418 418 * 1 sec. and retry a few times. Even if we can't setup the zone's
419 419 * console, we still go ahead and boot the zone.
420 420 */
421 421 (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
422 422 zone_name, ZCONS_MASTER_NAME);
423 - for (i = 0; i < ZCONS_RETRY; i++) {
424 - masterfd = open(conspath, O_RDWR | O_NOCTTY);
425 - if (masterfd >= 0 || errno != ENOENT)
426 - break;
427 - (void) sleep(1);
428 - }
429 - if (masterfd == -1) {
423 + if ((masterfd = open(conspath, O_RDWR | O_NOCTTY)) == -1) {
430 424 zerror(zlogp, B_TRUE, "ERROR: could not open master side of "
431 425 "zone console for %s to acquire slave handle", zone_name);
432 426 master_zcons_failed = B_TRUE;
433 427 }
434 -
435 428 (void) snprintf(conspath, sizeof (conspath), "/dev/zcons/%s/%s",
436 429 zone_name, ZCONS_SLAVE_NAME);
437 430 for (i = 0; i < ZCONS_RETRY; i++) {
438 431 slavefd = open(conspath, O_RDWR | O_NOCTTY);
439 432 if (slavefd >= 0 || errno != ENOENT)
440 433 break;
441 434 (void) sleep(1);
442 435 }
443 436 if (slavefd == -1)
444 437 zerror(zlogp, B_TRUE, "ERROR: could not open slave side of zone"
445 438 " console for %s to acquire slave handle", zone_name);
446 439
447 440 /*
448 441 * This ioctl can occasionally return ENXIO if devfs doesn't have
449 442 * everything plumbed up yet due to heavy zone startup load. Wait for
450 443 * 1 sec. and retry a few times before we fail to boot the zone.
451 444 */
452 445 if (masterfd != -1 && slavefd != -1) {
453 446 for (i = 0; i < ZCONS_RETRY; i++) {
454 447 if (ioctl(masterfd, ZC_HOLDSLAVE,
455 448 (caddr_t)(intptr_t)slavefd) == 0) {
456 449 rv = 0;
457 450 break;
458 451 } else if (errno != ENXIO) {
459 452 break;
460 453 }
461 454 (void) sleep(1);
462 455 }
463 456 if (rv != 0)
464 457 zerror(zlogp, B_TRUE, "ERROR: error while acquiring "
465 458 "slave handle of zone console for %s", zone_name);
466 459 }
467 460
468 461 if (slavefd != -1)
469 462 (void) close(slavefd);
470 463 if (masterfd != -1)
471 464 (void) close(masterfd);
472 465
473 466 error:
474 467 if (ddef_hdl)
475 468 devctl_ddef_free(ddef_hdl);
476 469 if (bus_hdl)
477 470 devctl_release(bus_hdl);
478 471 if (dev_hdl)
479 472 devctl_release(dev_hdl);
480 473 return (rv);
481 474 }
482 475
483 476 static int
484 477 init_console_sock(zlog_t *zlogp)
485 478 {
486 479 int servfd;
487 480 struct sockaddr_un servaddr;
488 481
489 482 bzero(&servaddr, sizeof (servaddr));
490 483 servaddr.sun_family = AF_UNIX;
491 484 (void) snprintf(servaddr.sun_path, sizeof (servaddr.sun_path),
492 485 CONSOLE_SOCKPATH, zone_name);
493 486
494 487 if ((servfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
495 488 zerror(zlogp, B_TRUE, "console setup: could not create socket");
496 489 return (-1);
497 490 }
498 491 (void) unlink(servaddr.sun_path);
499 492
500 493 if (bind(servfd, (struct sockaddr *)&servaddr,
501 494 sizeof (servaddr)) == -1) {
502 495 zerror(zlogp, B_TRUE,
503 496 "console setup: could not bind to socket");
504 497 goto out;
505 498 }
506 499
507 500 if (listen(servfd, 4) == -1) {
508 501 zerror(zlogp, B_TRUE,
509 502 "console setup: could not listen on socket");
510 503 goto out;
511 504 }
512 505 return (servfd);
513 506
514 507 out:
515 508 (void) unlink(servaddr.sun_path);
516 509 (void) close(servfd);
517 510 return (-1);
518 511 }
519 512
520 513 static void
521 514 destroy_console_sock(int servfd)
522 515 {
523 516 char path[MAXPATHLEN];
524 517
525 518 (void) snprintf(path, sizeof (path), CONSOLE_SOCKPATH, zone_name);
526 519 (void) unlink(path);
527 520 (void) shutdown(servfd, SHUT_RDWR);
528 521 (void) close(servfd);
529 522 }
530 523
531 524 /*
532 525 * Read the "ident" string from the client's descriptor; this routine also
533 526 * tolerates being called with pid=NULL, for times when you want to "eat"
534 527 * the ident string from a client without saving it.
535 528 */
536 529 static int
537 530 get_client_ident(int clifd, pid_t *pid, char *locale, size_t locale_len,
538 531 int *disconnect)
539 532 {
540 533 char buf[BUFSIZ], *bufp;
541 534 size_t buflen = sizeof (buf);
542 535 char c = '\0';
543 536 int i = 0, r;
544 537 ucred_t *cred = NULL;
545 538
546 539 /* "eat up the ident string" case, for simplicity */
547 540 if (pid == NULL) {
548 541 assert(locale == NULL && locale_len == 0);
549 542 while (read(clifd, &c, 1) == 1) {
550 543 if (c == '\n')
551 544 return (0);
552 545 }
553 546 }
554 547
555 548 bzero(buf, sizeof (buf));
556 549 while ((buflen > 1) && (r = read(clifd, &c, 1)) == 1) {
557 550 buflen--;
558 551 if (c == '\n')
559 552 break;
560 553
561 554 buf[i] = c;
562 555 i++;
563 556 }
564 557 if (r == -1)
565 558 return (-1);
566 559
567 560 /*
568 561 * We've filled the buffer, but still haven't seen \n. Keep eating
569 562 * until we find it; we don't expect this to happen, but this is
570 563 * defensive.
571 564 */
572 565 if (c != '\n') {
573 566 while ((r = read(clifd, &c, sizeof (c))) > 0)
574 567 if (c == '\n')
575 568 break;
576 569 }
577 570
578 571 if (getpeerucred(clifd, &cred) == 0) {
579 572 *pid = ucred_getpid((const ucred_t *)cred);
580 573 ucred_free(cred);
581 574 } else {
582 575 return (-1);
583 576 }
584 577
585 578 /*
586 579 * Parse buffer for message of the form:
587 580 * IDENT <locale> <disconnect flag>
588 581 */
589 582 bufp = buf;
590 583 if (strncmp(bufp, "IDENT ", 6) != 0)
591 584 return (-1);
592 585 bufp += 6;
593 586 errno = 0;
594 587
595 588 while (*bufp != '\0' && isspace(*bufp))
596 589 bufp++;
597 590 buflen = strlen(bufp) - 1;
598 591 *disconnect = atoi(&bufp[buflen]);
599 592 bufp[buflen - 1] = '\0';
600 593 (void) strlcpy(locale, bufp, locale_len);
601 594
602 595 return (0);
603 596 }
604 597
605 598 static int
606 599 accept_client(int servfd, pid_t *pid, char *locale, size_t locale_len,
607 600 int *disconnect)
608 601 {
609 602 int connfd;
610 603 struct sockaddr_un cliaddr;
611 604 socklen_t clilen;
612 605
613 606 clilen = sizeof (cliaddr);
614 607 connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
615 608 if (connfd == -1)
616 609 return (-1);
617 610 if (get_client_ident(connfd, pid, locale, locale_len,
618 611 disconnect) == -1) {
619 612 (void) shutdown(connfd, SHUT_RDWR);
620 613 (void) close(connfd);
621 614 return (-1);
622 615 }
623 616 (void) write(connfd, "OK\n", 3);
624 617 return (connfd);
625 618 }
626 619
627 620 static void
628 621 reject_client(int servfd, pid_t clientpid)
629 622 {
630 623 int connfd;
631 624 struct sockaddr_un cliaddr;
632 625 socklen_t clilen;
633 626 char nak[MAXPATHLEN];
634 627
635 628 clilen = sizeof (cliaddr);
636 629 connfd = accept(servfd, (struct sockaddr *)&cliaddr, &clilen);
637 630
638 631 /*
639 632 * After hear its ident string, tell client to get lost.
640 633 */
641 634 if (get_client_ident(connfd, NULL, NULL, 0, NULL) == 0) {
642 635 (void) snprintf(nak, sizeof (nak), "%lu\n",
643 636 clientpid);
644 637 (void) write(connfd, nak, strlen(nak));
645 638 }
646 639 (void) shutdown(connfd, SHUT_RDWR);
647 640 (void) close(connfd);
648 641 }
649 642
650 643 static void
651 644 event_message(int clifd, char *clilocale, zone_evt_t evt, int dflag)
652 645 {
653 646 char *str, *lstr = NULL;
654 647 char lmsg[BUFSIZ];
655 648 char outbuf[BUFSIZ];
656 649
657 650 if (clifd == -1)
658 651 return;
659 652
660 653 switch (evt) {
661 654 case Z_EVT_ZONE_BOOTING:
662 655 if (*boot_args == '\0') {
663 656 str = "NOTICE: Zone booting up";
664 657 break;
665 658 }
666 659 /*LINTED*/
667 660 (void) snprintf(lmsg, sizeof (lmsg), localize_msg(clilocale,
668 661 "NOTICE: Zone booting up with arguments: %s"), boot_args);
669 662 lstr = lmsg;
670 663 break;
671 664 case Z_EVT_ZONE_READIED:
672 665 str = "NOTICE: Zone readied";
673 666 break;
674 667 case Z_EVT_ZONE_HALTED:
675 668 if (dflag)
676 669 str = "NOTICE: Zone halted. Disconnecting...";
677 670 else
678 671 str = "NOTICE: Zone halted";
679 672 break;
680 673 case Z_EVT_ZONE_REBOOTING:
681 674 if (*boot_args == '\0') {
682 675 str = "NOTICE: Zone rebooting";
683 676 break;
684 677 }
685 678 /*LINTED*/
686 679 (void) snprintf(lmsg, sizeof (lmsg), localize_msg(clilocale,
687 680 "NOTICE: Zone rebooting with arguments: %s"), boot_args);
688 681 lstr = lmsg;
689 682 break;
690 683 case Z_EVT_ZONE_UNINSTALLING:
691 684 str = "NOTICE: Zone is being uninstalled. Disconnecting...";
692 685 break;
693 686 case Z_EVT_ZONE_BOOTFAILED:
694 687 if (dflag)
695 688 str = "NOTICE: Zone boot failed. Disconnecting...";
696 689 else
697 690 str = "NOTICE: Zone boot failed";
698 691 break;
699 692 default:
700 693 return;
701 694 }
702 695
703 696 if (lstr == NULL)
704 697 lstr = localize_msg(clilocale, str);
705 698 (void) snprintf(outbuf, sizeof (outbuf), "\r\n[%s]\r\n", lstr);
706 699 (void) write(clifd, outbuf, strlen(outbuf));
707 700 }
708 701
709 702 /*
710 703 * Check to see if the client at the other end of the socket is still
711 704 * alive; we know it is not if it throws EPIPE at us when we try to write
712 705 * an otherwise harmless 0-length message to it.
713 706 */
714 707 static int
715 708 test_client(int clifd)
716 709 {
717 710 if ((write(clifd, "", 0) == -1) && errno == EPIPE)
718 711 return (-1);
719 712 return (0);
720 713 }
721 714
722 715 /*
723 716 * This routine drives the console I/O loop. It polls for input from the
724 717 * master side of the console (output to the console), and from the client
725 718 * (input from the console user). Additionally, it polls on the server fd,
726 719 * and disconnects any clients that might try to hook up with the zone while
727 720 * the console is in use.
728 721 *
729 722 * When the client first calls us up, it is expected to send a line giving
730 723 * its "identity"; this consists of the string 'IDENT <pid> <locale>'.
731 724 * This is so that we can report that the console is busy along with
732 725 * some diagnostics about who has it busy; the locale is used so that
733 726 * asynchronous messages about zone state (like the NOTICE: zone halted
734 727 * messages) can be output in the user's locale.
735 728 */
736 729 static void
737 730 do_console_io(zlog_t *zlogp, int consfd, int servfd)
738 731 {
739 732 struct pollfd pollfds[4];
740 733 char ibuf[BUFSIZ];
741 734 int cc, ret;
742 735 int clifd = -1;
743 736 int pollerr = 0;
744 737 char clilocale[MAXPATHLEN];
745 738 pid_t clipid = 0;
746 739 int disconnect = 0;
747 740
748 741 /* console side, watch for read events */
749 742 pollfds[0].fd = consfd;
750 743 pollfds[0].events = POLLIN | POLLRDNORM | POLLRDBAND |
751 744 POLLPRI | POLLERR | POLLHUP | POLLNVAL;
752 745
753 746 /* client side, watch for read events */
754 747 pollfds[1].fd = clifd;
755 748 pollfds[1].events = pollfds[0].events;
756 749
757 750 /* the server socket; watch for events (new connections) */
758 751 pollfds[2].fd = servfd;
759 752 pollfds[2].events = pollfds[0].events;
760 753
761 754 /* the eventstram; watch for events (e.g.: zone halted) */
762 755 pollfds[3].fd = eventstream[1];
763 756 pollfds[3].events = pollfds[0].events;
764 757
765 758 for (;;) {
766 759 pollfds[0].revents = pollfds[1].revents = 0;
767 760 pollfds[2].revents = pollfds[3].revents = 0;
768 761
769 762 ret = poll(pollfds,
770 763 sizeof (pollfds) / sizeof (struct pollfd), -1);
771 764 if (ret == -1 && errno != EINTR) {
772 765 zerror(zlogp, B_TRUE, "poll failed");
773 766 /* we are hosed, close connection */
774 767 break;
775 768 }
776 769
777 770 /* event from console side */
778 771 if (pollfds[0].revents) {
779 772 if (pollfds[0].revents &
780 773 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
781 774 errno = 0;
782 775 cc = read(consfd, ibuf, BUFSIZ);
783 776 if (cc <= 0 && (errno != EINTR) &&
784 777 (errno != EAGAIN))
785 778 break;
786 779 /*
787 780 * Lose I/O if no one is listening
788 781 */
789 782 if (clifd != -1 && cc > 0)
790 783 (void) write(clifd, ibuf, cc);
791 784 } else {
792 785 pollerr = pollfds[0].revents;
793 786 zerror(zlogp, B_FALSE,
794 787 "closing connection with (console) "
795 788 "pollerr %d\n", pollerr);
796 789 break;
797 790 }
798 791 }
799 792
800 793 /* event from client side */
801 794 if (pollfds[1].revents) {
802 795 if (pollfds[1].revents &
803 796 (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
804 797 errno = 0;
805 798 cc = read(clifd, ibuf, BUFSIZ);
806 799 if (cc <= 0 && (errno != EINTR) &&
807 800 (errno != EAGAIN))
808 801 break;
809 802 (void) write(consfd, ibuf, cc);
810 803 } else {
811 804 pollerr = pollfds[1].revents;
812 805 zerror(zlogp, B_FALSE,
813 806 "closing connection with (client) "
814 807 "pollerr %d\n", pollerr);
815 808 break;
816 809 }
817 810 }
818 811
819 812 /* event from server socket */
820 813 if (pollfds[2].revents &&
821 814 (pollfds[2].revents & (POLLIN | POLLRDNORM))) {
822 815 if (clifd != -1) {
823 816 /*
824 817 * Test the client to see if it is really
825 818 * still alive. If it has died but we
826 819 * haven't yet detected that, we might
827 820 * deny a legitimate connect attempt. If it
828 821 * is dead, we break out; once we tear down
829 822 * the old connection, the new connection
830 823 * will happen.
831 824 */
832 825 if (test_client(clifd) == -1) {
833 826 break;
834 827 }
835 828 /* we're already handling a client */
836 829 reject_client(servfd, clipid);
837 830
838 831
839 832 } else if ((clifd = accept_client(servfd, &clipid,
840 833 clilocale, sizeof (clilocale),
841 834 &disconnect)) != -1) {
842 835 pollfds[1].fd = clifd;
843 836
844 837 } else {
845 838 break;
846 839 }
847 840 }
848 841
849 842 /*
850 843 * Watch for events on the eventstream. This is how we get
851 844 * notified of the zone halting, etc. It provides us a
852 845 * "wakeup" from poll when important things happen, which
853 846 * is good.
854 847 */
855 848 if (pollfds[3].revents) {
856 849 int evt = eventstream_read();
857 850 /*
858 851 * After we drain out the event, if we aren't servicing
859 852 * a console client, we hop back out to our caller,
860 853 * which will check to see if it is time to shutdown
861 854 * the daemon, or if we should take another console
862 855 * service lap.
863 856 */
864 857 if (clifd == -1) {
865 858 break;
866 859 }
867 860 event_message(clifd, clilocale, evt, disconnect);
868 861 /*
869 862 * Special handling for the message that the zone is
870 863 * uninstalling; we boot the client, then break out
871 864 * of this function. When we return to the
872 865 * serve_console loop, we will see that the zone is
873 866 * in a state < READY, and so zoneadmd will shutdown.
874 867 */
875 868 if (evt == Z_EVT_ZONE_UNINSTALLING) {
876 869 break;
877 870 }
878 871 /*
879 872 * Diconnect if -C and -d options were specified and
880 873 * zone was halted or failed to boot.
881 874 */
882 875 if ((evt == Z_EVT_ZONE_HALTED ||
883 876 evt == Z_EVT_ZONE_BOOTFAILED) && disconnect) {
884 877 break;
885 878 }
886 879 }
887 880
888 881 }
889 882
890 883 if (clifd != -1) {
891 884 (void) shutdown(clifd, SHUT_RDWR);
892 885 (void) close(clifd);
893 886 }
894 887 }
895 888
896 889 int
897 890 init_console(zlog_t *zlogp)
898 891 {
899 892 if (init_console_dev(zlogp) == -1) {
900 893 zerror(zlogp, B_FALSE,
901 894 "console setup: device initialization failed");
902 895 }
903 896
904 897 if ((serverfd = init_console_sock(zlogp)) == -1) {
905 898 zerror(zlogp, B_FALSE,
906 899 "console setup: socket initialization failed");
907 900 return (-1);
908 901 }
909 902 return (0);
910 903 }
911 904
912 905 /*
913 906 * Maintain a simple flag that tracks if we have seen at least one state
914 907 * change. This is currently only used to handle the special case where we are
915 908 * running without a console device, which is what normally drives shutdown.
916 909 */
917 910 void
918 911 zcons_statechanged()
919 912 {
920 913 state_changed = B_TRUE;
921 914 }
922 915
923 916 /*
924 917 * serve_console() is the master loop for driving console I/O. It is also the
925 918 * routine which is ultimately responsible for "pulling the plug" on zoneadmd
926 919 * when it realizes that the daemon should shut down.
927 920 *
928 921 * The rules for shutdown are: there must be no console client, and the zone
929 922 * state must be < ready. However, we need to give things a chance to actually
930 923 * get going when the daemon starts up-- otherwise the daemon would immediately
931 924 * exit on startup if the zone was in the installed state, so we first drop
932 925 * into the do_console_io() loop in order to give *something* a chance to
933 926 * happen.
934 927 */
935 928 void
936 929 serve_console(zlog_t *zlogp)
937 930 {
938 931 int masterfd;
939 932 zone_state_t zstate;
940 933 char conspath[MAXPATHLEN];
941 934 static boolean_t cons_warned = B_FALSE;
942 935
943 936 (void) snprintf(conspath, sizeof (conspath),
944 937 "/dev/zcons/%s/%s", zone_name, ZCONS_MASTER_NAME);
945 938
946 939 for (;;) {
947 940 masterfd = open(conspath, O_RDWR|O_NONBLOCK|O_NOCTTY);
948 941 if (masterfd == -1) {
949 942 if (master_zcons_failed) {
950 943 /*
951 944 * If we don't have a console and the zone is
952 945 * not shutting down, there may have been a
953 946 * race/failure with devfs while creating the
954 947 * console. In this case we want to leave the
955 948 * zone up, even without a console, so
956 949 * periodically recheck.
957 950 */
958 951 int i;
959 952
960 953 /*
961 954 * In the normal flow of this loop, we use
962 955 * do_console_io to give things a chance to get
963 956 * going first. However, in this case we can't
964 957 * use that, so we have to wait for at least
965 958 * one state change before checking the state.
966 959 */
967 960 for (i = 0; i < 60; i++) {
968 961 if (state_changed)
969 962 break;
970 963 (void) sleep(1);
971 964 }
972 965
973 966 if (i < 60 && zone_get_state(zone_name,
974 967 &zstate) == Z_OK &&
975 968 (zstate == ZONE_STATE_READY ||
976 969 zstate == ZONE_STATE_RUNNING)) {
977 970 if (!cons_warned) {
978 971 zerror(zlogp, B_FALSE,
979 972 "WARNING: missing zone "
980 973 "console for %s",
981 974 zone_name);
982 975 cons_warned = B_TRUE;
983 976 }
984 977 (void) sleep(ZCONS_RETRY);
985 978 continue;
986 979 }
987 980 }
988 981
989 982 zerror(zlogp, B_TRUE, "failed to open console master");
990 983 (void) mutex_lock(&lock);
991 984 goto death;
992 985 }
993 986
994 987 /*
995 988 * Setting RPROTDIS on the stream means that the control
996 989 * portion of messages received (which we don't care about)
997 990 * will be discarded by the stream head. If we allowed such
998 991 * messages, we wouldn't be able to use read(2), as it fails
999 992 * (EBADMSG) when a message with a control element is received.
1000 993 */
1001 994 if (ioctl(masterfd, I_SRDOPT, RNORM|RPROTDIS) == -1) {
1002 995 zerror(zlogp, B_TRUE, "failed to set options on "
1003 996 "console master");
1004 997 (void) mutex_lock(&lock);
1005 998 goto death;
1006 999 }
1007 1000
1008 1001 do_console_io(zlogp, masterfd, serverfd);
1009 1002
1010 1003 /*
1011 1004 * We would prefer not to do this, but hostile zone processes
1012 1005 * can cause the stream to become tainted, and reads will
1013 1006 * fail. So, in case something has gone seriously ill,
1014 1007 * we dismantle the stream and reopen the console when we
1015 1008 * take another lap.
1016 1009 */
1017 1010 (void) close(masterfd);
1018 1011
1019 1012 (void) mutex_lock(&lock);
1020 1013 /*
1021 1014 * We need to set death_throes (see below) atomically with
1022 1015 * respect to noticing that (a) we have no console client and
1023 1016 * (b) the zone is not installed. Otherwise we could get a
1024 1017 * request to boot during this time. Once we set death_throes,
1025 1018 * any incoming door stuff will be turned away.
1026 1019 */
1027 1020 if (zone_get_state(zone_name, &zstate) == Z_OK) {
1028 1021 if (zstate < ZONE_STATE_READY)
1029 1022 goto death;
1030 1023 } else {
1031 1024 zerror(zlogp, B_FALSE,
1032 1025 "unable to determine state of zone");
1033 1026 goto death;
1034 1027 }
1035 1028 /*
1036 1029 * Even if zone_get_state() fails, stay conservative, and
1037 1030 * take another lap.
1038 1031 */
1039 1032 (void) mutex_unlock(&lock);
1040 1033 }
1041 1034
1042 1035 death:
1043 1036 assert(MUTEX_HELD(&lock));
1044 1037 in_death_throes = B_TRUE;
1045 1038 (void) mutex_unlock(&lock);
1046 1039
1047 1040 destroy_console_sock(serverfd);
1048 1041 (void) destroy_console_devs(zlogp);
1049 1042 }
|
↓ open down ↓ |
605 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX