xref: /illumos-gate/usr/src/cmd/hal/hald/solaris/osspec.c (revision 2a8bcb4e)
1 /***************************************************************************
2  *
3  * osspec.c : Solaris HAL backend entry points
4  *
5  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
6  * Use is subject to license terms.
7  *
8  * Licensed under the Academic Free License version 2.1
9  *
10  **************************************************************************/
11 
12 #ifdef HAVE_CONFIG_H
13 #  include <config.h>
14 #endif
15 
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <strings.h>
19 #include <port.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <sys/types.h>
23 #include <sys/mntent.h>
24 #include <sys/mnttab.h>
25 
26 #include "../osspec.h"
27 #include "../logger.h"
28 #include "../hald.h"
29 #include "../hald_dbus.h"
30 #include "../device_info.h"
31 #include "../util.h"
32 #include "../ids.h"
33 #include "osspec_solaris.h"
34 #include "hotplug.h"
35 #include "sysevent.h"
36 #include "devinfo.h"
37 #include "devinfo_storage.h"
38 
39 static void mnttab_event_init ();
40 static gboolean mnttab_event (GIOChannel *channel, GIOCondition cond, gpointer user_data);
41 
42 void
osspec_init(void)43 osspec_init (void)
44 {
45 	ids_init ();
46 	sysevent_init ();
47 	mnttab_event_init ();
48 }
49 
50 void
hotplug_queue_now_empty(void)51 hotplug_queue_now_empty (void)
52 {
53         if (hald_is_initialising) {
54                 osspec_probe_done ();
55 	}
56 }
57 
58 void
osspec_probe(void)59 osspec_probe (void)
60 {
61 	/* add entire device tree */
62 	devinfo_add (NULL, "/");
63 
64 	/* start processing events */
65 	hotplug_event_process_queue ();
66 }
67 
68 gboolean
osspec_device_rescan(HalDevice * d)69 osspec_device_rescan (HalDevice *d)
70 {
71 	   return (devinfo_device_rescan (d));
72 }
73 
74 gboolean
osspec_device_reprobe(HalDevice * d)75 osspec_device_reprobe (HalDevice *d)
76 {
77 	   return FALSE;
78 }
79 
80 DBusHandlerResult
osspec_filter_function(DBusConnection * connection,DBusMessage * message,void * user_data)81 osspec_filter_function (DBusConnection *connection, DBusMessage *message, void *user_data)
82 {
83 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
84 }
85 
86 /** Find the closest ancestor by looking at devfs paths
87  *
88  *  @param  devfs_path           Path into devfs, e.g. /pci@0,0/pci1025,57@10,2/storage@1
89  *  @return                      Parent Hal Device Object or #NULL if there is none
90  */
91 HalDevice *
hal_util_find_closest_ancestor(const gchar * devfs_path,gchar ** ancestor_devfs_path,gchar ** hotplug_devfs_path)92 hal_util_find_closest_ancestor (const gchar *devfs_path, gchar **ancestor_devfs_path, gchar **hotplug_devfs_path)
93 {
94         gchar buf[512];
95 	gchar c;
96         HalDevice *parent;
97 
98         parent = NULL;
99 
100         strncpy (buf, devfs_path, sizeof (buf));
101         do {
102                 char *p;
103 
104                 p = strrchr (buf, '/');
105                 if (p == NULL)
106                         break;
107 		c = *p;
108                 *p = '\0';
109 
110                 parent = hal_device_store_match_key_value_string (hald_get_gdl (),
111                                                                   "solaris.devfs_path",
112                                                                   buf);
113                 if (parent != NULL) {
114 			if (ancestor_devfs_path != NULL) {
115 				*ancestor_devfs_path = g_strdup (buf);
116 			}
117 			if (hotplug_devfs_path != NULL) {
118 				*p = c;
119 				*hotplug_devfs_path = g_strdup (buf);
120 			}
121                         break;
122 		}
123 
124         } while (TRUE);
125 
126         return parent;
127 }
128 
129 char *
dsk_to_rdsk(char * dsk)130 dsk_to_rdsk(char *dsk)
131 {
132         int     len, pos;
133         char    *p;
134         char    *rdsk;
135 
136 	if ((len = strlen (dsk)) < sizeof ("/dev/dsk/cN") - 1) {
137 		return (strdup(""));
138 	}
139 	if ((p = strstr (dsk, "/dsk/")) == NULL) {
140 		if ((p = strstr (dsk, "/lofi/")) == NULL) {
141 			p = strstr (dsk, "/diskette");
142 		}
143 	}
144 	if (p == NULL) {
145 		return (strdup(""));
146 	}
147 
148 	pos = (uintptr_t)p - (uintptr_t)dsk;
149 	if ((rdsk = (char *)calloc (len + 2, 1)) != NULL) {
150         	strncpy (rdsk, dsk, pos + 1);
151         	rdsk[pos + 1] = 'r';
152         	strcpy (rdsk + pos + 2, dsk + pos + 1);
153 	}
154 
155         return (rdsk);
156 }
157 
158 /*
159  * Setup to watch mnttab changes
160  *
161  * When mnttab changes, POLLRDBAND is set. However, glib does not
162  * support POLLRDBAND, so we use Solaris ports (see port_create(3C))
163  * to "map" POLLRDBAND to POLLIN:
164  *
165  * - create a port
166  * - associate the port with mnttab file descriptor and POLLRDBAND
167  * - now polling for POLLIN on the port descriptor will unblock when
168  *   the associated file descriptor receives POLLRDBAND
169  */
170 static int	mnttab_fd;
171 static int	mnttab_port;
172 static GIOChannel *mnttab_channel;
173 
174 static void
mnttab_event_init()175 mnttab_event_init ()
176 {
177 	char	buf[81];
178 
179 	if ((mnttab_fd = open (MNTTAB, O_RDONLY)) < 0) {
180 		return;
181 	}
182 	if ((mnttab_port = port_create ()) < 0) {
183 		(void) close (mnttab_fd);
184 		return;
185 	}
186 	if (port_associate (mnttab_port, PORT_SOURCE_FD, mnttab_fd, POLLRDBAND,
187 	    NULL) != 0) {
188 		(void) close (mnttab_port);
189 		(void) close (mnttab_fd);
190 		return;
191 	}
192 
193 	/* suppress initial event */
194 	(void) read(mnttab_fd, buf, (size_t)(sizeof (buf) - 1));
195 	(void) lseek(mnttab_fd, 0, SEEK_SET);
196 
197 	mnttab_channel = g_io_channel_unix_new (mnttab_port);
198 	g_io_add_watch (mnttab_channel, G_IO_IN, mnttab_event, NULL);
199 }
200 
201 static gboolean
mnttab_event(GIOChannel * channel,GIOCondition cond,gpointer user_data)202 mnttab_event (GIOChannel *channel, GIOCondition cond, gpointer user_data)
203 {
204 	port_event_t pe;
205 	timespec_t timeout;
206 	char	buf[81];
207 
208 	/* if (cond & ~G_IO_ERR)
209 		return TRUE;
210 	 */
211 	HAL_INFO (("mnttab event"));
212 
213 	/* we have to re-associate port with fd every time */
214 	timeout.tv_sec = timeout.tv_nsec = 0;
215 	(void) port_get(mnttab_port, &pe, &timeout);
216 	(void) port_associate(mnttab_port, PORT_SOURCE_FD,
217 	    mnttab_fd, POLLRDBAND, NULL);
218 
219 	if (!hald_is_initialising) {
220 		devinfo_storage_mnttab_event (NULL);
221 	}
222 
223 	(void) lseek(mnttab_fd, 0, SEEK_SET);
224 	(void) read(mnttab_fd, buf, (size_t)(sizeof (buf) - 1));
225 
226 	return TRUE;
227 }
228 
229 void
osspec_refresh_mount_state_for_block_device(HalDevice * d)230 osspec_refresh_mount_state_for_block_device (HalDevice *d)
231 {
232 	devinfo_storage_mnttab_event (d);
233 }
234