1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate #include <stdio.h> 29*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 30*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 31*7c478bd9Sstevel@tonic-gate #include <unistd.h> 32*7c478bd9Sstevel@tonic-gate #include <assert.h> 33*7c478bd9Sstevel@tonic-gate #include <string.h> 34*7c478bd9Sstevel@tonic-gate #include <limits.h> 35*7c478bd9Sstevel@tonic-gate #include <synch.h> 36*7c478bd9Sstevel@tonic-gate #include <libintl.h> 37*7c478bd9Sstevel@tonic-gate #include <errno.h> 38*7c478bd9Sstevel@tonic-gate #include <libdevinfo.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/uio.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 42*7c478bd9Sstevel@tonic-gate #include <stropts.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 44*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/openpromio.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/ttymuxuser.h> 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate #include "ttymux_rcm_impl.h" 53*7c478bd9Sstevel@tonic-gate #include "rcm_module.h" 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate #define TTYMUX_OFFLINE_ERR gettext("Resource is in use by") 56*7c478bd9Sstevel@tonic-gate #define TTYMUX_UNKNOWN_ERR gettext("Unknown Operation attempted") 57*7c478bd9Sstevel@tonic-gate #define TTYMUX_ONLINE_ERR gettext("Failed to connect under multiplexer") 58*7c478bd9Sstevel@tonic-gate #define TTYMUX_INVALID_ERR gettext("Invalid Operation on this resource") 59*7c478bd9Sstevel@tonic-gate #define TTYMUX_OFFLINE_FAIL gettext("Failed to disconnect from multiplexer") 60*7c478bd9Sstevel@tonic-gate #define TTYMUX_MEMORY_ERR gettext("TTYMUX: strdup failure\n") 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate static int msglvl = 6; /* print messages less than this level */ 64*7c478bd9Sstevel@tonic-gate #define TEST(cond, stmt) { if (cond) stmt; } 65*7c478bd9Sstevel@tonic-gate #define _msg(lvl, args) TEST(msglvl > (lvl), trace args) 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate static int oflags = O_EXCL|O_RDWR|O_NONBLOCK|O_NOCTTY; 68*7c478bd9Sstevel@tonic-gate static dev_t cn_dev = NODEV; 69*7c478bd9Sstevel@tonic-gate static rsrc_t *cn_rsrc = NULL; 70*7c478bd9Sstevel@tonic-gate static rsrc_t cache_head; 71*7c478bd9Sstevel@tonic-gate static rsrc_t cache_tail; 72*7c478bd9Sstevel@tonic-gate static mutex_t cache_lock; 73*7c478bd9Sstevel@tonic-gate static char muxctl[PATH_MAX] = {0}; 74*7c478bd9Sstevel@tonic-gate static char muxcon[PATH_MAX] = {0}; 75*7c478bd9Sstevel@tonic-gate static int muxfd; 76*7c478bd9Sstevel@tonic-gate static boolean_t register_rsrcs; 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate /* module interface routines */ 79*7c478bd9Sstevel@tonic-gate static int tty_register(rcm_handle_t *); 80*7c478bd9Sstevel@tonic-gate static int tty_unregister(rcm_handle_t *); 81*7c478bd9Sstevel@tonic-gate static int tty_getinfo(rcm_handle_t *, char *, id_t, uint_t, char **, 82*7c478bd9Sstevel@tonic-gate char **, nvlist_t *, rcm_info_t **); 83*7c478bd9Sstevel@tonic-gate static int tty_suspend(rcm_handle_t *, char *, id_t, 84*7c478bd9Sstevel@tonic-gate timespec_t *, uint_t, char **, rcm_info_t **); 85*7c478bd9Sstevel@tonic-gate static int tty_resume(rcm_handle_t *, char *, id_t, uint_t, char **, 86*7c478bd9Sstevel@tonic-gate rcm_info_t **); 87*7c478bd9Sstevel@tonic-gate static int tty_offline(rcm_handle_t *, char *, id_t, uint_t, char **, 88*7c478bd9Sstevel@tonic-gate rcm_info_t **); 89*7c478bd9Sstevel@tonic-gate static int tty_online(rcm_handle_t *, char *, id_t, uint_t, char **, 90*7c478bd9Sstevel@tonic-gate rcm_info_t **); 91*7c478bd9Sstevel@tonic-gate static int tty_remove(rcm_handle_t *, char *, id_t, uint_t, char **, 92*7c478bd9Sstevel@tonic-gate rcm_info_t **); 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate static int get_devpath(char *, char **, dev_t *); 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate /* 97*7c478bd9Sstevel@tonic-gate * Module-Private data 98*7c478bd9Sstevel@tonic-gate */ 99*7c478bd9Sstevel@tonic-gate static struct rcm_mod_ops tty_ops = { 100*7c478bd9Sstevel@tonic-gate RCM_MOD_OPS_VERSION, 101*7c478bd9Sstevel@tonic-gate tty_register, 102*7c478bd9Sstevel@tonic-gate tty_unregister, 103*7c478bd9Sstevel@tonic-gate tty_getinfo, 104*7c478bd9Sstevel@tonic-gate tty_suspend, 105*7c478bd9Sstevel@tonic-gate tty_resume, 106*7c478bd9Sstevel@tonic-gate tty_offline, 107*7c478bd9Sstevel@tonic-gate tty_online, 108*7c478bd9Sstevel@tonic-gate tty_remove, 109*7c478bd9Sstevel@tonic-gate NULL, 110*7c478bd9Sstevel@tonic-gate NULL 111*7c478bd9Sstevel@tonic-gate }; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 114*7c478bd9Sstevel@tonic-gate static void 115*7c478bd9Sstevel@tonic-gate trace(char *fmt, ...) 116*7c478bd9Sstevel@tonic-gate { 117*7c478bd9Sstevel@tonic-gate va_list args; 118*7c478bd9Sstevel@tonic-gate char buf[256]; 119*7c478bd9Sstevel@tonic-gate int sz; 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate va_start(args, fmt); 122*7c478bd9Sstevel@tonic-gate sz = vsnprintf(buf, sizeof (buf), fmt, args); 123*7c478bd9Sstevel@tonic-gate va_end(args); 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate if (sz < 0) 126*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, 127*7c478bd9Sstevel@tonic-gate _("TTYMUX: vsnprintf parse error\n")); 128*7c478bd9Sstevel@tonic-gate else if (sz > sizeof (buf)) { 129*7c478bd9Sstevel@tonic-gate char *b = malloc(sz + 1); 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate if (b != NULL) { 132*7c478bd9Sstevel@tonic-gate va_start(args, fmt); 133*7c478bd9Sstevel@tonic-gate sz = vsnprintf(b, sz + 1, fmt, args); 134*7c478bd9Sstevel@tonic-gate va_end(args); 135*7c478bd9Sstevel@tonic-gate if (sz > 0) 136*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, _("%s"), b); 137*7c478bd9Sstevel@tonic-gate free(b); 138*7c478bd9Sstevel@tonic-gate } 139*7c478bd9Sstevel@tonic-gate } else { 140*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_TRACE1, _("%s"), buf); 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate } 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate /* 145*7c478bd9Sstevel@tonic-gate * CACHE MANAGEMENT 146*7c478bd9Sstevel@tonic-gate * Resources managed by this module are stored in a list of rsrc_t 147*7c478bd9Sstevel@tonic-gate * structures. 148*7c478bd9Sstevel@tonic-gate */ 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate /* 151*7c478bd9Sstevel@tonic-gate * cache_lookup() 152*7c478bd9Sstevel@tonic-gate * 153*7c478bd9Sstevel@tonic-gate * Get a cache node for a resource. Call with cache lock held. 154*7c478bd9Sstevel@tonic-gate */ 155*7c478bd9Sstevel@tonic-gate static rsrc_t * 156*7c478bd9Sstevel@tonic-gate cache_lookup(const char *resource) 157*7c478bd9Sstevel@tonic-gate { 158*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc; 159*7c478bd9Sstevel@tonic-gate rsrc = cache_head.next; 160*7c478bd9Sstevel@tonic-gate while (rsrc != &cache_tail) { 161*7c478bd9Sstevel@tonic-gate if (rsrc->id && strcmp(resource, rsrc->id) == 0) { 162*7c478bd9Sstevel@tonic-gate return (rsrc); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate rsrc = rsrc->next; 165*7c478bd9Sstevel@tonic-gate } 166*7c478bd9Sstevel@tonic-gate return (NULL); 167*7c478bd9Sstevel@tonic-gate } 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate /* 170*7c478bd9Sstevel@tonic-gate * Get a cache node for a minor node. Call with cache lock held. 171*7c478bd9Sstevel@tonic-gate */ 172*7c478bd9Sstevel@tonic-gate static rsrc_t * 173*7c478bd9Sstevel@tonic-gate cache_lookup_bydevt(dev_t devt) 174*7c478bd9Sstevel@tonic-gate { 175*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc; 176*7c478bd9Sstevel@tonic-gate rsrc = cache_head.next; 177*7c478bd9Sstevel@tonic-gate while (rsrc != &cache_tail) { 178*7c478bd9Sstevel@tonic-gate if (rsrc->dev == devt) 179*7c478bd9Sstevel@tonic-gate return (rsrc); 180*7c478bd9Sstevel@tonic-gate rsrc = rsrc->next; 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate return (NULL); 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate /* 186*7c478bd9Sstevel@tonic-gate * free_node() 187*7c478bd9Sstevel@tonic-gate * 188*7c478bd9Sstevel@tonic-gate * Free a node. Make sure it isn't in the list! 189*7c478bd9Sstevel@tonic-gate */ 190*7c478bd9Sstevel@tonic-gate static void 191*7c478bd9Sstevel@tonic-gate free_node(rsrc_t *node) 192*7c478bd9Sstevel@tonic-gate { 193*7c478bd9Sstevel@tonic-gate if (node) { 194*7c478bd9Sstevel@tonic-gate if (node->id) { 195*7c478bd9Sstevel@tonic-gate free(node->id); 196*7c478bd9Sstevel@tonic-gate } 197*7c478bd9Sstevel@tonic-gate free(node); 198*7c478bd9Sstevel@tonic-gate } 199*7c478bd9Sstevel@tonic-gate } 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate /* 202*7c478bd9Sstevel@tonic-gate * cache_insert() 203*7c478bd9Sstevel@tonic-gate * 204*7c478bd9Sstevel@tonic-gate * Call with the cache_lock held. 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate static void 207*7c478bd9Sstevel@tonic-gate cache_insert(rsrc_t *node) 208*7c478bd9Sstevel@tonic-gate { 209*7c478bd9Sstevel@tonic-gate /* insert at the head for best performance */ 210*7c478bd9Sstevel@tonic-gate node->next = cache_head.next; 211*7c478bd9Sstevel@tonic-gate node->prev = &cache_head; 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate node->next->prev = node; 214*7c478bd9Sstevel@tonic-gate node->prev->next = node; 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* 218*7c478bd9Sstevel@tonic-gate * cache_create() 219*7c478bd9Sstevel@tonic-gate * 220*7c478bd9Sstevel@tonic-gate * Call with the cache_lock held. 221*7c478bd9Sstevel@tonic-gate */ 222*7c478bd9Sstevel@tonic-gate static rsrc_t * 223*7c478bd9Sstevel@tonic-gate cache_create(const char *resource, dev_t dev) 224*7c478bd9Sstevel@tonic-gate { 225*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc = malloc(sizeof (rsrc_t)); 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate if (rsrc != NULL) { 228*7c478bd9Sstevel@tonic-gate if ((rsrc->id = strdup(resource)) != NULL) { 229*7c478bd9Sstevel@tonic-gate rsrc->dev = dev; 230*7c478bd9Sstevel@tonic-gate rsrc->flags = 0; 231*7c478bd9Sstevel@tonic-gate rsrc->dependencies = NULL; 232*7c478bd9Sstevel@tonic-gate cache_insert(rsrc); 233*7c478bd9Sstevel@tonic-gate } else { 234*7c478bd9Sstevel@tonic-gate free(rsrc); 235*7c478bd9Sstevel@tonic-gate rsrc = NULL; 236*7c478bd9Sstevel@tonic-gate } 237*7c478bd9Sstevel@tonic-gate } else { 238*7c478bd9Sstevel@tonic-gate _msg(0, ("TTYMUX: malloc failure for resource %s.\n", 239*7c478bd9Sstevel@tonic-gate resource)); 240*7c478bd9Sstevel@tonic-gate } 241*7c478bd9Sstevel@tonic-gate return (rsrc); 242*7c478bd9Sstevel@tonic-gate } 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate /* 245*7c478bd9Sstevel@tonic-gate * cache_get() 246*7c478bd9Sstevel@tonic-gate * 247*7c478bd9Sstevel@tonic-gate * Call with the cache_lock held. 248*7c478bd9Sstevel@tonic-gate */ 249*7c478bd9Sstevel@tonic-gate static rsrc_t * 250*7c478bd9Sstevel@tonic-gate cache_get(const char *resource) 251*7c478bd9Sstevel@tonic-gate { 252*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc = cache_lookup(resource); 253*7c478bd9Sstevel@tonic-gate if (rsrc == NULL) { 254*7c478bd9Sstevel@tonic-gate dev_t dev; 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate (void) get_devpath((char *)resource, NULL, &dev); 257*7c478bd9Sstevel@tonic-gate rsrc = cache_create(resource, dev); 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate return (rsrc); 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate /* 263*7c478bd9Sstevel@tonic-gate * cache_remove() 264*7c478bd9Sstevel@tonic-gate * 265*7c478bd9Sstevel@tonic-gate * Call with the cache_lock held. 266*7c478bd9Sstevel@tonic-gate */ 267*7c478bd9Sstevel@tonic-gate static void 268*7c478bd9Sstevel@tonic-gate cache_remove(rsrc_t *node) 269*7c478bd9Sstevel@tonic-gate { 270*7c478bd9Sstevel@tonic-gate node->next->prev = node->prev; 271*7c478bd9Sstevel@tonic-gate node->prev->next = node->next; 272*7c478bd9Sstevel@tonic-gate node->next = NULL; 273*7c478bd9Sstevel@tonic-gate node->prev = NULL; 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate /* 277*7c478bd9Sstevel@tonic-gate * Open a file identified by fname with the given open flags. 278*7c478bd9Sstevel@tonic-gate * If the request is to open a file with exclusive access and the open 279*7c478bd9Sstevel@tonic-gate * fails then backoff exponentially and then retry the open. 280*7c478bd9Sstevel@tonic-gate * Do not wait for longer than about a second (since this may be an rcm 281*7c478bd9Sstevel@tonic-gate * framework thread). 282*7c478bd9Sstevel@tonic-gate */ 283*7c478bd9Sstevel@tonic-gate static int 284*7c478bd9Sstevel@tonic-gate open_file(char *fname, int flags) 285*7c478bd9Sstevel@tonic-gate { 286*7c478bd9Sstevel@tonic-gate int fd, cnt; 287*7c478bd9Sstevel@tonic-gate struct timespec ts; 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate if ((flags & O_EXCL) == 0) 290*7c478bd9Sstevel@tonic-gate return (open(fname, flags)); 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate ts.tv_sec = 0; 293*7c478bd9Sstevel@tonic-gate ts.tv_nsec = 16000000; /* 16 milliseconds */ 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < 5 && (fd = open(fname, flags)) == -1; cnt++) { 296*7c478bd9Sstevel@tonic-gate (void) nanosleep(&ts, NULL); 297*7c478bd9Sstevel@tonic-gate ts.tv_nsec *= 2; 298*7c478bd9Sstevel@tonic-gate } 299*7c478bd9Sstevel@tonic-gate return (fd); 300*7c478bd9Sstevel@tonic-gate } 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate /* 303*7c478bd9Sstevel@tonic-gate * No-op for creating an association between a pair of resources. 304*7c478bd9Sstevel@tonic-gate */ 305*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 306*7c478bd9Sstevel@tonic-gate static int 307*7c478bd9Sstevel@tonic-gate nullconnect(link_t *link) 308*7c478bd9Sstevel@tonic-gate { 309*7c478bd9Sstevel@tonic-gate return (0); 310*7c478bd9Sstevel@tonic-gate } 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate /* 313*7c478bd9Sstevel@tonic-gate * No-op for destroying an association between a pair of resources. 314*7c478bd9Sstevel@tonic-gate */ 315*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 316*7c478bd9Sstevel@tonic-gate static int 317*7c478bd9Sstevel@tonic-gate nulldisconnect(link_t *link) 318*7c478bd9Sstevel@tonic-gate { 319*7c478bd9Sstevel@tonic-gate return (0); 320*7c478bd9Sstevel@tonic-gate } 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate /* 323*7c478bd9Sstevel@tonic-gate * Record an actual or desired association between two resources 324*7c478bd9Sstevel@tonic-gate * identified by their rsrc_t structures. 325*7c478bd9Sstevel@tonic-gate */ 326*7c478bd9Sstevel@tonic-gate static link_t * 327*7c478bd9Sstevel@tonic-gate add_dependency(rsrc_t *user, rsrc_t *used) 328*7c478bd9Sstevel@tonic-gate { 329*7c478bd9Sstevel@tonic-gate link_t *linkhead; 330*7c478bd9Sstevel@tonic-gate link_t *link; 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate if (user == NULL || used == NULL) 333*7c478bd9Sstevel@tonic-gate return (NULL); 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate if (user->id && used->id && strcmp(user->id, used->id) == 0) { 336*7c478bd9Sstevel@tonic-gate _msg(2, ("TTYMUX: attempt to connect devices created by " 337*7c478bd9Sstevel@tonic-gate "the same driver\n")); 338*7c478bd9Sstevel@tonic-gate return (NULL); 339*7c478bd9Sstevel@tonic-gate } 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate /* 342*7c478bd9Sstevel@tonic-gate * Search for all resources that this resource user is depending 343*7c478bd9Sstevel@tonic-gate * upon. 344*7c478bd9Sstevel@tonic-gate */ 345*7c478bd9Sstevel@tonic-gate linkhead = user->dependencies; 346*7c478bd9Sstevel@tonic-gate for (link = linkhead; link != NULL; link = link->next) { 347*7c478bd9Sstevel@tonic-gate /* 348*7c478bd9Sstevel@tonic-gate * Does the using resource already depends on the used 349*7c478bd9Sstevel@tonic-gate * resource 350*7c478bd9Sstevel@tonic-gate */ 351*7c478bd9Sstevel@tonic-gate if (link->used == used) 352*7c478bd9Sstevel@tonic-gate return (link); 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate link = malloc(sizeof (link_t)); 356*7c478bd9Sstevel@tonic-gate 357*7c478bd9Sstevel@tonic-gate if (link == NULL) { 358*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, _("TTYMUX: Out of memory\n")); 359*7c478bd9Sstevel@tonic-gate return (NULL); 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: New link user %s used %s\n", user->id, used->id)); 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate link->user = user; 365*7c478bd9Sstevel@tonic-gate link->used = used; 366*7c478bd9Sstevel@tonic-gate link->linkid = 0; 367*7c478bd9Sstevel@tonic-gate link->state = UNKNOWN; 368*7c478bd9Sstevel@tonic-gate link->flags = 0; 369*7c478bd9Sstevel@tonic-gate 370*7c478bd9Sstevel@tonic-gate link->connect = nullconnect; 371*7c478bd9Sstevel@tonic-gate link->disconnect = nulldisconnect; 372*7c478bd9Sstevel@tonic-gate link->next = linkhead; 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate user->dependencies = link; 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate return (link); 377*7c478bd9Sstevel@tonic-gate } 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate /* 380*7c478bd9Sstevel@tonic-gate * Send an I_STR stream ioctl to a device 381*7c478bd9Sstevel@tonic-gate */ 382*7c478bd9Sstevel@tonic-gate static int 383*7c478bd9Sstevel@tonic-gate istrioctl(int fd, int cmd, void *data, int datalen, int *bytes) { 384*7c478bd9Sstevel@tonic-gate struct strioctl ios; 385*7c478bd9Sstevel@tonic-gate int rval; 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate ios.ic_timout = 0; /* use the default */ 388*7c478bd9Sstevel@tonic-gate ios.ic_cmd = cmd; 389*7c478bd9Sstevel@tonic-gate ios.ic_dp = (char *)data; 390*7c478bd9Sstevel@tonic-gate ios.ic_len = datalen; 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate rval = ioctl(fd, I_STR, (char *)&ios); 393*7c478bd9Sstevel@tonic-gate if (bytes) 394*7c478bd9Sstevel@tonic-gate *bytes = ios.ic_len; 395*7c478bd9Sstevel@tonic-gate return (rval); 396*7c478bd9Sstevel@tonic-gate } 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate /* 399*7c478bd9Sstevel@tonic-gate * Streams link the driver identified by fd underneath a mux 400*7c478bd9Sstevel@tonic-gate * identified by ctrl_fd. 401*7c478bd9Sstevel@tonic-gate */ 402*7c478bd9Sstevel@tonic-gate static int 403*7c478bd9Sstevel@tonic-gate plink(int ctrl_fd, int fd) 404*7c478bd9Sstevel@tonic-gate { 405*7c478bd9Sstevel@tonic-gate int linkid; 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate /* 408*7c478bd9Sstevel@tonic-gate * pop any modules off the lower stream. 409*7c478bd9Sstevel@tonic-gate */ 410*7c478bd9Sstevel@tonic-gate while (ioctl(fd, I_POP, 0) == 0) 411*7c478bd9Sstevel@tonic-gate ; 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate if ((linkid = ioctl(ctrl_fd, I_PLINK, fd)) < 0) 414*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 415*7c478bd9Sstevel@tonic-gate _("TTYMUX: I_PLINK error %d.\n"), errno); 416*7c478bd9Sstevel@tonic-gate return (linkid); 417*7c478bd9Sstevel@tonic-gate } 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate /* 420*7c478bd9Sstevel@tonic-gate * Streams unlink the STREAM identified by linkid from a mux 421*7c478bd9Sstevel@tonic-gate * identified by ctrl_fd. 422*7c478bd9Sstevel@tonic-gate */ 423*7c478bd9Sstevel@tonic-gate static int 424*7c478bd9Sstevel@tonic-gate punlink(int ctrl_fd, int linkid) 425*7c478bd9Sstevel@tonic-gate { 426*7c478bd9Sstevel@tonic-gate if (ioctl(ctrl_fd, I_PUNLINK, linkid) < 0) 427*7c478bd9Sstevel@tonic-gate return (errno); 428*7c478bd9Sstevel@tonic-gate else 429*7c478bd9Sstevel@tonic-gate return (0); 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate /* 433*7c478bd9Sstevel@tonic-gate * Connect a pair of resources by establishing the dependency association. 434*7c478bd9Sstevel@tonic-gate * Only works for devices that support the TTYMUX ioctls. 435*7c478bd9Sstevel@tonic-gate */ 436*7c478bd9Sstevel@tonic-gate static int 437*7c478bd9Sstevel@tonic-gate mux_connect(link_t *link) 438*7c478bd9Sstevel@tonic-gate { 439*7c478bd9Sstevel@tonic-gate int lfd; 440*7c478bd9Sstevel@tonic-gate int rv; 441*7c478bd9Sstevel@tonic-gate ttymux_assoc_t as; 442*7c478bd9Sstevel@tonic-gate uint8_t ioflags; 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: mux_connect (%ld:%ld<->%ld:%ld %s <-> %s\n", 445*7c478bd9Sstevel@tonic-gate major(link->user->dev), minor(link->user->dev), 446*7c478bd9Sstevel@tonic-gate major(link->used->dev), minor(link->used->dev), 447*7c478bd9Sstevel@tonic-gate link->user->id, link->used->id)); 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate _msg(12, ("TTYMUX: struct size = %d (plen %d)\n", 450*7c478bd9Sstevel@tonic-gate sizeof (as), PATH_MAX)); 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate if (link->user->dev == NODEV || link->used->dev == NODEV) { 453*7c478bd9Sstevel@tonic-gate /* 454*7c478bd9Sstevel@tonic-gate * One of the resources in the association is not 455*7c478bd9Sstevel@tonic-gate * present (wait for the online notification before 456*7c478bd9Sstevel@tonic-gate * attempting to establish the dependency association. 457*7c478bd9Sstevel@tonic-gate */ 458*7c478bd9Sstevel@tonic-gate return (EAGAIN); 459*7c478bd9Sstevel@tonic-gate } 460*7c478bd9Sstevel@tonic-gate if (major(link->user->dev) == major(link->used->dev)) { 461*7c478bd9Sstevel@tonic-gate _msg(2, ("TTYMUX: attempt to link devices created by " 462*7c478bd9Sstevel@tonic-gate "the same driver\n")); 463*7c478bd9Sstevel@tonic-gate return (EINVAL); 464*7c478bd9Sstevel@tonic-gate } 465*7c478bd9Sstevel@tonic-gate /* 466*7c478bd9Sstevel@tonic-gate * Explicitly check for attempts to plumb the system console - 467*7c478bd9Sstevel@tonic-gate * required becuase not all serial devices support the 468*7c478bd9Sstevel@tonic-gate * O_EXCL open flag. 469*7c478bd9Sstevel@tonic-gate */ 470*7c478bd9Sstevel@tonic-gate if (link->used->dev == cn_dev) { 471*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, _("TTYMUX: Request to link the " 472*7c478bd9Sstevel@tonic-gate " system console under another device not allowed!\n")); 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate return (EPERM); 475*7c478bd9Sstevel@tonic-gate } 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate /* 478*7c478bd9Sstevel@tonic-gate * Ensure that the input/output mode of the dependent is reasonable 479*7c478bd9Sstevel@tonic-gate */ 480*7c478bd9Sstevel@tonic-gate if ((ioflags = link->flags & FORIO) == 0) 481*7c478bd9Sstevel@tonic-gate ioflags = FORIO; 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate /* 484*7c478bd9Sstevel@tonic-gate * Open each resource participating in the association. 485*7c478bd9Sstevel@tonic-gate */ 486*7c478bd9Sstevel@tonic-gate lfd = open(link->used->id, O_EXCL|O_RDWR|O_NONBLOCK|O_NOCTTY); 487*7c478bd9Sstevel@tonic-gate if (lfd == -1) { 488*7c478bd9Sstevel@tonic-gate if (errno == EBUSY) { 489*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, _("TTYMUX: device %s is " 490*7c478bd9Sstevel@tonic-gate " busy - " " cannot connect to %s\n"), 491*7c478bd9Sstevel@tonic-gate link->used->id, link->user->id); 492*7c478bd9Sstevel@tonic-gate } else { 493*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, 494*7c478bd9Sstevel@tonic-gate _("TTYMUX: open error %d for device %s\n"), 495*7c478bd9Sstevel@tonic-gate errno, link->used->id); 496*7c478bd9Sstevel@tonic-gate } 497*7c478bd9Sstevel@tonic-gate return (errno); 498*7c478bd9Sstevel@tonic-gate } 499*7c478bd9Sstevel@tonic-gate /* 500*7c478bd9Sstevel@tonic-gate * Note: Issuing the I_PLINK and TTYMUX_ASSOC request on the 'using' 501*7c478bd9Sstevel@tonic-gate * resource is more generic: 502*7c478bd9Sstevel@tonic-gate * muxfd = open(link->user->id, oflags); 503*7c478bd9Sstevel@tonic-gate * However using the ctl (MUXCTLLINK) node means that any current opens 504*7c478bd9Sstevel@tonic-gate * on the 'using' resource are uneffected. 505*7c478bd9Sstevel@tonic-gate */ 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate /* 508*7c478bd9Sstevel@tonic-gate * Figure out if the 'used' resource is already associated with 509*7c478bd9Sstevel@tonic-gate * some resource - if so tell the caller to try again later. 510*7c478bd9Sstevel@tonic-gate * More generally if any user or kernel thread has the resource 511*7c478bd9Sstevel@tonic-gate * open then the association should not be made. 512*7c478bd9Sstevel@tonic-gate * The ttymux driver makes this check (but it should be done here). 513*7c478bd9Sstevel@tonic-gate */ 514*7c478bd9Sstevel@tonic-gate as.ttymux_linkid = 0; 515*7c478bd9Sstevel@tonic-gate as.ttymux_ldev = link->used->dev; 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate if (istrioctl(muxfd, TTYMUX_GETLINK, 518*7c478bd9Sstevel@tonic-gate (void *)&as, sizeof (as), NULL) == 0) { 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate _msg(7, ("TTYMUX: %ld:%ld (%d) (udev %ld:%ld) already linked\n", 521*7c478bd9Sstevel@tonic-gate major(as.ttymux_ldev), minor(as.ttymux_ldev), 522*7c478bd9Sstevel@tonic-gate as.ttymux_linkid, major(as.ttymux_udev), 523*7c478bd9Sstevel@tonic-gate minor(as.ttymux_udev))); 524*7c478bd9Sstevel@tonic-gate link->linkid = as.ttymux_linkid; 525*7c478bd9Sstevel@tonic-gate if (as.ttymux_udev != NODEV) { 526*7c478bd9Sstevel@tonic-gate (void) close(lfd); 527*7c478bd9Sstevel@tonic-gate return (EAGAIN); 528*7c478bd9Sstevel@tonic-gate } 529*7c478bd9Sstevel@tonic-gate } 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate /* 532*7c478bd9Sstevel@tonic-gate * Now link and associate the used resource under the using resource. 533*7c478bd9Sstevel@tonic-gate */ 534*7c478bd9Sstevel@tonic-gate as.ttymux_udev = link->user->dev; 535*7c478bd9Sstevel@tonic-gate as.ttymux_ldev = link->used->dev; 536*7c478bd9Sstevel@tonic-gate as.ttymux_tag = 0ul; 537*7c478bd9Sstevel@tonic-gate as.ttymux_ioflag = ioflags; 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: connecting %ld:%ld to %ld:%ld\n", 540*7c478bd9Sstevel@tonic-gate major(as.ttymux_ldev), minor(as.ttymux_ldev), 541*7c478bd9Sstevel@tonic-gate major(as.ttymux_udev), minor(as.ttymux_udev))); 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate if (as.ttymux_udev == cn_dev) { 544*7c478bd9Sstevel@tonic-gate struct termios tc; 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate if (ioctl(lfd, TCGETS, &tc) != -1) { 547*7c478bd9Sstevel@tonic-gate tc.c_cflag |= CREAD; 548*7c478bd9Sstevel@tonic-gate if (ioctl(lfd, TCSETSW, &tc) == -1) { 549*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, 550*7c478bd9Sstevel@tonic-gate _("TTYMUX: error %d whilst enabling the " 551*7c478bd9Sstevel@tonic-gate "receiver on device %d:%d\n"), 552*7c478bd9Sstevel@tonic-gate errno, major(as.ttymux_ldev), 553*7c478bd9Sstevel@tonic-gate minor(as.ttymux_ldev)); 554*7c478bd9Sstevel@tonic-gate } 555*7c478bd9Sstevel@tonic-gate } 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate if (as.ttymux_linkid <= 0 && (as.ttymux_linkid = 559*7c478bd9Sstevel@tonic-gate plink(muxfd, lfd)) <= 0) { 560*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, 561*7c478bd9Sstevel@tonic-gate _("TTYMUX: Link error %d for device %s\n"), 562*7c478bd9Sstevel@tonic-gate errno, link->used->id); 563*7c478bd9Sstevel@tonic-gate rv = errno; 564*7c478bd9Sstevel@tonic-gate goto out; 565*7c478bd9Sstevel@tonic-gate } 566*7c478bd9Sstevel@tonic-gate link->linkid = as.ttymux_linkid; 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: associating\n")); 569*7c478bd9Sstevel@tonic-gate if (istrioctl(muxfd, TTYMUX_ASSOC, (void *)&as, sizeof (as), 0) != 0) { 570*7c478bd9Sstevel@tonic-gate rv = errno; 571*7c478bd9Sstevel@tonic-gate goto out; 572*7c478bd9Sstevel@tonic-gate } 573*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: Succesfully connected %ld:%ld to %ld:%ld\n", 574*7c478bd9Sstevel@tonic-gate major(as.ttymux_ldev), minor(as.ttymux_ldev), 575*7c478bd9Sstevel@tonic-gate major(as.ttymux_udev), minor(as.ttymux_udev))); 576*7c478bd9Sstevel@tonic-gate link->state = CONNECTED; 577*7c478bd9Sstevel@tonic-gate (void) close(lfd); 578*7c478bd9Sstevel@tonic-gate return (0); 579*7c478bd9Sstevel@tonic-gate out: 580*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, 581*7c478bd9Sstevel@tonic-gate _("TTYMUX: Error [%d] connecting %d:%d to %d:%d\n"), 582*7c478bd9Sstevel@tonic-gate rv, major(as.ttymux_ldev), minor(as.ttymux_ldev), 583*7c478bd9Sstevel@tonic-gate major(as.ttymux_udev), minor(as.ttymux_udev)); 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate (void) close(lfd); 586*7c478bd9Sstevel@tonic-gate if (as.ttymux_linkid > 0) { 587*7c478bd9Sstevel@tonic-gate /* 588*7c478bd9Sstevel@tonic-gate * There was an error so unwind the I_PLINK step 589*7c478bd9Sstevel@tonic-gate */ 590*7c478bd9Sstevel@tonic-gate if (punlink(muxfd, as.ttymux_linkid) != 0) 591*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, 592*7c478bd9Sstevel@tonic-gate _("TTYMUX: Unlink error %d (%s).\n"), 593*7c478bd9Sstevel@tonic-gate errno, link->used->id); 594*7c478bd9Sstevel@tonic-gate } 595*7c478bd9Sstevel@tonic-gate return (rv); 596*7c478bd9Sstevel@tonic-gate } 597*7c478bd9Sstevel@tonic-gate 598*7c478bd9Sstevel@tonic-gate /* 599*7c478bd9Sstevel@tonic-gate * Disconnect a pair of resources by destroying the dependency association. 600*7c478bd9Sstevel@tonic-gate * Only works for devices that support the TTYMUX ioctls. 601*7c478bd9Sstevel@tonic-gate */ 602*7c478bd9Sstevel@tonic-gate static int 603*7c478bd9Sstevel@tonic-gate mux_disconnect(link_t *link) 604*7c478bd9Sstevel@tonic-gate { 605*7c478bd9Sstevel@tonic-gate int rv; 606*7c478bd9Sstevel@tonic-gate ttymux_assoc_t as; 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: mux_disconnect %s<->%s (%ld:%ld<->%ld:%ld)\n", 609*7c478bd9Sstevel@tonic-gate link->user->id, link->used->id, 610*7c478bd9Sstevel@tonic-gate major(link->user->dev), minor(link->user->dev), 611*7c478bd9Sstevel@tonic-gate major(link->used->dev), minor(link->used->dev))); 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate as.ttymux_ldev = link->used->dev; 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate if (istrioctl(muxfd, TTYMUX_GETLINK, 616*7c478bd9Sstevel@tonic-gate (void *)&as, sizeof (as), NULL) != 0) { 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate _msg(1, ("TTYMUX: %ld:%ld not linked [err %d]\n", 619*7c478bd9Sstevel@tonic-gate major(link->used->dev), minor(link->used->dev), errno)); 620*7c478bd9Sstevel@tonic-gate return (0); 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate /* 623*7c478bd9Sstevel@tonic-gate * Do not disassociate console resources - simply 624*7c478bd9Sstevel@tonic-gate * unlink them so that they remain persistent. 625*7c478bd9Sstevel@tonic-gate */ 626*7c478bd9Sstevel@tonic-gate } else if (as.ttymux_udev != cn_dev && 627*7c478bd9Sstevel@tonic-gate istrioctl(muxfd, TTYMUX_DISASSOC, (void *)&as, 628*7c478bd9Sstevel@tonic-gate sizeof (as), 0) == -1) { 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate rv = errno; 631*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, 632*7c478bd9Sstevel@tonic-gate _("TTYMUX: Dissassociate error %d for %s\n"), 633*7c478bd9Sstevel@tonic-gate rv, link->used->id); 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate } else if (punlink(muxfd, as.ttymux_linkid) != 0) { 636*7c478bd9Sstevel@tonic-gate rv = errno; 637*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, 638*7c478bd9Sstevel@tonic-gate _("TTYMUX: Error %d unlinking %d:%d\n"), 639*7c478bd9Sstevel@tonic-gate errno, major(link->used->dev), minor(link->used->dev)); 640*7c478bd9Sstevel@tonic-gate } else { 641*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: %s<->%s disconnected.\n", 642*7c478bd9Sstevel@tonic-gate link->user->id, link->used->id)); 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate link->state = DISCONNECTED; 645*7c478bd9Sstevel@tonic-gate link->linkid = 0; 646*7c478bd9Sstevel@tonic-gate rv = 0; 647*7c478bd9Sstevel@tonic-gate } 648*7c478bd9Sstevel@tonic-gate return (rv); 649*7c478bd9Sstevel@tonic-gate } 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate /* PESISTENCY */ 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate /* 654*7c478bd9Sstevel@tonic-gate * Given a special device file system path return the /devices path 655*7c478bd9Sstevel@tonic-gate * and/or the device number (dev_t) of the device. 656*7c478bd9Sstevel@tonic-gate */ 657*7c478bd9Sstevel@tonic-gate static int 658*7c478bd9Sstevel@tonic-gate get_devpath(char *dev, char **cname, dev_t *devt) 659*7c478bd9Sstevel@tonic-gate { 660*7c478bd9Sstevel@tonic-gate struct stat sb; 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate if (cname != NULL) 663*7c478bd9Sstevel@tonic-gate *cname = NULL; 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate if (devt != NULL) 666*7c478bd9Sstevel@tonic-gate *devt = NODEV; 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate if (lstat(dev, &sb) < 0) { 669*7c478bd9Sstevel@tonic-gate return (errno); 670*7c478bd9Sstevel@tonic-gate } else if ((sb.st_mode & S_IFMT) == S_IFLNK) { 671*7c478bd9Sstevel@tonic-gate int lsz; 672*7c478bd9Sstevel@tonic-gate char linkbuf[PATH_MAX+1]; 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate if (stat(dev, &sb) < 0) 675*7c478bd9Sstevel@tonic-gate return (errno); 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate lsz = readlink(dev, linkbuf, PATH_MAX); 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate if (lsz <= 0) 680*7c478bd9Sstevel@tonic-gate return (ENODEV); 681*7c478bd9Sstevel@tonic-gate linkbuf[lsz] = '\0'; 682*7c478bd9Sstevel@tonic-gate dev = strstr(linkbuf, "/devices"); 683*7c478bd9Sstevel@tonic-gate if (dev == NULL) 684*7c478bd9Sstevel@tonic-gate return (ENODEV); 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate if (cname != NULL) 688*7c478bd9Sstevel@tonic-gate *cname = strdup(dev); 689*7c478bd9Sstevel@tonic-gate 690*7c478bd9Sstevel@tonic-gate if (devt != NULL) 691*7c478bd9Sstevel@tonic-gate *devt = sb.st_rdev; 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate return (0); 694*7c478bd9Sstevel@tonic-gate } 695*7c478bd9Sstevel@tonic-gate 696*7c478bd9Sstevel@tonic-gate /* 697*7c478bd9Sstevel@tonic-gate * See routine locate_node 698*7c478bd9Sstevel@tonic-gate */ 699*7c478bd9Sstevel@tonic-gate static int 700*7c478bd9Sstevel@tonic-gate locate_dev(di_node_t node, di_minor_t minor, void *arg) 701*7c478bd9Sstevel@tonic-gate { 702*7c478bd9Sstevel@tonic-gate char *devfspath; 703*7c478bd9Sstevel@tonic-gate char resource[PATH_MAX]; 704*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc; 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate if (di_minor_devt(minor) != (dev_t)arg) 707*7c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate if ((devfspath = di_devfs_path(node)) == NULL) 710*7c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate if (snprintf(resource, sizeof (resource), "/devices%s:%s", 713*7c478bd9Sstevel@tonic-gate devfspath, di_minor_name(minor)) > sizeof (resource)) { 714*7c478bd9Sstevel@tonic-gate di_devfs_path_free(devfspath); 715*7c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 716*7c478bd9Sstevel@tonic-gate } 717*7c478bd9Sstevel@tonic-gate 718*7c478bd9Sstevel@tonic-gate di_devfs_path_free(devfspath); 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate rsrc = cache_lookup(resource); 721*7c478bd9Sstevel@tonic-gate if (rsrc == NULL && 722*7c478bd9Sstevel@tonic-gate (rsrc = cache_create(resource, di_minor_devt(minor))) == NULL) 723*7c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate rsrc->dev = di_minor_devt(minor); 726*7c478bd9Sstevel@tonic-gate rsrc->flags |= PRESENT; 727*7c478bd9Sstevel@tonic-gate rsrc->flags &= ~UNKNOWN; 728*7c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 729*7c478bd9Sstevel@tonic-gate } 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate /* 732*7c478bd9Sstevel@tonic-gate * Find a devinfo node that matches the device argument (dev). 733*7c478bd9Sstevel@tonic-gate * This is an expensive search of the whole device tree! 734*7c478bd9Sstevel@tonic-gate */ 735*7c478bd9Sstevel@tonic-gate static rsrc_t * 736*7c478bd9Sstevel@tonic-gate locate_node(dev_t dev, di_node_t *root) 737*7c478bd9Sstevel@tonic-gate { 738*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc; 739*7c478bd9Sstevel@tonic-gate 740*7c478bd9Sstevel@tonic-gate assert(root != NULL); 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate if ((rsrc = cache_lookup_bydevt(dev)) != NULL) 743*7c478bd9Sstevel@tonic-gate return (rsrc); 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate (void) di_walk_minor(*root, NULL, 0, (void*)dev, locate_dev); 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate return (cache_lookup_bydevt(dev)); 748*7c478bd9Sstevel@tonic-gate } 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate /* 751*7c478bd9Sstevel@tonic-gate * Search for any existing dependency relationships managed by this 752*7c478bd9Sstevel@tonic-gate * RCM module. 753*7c478bd9Sstevel@tonic-gate */ 754*7c478bd9Sstevel@tonic-gate static int 755*7c478bd9Sstevel@tonic-gate probe_dependencies() 756*7c478bd9Sstevel@tonic-gate { 757*7c478bd9Sstevel@tonic-gate ttymux_assocs_t links; 758*7c478bd9Sstevel@tonic-gate ttymux_assoc_t *asp; 759*7c478bd9Sstevel@tonic-gate int cnt, n; 760*7c478bd9Sstevel@tonic-gate rsrc_t *ruser; 761*7c478bd9Sstevel@tonic-gate rsrc_t *used; 762*7c478bd9Sstevel@tonic-gate link_t *link; 763*7c478bd9Sstevel@tonic-gate di_node_t root; 764*7c478bd9Sstevel@tonic-gate 765*7c478bd9Sstevel@tonic-gate cnt = istrioctl(muxfd, TTYMUX_LIST, (void *)0, 0, 0); 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate _msg(8, ("TTYMUX: Probed %d links [%d]\n", cnt, errno)); 768*7c478bd9Sstevel@tonic-gate 769*7c478bd9Sstevel@tonic-gate if (cnt <= 0) 770*7c478bd9Sstevel@tonic-gate return (0); 771*7c478bd9Sstevel@tonic-gate 772*7c478bd9Sstevel@tonic-gate if ((links.ttymux_assocs = calloc(cnt, sizeof (ttymux_assoc_t))) == 0) 773*7c478bd9Sstevel@tonic-gate return (EAGAIN); 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate links.ttymux_nlinks = cnt; 776*7c478bd9Sstevel@tonic-gate 777*7c478bd9Sstevel@tonic-gate n = istrioctl(muxfd, TTYMUX_LIST, (void *)&links, sizeof (links), 0); 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate if (n == -1) { 780*7c478bd9Sstevel@tonic-gate _msg(2, ("TTYMUX: Probe error %s\n", strerror(errno))); 781*7c478bd9Sstevel@tonic-gate free(links.ttymux_assocs); 782*7c478bd9Sstevel@tonic-gate return (0); 783*7c478bd9Sstevel@tonic-gate } 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate asp = (ttymux_assoc_t *)links.ttymux_assocs; 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate if ((root = di_init("/", DINFOSUBTREE|DINFOMINOR)) == DI_NODE_NIL) 788*7c478bd9Sstevel@tonic-gate return (errno); 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&cache_lock); 791*7c478bd9Sstevel@tonic-gate for (; cnt--; asp++) { 792*7c478bd9Sstevel@tonic-gate _msg(7, ("TTYMUX: Probed: %ld %ld %ld:%ld <-> %ld:%ld\n", 793*7c478bd9Sstevel@tonic-gate asp->ttymux_udev, asp->ttymux_ldev, 794*7c478bd9Sstevel@tonic-gate major(asp->ttymux_udev), minor(asp->ttymux_udev), 795*7c478bd9Sstevel@tonic-gate major(asp->ttymux_ldev), minor(asp->ttymux_ldev))); 796*7c478bd9Sstevel@tonic-gate /* 797*7c478bd9Sstevel@tonic-gate * The TTYMUX_LIST ioctl can return links relating 798*7c478bd9Sstevel@tonic-gate * to potential devices. Such devices are identified 799*7c478bd9Sstevel@tonic-gate * in the path field. 800*7c478bd9Sstevel@tonic-gate */ 801*7c478bd9Sstevel@tonic-gate if (asp->ttymux_ldev == NODEV) { 802*7c478bd9Sstevel@tonic-gate char buf[PATH_MAX]; 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate if (asp->ttymux_path == NULL || 805*7c478bd9Sstevel@tonic-gate *asp->ttymux_path != '/') 806*7c478bd9Sstevel@tonic-gate continue; 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate if (snprintf(buf, sizeof (buf), "/devices%s", 809*7c478bd9Sstevel@tonic-gate asp->ttymux_path) > sizeof (buf)) 810*7c478bd9Sstevel@tonic-gate continue; 811*7c478bd9Sstevel@tonic-gate 812*7c478bd9Sstevel@tonic-gate used = cache_get(buf); 813*7c478bd9Sstevel@tonic-gate } else { 814*7c478bd9Sstevel@tonic-gate used = locate_node(asp->ttymux_ldev, &root); 815*7c478bd9Sstevel@tonic-gate } 816*7c478bd9Sstevel@tonic-gate if ((ruser = locate_node(asp->ttymux_udev, &root)) == NULL) { 817*7c478bd9Sstevel@tonic-gate _msg(7, ("TTYMUX: Probe: %ld:%ld not present\n", 818*7c478bd9Sstevel@tonic-gate major(asp->ttymux_udev), minor(asp->ttymux_udev))); 819*7c478bd9Sstevel@tonic-gate continue; 820*7c478bd9Sstevel@tonic-gate } 821*7c478bd9Sstevel@tonic-gate if (used == NULL) { 822*7c478bd9Sstevel@tonic-gate _msg(7, ("TTYMUX: Probe: %ld:%ld not present\n", 823*7c478bd9Sstevel@tonic-gate major(asp->ttymux_ldev), minor(asp->ttymux_ldev))); 824*7c478bd9Sstevel@tonic-gate continue; 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: Probe: Restore %s <-> %s (id %d)\n", 827*7c478bd9Sstevel@tonic-gate ruser->id, used->id, asp->ttymux_linkid)); 828*7c478bd9Sstevel@tonic-gate 829*7c478bd9Sstevel@tonic-gate link = add_dependency(ruser, used); 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate if (link != NULL) { 832*7c478bd9Sstevel@tonic-gate link->flags = (uint_t)asp->ttymux_ioflag; 833*7c478bd9Sstevel@tonic-gate link->linkid = asp->ttymux_linkid; 834*7c478bd9Sstevel@tonic-gate link->state = CONNECTED; 835*7c478bd9Sstevel@tonic-gate link->connect = mux_connect; 836*7c478bd9Sstevel@tonic-gate link->disconnect = mux_disconnect; 837*7c478bd9Sstevel@tonic-gate } 838*7c478bd9Sstevel@tonic-gate } 839*7c478bd9Sstevel@tonic-gate di_fini(root); 840*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock); 841*7c478bd9Sstevel@tonic-gate free(links.ttymux_assocs); 842*7c478bd9Sstevel@tonic-gate return (0); 843*7c478bd9Sstevel@tonic-gate } 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate /* 846*7c478bd9Sstevel@tonic-gate * A resource has become available. Re-establish any associations involving 847*7c478bd9Sstevel@tonic-gate * the resource. 848*7c478bd9Sstevel@tonic-gate */ 849*7c478bd9Sstevel@tonic-gate static int 850*7c478bd9Sstevel@tonic-gate rsrc_available(rsrc_t *rsrc) 851*7c478bd9Sstevel@tonic-gate { 852*7c478bd9Sstevel@tonic-gate link_t *link; 853*7c478bd9Sstevel@tonic-gate rsrc_t *rs; 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate if (rsrc->dev == NODEV) { 856*7c478bd9Sstevel@tonic-gate /* 857*7c478bd9Sstevel@tonic-gate * Now that the resource is present obtain its device number. 858*7c478bd9Sstevel@tonic-gate * For this to work the node must be present in the /devices 859*7c478bd9Sstevel@tonic-gate * tree (see devfsadm(1M) or drvconfig(1M)). 860*7c478bd9Sstevel@tonic-gate * We do not use libdevinfo because the node must be present 861*7c478bd9Sstevel@tonic-gate * under /devices for the connect step below to work 862*7c478bd9Sstevel@tonic-gate * (the node needs to be opened). 863*7c478bd9Sstevel@tonic-gate */ 864*7c478bd9Sstevel@tonic-gate (void) get_devpath(rsrc->id, NULL, &rsrc->dev); 865*7c478bd9Sstevel@tonic-gate if (rsrc->dev == NODEV) { 866*7c478bd9Sstevel@tonic-gate _msg(4, 867*7c478bd9Sstevel@tonic-gate ("Device node %s does not exist\n", rsrc->id)); 868*7c478bd9Sstevel@tonic-gate /* 869*7c478bd9Sstevel@tonic-gate * What does RCM do with failed online notifications. 870*7c478bd9Sstevel@tonic-gate */ 871*7c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 872*7c478bd9Sstevel@tonic-gate } 873*7c478bd9Sstevel@tonic-gate } 874*7c478bd9Sstevel@tonic-gate for (rs = cache_head.next; rs != &cache_tail; rs = rs->next) { 875*7c478bd9Sstevel@tonic-gate for (link = rs->dependencies; 876*7c478bd9Sstevel@tonic-gate link != NULL; 877*7c478bd9Sstevel@tonic-gate link = link->next) { 878*7c478bd9Sstevel@tonic-gate if (link->user == rsrc || link->used == rsrc) { 879*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: re-connect\n")); 880*7c478bd9Sstevel@tonic-gate (void) link->connect(link); 881*7c478bd9Sstevel@tonic-gate } 882*7c478bd9Sstevel@tonic-gate } 883*7c478bd9Sstevel@tonic-gate } 884*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 885*7c478bd9Sstevel@tonic-gate } 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate /* 888*7c478bd9Sstevel@tonic-gate * A resource is going away. Tear down any associations involving 889*7c478bd9Sstevel@tonic-gate * the resource. 890*7c478bd9Sstevel@tonic-gate */ 891*7c478bd9Sstevel@tonic-gate static int 892*7c478bd9Sstevel@tonic-gate rsrc_unavailable(rsrc_t *rsrc) 893*7c478bd9Sstevel@tonic-gate { 894*7c478bd9Sstevel@tonic-gate link_t *link; 895*7c478bd9Sstevel@tonic-gate rsrc_t *rs; 896*7c478bd9Sstevel@tonic-gate 897*7c478bd9Sstevel@tonic-gate for (rs = cache_head.next; rs != &cache_tail; rs = rs->next) { 898*7c478bd9Sstevel@tonic-gate for (link = rs->dependencies; 899*7c478bd9Sstevel@tonic-gate link != NULL; 900*7c478bd9Sstevel@tonic-gate link = link->next) { 901*7c478bd9Sstevel@tonic-gate if (link->user == rsrc || link->used == rsrc) { 902*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: unavailable %s %s\n", 903*7c478bd9Sstevel@tonic-gate link->user->id, link->used->id)); 904*7c478bd9Sstevel@tonic-gate (void) link->disconnect(link); 905*7c478bd9Sstevel@tonic-gate } 906*7c478bd9Sstevel@tonic-gate } 907*7c478bd9Sstevel@tonic-gate } 908*7c478bd9Sstevel@tonic-gate 909*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 910*7c478bd9Sstevel@tonic-gate } 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate /* 913*7c478bd9Sstevel@tonic-gate * Find any resources that are using a given resource (identified by 914*7c478bd9Sstevel@tonic-gate * the rsrc argument). The search begins after the resource identified 915*7c478bd9Sstevel@tonic-gate * by the next argument. If next is NULL start at the first resource 916*7c478bd9Sstevel@tonic-gate * in this RCM modules resource list. If the redundancy argument is 917*7c478bd9Sstevel@tonic-gate * greater than zero then a resource which uses rsrc will only be 918*7c478bd9Sstevel@tonic-gate * returned if it is associated with >= redundancy dependents. 919*7c478bd9Sstevel@tonic-gate * 920*7c478bd9Sstevel@tonic-gate * Thus, provided that the caller keeps the list locked he can iterate 921*7c478bd9Sstevel@tonic-gate * through all the resources in the cache that depend upon rsrc. 922*7c478bd9Sstevel@tonic-gate */ 923*7c478bd9Sstevel@tonic-gate static rsrc_t * 924*7c478bd9Sstevel@tonic-gate get_next_user(rsrc_t *next, rsrc_t *rsrc, int redundancy) 925*7c478bd9Sstevel@tonic-gate { 926*7c478bd9Sstevel@tonic-gate rsrc_t *src; 927*7c478bd9Sstevel@tonic-gate link_t *link; 928*7c478bd9Sstevel@tonic-gate int cnt = 0; 929*7c478bd9Sstevel@tonic-gate boolean_t inuse; 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate src = (next != NULL) ? next->next : cache_head.next; 932*7c478bd9Sstevel@tonic-gate 933*7c478bd9Sstevel@tonic-gate while (src != &cache_tail) { 934*7c478bd9Sstevel@tonic-gate inuse = B_FALSE; 935*7c478bd9Sstevel@tonic-gate 936*7c478bd9Sstevel@tonic-gate for (link = src->dependencies, cnt = 0; 937*7c478bd9Sstevel@tonic-gate link != NULL; 938*7c478bd9Sstevel@tonic-gate link = link->next) { 939*7c478bd9Sstevel@tonic-gate 940*7c478bd9Sstevel@tonic-gate if (link->state == CONNECTED) 941*7c478bd9Sstevel@tonic-gate cnt++; 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate if (link->used == rsrc) 944*7c478bd9Sstevel@tonic-gate inuse = B_TRUE; 945*7c478bd9Sstevel@tonic-gate } 946*7c478bd9Sstevel@tonic-gate if (inuse == B_TRUE && 947*7c478bd9Sstevel@tonic-gate (redundancy <= 0 || cnt == redundancy)) { 948*7c478bd9Sstevel@tonic-gate return (src); 949*7c478bd9Sstevel@tonic-gate } 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate src = src->next; 952*7c478bd9Sstevel@tonic-gate } 953*7c478bd9Sstevel@tonic-gate 954*7c478bd9Sstevel@tonic-gate _msg(8, ("TTYMUX: count_users(%s) res %d.\n", rsrc->id, cnt)); 955*7c478bd9Sstevel@tonic-gate return (NULL); 956*7c478bd9Sstevel@tonic-gate } 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate /* 959*7c478bd9Sstevel@tonic-gate * Common handler for RCM notifications. 960*7c478bd9Sstevel@tonic-gate */ 961*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 962*7c478bd9Sstevel@tonic-gate static int 963*7c478bd9Sstevel@tonic-gate rsrc_change_common(rcm_handle_t *hd, int op, const char *rsrcid, uint_t flag, 964*7c478bd9Sstevel@tonic-gate char **reason, rcm_info_t **dependent_reason, void *arg) 965*7c478bd9Sstevel@tonic-gate { 966*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc, *user; 967*7c478bd9Sstevel@tonic-gate int rv, len; 968*7c478bd9Sstevel@tonic-gate char *tmp = NULL; 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&cache_lock); 971*7c478bd9Sstevel@tonic-gate rsrc = cache_lookup(rsrcid); 972*7c478bd9Sstevel@tonic-gate if (rsrc == NULL) { 973*7c478bd9Sstevel@tonic-gate /* shouldn't happen because rsrc has been registered */ 974*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock); 975*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 976*7c478bd9Sstevel@tonic-gate } 977*7c478bd9Sstevel@tonic-gate if ((muxfd = open_file(muxctl, oflags)) == -1) { 978*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, _("TTYMUX: %s unavailable: %s\n"), 979*7c478bd9Sstevel@tonic-gate muxctl, strerror(errno)); 980*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock); 981*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 982*7c478bd9Sstevel@tonic-gate } 983*7c478bd9Sstevel@tonic-gate switch (op) { 984*7c478bd9Sstevel@tonic-gate 985*7c478bd9Sstevel@tonic-gate case TTYMUX_SUSPEND: 986*7c478bd9Sstevel@tonic-gate rv = RCM_FAILURE; 987*7c478bd9Sstevel@tonic-gate _msg(4, ("TTYMUX: SUSPEND %s operation refused.\n", 988*7c478bd9Sstevel@tonic-gate rsrc->id)); 989*7c478bd9Sstevel@tonic-gate if ((*reason = strdup(TTYMUX_INVALID_ERR)) == NULL) { 990*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, TTYMUX_MEMORY_ERR); 991*7c478bd9Sstevel@tonic-gate } 992*7c478bd9Sstevel@tonic-gate break; 993*7c478bd9Sstevel@tonic-gate 994*7c478bd9Sstevel@tonic-gate case TTYMUX_REMOVE: 995*7c478bd9Sstevel@tonic-gate rsrc->flags |= UNKNOWN; 996*7c478bd9Sstevel@tonic-gate rsrc->flags &= ~(PRESENT | REGISTERED); 997*7c478bd9Sstevel@tonic-gate rv = RCM_SUCCESS; 998*7c478bd9Sstevel@tonic-gate break; 999*7c478bd9Sstevel@tonic-gate 1000*7c478bd9Sstevel@tonic-gate case TTYMUX_OFFLINE: 1001*7c478bd9Sstevel@tonic-gate user = get_next_user(NULL, rsrc, 1); 1002*7c478bd9Sstevel@tonic-gate if (flag & RCM_QUERY) { 1003*7c478bd9Sstevel@tonic-gate rv = ((flag & RCM_FORCE) || (user == NULL)) ? 1004*7c478bd9Sstevel@tonic-gate RCM_SUCCESS : RCM_FAILURE; 1005*7c478bd9Sstevel@tonic-gate if (rv == RCM_FAILURE) { 1006*7c478bd9Sstevel@tonic-gate tmp = TTYMUX_OFFLINE_ERR; 1007*7c478bd9Sstevel@tonic-gate assert(tmp != NULL); 1008*7c478bd9Sstevel@tonic-gate len = strlen(tmp) + strlen(user->id) + 2; 1009*7c478bd9Sstevel@tonic-gate if ((*reason = (char *)malloc(len)) != NULL) { 1010*7c478bd9Sstevel@tonic-gate (void) snprintf(*reason, len, 1011*7c478bd9Sstevel@tonic-gate "%s %s", tmp, user->id); 1012*7c478bd9Sstevel@tonic-gate } else { 1013*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, TTYMUX_MEMORY_ERR); 1014*7c478bd9Sstevel@tonic-gate } 1015*7c478bd9Sstevel@tonic-gate } 1016*7c478bd9Sstevel@tonic-gate 1017*7c478bd9Sstevel@tonic-gate } else if (flag & RCM_FORCE) { 1018*7c478bd9Sstevel@tonic-gate rv = rsrc_unavailable(rsrc); 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate if (rv == RCM_FAILURE) { 1021*7c478bd9Sstevel@tonic-gate if ((*reason = strdup(TTYMUX_OFFLINE_FAIL)) == 1022*7c478bd9Sstevel@tonic-gate NULL) { 1023*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 1024*7c478bd9Sstevel@tonic-gate TTYMUX_MEMORY_ERR); 1025*7c478bd9Sstevel@tonic-gate } 1026*7c478bd9Sstevel@tonic-gate } 1027*7c478bd9Sstevel@tonic-gate 1028*7c478bd9Sstevel@tonic-gate } else if (user != NULL) { 1029*7c478bd9Sstevel@tonic-gate rv = RCM_FAILURE; 1030*7c478bd9Sstevel@tonic-gate tmp = TTYMUX_OFFLINE_ERR; 1031*7c478bd9Sstevel@tonic-gate assert(tmp != NULL); 1032*7c478bd9Sstevel@tonic-gate len = strlen(tmp) + strlen(user->id) + 2; 1033*7c478bd9Sstevel@tonic-gate if ((*reason = (char *)malloc(len)) != NULL) { 1034*7c478bd9Sstevel@tonic-gate (void) snprintf(*reason, len, 1035*7c478bd9Sstevel@tonic-gate "%s %s", tmp, user->id); 1036*7c478bd9Sstevel@tonic-gate } else { 1037*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, TTYMUX_MEMORY_ERR); 1038*7c478bd9Sstevel@tonic-gate } 1039*7c478bd9Sstevel@tonic-gate 1040*7c478bd9Sstevel@tonic-gate } else { 1041*7c478bd9Sstevel@tonic-gate rv = rsrc_unavailable(rsrc); 1042*7c478bd9Sstevel@tonic-gate if (rv == RCM_FAILURE) { 1043*7c478bd9Sstevel@tonic-gate if ((*reason = strdup(TTYMUX_OFFLINE_FAIL)) == 1044*7c478bd9Sstevel@tonic-gate NULL) { 1045*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, 1046*7c478bd9Sstevel@tonic-gate TTYMUX_MEMORY_ERR); 1047*7c478bd9Sstevel@tonic-gate } 1048*7c478bd9Sstevel@tonic-gate } 1049*7c478bd9Sstevel@tonic-gate } 1050*7c478bd9Sstevel@tonic-gate 1051*7c478bd9Sstevel@tonic-gate if (rv == RCM_FAILURE) { 1052*7c478bd9Sstevel@tonic-gate _msg(4, ("TTYMUX: OFFLINE %s operation refused.\n", 1053*7c478bd9Sstevel@tonic-gate rsrc->id)); 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate } else { 1056*7c478bd9Sstevel@tonic-gate _msg(4, ("TTYMUX: OFFLINE %s res %d.\n", rsrc->id, rv)); 1057*7c478bd9Sstevel@tonic-gate } 1058*7c478bd9Sstevel@tonic-gate break; 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate case TTYMUX_RESUME: 1061*7c478bd9Sstevel@tonic-gate rv = RCM_FAILURE; 1062*7c478bd9Sstevel@tonic-gate _msg(4, ("TTYMUX: RESUME %s operation refused.\n", 1063*7c478bd9Sstevel@tonic-gate rsrc->id)); 1064*7c478bd9Sstevel@tonic-gate if ((*reason = strdup(TTYMUX_INVALID_ERR)) == NULL) { 1065*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, TTYMUX_MEMORY_ERR); 1066*7c478bd9Sstevel@tonic-gate } 1067*7c478bd9Sstevel@tonic-gate break; 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate case TTYMUX_ONLINE: 1070*7c478bd9Sstevel@tonic-gate _msg(4, ("TTYMUX: ONLINE %s res %d.\n", rsrc->id, rv)); 1071*7c478bd9Sstevel@tonic-gate rv = rsrc_available(rsrc); 1072*7c478bd9Sstevel@tonic-gate if (rv == RCM_FAILURE) { 1073*7c478bd9Sstevel@tonic-gate if ((*reason = strdup(TTYMUX_ONLINE_ERR)) == NULL) { 1074*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, TTYMUX_MEMORY_ERR); 1075*7c478bd9Sstevel@tonic-gate } 1076*7c478bd9Sstevel@tonic-gate } 1077*7c478bd9Sstevel@tonic-gate break; 1078*7c478bd9Sstevel@tonic-gate default: 1079*7c478bd9Sstevel@tonic-gate rv = RCM_FAILURE; 1080*7c478bd9Sstevel@tonic-gate if ((*reason = strdup(TTYMUX_UNKNOWN_ERR)) == NULL) { 1081*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, TTYMUX_MEMORY_ERR); 1082*7c478bd9Sstevel@tonic-gate } 1083*7c478bd9Sstevel@tonic-gate } 1084*7c478bd9Sstevel@tonic-gate 1085*7c478bd9Sstevel@tonic-gate (void) close(muxfd); 1086*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock); 1087*7c478bd9Sstevel@tonic-gate return (rv); 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate 1090*7c478bd9Sstevel@tonic-gate static boolean_t 1091*7c478bd9Sstevel@tonic-gate find_mux_nodes(char *drv) 1092*7c478bd9Sstevel@tonic-gate { 1093*7c478bd9Sstevel@tonic-gate di_node_t root, node; 1094*7c478bd9Sstevel@tonic-gate di_minor_t dim; 1095*7c478bd9Sstevel@tonic-gate char *devfspath; 1096*7c478bd9Sstevel@tonic-gate char muxctlname[] = "ctl"; 1097*7c478bd9Sstevel@tonic-gate char muxconname[] = "con"; 1098*7c478bd9Sstevel@tonic-gate int nminors = 0; 1099*7c478bd9Sstevel@tonic-gate 1100*7c478bd9Sstevel@tonic-gate (void) strcpy(muxctl, MUXCTLLINK); 1101*7c478bd9Sstevel@tonic-gate (void) strcpy(muxcon, MUXCONLINK); 1102*7c478bd9Sstevel@tonic-gate cn_rsrc = NULL; 1103*7c478bd9Sstevel@tonic-gate 1104*7c478bd9Sstevel@tonic-gate if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 1105*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, _("di_init error\n")); 1106*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1107*7c478bd9Sstevel@tonic-gate } 1108*7c478bd9Sstevel@tonic-gate 1109*7c478bd9Sstevel@tonic-gate node = di_drv_first_node(drv, root); 1110*7c478bd9Sstevel@tonic-gate if (node == DI_NODE_NIL) { 1111*7c478bd9Sstevel@tonic-gate _msg(4, ("no node for %s\n", drv)); 1112*7c478bd9Sstevel@tonic-gate di_fini(root); 1113*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1114*7c478bd9Sstevel@tonic-gate } 1115*7c478bd9Sstevel@tonic-gate /* 1116*7c478bd9Sstevel@tonic-gate * If the device is not a prom node do not continue. 1117*7c478bd9Sstevel@tonic-gate */ 1118*7c478bd9Sstevel@tonic-gate if (di_nodeid(node) != DI_PROM_NODEID) { 1119*7c478bd9Sstevel@tonic-gate di_fini(root); 1120*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1121*7c478bd9Sstevel@tonic-gate } 1122*7c478bd9Sstevel@tonic-gate if ((devfspath = di_devfs_path(node)) == NULL) { 1123*7c478bd9Sstevel@tonic-gate di_fini(root); 1124*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1125*7c478bd9Sstevel@tonic-gate } 1126*7c478bd9Sstevel@tonic-gate 1127*7c478bd9Sstevel@tonic-gate /* 1128*7c478bd9Sstevel@tonic-gate * Loop through all the minor nodes the driver (drv) looking 1129*7c478bd9Sstevel@tonic-gate * for the ctl node (this is the device on which 1130*7c478bd9Sstevel@tonic-gate * to issue ioctls). 1131*7c478bd9Sstevel@tonic-gate */ 1132*7c478bd9Sstevel@tonic-gate dim = DI_MINOR_NIL; 1133*7c478bd9Sstevel@tonic-gate while ((dim = di_minor_next(node, dim)) != DI_MINOR_NIL) { 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate _msg(7, ("MUXNODES: minor %s\n", di_minor_name(dim))); 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate if (strcmp(di_minor_name(dim), muxctlname) == 0) { 1138*7c478bd9Sstevel@tonic-gate if (snprintf(muxctl, sizeof (muxctl), 1139*7c478bd9Sstevel@tonic-gate "/devices%s:%s", devfspath, 1140*7c478bd9Sstevel@tonic-gate di_minor_name(dim)) > sizeof (muxctl)) { 1141*7c478bd9Sstevel@tonic-gate _msg(1, ("muxctl:snprintf error\n")); 1142*7c478bd9Sstevel@tonic-gate } 1143*7c478bd9Sstevel@tonic-gate if (++nminors == 2) 1144*7c478bd9Sstevel@tonic-gate break; 1145*7c478bd9Sstevel@tonic-gate } else if (strcmp(di_minor_name(dim), muxconname) == 0) { 1146*7c478bd9Sstevel@tonic-gate if (snprintf(muxcon, sizeof (muxcon), 1147*7c478bd9Sstevel@tonic-gate "/devices%s:%s", devfspath, 1148*7c478bd9Sstevel@tonic-gate di_minor_name(dim)) > sizeof (muxcon)) { 1149*7c478bd9Sstevel@tonic-gate _msg(1, ("muxcon:snprintf error\n")); 1150*7c478bd9Sstevel@tonic-gate } 1151*7c478bd9Sstevel@tonic-gate if (++nminors == 2) 1152*7c478bd9Sstevel@tonic-gate break; 1153*7c478bd9Sstevel@tonic-gate } 1154*7c478bd9Sstevel@tonic-gate } 1155*7c478bd9Sstevel@tonic-gate 1156*7c478bd9Sstevel@tonic-gate di_devfs_path_free(devfspath); 1157*7c478bd9Sstevel@tonic-gate di_fini(root); 1158*7c478bd9Sstevel@tonic-gate 1159*7c478bd9Sstevel@tonic-gate if ((muxfd = open_file(muxctl, oflags)) != -1) { 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate if (istrioctl(muxfd, TTYMUX_CONSDEV, (void *)&cn_dev, 1162*7c478bd9Sstevel@tonic-gate sizeof (cn_dev), 0) != 0) { 1163*7c478bd9Sstevel@tonic-gate cn_dev = NODEV; 1164*7c478bd9Sstevel@tonic-gate } else { 1165*7c478bd9Sstevel@tonic-gate _msg(8, ("MUXNODES: found sys console: %ld:%ld\n", 1166*7c478bd9Sstevel@tonic-gate major(cn_dev), minor(cn_dev))); 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate cn_rsrc = cache_create(muxcon, cn_dev); 1169*7c478bd9Sstevel@tonic-gate if (cn_rsrc != NULL) { 1170*7c478bd9Sstevel@tonic-gate cn_rsrc->flags |= PRESENT; 1171*7c478bd9Sstevel@tonic-gate cn_rsrc->flags &= ~UNKNOWN; 1172*7c478bd9Sstevel@tonic-gate } 1173*7c478bd9Sstevel@tonic-gate } 1174*7c478bd9Sstevel@tonic-gate (void) close(muxfd); 1175*7c478bd9Sstevel@tonic-gate 1176*7c478bd9Sstevel@tonic-gate if (cn_dev != NODEV) 1177*7c478bd9Sstevel@tonic-gate return (B_TRUE); 1178*7c478bd9Sstevel@tonic-gate } else { 1179*7c478bd9Sstevel@tonic-gate _msg(1, ("TTYMUX: %s unavailable: %s\n", 1180*7c478bd9Sstevel@tonic-gate muxctl, strerror(errno))); 1181*7c478bd9Sstevel@tonic-gate } 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate return (B_FALSE); 1184*7c478bd9Sstevel@tonic-gate } 1185*7c478bd9Sstevel@tonic-gate 1186*7c478bd9Sstevel@tonic-gate /* 1187*7c478bd9Sstevel@tonic-gate * Update registrations, and return the ops structure. 1188*7c478bd9Sstevel@tonic-gate */ 1189*7c478bd9Sstevel@tonic-gate struct rcm_mod_ops * 1190*7c478bd9Sstevel@tonic-gate rcm_mod_init() 1191*7c478bd9Sstevel@tonic-gate { 1192*7c478bd9Sstevel@tonic-gate _msg(4, ("TTYMUX: mod_init:\n")); 1193*7c478bd9Sstevel@tonic-gate cache_head.next = &cache_tail; 1194*7c478bd9Sstevel@tonic-gate cache_head.prev = NULL; 1195*7c478bd9Sstevel@tonic-gate cache_tail.prev = &cache_head; 1196*7c478bd9Sstevel@tonic-gate cache_tail.next = NULL; 1197*7c478bd9Sstevel@tonic-gate (void) mutex_init(&cache_lock, NULL, NULL); 1198*7c478bd9Sstevel@tonic-gate 1199*7c478bd9Sstevel@tonic-gate /* 1200*7c478bd9Sstevel@tonic-gate * Find the multiplexer ctl and con nodes 1201*7c478bd9Sstevel@tonic-gate */ 1202*7c478bd9Sstevel@tonic-gate register_rsrcs = find_mux_nodes(TTYMUX_DRVNAME); 1203*7c478bd9Sstevel@tonic-gate 1204*7c478bd9Sstevel@tonic-gate return (&tty_ops); 1205*7c478bd9Sstevel@tonic-gate } 1206*7c478bd9Sstevel@tonic-gate 1207*7c478bd9Sstevel@tonic-gate /* 1208*7c478bd9Sstevel@tonic-gate * Save state and release resources. 1209*7c478bd9Sstevel@tonic-gate */ 1210*7c478bd9Sstevel@tonic-gate int 1211*7c478bd9Sstevel@tonic-gate rcm_mod_fini() 1212*7c478bd9Sstevel@tonic-gate { 1213*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc; 1214*7c478bd9Sstevel@tonic-gate link_t *link, *nlink; 1215*7c478bd9Sstevel@tonic-gate 1216*7c478bd9Sstevel@tonic-gate _msg(7, ("TTYMUX: freeing cache.\n")); 1217*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&cache_lock); 1218*7c478bd9Sstevel@tonic-gate rsrc = cache_head.next; 1219*7c478bd9Sstevel@tonic-gate while (rsrc != &cache_tail) { 1220*7c478bd9Sstevel@tonic-gate cache_remove(rsrc); 1221*7c478bd9Sstevel@tonic-gate 1222*7c478bd9Sstevel@tonic-gate for (link = rsrc->dependencies; link != NULL; ) { 1223*7c478bd9Sstevel@tonic-gate nlink = link->next; 1224*7c478bd9Sstevel@tonic-gate free(link); 1225*7c478bd9Sstevel@tonic-gate link = nlink; 1226*7c478bd9Sstevel@tonic-gate } 1227*7c478bd9Sstevel@tonic-gate 1228*7c478bd9Sstevel@tonic-gate free_node(rsrc); 1229*7c478bd9Sstevel@tonic-gate rsrc = cache_head.next; 1230*7c478bd9Sstevel@tonic-gate } 1231*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock); 1232*7c478bd9Sstevel@tonic-gate 1233*7c478bd9Sstevel@tonic-gate (void) mutex_destroy(&cache_lock); 1234*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 1235*7c478bd9Sstevel@tonic-gate } 1236*7c478bd9Sstevel@tonic-gate 1237*7c478bd9Sstevel@tonic-gate /* 1238*7c478bd9Sstevel@tonic-gate * Return a string describing this module. 1239*7c478bd9Sstevel@tonic-gate */ 1240*7c478bd9Sstevel@tonic-gate const char * 1241*7c478bd9Sstevel@tonic-gate rcm_mod_info() 1242*7c478bd9Sstevel@tonic-gate { 1243*7c478bd9Sstevel@tonic-gate return ("Serial mux device module 1.1"); 1244*7c478bd9Sstevel@tonic-gate } 1245*7c478bd9Sstevel@tonic-gate 1246*7c478bd9Sstevel@tonic-gate /* 1247*7c478bd9Sstevel@tonic-gate * RCM Notification Handlers 1248*7c478bd9Sstevel@tonic-gate */ 1249*7c478bd9Sstevel@tonic-gate 1250*7c478bd9Sstevel@tonic-gate static int 1251*7c478bd9Sstevel@tonic-gate tty_register(rcm_handle_t *hd) 1252*7c478bd9Sstevel@tonic-gate { 1253*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc; 1254*7c478bd9Sstevel@tonic-gate link_t *link; 1255*7c478bd9Sstevel@tonic-gate int rv; 1256*7c478bd9Sstevel@tonic-gate 1257*7c478bd9Sstevel@tonic-gate if (register_rsrcs == B_FALSE) 1258*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 1259*7c478bd9Sstevel@tonic-gate 1260*7c478bd9Sstevel@tonic-gate if ((muxfd = open_file(muxctl, oflags)) == -1) { 1261*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_ERROR, _("TTYMUX: %s unavailable: %s\n"), 1262*7c478bd9Sstevel@tonic-gate muxctl, strerror(errno)); 1263*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 1264*7c478bd9Sstevel@tonic-gate } 1265*7c478bd9Sstevel@tonic-gate /* 1266*7c478bd9Sstevel@tonic-gate * Search for any new dependencies since the last notification or 1267*7c478bd9Sstevel@tonic-gate * since module was initialisated. 1268*7c478bd9Sstevel@tonic-gate */ 1269*7c478bd9Sstevel@tonic-gate (void) probe_dependencies(); 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate /* 1272*7c478bd9Sstevel@tonic-gate * Search the whole cache looking for any unregistered used resources 1273*7c478bd9Sstevel@tonic-gate * and register them. Note that the 'using resource' (a ttymux device 1274*7c478bd9Sstevel@tonic-gate * node) is not subject to DR operations so there is no need to 1275*7c478bd9Sstevel@tonic-gate * register them with the RCM framework. 1276*7c478bd9Sstevel@tonic-gate */ 1277*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&cache_lock); 1278*7c478bd9Sstevel@tonic-gate for (rsrc = cache_head.next; rsrc != &cache_tail; rsrc = rsrc->next) { 1279*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: REGISTER rsrc %s flags %d\n", 1280*7c478bd9Sstevel@tonic-gate rsrc->id, rsrc->flags)); 1281*7c478bd9Sstevel@tonic-gate 1282*7c478bd9Sstevel@tonic-gate if (rsrc->dependencies != NULL && 1283*7c478bd9Sstevel@tonic-gate (rsrc->flags & REGISTERED) == 0) { 1284*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: Registering rsrc %s\n", rsrc->id)); 1285*7c478bd9Sstevel@tonic-gate rv = rcm_register_interest(hd, rsrc->id, 0, NULL); 1286*7c478bd9Sstevel@tonic-gate if (rv == RCM_SUCCESS) 1287*7c478bd9Sstevel@tonic-gate rsrc->flags |= REGISTERED; 1288*7c478bd9Sstevel@tonic-gate } 1289*7c478bd9Sstevel@tonic-gate 1290*7c478bd9Sstevel@tonic-gate for (link = rsrc->dependencies; link != NULL; 1291*7c478bd9Sstevel@tonic-gate link = link->next) { 1292*7c478bd9Sstevel@tonic-gate if ((link->used->flags & REGISTERED) != 0) 1293*7c478bd9Sstevel@tonic-gate continue; 1294*7c478bd9Sstevel@tonic-gate 1295*7c478bd9Sstevel@tonic-gate _msg(6, ("TTYMUX: Registering rsrc %s\n", 1296*7c478bd9Sstevel@tonic-gate link->used->id)); 1297*7c478bd9Sstevel@tonic-gate rv = rcm_register_interest(hd, link->used->id, 1298*7c478bd9Sstevel@tonic-gate 0, NULL); 1299*7c478bd9Sstevel@tonic-gate if (rv != RCM_SUCCESS) 1300*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, 1301*7c478bd9Sstevel@tonic-gate _("TTYMUX: err %d registering %s\n"), 1302*7c478bd9Sstevel@tonic-gate rv, link->used->id); 1303*7c478bd9Sstevel@tonic-gate else 1304*7c478bd9Sstevel@tonic-gate link->used->flags |= REGISTERED; 1305*7c478bd9Sstevel@tonic-gate } 1306*7c478bd9Sstevel@tonic-gate } 1307*7c478bd9Sstevel@tonic-gate 1308*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock); 1309*7c478bd9Sstevel@tonic-gate (void) close(muxfd); 1310*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 1311*7c478bd9Sstevel@tonic-gate } 1312*7c478bd9Sstevel@tonic-gate 1313*7c478bd9Sstevel@tonic-gate /* 1314*7c478bd9Sstevel@tonic-gate * Unregister all registrations. 1315*7c478bd9Sstevel@tonic-gate */ 1316*7c478bd9Sstevel@tonic-gate static int 1317*7c478bd9Sstevel@tonic-gate tty_unregister(rcm_handle_t *hd) 1318*7c478bd9Sstevel@tonic-gate { 1319*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc; 1320*7c478bd9Sstevel@tonic-gate 1321*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&cache_lock); 1322*7c478bd9Sstevel@tonic-gate /* 1323*7c478bd9Sstevel@tonic-gate * Search every resource in the cache and if it has been registered 1324*7c478bd9Sstevel@tonic-gate * then unregister it from the RCM framework. 1325*7c478bd9Sstevel@tonic-gate */ 1326*7c478bd9Sstevel@tonic-gate for (rsrc = cache_head.next; rsrc != &cache_tail; rsrc = rsrc->next) { 1327*7c478bd9Sstevel@tonic-gate if ((rsrc->flags & REGISTERED) == 0) 1328*7c478bd9Sstevel@tonic-gate continue; 1329*7c478bd9Sstevel@tonic-gate 1330*7c478bd9Sstevel@tonic-gate if (rcm_unregister_interest(hd, rsrc->id, 0) != RCM_SUCCESS) 1331*7c478bd9Sstevel@tonic-gate rcm_log_message(RCM_WARNING, 1332*7c478bd9Sstevel@tonic-gate _("TTYMUX: Failed to unregister %s\n"), rsrc->id); 1333*7c478bd9Sstevel@tonic-gate else 1334*7c478bd9Sstevel@tonic-gate rsrc->flags &= ~REGISTERED; 1335*7c478bd9Sstevel@tonic-gate } 1336*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock); 1337*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 1338*7c478bd9Sstevel@tonic-gate } 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate /* 1341*7c478bd9Sstevel@tonic-gate * Report resource usage information. 1342*7c478bd9Sstevel@tonic-gate */ 1343*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1344*7c478bd9Sstevel@tonic-gate static int 1345*7c478bd9Sstevel@tonic-gate tty_getinfo(rcm_handle_t *hd, char *rsrcid, id_t id, uint_t flag, char **info, 1346*7c478bd9Sstevel@tonic-gate char **errstr, nvlist_t *proplist, rcm_info_t **depend_info) 1347*7c478bd9Sstevel@tonic-gate { 1348*7c478bd9Sstevel@tonic-gate rsrc_t *rsrc, *user; 1349*7c478bd9Sstevel@tonic-gate char *ru; 1350*7c478bd9Sstevel@tonic-gate size_t sz; 1351*7c478bd9Sstevel@tonic-gate 1352*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&cache_lock); 1353*7c478bd9Sstevel@tonic-gate rsrc = cache_lookup(rsrcid); 1354*7c478bd9Sstevel@tonic-gate 1355*7c478bd9Sstevel@tonic-gate if (rsrc == NULL) { 1356*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock); 1357*7c478bd9Sstevel@tonic-gate *errstr = strdup(gettext("Unmanaged resource")); 1358*7c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 1359*7c478bd9Sstevel@tonic-gate } 1360*7c478bd9Sstevel@tonic-gate 1361*7c478bd9Sstevel@tonic-gate ru = strdup(gettext("Resource Users")); 1362*7c478bd9Sstevel@tonic-gate user = NULL; 1363*7c478bd9Sstevel@tonic-gate while ((user = get_next_user(user, rsrc, -1)) != NULL) { 1364*7c478bd9Sstevel@tonic-gate *info = ru; 1365*7c478bd9Sstevel@tonic-gate sz = strlen(*info) + strlen(user->id) + 2; 1366*7c478bd9Sstevel@tonic-gate ru = malloc(sz); 1367*7c478bd9Sstevel@tonic-gate if (ru == NULL) { 1368*7c478bd9Sstevel@tonic-gate free(*info); 1369*7c478bd9Sstevel@tonic-gate *info = NULL; 1370*7c478bd9Sstevel@tonic-gate break; 1371*7c478bd9Sstevel@tonic-gate } 1372*7c478bd9Sstevel@tonic-gate if (snprintf(ru, sz, ": %s%s", *info, user->id) > sz) { 1373*7c478bd9Sstevel@tonic-gate _msg(4, ("tty_getinfo: snprintf error.\n")); 1374*7c478bd9Sstevel@tonic-gate } 1375*7c478bd9Sstevel@tonic-gate 1376*7c478bd9Sstevel@tonic-gate free(*info); 1377*7c478bd9Sstevel@tonic-gate } 1378*7c478bd9Sstevel@tonic-gate *info = ru; 1379*7c478bd9Sstevel@tonic-gate 1380*7c478bd9Sstevel@tonic-gate if (*info == NULL) { 1381*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock); 1382*7c478bd9Sstevel@tonic-gate *errstr = strdup(gettext("Short of memory resources")); 1383*7c478bd9Sstevel@tonic-gate return (RCM_FAILURE); 1384*7c478bd9Sstevel@tonic-gate } 1385*7c478bd9Sstevel@tonic-gate 1386*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&cache_lock); 1387*7c478bd9Sstevel@tonic-gate return (RCM_SUCCESS); 1388*7c478bd9Sstevel@tonic-gate } 1389*7c478bd9Sstevel@tonic-gate 1390*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1391*7c478bd9Sstevel@tonic-gate static int 1392*7c478bd9Sstevel@tonic-gate tty_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 1393*7c478bd9Sstevel@tonic-gate char **reason, rcm_info_t **dependent_reason) 1394*7c478bd9Sstevel@tonic-gate { 1395*7c478bd9Sstevel@tonic-gate return (rsrc_change_common(hd, TTYMUX_OFFLINE, rsrc, flags, 1396*7c478bd9Sstevel@tonic-gate reason, dependent_reason, NULL)); 1397*7c478bd9Sstevel@tonic-gate } 1398*7c478bd9Sstevel@tonic-gate 1399*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1400*7c478bd9Sstevel@tonic-gate static int 1401*7c478bd9Sstevel@tonic-gate tty_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 1402*7c478bd9Sstevel@tonic-gate char **reason, rcm_info_t **dependent_reason) 1403*7c478bd9Sstevel@tonic-gate { 1404*7c478bd9Sstevel@tonic-gate return (rsrc_change_common(hd, TTYMUX_REMOVE, rsrc, flags, 1405*7c478bd9Sstevel@tonic-gate reason, dependent_reason, NULL)); 1406*7c478bd9Sstevel@tonic-gate } 1407*7c478bd9Sstevel@tonic-gate 1408*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1409*7c478bd9Sstevel@tonic-gate static int 1410*7c478bd9Sstevel@tonic-gate tty_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval, 1411*7c478bd9Sstevel@tonic-gate uint_t flag, char **reason, rcm_info_t **dependent_reason) 1412*7c478bd9Sstevel@tonic-gate { 1413*7c478bd9Sstevel@tonic-gate return (rsrc_change_common(hd, TTYMUX_SUSPEND, rsrc, flag, 1414*7c478bd9Sstevel@tonic-gate reason, dependent_reason, (void *)interval)); 1415*7c478bd9Sstevel@tonic-gate } 1416*7c478bd9Sstevel@tonic-gate 1417*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1418*7c478bd9Sstevel@tonic-gate static int 1419*7c478bd9Sstevel@tonic-gate tty_online(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 1420*7c478bd9Sstevel@tonic-gate char **reason, rcm_info_t **dependent_reason) 1421*7c478bd9Sstevel@tonic-gate { 1422*7c478bd9Sstevel@tonic-gate return (rsrc_change_common(hd, TTYMUX_ONLINE, rsrc, flags, 1423*7c478bd9Sstevel@tonic-gate reason, dependent_reason, NULL)); 1424*7c478bd9Sstevel@tonic-gate } 1425*7c478bd9Sstevel@tonic-gate 1426*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1427*7c478bd9Sstevel@tonic-gate static int 1428*7c478bd9Sstevel@tonic-gate tty_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 1429*7c478bd9Sstevel@tonic-gate char **reason, rcm_info_t **dependent_reason) 1430*7c478bd9Sstevel@tonic-gate { 1431*7c478bd9Sstevel@tonic-gate return (rsrc_change_common(hd, TTYMUX_RESUME, rsrc, flags, 1432*7c478bd9Sstevel@tonic-gate reason, dependent_reason, NULL)); 1433*7c478bd9Sstevel@tonic-gate } 1434