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