author | cth |
Fri, 22 Feb 2008 09:02:16 -0800 | |
changeset 6065 | b05c5c670963 |
parent 6013 | fe64a0b9ee89 |
child 6141 | 80e002a17510 |
permissions | -rw-r--r-- |
0 | 1 |
/* |
2 |
* CDDL HEADER START |
|
3 |
* |
|
4 |
* The contents of this file are subject to the terms of the |
|
1441
e831cb15de0e
4976415 devfsadmd for zones could be smarter when major numbers change
edp
parents:
893
diff
changeset
|
5 |
* Common Development and Distribution License (the "License"). |
e831cb15de0e
4976415 devfsadmd for zones could be smarter when major numbers change
edp
parents:
893
diff
changeset
|
6 |
* You may not use this file except in compliance with the License. |
0 | 7 |
* |
8 |
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
9 |
* or http://www.opensolaris.org/os/licensing. |
|
10 |
* See the License for the specific language governing permissions |
|
11 |
* and limitations under the License. |
|
12 |
* |
|
13 |
* When distributing Covered Code, include this CDDL HEADER in each |
|
14 |
* file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
15 |
* If applicable, add the following below this CDDL HEADER, with the |
|
16 |
* fields enclosed by brackets "[]" replaced with your own identifying |
|
17 |
* information: Portions Copyright [yyyy] [name of copyright owner] |
|
18 |
* |
|
19 |
* CDDL HEADER END |
|
20 |
*/ |
|
1441
e831cb15de0e
4976415 devfsadmd for zones could be smarter when major numbers change
edp
parents:
893
diff
changeset
|
21 |
|
0 | 22 |
/* |
5895
f251acdd9bdc
PSARC/2006/499 Clearview Nemo unification and vanity naming
yz147064
parents:
5032
diff
changeset
|
23 |
* Copyright 2008 Sun Microsystems, Inc. All rights reserved. |
0 | 24 |
* Use is subject to license terms. |
25 |
*/ |
|
26 |
||
27 |
#pragma ident "%Z%%M% %I% %E% SMI" |
|
28 |
||
29 |
/* |
|
30 |
* Devfsadm replaces drvconfig, audlinks, disks, tapes, ports, devlinks |
|
31 |
* as a general purpose device administrative utility. It creates |
|
32 |
* devices special files in /devices and logical links in /dev, and |
|
33 |
* coordinates updates to /etc/path_to_instance with the kernel. It |
|
34 |
* operates in both command line mode to handle user or script invoked |
|
35 |
* reconfiguration updates, and operates in daemon mode to handle dynamic |
|
36 |
* reconfiguration for hotplugging support. |
|
37 |
*/ |
|
38 |
||
1676 | 39 |
#include <string.h> |
4746
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
40 |
#include <deflt.h> |
1676 | 41 |
#include <tsol/label.h> |
42 |
#include <bsm/devices.h> |
|
43 |
#include <bsm/devalloc.h> |
|
0 | 44 |
#include <utime.h> |
5032
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
45 |
#include <sys/param.h> |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
46 |
#include <bsm/libbsm.h> |
1676 | 47 |
#include "devfsadm_impl.h" |
48 |
||
49 |
/* externs from devalloc.c */ |
|
50 |
extern void _reset_devalloc(int); |
|
51 |
extern void _update_devalloc_db(devlist_t *, int, int, char *, char *); |
|
52 |
extern int _da_check_for_usb(char *, char *); |
|
0 | 53 |
|
54 |
/* create or remove nodes or links. unset with -n */ |
|
55 |
static int file_mods = TRUE; |
|
56 |
||
57 |
/* cleanup mode. Set with -C */ |
|
58 |
static int cleanup = FALSE; |
|
59 |
||
60 |
/* devlinks -d compatibility */ |
|
61 |
static int devlinks_debug = FALSE; |
|
62 |
||
1676 | 63 |
/* flag to check if system is labeled */ |
64 |
int system_labeled = FALSE; |
|
65 |
||
66 |
/* flag to enable/disable device allocation with -e/-d */ |
|
67 |
static int devalloc_flag = 0; |
|
68 |
||
5032
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
69 |
/* flag that indicates if device allocation is on or not */ |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
70 |
static int devalloc_is_on = 0; |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
71 |
|
1676 | 72 |
/* flag to update device allocation database for this device type */ |
73 |
static int update_devdb = 0; |
|
74 |
||
75 |
/* |
|
76 |
* devices to be deallocated with -d : |
|
77 |
* audio, floppy, cd, floppy, tape, rmdisk. |
|
78 |
*/ |
|
79 |
static char *devalloc_list[10] = {DDI_NT_AUDIO, DDI_NT_CD, DDI_NT_CD_CHAN, |
|
80 |
DDI_NT_FD, DDI_NT_TAPE, DDI_NT_BLOCK_CHAN, |
|
81 |
DDI_NT_UGEN, DDI_NT_USB_ATTACHMENT_POINT, |
|
82 |
DDI_NT_SCSI_NEXUS, NULL}; |
|
83 |
||
84 |
/* list of allocatable devices */ |
|
85 |
static devlist_t devlist; |
|
0 | 86 |
|
87 |
/* load a single driver only. set with -i */ |
|
88 |
static int single_drv = FALSE; |
|
89 |
static char *driver = NULL; |
|
90 |
||
91 |
/* attempt to load drivers or defer attach nodes */ |
|
92 |
static int load_attach_drv = TRUE; |
|
93 |
||
94 |
/* set if invoked via /usr/lib/devfsadm/devfsadmd */ |
|
95 |
static int daemon_mode = FALSE; |
|
96 |
||
97 |
/* output directed to syslog during daemon mode if set */ |
|
98 |
static int logflag = FALSE; |
|
99 |
||
100 |
/* build links in /dev. -x to turn off */ |
|
101 |
static int build_dev = TRUE; |
|
102 |
||
103 |
/* build nodes in /devices. -y to turn off */ |
|
104 |
static int build_devices = TRUE; |
|
105 |
||
106 |
/* -z to turn off */ |
|
107 |
static int flush_path_to_inst_enable = TRUE; |
|
108 |
||
109 |
/* variables used for path_to_inst flushing */ |
|
110 |
static int inst_count = 0; |
|
111 |
static mutex_t count_lock; |
|
112 |
static cond_t cv; |
|
113 |
||
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
114 |
/* variables for minor_fini thread */ |
0 | 115 |
static mutex_t minor_fini_mutex; |
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
116 |
static int minor_fini_canceled = TRUE; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
117 |
static int minor_fini_delayed = FALSE; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
118 |
static cond_t minor_fini_cv; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
119 |
static int minor_fini_timeout = MINOR_FINI_TIMEOUT_DEFAULT; |
0 | 120 |
|
121 |
/* single-threads /dev modification */ |
|
122 |
static sema_t dev_sema; |
|
123 |
||
124 |
/* the program we were invoked as; ie argv[0] */ |
|
125 |
static char *prog; |
|
126 |
||
127 |
/* pointers to create/remove link lists */ |
|
128 |
static create_list_t *create_head = NULL; |
|
129 |
static remove_list_t *remove_head = NULL; |
|
130 |
||
131 |
/* supports the class -c option */ |
|
132 |
static char **classes = NULL; |
|
133 |
static int num_classes = 0; |
|
134 |
||
135 |
/* used with verbose option -v or -V */ |
|
136 |
static int num_verbose = 0; |
|
137 |
static char **verbose = NULL; |
|
138 |
||
139 |
static struct mperm *minor_perms = NULL; |
|
140 |
static driver_alias_t *driver_aliases = NULL; |
|
141 |
||
142 |
/* set if -r alternate root given */ |
|
143 |
static char *root_dir = ""; |
|
144 |
||
145 |
/* /devices or <rootdir>/devices */ |
|
146 |
static char *devices_dir = DEVICES; |
|
147 |
||
148 |
/* /dev or <rootdir>/dev */ |
|
149 |
static char *dev_dir = DEV; |
|
150 |
||
2621 | 151 |
/* /etc/dev or <rootdir>/etc/dev */ |
152 |
static char *etc_dev_dir = ETCDEV; |
|
153 |
||
154 |
/* |
|
155 |
* writable root (for lock files and doors during install). |
|
156 |
* This is also root dir for /dev attr dir during install. |
|
157 |
*/ |
|
158 |
static char *attr_root = NULL; |
|
0 | 159 |
|
160 |
/* /etc/path_to_inst unless -p used */ |
|
161 |
static char *inst_file = INSTANCE_FILE; |
|
162 |
||
163 |
/* /usr/lib/devfsadm/linkmods unless -l used */ |
|
164 |
static char *module_dirs = MODULE_DIRS; |
|
165 |
||
166 |
/* default uid/gid used if /etc/minor_perm entry not found */ |
|
167 |
static uid_t root_uid; |
|
168 |
static gid_t sys_gid; |
|
169 |
||
170 |
/* /etc/devlink.tab unless devlinks -t used */ |
|
171 |
static char *devlinktab_file = NULL; |
|
172 |
||
4876 | 173 |
/* File and data structure to reserve enumerate IDs */ |
174 |
static char *enumerate_file = ENUMERATE_RESERVED; |
|
175 |
static enumerate_file_t *enumerate_reserved = NULL; |
|
176 |
||
0 | 177 |
/* set if /dev link is new. speeds up rm_stale_links */ |
178 |
static int linknew = TRUE; |
|
179 |
||
180 |
/* variables for devlink.tab compat processing */ |
|
181 |
static devlinktab_list_t *devlinktab_list = NULL; |
|
182 |
static unsigned int devlinktab_line = 0; |
|
183 |
||
184 |
/* cache head for devfsadm_enumerate*() functions */ |
|
185 |
static numeral_set_t *head_numeral_set = NULL; |
|
186 |
||
187 |
/* list list of devfsadm modules */ |
|
188 |
static module_t *module_head = NULL; |
|
189 |
||
190 |
/* name_to_major list used in utility function */ |
|
191 |
static n2m_t *n2m_list = NULL; |
|
192 |
||
193 |
/* cache of some links used for performance */ |
|
194 |
static linkhead_t *headlinkhead = NULL; |
|
195 |
||
196 |
/* locking variables to prevent multiples writes to /dev */ |
|
197 |
static int hold_dev_lock = FALSE; |
|
198 |
static int hold_daemon_lock = FALSE; |
|
199 |
static int dev_lock_fd; |
|
200 |
static int daemon_lock_fd; |
|
201 |
static char dev_lockfile[PATH_MAX + 1]; |
|
202 |
static char daemon_lockfile[PATH_MAX + 1]; |
|
203 |
||
204 |
/* last devinfo node/minor processed. used for performance */ |
|
205 |
static di_node_t lnode; |
|
206 |
static di_minor_t lminor; |
|
207 |
static char lphy_path[PATH_MAX + 1] = {""}; |
|
208 |
||
209 |
/* Globals used by the link database */ |
|
210 |
static di_devlink_handle_t devlink_cache; |
|
211 |
static int update_database = FALSE; |
|
212 |
||
213 |
/* Globals used to set logindev perms */ |
|
214 |
static struct login_dev *login_dev_cache = NULL; |
|
215 |
static int login_dev_enable = FALSE; |
|
216 |
||
217 |
/* Global to use devinfo snapshot cache */ |
|
218 |
static int use_snapshot_cache = FALSE; |
|
219 |
||
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
220 |
/* Global for no-further-processing hash */ |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
221 |
static item_t **nfp_hash; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
222 |
static mutex_t nfp_mutex = DEFAULTMUTEX; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
223 |
|
0 | 224 |
/* |
225 |
* Packaged directories - not removed even when empty. |
|
226 |
* The dirs must be listed in canonical form |
|
227 |
* i.e. without leading "/dev/" |
|
228 |
*/ |
|
229 |
static char *packaged_dirs[] = |
|
230 |
{"dsk", "rdsk", "term", NULL}; |
|
231 |
||
232 |
/* RCM related globals */ |
|
233 |
static void *librcm_hdl; |
|
234 |
static rcm_handle_t *rcm_hdl = NULL; |
|
235 |
static thread_t process_rcm_events_tid; |
|
236 |
static struct rcm_eventq *volatile rcm_eventq_head = NULL; |
|
237 |
static struct rcm_eventq *rcm_eventq_tail = NULL; |
|
238 |
static mutex_t rcm_eventq_lock; |
|
239 |
static cond_t rcm_eventq_cv; |
|
240 |
static volatile int need_to_exit_rcm_event_thread = 0; |
|
241 |
||
2621 | 242 |
/* Devname globals */ |
243 |
static int devname_debug_msg = 1; |
|
244 |
static nvlist_t *devname_maps = NULL; |
|
245 |
static int devname_first_call = 1; |
|
246 |
static int load_devname_nsmaps = FALSE; |
|
247 |
static int lookup_door_fd = -1; |
|
248 |
static char *lookup_door_path; |
|
249 |
||
0 | 250 |
static void load_dev_acl(void); |
251 |
static void update_drvconf(major_t); |
|
2621 | 252 |
static void check_reconfig_state(void); |
253 |
static void devname_setup_nsmaps(void); |
|
254 |
static int s_stat(const char *, struct stat *); |
|
0 | 255 |
|
2805
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
256 |
static int is_blank(char *); |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
257 |
|
3854 | 258 |
/* sysevent queue related globals */ |
259 |
static mutex_t syseventq_mutex = DEFAULTMUTEX; |
|
260 |
static syseventq_t *syseventq_front; |
|
261 |
static syseventq_t *syseventq_back; |
|
262 |
static void process_syseventq(); |
|
263 |
||
0 | 264 |
int |
265 |
main(int argc, char *argv[]) |
|
266 |
{ |
|
267 |
struct passwd *pw; |
|
268 |
struct group *gp; |
|
269 |
pid_t pid; |
|
5032
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
270 |
int cond = 0; |
0 | 271 |
|
272 |
(void) setlocale(LC_ALL, ""); |
|
273 |
(void) textdomain(TEXT_DOMAIN); |
|
274 |
||
275 |
if ((prog = strrchr(argv[0], '/')) == NULL) { |
|
276 |
prog = argv[0]; |
|
277 |
} else { |
|
278 |
prog++; |
|
279 |
} |
|
280 |
||
281 |
if (getuid() != 0) { |
|
282 |
err_print(MUST_BE_ROOT); |
|
283 |
devfsadm_exit(1); |
|
284 |
} |
|
285 |
||
286 |
/* |
|
287 |
* Close all files except stdin/stdout/stderr |
|
288 |
*/ |
|
289 |
closefrom(3); |
|
290 |
||
291 |
if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) { |
|
292 |
root_uid = pw->pw_uid; |
|
293 |
} else { |
|
294 |
err_print(CANT_FIND_USER, DEFAULT_DEV_USER); |
|
295 |
root_uid = (uid_t)0; /* assume 0 is root */ |
|
296 |
} |
|
297 |
||
298 |
/* the default group is sys */ |
|
299 |
||
300 |
if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) { |
|
301 |
sys_gid = gp->gr_gid; |
|
302 |
} else { |
|
303 |
err_print(CANT_FIND_GROUP, DEFAULT_DEV_GROUP); |
|
304 |
sys_gid = (gid_t)3; /* assume 3 is sys */ |
|
305 |
} |
|
306 |
||
307 |
(void) umask(0); |
|
308 |
||
1676 | 309 |
system_labeled = is_system_labeled(); |
310 |
if (system_labeled == FALSE) { |
|
311 |
/* |
|
312 |
* is_system_labeled() will return false in case we are |
|
313 |
* starting before the first reboot after Trusted Extensions |
|
4746
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
314 |
* is enabled. Check the setting in /etc/system to see if |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
315 |
* TX is enabled (even if not yet booted). |
1676 | 316 |
*/ |
4746
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
317 |
if (defopen("/etc/system") == 0) { |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
318 |
if (defread("set sys_labeling=1") != NULL) |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
319 |
system_labeled = TRUE; |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
320 |
|
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
321 |
/* close defaults file */ |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
322 |
(void) defopen(NULL); |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
323 |
} |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
324 |
} |
5032
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
325 |
/* |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
326 |
* Check if device allocation is enabled. |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
327 |
*/ |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
328 |
if (system_labeled) { |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
329 |
/* |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
330 |
* In TX, the first line in /etc/security/device_allocate has |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
331 |
* DEVICE_ALLOCATION=ON if the feature is enabled. |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
332 |
*/ |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
333 |
devalloc_is_on = da_is_on(); |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
334 |
} else if (auditon(A_GETCOND, (caddr_t)&cond, sizeof (cond)) == 0) { |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
335 |
/* |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
336 |
* Device allocation (and auditing) is enabled if BSM is |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
337 |
* enabled. auditon returns -1 and sets errno to EINVAL if BSM |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
338 |
* is not enabled. |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
339 |
*/ |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
340 |
devalloc_is_on = 1; |
f8f641f371f1
6589362 unnecessary overhead caused by device allocation check when booting zones
aj
parents:
4876
diff
changeset
|
341 |
} |
4746
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
342 |
|
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
343 |
#ifdef DEBUG |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
344 |
if (system_labeled == FALSE) { |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
345 |
struct stat tx_stat; |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
346 |
|
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
347 |
/* test hook: see also mkdevalloc.c and allocate.c */ |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
348 |
system_labeled = is_system_labeled_debug(&tx_stat); |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
349 |
} |
0bc0c48f4304
PSARC 2007/254 - Enabling method for Trusted Extensions
rica
parents:
4400
diff
changeset
|
350 |
#endif |
1676 | 351 |
|
0 | 352 |
parse_args(argc, argv); |
353 |
||
354 |
(void) sema_init(&dev_sema, 1, USYNC_THREAD, NULL); |
|
355 |
||
1676 | 356 |
/* Initialize device allocation list */ |
357 |
devlist.audio = devlist.cd = devlist.floppy = devlist.tape = |
|
358 |
devlist.rmdisk = NULL; |
|
359 |
||
0 | 360 |
if (daemon_mode == TRUE) { |
361 |
/* |
|
362 |
* Build /dev and /devices before daemonizing if |
|
363 |
* reconfig booting and daemon invoked with alternate |
|
364 |
* root. This is to support install. |
|
365 |
*/ |
|
366 |
if (getenv(RECONFIG_BOOT) != NULL && root_dir[0] != '\0') { |
|
367 |
vprint(INFO_MID, CONFIGURING); |
|
368 |
load_dev_acl(); |
|
369 |
update_drvconf((major_t)-1); |
|
370 |
process_devinfo_tree(); |
|
371 |
(void) modctl(MODSETMINIROOT); |
|
372 |
} |
|
373 |
||
374 |
/* |
|
375 |
* fork before detaching from tty in order to print error |
|
376 |
* message if unable to acquire file lock. locks not preserved |
|
377 |
* across forks. Even under debug we want to fork so that |
|
378 |
* when executed at boot we don't hang. |
|
379 |
*/ |
|
380 |
if (fork() != 0) { |
|
381 |
devfsadm_exit(0); |
|
382 |
} |
|
383 |
||
384 |
/* set directory to / so it coredumps there */ |
|
385 |
if (chdir("/") == -1) { |
|
386 |
err_print(CHROOT_FAILED, strerror(errno)); |
|
387 |
} |
|
388 |
||
389 |
/* only one daemon can run at a time */ |
|
390 |
if ((pid = enter_daemon_lock()) == getpid()) { |
|
391 |
detachfromtty(); |
|
392 |
(void) cond_init(&cv, USYNC_THREAD, 0); |
|
393 |
(void) mutex_init(&count_lock, USYNC_THREAD, 0); |
|
394 |
if (thr_create(NULL, NULL, |
|
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
395 |
(void *(*)(void *))instance_flush_thread, |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
396 |
NULL, THR_DETACHED, NULL) != 0) { |
0 | 397 |
err_print(CANT_CREATE_THREAD, "daemon", |
398 |
strerror(errno)); |
|
399 |
devfsadm_exit(1); |
|
400 |
} |
|
401 |
||
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
402 |
/* start the minor_fini_thread */ |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
403 |
(void) mutex_init(&minor_fini_mutex, USYNC_THREAD, 0); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
404 |
(void) cond_init(&minor_fini_cv, USYNC_THREAD, 0); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
405 |
if (thr_create(NULL, NULL, |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
406 |
(void *(*)(void *))minor_fini_thread, |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
407 |
NULL, THR_DETACHED, NULL)) { |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
408 |
err_print(CANT_CREATE_THREAD, "minor_fini", |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
409 |
strerror(errno)); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
410 |
devfsadm_exit(1); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
411 |
} |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
412 |
|
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
413 |
|
0 | 414 |
/* |
415 |
* No need for rcm notifications when running |
|
416 |
* with an alternate root. So initialize rcm only |
|
417 |
* when devfsadm is running with root dir "/". |
|
418 |
* Similarly, logindevperms need only be set |
|
419 |
* in daemon mode and when root dir is "/". |
|
420 |
*/ |
|
421 |
if (root_dir[0] == '\0') { |
|
422 |
(void) rcm_init(); |
|
423 |
login_dev_enable = TRUE; |
|
424 |
} |
|
425 |
daemon_update(); |
|
426 |
} else { |
|
427 |
err_print(DAEMON_RUNNING, pid); |
|
428 |
devfsadm_exit(1); |
|
429 |
} |
|
430 |
exit_daemon_lock(); |
|
431 |
||
432 |
} else { |
|
433 |
/* not a daemon, so just build /dev and /devices */ |
|
434 |
process_devinfo_tree(); |
|
1676 | 435 |
if (devalloc_flag != 0) |
436 |
/* Enable/disable device allocation */ |
|
437 |
_reset_devalloc(devalloc_flag); |
|
0 | 438 |
} |
439 |
return (0); |
|
440 |
} |
|
441 |
||
442 |
static void |
|
443 |
update_drvconf(major_t major) |
|
444 |
{ |
|
445 |
if (modctl(MODLOADDRVCONF, major) != 0) |
|
446 |
err_print(gettext("update_drvconf failed for major %d\n"), |
|
447 |
major); |
|
448 |
} |
|
449 |
||
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
450 |
|
0 | 451 |
static void |
452 |
load_dev_acl() |
|
453 |
{ |
|
454 |
if (load_devpolicy() != 0) |
|
455 |
err_print(gettext("device policy load failed\n")); |
|
456 |
load_minor_perm_file(); |
|
457 |
} |
|
458 |
||
459 |
/* |
|
2621 | 460 |
* As devfsadm is run early in boot to provide the kernel with |
461 |
* minor_perm info, we might as well check for reconfig at the |
|
462 |
* same time to avoid running devfsadm twice. This gets invoked |
|
463 |
* earlier than the env variable RECONFIG_BOOT is set up. |
|
0 | 464 |
*/ |
2621 | 465 |
static void |
466 |
check_reconfig_state() |
|
467 |
{ |
|
468 |
struct stat sb; |
|
469 |
||
470 |
if (s_stat("/reconfigure", &sb) == 0) { |
|
471 |
(void) modctl(MODDEVNAME, MODDEVNAME_RECONFIG, 0); |
|
472 |
} |
|
473 |
} |
|
474 |
||
475 |
static void |
|
476 |
modctl_sysavail() |
|
477 |
{ |
|
478 |
/* |
|
479 |
* Inform /dev that system is available, that |
|
480 |
* implicit reconfig can now be performed. |
|
481 |
*/ |
|
482 |
(void) modctl(MODDEVNAME, MODDEVNAME_SYSAVAIL, 0); |
|
483 |
} |
|
484 |
||
485 |
static void |
|
486 |
set_lock_root(void) |
|
487 |
{ |
|
488 |
struct stat sb; |
|
489 |
char *lock_root; |
|
490 |
size_t len; |
|
491 |
||
492 |
lock_root = attr_root ? attr_root : root_dir; |
|
493 |
||
494 |
len = strlen(lock_root) + strlen(ETCDEV) + 1; |
|
495 |
etc_dev_dir = s_malloc(len); |
|
496 |
(void) snprintf(etc_dev_dir, len, "%s%s", lock_root, ETCDEV); |
|
497 |
||
498 |
if (s_stat(etc_dev_dir, &sb) != 0) { |
|
499 |
s_mkdirp(etc_dev_dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); |
|
500 |
} else if (!S_ISDIR(sb.st_mode)) { |
|
501 |
err_print(NOT_DIR, etc_dev_dir); |
|
502 |
devfsadm_exit(1); |
|
503 |
} |
|
504 |
} |
|
505 |
||
0 | 506 |
|
507 |
/* |
|
508 |
* Parse arguments for all 6 programs handled from devfsadm. |
|
509 |
*/ |
|
510 |
static void |
|
511 |
parse_args(int argc, char *argv[]) |
|
512 |
{ |
|
513 |
char opt; |
|
514 |
char get_linkcompat_opts = FALSE; |
|
515 |
char *compat_class; |
|
516 |
int num_aliases = 0; |
|
517 |
int len; |
|
518 |
int retval; |
|
519 |
int add_bind = FALSE; |
|
520 |
struct aliases *ap = NULL; |
|
521 |
struct aliases *a_head = NULL; |
|
522 |
struct aliases *a_tail = NULL; |
|
523 |
struct modconfig mc; |
|
524 |
||
525 |
if (strcmp(prog, DISKS) == 0) { |
|
526 |
compat_class = "disk"; |
|
527 |
get_linkcompat_opts = TRUE; |
|
528 |
||
529 |
} else if (strcmp(prog, TAPES) == 0) { |
|
530 |
compat_class = "tape"; |
|
531 |
get_linkcompat_opts = TRUE; |
|
532 |
||
533 |
} else if (strcmp(prog, PORTS) == 0) { |
|
534 |
compat_class = "port"; |
|
535 |
get_linkcompat_opts = TRUE; |
|
536 |
||
537 |
} else if (strcmp(prog, AUDLINKS) == 0) { |
|
538 |
compat_class = "audio"; |
|
539 |
get_linkcompat_opts = TRUE; |
|
540 |
||
541 |
} else if (strcmp(prog, DEVLINKS) == 0) { |
|
542 |
devlinktab_file = DEVLINKTAB_FILE; |
|
543 |
||
544 |
build_devices = FALSE; |
|
545 |
load_attach_drv = FALSE; |
|
546 |
||
547 |
while ((opt = getopt(argc, argv, "dnr:st:vV:")) != EOF) { |
|
548 |
switch (opt) { |
|
549 |
case 'd': |
|
550 |
file_mods = FALSE; |
|
551 |
flush_path_to_inst_enable = FALSE; |
|
552 |
devlinks_debug = TRUE; |
|
553 |
break; |
|
554 |
case 'n': |
|
555 |
/* prevent driver loading and deferred attach */ |
|
556 |
load_attach_drv = FALSE; |
|
557 |
break; |
|
558 |
case 'r': |
|
2621 | 559 |
set_root_devices_dev_dir(optarg); |
0 | 560 |
if (zone_pathcheck(root_dir) != |
561 |
DEVFSADM_SUCCESS) |
|
562 |
devfsadm_exit(1); |
|
563 |
break; |
|
564 |
case 's': |
|
565 |
/* |
|
566 |
* suppress. don't create/remove links/nodes |
|
567 |
* useful with -v or -V |
|
568 |
*/ |
|
569 |
file_mods = FALSE; |
|
570 |
flush_path_to_inst_enable = FALSE; |
|
571 |
break; |
|
572 |
case 't': |
|
573 |
/* supply a non-default table file */ |
|
574 |
devlinktab_file = optarg; |
|
575 |
break; |
|
576 |
case 'v': |
|
577 |
/* documented verbose flag */ |
|
578 |
add_verbose_id(VERBOSE_MID); |
|
579 |
break; |
|
580 |
case 'V': |
|
581 |
/* undocumented for extra verbose levels */ |
|
582 |
add_verbose_id(optarg); |
|
583 |
break; |
|
584 |
default: |
|
585 |
usage(); |
|
586 |
break; |
|
587 |
} |
|
588 |
} |
|
589 |
||
590 |
if (optind < argc) { |
|
591 |
usage(); |
|
592 |
} |
|
593 |
||
594 |
} else if (strcmp(prog, DRVCONFIG) == 0) { |
|
595 |
build_dev = FALSE; |
|
596 |
||
597 |
while ((opt = |
|
598 |
getopt(argc, argv, "a:bdc:i:m:np:R:r:svV:")) != EOF) { |
|
599 |
switch (opt) { |
|
600 |
case 'a': |
|
601 |
ap = calloc(sizeof (struct aliases), 1); |
|
602 |
ap->a_name = dequote(optarg); |
|
603 |
len = strlen(ap->a_name) + 1; |
|
604 |
if (len > MAXMODCONFNAME) { |
|
605 |
err_print(ALIAS_TOO_LONG, |
|
606 |
MAXMODCONFNAME, ap->a_name); |
|
607 |
devfsadm_exit(1); |
|
608 |
} |
|
609 |
ap->a_len = len; |
|
610 |
if (a_tail == NULL) { |
|
611 |
a_head = ap; |
|
612 |
} else { |
|
613 |
a_tail->a_next = ap; |
|
614 |
} |
|
615 |
a_tail = ap; |
|
616 |
num_aliases++; |
|
617 |
add_bind = TRUE; |
|
618 |
break; |
|
619 |
case 'b': |
|
620 |
add_bind = TRUE; |
|
621 |
break; |
|
622 |
case 'c': |
|
623 |
(void) strcpy(mc.drvclass, optarg); |
|
624 |
break; |
|
625 |
case 'd': |
|
626 |
/* |
|
627 |
* need to keep for compatibility, but |
|
628 |
* do nothing. |
|
629 |
*/ |
|
630 |
break; |
|
631 |
case 'i': |
|
632 |
single_drv = TRUE; |
|
633 |
(void) strcpy(mc.drvname, optarg); |
|
634 |
driver = s_strdup(optarg); |
|
635 |
break; |
|
636 |
case 'm': |
|
637 |
mc.major = atoi(optarg); |
|
638 |
break; |
|
639 |
case 'n': |
|
640 |
/* prevent driver loading and deferred attach */ |
|
641 |
load_attach_drv = FALSE; |
|
642 |
break; |
|
643 |
case 'p': |
|
644 |
/* specify alternate path_to_inst file */ |
|
645 |
inst_file = s_strdup(optarg); |
|
646 |
break; |
|
647 |
case 'R': |
|
648 |
/* |
|
649 |
* Private flag for suninstall to populate |
|
650 |
* device information on the installed root. |
|
651 |
*/ |
|
652 |
root_dir = s_strdup(optarg); |
|
653 |
if (zone_pathcheck(root_dir) != |
|
654 |
DEVFSADM_SUCCESS) |
|
655 |
devfsadm_exit(devfsadm_copy()); |
|
656 |
break; |
|
657 |
case 'r': |
|
658 |
devices_dir = s_strdup(optarg); |
|
659 |
if (zone_pathcheck(devices_dir) != |
|
660 |
DEVFSADM_SUCCESS) |
|
661 |
devfsadm_exit(1); |
|
662 |
break; |
|
663 |
case 's': |
|
664 |
/* |
|
665 |
* suppress. don't create nodes |
|
666 |
* useful with -v or -V |
|
667 |
*/ |
|
668 |
file_mods = FALSE; |
|
669 |
flush_path_to_inst_enable = FALSE; |
|
670 |
break; |
|
671 |
case 'v': |
|
672 |
/* documented verbose flag */ |
|
673 |
add_verbose_id(VERBOSE_MID); |
|
674 |
break; |
|
675 |
case 'V': |
|
676 |
/* undocumented for extra verbose levels */ |
|
677 |
add_verbose_id(optarg); |
|
678 |
break; |
|
679 |
default: |
|
680 |
usage(); |
|
681 |
} |
|
682 |
} |
|
683 |
||
684 |
if (optind < argc) { |
|
685 |
usage(); |
|
686 |
} |
|
687 |
||
688 |
if ((add_bind == TRUE) && (mc.major == -1 || |
|
689 |
mc.drvname[0] == NULL)) { |
|
690 |
err_print(MAJOR_AND_B_FLAG); |
|
691 |
devfsadm_exit(1); |
|
692 |
} |
|
693 |
if (add_bind == TRUE) { |
|
694 |
mc.num_aliases = num_aliases; |
|
695 |
mc.ap = a_head; |
|
696 |
retval = modctl(MODADDMAJBIND, NULL, (caddr_t)&mc); |
|
697 |
if (retval < 0) { |
|
698 |
err_print(MODCTL_ADDMAJBIND); |
|
699 |
} |
|
700 |
devfsadm_exit(retval); |
|
701 |
} |
|
702 |
||
703 |
} else if ((strcmp(prog, DEVFSADM) == 0) || |
|
704 |
(strcmp(prog, DEVFSADMD) == 0)) { |
|
705 |
char *zonename = NULL; |
|
706 |
int init_drvconf = 0; |
|
707 |
int init_perm = 0; |
|
708 |
int public_mode = 0; |
|
2621 | 709 |
int init_sysavail = 0; |
0 | 710 |
|
711 |
if (strcmp(prog, DEVFSADMD) == 0) { |
|
712 |
daemon_mode = TRUE; |
|
713 |
} |
|
714 |
||
715 |
devlinktab_file = DEVLINKTAB_FILE; |
|
716 |
||
717 |
while ((opt = getopt(argc, argv, |
|
2621 | 718 |
"a:Cc:deIi:l:mnp:PR:r:sSt:vV:x:")) != EOF) { |
719 |
if (opt == 'I' || opt == 'P' || opt == 'S') { |
|
0 | 720 |
if (public_mode) |
721 |
usage(); |
|
722 |
} else { |
|
2621 | 723 |
if (init_perm || init_drvconf || init_sysavail) |
0 | 724 |
usage(); |
725 |
public_mode = 1; |
|
726 |
} |
|
727 |
switch (opt) { |
|
2621 | 728 |
case 'a': |
729 |
attr_root = s_strdup(optarg); |
|
730 |
break; |
|
0 | 731 |
case 'C': |
732 |
cleanup = TRUE; |
|
733 |
break; |
|
734 |
case 'c': |
|
735 |
num_classes++; |
|
736 |
classes = s_realloc(classes, num_classes * |
|
737 |
sizeof (char *)); |
|
738 |
classes[num_classes - 1] = optarg; |
|
739 |
break; |
|
1676 | 740 |
case 'd': |
0 | 741 |
if (daemon_mode == FALSE) { |
1676 | 742 |
/* |
743 |
* Device allocation to be disabled. |
|
744 |
*/ |
|
745 |
devalloc_flag = DA_OFF; |
|
746 |
build_dev = FALSE; |
|
747 |
} |
|
748 |
break; |
|
749 |
case 'e': |
|
750 |
if (daemon_mode == FALSE) { |
|
751 |
/* |
|
752 |
* Device allocation to be enabled. |
|
753 |
*/ |
|
754 |
devalloc_flag = DA_ON; |
|
0 | 755 |
build_dev = FALSE; |
756 |
} |
|
757 |
break; |
|
758 |
case 'I': /* update kernel driver.conf cache */ |
|
759 |
if (daemon_mode == TRUE) |
|
760 |
usage(); |
|
761 |
init_drvconf = 1; |
|
762 |
break; |
|
763 |
case 'i': |
|
764 |
single_drv = TRUE; |
|
765 |
driver = s_strdup(optarg); |
|
766 |
break; |
|
767 |
case 'l': |
|
768 |
/* specify an alternate module load path */ |
|
769 |
module_dirs = s_strdup(optarg); |
|
770 |
break; |
|
2621 | 771 |
case 'm': |
772 |
load_devname_nsmaps = TRUE; |
|
773 |
break; |
|
0 | 774 |
case 'n': |
775 |
/* prevent driver loading and deferred attach */ |
|
776 |
load_attach_drv = FALSE; |
|
777 |
break; |
|
778 |
case 'p': |
|
779 |
/* specify alternate path_to_inst file */ |
|
780 |
inst_file = s_strdup(optarg); |
|
781 |
break; |
|
782 |
case 'P': |
|
783 |
if (daemon_mode == TRUE) |
|
784 |
usage(); |
|
785 |
/* load minor_perm and device_policy */ |
|
786 |
init_perm = 1; |
|
787 |
break; |
|
788 |
case 'R': |
|
789 |
/* |
|
790 |
* Private flag for suninstall to populate |
|
791 |
* device information on the installed root. |
|
792 |
*/ |
|
793 |
root_dir = s_strdup(optarg); |
|
794 |
devfsadm_exit(devfsadm_copy()); |
|
795 |
break; |
|
796 |
case 'r': |
|
2621 | 797 |
set_root_devices_dev_dir(optarg); |
0 | 798 |
break; |
799 |
case 's': |
|
800 |
/* |
|
801 |
* suppress. don't create/remove links/nodes |
|
802 |
* useful with -v or -V |
|
803 |
*/ |
|
804 |
file_mods = FALSE; |
|
805 |
flush_path_to_inst_enable = FALSE; |
|
806 |
break; |
|
2621 | 807 |
case 'S': |
808 |
if (daemon_mode == TRUE) |
|
809 |
usage(); |
|
810 |
init_sysavail = 1; |
|
811 |
break; |
|
0 | 812 |
case 't': |
813 |
devlinktab_file = optarg; |
|
814 |
break; |
|
815 |
case 'v': |
|
816 |
/* documented verbose flag */ |
|
817 |
add_verbose_id(VERBOSE_MID); |
|
818 |
break; |
|
819 |
case 'V': |
|
820 |
/* undocumented: specify verbose lvl */ |
|
821 |
add_verbose_id(optarg); |
|
822 |
break; |
|
823 |
case 'x': |
|
824 |
/* |
|
825 |
* x is the "private switch" option. The |
|
826 |
* goal is to not suck up all the other |
|
827 |
* option letters. |
|
828 |
*/ |
|
829 |
if (strcmp(optarg, "update_devlinksdb") == 0) { |
|
830 |
update_database = TRUE; |
|
831 |
} else if (strcmp(optarg, "no_dev") == 0) { |
|
832 |
/* don't build /dev */ |
|
833 |
build_dev = FALSE; |
|
834 |
} else if (strcmp(optarg, "no_devices") == 0) { |
|
835 |
/* don't build /devices */ |
|
836 |
build_devices = FALSE; |
|
837 |
} else if (strcmp(optarg, "no_p2i") == 0) { |
|
838 |
/* don't flush path_to_inst */ |
|
839 |
flush_path_to_inst_enable = FALSE; |
|
840 |
} else if (strcmp(optarg, "use_dicache") == 0) { |
|
841 |
use_snapshot_cache = TRUE; |
|
842 |
} else { |
|
843 |
usage(); |
|
844 |
} |
|
845 |
break; |
|
846 |
default: |
|
847 |
usage(); |
|
848 |
break; |
|
849 |
} |
|
850 |
} |
|
851 |
if (optind < argc) { |
|
852 |
usage(); |
|
853 |
} |
|
854 |
||
855 |
/* |
|
856 |
* We're not in zone mode; Check to see if the rootpath |
|
857 |
* collides with any zonepaths. |
|
858 |
*/ |
|
859 |
if (zonename == NULL) { |
|
860 |
if (zone_pathcheck(root_dir) != DEVFSADM_SUCCESS) |
|
861 |
devfsadm_exit(1); |
|
862 |
} |
|
863 |
||
2621 | 864 |
if (init_drvconf || init_perm || init_sysavail) { |
0 | 865 |
/* |
866 |
* Load minor perm before force-loading drivers |
|
867 |
* so the correct permissions are picked up. |
|
868 |
*/ |
|
2621 | 869 |
if (init_perm) { |
870 |
check_reconfig_state(); |
|
0 | 871 |
load_dev_acl(); |
2621 | 872 |
} |
0 | 873 |
if (init_drvconf) |
874 |
update_drvconf((major_t)-1); |
|
2621 | 875 |
if (init_sysavail) |
876 |
modctl_sysavail(); |
|
0 | 877 |
devfsadm_exit(0); |
878 |
/* NOTREACHED */ |
|
879 |
} |
|
2621 | 880 |
|
881 |
if (load_devname_nsmaps == TRUE) { |
|
882 |
devname_setup_nsmaps(); |
|
883 |
devfsadm_exit(0); |
|
884 |
} |
|
0 | 885 |
} |
886 |
||
887 |
||
888 |
if (get_linkcompat_opts == TRUE) { |
|
889 |
||
890 |
build_devices = FALSE; |
|
891 |
load_attach_drv = FALSE; |
|
892 |
num_classes++; |
|
893 |
classes = s_realloc(classes, num_classes * |
|
894 |
sizeof (char *)); |
|
895 |
classes[num_classes - 1] = compat_class; |
|
896 |
||
897 |
while ((opt = getopt(argc, argv, "Cnr:svV:")) != EOF) { |
|
898 |
switch (opt) { |
|
899 |
case 'C': |
|
900 |
cleanup = TRUE; |
|
901 |
break; |
|
902 |
case 'n': |
|
903 |
/* prevent driver loading or deferred attach */ |
|
904 |
load_attach_drv = FALSE; |
|
905 |
break; |
|
906 |
case 'r': |
|
2621 | 907 |
set_root_devices_dev_dir(optarg); |
0 | 908 |
if (zone_pathcheck(root_dir) != |
909 |
DEVFSADM_SUCCESS) |
|
910 |
devfsadm_exit(1); |
|
911 |
break; |
|
912 |
case 's': |
|
913 |
/* suppress. don't create/remove links/nodes */ |
|
914 |
/* useful with -v or -V */ |
|
915 |
file_mods = FALSE; |
|
916 |
flush_path_to_inst_enable = FALSE; |
|
917 |
break; |
|
918 |
case 'v': |
|
919 |
/* documented verbose flag */ |
|
920 |
add_verbose_id(VERBOSE_MID); |
|
921 |
break; |
|
922 |
case 'V': |
|
923 |
/* undocumented for extra verbose levels */ |
|
924 |
add_verbose_id(optarg); |
|
925 |
break; |
|
926 |
default: |
|
927 |
usage(); |
|
928 |
} |
|
929 |
} |
|
930 |
if (optind < argc) { |
|
931 |
usage(); |
|
932 |
} |
|
933 |
} |
|
2621 | 934 |
set_lock_root(); |
0 | 935 |
} |
936 |
||
937 |
void |
|
938 |
usage(void) |
|
939 |
{ |
|
940 |
if (strcmp(prog, DEVLINKS) == 0) { |
|
941 |
err_print(DEVLINKS_USAGE); |
|
942 |
} else if (strcmp(prog, DRVCONFIG) == 0) { |
|
943 |
err_print(DRVCONFIG_USAGE); |
|
944 |
} else if ((strcmp(prog, DEVFSADM) == 0) || |
|
945 |
(strcmp(prog, DEVFSADMD) == 0)) { |
|
946 |
err_print(DEVFSADM_USAGE); |
|
947 |
} else { |
|
948 |
err_print(COMPAT_LINK_USAGE); |
|
949 |
} |
|
950 |
||
951 |
devfsadm_exit(1); |
|
952 |
} |
|
953 |
||
954 |
static void |
|
955 |
devi_tree_walk(struct dca_impl *dcip, int flags, char *ev_subclass) |
|
956 |
{ |
|
957 |
char *msg, *name; |
|
958 |
struct mlist mlist = {0}; |
|
959 |
di_node_t node; |
|
960 |
||
961 |
vprint(CHATTY_MID, "devi_tree_walk: root=%s, minor=%s, driver=%s," |
|
962 |
" error=%d, flags=%u\n", dcip->dci_root, |
|
963 |
dcip->dci_minor ? dcip->dci_minor : "<NULL>", |
|
964 |
dcip->dci_driver ? dcip->dci_driver : "<NULL>", dcip->dci_error, |
|
965 |
dcip->dci_flags); |
|
966 |
||
967 |
assert(dcip->dci_root); |
|
968 |
||
969 |
if (dcip->dci_flags & DCA_LOAD_DRV) { |
|
970 |
node = di_init_driver(dcip->dci_driver, flags); |
|
971 |
msg = DRIVER_FAILURE; |
|
972 |
name = dcip->dci_driver; |
|
973 |
} else { |
|
974 |
node = di_init(dcip->dci_root, flags); |
|
975 |
msg = DI_INIT_FAILED; |
|
976 |
name = dcip->dci_root; |
|
977 |
} |
|
978 |
||
979 |
if (node == DI_NODE_NIL) { |
|
980 |
dcip->dci_error = errno; |
|
981 |
/* |
|
982 |
* Rapid hotplugging (commonly seen during USB testing), |
|
983 |
* may remove a device before the create event for it |
|
984 |
* has been processed. To prevent alarming users with |
|
985 |
* a superfluous message, we suppress error messages |
|
986 |
* for ENXIO and hotplug. |
|
987 |
*/ |
|
988 |
if (!(errno == ENXIO && (dcip->dci_flags & DCA_HOT_PLUG))) |
|
989 |
err_print(msg, name, strerror(dcip->dci_error)); |
|
990 |
return; |
|
991 |
} |
|
992 |
||
993 |
if (dcip->dci_flags & DCA_FLUSH_PATHINST) |
|
994 |
flush_path_to_inst(); |
|
995 |
||
996 |
dcip->dci_arg = &mlist; |
|
997 |
||
998 |
vprint(CHATTY_MID, "walking device tree\n"); |
|
999 |
||
1000 |
(void) di_walk_minor(node, NULL, DI_CHECK_ALIAS, dcip, |
|
1001 |
check_minor_type); |
|
1002 |
||
1003 |
process_deferred_links(dcip, DCA_CREATE_LINK); |
|
1004 |
||
1005 |
dcip->dci_arg = NULL; |
|
1006 |
||
1007 |
/* |
|
1008 |
* Finished creating devfs files and dev links. |
|
1009 |
* Log sysevent and notify RCM. |
|
1010 |
*/ |
|
1011 |
if (ev_subclass) |
|
3854 | 1012 |
build_and_enq_event(EC_DEV_ADD, ev_subclass, dcip->dci_root, |
4211 | 1013 |
node, dcip->dci_minor); |
0 | 1014 |
|
1015 |
if ((dcip->dci_flags & DCA_NOTIFY_RCM) && rcm_hdl) |
|
1016 |
(void) notify_rcm(node, dcip->dci_minor); |
|
1017 |
||
1676 | 1018 |
/* Add new device to device allocation database */ |
1019 |
if (system_labeled && update_devdb) { |
|
1020 |
_update_devalloc_db(&devlist, 0, DA_ADD, NULL, root_dir); |
|
1021 |
update_devdb = 0; |
|
1022 |
} |
|
1023 |
||
0 | 1024 |
di_fini(node); |
1025 |
} |
|
1026 |
||
1027 |
static void |
|
1028 |
process_deferred_links(struct dca_impl *dcip, int flags) |
|
1029 |
{ |
|
1030 |
struct mlist *dep; |
|
1031 |
struct minor *mp, *smp; |
|
1032 |
||
1033 |
vprint(CHATTY_MID, "processing deferred links\n"); |
|
1034 |
||
1035 |
dep = dcip->dci_arg; |
|
1036 |
||
1037 |
/* |
|
1038 |
* The list head is not used during the deferred create phase |
|
1039 |
*/ |
|
1040 |
dcip->dci_arg = NULL; |
|
1041 |
||
1042 |
assert(dep); |
|
1043 |
assert((dep->head == NULL) ^ (dep->tail != NULL)); |
|
1044 |
assert(flags == DCA_FREE_LIST || flags == DCA_CREATE_LINK); |
|
1045 |
||
1046 |
for (smp = NULL, mp = dep->head; mp; mp = mp->next) { |
|
1047 |
if (flags == DCA_CREATE_LINK) |
|
1048 |
(void) check_minor_type(mp->node, mp->minor, dcip); |
|
1049 |
free(smp); |
|
1050 |
smp = mp; |
|
1051 |
} |
|
1052 |
||
1053 |
free(smp); |
|
1054 |
} |
|
1055 |
||
1056 |
/* |
|
1057 |
* Called in non-daemon mode to take a snap shot of the devinfo tree. |
|
1058 |
* Then it calls the appropriate functions to build /devices and /dev. |
|
1059 |
* It also flushes path_to_inst. |
|
6013
fe64a0b9ee89
6627468 The fix for CR# 6274924 has a side-effect such that process_devinfo_tree() takes longer to complete.
htk
parents:
5895
diff
changeset
|
1060 |
* Except in the devfsadm -i (single driver case), the flags used by devfsadm |
fe64a0b9ee89
6627468 The fix for CR# 6274924 has a side-effect such that process_devinfo_tree() takes longer to complete.
htk
parents:
5895
diff
changeset
|
1061 |
* needs to match DI_CACHE_SNAPSHOT_FLAGS. That will make DINFOCACHE snapshot |
fe64a0b9ee89
6627468 The fix for CR# 6274924 has a side-effect such that process_devinfo_tree() takes longer to complete.
htk
parents:
5895
diff
changeset
|
1062 |
* updated. |
0 | 1063 |
*/ |
1064 |
void |
|
1065 |
process_devinfo_tree() |
|
1066 |
{ |
|
6013
fe64a0b9ee89
6627468 The fix for CR# 6274924 has a side-effect such that process_devinfo_tree() takes longer to complete.
htk
parents:
5895
diff
changeset
|
1067 |
uint_t flags; |
0 | 1068 |
struct dca_impl dci; |
1069 |
char name[MAXNAMELEN]; |
|
1070 |
char *fcn = "process_devinfo_tree: "; |
|
1071 |
||
1072 |
vprint(CHATTY_MID, "%senter\n", fcn); |
|
1073 |
||
1074 |
dca_impl_init("/", NULL, &dci); |
|
1075 |
||
1076 |
lock_dev(); |
|
1077 |
||
1078 |
/* |
|
1079 |
* Update kernel driver.conf cache when devfsadm/drvconfig |
|
1080 |
* is invoked to build /devices and /dev. |
|
1081 |
*/ |
|
1082 |
if (load_attach_drv == TRUE) |
|
1083 |
update_drvconf((major_t)-1); |
|
1084 |
||
1085 |
if (single_drv == TRUE) { |
|
1086 |
/* |
|
1087 |
* load a single driver, but walk the entire devinfo tree |
|
1088 |
*/ |
|
1089 |
if (load_attach_drv == FALSE) |
|
1090 |
err_print(DRV_LOAD_REQD); |
|
1091 |
||
1092 |
vprint(CHATTY_MID, "%sattaching driver (%s)\n", fcn, driver); |
|
1093 |
||
1094 |
dci.dci_flags |= DCA_LOAD_DRV; |
|
1095 |
(void) snprintf(name, sizeof (name), "%s", driver); |
|
1096 |
dci.dci_driver = name; |
|
6013
fe64a0b9ee89
6627468 The fix for CR# 6274924 has a side-effect such that process_devinfo_tree() takes longer to complete.
htk
parents:
5895
diff
changeset
|
1097 |
flags = DINFOCPYALL | DINFOPATH; |
0 | 1098 |
|
1099 |
} else if (load_attach_drv == TRUE) { |
|
1100 |
/* |
|
1676 | 1101 |
* Load and attach all drivers, then walk the entire tree. |
0 | 1102 |
* If the cache flag is set, use DINFOCACHE to get cached |
1103 |
* data. |
|
1104 |
*/ |
|
1105 |
if (use_snapshot_cache == TRUE) { |
|
1106 |
flags = DINFOCACHE; |
|
1107 |
vprint(CHATTY_MID, "%susing snapshot cache\n", fcn); |
|
1108 |
} else { |
|
1109 |
vprint(CHATTY_MID, "%sattaching all drivers\n", fcn); |
|
6013
fe64a0b9ee89
6627468 The fix for CR# 6274924 has a side-effect such that process_devinfo_tree() takes longer to complete.
htk
parents:
5895
diff
changeset
|
1110 |
flags = DI_CACHE_SNAPSHOT_FLAGS; |
878 | 1111 |
if (cleanup) { |
1112 |
/* |
|
1113 |
* remove dangling entries from /etc/devices |
|
1114 |
* files. |
|
1115 |
*/ |
|
1116 |
flags |= DINFOCLEANUP; |
|
1117 |
} |
|
0 | 1118 |
} |
1119 |
} |
|
1120 |
||
1121 |
if (((load_attach_drv == TRUE) || (single_drv == TRUE)) && |
|
1122 |
(build_devices == TRUE)) { |
|
1123 |
dci.dci_flags |= DCA_FLUSH_PATHINST; |
|
1124 |
} |
|
1125 |
||
1126 |
/* handle pre-cleanup operations desired by the modules. */ |
|
1127 |
pre_and_post_cleanup(RM_PRE); |
|
1128 |
||
1129 |
devi_tree_walk(&dci, flags, NULL); |
|
1130 |
||
1131 |
if (dci.dci_error) { |
|
1132 |
devfsadm_exit(1); |
|
1133 |
} |
|
1134 |
||
1135 |
/* handle post-cleanup operations desired by the modules. */ |
|
1136 |
pre_and_post_cleanup(RM_POST); |
|
1137 |
||
1138 |
unlock_dev(SYNC_STATE); |
|
1139 |
} |
|
1140 |
||
1141 |
/*ARGSUSED*/ |
|
1142 |
static void |
|
1143 |
print_cache_signal(int signo) |
|
1144 |
{ |
|
1145 |
if (signal(SIGUSR1, print_cache_signal) == SIG_ERR) { |
|
1146 |
err_print("signal SIGUSR1 failed: %s\n", strerror(errno)); |
|
1147 |
devfsadm_exit(1); |
|
1148 |
} |
|
1149 |
} |
|
1150 |
||
2621 | 1151 |
static void |
1152 |
revoke_lookup_door(void) |
|
1153 |
{ |
|
1154 |
if (lookup_door_fd != -1) { |
|
1155 |
if (door_revoke(lookup_door_fd) == -1) { |
|
1156 |
err_print("door_revoke of %s failed - %s\n", |
|
1157 |
lookup_door_path, strerror(errno)); |
|
1158 |
} |
|
1159 |
} |
|
1160 |
} |
|
1161 |
||
1162 |
/*ARGSUSED*/ |
|
1163 |
static void |
|
1164 |
catch_exit(int signo) |
|
1165 |
{ |
|
1166 |
revoke_lookup_door(); |
|
1167 |
} |
|
1168 |
||
0 | 1169 |
/* |
1170 |
* Register with eventd for messages. Create doors for synchronous |
|
1171 |
* link creation. |
|
1172 |
*/ |
|
1173 |
static void |
|
1174 |
daemon_update(void) |
|
1175 |
{ |
|
1176 |
int fd; |
|
1177 |
char *fcn = "daemon_update: "; |
|
1178 |
char door_file[MAXPATHLEN]; |
|
1179 |
const char *subclass_list; |
|
1180 |
sysevent_handle_t *sysevent_hp; |
|
1181 |
vprint(CHATTY_MID, "%senter\n", fcn); |
|
1182 |
||
1183 |
if (signal(SIGUSR1, print_cache_signal) == SIG_ERR) { |
|
1184 |
err_print("signal SIGUSR1 failed: %s\n", strerror(errno)); |
|
1185 |
devfsadm_exit(1); |
|
1186 |
} |
|
2621 | 1187 |
if (signal(SIGTERM, catch_exit) == SIG_ERR) { |
1188 |
err_print("signal SIGTERM failed: %s\n", strerror(errno)); |
|
1189 |
devfsadm_exit(1); |
|
1190 |
} |
|
0 | 1191 |
|
1192 |
if (snprintf(door_file, sizeof (door_file), |
|
2621 | 1193 |
"%s%s", attr_root ? attr_root : root_dir, DEVFSADM_SERVICE_DOOR) |
1194 |
>= sizeof (door_file)) { |
|
0 | 1195 |
err_print("update_daemon failed to open sysevent service " |
1196 |
"door\n"); |
|
1197 |
devfsadm_exit(1); |
|
1198 |
} |
|
1199 |
if ((sysevent_hp = sysevent_open_channel_alt( |
|
1200 |
door_file)) == NULL) { |
|
1201 |
err_print(CANT_CREATE_DOOR, |
|
1202 |
door_file, strerror(errno)); |
|
1203 |
devfsadm_exit(1); |
|
1204 |
} |
|
1205 |
if (sysevent_bind_subscriber(sysevent_hp, event_handler) != 0) { |
|
1206 |
err_print(CANT_CREATE_DOOR, |
|
1207 |
door_file, strerror(errno)); |
|
1208 |
(void) sysevent_close_channel(sysevent_hp); |
|
1209 |
devfsadm_exit(1); |
|
1210 |
} |
|
1211 |
subclass_list = EC_SUB_ALL; |
|
1212 |
if (sysevent_register_event(sysevent_hp, EC_ALL, &subclass_list, 1) |
|
1213 |
!= 0) { |
|
1214 |
err_print(CANT_CREATE_DOOR, |
|
1215 |
door_file, strerror(errno)); |
|
1216 |
(void) sysevent_unbind_subscriber(sysevent_hp); |
|
1217 |
(void) sysevent_close_channel(sysevent_hp); |
|
1218 |
devfsadm_exit(1); |
|
1219 |
} |
|
2621 | 1220 |
if (snprintf(door_file, sizeof (door_file), "%s/%s", |
1221 |
etc_dev_dir, DEVFSADM_SYNCH_DOOR) >= sizeof (door_file)) { |
|
1222 |
err_print(CANT_CREATE_DOOR, DEVFSADM_SYNCH_DOOR, |
|
0 | 1223 |
strerror(ENAMETOOLONG)); |
1224 |
devfsadm_exit(1); |
|
1225 |
} |
|
1226 |
||
1227 |
(void) s_unlink(door_file); |
|
1228 |
if ((fd = open(door_file, O_RDWR | O_CREAT, SYNCH_DOOR_PERMS)) == -1) { |
|
1229 |
err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); |
|
1230 |
devfsadm_exit(1); |
|
1231 |
} |
|
1232 |
(void) close(fd); |
|
1233 |
||
1234 |
if ((fd = door_create(sync_handler, NULL, |
|
1235 |
DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { |
|
1236 |
err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); |
|
1237 |
(void) s_unlink(door_file); |
|
1238 |
devfsadm_exit(1); |
|
1239 |
} |
|
1240 |
||
1241 |
if (fattach(fd, door_file) == -1) { |
|
1242 |
err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); |
|
1243 |
(void) s_unlink(door_file); |
|
1244 |
devfsadm_exit(1); |
|
1245 |
} |
|
1246 |
||
1247 |
/* |
|
2621 | 1248 |
* devname_lookup_door |
0 | 1249 |
*/ |
2621 | 1250 |
if (snprintf(door_file, sizeof (door_file), "%s/%s", |
1251 |
etc_dev_dir, DEVNAME_LOOKUP_DOOR) >= sizeof (door_file)) { |
|
1252 |
err_print(CANT_CREATE_DOOR, DEVNAME_LOOKUP_DOOR, |
|
1253 |
strerror(ENAMETOOLONG)); |
|
1254 |
devfsadm_exit(1); |
|
1255 |
} |
|
1256 |
||
1257 |
(void) s_unlink(door_file); |
|
1258 |
if ((fd = open(door_file, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR)) == -1) { |
|
1259 |
err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); |
|
1260 |
devfsadm_exit(1); |
|
1261 |
} |
|
1262 |
(void) close(fd); |
|
1263 |
||
1264 |
if ((fd = door_create(devname_lookup_handler, NULL, |
|
1265 |
DOOR_REFUSE_DESC)) == -1) { |
|
1266 |
err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); |
|
1267 |
(void) s_unlink(door_file); |
|
1268 |
devfsadm_exit(1); |
|
1269 |
} |
|
1270 |
||
1271 |
(void) fdetach(door_file); |
|
1272 |
lookup_door_path = s_strdup(door_file); |
|
1273 |
retry: |
|
1274 |
if (fattach(fd, door_file) == -1) { |
|
1275 |
if (errno == EBUSY) |
|
1276 |
goto retry; |
|
1277 |
err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); |
|
1278 |
(void) s_unlink(door_file); |
|
1279 |
devfsadm_exit(1); |
|
1280 |
} |
|
1281 |
lookup_door_fd = fd; |
|
1282 |
||
1283 |
/* pass down the door name to kernel for door_ki_open */ |
|
1284 |
if (devname_kcall(MODDEVNAME_LOOKUPDOOR, (void *)door_file) != 0) |
|
1285 |
err_print(DEVNAME_CONTACT_FAILED, strerror(errno)); |
|
1286 |
else |
|
1287 |
devname_setup_nsmaps(); |
|
0 | 1288 |
|
1289 |
vprint(CHATTY_MID, "%spausing\n", fcn); |
|
1290 |
for (;;) { |
|
1291 |
(void) pause(); |
|
1292 |
} |
|
1293 |
} |
|
1294 |
||
1295 |
/*ARGSUSED*/ |
|
1296 |
static void |
|
1297 |
sync_handler(void *cookie, char *ap, size_t asize, |
|
1298 |
door_desc_t *dp, uint_t ndesc) |
|
1299 |
{ |
|
1300 |
door_cred_t dcred; |
|
1301 |
struct dca_off *dcp, rdca; |
|
1302 |
struct dca_impl dci; |
|
1303 |
||
1304 |
/* |
|
1305 |
* Must be root to make this call |
|
1306 |
* If caller is not root, don't touch its data. |
|
1307 |
*/ |
|
1308 |
if (door_cred(&dcred) != 0 || dcred.dc_euid != 0) { |
|
1309 |
dcp = ⤷ |
|
1310 |
dcp->dca_error = EPERM; |
|
1311 |
goto out; |
|
1312 |
} |
|
1313 |
||
1314 |
assert(ap); |
|
1315 |
assert(asize == sizeof (*dcp)); |
|
1316 |
||
1317 |
dcp = (void *)ap; |
|
1318 |
||
1319 |
/* |
|
1320 |
* Root is always present and is the first component of "name" member |
|
1321 |
*/ |
|
1322 |
assert(dcp->dca_root == 0); |
|
1323 |
||
1324 |
/* |
|
1325 |
* The structure passed in by the door_client uses offsets |
|
1326 |
* instead of pointers to work across address space boundaries. |
|
1327 |
* Now copy the data into a structure (dca_impl) which uses |
|
1328 |
* pointers. |
|
1329 |
*/ |
|
1330 |
dci.dci_root = &dcp->dca_name[dcp->dca_root]; |
|
1331 |
dci.dci_minor = dcp->dca_minor ? &dcp->dca_name[dcp->dca_minor] : NULL; |
|
1332 |
dci.dci_driver = |
|
1333 |
dcp->dca_driver ? &dcp->dca_name[dcp->dca_driver] : NULL; |
|
1334 |
dci.dci_error = 0; |
|
1335 |
dci.dci_flags = dcp->dca_flags | (dci.dci_driver ? DCA_LOAD_DRV : 0); |
|
1336 |
dci.dci_arg = NULL; |
|
1337 |
||
1338 |
lock_dev(); |
|
1339 |
devi_tree_walk(&dci, DINFOCPYALL, NULL); |
|
1340 |
dcp->dca_error = dci.dci_error; |
|
1341 |
||
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1342 |
if (dcp->dca_flags & DCA_DEVLINK_SYNC) |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1343 |
unlock_dev(SYNC_STATE); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1344 |
else |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1345 |
unlock_dev(CACHE_STATE); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1346 |
|
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1347 |
out: (void) door_return((char *)dcp, sizeof (*dcp), NULL, 0); |
0 | 1348 |
} |
1349 |
||
1350 |
static void |
|
1351 |
lock_dev(void) |
|
1352 |
{ |
|
1353 |
vprint(CHATTY_MID, "lock_dev(): entered\n"); |
|
1354 |
||
1355 |
if (build_dev == FALSE) |
|
1356 |
return; |
|
1357 |
||
1358 |
/* lockout other threads from /dev */ |
|
1359 |
while (sema_wait(&dev_sema) != 0); |
|
1360 |
||
1361 |
/* |
|
1362 |
* Lock out other devfsadm processes from /dev. |
|
1363 |
* If this wasn't the last process to run, |
|
1364 |
* clear caches |
|
1365 |
*/ |
|
1366 |
if (enter_dev_lock() != getpid()) { |
|
1367 |
invalidate_enumerate_cache(); |
|
1368 |
rm_all_links_from_cache(); |
|
1369 |
(void) di_devlink_close(&devlink_cache, DI_LINK_ERROR); |
|
3854 | 1370 |
|
1371 |
/* send any sysevents that were queued up. */ |
|
1372 |
process_syseventq(); |
|
0 | 1373 |
} |
1374 |
||
1375 |
/* |
|
1376 |
* (re)load the reverse links database if not |
|
1377 |
* already cached. |
|
1378 |
*/ |
|
1379 |
if (devlink_cache == NULL) |
|
1380 |
devlink_cache = di_devlink_open(root_dir, 0); |
|
1381 |
||
1382 |
/* |
|
1383 |
* If modules were unloaded, reload them. Also use module status |
|
1384 |
* as an indication that we should check to see if other binding |
|
1385 |
* files need to be reloaded. |
|
1386 |
*/ |
|
1387 |
if (module_head == NULL) { |
|
1388 |
load_modules(); |
|
1389 |
read_minor_perm_file(); |
|
1390 |
read_driver_aliases_file(); |
|
1391 |
read_devlinktab_file(); |
|
1392 |
read_logindevperm_file(); |
|
4876 | 1393 |
read_enumerate_file(); |
0 | 1394 |
} |
1395 |
||
1396 |
if (module_head != NULL) |
|
1397 |
return; |
|
1398 |
||
1399 |
if (strcmp(prog, DEVLINKS) == 0) { |
|
1400 |
if (devlinktab_list == NULL) { |
|
1401 |
err_print(NO_LINKTAB, devlinktab_file); |
|
1402 |
err_print(NO_MODULES, module_dirs); |
|
1403 |
err_print(ABORTING); |
|
1404 |
devfsadm_exit(1); |
|
1405 |
} |
|
1406 |
} else { |
|
1407 |
err_print(NO_MODULES, module_dirs); |
|
1408 |
if (strcmp(prog, DEVFSADM) == 0) { |
|
1409 |
err_print(MODIFY_PATH); |
|
1410 |
} |
|
1411 |
} |
|
1412 |
} |
|
1413 |
||
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1414 |
/* |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1415 |
* Unlock the device. If we are processing a CACHE_STATE call, we signal a |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1416 |
* minor_fini_thread delayed SYNC_STATE at the end of the call. If we are |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1417 |
* processing a SYNC_STATE call, we cancel any minor_fini_thread SYNC_STATE |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1418 |
* at both the start and end of the call since we will be doing the SYNC_STATE. |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1419 |
*/ |
0 | 1420 |
static void |
1421 |
unlock_dev(int flag) |
|
1422 |
{ |
|
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1423 |
assert(flag == SYNC_STATE || flag == CACHE_STATE); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1424 |
|
0 | 1425 |
vprint(CHATTY_MID, "unlock_dev(): entered\n"); |
1426 |
||
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1427 |
/* If we are starting a SYNC_STATE, cancel minor_fini_thread SYNC */ |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1428 |
if (flag == SYNC_STATE) { |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1429 |
(void) mutex_lock(&minor_fini_mutex); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1430 |
minor_fini_canceled = TRUE; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1431 |
minor_fini_delayed = FALSE; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1432 |
(void) mutex_unlock(&minor_fini_mutex); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1433 |
} |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1434 |
|
0 | 1435 |
if (build_dev == FALSE) |
1436 |
return; |
|
1437 |
||
3858
c1c1d0ea79ef
6527366 di_devlink_open() fails in the miniroot after devname integration
vikram
parents:
3854
diff
changeset
|
1438 |
if (devlink_cache == NULL) { |
c1c1d0ea79ef
6527366 di_devlink_open() fails in the miniroot after devname integration
vikram
parents:
3854
diff
changeset
|
1439 |
err_print(NO_DEVLINK_CACHE); |
c1c1d0ea79ef
6527366 di_devlink_open() fails in the miniroot after devname integration
vikram
parents:
3854
diff
changeset
|
1440 |
} |
0 | 1441 |
assert(devlink_cache); |
1442 |
||
1443 |
if (flag == SYNC_STATE) { |
|
1444 |
unload_modules(); |
|
1445 |
if (update_database) |
|
1446 |
(void) di_devlink_update(devlink_cache); |
|
1447 |
(void) di_devlink_close(&devlink_cache, 0); |
|
3854 | 1448 |
|
1449 |
/* |
|
1450 |
* now that the devlinks db cache has been flushed, it is safe |
|
1451 |
* to send any sysevents that were queued up. |
|
1452 |
*/ |
|
1453 |
process_syseventq(); |
|
0 | 1454 |
} |
1455 |
||
1456 |
exit_dev_lock(); |
|
1457 |
||
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1458 |
(void) mutex_lock(&minor_fini_mutex); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1459 |
if (flag == SYNC_STATE) { |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1460 |
/* We did a SYNC_STATE, cancel minor_fini_thread SYNC */ |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1461 |
minor_fini_canceled = TRUE; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1462 |
minor_fini_delayed = FALSE; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1463 |
} else { |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1464 |
/* We did a CACHE_STATE, start delayed minor_fini_thread SYNC */ |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1465 |
minor_fini_canceled = FALSE; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1466 |
minor_fini_delayed = TRUE; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1467 |
(void) cond_signal(&minor_fini_cv); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1468 |
} |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1469 |
(void) mutex_unlock(&minor_fini_mutex); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
1470 |
|
0 | 1471 |
(void) sema_post(&dev_sema); |
1472 |
} |
|
1473 |
||
1474 |
/* |
|
1475 |
* Check that if -r is set, it is not any part of a zone--- that is, that |
|
1476 |
* the zonepath is not a substring of the root path. |
|
1477 |
*/ |
|
1478 |
static int |
|
1479 |
zone_pathcheck(char *checkpath) |
|
1480 |
{ |
|
1481 |
void *dlhdl = NULL; |
|
1482 |
char *name; |
|
1483 |
char root[MAXPATHLEN]; /* resolved devfsadm root path */ |
|
1484 |
char zroot[MAXPATHLEN]; /* zone root path */ |
|
1485 |
char rzroot[MAXPATHLEN]; /* resolved zone root path */ |
|
2621 | 1486 |
char tmp[MAXPATHLEN]; |
0 | 1487 |
FILE *cookie; |
1488 |
int err = DEVFSADM_SUCCESS; |
|
1489 |
||
1490 |
if (checkpath[0] == '\0') |
|
1491 |
return (DEVFSADM_SUCCESS); |
|
1492 |
||
1493 |
/* |
|
1494 |
* Check if zones is available on this system. |
|
1495 |
*/ |
|
1496 |
if ((dlhdl = dlopen(LIBZONECFG_PATH, RTLD_LAZY)) == NULL) { |
|
1497 |
return (DEVFSADM_SUCCESS); |
|
1498 |
} |
|
1499 |
||
1500 |
bzero(root, sizeof (root)); |
|
1501 |
if (resolvepath(checkpath, root, sizeof (root) - 1) == -1) { |
|
1502 |
/* |
|
2621 | 1503 |
* In this case the user has done "devfsadm -r" on some path |
0 | 1504 |
* which does not yet exist, or we got some other misc. error. |
1505 |
* We punt and don't resolve the path in this case. |
|
1506 |
*/ |
|
1507 |
(void) strlcpy(root, checkpath, sizeof (root)); |
|
1508 |
} |
|
1509 |
||
1510 |
if (strlen(root) > 0 && (root[strlen(root) - 1] != '/')) { |
|
1511 |
(void) snprintf(tmp, sizeof (tmp), "%s/", root); |
|
1512 |
(void) strlcpy(root, tmp, sizeof (root)); |
|
1513 |
} |
|
1514 |
||
1515 |
cookie = setzoneent(); |
|
1516 |
while ((name = getzoneent(cookie)) != NULL) { |
|
1517 |
/* Skip the global zone */ |
|
1518 |
if (strcmp(name, GLOBAL_ZONENAME) == 0) { |
|
1519 |
free(name); |
|
1520 |
continue; |
|
1521 |
} |
|
1522 |
||
1523 |
if (zone_get_zonepath(name, zroot, sizeof (zroot)) != Z_OK) { |
|
1524 |
free(name); |
|
1525 |
continue; |
|
1526 |
} |
|
1527 |
||
1528 |
bzero(rzroot, sizeof (rzroot)); |
|
1529 |
if (resolvepath(zroot, rzroot, sizeof (rzroot) - 1) == -1) { |
|
1530 |
/* |
|
1531 |
* Zone path doesn't exist, or other misc error, |
|
1532 |
* so we try using the non-resolved pathname. |
|
1533 |
*/ |
|
1534 |
(void) strlcpy(rzroot, zroot, sizeof (rzroot)); |
|
1535 |
} |
|
1536 |
if (strlen(rzroot) > 0 && (rzroot[strlen(rzroot) - 1] != '/')) { |
|
1537 |
(void) snprintf(tmp, sizeof (tmp), "%s/", rzroot); |
|
1538 |
(void) strlcpy(rzroot, tmp, sizeof (rzroot)); |
|
1539 |
} |
|
1540 |
||
1541 |
/* |
|
1542 |
* Finally, the comparison. If the zone root path is a |
|
1543 |
* leading substring of the root path, fail. |
|
1544 |
*/ |
|
1545 |
if (strncmp(rzroot, root, strlen(rzroot)) == 0) { |
|
1546 |
err_print(ZONE_PATHCHECK, root, name); |
|
1547 |
err = DEVFSADM_FAILURE; |
|
1548 |
free(name); |
|
1549 |
break; |
|
1550 |
} |
|
1551 |
free(name); |
|
1552 |
} |
|
1553 |
endzoneent(cookie); |
|
1554 |
(void) dlclose(dlhdl); |
|
1555 |
return (err); |
|
1556 |
} |
|
1557 |
||
1558 |
/* |
|
1559 |
* Called by the daemon when it receives an event from the devfsadm SLM |
|
1560 |
* to syseventd. |
|
1561 |
* |
|
1562 |
* The devfsadm SLM uses a private event channel for communication to |
|
1563 |
* devfsadmd set-up via private libsysevent interfaces. This handler is |
|
1564 |
* used to bind to the devfsadmd channel for event delivery. |
|
1565 |
* The devfsadmd SLM insures single calls to this routine as well as |
|
1566 |
* synchronized event delivery. |
|
1567 |
* |
|
1568 |
*/ |
|
1569 |
static void |
|
1570 |
event_handler(sysevent_t *ev) |
|
1571 |
{ |
|
1572 |
char *path; |
|
1573 |
char *minor; |
|
1574 |
char *subclass; |
|
1575 |
char *dev_ev_subclass; |
|
1576 |
char *driver_name; |
|
1577 |
nvlist_t *attr_list = NULL; |
|
1578 |
int err = 0; |
|
1579 |
int instance; |
|
1580 |
int branch_event = 0; |
|
1581 |
||
1582 |
subclass = sysevent_get_subclass_name(ev); |
|
1583 |
vprint(EVENT_MID, "event_handler: %s id:0X%llx\n", |
|
1584 |
subclass, sysevent_get_seq(ev)); |
|
1585 |
||
2621 | 1586 |
if (strcmp(subclass, ESC_DEVFS_START) == 0) { |
1587 |
return; |
|
1588 |
} |
|
1589 |
||
0 | 1590 |
/* Check if event is an instance modification */ |
1591 |
if (strcmp(subclass, ESC_DEVFS_INSTANCE_MOD) == 0) { |
|
1592 |
devfs_instance_mod(); |
|
1593 |
return; |
|
1594 |
} |
|
1595 |
if (sysevent_get_attr_list(ev, &attr_list) != 0) { |
|
1596 |
vprint(EVENT_MID, "event_handler: can not get attr list\n"); |
|
1597 |
return; |
|
1598 |
} |
|
1599 |
||
1600 |
if (strcmp(subclass, ESC_DEVFS_DEVI_ADD) == 0 || |
|
1601 |
strcmp(subclass, ESC_DEVFS_DEVI_REMOVE) == 0 || |
|
1602 |
strcmp(subclass, ESC_DEVFS_MINOR_CREATE) == 0 || |
|
1603 |
strcmp(subclass, ESC_DEVFS_MINOR_REMOVE) == 0) { |
|
1604 |
if ((err = nvlist_lookup_string(attr_list, DEVFS_PATHNAME, |
|
1605 |
&path)) != 0) |
|
1606 |
goto out; |
|
1607 |
||
4211 | 1608 |
if (nvlist_lookup_string(attr_list, DEVFS_DEVI_CLASS, |
1609 |
&dev_ev_subclass) != 0) |
|
1610 |
dev_ev_subclass = NULL; |
|
1611 |
||
1612 |
if (nvlist_lookup_string(attr_list, DEVFS_DRIVER_NAME, |
|
1613 |
&driver_name) != 0) |
|
1614 |
driver_name = NULL; |
|
1615 |
||
1616 |
if (nvlist_lookup_int32(attr_list, DEVFS_INSTANCE, |
|
1617 |
&instance) != 0) |
|
1618 |
instance = -1; |
|
1619 |
||
1620 |
if (nvlist_lookup_int32(attr_list, DEVFS_BRANCH_EVENT, |
|
1621 |
&branch_event) != 0) |
|
1622 |
branch_event = 0; |
|
1623 |
||
1624 |
if (nvlist_lookup_string(attr_list, DEVFS_MINOR_NAME, |
|
1625 |
&minor) != 0) |
|
1626 |
minor = NULL; |
|
0 | 1627 |
|
1628 |
lock_dev(); |
|
1629 |
||
1630 |
if (strcmp(ESC_DEVFS_DEVI_ADD, subclass) == 0) { |
|
1631 |
add_minor_pathname(path, NULL, dev_ev_subclass); |
|
1632 |
if (branch_event) { |
|
3854 | 1633 |
build_and_enq_event(EC_DEV_BRANCH, |
4211 | 1634 |
ESC_DEV_BRANCH_ADD, path, DI_NODE_NIL, |
1635 |
NULL); |
|
0 | 1636 |
} |
1637 |
||
1638 |
} else if (strcmp(ESC_DEVFS_MINOR_CREATE, subclass) == 0) { |
|
4211 | 1639 |
add_minor_pathname(path, minor, dev_ev_subclass); |
0 | 1640 |
|
1641 |
} else if (strcmp(ESC_DEVFS_MINOR_REMOVE, subclass) == 0) { |
|
4211 | 1642 |
hot_cleanup(path, minor, dev_ev_subclass, driver_name, |
1643 |
instance); |
|
0 | 1644 |
|
1645 |
} else { /* ESC_DEVFS_DEVI_REMOVE */ |
|
1646 |
hot_cleanup(path, NULL, dev_ev_subclass, |
|
1647 |
driver_name, instance); |
|
1648 |
if (branch_event) { |
|
3854 | 1649 |
build_and_enq_event(EC_DEV_BRANCH, |
4211 | 1650 |
ESC_DEV_BRANCH_REMOVE, path, DI_NODE_NIL, |
1651 |
NULL); |
|
0 | 1652 |
} |
1653 |
} |
|
1654 |
||
1655 |
unlock_dev(CACHE_STATE); |
|
1656 |
||
1657 |
} else if (strcmp(subclass, ESC_DEVFS_BRANCH_ADD) == 0 || |
|
1658 |
strcmp(subclass, ESC_DEVFS_BRANCH_REMOVE) == 0) { |
|
1659 |
if ((err = nvlist_lookup_string(attr_list, |
|
1660 |
DEVFS_PATHNAME, &path)) != 0) |
|
1661 |
goto out; |
|
1662 |
||
1663 |
/* just log ESC_DEV_BRANCH... event */ |
|
1664 |
if (strcmp(subclass, ESC_DEVFS_BRANCH_ADD) == 0) |
|
1665 |
dev_ev_subclass = ESC_DEV_BRANCH_ADD; |
|
1666 |
else |
|
1667 |
dev_ev_subclass = ESC_DEV_BRANCH_REMOVE; |
|
1668 |
||
578
aa1ffd6f3e7b
6317254 missing lock_dev()/unlock_dev() in devfsadm event_handler()
cth
parents:
296
diff
changeset
|
1669 |
lock_dev(); |
3854 | 1670 |
build_and_enq_event(EC_DEV_BRANCH, dev_ev_subclass, path, |
4211 | 1671 |
DI_NODE_NIL, NULL); |
578
aa1ffd6f3e7b
6317254 missing lock_dev()/unlock_dev() in devfsadm event_handler()
cth
parents:
296
diff
changeset
|
1672 |
unlock_dev(CACHE_STATE); |
0 | 1673 |
} else |
1674 |
err_print(UNKNOWN_EVENT, subclass); |
|
1675 |
||
1676 |
out: |
|
1677 |
if (err) |
|
1678 |
err_print(EVENT_ATTR_LOOKUP_FAILED, strerror(err)); |
|
1679 |
nvlist_free(attr_list); |
|
1680 |
} |
|
1681 |
||
1682 |
static void |
|
1683 |
dca_impl_init(char *root, char *minor, struct dca_impl *dcip) |
|
1684 |
{ |
|
1685 |
assert(root); |
|
1686 |
||
1687 |
dcip->dci_root = root; |
|
1688 |
dcip->dci_minor = minor; |
|
1689 |
dcip->dci_driver = NULL; |
|
1690 |
dcip->dci_error = 0; |
|
1691 |
dcip->dci_flags = 0; |
|
1692 |
dcip->dci_arg = NULL; |
|
1693 |
} |
|
1694 |
||
1695 |
/* |
|
1696 |
* Kernel logs a message when a devinfo node is attached. Try to create |
|
1697 |
* /dev and /devices for each minor node. minorname can be NULL. |
|
1698 |
*/ |
|
1699 |
void |
|
1700 |
add_minor_pathname(char *node, char *minor, char *ev_subclass) |
|
1701 |
{ |
|
1702 |
struct dca_impl dci; |
|
1703 |
||
1704 |
vprint(CHATTY_MID, "add_minor_pathname: node_path=%s minor=%s\n", |
|
1705 |
node, minor ? minor : "NULL"); |
|
1706 |
||
1707 |
dca_impl_init(node, minor, &dci); |
|
1708 |
||
1709 |
/* |
|
1710 |
* Restrict hotplug link creation if daemon |
|
1711 |
* started with -i option. |
|
1712 |
*/ |
|
1713 |
if (single_drv == TRUE) { |
|
1714 |
dci.dci_driver = driver; |
|
1715 |
} |
|
1716 |
||
1717 |
/* |
|
1718 |
* We are being invoked in response to a hotplug |
|
1719 |
* event. Also, notify RCM if nodetype indicates |
|
1720 |
* a network device has been hotplugged. |
|
1721 |
*/ |
|
1722 |
dci.dci_flags = DCA_HOT_PLUG | DCA_CHECK_TYPE; |
|
1723 |
||
1724 |
devi_tree_walk(&dci, DINFOPROP|DINFOMINOR, ev_subclass); |
|
1725 |
} |
|
1726 |
||
1727 |
static di_node_t |
|
1728 |
find_clone_node() |
|
1729 |
{ |
|
1730 |
static di_node_t clone_node = DI_NODE_NIL; |
|
1731 |
||
1732 |
if (clone_node == DI_NODE_NIL) |
|
1733 |
clone_node = di_init("/pseudo/clone@0", DINFOPROP); |
|
1734 |
return (clone_node); |
|
1735 |
} |
|
1736 |
||
1737 |
static int |
|
1738 |
is_descendent_of(di_node_t node, char *driver) |
|
1739 |
{ |
|
1740 |
while (node != DI_NODE_NIL) { |
|
1741 |
char *drv = di_driver_name(node); |
|
1742 |
if (strcmp(drv, driver) == 0) |
|
1743 |
return (1); |
|
1744 |
node = di_parent_node(node); |
|
1745 |
} |
|
1746 |
return (0); |
|
1747 |
} |
|
1748 |
||
1749 |
/* |
|
1750 |
* Checks the minor type. If it is an alias node, then lookup |
|
1751 |
* the real node/minor first, then call minor_process() to |
|
1752 |
* do the real work. |
|
1753 |
*/ |
|
1754 |
static int |
|
1755 |
check_minor_type(di_node_t node, di_minor_t minor, void *arg) |
|
1756 |
{ |
|
1757 |
ddi_minor_type minor_type; |
|
1758 |
di_node_t clone_node; |
|
1759 |
char *mn; |
|
1760 |
char *nt; |
|
1761 |
struct mlist *dep; |
|
1762 |
struct dca_impl *dcip = arg; |
|
1763 |
||
1764 |
assert(dcip); |
|
1765 |
||
1766 |
dep = dcip->dci_arg; |
|
1767 |
||
1768 |
mn = di_minor_name(minor); |
|
1769 |
||
1770 |
/* |
|
1771 |
* We match driver here instead of in minor_process |
|
1772 |
* as we want the actual driver name. This check is |
|
1773 |
* unnecessary during deferred processing. |
|
1774 |
*/ |
|
1775 |
if (dep && |
|
1776 |
((dcip->dci_driver && !is_descendent_of(node, dcip->dci_driver)) || |
|
1777 |
(dcip->dci_minor && strcmp(mn, dcip->dci_minor)))) { |
|
1778 |
return (DI_WALK_CONTINUE); |
|
1779 |
} |
|
1780 |
||
1781 |
if ((dcip->dci_flags & DCA_CHECK_TYPE) && |
|
1782 |
(nt = di_minor_nodetype(minor)) && |
|
269
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
1783 |
(strcmp(nt, DDI_NT_NET) == 0)) { |
0 | 1784 |
dcip->dci_flags |= DCA_NOTIFY_RCM; |
1785 |
dcip->dci_flags &= ~DCA_CHECK_TYPE; |
|
1786 |
} |
|
1787 |
||
1788 |
minor_type = di_minor_type(minor); |
|
1789 |
||
1790 |
if (minor_type == DDM_MINOR) { |
|
1791 |
minor_process(node, minor, dep); |
|
1792 |
||
1793 |
} else if (minor_type == DDM_ALIAS) { |
|
1794 |
struct mlist *cdep, clone_del = {0}; |
|
1795 |
||
1796 |
clone_node = find_clone_node(); |
|
1797 |
if (clone_node == DI_NODE_NIL) { |
|
1798 |
err_print(DI_INIT_FAILED, "clone", strerror(errno)); |
|
1799 |
return (DI_WALK_CONTINUE); |
|
1800 |
} |
|
1801 |
||
1802 |
cdep = dep ? &clone_del : NULL; |
|
1803 |
||
1804 |
minor_process(clone_node, minor, cdep); |
|
1805 |
||
1806 |
/* |
|
1807 |
* cache "alias" minor node and free "clone" minor |
|
1808 |
*/ |
|
1809 |
if (cdep != NULL && cdep->head != NULL) { |
|
1810 |
assert(cdep->tail != NULL); |
|
1811 |
cache_deferred_minor(dep, node, minor); |
|
1812 |
dcip->dci_arg = cdep; |
|
1813 |
process_deferred_links(dcip, DCA_FREE_LIST); |
|
1814 |
dcip->dci_arg = dep; |
|
1815 |
} |
|
1816 |
} |
|
1817 |
||
1818 |
return (DI_WALK_CONTINUE); |
|
1819 |
} |
|
1820 |
||
1821 |
||
1822 |
/* |
|
1823 |
* This is the entry point for each minor node, whether walking |
|
1824 |
* the entire tree via di_walk_minor() or processing a hotplug event |
|
1825 |
* for a single devinfo node (via hotplug ndi_devi_online()). |
|
1826 |
*/ |
|
1827 |
/*ARGSUSED*/ |
|
1828 |
static void |
|
1829 |
minor_process(di_node_t node, di_minor_t minor, struct mlist *dep) |
|
1830 |
{ |
|
1831 |
create_list_t *create; |
|
1832 |
int defer; |
|
1833 |
||
1834 |
vprint(CHATTY_MID, "minor_process: node=%s, minor=%s\n", |
|
1835 |
di_node_name(node), di_minor_name(minor)); |
|
1836 |
||
1837 |
if (dep != NULL) { |
|
1838 |
||
1839 |
/* |
|
1840 |
* Reset /devices node to minor_perm perm/ownership |
|
1841 |
* if we are here to deactivate device allocation |
|
1842 |
*/ |
|
1843 |
if (build_devices == TRUE) { |
|
1844 |
reset_node_permissions(node, minor); |
|
1845 |
} |
|
1846 |
||
1847 |
if (build_dev == FALSE) { |
|
1848 |
return; |
|
1849 |
} |
|
1850 |
||
1851 |
/* |
|
1852 |
* This function will create any nodes for /etc/devlink.tab. |
|
1853 |
* If devlink.tab handles link creation, we don't call any |
|
1854 |
* devfsadm modules since that could cause duplicate caching |
|
1855 |
* in the enumerate functions if different re strings are |
|
1856 |
* passed that are logically identical. I'm still not |
|
1857 |
* convinced this would cause any harm, but better to be safe. |
|
1858 |
* |
|
1859 |
* Deferred processing is available only for devlinks |
|
1860 |
* created through devfsadm modules. |
|
1861 |
*/ |
|
1862 |
if (process_devlink_compat(minor, node) == TRUE) { |
|
1863 |
return; |
|
1864 |
} |
|
1865 |
} else { |
|
1866 |
vprint(CHATTY_MID, "minor_process: deferred processing\n"); |
|
1867 |
} |
|
1868 |
||
1869 |
/* |
|
1870 |
* look for relevant link create rules in the modules, and |
|
1871 |
* invoke the link create callback function to build a link |
|
1872 |
* if there is a match. |
|
1873 |
*/ |
|
1874 |
defer = 0; |
|
1875 |
for (create = create_head; create != NULL; create = create->next) { |
|
1876 |
if ((minor_matches_rule(node, minor, create) == TRUE) && |
|
1877 |
class_ok(create->create->device_class) == |
|
1878 |
DEVFSADM_SUCCESS) { |
|
1879 |
if (call_minor_init(create->modptr) == |
|
1880 |
DEVFSADM_FAILURE) { |
|
1881 |
continue; |
|
1882 |
} |
|
1883 |
||
1884 |
/* |
|
1885 |
* If NOT doing the deferred creates (i.e. 1st pass) and |
|
1886 |
* rule requests deferred processing cache the minor |
|
1887 |
* data. |
|
1888 |
* |
|
1889 |
* If deferred processing (2nd pass), create links |
|
1890 |
* ONLY if rule requests deferred processing. |
|
1891 |
*/ |
|
1892 |
if (dep && ((create->create->flags & CREATE_MASK) == |
|
1893 |
CREATE_DEFER)) { |
|
1894 |
defer = 1; |
|
1895 |
continue; |
|
1896 |
} else if (dep == NULL && |
|
1897 |
((create->create->flags & CREATE_MASK) != |
|
1898 |
CREATE_DEFER)) { |
|
1899 |
continue; |
|
1900 |
} |
|
1901 |
||
1902 |
if ((*(create->create->callback_fcn)) |
|
1903 |
(minor, node) == DEVFSADM_TERMINATE) { |
|
1904 |
break; |
|
1905 |
} |
|
1906 |
} |
|
1907 |
} |
|
1908 |
||
1909 |
if (defer) |
|
1910 |
cache_deferred_minor(dep, node, minor); |
|
1911 |
} |
|
1912 |
||
1913 |
||
1914 |
/* |
|
1915 |
* Cache node and minor in defer list. |
|
1916 |
*/ |
|
1917 |
static void |
|
1918 |
cache_deferred_minor( |
|
1919 |
struct mlist *dep, |
|
1920 |
di_node_t node, |
|
1921 |
di_minor_t minor) |
|
1922 |
{ |
|
1923 |
struct minor *mp; |
|
1924 |
const char *fcn = "cache_deferred_minor"; |
|
1925 |
||
1926 |
vprint(CHATTY_MID, "%s node=%s, minor=%s\n", fcn, |
|
1927 |
di_node_name(node), di_minor_name(minor)); |
|
1928 |
||
1929 |
if (dep == NULL) { |
|
1930 |
vprint(CHATTY_MID, "%s: cannot cache during " |
|
1931 |
"deferred processing. Ignoring minor\n", fcn); |
|
1932 |
return; |
|
1933 |
} |
|
1934 |
||
1935 |
mp = (struct minor *)s_zalloc(sizeof (struct minor)); |
|
1936 |
mp->node = node; |
|
1937 |
mp->minor = minor; |
|
1938 |
mp->next = NULL; |
|
1939 |
||
1940 |
assert(dep->head == NULL || dep->tail != NULL); |
|
1941 |
if (dep->head == NULL) { |
|
1942 |
dep->head = mp; |
|
1943 |
} else { |
|
1944 |
dep->tail->next = mp; |
|
1945 |
} |
|
1946 |
dep->tail = mp; |
|
1947 |
} |
|
1948 |
||
1949 |
/* |
|
1950 |
* Check to see if "create" link creation rule matches this node/minor. |
|
1951 |
* If it does, return TRUE. |
|
1952 |
*/ |
|
1953 |
static int |
|
1954 |
minor_matches_rule(di_node_t node, di_minor_t minor, create_list_t *create) |
|
1955 |
{ |
|
1956 |
char *m_nodetype, *m_drvname; |
|
1957 |
||
1958 |
if (create->create->node_type != NULL) { |
|
1959 |
||
1960 |
m_nodetype = di_minor_nodetype(minor); |
|
1961 |
assert(m_nodetype != NULL); |
|
1962 |
||
1963 |
switch (create->create->flags & TYPE_MASK) { |
|
1964 |
case TYPE_EXACT: |
|
1965 |
if (strcmp(create->create->node_type, m_nodetype) != |
|
1966 |
0) { |
|
1967 |
return (FALSE); |
|
1968 |
} |
|
1969 |
break; |
|
1970 |
case TYPE_PARTIAL: |
|
1971 |
if (strncmp(create->create->node_type, m_nodetype, |
|
1972 |
strlen(create->create->node_type)) != 0) { |
|
1973 |
return (FALSE); |
|
1974 |
} |
|
1975 |
break; |
|
1976 |
case TYPE_RE: |
|
1977 |
if (regexec(&(create->node_type_comp), m_nodetype, |
|
1978 |
0, NULL, 0) != 0) { |
|
1979 |
return (FALSE); |
|
1980 |
} |
|
1981 |
break; |
|
1982 |
} |
|
1983 |
} |
|
1984 |
||
1985 |
if (create->create->drv_name != NULL) { |
|
1986 |
m_drvname = di_driver_name(node); |
|
1987 |
switch (create->create->flags & DRV_MASK) { |
|
1988 |
case DRV_EXACT: |
|
1989 |
if (strcmp(create->create->drv_name, m_drvname) != 0) { |
|
1990 |
return (FALSE); |
|
1991 |
} |
|
1992 |
break; |
|
1993 |
case DRV_RE: |
|
1994 |
if (regexec(&(create->drv_name_comp), m_drvname, |
|
1995 |
0, NULL, 0) != 0) { |
|
1996 |
return (FALSE); |
|
1997 |
} |
|
1998 |
break; |
|
1999 |
} |
|
2000 |
} |
|
2001 |
||
2002 |
return (TRUE); |
|
2003 |
} |
|
2004 |
||
2005 |
/* |
|
2006 |
* If no classes were given on the command line, then return DEVFSADM_SUCCESS. |
|
2007 |
* Otherwise, return DEVFSADM_SUCCESS if the device "class" from the module |
|
2008 |
* matches one of the device classes given on the command line, |
|
2009 |
* otherwise, return DEVFSADM_FAILURE. |
|
2010 |
*/ |
|
2011 |
static int |
|
2012 |
class_ok(char *class) |
|
2013 |
{ |
|
2014 |
int i; |
|
2015 |
||
2016 |
if (num_classes == 0) { |
|
2017 |
return (DEVFSADM_SUCCESS); |
|
2018 |
} |
|
2019 |
||
2020 |
for (i = 0; i < num_classes; i++) { |
|
2021 |
if (strcmp(class, classes[i]) == 0) { |
|
2022 |
return (DEVFSADM_SUCCESS); |
|
2023 |
} |
|
2024 |
} |
|
2025 |
return (DEVFSADM_FAILURE); |
|
2026 |
} |
|
2027 |
||
2028 |
/* |
|
2029 |
* call minor_fini on active modules, then unload ALL modules |
|
2030 |
*/ |
|
2031 |
static void |
|
2032 |
unload_modules(void) |
|
2033 |
{ |
|
2034 |
module_t *module_free; |
|
2035 |
create_list_t *create_free; |
|
2036 |
remove_list_t *remove_free; |
|
2037 |
||
2038 |
while (create_head != NULL) { |
|
2039 |
create_free = create_head; |
|
2040 |
create_head = create_head->next; |
|
2041 |
||
2042 |
if ((create_free->create->flags & TYPE_RE) == TYPE_RE) { |
|
2043 |
regfree(&(create_free->node_type_comp)); |
|
2044 |
} |
|
2045 |
if ((create_free->create->flags & DRV_RE) == DRV_RE) { |
|
2046 |
regfree(&(create_free->drv_name_comp)); |
|
2047 |
} |
|
2048 |
free(create_free); |
|
2049 |
} |
|
2050 |
||
2051 |
while (remove_head != NULL) { |
|
2052 |
remove_free = remove_head; |
|
2053 |
remove_head = remove_head->next; |
|
2054 |
free(remove_free); |
|
2055 |
} |
|
2056 |
||
2057 |
while (module_head != NULL) { |
|
2058 |
||
2059 |
if ((module_head->minor_fini != NULL) && |
|
2060 |
((module_head->flags & MODULE_ACTIVE) == MODULE_ACTIVE)) { |
|
2061 |
(void) (*(module_head->minor_fini))(); |
|
2062 |
} |
|
2063 |
||
2064 |
vprint(MODLOAD_MID, "unloading module %s\n", module_head->name); |
|
2065 |
free(module_head->name); |
|
2066 |
(void) dlclose(module_head->dlhandle); |
|
2067 |
||
2068 |
module_free = module_head; |
|
2069 |
module_head = module_head->next; |
|
2070 |
free(module_free); |
|
2071 |
} |
|
2072 |
} |
|
2073 |
||
2074 |
/* |
|
2075 |
* Load devfsadm logical link processing modules. |
|
2076 |
*/ |
|
2077 |
static void |
|
2078 |
load_modules(void) |
|
2079 |
{ |
|
2080 |
DIR *mod_dir; |
|
871 | 2081 |
struct dirent *entp; |
0 | 2082 |
char cdir[PATH_MAX + 1]; |
2083 |
char *last; |
|
2084 |
char *mdir = module_dirs; |
|
2085 |
char *fcn = "load_modules: "; |
|
2086 |
||
2087 |
while (*mdir != '\0') { |
|
2088 |
||
2089 |
while (*mdir == ':') { |
|
2090 |
mdir++; |
|
2091 |
} |
|
2092 |
||
2093 |
if (*mdir == '\0') { |
|
2094 |
continue; |
|
2095 |
} |
|
2096 |
||
2097 |
last = strchr(mdir, ':'); |
|
2098 |
||
2099 |
if (last == NULL) { |
|
2100 |
last = mdir + strlen(mdir); |
|
2101 |
} |
|
2102 |
||
2103 |
(void) strncpy(cdir, mdir, last - mdir); |
|
2104 |
cdir[last - mdir] = '\0'; |
|
2105 |
mdir += strlen(cdir); |
|
2106 |
||
2107 |
if ((mod_dir = opendir(cdir)) == NULL) { |
|
2108 |
vprint(MODLOAD_MID, "%sopendir(%s): %s\n", |
|
2109 |
fcn, cdir, strerror(errno)); |
|
2110 |
continue; |
|
2111 |
} |
|
2112 |
||
871 | 2113 |
while ((entp = readdir(mod_dir)) != NULL) { |
0 | 2114 |
|
2115 |
if ((strcmp(entp->d_name, ".") == 0) || |
|
2116 |
(strcmp(entp->d_name, "..") == 0)) { |
|
2117 |
continue; |
|
2118 |
} |
|
2119 |
||
2120 |
load_module(entp->d_name, cdir); |
|
2121 |
} |
|
2122 |
s_closedir(mod_dir); |
|
2123 |
} |
|
2124 |
} |
|
2125 |
||
2126 |
static void |
|
2127 |
load_module(char *mname, char *cdir) |
|
2128 |
{ |
|
2129 |
_devfsadm_create_reg_t *create_reg; |
|
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
2130 |
_devfsadm_remove_reg_V1_t *remove_reg; |
0 | 2131 |
create_list_t *create_list_element; |
2132 |
create_list_t **create_list_next; |
|
2133 |
remove_list_t *remove_list_element; |
|
2134 |
remove_list_t **remove_list_next; |
|
2135 |
char epath[PATH_MAX + 1], *end; |
|
2136 |
char *fcn = "load_module: "; |
|
2137 |
char *dlerrstr; |
|
2138 |
void *dlhandle; |
|
2139 |
module_t *module; |
|
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
2140 |
int flags; |
0 | 2141 |
int n; |
2142 |
int i; |
|
2143 |
||
2144 |
/* ignore any file which does not end in '.so' */ |
|
2145 |
if ((end = strstr(mname, MODULE_SUFFIX)) != NULL) { |
|
2146 |
if (end[strlen(MODULE_SUFFIX)] != '\0') { |
|
2147 |
return; |
|
2148 |
} |
|
2149 |
} else { |
|
2150 |
return; |
|
2151 |
} |
|
2152 |
||
2153 |
(void) snprintf(epath, sizeof (epath), "%s/%s", cdir, mname); |
|
2154 |
||
2155 |
if ((dlhandle = dlopen(epath, RTLD_LAZY)) == NULL) { |
|
2156 |
dlerrstr = dlerror(); |
|
2157 |
err_print(DLOPEN_FAILED, epath, |
|
2158 |
dlerrstr ? dlerrstr : "unknown error"); |
|
2159 |
return; |
|
2160 |
} |
|
2161 |
||
2162 |
/* dlsym the _devfsadm_create_reg structure */ |
|
2163 |
if (NULL == (create_reg = (_devfsadm_create_reg_t *) |
|
2164 |
dlsym(dlhandle, _DEVFSADM_CREATE_REG))) { |
|
2165 |
vprint(MODLOAD_MID, "dlsym(%s, %s): symbol not found\n", epath, |
|
2166 |
_DEVFSADM_CREATE_REG); |
|
2167 |
} else { |
|
2168 |
vprint(MODLOAD_MID, "%sdlsym(%s, %s) succeeded\n", |
|
2169 |
fcn, epath, _DEVFSADM_CREATE_REG); |
|
2170 |
} |
|
2171 |
||
2172 |
/* dlsym the _devfsadm_remove_reg structure */ |
|
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
2173 |
if (NULL == (remove_reg = (_devfsadm_remove_reg_V1_t *) |
0 | 2174 |
dlsym(dlhandle, _DEVFSADM_REMOVE_REG))) { |
2175 |
vprint(MODLOAD_MID, "dlsym(%s,\n\t%s): symbol not found\n", |
|
2176 |
epath, _DEVFSADM_REMOVE_REG); |
|
2177 |
} else { |
|
2178 |
vprint(MODLOAD_MID, "dlsym(%s, %s): succeeded\n", |
|
2179 |
epath, _DEVFSADM_REMOVE_REG); |
|
2180 |
} |
|
2181 |
||
2182 |
vprint(MODLOAD_MID, "module %s loaded\n", epath); |
|
2183 |
||
2184 |
module = (module_t *)s_malloc(sizeof (module_t)); |
|
2185 |
module->name = s_strdup(epath); |
|
2186 |
module->dlhandle = dlhandle; |
|
2187 |
||
2188 |
/* dlsym other module functions, to be called later */ |
|
2189 |
module->minor_fini = (int (*)())dlsym(dlhandle, MINOR_FINI); |
|
2190 |
module->minor_init = (int (*)())dlsym(dlhandle, MINOR_INIT); |
|
2191 |
module->flags = 0; |
|
2192 |
||
2193 |
/* |
|
2194 |
* put a ptr to each struct devfsadm_create on "create_head" |
|
2195 |
* list sorted in interpose_lvl. |
|
2196 |
*/ |
|
2197 |
if (create_reg != NULL) { |
|
2198 |
for (i = 0; i < create_reg->count; i++) { |
|
2199 |
int flags = create_reg->tblp[i].flags; |
|
2200 |
||
2201 |
create_list_element = (create_list_t *) |
|
2202 |
s_malloc(sizeof (create_list_t)); |
|
2203 |
||
2204 |
create_list_element->create = &(create_reg->tblp[i]); |
|
2205 |
create_list_element->modptr = module; |
|
2206 |
||
2207 |
if (((flags & CREATE_MASK) != 0) && |
|
2208 |
((flags & CREATE_MASK) != CREATE_DEFER)) { |
|
2209 |
free(create_list_element); |
|
2210 |
err_print("illegal flag combination in " |
|
2211 |
"module create\n"); |
|
2212 |
err_print(IGNORING_ENTRY, i, epath); |
|
2213 |
continue; |
|
2214 |
} |
|
2215 |
||
2216 |
if (((flags & TYPE_MASK) == 0) ^ |
|
2217 |
(create_reg->tblp[i].node_type == NULL)) { |
|
2218 |
free(create_list_element); |
|
2219 |
err_print("flags value incompatible with " |
|
2220 |
"node_type value in module create\n"); |
|
2221 |
err_print(IGNORING_ENTRY, i, epath); |
|
2222 |
continue; |
|
2223 |
} |
|
2224 |
||
2225 |
if (((flags & TYPE_MASK) != 0) && |
|
2226 |
((flags & TYPE_MASK) != TYPE_EXACT) && |
|
2227 |
((flags & TYPE_MASK) != TYPE_RE) && |
|
2228 |
((flags & TYPE_MASK) != TYPE_PARTIAL)) { |
|
2229 |
free(create_list_element); |
|
2230 |
err_print("illegal TYPE_* flag combination in " |
|
2231 |
"module create\n"); |
|
2232 |
err_print(IGNORING_ENTRY, i, epath); |
|
2233 |
continue; |
|
2234 |
} |
|
2235 |
||
2236 |
/* precompile regular expression for efficiency */ |
|
2237 |
if ((flags & TYPE_RE) == TYPE_RE) { |
|
2238 |
if ((n = regcomp(&(create_list_element-> |
|
2239 |
node_type_comp), |
|
2240 |
create_reg->tblp[i].node_type, |
|
2241 |
REG_EXTENDED)) != 0) { |
|
2242 |
free(create_list_element); |
|
2243 |
err_print(REGCOMP_FAILED, |
|
2244 |
create_reg->tblp[i].node_type, |
|
2245 |
n); |
|
2246 |
err_print(IGNORING_ENTRY, i, epath); |
|
2247 |
continue; |
|
2248 |
} |
|
2249 |
} |
|
2250 |
||
2251 |
if (((flags & DRV_MASK) == 0) ^ |
|
2252 |
(create_reg->tblp[i].drv_name == NULL)) { |
|
2253 |
if ((flags & TYPE_RE) == TYPE_RE) { |
|
2254 |
regfree(&(create_list_element-> |
|
2255 |
node_type_comp)); |
|
2256 |
} |
|
2257 |
free(create_list_element); |
|
2258 |
err_print("flags value incompatible with " |
|
2259 |
"drv_name value in module create\n"); |
|
2260 |
err_print(IGNORING_ENTRY, i, epath); |
|
2261 |
continue; |
|
2262 |
} |
|
2263 |
||
2264 |
if (((flags & DRV_MASK) != 0) && |
|
2265 |
((flags & DRV_MASK) != DRV_EXACT) && |
|
2266 |
((flags & DRV_MASK) != DRV_RE)) { |
|
2267 |
if ((flags & TYPE_RE) == TYPE_RE) { |
|
2268 |
regfree(&(create_list_element-> |
|
2269 |
node_type_comp)); |
|
2270 |
} |
|
2271 |
free(create_list_element); |
|
2272 |
err_print("illegal DRV_* flag combination in " |
|
2273 |
"module create\n"); |
|
2274 |
err_print(IGNORING_ENTRY, i, epath); |
|
2275 |
continue; |
|
2276 |
} |
|
2277 |
||
2278 |
/* precompile regular expression for efficiency */ |
|
2279 |
if ((create_reg->tblp[i].flags & DRV_RE) == DRV_RE) { |
|
2280 |
if ((n = regcomp(&(create_list_element-> |
|
2281 |
drv_name_comp), |
|
2282 |
create_reg->tblp[i].drv_name, |
|
2283 |
REG_EXTENDED)) != 0) { |
|
2284 |
if ((flags & TYPE_RE) == TYPE_RE) { |
|
2285 |
regfree(&(create_list_element-> |
|
2286 |
node_type_comp)); |
|
2287 |
} |
|
2288 |
free(create_list_element); |
|
2289 |
err_print(REGCOMP_FAILED, |
|
2290 |
create_reg->tblp[i].drv_name, |
|
2291 |
n); |
|
2292 |
err_print(IGNORING_ENTRY, i, epath); |
|
2293 |
continue; |
|
2294 |
} |
|
2295 |
} |
|
2296 |
||
2297 |
||
2298 |
/* add to list sorted by interpose level */ |
|
2299 |
for (create_list_next = &(create_head); |
|
2300 |
(*create_list_next != NULL) && |
|
2301 |
(*create_list_next)->create->interpose_lvl >= |
|
2302 |
create_list_element->create->interpose_lvl; |
|
2303 |
create_list_next = |
|
2304 |
&((*create_list_next)->next)); |
|
2305 |
create_list_element->next = *create_list_next; |
|
2306 |
*create_list_next = create_list_element; |
|
2307 |
} |
|
2308 |
} |
|
2309 |
||
2310 |
/* |
|
2311 |
* put a ptr to each struct devfsadm_remove on "remove_head" |
|
2312 |
* list sorted by interpose_lvl. |
|
2313 |
*/ |
|
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
2314 |
flags = 0; |
0 | 2315 |
if (remove_reg != NULL) { |
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
2316 |
if (remove_reg->version < DEVFSADM_V1) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
2317 |
flags |= RM_NOINTERPOSE; |
0 | 2318 |
for (i = 0; i < remove_reg->count; i++) { |
2319 |
||
2320 |
remove_list_element = (remove_list_t *) |
|
2321 |
s_malloc(sizeof (remove_list_t)); |
|
2322 |
||
2323 |
remove_list_element->remove = &(remove_reg->tblp[i]); |
|
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
2324 |
remove_list_element->remove->flags |= flags; |
0 | 2325 |
remove_list_element->modptr = module; |
2326 |
||
2327 |
for (remove_list_next = &(remove_head); |
|
2328 |
(*remove_list_next != NULL) && |
|
2329 |
(*remove_list_next)->remove->interpose_lvl >= |
|
2330 |
remove_list_element->remove->interpose_lvl; |
|
2331 |
remove_list_next = |
|
2332 |
&((*remove_list_next)->next)); |
|
2333 |
remove_list_element->next = *remove_list_next; |
|
2334 |
*remove_list_next = remove_list_element; |
|
2335 |
} |
|
2336 |
} |
|
2337 |
||
2338 |
module->next = module_head; |
|
2339 |
module_head = module; |
|
2340 |
} |
|
2341 |
||
2342 |
/* |
|
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2343 |
* After we have completed a CACHE_STATE, if a SYNC_STATE does not occur |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2344 |
* within 'timeout' secs the minor_fini_thread needs to do a SYNC_STATE |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2345 |
* so that we still call the minor_fini routines. |
0 | 2346 |
*/ |
2347 |
/*ARGSUSED*/ |
|
2348 |
static void |
|
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2349 |
minor_fini_thread(void *arg) |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2350 |
{ |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2351 |
timestruc_t abstime; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2352 |
|
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2353 |
vprint(INITFINI_MID, "minor_fini_thread starting\n"); |
0 | 2354 |
|
2355 |
(void) mutex_lock(&minor_fini_mutex); |
|
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2356 |
for (;;) { |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2357 |
/* wait the gather period, or until signaled */ |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2358 |
abstime.tv_sec = time(NULL) + minor_fini_timeout; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2359 |
abstime.tv_nsec = 0; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2360 |
(void) cond_timedwait(&minor_fini_cv, |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2361 |
&minor_fini_mutex, &abstime); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2362 |
|
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2363 |
/* if minor_fini was canceled, go wait again */ |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2364 |
if (minor_fini_canceled == TRUE) |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2365 |
continue; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2366 |
|
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2367 |
/* if minor_fini was delayed, go wait again */ |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2368 |
if (minor_fini_delayed == TRUE) { |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2369 |
minor_fini_delayed = FALSE; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2370 |
continue; |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2371 |
} |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2372 |
|
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2373 |
/* done with cancellations and delays, do the SYNC_STATE */ |
0 | 2374 |
(void) mutex_unlock(&minor_fini_mutex); |
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2375 |
|
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2376 |
lock_dev(); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2377 |
unlock_dev(SYNC_STATE); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2378 |
vprint(INITFINI_MID, "minor_fini sync done\n"); |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2379 |
|
0 | 2380 |
(void) mutex_lock(&minor_fini_mutex); |
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2381 |
} |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2382 |
} |
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2383 |
|
0 | 2384 |
|
2385 |
/* |
|
2386 |
* Attempt to initialize module, if a minor_init routine exists. Set |
|
2387 |
* the active flag if the routine exists and succeeds. If it doesn't |
|
2388 |
* exist, just set the active flag. |
|
2389 |
*/ |
|
2390 |
static int |
|
2391 |
call_minor_init(module_t *module) |
|
2392 |
{ |
|
2393 |
char *fcn = "call_minor_init: "; |
|
2394 |
||
2395 |
if ((module->flags & MODULE_ACTIVE) == MODULE_ACTIVE) { |
|
2396 |
return (DEVFSADM_SUCCESS); |
|
2397 |
} |
|
2398 |
||
2399 |
vprint(INITFINI_MID, "%smodule %s. current state: inactive\n", |
|
2400 |
fcn, module->name); |
|
2401 |
||
2402 |
if (module->minor_init == NULL) { |
|
2403 |
module->flags |= MODULE_ACTIVE; |
|
2404 |
vprint(INITFINI_MID, "minor_init not defined\n"); |
|
2405 |
return (DEVFSADM_SUCCESS); |
|
2406 |
} |
|
2407 |
||
2408 |
if ((*(module->minor_init))() == DEVFSADM_FAILURE) { |
|
2409 |
err_print(FAILED_FOR_MODULE, MINOR_INIT, module->name); |
|
2410 |
return (DEVFSADM_FAILURE); |
|
2411 |
} |
|
2412 |
||
2413 |
vprint(INITFINI_MID, "minor_init() returns DEVFSADM_SUCCESS. " |
|
2414 |
"new state: active\n"); |
|
2415 |
||
2416 |
module->flags |= MODULE_ACTIVE; |
|
2417 |
return (DEVFSADM_SUCCESS); |
|
2418 |
} |
|
2419 |
||
2420 |
/* |
|
2421 |
* Creates a symlink 'link' to the physical path of node:minor. |
|
2422 |
* Construct link contents, then call create_link_common(). |
|
2423 |
*/ |
|
2424 |
/*ARGSUSED*/ |
|
2425 |
int |
|
2621 | 2426 |
devfsadm_mklink(char *link, di_node_t node, di_minor_t minor, int flags) |
0 | 2427 |
{ |
2428 |
char rcontents[PATH_MAX]; |
|
2429 |
char devlink[PATH_MAX]; |
|
2430 |
char phy_path[PATH_MAX]; |
|
2431 |
char *acontents; |
|
2432 |
char *dev_path; |
|
2433 |
int numslashes; |
|
2434 |
int rv; |
|
2435 |
int i, link_exists; |
|
2436 |
int last_was_slash = FALSE; |
|
2437 |
||
2438 |
/* |
|
2439 |
* try to use devices path |
|
2440 |
*/ |
|
2441 |
if ((node == lnode) && (minor == lminor)) { |
|
2442 |
acontents = lphy_path; |
|
2443 |
} else if (di_minor_type(minor) == DDM_ALIAS) { |
|
2444 |
/* use /pseudo/clone@0:<driver> as the phys path */ |
|
2445 |
(void) snprintf(phy_path, sizeof (phy_path), |
|
2446 |
"/pseudo/clone@0:%s", |
|
2447 |
di_driver_name(di_minor_devinfo(minor))); |
|
2448 |
acontents = phy_path; |
|
2449 |
} else { |
|
2450 |
if ((dev_path = di_devfs_path(node)) == NULL) { |
|
2451 |
err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); |
|
2452 |
devfsadm_exit(1); |
|
2453 |
} |
|
2454 |
(void) snprintf(phy_path, sizeof (phy_path), "%s:%s", |
|
2455 |
dev_path, di_minor_name(minor)); |
|
2456 |
di_devfs_path_free(dev_path); |
|
2457 |
acontents = phy_path; |
|
2458 |
} |
|
2459 |
||
2460 |
/* prepend link with dev_dir contents */ |
|
2461 |
(void) strlcpy(devlink, dev_dir, sizeof (devlink)); |
|
2462 |
(void) strlcat(devlink, "/", sizeof (devlink)); |
|
2463 |
(void) strlcat(devlink, link, sizeof (devlink)); |
|
2464 |
||
2465 |
/* |
|
2466 |
* Calculate # of ../ to add. Account for double '//' in path. |
|
2467 |
* Ignore all leading slashes. |
|
2468 |
*/ |
|
2469 |
for (i = 0; link[i] == '/'; i++) |
|
2470 |
; |
|
2471 |
for (numslashes = 0; link[i] != '\0'; i++) { |
|
2472 |
if (link[i] == '/') { |
|
2473 |
if (last_was_slash == FALSE) { |
|
2474 |
numslashes++; |
|
2475 |
last_was_slash = TRUE; |
|
2476 |
} |
|
2477 |
} else { |
|
2478 |
last_was_slash = FALSE; |
|
2479 |
} |
|
2480 |
} |
|
2481 |
/* Don't count any trailing '/' */ |
|
2482 |
if (link[i-1] == '/') { |
|
2483 |
numslashes--; |
|
2484 |
} |
|
2485 |
||
2486 |
rcontents[0] = '\0'; |
|
2487 |
do { |
|
2488 |
(void) strlcat(rcontents, "../", sizeof (rcontents)); |
|
2489 |
} while (numslashes-- != 0); |
|
2490 |
||
2491 |
(void) strlcat(rcontents, "devices", sizeof (rcontents)); |
|
2492 |
(void) strlcat(rcontents, acontents, sizeof (rcontents)); |
|
2493 |
||
2494 |
if (devlinks_debug == TRUE) { |
|
2495 |
vprint(INFO_MID, "adding link %s ==> %s\n", devlink, rcontents); |
|
2496 |
} |
|
2497 |
||
2498 |
if ((rv = create_link_common(devlink, rcontents, &link_exists)) |
|
2499 |
== DEVFSADM_SUCCESS) { |
|
2500 |
linknew = TRUE; |
|
2501 |
add_link_to_cache(link, acontents); |
|
2502 |
} else { |
|
2503 |
linknew = FALSE; |
|
2504 |
} |
|
2505 |
||
2506 |
if (link_exists == TRUE) { |
|
4400
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2507 |
/* Link exists or was just created */ |
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2508 |
(void) di_devlink_add_link(devlink_cache, link, rcontents, |
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2509 |
DI_PRIMARY_LINK); |
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2510 |
|
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2511 |
if (system_labeled && (flags & DA_ADD)) { |
1676 | 2512 |
/* |
4400
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2513 |
* Add this to the list of allocatable devices. If this |
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2514 |
* is a hotplugged, removable disk, add it as rmdisk. |
1676 | 2515 |
*/ |
4400
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2516 |
int instance = di_instance(node); |
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2517 |
|
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2518 |
if ((flags & DA_CD) && |
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2519 |
(_da_check_for_usb(devlink, root_dir) == 1)) { |
1676 | 2520 |
(void) da_add_list(&devlist, devlink, instance, |
2521 |
DA_ADD|DA_RMDISK); |
|
2522 |
update_devdb = DA_RMDISK; |
|
4400
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2523 |
} else if (linknew == TRUE) { |
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2524 |
(void) da_add_list(&devlist, devlink, instance, |
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2525 |
flags); |
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
2526 |
update_devdb = flags; |
1676 | 2527 |
} |
2528 |
} |
|
0 | 2529 |
} |
2530 |
||
2531 |
return (rv); |
|
2532 |
} |
|
2533 |
||
2534 |
/* |
|
2535 |
* Creates a symlink link to primary_link. Calculates relative |
|
2536 |
* directory offsets, then calls link_common(). |
|
2537 |
*/ |
|
2538 |
/*ARGSUSED*/ |
|
2539 |
int |
|
2540 |
devfsadm_secondary_link(char *link, char *primary_link, int flags) |
|
2541 |
{ |
|
2542 |
char contents[PATH_MAX + 1]; |
|
2543 |
char devlink[PATH_MAX + 1]; |
|
2544 |
int rv, link_exists; |
|
2545 |
char *fpath; |
|
2546 |
char *tpath; |
|
2547 |
char *op; |
|
2548 |
||
2549 |
/* prepend link with dev_dir contents */ |
|
2550 |
(void) strcpy(devlink, dev_dir); |
|
2551 |
(void) strcat(devlink, "/"); |
|
2552 |
(void) strcat(devlink, link); |
|
2553 |
/* |
|
2554 |
* building extra link, so use first link as link contents, but first |
|
2555 |
* make it relative. |
|
2556 |
*/ |
|
2557 |
fpath = link; |
|
2558 |
tpath = primary_link; |
|
2559 |
op = contents; |
|
2560 |
||
2561 |
while (*fpath == *tpath && *fpath != '\0') { |
|
2562 |
fpath++, tpath++; |
|
2563 |
} |
|
2564 |
||
2565 |
/* Count directories to go up, if any, and add "../" */ |
|
2566 |
while (*fpath != '\0') { |
|
2567 |
if (*fpath == '/') { |
|
2568 |
(void) strcpy(op, "../"); |
|
2569 |
op += 3; |
|
2570 |
} |
|
2571 |
fpath++; |
|
2572 |
} |
|
2573 |
||
2574 |
/* |
|
2575 |
* Back up to the start of the current path component, in |
|
2576 |
* case in the middle |
|
2577 |
*/ |
|
2578 |
while (tpath != primary_link && *(tpath-1) != '/') { |
|
2579 |
tpath--; |
|
2580 |
} |
|
2581 |
(void) strcpy(op, tpath); |
|
2582 |
||
2583 |
if (devlinks_debug == TRUE) { |
|
2584 |
vprint(INFO_MID, "adding extra link %s ==> %s\n", |
|
2585 |
devlink, contents); |
|
2586 |
} |
|
2587 |
||
2588 |
if ((rv = create_link_common(devlink, contents, &link_exists)) |
|
2589 |
== DEVFSADM_SUCCESS) { |
|
2590 |
/* |
|
2591 |
* we need to save the ultimate /devices contents, and not the |
|
2592 |
* secondary link, since hotcleanup only looks at /devices path. |
|
2593 |
* Since we don't have devices path here, we can try to get it |
|
2594 |
* by readlink'ing the secondary link. This assumes the primary |
|
2595 |
* link was created first. |
|
2596 |
*/ |
|
2597 |
add_link_to_cache(link, lphy_path); |
|
2598 |
linknew = TRUE; |
|
1676 | 2599 |
if (system_labeled && |
2600 |
((flags & DA_AUDIO) && (flags & DA_ADD))) { |
|
2601 |
/* |
|
2602 |
* Add this device to the list of allocatable devices. |
|
2603 |
*/ |
|
2604 |
int instance = 0; |
|
2605 |
||
2606 |
op = strrchr(contents, '/'); |
|
2607 |
op++; |
|
2608 |
(void) sscanf(op, "%d", &instance); |
|
2609 |
(void) da_add_list(&devlist, devlink, instance, flags); |
|
2610 |
update_devdb = flags; |
|
2611 |
} |
|
0 | 2612 |
} else { |
2613 |
linknew = FALSE; |
|
2614 |
} |
|
2615 |
||
2616 |
/* |
|
2617 |
* If link exists or was just created, add it to the database |
|
2618 |
*/ |
|
2619 |
if (link_exists == TRUE) { |
|
2620 |
(void) di_devlink_add_link(devlink_cache, link, contents, |
|
2621 |
DI_SECONDARY_LINK); |
|
2622 |
} |
|
2623 |
||
2624 |
return (rv); |
|
2625 |
} |
|
2626 |
||
2627 |
/* returns pointer to the devices directory */ |
|
2628 |
char * |
|
2629 |
devfsadm_get_devices_dir() |
|
2630 |
{ |
|
2631 |
return (devices_dir); |
|
2632 |
} |
|
2633 |
||
2634 |
/* |
|
2635 |
* Does the actual link creation. VERBOSE_MID only used if there is |
|
2636 |
* a change. CHATTY_MID used otherwise. |
|
2637 |
*/ |
|
2638 |
static int |
|
2639 |
create_link_common(char *devlink, char *contents, int *exists) |
|
2640 |
{ |
|
2641 |
int try; |
|
2642 |
int linksize; |
|
2643 |
int max_tries = 0; |
|
2644 |
static int prev_link_existed = TRUE; |
|
2645 |
char checkcontents[PATH_MAX + 1]; |
|
2646 |
char *hide; |
|
2647 |
||
2648 |
*exists = FALSE; |
|
2649 |
||
2650 |
/* Database is not updated when file_mods == FALSE */ |
|
2651 |
if (file_mods == FALSE) { |
|
2652 |
linksize = readlink(devlink, checkcontents, PATH_MAX); |
|
2653 |
if (linksize > 0) { |
|
2654 |
checkcontents[linksize] = '\0'; |
|
2655 |
if (strcmp(checkcontents, contents) != 0) { |
|
2656 |
vprint(CHATTY_MID, REMOVING_LINK, |
|
2657 |
devlink, checkcontents); |
|
2658 |
return (DEVFSADM_SUCCESS); |
|
2659 |
} else { |
|
2660 |
vprint(CHATTY_MID, "link exists and is correct:" |
|
2661 |
" %s -> %s\n", devlink, contents); |
|
2662 |
/* failure only in that the link existed */ |
|
2663 |
return (DEVFSADM_FAILURE); |
|
2664 |
} |
|
2665 |
} else { |
|
2666 |
vprint(VERBOSE_MID, CREATING_LINK, devlink, contents); |
|
2667 |
return (DEVFSADM_SUCCESS); |
|
2668 |
} |
|
2669 |
} |
|
2670 |
||
2671 |
/* |
|
2672 |
* systems calls are expensive, so predict whether to readlink |
|
2673 |
* or symlink first, based on previous attempt |
|
2674 |
*/ |
|
2675 |
if (prev_link_existed == FALSE) { |
|
2676 |
try = CREATE_LINK; |
|
2677 |
} else { |
|
2678 |
try = READ_LINK; |
|
2679 |
} |
|
2680 |
||
2681 |
while (++max_tries <= 3) { |
|
2682 |
||
2683 |
switch (try) { |
|
2684 |
case CREATE_LINK: |
|
2685 |
||
2686 |
if (symlink(contents, devlink) == 0) { |
|
2687 |
vprint(VERBOSE_MID, CREATING_LINK, devlink, |
|
2688 |
contents); |
|
2689 |
prev_link_existed = FALSE; |
|
2690 |
/* link successfully created */ |
|
2691 |
*exists = TRUE; |
|
2692 |
set_logindev_perms(devlink); |
|
2693 |
return (DEVFSADM_SUCCESS); |
|
2694 |
} else { |
|
2695 |
switch (errno) { |
|
2696 |
||
2697 |
case ENOENT: |
|
2698 |
/* dirpath to node doesn't exist */ |
|
2699 |
hide = strrchr(devlink, '/'); |
|
2700 |
*hide = '\0'; |
|
2701 |
s_mkdirp(devlink, S_IRWXU|S_IRGRP| |
|
2702 |
S_IXGRP|S_IROTH|S_IXOTH); |
|
2703 |
*hide = '/'; |
|
2704 |
break; |
|
2705 |
case EEXIST: |
|
2706 |
try = READ_LINK; |
|
2707 |
break; |
|
2708 |
default: |
|
2709 |
err_print(SYMLINK_FAILED, devlink, |
|
2710 |
contents, strerror(errno)); |
|
2711 |
return (DEVFSADM_FAILURE); |
|
2712 |
} |
|
2713 |
} |
|
2714 |
break; |
|
2715 |
||
2716 |
case READ_LINK: |
|
2717 |
||
2718 |
linksize = readlink(devlink, checkcontents, PATH_MAX); |
|
2719 |
if (linksize >= 0) { |
|
2720 |
checkcontents[linksize] = '\0'; |
|
2721 |
if (strcmp(checkcontents, contents) != 0) { |
|
2722 |
s_unlink(devlink); |
|
2723 |
vprint(VERBOSE_MID, REMOVING_LINK, |
|
2724 |
devlink, checkcontents); |
|
2725 |
try = CREATE_LINK; |
|
2726 |
} else { |
|
2727 |
prev_link_existed = TRUE; |
|
2728 |
vprint(CHATTY_MID, |
|
2729 |
"link exists and is correct:" |
|
2730 |
" %s -> %s\n", devlink, |
|
2731 |
contents); |
|
2732 |
*exists = TRUE; |
|
2733 |
/* failure in that the link existed */ |
|
2734 |
return (DEVFSADM_FAILURE); |
|
2735 |
} |
|
2736 |
} else { |
|
2737 |
switch (errno) { |
|
2738 |
case EINVAL: |
|
2739 |
/* not a symlink, remove and create */ |
|
2740 |
s_unlink(devlink); |
|
2741 |
default: |
|
2742 |
/* maybe it didn't exist at all */ |
|
2743 |
try = CREATE_LINK; |
|
2744 |
break; |
|
2745 |
} |
|
2746 |
} |
|
2747 |
break; |
|
2748 |
} |
|
2749 |
} |
|
2750 |
err_print(MAX_ATTEMPTS, devlink, contents); |
|
2751 |
return (DEVFSADM_FAILURE); |
|
2752 |
} |
|
2753 |
||
2754 |
static void |
|
2755 |
set_logindev_perms(char *devlink) |
|
2756 |
{ |
|
2757 |
struct login_dev *newdev; |
|
2758 |
struct passwd pwd, *resp; |
|
2759 |
char pwd_buf[PATH_MAX]; |
|
2760 |
int rv; |
|
2761 |
struct stat sb; |
|
2762 |
char *devfs_path = NULL; |
|
2763 |
||
2764 |
/* |
|
2765 |
* We only want logindev perms to be set when a device is |
|
2766 |
* hotplugged or an application requests synchronous creates. |
|
2767 |
* So we enable this only in daemon mode. In addition, |
|
2768 |
* login(1) only fixes the std. /dev dir. So we don't |
|
2769 |
* change perms if alternate root is set. |
|
2770 |
* login_dev_enable is TRUE only in these cases. |
|
2771 |
*/ |
|
2772 |
if (login_dev_enable != TRUE) |
|
2773 |
return; |
|
2774 |
||
2775 |
/* |
|
2776 |
* Normally, /etc/logindevperm has few (8 - 10 entries) which |
|
2777 |
* may be regular expressions (globs were converted to RE). |
|
2778 |
* So just do a linear search through the list. |
|
2779 |
*/ |
|
2780 |
for (newdev = login_dev_cache; newdev; newdev = newdev->ldev_next) { |
|
2781 |
vprint(FILES_MID, "matching %s with %s\n", devlink, |
|
2782 |
newdev->ldev_device); |
|
2783 |
||
2784 |
if (regexec(&newdev->ldev_device_regex, devlink, 0, |
|
2785 |
NULL, 0) == 0) { |
|
2786 |
vprint(FILES_MID, "matched %s with %s\n", devlink, |
|
2787 |
newdev->ldev_device); |
|
2788 |
break; |
|
2789 |
} |
|
2790 |
} |
|
2791 |
||
2792 |
if (newdev == NULL) |
|
2793 |
return; |
|
2794 |
||
2795 |
/* |
|
2796 |
* we have a match, now find the driver associated with this |
|
2797 |
* minor node using a snapshot on the physical path |
|
2798 |
*/ |
|
2799 |
(void) resolve_link(devlink, NULL, NULL, &devfs_path, 0); |
|
2800 |
if (devfs_path) { |
|
2801 |
di_node_t node; |
|
2802 |
char *drv = NULL; |
|
2803 |
struct driver_list *list; |
|
2804 |
char *p; |
|
2805 |
||
2806 |
/* truncate on : so we can take a snapshot */ |
|
2807 |
(void) strcpy(pwd_buf, devfs_path); |
|
2808 |
p = strrchr(pwd_buf, ':'); |
|
2809 |
if (p == NULL) { |
|
2810 |
free(devfs_path); |
|
2811 |
return; |
|
2812 |
} |
|
2813 |
*p = '\0'; |
|
2814 |
||
2815 |
vprint(FILES_MID, "link=%s->physpath=%s\n", |
|
2816 |
devlink, pwd_buf); |
|
2817 |
||
2818 |
node = di_init(pwd_buf, DINFOMINOR); |
|
2819 |
||
2820 |
if (node) { |
|
2821 |
drv = di_driver_name(node); |
|
2822 |
||
2823 |
if (drv) { |
|
2824 |
vprint(FILES_MID, "%s: driver is %s\n", |
|
2825 |
devlink, drv); |
|
2826 |
} |
|
2827 |
di_fini(node); |
|
2828 |
} |
|
2829 |
/* search thru the driver list specified in logindevperm */ |
|
2830 |
list = newdev->ldev_driver_list; |
|
2831 |
if ((drv != NULL) && (list != NULL)) { |
|
2832 |
while (list) { |
|
2833 |
if (strcmp(list->driver_name, |
|
2834 |
drv) == 0) { |
|
2835 |
vprint(FILES_MID, |
|
2836 |
"driver %s match!\n", drv); |
|
2837 |
break; |
|
2838 |
} |
|
2839 |
list = list->next; |
|
2840 |
} |
|
2841 |
if (list == NULL) { |
|
2842 |
vprint(FILES_MID, "no driver match!\n"); |
|
2843 |
free(devfs_path); |
|
2844 |
return; |
|
2845 |
} |
|
2846 |
} |
|
2847 |
free(devfs_path); |
|
2848 |
} else { |
|
2849 |
return; |
|
2850 |
} |
|
2851 |
||
2852 |
vprint(FILES_MID, "changing permissions of %s\n", devlink); |
|
2853 |
||
2854 |
/* |
|
2855 |
* We have a match. We now attempt to determine the |
|
2856 |
* owner and group of the console user. |
|
2857 |
* |
|
2858 |
* stat() the console device newdev->ldev_console |
|
2859 |
* which will always exist - it will have the right owner but |
|
2860 |
* not the right group. Use getpwuid_r() to determine group for this |
|
2861 |
* uid. |
|
2862 |
* Note, it is safe to use name service here since if name services |
|
2863 |
* are not available (during boot or in single-user mode), then |
|
2864 |
* console owner will be root and its gid can be found in |
|
2865 |
* local files. |
|
2866 |
*/ |
|
2867 |
if (stat(newdev->ldev_console, &sb) == -1) { |
|
2868 |
vprint(VERBOSE_MID, STAT_FAILED, newdev->ldev_console, |
|
2869 |
strerror(errno)); |
|
2870 |
return; |
|
2871 |
} |
|
2872 |
||
2873 |
resp = NULL; |
|
2874 |
rv = getpwuid_r(sb.st_uid, &pwd, pwd_buf, sizeof (pwd_buf), &resp); |
|
2875 |
if (rv || resp == NULL) { |
|
2876 |
rv = rv ? rv : EINVAL; |
|
2877 |
vprint(VERBOSE_MID, GID_FAILED, sb.st_uid, |
|
2878 |
strerror(rv)); |
|
2879 |
return; |
|
2880 |
} |
|
2881 |
||
2882 |
assert(&pwd == resp); |
|
2883 |
||
2884 |
sb.st_gid = resp->pw_gid; |
|
2885 |
||
2886 |
if (chmod(devlink, newdev->ldev_perms) == -1) { |
|
2887 |
vprint(VERBOSE_MID, CHMOD_FAILED, devlink, |
|
2888 |
strerror(errno)); |
|
2889 |
return; |
|
2890 |
} |
|
2891 |
||
2892 |
if (chown(devlink, sb.st_uid, sb.st_gid) == -1) { |
|
2893 |
vprint(VERBOSE_MID, CHOWN_FAILED, devlink, |
|
2894 |
strerror(errno)); |
|
2895 |
} |
|
2896 |
} |
|
2897 |
||
2898 |
/* |
|
2899 |
* Reset /devices node with appropriate permissions and |
|
2900 |
* ownership as specified in /etc/minor_perm. |
|
2901 |
*/ |
|
2902 |
static void |
|
2903 |
reset_node_permissions(di_node_t node, di_minor_t minor) |
|
2904 |
{ |
|
2905 |
int spectype; |
|
2906 |
char phy_path[PATH_MAX + 1]; |
|
2907 |
mode_t mode; |
|
2908 |
dev_t dev; |
|
2909 |
uid_t uid; |
|
2910 |
gid_t gid; |
|
2911 |
struct stat sb; |
|
2912 |
char *dev_path, *aminor = NULL; |
|
2913 |
||
2914 |
/* lphy_path starts with / */ |
|
2915 |
if ((dev_path = di_devfs_path(node)) == NULL) { |
|
2916 |
err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); |
|
2917 |
devfsadm_exit(1); |
|
2918 |
} |
|
2919 |
(void) strcpy(lphy_path, dev_path); |
|
2920 |
di_devfs_path_free(dev_path); |
|
2921 |
||
2922 |
(void) strcat(lphy_path, ":"); |
|
2923 |
if (di_minor_type(minor) == DDM_ALIAS) { |
|
2924 |
char *driver; |
|
2925 |
aminor = di_minor_name(minor); |
|
2926 |
driver = di_driver_name(di_minor_devinfo(minor)); |
|
2927 |
(void) strcat(lphy_path, driver); |
|
2928 |
} else |
|
2929 |
(void) strcat(lphy_path, di_minor_name(minor)); |
|
2930 |
||
2931 |
(void) strcpy(phy_path, devices_dir); |
|
2932 |
(void) strcat(phy_path, lphy_path); |
|
2933 |
||
2934 |
lnode = node; |
|
2935 |
lminor = minor; |
|
2936 |
||
2937 |
vprint(CHATTY_MID, "reset_node_permissions: phy_path=%s lphy_path=%s\n", |
|
2938 |
phy_path, lphy_path); |
|
2939 |
||
2940 |
dev = di_minor_devt(minor); |
|
2941 |
spectype = di_minor_spectype(minor); /* block or char */ |
|
2942 |
||
2943 |
getattr(phy_path, aminor, spectype, dev, &mode, &uid, &gid); |
|
2944 |
||
2945 |
/* |
|
2946 |
* compare and set permissions and ownership |
|
2947 |
* |
|
2948 |
* Under devfs, a quick insertion and removal of USB devices |
|
2949 |
* would cause stat of physical path to fail. In this case, |
|
2950 |
* we emit a verbose message, but don't print errors. |
|
2951 |
*/ |
|
2952 |
if ((stat(phy_path, &sb) == -1) || (sb.st_rdev != dev)) { |
|
2953 |
vprint(VERBOSE_MID, NO_DEVFS_NODE, phy_path); |
|
2954 |
return; |
|
2955 |
} |
|
2956 |
||
2957 |
/* |
|
1676 | 2958 |
* If we are here for a new device |
2959 |
* If device allocation is on |
|
2960 |
* then |
|
2961 |
* set ownership to root:other and permissions to 0000 |
|
2962 |
* else |
|
2963 |
* set ownership and permissions as specified in minor_perm |
|
2964 |
* If we are here for an existing device |
|
2965 |
* If device allocation is to be turned on |
|
2966 |
* then |
|
2967 |
* reset ownership to root:other and permissions to 0000 |
|
2968 |
* else if device allocation is to be turned off |
|
2969 |
* reset ownership and permissions to those specified in |
|
2970 |
* minor_perm |
|
2971 |
* else |
|
3496
115c8a88f74b
6452574 we should improve management of the /dev/.devlink_db file
cth
parents:
2846
diff
changeset
|
2972 |
* preserve existing/user-modified ownership and |
1676 | 2973 |
* permissions |
2974 |
* |
|
2975 |
* devfs indicates a new device by faking access time to be zero. |
|
0 | 2976 |
*/ |
2977 |
if (sb.st_atime != 0) { |
|
2978 |
int i; |
|
2979 |
char *nt; |
|
2980 |
||
1676 | 2981 |
if ((devalloc_flag == 0) && (devalloc_is_on != 1)) |
2982 |
/* |
|
2983 |
* Leave existing devices as they are if we are not |
|
2984 |
* turning device allocation on/off. |
|
2985 |
*/ |
|
0 | 2986 |
return; |
2987 |
||
2988 |
nt = di_minor_nodetype(minor); |
|
1676 | 2989 |
|
0 | 2990 |
if (nt == NULL) |
2991 |
return; |
|
1676 | 2992 |
|
2993 |
for (i = 0; devalloc_list[i]; i++) { |
|
2994 |
if (strcmp(nt, devalloc_list[i]) == 0) |
|
2995 |
/* |
|
2996 |
* One of the types recognized by devalloc, |
|
2997 |
* reset attrs. |
|
2998 |
*/ |
|
0 | 2999 |
break; |
3000 |
} |
|
1676 | 3001 |
if (devalloc_list[i] == NULL) |
0 | 3002 |
return; |
3003 |
} |
|
3004 |
||
3005 |
if (file_mods == FALSE) { |
|
3006 |
/* Nothing more to do if simulating */ |
|
3007 |
vprint(VERBOSE_MID, PERM_MSG, phy_path, uid, gid, mode); |
|
3008 |
return; |
|
3009 |
} |
|
3010 |
||
1676 | 3011 |
if ((devalloc_flag == DA_ON) || (devalloc_is_on == 1)) { |
3012 |
/* |
|
3013 |
* we are here either to turn device allocation on |
|
3014 |
* or to add a new device while device allocation in on |
|
3015 |
*/ |
|
3016 |
mode = DEALLOC_MODE; |
|
3017 |
uid = DA_UID; |
|
3018 |
gid = DA_GID; |
|
3019 |
} |
|
3020 |
||
3021 |
if ((devalloc_is_on == 1) || (devalloc_flag == DA_ON) || |
|
3022 |
(sb.st_mode != mode)) { |
|
0 | 3023 |
if (chmod(phy_path, mode) == -1) |
3024 |
vprint(VERBOSE_MID, CHMOD_FAILED, |
|
3025 |
phy_path, strerror(errno)); |
|
3026 |
} |
|
1676 | 3027 |
if ((devalloc_is_on == 1) || (devalloc_flag == DA_ON) || |
3028 |
(sb.st_uid != uid || sb.st_gid != gid)) { |
|
0 | 3029 |
if (chown(phy_path, uid, gid) == -1) |
3030 |
vprint(VERBOSE_MID, CHOWN_FAILED, |
|
3031 |
phy_path, strerror(errno)); |
|
3032 |
} |
|
3033 |
||
3034 |
/* Report that we actually did something */ |
|
3035 |
vprint(VERBOSE_MID, PERM_MSG, phy_path, uid, gid, mode); |
|
3036 |
} |
|
3037 |
||
3038 |
/* |
|
3039 |
* Removes logical link and the minor node it refers to. If file is a |
|
3040 |
* link, we recurse and try to remove the minor node (or link if path is |
|
3041 |
* a double link) that file's link contents refer to. |
|
3042 |
*/ |
|
3043 |
static void |
|
3044 |
devfsadm_rm_work(char *file, int recurse, int file_type) |
|
3045 |
{ |
|
3046 |
char *fcn = "devfsadm_rm_work: "; |
|
3047 |
int linksize; |
|
3048 |
char contents[PATH_MAX + 1]; |
|
3049 |
char nextfile[PATH_MAX + 1]; |
|
3050 |
char newfile[PATH_MAX + 1]; |
|
3051 |
char *ptr; |
|
3052 |
||
3053 |
vprint(REMOVE_MID, "%s%s\n", fcn, file); |
|
3054 |
||
3055 |
/* TYPE_LINK split into multiple if's due to excessive indentations */ |
|
3056 |
if (file_type == TYPE_LINK) { |
|
3057 |
(void) strcpy(newfile, dev_dir); |
|
3058 |
(void) strcat(newfile, "/"); |
|
3059 |
(void) strcat(newfile, file); |
|
3060 |
} |
|
3061 |
||
3062 |
if ((file_type == TYPE_LINK) && (recurse == TRUE) && |
|
3063 |
((linksize = readlink(newfile, contents, PATH_MAX)) > 0)) { |
|
3064 |
contents[linksize] = '\0'; |
|
3065 |
||
3066 |
if (is_minor_node(contents, &ptr) == DEVFSADM_TRUE) { |
|
3067 |
devfsadm_rm_work(++ptr, FALSE, TYPE_DEVICES); |
|
3068 |
} else { |
|
3069 |
if (strncmp(contents, DEV "/", strlen(DEV) + 1) == 0) { |
|
3070 |
devfsadm_rm_work(&contents[strlen(DEV) + 1], |
|
3071 |
TRUE, TYPE_LINK); |
|
3072 |
} else { |
|
3073 |
if ((ptr = strrchr(file, '/')) != NULL) { |
|
3074 |
*ptr = '\0'; |
|
3075 |
(void) strcpy(nextfile, file); |
|
3076 |
*ptr = '/'; |
|
3077 |
(void) strcat(nextfile, "/"); |
|
3078 |
} else { |
|
3079 |
(void) strcpy(nextfile, ""); |
|
3080 |
} |
|
3081 |
(void) strcat(nextfile, contents); |
|
3082 |
devfsadm_rm_work(nextfile, TRUE, TYPE_LINK); |
|
3083 |
} |
|
3084 |
} |
|
3085 |
} |
|
3086 |
||
3087 |
if (file_type == TYPE_LINK) { |
|
3088 |
vprint(VERBOSE_MID, DEVFSADM_UNLINK, newfile); |
|
3089 |
if (file_mods == TRUE) { |
|
3090 |
rm_link_from_cache(file); |
|
3091 |
s_unlink(newfile); |
|
3092 |
rm_parent_dir_if_empty(newfile); |
|
3093 |
invalidate_enumerate_cache(); |
|
3094 |
(void) di_devlink_rm_link(devlink_cache, file); |
|
3095 |
} |
|
3096 |
} |
|
3097 |
||
3098 |
/* |
|
3099 |
* Note: we don't remove /devices entries because they are |
|
3100 |
* covered by devfs. |
|
3101 |
*/ |
|
3102 |
} |
|
3103 |
||
3104 |
void |
|
3105 |
devfsadm_rm_link(char *file) |
|
3106 |
{ |
|
3107 |
devfsadm_rm_work(file, FALSE, TYPE_LINK); |
|
3108 |
} |
|
3109 |
||
3110 |
void |
|
3111 |
devfsadm_rm_all(char *file) |
|
3112 |
{ |
|
3113 |
devfsadm_rm_work(file, TRUE, TYPE_LINK); |
|
3114 |
} |
|
3115 |
||
871 | 3116 |
static int |
0 | 3117 |
s_rmdir(char *path) |
3118 |
{ |
|
3119 |
int i; |
|
3120 |
char *rpath, *dir; |
|
3121 |
const char *fcn = "s_rmdir"; |
|
3122 |
||
3123 |
/* |
|
3124 |
* Certain directories are created at install time by packages. |
|
3125 |
* Some of them (listed in packaged_dirs[]) are required by apps |
|
3126 |
* and need to be present even when empty. |
|
3127 |
*/ |
|
3128 |
vprint(REMOVE_MID, "%s: checking if %s is packaged\n", fcn, path); |
|
3129 |
||
3130 |
rpath = path + strlen(dev_dir) + 1; |
|
3131 |
||
3132 |
for (i = 0; (dir = packaged_dirs[i]) != NULL; i++) { |
|
3133 |
if (*rpath == *dir) { |
|
3134 |
if (strcmp(rpath, dir) == 0) { |
|
3135 |
vprint(REMOVE_MID, "%s: skipping packaged dir: " |
|
3136 |
"%s\n", fcn, path); |
|
871 | 3137 |
errno = EEXIST; |
3138 |
return (-1); |
|
0 | 3139 |
} |
3140 |
} |
|
3141 |
} |
|
3142 |
||
871 | 3143 |
return (rmdir(path)); |
0 | 3144 |
} |
3145 |
||
3146 |
/* |
|
3147 |
* Try to remove any empty directories up the tree. It is assumed that |
|
3148 |
* pathname is a file that was removed, so start with its parent, and |
|
3149 |
* work up the tree. |
|
3150 |
*/ |
|
3151 |
static void |
|
3152 |
rm_parent_dir_if_empty(char *pathname) |
|
3153 |
{ |
|
3154 |
char *ptr, path[PATH_MAX + 1]; |
|
3155 |
char *fcn = "rm_parent_dir_if_empty: "; |
|
3156 |
||
3157 |
vprint(REMOVE_MID, "%schecking %s if empty\n", fcn, pathname); |
|
3158 |
||
3159 |
(void) strcpy(path, pathname); |
|
3160 |
||
3161 |
/* |
|
3162 |
* ascend up the dir tree, deleting all empty dirs. |
|
3163 |
* Return immediately if a dir is not empty. |
|
3164 |
*/ |
|
3165 |
for (;;) { |
|
3166 |
||
3167 |
if ((ptr = strrchr(path, '/')) == NULL) { |
|
3168 |
return; |
|
3169 |
} |
|
3170 |
||
3171 |
*ptr = '\0'; |
|
3172 |
||
6065 | 3173 |
if (finddev_emptydir(path)) { |
3174 |
/* directory is empty */ |
|
2621 | 3175 |
if (s_rmdir(path) == 0) { |
3176 |
vprint(REMOVE_MID, |
|
3177 |
"%sremoving empty dir %s\n", fcn, path); |
|
3178 |
} else if (errno == EEXIST) { |
|
3179 |
vprint(REMOVE_MID, |
|
3180 |
"%sfailed to remove dir: %s\n", fcn, path); |
|
3181 |
return; |
|
3182 |
} |
|
3183 |
} else { |
|
3184 |
/* some other file is here, so return */ |
|
871 | 3185 |
vprint(REMOVE_MID, "%sdir not empty: %s\n", fcn, path); |
0 | 3186 |
return; |
3187 |
} |
|
3188 |
} |
|
3189 |
} |
|
3190 |
||
3191 |
/* |
|
3192 |
* This function and all the functions it calls below were added to |
|
3193 |
* handle the unique problem with world wide names (WWN). The problem is |
|
3194 |
* that if a WWN device is moved to another address on the same controller |
|
3195 |
* its logical link will change, while the physical node remains the same. |
|
3196 |
* The result is that two logical links will point to the same physical path |
|
3197 |
* in /devices, the valid link and a stale link. This function will |
|
3198 |
* find all the stale nodes, though at a significant performance cost. |
|
3199 |
* |
|
3200 |
* Caching is used to increase performance. |
|
3201 |
* A cache will be built from disk if the cache tag doesn't already exist. |
|
3202 |
* The cache tag is a regular expression "dir_re", which selects a |
|
3203 |
* subset of disks to search from typically something like |
|
3204 |
* "dev/cXt[0-9]+d[0-9]+s[0-9]+". After the cache is built, consistency must |
|
3205 |
* be maintained, so entries are added as new links are created, and removed |
|
3206 |
* as old links are deleted. The whole cache is flushed if we are a daemon, |
|
3207 |
* and another devfsadm process ran in between. |
|
3208 |
* |
|
3209 |
* Once the cache is built, this function finds the cache which matches |
|
3210 |
* dir_re, and then it searches all links in that cache looking for |
|
3211 |
* any link whose contents match "valid_link_contents" with a corresponding link |
|
3212 |
* which does not match "valid_link". Any such matches are stale and removed. |
|
3213 |
*/ |
|
3214 |
void |
|
3215 |
devfsadm_rm_stale_links(char *dir_re, char *valid_link, di_node_t node, |
|
3216 |
di_minor_t minor) |
|
3217 |
{ |
|
3218 |
link_t *link; |
|
3219 |
linkhead_t *head; |
|
3220 |
char phy_path[PATH_MAX + 1]; |
|
3221 |
char *valid_link_contents; |
|
3222 |
char *dev_path; |
|
3223 |
char rmlink[PATH_MAX + 1]; |
|
3224 |
||
3225 |
/* |
|
3226 |
* try to use devices path |
|
3227 |
*/ |
|
3228 |
if ((node == lnode) && (minor == lminor)) { |
|
3229 |
valid_link_contents = lphy_path; |
|
3230 |
} else { |
|
3231 |
if ((dev_path = di_devfs_path(node)) == NULL) { |
|
3232 |
err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); |
|
3233 |
devfsadm_exit(1); |
|
3234 |
} |
|
3235 |
(void) strcpy(phy_path, dev_path); |
|
3236 |
di_devfs_path_free(dev_path); |
|
3237 |
||
3238 |
(void) strcat(phy_path, ":"); |
|
3239 |
(void) strcat(phy_path, di_minor_name(minor)); |
|
3240 |
valid_link_contents = phy_path; |
|
3241 |
} |
|
3242 |
||
3243 |
/* |
|
3244 |
* As an optimization, check to make sure the corresponding |
|
3245 |
* devlink was just created before continuing. |
|
3246 |
*/ |
|
3247 |
||
3248 |
if (linknew == FALSE) { |
|
3249 |
return; |
|
3250 |
} |
|
3251 |
||
3252 |
head = get_cached_links(dir_re); |
|
3253 |
||
3254 |
assert(head->nextlink == NULL); |
|
3255 |
||
3256 |
for (link = head->link; link != NULL; link = head->nextlink) { |
|
3257 |
/* |
|
3258 |
* See hot_cleanup() for why we do this |
|
3259 |
*/ |
|
3260 |
head->nextlink = link->next; |
|
3261 |
if ((strcmp(link->contents, valid_link_contents) == 0) && |
|
3262 |
(strcmp(link->devlink, valid_link) != 0)) { |
|
3263 |
vprint(CHATTY_MID, "removing %s -> %s\n" |
|
3264 |
"valid link is: %s -> %s\n", |
|
3265 |
link->devlink, link->contents, |
|
3266 |
valid_link, valid_link_contents); |
|
3267 |
/* |
|
3268 |
* Use a copy of the cached link name as the |
|
3269 |
* cache entry will go away during link removal |
|
3270 |
*/ |
|
3271 |
(void) snprintf(rmlink, sizeof (rmlink), "%s", |
|
3272 |
link->devlink); |
|
3273 |
devfsadm_rm_link(rmlink); |
|
3274 |
} |
|
3275 |
} |
|
3276 |
} |
|
3277 |
||
3278 |
/* |
|
3279 |
* Return previously created cache, or create cache. |
|
3280 |
*/ |
|
3281 |
static linkhead_t * |
|
3282 |
get_cached_links(char *dir_re) |
|
3283 |
{ |
|
3284 |
recurse_dev_t rd; |
|
3285 |
linkhead_t *linkhead; |
|
3286 |
int n; |
|
3287 |
||
3288 |
vprint(BUILDCACHE_MID, "get_cached_links: %s\n", dir_re); |
|
3289 |
||
3290 |
for (linkhead = headlinkhead; linkhead != NULL; |
|
3291 |
linkhead = linkhead->nexthead) { |
|
3292 |
if (strcmp(linkhead->dir_re, dir_re) == 0) { |
|
3293 |
return (linkhead); |
|
3294 |
} |
|
3295 |
} |
|
3296 |
||
3297 |
/* |
|
3298 |
* This tag is not in cache, so add it, along with all its |
|
3299 |
* matching /dev entries. This is the only time we go to disk. |
|
3300 |
*/ |
|
3301 |
linkhead = s_malloc(sizeof (linkhead_t)); |
|
3302 |
linkhead->nexthead = headlinkhead; |
|
3303 |
headlinkhead = linkhead; |
|
3304 |
linkhead->dir_re = s_strdup(dir_re); |
|
3305 |
||
3306 |
if ((n = regcomp(&(linkhead->dir_re_compiled), dir_re, |
|
3307 |
REG_EXTENDED)) != 0) { |
|
3308 |
err_print(REGCOMP_FAILED, dir_re, n); |
|
3309 |
} |
|
3310 |
||
3311 |
linkhead->nextlink = NULL; |
|
3312 |
linkhead->link = NULL; |
|
3313 |
||
3314 |
rd.fcn = build_devlink_list; |
|
3315 |
rd.data = (void *)linkhead; |
|
3316 |
||
3317 |
vprint(BUILDCACHE_MID, "get_cached_links: calling recurse_dev_re\n"); |
|
3318 |
||
3319 |
/* call build_devlink_list for each directory in the dir_re RE */ |
|
3320 |
if (dir_re[0] == '/') { |
|
3321 |
recurse_dev_re("/", &dir_re[1], &rd); |
|
3322 |
} else { |
|
3323 |
recurse_dev_re(dev_dir, dir_re, &rd); |
|
3324 |
} |
|
3325 |
||
3326 |
return (linkhead); |
|
3327 |
} |
|
3328 |
||
3329 |
static void |
|
3330 |
build_devlink_list(char *devlink, void *data) |
|
3331 |
{ |
|
3332 |
char *fcn = "build_devlink_list: "; |
|
3333 |
char *ptr; |
|
3334 |
char *r_contents; |
|
3335 |
char *r_devlink; |
|
3336 |
char contents[PATH_MAX + 1]; |
|
3337 |
char newlink[PATH_MAX + 1]; |
|
3338 |
char stage_link[PATH_MAX + 1]; |
|
3339 |
int linksize; |
|
3340 |
linkhead_t *linkhead = (linkhead_t *)data; |
|
3341 |
link_t *link; |
|
3342 |
int i = 0; |
|
3343 |
||
3344 |
vprint(BUILDCACHE_MID, "%scheck_link: %s\n", fcn, devlink); |
|
3345 |
||
3346 |
(void) strcpy(newlink, devlink); |
|
3347 |
||
3348 |
do { |
|
3349 |
linksize = readlink(newlink, contents, PATH_MAX); |
|
3350 |
if (linksize <= 0) { |
|
3351 |
/* |
|
3352 |
* The first pass through the do loop we may readlink() |
|
3353 |
* non-symlink files(EINVAL) from false regexec matches. |
|
3354 |
* Suppress error messages in those cases or if the link |
|
3355 |
* content is the empty string. |
|
3356 |
*/ |
|
3357 |
if (linksize < 0 && (i || errno != EINVAL)) |
|
3358 |
err_print(READLINK_FAILED, "build_devlink_list", |
|
3359 |
newlink, strerror(errno)); |
|
3360 |
return; |
|
3361 |
} |
|
3362 |
contents[linksize] = '\0'; |
|
3363 |
i = 1; |
|
3364 |
||
3365 |
if (is_minor_node(contents, &r_contents) == DEVFSADM_FALSE) { |
|
3366 |
/* |
|
3367 |
* assume that link contents is really a pointer to |
|
3368 |
* another link, so recurse and read its link contents. |
|
3369 |
* |
|
3370 |
* some link contents are absolute: |
|
3371 |
* /dev/audio -> /dev/sound/0 |
|
3372 |
*/ |
|
3373 |
if (strncmp(contents, DEV "/", |
|
3374 |
strlen(DEV) + strlen("/")) != 0) { |
|
3375 |
||
3376 |
if ((ptr = strrchr(newlink, '/')) == NULL) { |
|
3377 |
vprint(REMOVE_MID, "%s%s -> %s invalid " |
|
3378 |
"link. missing '/'\n", fcn, |
|
3379 |
newlink, contents); |
|
3380 |
return; |
|
3381 |
} |
|
3382 |
*ptr = '\0'; |
|
3383 |
(void) strcpy(stage_link, newlink); |
|
3384 |
*ptr = '/'; |
|
3385 |
(void) strcat(stage_link, "/"); |
|
3386 |
(void) strcat(stage_link, contents); |
|
3387 |
(void) strcpy(newlink, stage_link); |
|
3388 |
} else { |
|
3389 |
(void) strcpy(newlink, dev_dir); |
|
3390 |
(void) strcat(newlink, "/"); |
|
3391 |
(void) strcat(newlink, |
|
3392 |
&contents[strlen(DEV) + strlen("/")]); |
|
3393 |
} |
|
3394 |
||
3395 |
} else { |
|
3396 |
newlink[0] = '\0'; |
|
3397 |
} |
|
3398 |
} while (newlink[0] != '\0'); |
|
3399 |
||
3400 |
if (strncmp(devlink, dev_dir, strlen(dev_dir)) != 0) { |
|
3401 |
vprint(BUILDCACHE_MID, "%sinvalid link: %s\n", fcn, devlink); |
|
3402 |
return; |
|
3403 |
} |
|
3404 |
||
3405 |
r_devlink = devlink + strlen(dev_dir); |
|
3406 |
||
3407 |
if (r_devlink[0] != '/') |
|
3408 |
return; |
|
3409 |
||
3410 |
link = s_malloc(sizeof (link_t)); |
|
3411 |
||
3412 |
/* don't store the '/' after rootdir/dev */ |
|
3413 |
r_devlink += 1; |
|
3414 |
||
3415 |
vprint(BUILDCACHE_MID, "%scaching link: %s\n", fcn, r_devlink); |
|
3416 |
link->devlink = s_strdup(r_devlink); |
|
3417 |
||
3418 |
link->contents = s_strdup(r_contents); |
|
3419 |
||
3420 |
link->next = linkhead->link; |
|
3421 |
linkhead->link = link; |
|
3422 |
} |
|
3423 |
||
3424 |
/* |
|
3425 |
* to be consistent, devlink must not begin with / and must be |
|
3426 |
* relative to /dev/, whereas physpath must contain / and be |
|
3427 |
* relative to /devices. |
|
3428 |
*/ |
|
3429 |
static void |
|
3430 |
add_link_to_cache(char *devlink, char *physpath) |
|
3431 |
{ |
|
3432 |
linkhead_t *linkhead; |
|
3433 |
link_t *link; |
|
3434 |
int added = 0; |
|
3435 |
||
3436 |
if (file_mods == FALSE) { |
|
3437 |
return; |
|
3438 |
} |
|
3439 |
||
3440 |
vprint(CACHE_MID, "add_link_to_cache: %s -> %s ", |
|
3441 |
devlink, physpath); |
|
3442 |
||
3443 |
for (linkhead = headlinkhead; linkhead != NULL; |
|
3444 |
linkhead = linkhead->nexthead) { |
|
3445 |
if (regexec(&(linkhead->dir_re_compiled), devlink, 0, NULL, |
|
3446 |
0) == 0) { |
|
3447 |
added++; |
|
3448 |
link = s_malloc(sizeof (link_t)); |
|
3449 |
link->devlink = s_strdup(devlink); |
|
3450 |
link->contents = s_strdup(physpath); |
|
3451 |
link->next = linkhead->link; |
|
3452 |
linkhead->link = link; |
|
3453 |
} |
|
3454 |
} |
|
3455 |
||
3456 |
vprint(CACHE_MID, |
|
3457 |
" %d %s\n", added, added == 0 ? "NOT ADDED" : "ADDED"); |
|
3458 |
} |
|
3459 |
||
3460 |
/* |
|
3461 |
* Remove devlink from cache. Devlink must be relative to /dev/ and not start |
|
3462 |
* with /. |
|
3463 |
*/ |
|
3464 |
static void |
|
3465 |
rm_link_from_cache(char *devlink) |
|
3466 |
{ |
|
3467 |
linkhead_t *linkhead; |
|
3468 |
link_t **linkp; |
|
3469 |
link_t *save; |
|
3470 |
||
3471 |
vprint(CACHE_MID, "rm_link_from_cache enter: %s\n", devlink); |
|
3472 |
||
3473 |
for (linkhead = headlinkhead; linkhead != NULL; |
|
3474 |
linkhead = linkhead->nexthead) { |
|
3475 |
if (regexec(&(linkhead->dir_re_compiled), devlink, 0, NULL, |
|
3476 |
0) == 0) { |
|
3477 |
||
3478 |
for (linkp = &(linkhead->link); *linkp != NULL; ) { |
|
3479 |
if ((strcmp((*linkp)->devlink, devlink) == 0)) { |
|
3480 |
save = *linkp; |
|
3481 |
*linkp = (*linkp)->next; |
|
3482 |
/* |
|
3483 |
* We are removing our caller's |
|
3484 |
* "next" link. Update the nextlink |
|
3485 |
* field in the head so that our |
|
3486 |
* callers accesses the next valid |
|
3487 |
* link |
|
3488 |
*/ |
|
3489 |
if (linkhead->nextlink == save) |
|
3490 |
linkhead->nextlink = *linkp; |
|
3491 |
free(save->devlink); |
|
3492 |
free(save->contents); |
|
3493 |
free(save); |
|
3494 |
vprint(CACHE_MID, " %s FREED FROM " |
|
3495 |
"CACHE\n", devlink); |
|
3496 |
} else { |
|
3497 |
linkp = &((*linkp)->next); |
|
3498 |
} |
|
3499 |
} |
|
3500 |
} |
|
3501 |
} |
|
3502 |
} |
|
3503 |
||
3504 |
static void |
|
3505 |
rm_all_links_from_cache() |
|
3506 |
{ |
|
3507 |
linkhead_t *linkhead; |
|
3508 |
linkhead_t *nextlinkhead; |
|
3509 |
link_t *link; |
|
3510 |
link_t *nextlink; |
|
3511 |
||
3512 |
vprint(CACHE_MID, "rm_all_links_from_cache\n"); |
|
3513 |
||
3514 |
for (linkhead = headlinkhead; linkhead != NULL; |
|
3515 |
linkhead = nextlinkhead) { |
|
3516 |
||
3517 |
nextlinkhead = linkhead->nexthead; |
|
3518 |
assert(linkhead->nextlink == NULL); |
|
3519 |
for (link = linkhead->link; link != NULL; link = nextlink) { |
|
3520 |
nextlink = link->next; |
|
3521 |
free(link->devlink); |
|
3522 |
free(link->contents); |
|
3523 |
free(link); |
|
3524 |
} |
|
3525 |
regfree(&(linkhead->dir_re_compiled)); |
|
3526 |
free(linkhead->dir_re); |
|
3527 |
free(linkhead); |
|
3528 |
} |
|
3529 |
headlinkhead = NULL; |
|
3530 |
} |
|
3531 |
||
3532 |
/* |
|
3533 |
* Called when the kernel has modified the incore path_to_inst data. This |
|
3534 |
* function will schedule a flush of the data to the filesystem. |
|
3535 |
*/ |
|
3536 |
static void |
|
3537 |
devfs_instance_mod(void) |
|
3538 |
{ |
|
3539 |
char *fcn = "devfs_instance_mod: "; |
|
3540 |
vprint(PATH2INST_MID, "%senter\n", fcn); |
|
3541 |
||
3542 |
/* signal instance thread */ |
|
3543 |
(void) mutex_lock(&count_lock); |
|
3544 |
inst_count++; |
|
3545 |
(void) cond_signal(&cv); |
|
3546 |
(void) mutex_unlock(&count_lock); |
|
3547 |
} |
|
3548 |
||
3549 |
static void |
|
3550 |
instance_flush_thread(void) |
|
3551 |
{ |
|
3552 |
int i; |
|
3553 |
int idle; |
|
3554 |
||
3555 |
for (;;) { |
|
3556 |
||
3557 |
(void) mutex_lock(&count_lock); |
|
3558 |
while (inst_count == 0) { |
|
3559 |
(void) cond_wait(&cv, &count_lock); |
|
3560 |
} |
|
3561 |
inst_count = 0; |
|
3562 |
||
3563 |
vprint(PATH2INST_MID, "signaled to flush path_to_inst." |
|
3564 |
" Enter delay loop\n"); |
|
3565 |
/* |
|
3566 |
* Wait MAX_IDLE_DELAY seconds after getting the last flush |
|
3567 |
* path_to_inst event before invoking a flush, but never wait |
|
3568 |
* more than MAX_DELAY seconds after getting the first event. |
|
3569 |
*/ |
|
3570 |
for (idle = 0, i = 0; i < MAX_DELAY; i++) { |
|
3571 |
||
3572 |
(void) mutex_unlock(&count_lock); |
|
3573 |
(void) sleep(1); |
|
3574 |
(void) mutex_lock(&count_lock); |
|
3575 |
||
3576 |
/* shorten the delay if we are idle */ |
|
3577 |
if (inst_count == 0) { |
|
3578 |
idle++; |
|
3579 |
if (idle > MAX_IDLE_DELAY) { |
|
3580 |
break; |
|
3581 |
} |
|
3582 |
} else { |
|
3583 |
inst_count = idle = 0; |
|
3584 |
} |
|
3585 |
} |
|
3586 |
||
3587 |
(void) mutex_unlock(&count_lock); |
|
3588 |
||
3589 |
flush_path_to_inst(); |
|
3590 |
} |
|
3591 |
} |
|
3592 |
||
3593 |
/* |
|
3594 |
* Helper function for flush_path_to_inst() below; this routine calls the |
|
3595 |
* inst_sync syscall to flush the path_to_inst database to the given file. |
|
3596 |
*/ |
|
3597 |
static int |
|
3598 |
do_inst_sync(char *filename) |
|
3599 |
{ |
|
3600 |
void (*sigsaved)(int); |
|
3601 |
int err = 0; |
|
3602 |
||
3603 |
vprint(INSTSYNC_MID, "do_inst_sync: about to flush %s\n", filename); |
|
3604 |
sigsaved = sigset(SIGSYS, SIG_IGN); |
|
3605 |
if (inst_sync(filename, 0) == -1) |
|
3606 |
err = errno; |
|
3607 |
(void) sigset(SIGSYS, sigsaved); |
|
3608 |
||
3609 |
switch (err) { |
|
3610 |
case 0: |
|
3611 |
return (DEVFSADM_SUCCESS); |
|
3612 |
case EALREADY: /* no-op, path_to_inst already up to date */ |
|
3613 |
return (EALREADY); |
|
3614 |
case ENOSYS: |
|
3615 |
err_print(CANT_LOAD_SYSCALL); |
|
3616 |
break; |
|
3617 |
case EPERM: |
|
3618 |
err_print(SUPER_TO_SYNC); |
|
3619 |
break; |
|
3620 |
default: |
|
3621 |
err_print(INSTSYNC_FAILED, filename, strerror(err)); |
|
3622 |
break; |
|
3623 |
} |
|
3624 |
return (DEVFSADM_FAILURE); |
|
3625 |
} |
|
3626 |
||
3627 |
/* |
|
3628 |
* Flush the kernel's path_to_inst database to /etc/path_to_inst. To do so |
|
3629 |
* safely, the database is flushed to a temporary file, then moved into place. |
|
3630 |
* |
|
3631 |
* The following files are used during this process: |
|
3632 |
* /etc/path_to_inst: The path_to_inst file |
|
3633 |
* /etc/path_to_inst.<pid>: Contains data flushed from the kernel |
|
3634 |
* /etc/path_to_inst.old: The backup file |
|
3635 |
* /etc/path_to_inst.old.<pid>: Temp file for creating backup |
|
3636 |
* |
|
3637 |
*/ |
|
3638 |
static void |
|
3639 |
flush_path_to_inst(void) |
|
3640 |
{ |
|
3641 |
char *new_inst_file = NULL; |
|
3642 |
char *old_inst_file = NULL; |
|
3643 |
char *old_inst_file_npid = NULL; |
|
3644 |
FILE *inst_file_fp = NULL; |
|
3645 |
FILE *old_inst_file_fp = NULL; |
|
3646 |
struct stat sb; |
|
3647 |
int err = 0; |
|
3648 |
int c; |
|
3649 |
int inst_strlen; |
|
3650 |
||
3651 |
vprint(PATH2INST_MID, "flush_path_to_inst: %s\n", |
|
3652 |
(flush_path_to_inst_enable == TRUE) ? "ENABLED" : "DISABLED"); |
|
3653 |
||
3654 |
if (flush_path_to_inst_enable == FALSE) { |
|
3655 |
return; |
|
3656 |
} |
|
3657 |
||
3658 |
inst_strlen = strlen(inst_file); |
|
3659 |
new_inst_file = s_malloc(inst_strlen + PID_STR_LEN + 2); |
|
3660 |
old_inst_file = s_malloc(inst_strlen + PID_STR_LEN + 6); |
|
3661 |
old_inst_file_npid = s_malloc(inst_strlen + |
|
3662 |
sizeof (INSTANCE_FILE_SUFFIX)); |
|
3663 |
||
3664 |
(void) snprintf(new_inst_file, inst_strlen + PID_STR_LEN + 2, |
|
3665 |
"%s.%ld", inst_file, getpid()); |
|
3666 |
||
3667 |
if (stat(new_inst_file, &sb) == 0) { |
|
3668 |
s_unlink(new_inst_file); |
|
3669 |
} |
|
3670 |
||
3671 |
if ((err = do_inst_sync(new_inst_file)) != DEVFSADM_SUCCESS) { |
|
3672 |
goto out; |
|
3673 |
/*NOTREACHED*/ |
|
3674 |
} |
|
3675 |
||
3676 |
/* |
|
3677 |
* Now we deal with the somewhat tricky updating and renaming |
|
3678 |
* of this critical piece of kernel state. |
|
3679 |
*/ |
|
3680 |
||
3681 |
/* |
|
3682 |
* Copy the current instance file into a temporary file. |
|
3683 |
* Then rename the temporary file into the backup (.old) |
|
3684 |
* file and rename the newly flushed kernel data into |
|
3685 |
* the instance file. |
|
3686 |
* Of course if 'inst_file' doesn't exist, there's much |
|
3687 |
* less for us to do .. tee hee. |
|
3688 |
*/ |
|
3689 |
if ((inst_file_fp = fopen(inst_file, "r")) == NULL) { |
|
3690 |
/* |
|
3691 |
* No such file. Rename the new onto the old |
|
3692 |
*/ |
|
3693 |
if ((err = rename(new_inst_file, inst_file)) != 0) |
|
3694 |
err_print(RENAME_FAILED, inst_file, strerror(errno)); |
|
3695 |
goto out; |
|
3696 |
/*NOTREACHED*/ |
|
3697 |
} |
|
3698 |
||
3699 |
(void) snprintf(old_inst_file, inst_strlen + PID_STR_LEN + 6, |
|
3700 |
"%s.old.%ld", inst_file, getpid()); |
|
3701 |
||
3702 |
if (stat(old_inst_file, &sb) == 0) { |
|
3703 |
s_unlink(old_inst_file); |
|
3704 |
} |
|
3705 |
||
3706 |
if ((old_inst_file_fp = fopen(old_inst_file, "w")) == NULL) { |
|
3707 |
/* |
|
3708 |
* Can't open the 'old_inst_file' file for writing. |
|
3709 |
* This is somewhat strange given that the syscall |
|
3710 |
* just succeeded to write a file out.. hmm.. maybe |
|
3711 |
* the fs just filled up or something nasty. |
|
3712 |
* |
|
3713 |
* Anyway, abort what we've done so far. |
|
3714 |
*/ |
|
3715 |
err_print(CANT_UPDATE, old_inst_file); |
|
3716 |
err = DEVFSADM_FAILURE; |
|
3717 |
goto out; |
|
3718 |
/*NOTREACHED*/ |
|
3719 |
} |
|
3720 |
||
3721 |
/* |
|
3722 |
* Copy current instance file into the temporary file |
|
3723 |
*/ |
|
3724 |
err = 0; |
|
3725 |
while ((c = getc(inst_file_fp)) != EOF) { |
|
3726 |
if ((err = putc(c, old_inst_file_fp)) == EOF) { |
|
3727 |
break; |
|
3728 |
} |
|
3729 |
} |
|
3730 |
||
3731 |
if (fclose(old_inst_file_fp) == EOF || err == EOF) { |
|
3732 |
vprint(INFO_MID, CANT_UPDATE, old_inst_file); |
|
3733 |
err = DEVFSADM_FAILURE; |
|
3734 |
goto out; |
|
3735 |
/* NOTREACHED */ |
|
3736 |
} |
|
3737 |
||
3738 |
/* |
|
3739 |
* Set permissions to be the same on the backup as |
|
3740 |
* /etc/path_to_inst. |
|
3741 |
*/ |
|
3742 |
(void) chmod(old_inst_file, 0444); |
|
3743 |
||
3744 |
/* |
|
3745 |
* So far, everything we've done is more or less reversible. |
|
3746 |
* But now we're going to commit ourselves. |
|
3747 |
*/ |
|
3748 |
||
3749 |
(void) snprintf(old_inst_file_npid, |
|
3750 |
inst_strlen + sizeof (INSTANCE_FILE_SUFFIX), |
|
3751 |
"%s%s", inst_file, INSTANCE_FILE_SUFFIX); |
|
3752 |
||
3753 |
if ((err = rename(old_inst_file, old_inst_file_npid)) != 0) { |
|
3754 |
err_print(RENAME_FAILED, old_inst_file_npid, |
|
3755 |
strerror(errno)); |
|
3756 |
} else if ((err = rename(new_inst_file, inst_file)) != 0) { |
|
3757 |
err_print(RENAME_FAILED, inst_file, strerror(errno)); |
|
3758 |
} |
|
3759 |
||
3760 |
out: |
|
3761 |
if (inst_file_fp != NULL) { |
|
3762 |
if (fclose(inst_file_fp) == EOF) { |
|
3763 |
err_print(FCLOSE_FAILED, inst_file, strerror(errno)); |
|
3764 |
} |
|
3765 |
} |
|
3766 |
||
3767 |
if (stat(new_inst_file, &sb) == 0) { |
|
3768 |
s_unlink(new_inst_file); |
|
3769 |
} |
|
3770 |
free(new_inst_file); |
|
3771 |
||
3772 |
if (stat(old_inst_file, &sb) == 0) { |
|
3773 |
s_unlink(old_inst_file); |
|
3774 |
} |
|
3775 |
free(old_inst_file); |
|
3776 |
||
3777 |
free(old_inst_file_npid); |
|
3778 |
||
3779 |
if (err != 0 && err != EALREADY) { |
|
3780 |
err_print(FAILED_TO_UPDATE, inst_file); |
|
3781 |
} |
|
3782 |
} |
|
3783 |
||
3784 |
/* |
|
3785 |
* detach from tty. For daemon mode. |
|
3786 |
*/ |
|
3787 |
void |
|
3788 |
detachfromtty() |
|
3789 |
{ |
|
3790 |
(void) setsid(); |
|
3791 |
if (DEVFSADM_DEBUG_ON == TRUE) { |
|
3792 |
return; |
|
3793 |
} |
|
3794 |
||
3795 |
(void) close(0); |
|
3796 |
(void) close(1); |
|
3797 |
(void) close(2); |
|
3798 |
(void) open("/dev/null", O_RDWR, 0); |
|
3799 |
(void) dup(0); |
|
3800 |
(void) dup(0); |
|
3801 |
openlog(DEVFSADMD, LOG_PID, LOG_DAEMON); |
|
3802 |
(void) setlogmask(LOG_UPTO(LOG_INFO)); |
|
3803 |
logflag = TRUE; |
|
3804 |
} |
|
3805 |
||
3806 |
/* |
|
3807 |
* Use an advisory lock to synchronize updates to /dev. If the lock is |
|
3808 |
* held by another process, block in the fcntl() system call until that |
|
3809 |
* process drops the lock or exits. The lock file itself is |
|
3810 |
* DEV_LOCK_FILE. The process id of the current and last process owning |
|
3811 |
* the lock is kept in the lock file. After acquiring the lock, read the |
|
3812 |
* process id and return it. It is the process ID which last owned the |
|
3813 |
* lock, and will be used to determine if caches need to be flushed. |
|
3814 |
* |
|
3815 |
* NOTE: if the devlink database is held open by the caller, it may |
|
3816 |
* be closed by this routine. This is to enforce the following lock ordering: |
|
3817 |
* 1) /dev lock 2) database open |
|
3818 |
*/ |
|
3819 |
pid_t |
|
3820 |
enter_dev_lock() |
|
3821 |
{ |
|
3822 |
struct flock lock; |
|
3823 |
int n; |
|
3824 |
pid_t pid; |
|
3825 |
pid_t last_owner_pid; |
|
3826 |
||
3827 |
if (file_mods == FALSE) { |
|
3828 |
return (0); |
|
3829 |
} |
|
3830 |
||
3831 |
(void) snprintf(dev_lockfile, sizeof (dev_lockfile), |
|
2621 | 3832 |
"%s/%s", etc_dev_dir, DEV_LOCK_FILE); |
0 | 3833 |
|
3834 |
vprint(LOCK_MID, "enter_dev_lock: lock file %s\n", dev_lockfile); |
|
3835 |
||
3836 |
dev_lock_fd = open(dev_lockfile, O_CREAT|O_RDWR, 0644); |
|
3837 |
if (dev_lock_fd < 0) { |
|
3838 |
err_print(OPEN_FAILED, dev_lockfile, strerror(errno)); |
|
3839 |
devfsadm_exit(1); |
|
3840 |
} |
|
3841 |
||
3842 |
lock.l_type = F_WRLCK; |
|
3843 |
lock.l_whence = SEEK_SET; |
|
3844 |
lock.l_start = 0; |
|
3845 |
lock.l_len = 0; |
|
3846 |
||
3847 |
/* try for the lock, but don't wait */ |
|
3848 |
if (fcntl(dev_lock_fd, F_SETLK, &lock) == -1) { |
|
3849 |
if ((errno == EACCES) || (errno == EAGAIN)) { |
|
3850 |
pid = 0; |
|
3851 |
n = read(dev_lock_fd, &pid, sizeof (pid_t)); |
|
3852 |
vprint(LOCK_MID, "waiting for PID %d to complete\n", |
|
3853 |
(int)pid); |
|
3854 |
if (lseek(dev_lock_fd, 0, SEEK_SET) == (off_t)-1) { |
|
3855 |
err_print(LSEEK_FAILED, dev_lockfile, |
|
3856 |
strerror(errno)); |
|
3857 |
devfsadm_exit(1); |
|
3858 |
} |
|
3859 |
/* |
|
3860 |
* wait for the dev lock. If we have the database open, |
|
3861 |
* close it first - the order of lock acquisition should |
|
3862 |
* always be: 1) dev_lock 2) database |
|
3863 |
* This is to prevent deadlocks with any locks the |
|
3864 |
* database code may hold. |
|
3865 |
*/ |
|
3866 |
(void) di_devlink_close(&devlink_cache, 0); |
|
3854 | 3867 |
|
3868 |
/* send any sysevents that were queued up. */ |
|
3869 |
process_syseventq(); |
|
3870 |
||
0 | 3871 |
if (fcntl(dev_lock_fd, F_SETLKW, &lock) == -1) { |
3872 |
err_print(LOCK_FAILED, dev_lockfile, |
|
3873 |
strerror(errno)); |
|
3874 |
devfsadm_exit(1); |
|
3875 |
} |
|
3876 |
} |
|
3877 |
} |
|
3878 |
||
3879 |
hold_dev_lock = TRUE; |
|
3880 |
pid = 0; |
|
3881 |
n = read(dev_lock_fd, &pid, sizeof (pid_t)); |
|
3882 |
if (n == sizeof (pid_t) && pid == getpid()) { |
|
3883 |
return (pid); |
|
3884 |
} |
|
3885 |
||
3886 |
last_owner_pid = pid; |
|
3887 |
||
3888 |
if (lseek(dev_lock_fd, 0, SEEK_SET) == (off_t)-1) { |
|
3889 |
err_print(LSEEK_FAILED, dev_lockfile, strerror(errno)); |
|
3890 |
devfsadm_exit(1); |
|
3891 |
} |
|
3892 |
pid = getpid(); |
|
3893 |
n = write(dev_lock_fd, &pid, sizeof (pid_t)); |
|
3894 |
if (n != sizeof (pid_t)) { |
|
3895 |
err_print(WRITE_FAILED, dev_lockfile, strerror(errno)); |
|
3896 |
devfsadm_exit(1); |
|
3897 |
} |
|
3898 |
||
3899 |
return (last_owner_pid); |
|
3900 |
} |
|
3901 |
||
3902 |
/* |
|
3903 |
* Drop the advisory /dev lock, close lock file. Close and re-open the |
|
3904 |
* file every time so to ensure a resync if for some reason the lock file |
|
3905 |
* gets removed. |
|
3906 |
*/ |
|
3907 |
void |
|
3908 |
exit_dev_lock() |
|
3909 |
{ |
|
3910 |
struct flock unlock; |
|
3911 |
||
3912 |
if (hold_dev_lock == FALSE) { |
|
3913 |
return; |
|
3914 |
} |
|
3915 |
||
3916 |
vprint(LOCK_MID, "exit_dev_lock: lock file %s\n", dev_lockfile); |
|
3917 |
||
3918 |
unlock.l_type = F_UNLCK; |
|
3919 |
unlock.l_whence = SEEK_SET; |
|
3920 |
unlock.l_start = 0; |
|
3921 |
unlock.l_len = 0; |
|
3922 |
||
3923 |
if (fcntl(dev_lock_fd, F_SETLK, &unlock) == -1) { |
|
3924 |
err_print(UNLOCK_FAILED, dev_lockfile, strerror(errno)); |
|
3925 |
} |
|
3926 |
||
3927 |
hold_dev_lock = FALSE; |
|
3928 |
||
3929 |
if (close(dev_lock_fd) == -1) { |
|
3930 |
err_print(CLOSE_FAILED, dev_lockfile, strerror(errno)); |
|
3931 |
devfsadm_exit(1); |
|
3932 |
} |
|
3933 |
} |
|
3934 |
||
3935 |
/* |
|
3936 |
* |
|
3937 |
* Use an advisory lock to ensure that only one daemon process is active |
|
3938 |
* in the system at any point in time. If the lock is held by another |
|
3939 |
* process, do not block but return the pid owner of the lock to the |
|
3940 |
* caller immediately. The lock is cleared if the holding daemon process |
|
3941 |
* exits for any reason even if the lock file remains, so the daemon can |
|
3942 |
* be restarted if necessary. The lock file is DAEMON_LOCK_FILE. |
|
3943 |
*/ |
|
3944 |
pid_t |
|
3945 |
enter_daemon_lock(void) |
|
3946 |
{ |
|
3947 |
struct flock lock; |
|
3948 |
||
3949 |
(void) snprintf(daemon_lockfile, sizeof (daemon_lockfile), |
|
2621 | 3950 |
"%s/%s", etc_dev_dir, DAEMON_LOCK_FILE); |
0 | 3951 |
|
3952 |
vprint(LOCK_MID, "enter_daemon_lock: lock file %s\n", daemon_lockfile); |
|
3953 |
||
3954 |
daemon_lock_fd = open(daemon_lockfile, O_CREAT|O_RDWR, 0644); |
|
3955 |
if (daemon_lock_fd < 0) { |
|
3956 |
err_print(OPEN_FAILED, daemon_lockfile, strerror(errno)); |
|
3957 |
devfsadm_exit(1); |
|
3958 |
} |
|
3959 |
||
3960 |
lock.l_type = F_WRLCK; |
|
3961 |
lock.l_whence = SEEK_SET; |
|
3962 |
lock.l_start = 0; |
|
3963 |
lock.l_len = 0; |
|
3964 |
||
3965 |
if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) { |
|
3966 |
||
3967 |
if (errno == EAGAIN || errno == EDEADLK) { |
|
3968 |
if (fcntl(daemon_lock_fd, F_GETLK, &lock) == -1) { |
|
3969 |
err_print(LOCK_FAILED, daemon_lockfile, |
|
3970 |
strerror(errno)); |
|
3971 |
devfsadm_exit(1); |
|
3972 |
} |
|
3973 |
return (lock.l_pid); |
|
3974 |
} |
|
3975 |
} |
|
3976 |
hold_daemon_lock = TRUE; |
|
3977 |
return (getpid()); |
|
3978 |
} |
|
3979 |
||
3980 |
/* |
|
3981 |
* Drop the advisory daemon lock, close lock file |
|
3982 |
*/ |
|
3983 |
void |
|
3984 |
exit_daemon_lock(void) |
|
3985 |
{ |
|
3986 |
struct flock lock; |
|
3987 |
||
3988 |
if (hold_daemon_lock == FALSE) { |
|
3989 |
return; |
|
3990 |
} |
|
3991 |
||
3992 |
vprint(LOCK_MID, "exit_daemon_lock: lock file %s\n", daemon_lockfile); |
|
3993 |
||
3994 |
lock.l_type = F_UNLCK; |
|
3995 |
lock.l_whence = SEEK_SET; |
|
3996 |
lock.l_start = 0; |
|
3997 |
lock.l_len = 0; |
|
3998 |
||
3999 |
if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) { |
|
4000 |
err_print(UNLOCK_FAILED, daemon_lockfile, strerror(errno)); |
|
4001 |
} |
|
4002 |
||
4003 |
if (close(daemon_lock_fd) == -1) { |
|
4004 |
err_print(CLOSE_FAILED, daemon_lockfile, strerror(errno)); |
|
4005 |
devfsadm_exit(1); |
|
4006 |
} |
|
4007 |
} |
|
4008 |
||
4009 |
/* |
|
4010 |
* Called to removed danging nodes in two different modes: RM_PRE, RM_POST. |
|
4011 |
* RM_PRE mode is called before processing the entire devinfo tree, and RM_POST |
|
4012 |
* is called after processing the entire devinfo tree. |
|
4013 |
*/ |
|
4014 |
static void |
|
4015 |
pre_and_post_cleanup(int flags) |
|
4016 |
{ |
|
4017 |
remove_list_t *rm; |
|
4018 |
recurse_dev_t rd; |
|
4019 |
cleanup_data_t cleanup_data; |
|
4020 |
char *fcn = "pre_and_post_cleanup: "; |
|
4021 |
||
4022 |
if (build_dev == FALSE) |
|
4023 |
return; |
|
4024 |
||
4025 |
vprint(CHATTY_MID, "attempting %s-cleanup\n", |
|
4026 |
flags == RM_PRE ? "pre" : "post"); |
|
4027 |
vprint(REMOVE_MID, "%sflags = %d\n", fcn, flags); |
|
4028 |
||
4029 |
/* |
|
4030 |
* the generic function recurse_dev_re is shared among different |
|
4031 |
* functions, so set the method and data that it should use for |
|
4032 |
* matches. |
|
4033 |
*/ |
|
4034 |
rd.fcn = matching_dev; |
|
4035 |
rd.data = (void *)&cleanup_data; |
|
4036 |
cleanup_data.flags = flags; |
|
4037 |
||
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4038 |
(void) mutex_lock(&nfp_mutex); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4039 |
nfphash_create(); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4040 |
|
0 | 4041 |
for (rm = remove_head; rm != NULL; rm = rm->next) { |
4042 |
if ((flags & rm->remove->flags) == flags) { |
|
4043 |
cleanup_data.rm = rm; |
|
4044 |
/* |
|
4045 |
* If reached this point, RM_PRE or RM_POST cleanup is |
|
4046 |
* desired. clean_ok() decides whether to clean |
|
4047 |
* under the given circumstances. |
|
4048 |
*/ |
|
4049 |
vprint(REMOVE_MID, "%scleanup: PRE or POST\n", fcn); |
|
4050 |
if (clean_ok(rm->remove) == DEVFSADM_SUCCESS) { |
|
4051 |
vprint(REMOVE_MID, "cleanup: cleanup OK\n"); |
|
4052 |
recurse_dev_re(dev_dir, rm->remove-> |
|
4053 |
dev_dirs_re, &rd); |
|
4054 |
} |
|
4055 |
} |
|
4056 |
} |
|
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4057 |
nfphash_destroy(); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4058 |
(void) mutex_unlock(&nfp_mutex); |
0 | 4059 |
} |
4060 |
||
4061 |
/* |
|
4062 |
* clean_ok() determines whether cleanup should be done according |
|
4063 |
* to the following matrix: |
|
4064 |
* |
|
4065 |
* command line arguments RM_PRE RM_POST RM_PRE && RM_POST && |
|
4066 |
* RM_ALWAYS RM_ALWAYS |
|
4067 |
* ---------------------- ------ ----- --------- ---------- |
|
4068 |
* |
|
4069 |
* <neither -c nor -C> - - pre-clean post-clean |
|
4070 |
* |
|
4071 |
* -C pre-clean post-clean pre-clean post-clean |
|
4072 |
* |
|
4073 |
* -C -c class pre-clean post-clean pre-clean post-clean |
|
4074 |
* if class if class if class if class |
|
4075 |
* matches matches matches matches |
|
4076 |
* |
|
4077 |
* -c class - - pre-clean post-clean |
|
4078 |
* if class if class |
|
4079 |
* matches matches |
|
4080 |
* |
|
4081 |
*/ |
|
4082 |
static int |
|
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4083 |
clean_ok(devfsadm_remove_V1_t *remove) |
0 | 4084 |
{ |
4085 |
int i; |
|
4086 |
||
4087 |
if (single_drv == TRUE) { |
|
4088 |
/* no cleanup at all when using -i option */ |
|
4089 |
return (DEVFSADM_FAILURE); |
|
4090 |
} |
|
4091 |
||
4092 |
/* |
|
4093 |
* no cleanup if drivers are not loaded. We make an exception |
|
4094 |
* for the "disks" program however, since disks has a public |
|
4095 |
* cleanup flag (-C) and disk drivers are usually never |
|
4096 |
* unloaded. |
|
4097 |
*/ |
|
4098 |
if (load_attach_drv == FALSE && strcmp(prog, DISKS) != 0) { |
|
4099 |
return (DEVFSADM_FAILURE); |
|
4100 |
} |
|
4101 |
||
4102 |
/* if the cleanup flag was not specified, return false */ |
|
4103 |
if ((cleanup == FALSE) && ((remove->flags & RM_ALWAYS) == 0)) { |
|
4104 |
return (DEVFSADM_FAILURE); |
|
4105 |
} |
|
4106 |
||
4107 |
if (num_classes == 0) { |
|
4108 |
return (DEVFSADM_SUCCESS); |
|
4109 |
} |
|
4110 |
||
4111 |
/* |
|
4112 |
* if reached this point, check to see if the class in the given |
|
4113 |
* remove structure matches a class given on the command line |
|
4114 |
*/ |
|
4115 |
||
4116 |
for (i = 0; i < num_classes; i++) { |
|
4117 |
if (strcmp(remove->device_class, classes[i]) == 0) { |
|
4118 |
return (DEVFSADM_SUCCESS); |
|
4119 |
} |
|
4120 |
} |
|
4121 |
||
4122 |
return (DEVFSADM_FAILURE); |
|
4123 |
} |
|
4124 |
||
4125 |
/* |
|
4126 |
* Called to remove dangling nodes after receiving a hotplug event |
|
4127 |
* containing the physical node pathname to be removed. |
|
4128 |
*/ |
|
4129 |
void |
|
4130 |
hot_cleanup(char *node_path, char *minor_name, char *ev_subclass, |
|
4131 |
char *driver_name, int instance) |
|
4132 |
{ |
|
4133 |
link_t *link; |
|
4134 |
linkhead_t *head; |
|
4135 |
remove_list_t *rm; |
|
4136 |
char *fcn = "hot_cleanup: "; |
|
4137 |
char path[PATH_MAX + 1]; |
|
4138 |
int path_len; |
|
4139 |
char rmlink[PATH_MAX + 1]; |
|
4140 |
nvlist_t *nvl = NULL; |
|
296 | 4141 |
int skip; |
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4142 |
int ret; |
0 | 4143 |
|
4144 |
/* |
|
4145 |
* dev links can go away as part of hot cleanup. |
|
4146 |
* So first build event attributes in order capture dev links. |
|
4147 |
*/ |
|
4148 |
if (ev_subclass != NULL) |
|
4149 |
nvl = build_event_attributes(EC_DEV_REMOVE, ev_subclass, |
|
4211 | 4150 |
node_path, DI_NODE_NIL, driver_name, instance, minor_name); |
0 | 4151 |
|
4152 |
(void) strcpy(path, node_path); |
|
4153 |
(void) strcat(path, ":"); |
|
4154 |
(void) strcat(path, minor_name == NULL ? "" : minor_name); |
|
4155 |
||
4156 |
path_len = strlen(path); |
|
4157 |
||
4158 |
vprint(REMOVE_MID, "%spath=%s\n", fcn, path); |
|
4159 |
||
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4160 |
(void) mutex_lock(&nfp_mutex); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4161 |
nfphash_create(); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4162 |
|
0 | 4163 |
for (rm = remove_head; rm != NULL; rm = rm->next) { |
4164 |
if ((RM_HOT & rm->remove->flags) == RM_HOT) { |
|
4165 |
head = get_cached_links(rm->remove->dev_dirs_re); |
|
4166 |
assert(head->nextlink == NULL); |
|
4167 |
for (link = head->link; |
|
4168 |
link != NULL; link = head->nextlink) { |
|
4169 |
/* |
|
4170 |
* The remove callback below may remove |
|
4171 |
* the current and/or any or all of the |
|
4172 |
* subsequent links in the list. |
|
4173 |
* Save the next link in the head. If |
|
4174 |
* the callback removes the next link |
|
4175 |
* the saved pointer in the head will be |
|
4176 |
* updated by the callback to point at |
|
4177 |
* the next valid link. |
|
4178 |
*/ |
|
4179 |
head->nextlink = link->next; |
|
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4180 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4181 |
/* |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4182 |
* if devlink is in no-further-process hash, |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4183 |
* skip its remove |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4184 |
*/ |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4185 |
if (nfphash_lookup(link->devlink) != NULL) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4186 |
continue; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4187 |
|
296 | 4188 |
if (minor_name) |
4189 |
skip = strcmp(link->contents, path); |
|
4190 |
else |
|
4191 |
skip = strncmp(link->contents, path, |
|
4192 |
path_len); |
|
4193 |
if (skip || |
|
4194 |
(call_minor_init(rm->modptr) == |
|
4195 |
DEVFSADM_FAILURE)) |
|
4196 |
continue; |
|
4197 |
||
4198 |
vprint(REMOVE_MID, |
|
4199 |
"%sremoving %s -> %s\n", fcn, |
|
4200 |
link->devlink, link->contents); |
|
4201 |
/* |
|
4202 |
* Use a copy of the cached link name |
|
4203 |
* as the cache entry will go away |
|
4204 |
* during link removal |
|
4205 |
*/ |
|
4206 |
(void) snprintf(rmlink, sizeof (rmlink), |
|
4207 |
"%s", link->devlink); |
|
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4208 |
if (rm->remove->flags & RM_NOINTERPOSE) { |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4209 |
((void (*)(char *)) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4210 |
(rm->remove->callback_fcn))(rmlink); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4211 |
} else { |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4212 |
ret = ((int (*)(char *)) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4213 |
(rm->remove->callback_fcn))(rmlink); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4214 |
if (ret == DEVFSADM_TERMINATE) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4215 |
nfphash_insert(rmlink); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4216 |
} |
0 | 4217 |
} |
4218 |
} |
|
4219 |
} |
|
4220 |
||
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4221 |
nfphash_destroy(); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4222 |
(void) mutex_unlock(&nfp_mutex); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4223 |
|
1676 | 4224 |
/* update device allocation database */ |
4225 |
if (system_labeled) { |
|
4226 |
int ret = 0; |
|
4227 |
int devtype = 0; |
|
4228 |
char devname[MAXNAMELEN]; |
|
4229 |
||
4230 |
devname[0] = '\0'; |
|
4231 |
if (strstr(node_path, DA_SOUND_NAME)) |
|
4232 |
devtype = DA_AUDIO; |
|
4233 |
else if (strstr(node_path, "disk")) |
|
4234 |
devtype = DA_RMDISK; |
|
4235 |
else |
|
4236 |
goto out; |
|
4237 |
ret = da_remove_list(&devlist, NULL, devtype, devname, |
|
4238 |
sizeof (devname)); |
|
4239 |
if (ret != -1) |
|
4240 |
(void) _update_devalloc_db(&devlist, devtype, DA_REMOVE, |
|
4241 |
devname, root_dir); |
|
4242 |
} |
|
4243 |
||
4244 |
out: |
|
0 | 4245 |
/* now log an event */ |
4246 |
if (nvl) { |
|
4247 |
log_event(EC_DEV_REMOVE, ev_subclass, nvl); |
|
4248 |
free(nvl); |
|
4249 |
} |
|
4250 |
} |
|
4251 |
||
4252 |
/* |
|
4253 |
* Open the dir current_dir. For every file which matches the first dir |
|
4254 |
* component of path_re, recurse. If there are no more *dir* path |
|
4255 |
* components left in path_re (ie no more /), then call function rd->fcn. |
|
4256 |
*/ |
|
4257 |
static void |
|
4258 |
recurse_dev_re(char *current_dir, char *path_re, recurse_dev_t *rd) |
|
4259 |
{ |
|
4260 |
regex_t re1; |
|
4261 |
char *slash; |
|
4262 |
char new_path[PATH_MAX + 1]; |
|
4263 |
char *anchored_path_re; |
|
4264 |
size_t len; |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
4265 |
finddevhdl_t fhandle; |
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
4266 |
const char *fp; |
0 | 4267 |
|
4268 |
vprint(RECURSEDEV_MID, "recurse_dev_re: curr = %s path=%s\n", |
|
4269 |
current_dir, path_re); |
|
4270 |
||
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
4271 |
if (finddev_readdir(current_dir, &fhandle) != 0) |
0 | 4272 |
return; |
4273 |
||
4274 |
len = strlen(path_re); |
|
4275 |
if ((slash = strchr(path_re, '/')) != NULL) { |
|
4276 |
len = (slash - path_re); |
|
4277 |
} |
|
4278 |
||
4279 |
anchored_path_re = s_malloc(len + 3); |
|
4280 |
(void) sprintf(anchored_path_re, "^%.*s$", len, path_re); |
|
4281 |
||
4282 |
if (regcomp(&re1, anchored_path_re, REG_EXTENDED) != 0) { |
|
4283 |
free(anchored_path_re); |
|
4284 |
goto out; |
|
4285 |
} |
|
4286 |
||
4287 |
free(anchored_path_re); |
|
4288 |
||
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
4289 |
while ((fp = finddev_next(fhandle)) != NULL) { |
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
4290 |
|
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
4291 |
if (regexec(&re1, fp, 0, NULL, 0) == 0) { |
0 | 4292 |
/* match */ |
4293 |
(void) strcpy(new_path, current_dir); |
|
4294 |
(void) strcat(new_path, "/"); |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
4295 |
(void) strcat(new_path, fp); |
0 | 4296 |
|
4297 |
vprint(RECURSEDEV_MID, "recurse_dev_re: match, new " |
|
4298 |
"path = %s\n", new_path); |
|
4299 |
||
4300 |
if (slash != NULL) { |
|
4301 |
recurse_dev_re(new_path, slash + 1, rd); |
|
4302 |
} else { |
|
4303 |
/* reached the leaf component of path_re */ |
|
4304 |
vprint(RECURSEDEV_MID, |
|
4305 |
"recurse_dev_re: calling fcn\n"); |
|
4306 |
(*(rd->fcn))(new_path, rd->data); |
|
4307 |
} |
|
4308 |
} |
|
4309 |
} |
|
4310 |
||
4311 |
regfree(&re1); |
|
4312 |
||
4313 |
out: |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
4314 |
finddev_close(fhandle); |
0 | 4315 |
} |
4316 |
||
4317 |
/* |
|
4318 |
* Found a devpath which matches a RE in the remove structure. |
|
4319 |
* Now check to see if it is dangling. |
|
4320 |
*/ |
|
4321 |
static void |
|
4322 |
matching_dev(char *devpath, void *data) |
|
4323 |
{ |
|
4324 |
cleanup_data_t *cleanup_data = data; |
|
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4325 |
int norm_len = strlen(dev_dir) + strlen("/"); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4326 |
int ret; |
0 | 4327 |
char *fcn = "matching_dev: "; |
4328 |
||
4329 |
vprint(RECURSEDEV_MID, "%sexamining devpath = '%s'\n", fcn, |
|
4330 |
devpath); |
|
4331 |
||
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4332 |
/* |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4333 |
* If the link is in the no-further-process hash |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4334 |
* don't do any remove operation on it. |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4335 |
*/ |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4336 |
if (nfphash_lookup(devpath + norm_len) != NULL) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4337 |
return; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4338 |
|
0 | 4339 |
if (resolve_link(devpath, NULL, NULL, NULL, 1) == TRUE) { |
4340 |
if (call_minor_init(cleanup_data->rm->modptr) == |
|
4341 |
DEVFSADM_FAILURE) { |
|
4342 |
return; |
|
4343 |
} |
|
4344 |
||
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4345 |
devpath += norm_len; |
0 | 4346 |
|
4347 |
vprint(RECURSEDEV_MID, "%scalling" |
|
4348 |
" callback %s\n", fcn, devpath); |
|
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4349 |
if (cleanup_data->rm->remove->flags & RM_NOINTERPOSE) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4350 |
((void (*)(char *)) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4351 |
(cleanup_data->rm->remove->callback_fcn))(devpath); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4352 |
else { |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4353 |
ret = ((int (*)(char *)) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4354 |
(cleanup_data->rm->remove->callback_fcn))(devpath); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4355 |
if (ret == DEVFSADM_TERMINATE) { |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4356 |
/* |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4357 |
* We want no further remove processing for |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4358 |
* this link. Add it to the nfp_hash; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4359 |
*/ |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4360 |
nfphash_insert(devpath); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4361 |
} |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
4362 |
} |
0 | 4363 |
} |
4364 |
} |
|
4365 |
||
4366 |
int |
|
4367 |
devfsadm_read_link(char *link, char **devfs_path) |
|
4368 |
{ |
|
4369 |
char devlink[PATH_MAX]; |
|
4370 |
||
4371 |
*devfs_path = NULL; |
|
4372 |
||
4373 |
/* prepend link with dev_dir contents */ |
|
4374 |
(void) strcpy(devlink, dev_dir); |
|
4375 |
(void) strcat(devlink, "/"); |
|
4376 |
(void) strcat(devlink, link); |
|
4377 |
||
4378 |
/* We *don't* want a stat of the /devices node */ |
|
4379 |
(void) resolve_link(devlink, NULL, NULL, devfs_path, 0); |
|
4380 |
||
4381 |
return (*devfs_path ? DEVFSADM_SUCCESS : DEVFSADM_FAILURE); |
|
4382 |
} |
|
4383 |
||
4384 |
int |
|
4385 |
devfsadm_link_valid(char *link) |
|
4386 |
{ |
|
4387 |
struct stat sb; |
|
1676 | 4388 |
char devlink[PATH_MAX + 1], *contents = NULL; |
0 | 4389 |
int rv, type; |
1676 | 4390 |
int instance = 0; |
0 | 4391 |
|
4392 |
/* prepend link with dev_dir contents */ |
|
4393 |
(void) strcpy(devlink, dev_dir); |
|
4394 |
(void) strcat(devlink, "/"); |
|
4395 |
(void) strcat(devlink, link); |
|
4396 |
||
2621 | 4397 |
if (!device_exists(devlink) || lstat(devlink, &sb) != 0) { |
0 | 4398 |
return (DEVFSADM_FALSE); |
4399 |
} |
|
4400 |
||
4401 |
contents = NULL; |
|
4402 |
type = 0; |
|
4403 |
if (resolve_link(devlink, &contents, &type, NULL, 1) == TRUE) { |
|
4404 |
rv = DEVFSADM_FALSE; |
|
4405 |
} else { |
|
4406 |
rv = DEVFSADM_TRUE; |
|
4407 |
} |
|
4408 |
||
4409 |
/* |
|
4410 |
* The link exists. Add it to the database |
|
4411 |
*/ |
|
4412 |
(void) di_devlink_add_link(devlink_cache, link, contents, type); |
|
1676 | 4413 |
if (system_labeled && (rv == DEVFSADM_TRUE) && |
4414 |
strstr(devlink, DA_AUDIO_NAME) && contents) { |
|
4415 |
(void) sscanf(contents, "%*[a-z]%d", &instance); |
|
4416 |
(void) da_add_list(&devlist, devlink, instance, |
|
4417 |
DA_ADD|DA_AUDIO); |
|
4418 |
_update_devalloc_db(&devlist, 0, DA_ADD, NULL, root_dir); |
|
4419 |
} |
|
0 | 4420 |
free(contents); |
4421 |
||
4422 |
return (rv); |
|
4423 |
} |
|
4424 |
||
4425 |
/* |
|
4426 |
* devpath: Absolute path to /dev link |
|
4427 |
* content_p: Returns malloced string (link content) |
|
4428 |
* type_p: Returns link type: primary or secondary |
|
4429 |
* devfs_path: Returns malloced string: /devices path w/out "/devices" |
|
4430 |
* dangle: if set, check if link is dangling |
|
4431 |
* Returns: |
|
4432 |
* TRUE if dangling |
|
4433 |
* FALSE if not or if caller doesn't care |
|
4434 |
* Caller is assumed to have initialized pointer contents to NULL |
|
4435 |
*/ |
|
4436 |
static int |
|
4437 |
resolve_link(char *devpath, char **content_p, int *type_p, char **devfs_path, |
|
4438 |
int dangle) |
|
4439 |
{ |
|
4440 |
char contents[PATH_MAX + 1]; |
|
4441 |
char stage_link[PATH_MAX + 1]; |
|
4442 |
char *fcn = "resolve_link: "; |
|
4443 |
char *ptr; |
|
4444 |
int linksize; |
|
4445 |
int rv = TRUE; |
|
4446 |
struct stat sb; |
|
4447 |
||
4448 |
linksize = readlink(devpath, contents, PATH_MAX); |
|
4449 |
||
4450 |
if (linksize <= 0) { |
|
4451 |
return (FALSE); |
|
4452 |
} else { |
|
4453 |
contents[linksize] = '\0'; |
|
4454 |
} |
|
4455 |
vprint(REMOVE_MID, "%s %s -> %s\n", fcn, devpath, contents); |
|
4456 |
||
4457 |
if (content_p) { |
|
4458 |
*content_p = s_strdup(contents); |
|
4459 |
} |
|
4460 |
||
4461 |
/* |
|
4462 |
* Check to see if this is a link pointing to another link in /dev. The |
|
4463 |
* cheap way to do this is to look for a lack of ../devices/. |
|
4464 |
*/ |
|
4465 |
||
4466 |
if (is_minor_node(contents, &ptr) == DEVFSADM_FALSE) { |
|
4467 |
||
4468 |
if (type_p) { |
|
4469 |
*type_p = DI_SECONDARY_LINK; |
|
4470 |
} |
|
4471 |
||
4472 |
/* |
|
4473 |
* assume that linkcontents is really a pointer to another |
|
4474 |
* link, and if so recurse and read its link contents. |
|
4475 |
*/ |
|
4476 |
if (strncmp(contents, DEV "/", strlen(DEV) + 1) == 0) { |
|
4477 |
(void) strcpy(stage_link, dev_dir); |
|
4478 |
(void) strcat(stage_link, "/"); |
|
4479 |
(void) strcpy(stage_link, |
|
4480 |
&contents[strlen(DEV) + strlen("/")]); |
|
4481 |
} else { |
|
4482 |
if ((ptr = strrchr(devpath, '/')) == NULL) { |
|
4483 |
vprint(REMOVE_MID, "%s%s -> %s invalid link. " |
|
4484 |
"missing '/'\n", fcn, devpath, |
|
4485 |
contents); |
|
4486 |
return (TRUE); |
|
4487 |
} |
|
4488 |
*ptr = '\0'; |
|
4489 |
(void) strcpy(stage_link, devpath); |
|
4490 |
*ptr = '/'; |
|
4491 |
(void) strcat(stage_link, "/"); |
|
4492 |
(void) strcat(stage_link, contents); |
|
4493 |
} |
|
4494 |
return (resolve_link(stage_link, NULL, NULL, devfs_path, |
|
4495 |
dangle)); |
|
4496 |
} |
|
4497 |
||
4498 |
/* Current link points at a /devices minor node */ |
|
4499 |
if (type_p) { |
|
4500 |
*type_p = DI_PRIMARY_LINK; |
|
4501 |
} |
|
4502 |
||
4503 |
if (devfs_path) |
|
4504 |
*devfs_path = s_strdup(ptr); |
|
4505 |
||
4506 |
rv = FALSE; |
|
4507 |
if (dangle) |
|
4508 |
rv = (stat(ptr - strlen(DEVICES), &sb) == -1); |
|
4509 |
||
4510 |
vprint(REMOVE_MID, "%slink=%s, returning %s\n", fcn, |
|
4511 |
devpath, ((rv == TRUE) ? "TRUE" : "FALSE")); |
|
4512 |
||
4513 |
return (rv); |
|
4514 |
} |
|
4515 |
||
4516 |
/* |
|
4517 |
* Returns the substring of interest, given a path. |
|
4518 |
*/ |
|
4519 |
static char * |
|
4520 |
alloc_cmp_str(const char *path, devfsadm_enumerate_t *dep) |
|
4521 |
{ |
|
4522 |
uint_t match; |
|
4523 |
char *np, *ap, *mp; |
|
4524 |
char *cmp_str = NULL; |
|
4525 |
char at[] = "@"; |
|
4526 |
char *fcn = "alloc_cmp_str"; |
|
4527 |
||
4528 |
np = ap = mp = NULL; |
|
4529 |
||
4530 |
/* |
|
4531 |
* extract match flags from the flags argument. |
|
4532 |
*/ |
|
4533 |
match = (dep->flags & MATCH_MASK); |
|
4534 |
||
4535 |
vprint(ENUM_MID, "%s: enumeration match type: 0x%x" |
|
4536 |
" path: %s\n", fcn, match, path); |
|
4537 |
||
4538 |
/* |
|
4539 |
* MATCH_CALLBACK and MATCH_ALL are the only flags |
|
4540 |
* which may be used if "path" is a /dev path |
|
4541 |
*/ |
|
4542 |
if (match == MATCH_CALLBACK) { |
|
4543 |
if (dep->sel_fcn == NULL) { |
|
4544 |
vprint(ENUM_MID, "%s: invalid enumerate" |
|
4545 |
" callback: path: %s\n", fcn, path); |
|
4546 |
return (NULL); |
|
4547 |
} |
|
4548 |
cmp_str = dep->sel_fcn(path, dep->cb_arg); |
|
4549 |
return (cmp_str); |
|
4550 |
} |
|
4551 |
||
4552 |
cmp_str = s_strdup(path); |
|
4553 |
||
4554 |
if (match == MATCH_ALL) { |
|
4555 |
return (cmp_str); |
|
4556 |
} |
|
4557 |
||
4558 |
/* |
|
4559 |
* The remaining flags make sense only for /devices |
|
4560 |
* paths |
|
4561 |
*/ |
|
4562 |
if ((mp = strrchr(cmp_str, ':')) == NULL) { |
|
4563 |
vprint(ENUM_MID, "%s: invalid path: %s\n", |
|
4564 |
fcn, path); |
|
4565 |
goto err; |
|
4566 |
} |
|
4567 |
||
4568 |
if (match == MATCH_MINOR) { |
|
4569 |
/* A NULL "match_arg" values implies entire minor */ |
|
4570 |
if (get_component(mp + 1, dep->match_arg) == NULL) { |
|
4571 |
vprint(ENUM_MID, "%s: invalid minor component:" |
|
4572 |
" path: %s\n", fcn, path); |
|
4573 |
goto err; |
|
4574 |
} |
|
4575 |
return (cmp_str); |
|
4576 |
} |
|
4577 |
||
4578 |
if ((np = strrchr(cmp_str, '/')) == NULL) { |
|
4579 |
vprint(ENUM_MID, "%s: invalid path: %s\n", fcn, path); |
|
4580 |
goto err; |
|
4581 |
} |
|
4582 |
||
4583 |
if (match == MATCH_PARENT) { |
|
4584 |
if (strcmp(cmp_str, "/") == 0) { |
|
4585 |
vprint(ENUM_MID, "%s: invalid path: %s\n", |
|
4586 |
fcn, path); |
|
4587 |
goto err; |
|
4588 |
} |
|
4589 |
||
4590 |
if (np == cmp_str) { |
|
4591 |
*(np + 1) = '\0'; |
|
4592 |
} else { |
|
4593 |
*np = '\0'; |
|
4594 |
} |
|
4595 |
return (cmp_str); |
|
4596 |
} |
|
4597 |
||
4598 |
/* ap can be NULL - Leaf address may not exist or be empty string */ |
|
4599 |
ap = strchr(np+1, '@'); |
|
4600 |
||
4601 |
/* minor is no longer of interest */ |
|
4602 |
*mp = '\0'; |
|
4603 |
||
4604 |
if (match == MATCH_NODE) { |
|
4605 |
if (ap) |
|
4606 |
*ap = '\0'; |
|
4607 |
return (cmp_str); |
|
4608 |
} else if (match == MATCH_ADDR) { |
|
4609 |
/* |
|
4610 |
* The empty string is a valid address. The only MATCH_ADDR |
|
4611 |
* allowed in this case is against the whole address or |
|
4612 |
* the first component of the address (match_arg=NULL/"0"/"1") |
|
4613 |
* Note that in this case, the path won't have an "@" |
|
4614 |
* As a result ap will be NULL. We fake up an ap = @'\0' |
|
4615 |
* so that get_component() will work correctly. |
|
4616 |
*/ |
|
4617 |
if (ap == NULL) { |
|
4618 |
ap = at; |
|
4619 |
} |
|
4620 |
||
4621 |
if (get_component(ap + 1, dep->match_arg) == NULL) { |
|
4622 |
vprint(ENUM_MID, "%s: invalid leaf addr. component:" |
|
4623 |
" path: %s\n", fcn, path); |
|
4624 |
goto err; |
|
4625 |
} |
|
4626 |
return (cmp_str); |
|
4627 |
} |
|
4628 |
||
4629 |
vprint(ENUM_MID, "%s: invalid enumeration flags: 0x%x" |
|
4630 |
" path: %s\n", fcn, dep->flags, path); |
|
4631 |
||
4632 |
/*FALLTHRU*/ |
|
4633 |
err: |
|
4634 |
free(cmp_str); |
|
4635 |
return (NULL); |
|
4636 |
} |
|
4637 |
||
4638 |
||
4639 |
/* |
|
4640 |
* "str" is expected to be a string with components separated by ',' |
|
4641 |
* The terminating null char is considered a separator. |
|
4642 |
* get_component() will remove the portion of the string beyond |
|
4643 |
* the component indicated. |
|
4644 |
* If comp_str is NULL, the entire "str" is returned. |
|
4645 |
*/ |
|
4646 |
static char * |
|
4647 |
get_component(char *str, const char *comp_str) |
|
4648 |
{ |
|
4649 |
long comp; |
|
4650 |
char *cp; |
|
4651 |
||
4652 |
if (str == NULL) { |
|
4653 |
return (NULL); |
|
4654 |
} |
|
4655 |
||
4656 |
if (comp_str == NULL) { |
|
4657 |
return (str); |
|
4658 |
} |
|
4659 |
||
4660 |
errno = 0; |
|
4661 |
comp = strtol(comp_str, &cp, 10); |
|
4662 |
if (errno != 0 || *cp != '\0' || comp < 0) { |
|
4663 |
return (NULL); |
|
4664 |
} |
|
4665 |
||
4666 |
if (comp == 0) |
|
4667 |
return (str); |
|
4668 |
||
4669 |
for (cp = str; ; cp++) { |
|
4670 |
if (*cp == ',' || *cp == '\0') |
|
4671 |
comp--; |
|
4672 |
if (*cp == '\0' || comp <= 0) { |
|
4673 |
break; |
|
4674 |
} |
|
4675 |
} |
|
4676 |
||
4677 |
if (comp == 0) { |
|
4678 |
*cp = '\0'; |
|
4679 |
} else { |
|
4680 |
str = NULL; |
|
4681 |
} |
|
4682 |
||
4683 |
return (str); |
|
4684 |
} |
|
4685 |
||
4686 |
||
4687 |
/* |
|
4688 |
* Enumerate serves as a generic counter as well as a means to determine |
|
4689 |
* logical unit/controller numbers for such items as disk and tape |
|
4690 |
* drives. |
|
4691 |
* |
|
4692 |
* rules[] is an array of devfsadm_enumerate_t structures which defines |
|
4693 |
* the enumeration rules to be used for a specified set of links in /dev. |
|
4694 |
* The set of links is specified through regular expressions (of the flavor |
|
4695 |
* described in regex(5)). These regular expressions are used to determine |
|
4696 |
* the set of links in /dev to examine. The last path component in these |
|
4697 |
* regular expressions MUST contain a parenthesized subexpression surrounding |
|
4698 |
* the RE which is to be considered the enumerating component. The subexp |
|
4699 |
* member in a rule is the subexpression number of the enumerating |
|
4700 |
* component. Subexpressions in the last path component are numbered starting |
|
4701 |
* from 1. |
|
4702 |
* |
|
4703 |
* A cache of current id assignments is built up from existing symlinks and |
|
4704 |
* new assignments use the lowest unused id. Assignments are based on a |
|
4705 |
* match of a specified substring of a symlink's contents. If the specified |
|
4706 |
* component for the devfs_path argument matches the corresponding substring |
|
4707 |
* for a existing symlink's contents, the cached id is returned. Else, a new |
|
4708 |
* id is created and returned in *buf. *buf must be freed by the caller. |
|
4709 |
* |
|
4710 |
* An id assignment may be governed by a combination of rules, each rule |
|
4711 |
* applicable to a different subset of links in /dev. For example, controller |
|
4712 |
* numbers may be determined by a combination of disk symlinks in /dev/[r]dsk |
|
4713 |
* and controller symlinks in /dev/cfg, with the two sets requiring different |
|
4714 |
* rules to derive the "substring of interest". In such cases, the rules |
|
4715 |
* array will have more than one element. |
|
4716 |
*/ |
|
4717 |
int |
|
4718 |
devfsadm_enumerate_int(char *devfs_path, int index, char **buf, |
|
4719 |
devfsadm_enumerate_t rules[], int nrules) |
|
4720 |
{ |
|
4721 |
return (find_enum_id(rules, nrules, |
|
4722 |
devfs_path, index, "0", INTEGER, buf, 0)); |
|
4723 |
} |
|
4724 |
||
4725 |
int |
|
4726 |
disk_enumerate_int(char *devfs_path, int index, char **buf, |
|
4727 |
devfsadm_enumerate_t rules[], int nrules) |
|
4728 |
{ |
|
4729 |
return (find_enum_id(rules, nrules, |
|
4730 |
devfs_path, index, "0", INTEGER, buf, 1)); |
|
4731 |
} |
|
4732 |
||
4733 |
/* |
|
4734 |
* Same as above, but allows a starting value to be specified. |
|
4735 |
* Private to devfsadm.... used by devlinks. |
|
4736 |
*/ |
|
4737 |
static int |
|
4738 |
devfsadm_enumerate_int_start(char *devfs_path, int index, char **buf, |
|
4739 |
devfsadm_enumerate_t rules[], int nrules, char *start) |
|
4740 |
{ |
|
4741 |
return (find_enum_id(rules, nrules, |
|
4742 |
devfs_path, index, start, INTEGER, buf, 0)); |
|
4743 |
} |
|
4744 |
||
4745 |
/* |
|
4746 |
* devfsadm_enumerate_char serves as a generic counter returning |
|
4747 |
* a single letter. |
|
4748 |
*/ |
|
4749 |
int |
|
4750 |
devfsadm_enumerate_char(char *devfs_path, int index, char **buf, |
|
4751 |
devfsadm_enumerate_t rules[], int nrules) |
|
4752 |
{ |
|
4753 |
return (find_enum_id(rules, nrules, |
|
4754 |
devfs_path, index, "a", LETTER, buf, 0)); |
|
4755 |
} |
|
4756 |
||
4757 |
/* |
|
4758 |
* Same as above, but allows a starting char to be specified. |
|
4759 |
* Private to devfsadm - used by ports module (port_link.c) |
|
4760 |
*/ |
|
4761 |
int |
|
4762 |
devfsadm_enumerate_char_start(char *devfs_path, int index, char **buf, |
|
4763 |
devfsadm_enumerate_t rules[], int nrules, char *start) |
|
4764 |
{ |
|
4765 |
return (find_enum_id(rules, nrules, |
|
4766 |
devfs_path, index, start, LETTER, buf, 0)); |
|
4767 |
} |
|
4768 |
||
4769 |
||
4770 |
/* |
|
4771 |
* For a given numeral_set (see get_cached_set for desc of numeral_set), |
|
4772 |
* search all cached entries looking for matches on a specified substring |
|
4773 |
* of devfs_path. The substring is derived from devfs_path based on the |
|
4774 |
* rule specified by "index". If a match is found on a cached entry, |
|
4775 |
* return the enumerated id in buf. Otherwise, create a new id by calling |
|
4776 |
* new_id, then cache and return that entry. |
|
4777 |
*/ |
|
4778 |
static int |
|
4779 |
find_enum_id(devfsadm_enumerate_t rules[], int nrules, |
|
4780 |
char *devfs_path, int index, char *min, int type, char **buf, |
|
4781 |
int multiple) |
|
4782 |
{ |
|
4783 |
numeral_t *matchnp; |
|
4784 |
numeral_t *numeral; |
|
4785 |
int matchcount = 0; |
|
4786 |
char *cmp_str; |
|
4787 |
char *fcn = "find_enum_id"; |
|
4788 |
numeral_set_t *set; |
|
4789 |
||
4790 |
if (rules == NULL) { |
|
4791 |
vprint(ENUM_MID, "%s: no rules. path: %s\n", |
|
4792 |
fcn, devfs_path ? devfs_path : "<NULL path>"); |
|
4793 |
return (DEVFSADM_FAILURE); |
|
4794 |
} |
|
4795 |
||
4796 |
if (devfs_path == NULL) { |
|
4797 |
vprint(ENUM_MID, "%s: NULL path\n", fcn); |
|
4798 |
return (DEVFSADM_FAILURE); |
|
4799 |
} |
|
4800 |
||
4801 |
if (nrules <= 0 || index < 0 || index >= nrules || buf == NULL) { |
|
4802 |
vprint(ENUM_MID, "%s: invalid arguments. path: %s\n", |
|
4803 |
fcn, devfs_path); |
|
4804 |
return (DEVFSADM_FAILURE); |
|
4805 |
} |
|
4806 |
||
4807 |
*buf = NULL; |
|
4808 |
||
4809 |
||
4810 |
cmp_str = alloc_cmp_str(devfs_path, &rules[index]); |
|
4811 |
if (cmp_str == NULL) { |
|
4812 |
return (DEVFSADM_FAILURE); |
|
4813 |
} |
|
4814 |
||
4815 |
if ((set = get_enum_cache(rules, nrules)) == NULL) { |
|
4816 |
free(cmp_str); |
|
4817 |
return (DEVFSADM_FAILURE); |
|
4818 |
} |
|
4819 |
||
4820 |
assert(nrules == set->re_count); |
|
4821 |
||
4822 |
/* |
|
4823 |
* Check and see if a matching entry is already cached. |
|
4824 |
*/ |
|
4825 |
matchcount = lookup_enum_cache(set, cmp_str, rules, index, |
|
4826 |
&matchnp); |
|
4827 |
||
4828 |
if (matchcount < 0 || matchcount > 1) { |
|
4829 |
free(cmp_str); |
|
4830 |
if (multiple && matchcount > 1) |
|
4831 |
return (DEVFSADM_MULTIPLE); |
|
4832 |
else |
|
4833 |
return (DEVFSADM_FAILURE); |
|
4834 |
} |
|
4835 |
||
4836 |
/* if matching entry already cached, return it */ |
|
4837 |
if (matchcount == 1) { |
|
4876 | 4838 |
/* should never create a link with a reserved ID */ |
4839 |
vprint(ENUM_MID, "%s: 1 match w/ ID: %s\n", fcn, matchnp->id); |
|
4840 |
assert(matchnp->flags == 0); |
|
0 | 4841 |
*buf = s_strdup(matchnp->id); |
4842 |
free(cmp_str); |
|
4843 |
return (DEVFSADM_SUCCESS); |
|
4844 |
} |
|
4845 |
||
4846 |
/* |
|
4847 |
* no cached entry, initialize a numeral struct |
|
4848 |
* by calling new_id() and cache onto the numeral_set |
|
4849 |
*/ |
|
4850 |
numeral = s_malloc(sizeof (numeral_t)); |
|
4851 |
numeral->id = new_id(set->headnumeral, type, min); |
|
4852 |
numeral->full_path = s_strdup(devfs_path); |
|
4853 |
numeral->rule_index = index; |
|
4854 |
numeral->cmp_str = cmp_str; |
|
4855 |
cmp_str = NULL; |
|
4876 | 4856 |
numeral->flags = 0; |
4857 |
vprint(RSRV_MID, "%s: alloc new_id: %s numeral flags = %d\n", |
|
4858 |
fcn, numeral->id, numeral->flags); |
|
4859 |
||
0 | 4860 |
|
4861 |
/* insert to head of list for fast lookups */ |
|
4862 |
numeral->next = set->headnumeral; |
|
4863 |
set->headnumeral = numeral; |
|
4864 |
||
4865 |
*buf = s_strdup(numeral->id); |
|
4866 |
return (DEVFSADM_SUCCESS); |
|
4867 |
} |
|
4868 |
||
4869 |
||
4870 |
/* |
|
4871 |
* Looks up the specified cache for a match with a specified string |
|
4872 |
* Returns: |
|
4873 |
* -1 : on error. |
|
4874 |
* 0/1/2 : Number of matches. |
|
4875 |
* Returns the matching element only if there is a single match. |
|
4876 |
* If the "uncached" flag is set, derives the "cmp_str" afresh |
|
4877 |
* for the match instead of using cached values. |
|
4878 |
*/ |
|
4879 |
static int |
|
4880 |
lookup_enum_cache(numeral_set_t *set, char *cmp_str, |
|
4881 |
devfsadm_enumerate_t rules[], int index, numeral_t **matchnpp) |
|
4882 |
{ |
|
4883 |
int matchcount = 0, rv = -1; |
|
4884 |
int uncached; |
|
4885 |
numeral_t *np; |
|
4886 |
char *fcn = "lookup_enum_cache"; |
|
4887 |
char *cp; |
|
4888 |
||
4889 |
*matchnpp = NULL; |
|
4890 |
||
4891 |
assert(index < set->re_count); |
|
4892 |
||
4893 |
if (cmp_str == NULL) { |
|
4894 |
return (-1); |
|
4895 |
} |
|
4896 |
||
4897 |
uncached = 0; |
|
4898 |
if ((rules[index].flags & MATCH_UNCACHED) == MATCH_UNCACHED) { |
|
4899 |
uncached = 1; |
|
4900 |
} |
|
4901 |
||
4902 |
/* |
|
4903 |
* Check and see if a matching entry is already cached. |
|
4904 |
*/ |
|
4905 |
for (np = set->headnumeral; np != NULL; np = np->next) { |
|
4876 | 4906 |
|
4907 |
/* |
|
4908 |
* Skip reserved IDs |
|
4909 |
*/ |
|
4910 |
if (np->flags & NUMERAL_RESERVED) { |
|
4911 |
vprint(RSRV_MID, "lookup_enum_cache: " |
|
4912 |
"Cannot Match with reserved ID (%s), " |
|
4913 |
"skipping\n", np->id); |
|
4914 |
assert(np->flags == NUMERAL_RESERVED); |
|
4915 |
continue; |
|
4916 |
} else { |
|
4917 |
vprint(RSRV_MID, "lookup_enum_cache: " |
|
4918 |
"Attempting match with numeral ID: %s" |
|
4919 |
" numeral flags = %d\n", np->id, np->flags); |
|
4920 |
assert(np->flags == 0); |
|
4921 |
} |
|
4922 |
||
0 | 4923 |
if (np->cmp_str == NULL) { |
4924 |
vprint(ENUM_MID, "%s: invalid entry in enumerate" |
|
4925 |
" cache. path: %s\n", fcn, np->full_path); |
|
4926 |
return (-1); |
|
4927 |
} |
|
4928 |
||
4929 |
if (uncached) { |
|
4930 |
vprint(CHATTY_MID, "%s: bypassing enumerate cache." |
|
4931 |
" path: %s\n", fcn, cmp_str); |
|
4932 |
cp = alloc_cmp_str(np->full_path, |
|
4933 |
&rules[np->rule_index]); |
|
4934 |
if (cp == NULL) |
|
4935 |
return (-1); |
|
4936 |
rv = strcmp(cmp_str, cp); |
|
4937 |
free(cp); |
|
4938 |
} else { |
|
4939 |
rv = strcmp(cmp_str, np->cmp_str); |
|
4940 |
} |
|
4941 |
||
4942 |
if (rv == 0) { |
|
4943 |
if (matchcount++ != 0) { |
|
4944 |
break; /* more than 1 match. */ |
|
4945 |
} |
|
4946 |
*matchnpp = np; |
|
4947 |
} |
|
4948 |
} |
|
4949 |
||
4950 |
return (matchcount); |
|
4951 |
} |
|
4952 |
||
4953 |
#ifdef DEBUG |
|
4954 |
static void |
|
4955 |
dump_enum_cache(numeral_set_t *setp) |
|
4956 |
{ |
|
4957 |
int i; |
|
4958 |
numeral_t *np; |
|
4959 |
char *fcn = "dump_enum_cache"; |
|
4960 |
||
4961 |
vprint(ENUM_MID, "%s: re_count = %d\n", fcn, setp->re_count); |
|
4962 |
for (i = 0; i < setp->re_count; i++) { |
|
4963 |
vprint(ENUM_MID, "%s: re[%d] = %s\n", fcn, i, setp->re[i]); |
|
4964 |
} |
|
4965 |
||
4966 |
for (np = setp->headnumeral; np != NULL; np = np->next) { |
|
4967 |
vprint(ENUM_MID, "%s: id: %s\n", fcn, np->id); |
|
4968 |
vprint(ENUM_MID, "%s: full_path: %s\n", fcn, np->full_path); |
|
4969 |
vprint(ENUM_MID, "%s: rule_index: %d\n", fcn, np->rule_index); |
|
4970 |
vprint(ENUM_MID, "%s: cmp_str: %s\n", fcn, np->cmp_str); |
|
4876 | 4971 |
vprint(ENUM_MID, "%s: flags: %d\n", fcn, np->flags); |
0 | 4972 |
} |
4973 |
} |
|
4974 |
#endif |
|
4975 |
||
4976 |
/* |
|
4977 |
* For a given set of regular expressions in rules[], this function returns |
|
4978 |
* either a previously cached struct numeral_set or it will create and |
|
4979 |
* cache a new struct numeral_set. There is only one struct numeral_set |
|
4980 |
* for the combination of REs present in rules[]. Each numeral_set contains |
|
4981 |
* the regular expressions in rules[] used for cache selection AND a linked |
|
4982 |
* list of struct numerals, ONE FOR EACH *UNIQUE* numeral or character ID |
|
4983 |
* selected by the grouping parenthesized subexpression found in the last |
|
4984 |
* path component of each rules[].re. For example, the RE: "rmt/([0-9]+)" |
|
4985 |
* selects all the logical nodes of the correct form in dev/rmt/. |
|
4986 |
* Each rmt/X will store a *single* struct numeral... ie 0, 1, 2 each get a |
|
4987 |
* single struct numeral. There is no need to store more than a single logical |
|
4988 |
* node matching X since the information desired in the devfspath would be |
|
4989 |
* identical for the portion of the devfspath of interest. (the part up to, |
|
4990 |
* but not including the minor name in this example.) |
|
4991 |
* |
|
4992 |
* If the given numeral_set is not yet cached, call enumerate_recurse to |
|
4993 |
* create it. |
|
4994 |
*/ |
|
4995 |
static numeral_set_t * |
|
4996 |
get_enum_cache(devfsadm_enumerate_t rules[], int nrules) |
|
4997 |
{ |
|
4998 |
/* linked list of numeral sets */ |
|
4999 |
numeral_set_t *setp; |
|
5000 |
int i; |
|
4876 | 5001 |
int ret; |
0 | 5002 |
char *path_left; |
4876 | 5003 |
enumerate_file_t *entry; |
0 | 5004 |
char *fcn = "get_enum_cache"; |
5005 |
||
5006 |
/* |
|
5007 |
* See if we've already cached this numeral set. |
|
5008 |
*/ |
|
5009 |
for (setp = head_numeral_set; setp != NULL; setp = setp->next) { |
|
5010 |
/* |
|
5011 |
* check all regexp's passed in function against |
|
5012 |
* those in cached set. |
|
5013 |
*/ |
|
5014 |
if (nrules != setp->re_count) { |
|
5015 |
continue; |
|
5016 |
} |
|
5017 |
||
5018 |
for (i = 0; i < nrules; i++) { |
|
5019 |
if (strcmp(setp->re[i], rules[i].re) != 0) { |
|
5020 |
break; |
|
5021 |
} |
|
5022 |
} |
|
5023 |
||
5024 |
if (i == nrules) { |
|
5025 |
return (setp); |
|
5026 |
} |
|
5027 |
} |
|
5028 |
||
5029 |
/* |
|
5030 |
* If the MATCH_UNCACHED flag is set, we should not be here. |
|
5031 |
*/ |
|
5032 |
for (i = 0; i < nrules; i++) { |
|
5033 |
if ((rules[i].flags & MATCH_UNCACHED) == MATCH_UNCACHED) { |
|
5034 |
vprint(ENUM_MID, "%s: invalid enumeration flags: " |
|
5035 |
"0x%x\n", fcn, rules[i].flags); |
|
5036 |
return (NULL); |
|
5037 |
} |
|
5038 |
} |
|
5039 |
||
5040 |
/* |
|
5041 |
* Since we made it here, we have not yet cached the given set of |
|
5042 |
* logical nodes matching the passed re. Create a cached entry |
|
5043 |
* struct numeral_set and populate it with a minimal set of |
|
5044 |
* logical nodes from /dev. |
|
5045 |
*/ |
|
5046 |
||
5047 |
setp = s_malloc(sizeof (numeral_set_t)); |
|
5048 |
setp->re = s_malloc(sizeof (char *) * nrules); |
|
5049 |
for (i = 0; i < nrules; i++) { |
|
5050 |
setp->re[i] = s_strdup(rules[i].re); |
|
5051 |
} |
|
5052 |
setp->re_count = nrules; |
|
5053 |
setp->headnumeral = NULL; |
|
5054 |
||
5055 |
/* put this new cached set on the cached set list */ |
|
5056 |
setp->next = head_numeral_set; |
|
5057 |
head_numeral_set = setp; |
|
5058 |
||
5059 |
/* |
|
4876 | 5060 |
* For each RE, search the "reserved" list to create numeral IDs that |
5061 |
* are reserved. |
|
5062 |
*/ |
|
5063 |
for (entry = enumerate_reserved; entry; entry = entry->er_next) { |
|
5064 |
||
5065 |
vprint(RSRV_MID, "parsing rstring: %s\n", entry->er_file); |
|
5066 |
||
5067 |
for (i = 0; i < nrules; i++) { |
|
5068 |
path_left = s_strdup(setp->re[i]); |
|
5069 |
vprint(RSRV_MID, "parsing rule RE: %s\n", path_left); |
|
5070 |
ret = enumerate_parse(entry->er_file, path_left, |
|
5071 |
setp, rules, i); |
|
5072 |
free(path_left); |
|
5073 |
if (ret == 1) { |
|
5074 |
/* |
|
5075 |
* We found the reserved ID for this entry. |
|
5076 |
* We still keep the entry since it is needed |
|
5077 |
* by the new link bypass code in disks |
|
5078 |
*/ |
|
5079 |
vprint(RSRV_MID, "found rsv ID: rstring: %s " |
|
5080 |
"rule RE: %s\n", entry->er_file, path_left); |
|
5081 |
break; |
|
5082 |
} |
|
5083 |
} |
|
5084 |
} |
|
5085 |
||
5086 |
/* |
|
0 | 5087 |
* For each RE, search disk and cache any matches on the |
2621 | 5088 |
* numeral list. |
0 | 5089 |
*/ |
5090 |
for (i = 0; i < nrules; i++) { |
|
5091 |
path_left = s_strdup(setp->re[i]); |
|
2621 | 5092 |
enumerate_recurse(dev_dir, path_left, setp, rules, i); |
0 | 5093 |
free(path_left); |
5094 |
} |
|
5095 |
||
5096 |
#ifdef DEBUG |
|
5097 |
dump_enum_cache(setp); |
|
5098 |
#endif |
|
5099 |
||
5100 |
return (setp); |
|
5101 |
} |
|
5102 |
||
5103 |
||
5104 |
/* |
|
5105 |
* This function stats the pathname namebuf. If this is a directory |
|
5106 |
* entry, we recurse down dname/fname until we find the first symbolic |
|
5107 |
* link, and then stat and return it. This is valid for the same reason |
|
5108 |
* that we only need to read a single pathname for multiple matching |
|
5109 |
* logical ID's... ie, all the logical nodes should contain identical |
|
5110 |
* physical paths for the parts we are interested. |
|
5111 |
*/ |
|
5112 |
int |
|
5113 |
get_stat_info(char *namebuf, struct stat *sb) |
|
5114 |
{ |
|
5115 |
char *cp; |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5116 |
finddevhdl_t fhandle; |
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5117 |
const char *fp; |
0 | 5118 |
|
5119 |
if (lstat(namebuf, sb) < 0) { |
|
5120 |
(void) err_print(LSTAT_FAILED, namebuf, strerror(errno)); |
|
5121 |
return (DEVFSADM_FAILURE); |
|
5122 |
} |
|
5123 |
||
5124 |
if ((sb->st_mode & S_IFMT) == S_IFLNK) { |
|
5125 |
return (DEVFSADM_SUCCESS); |
|
5126 |
} |
|
5127 |
||
5128 |
/* |
|
5129 |
* If it is a dir, recurse down until we find a link and |
|
5130 |
* then use the link. |
|
5131 |
*/ |
|
5132 |
if ((sb->st_mode & S_IFMT) == S_IFDIR) { |
|
5133 |
||
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5134 |
if (finddev_readdir(namebuf, &fhandle) != 0) { |
0 | 5135 |
return (DEVFSADM_FAILURE); |
5136 |
} |
|
5137 |
||
5138 |
/* |
|
5139 |
* Search each dir entry looking for a symlink. Return |
|
5140 |
* the first symlink found in namebuf. Recurse dirs. |
|
5141 |
*/ |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5142 |
while ((fp = finddev_next(fhandle)) != NULL) { |
2621 | 5143 |
cp = namebuf + strlen(namebuf); |
5144 |
if ((strlcat(namebuf, "/", PATH_MAX) >= PATH_MAX) || |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5145 |
(strlcat(namebuf, fp, PATH_MAX) >= PATH_MAX)) { |
2621 | 5146 |
*cp = '\0'; |
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5147 |
finddev_close(fhandle); |
2621 | 5148 |
return (DEVFSADM_FAILURE); |
0 | 5149 |
} |
5150 |
if (get_stat_info(namebuf, sb) == DEVFSADM_SUCCESS) { |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5151 |
finddev_close(fhandle); |
0 | 5152 |
return (DEVFSADM_SUCCESS); |
5153 |
} |
|
5154 |
*cp = '\0'; |
|
5155 |
} |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5156 |
finddev_close(fhandle); |
0 | 5157 |
} |
5158 |
||
5159 |
/* no symlink found, so return error */ |
|
5160 |
return (DEVFSADM_FAILURE); |
|
5161 |
} |
|
5162 |
||
5163 |
/* |
|
5164 |
* An existing matching ID was not found, so this function is called to |
|
5165 |
* create the next lowest ID. In the INTEGER case, return the next |
|
5166 |
* lowest unused integer. In the case of LETTER, return the next lowest |
|
5167 |
* unused letter. Return empty string if all 26 are used. |
|
5168 |
* Only IDs >= min will be returned. |
|
5169 |
*/ |
|
5170 |
char * |
|
5171 |
new_id(numeral_t *numeral, int type, char *min) |
|
5172 |
{ |
|
5173 |
int imin; |
|
5174 |
temp_t *temp; |
|
5175 |
temp_t *ptr; |
|
5176 |
temp_t **previous; |
|
5177 |
temp_t *head = NULL; |
|
5178 |
char *retval; |
|
5179 |
static char tempbuff[8]; |
|
5180 |
numeral_t *np; |
|
5181 |
||
5182 |
if (type == LETTER) { |
|
5183 |
||
5184 |
char letter[26], i; |
|
5185 |
||
5186 |
if (numeral == NULL) { |
|
5187 |
return (s_strdup(min)); |
|
5188 |
} |
|
5189 |
||
5190 |
for (i = 0; i < 26; i++) { |
|
5191 |
letter[i] = 0; |
|
5192 |
} |
|
5193 |
||
5194 |
for (np = numeral; np != NULL; np = np->next) { |
|
4876 | 5195 |
assert(np->flags == 0 || |
5196 |
np->flags == NUMERAL_RESERVED); |
|
0 | 5197 |
letter[*np->id - 'a']++; |
5198 |
} |
|
5199 |
||
5200 |
imin = *min - 'a'; |
|
5201 |
||
5202 |
for (i = imin; i < 26; i++) { |
|
5203 |
if (letter[i] == 0) { |
|
5204 |
retval = s_malloc(2); |
|
5205 |
retval[0] = 'a' + i; |
|
5206 |
retval[1] = '\0'; |
|
5207 |
return (retval); |
|
5208 |
} |
|
5209 |
} |
|
5210 |
||
5211 |
return (s_strdup("")); |
|
5212 |
} |
|
5213 |
||
5214 |
if (type == INTEGER) { |
|
5215 |
||
5216 |
if (numeral == NULL) { |
|
5217 |
return (s_strdup(min)); |
|
5218 |
} |
|
5219 |
||
5220 |
imin = atoi(min); |
|
5221 |
||
5222 |
/* sort list */ |
|
5223 |
for (np = numeral; np != NULL; np = np->next) { |
|
4876 | 5224 |
assert(np->flags == 0 || |
5225 |
np->flags == NUMERAL_RESERVED); |
|
0 | 5226 |
temp = s_malloc(sizeof (temp_t)); |
5227 |
temp->integer = atoi(np->id); |
|
5228 |
temp->next = NULL; |
|
5229 |
||
5230 |
previous = &head; |
|
5231 |
for (ptr = head; ptr != NULL; ptr = ptr->next) { |
|
5232 |
if (temp->integer < ptr->integer) { |
|
5233 |
temp->next = ptr; |
|
5234 |
*previous = temp; |
|
5235 |
break; |
|
5236 |
} |
|
5237 |
previous = &(ptr->next); |
|
5238 |
} |
|
5239 |
if (ptr == NULL) { |
|
5240 |
*previous = temp; |
|
5241 |
} |
|
5242 |
} |
|
5243 |
||
5244 |
/* now search sorted list for first hole >= imin */ |
|
5245 |
for (ptr = head; ptr != NULL; ptr = ptr->next) { |
|
5246 |
if (imin == ptr->integer) { |
|
5247 |
imin++; |
|
5248 |
} else { |
|
5249 |
if (imin < ptr->integer) { |
|
5250 |
break; |
|
5251 |
} |
|
5252 |
} |
|
5253 |
||
5254 |
} |
|
5255 |
||
5256 |
/* free temp list */ |
|
5257 |
for (ptr = head; ptr != NULL; ) { |
|
5258 |
temp = ptr; |
|
5259 |
ptr = ptr->next; |
|
5260 |
free(temp); |
|
5261 |
} |
|
5262 |
||
5263 |
(void) sprintf(tempbuff, "%d", imin); |
|
5264 |
return (s_strdup(tempbuff)); |
|
5265 |
} |
|
5266 |
||
5267 |
return (s_strdup("")); |
|
5268 |
} |
|
5269 |
||
4876 | 5270 |
static int |
5271 |
enumerate_parse(char *rsvstr, char *path_left, numeral_set_t *setp, |
|
5272 |
devfsadm_enumerate_t rules[], int index) |
|
5273 |
{ |
|
5274 |
char *slash1 = NULL; |
|
5275 |
char *slash2 = NULL; |
|
5276 |
char *numeral_id; |
|
5277 |
char *path_left_save; |
|
5278 |
char *rsvstr_save; |
|
5279 |
int ret = 0; |
|
5280 |
static int warned = 0; |
|
5281 |
||
5282 |
rsvstr_save = rsvstr; |
|
5283 |
path_left_save = path_left; |
|
5284 |
||
5285 |
if (rsvstr == NULL || rsvstr[0] == '\0' || rsvstr[0] == '/') { |
|
5286 |
if (!warned) { |
|
5287 |
err_print("invalid reserved filepath: %s\n", |
|
5288 |
rsvstr ? rsvstr : "<NULL>"); |
|
5289 |
warned = 1; |
|
5290 |
} |
|
5291 |
return (0); |
|
5292 |
} |
|
5293 |
||
5294 |
vprint(RSRV_MID, "processing rule: %s, rstring: %s\n", |
|
5295 |
path_left, rsvstr); |
|
5296 |
||
5297 |
||
5298 |
for (;;) { |
|
5299 |
/* get rid of any extra '/' in the reserve string */ |
|
5300 |
while (*rsvstr == '/') { |
|
5301 |
rsvstr++; |
|
5302 |
} |
|
5303 |
||
5304 |
/* get rid of any extra '/' in the RE */ |
|
5305 |
while (*path_left == '/') { |
|
5306 |
path_left++; |
|
5307 |
} |
|
5308 |
||
5309 |
if (slash1 = strchr(path_left, '/')) { |
|
5310 |
*slash1 = '\0'; |
|
5311 |
} |
|
5312 |
if (slash2 = strchr(rsvstr, '/')) { |
|
5313 |
*slash2 = '\0'; |
|
5314 |
} |
|
5315 |
||
5316 |
if ((slash1 != NULL) ^ (slash2 != NULL)) { |
|
5317 |
ret = 0; |
|
5318 |
vprint(RSRV_MID, "mismatch in # of path components\n"); |
|
5319 |
goto out; |
|
5320 |
} |
|
5321 |
||
5322 |
/* |
|
5323 |
* Returns true if path_left matches the list entry. |
|
5324 |
* If it is the last path component, pass subexp |
|
5325 |
* so that it will return the corresponding ID in |
|
5326 |
* numeral_id. |
|
5327 |
*/ |
|
5328 |
numeral_id = NULL; |
|
5329 |
if (match_path_component(path_left, rsvstr, &numeral_id, |
|
5330 |
slash1 ? 0 : rules[index].subexp)) { |
|
5331 |
||
5332 |
/* We have a match. */ |
|
5333 |
if (slash1 == NULL) { |
|
5334 |
/* Is last path component */ |
|
5335 |
vprint(RSRV_MID, "match and last component\n"); |
|
5336 |
create_reserved_numeral(setp, numeral_id); |
|
5337 |
if (numeral_id != NULL) { |
|
5338 |
free(numeral_id); |
|
5339 |
} |
|
5340 |
ret = 1; |
|
5341 |
goto out; |
|
5342 |
} else { |
|
5343 |
/* Not last path component. Continue parsing */ |
|
5344 |
*slash1 = '/'; |
|
5345 |
*slash2 = '/'; |
|
5346 |
path_left = slash1 + 1; |
|
5347 |
rsvstr = slash2 + 1; |
|
5348 |
vprint(RSRV_MID, |
|
5349 |
"match and NOT last component\n"); |
|
5350 |
continue; |
|
5351 |
} |
|
5352 |
} else { |
|
5353 |
/* No match */ |
|
5354 |
ret = 0; |
|
5355 |
vprint(RSRV_MID, "No match: rule RE = %s, " |
|
5356 |
"rstring = %s\n", path_left, rsvstr); |
|
5357 |
goto out; |
|
5358 |
} |
|
5359 |
} |
|
5360 |
||
5361 |
out: |
|
5362 |
if (slash1) |
|
5363 |
*slash1 = '/'; |
|
5364 |
if (slash2) |
|
5365 |
*slash2 = '/'; |
|
5366 |
||
5367 |
if (ret == 1) { |
|
5368 |
vprint(RSRV_MID, "match: rule RE: %s, rstring: %s\n", |
|
5369 |
path_left_save, rsvstr_save); |
|
5370 |
} else { |
|
5371 |
vprint(RSRV_MID, "NO match: rule RE: %s, rstring: %s\n", |
|
5372 |
path_left_save, rsvstr_save); |
|
5373 |
} |
|
5374 |
||
5375 |
return (ret); |
|
5376 |
} |
|
5377 |
||
0 | 5378 |
/* |
5379 |
* Search current_dir for all files which match the first path component |
|
5380 |
* of path_left, which is an RE. If a match is found, but there are more |
|
5381 |
* components of path_left, then recurse, otherwise, if we have reached |
|
5382 |
* the last component of path_left, call create_cached_numerals for each |
|
5383 |
* file. At some point, recurse_dev_re() should be rewritten so that this |
|
5384 |
* function can be eliminated. |
|
5385 |
*/ |
|
5386 |
static void |
|
5387 |
enumerate_recurse(char *current_dir, char *path_left, numeral_set_t *setp, |
|
5388 |
devfsadm_enumerate_t rules[], int index) |
|
5389 |
{ |
|
5390 |
char *slash; |
|
5391 |
char *new_path; |
|
5392 |
char *numeral_id; |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5393 |
finddevhdl_t fhandle; |
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5394 |
const char *fp; |
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5395 |
|
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5396 |
if (finddev_readdir(current_dir, &fhandle) != 0) { |
0 | 5397 |
return; |
5398 |
} |
|
5399 |
||
5400 |
/* get rid of any extra '/' */ |
|
5401 |
while (*path_left == '/') { |
|
5402 |
path_left++; |
|
5403 |
} |
|
5404 |
||
5405 |
if (slash = strchr(path_left, '/')) { |
|
5406 |
*slash = '\0'; |
|
5407 |
} |
|
5408 |
||
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5409 |
while ((fp = finddev_next(fhandle)) != NULL) { |
0 | 5410 |
|
5411 |
/* |
|
2621 | 5412 |
* Returns true if path_left matches the list entry. |
0 | 5413 |
* If it is the last path component, pass subexp |
5414 |
* so that it will return the corresponding ID in |
|
5415 |
* numeral_id. |
|
5416 |
*/ |
|
5417 |
numeral_id = NULL; |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5418 |
if (match_path_component(path_left, (char *)fp, &numeral_id, |
0 | 5419 |
slash ? 0 : rules[index].subexp)) { |
5420 |
||
5421 |
new_path = s_malloc(strlen(current_dir) + |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5422 |
strlen(fp) + 2); |
0 | 5423 |
|
5424 |
(void) strcpy(new_path, current_dir); |
|
5425 |
(void) strcat(new_path, "/"); |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5426 |
(void) strcat(new_path, fp); |
0 | 5427 |
|
5428 |
if (slash != NULL) { |
|
5429 |
enumerate_recurse(new_path, slash + 1, |
|
5430 |
setp, rules, index); |
|
5431 |
} else { |
|
5432 |
create_cached_numeral(new_path, setp, |
|
5433 |
numeral_id, rules, index); |
|
5434 |
if (numeral_id != NULL) { |
|
5435 |
free(numeral_id); |
|
5436 |
} |
|
5437 |
} |
|
5438 |
free(new_path); |
|
5439 |
} |
|
5440 |
} |
|
5441 |
||
5442 |
if (slash != NULL) { |
|
5443 |
*slash = '/'; |
|
5444 |
} |
|
3702
0c044e9df56a
6517848 dev_readdir() in devfsadm fails with alternate root
jg
parents:
3660
diff
changeset
|
5445 |
finddev_close(fhandle); |
0 | 5446 |
} |
5447 |
||
5448 |
||
5449 |
/* |
|
5450 |
* Returns true if file matches file_re. If subexp is non-zero, it means |
|
5451 |
* we are searching the last path component and need to return the |
|
5452 |
* parenthesized subexpression subexp in id. |
|
5453 |
* |
|
5454 |
*/ |
|
5455 |
static int |
|
5456 |
match_path_component(char *file_re, char *file, char **id, int subexp) |
|
5457 |
{ |
|
5458 |
regex_t re1; |
|
5459 |
int match = 0; |
|
5460 |
int nelements; |
|
5461 |
regmatch_t *pmatch; |
|
5462 |
||
5463 |
if (subexp != 0) { |
|
5464 |
nelements = subexp + 1; |
|
5465 |
pmatch = (regmatch_t *) |
|
5466 |
s_malloc(sizeof (regmatch_t) * nelements); |
|
5467 |
} else { |
|
5468 |
pmatch = NULL; |
|
5469 |
nelements = 0; |
|
5470 |
} |
|
5471 |
||
5472 |
if (regcomp(&re1, file_re, REG_EXTENDED) != 0) { |
|
5473 |
if (pmatch != NULL) { |
|
5474 |
free(pmatch); |
|
5475 |
} |
|
5476 |
return (0); |
|
5477 |
} |
|
5478 |
||
5479 |
if (regexec(&re1, file, nelements, pmatch, 0) == 0) { |
|
5480 |
match = 1; |
|
5481 |
} |
|
5482 |
||
5483 |
if ((match != 0) && (subexp != 0)) { |
|
5484 |
int size = pmatch[subexp].rm_eo - pmatch[subexp].rm_so; |
|
5485 |
*id = s_malloc(size + 1); |
|
5486 |
(void) strncpy(*id, &file[pmatch[subexp].rm_so], size); |
|
5487 |
(*id)[size] = '\0'; |
|
5488 |
} |
|
5489 |
||
5490 |
if (pmatch != NULL) { |
|
5491 |
free(pmatch); |
|
5492 |
} |
|
5493 |
regfree(&re1); |
|
5494 |
return (match); |
|
5495 |
} |
|
5496 |
||
4876 | 5497 |
static void |
5498 |
create_reserved_numeral(numeral_set_t *setp, char *numeral_id) |
|
5499 |
{ |
|
5500 |
numeral_t *np; |
|
5501 |
||
5502 |
vprint(RSRV_MID, "Attempting to create reserved numeral: %s\n", |
|
5503 |
numeral_id); |
|
5504 |
||
5505 |
/* |
|
5506 |
* We found a numeral_id from an entry in the enumerate_reserved file |
|
5507 |
* which matched the re passed in from devfsadm_enumerate. We only |
|
5508 |
* need to make sure ONE copy of numeral_id exists on the numeral list. |
|
5509 |
* We only need to store /dev/dsk/cNtod0s0 and no other entries |
|
5510 |
* hanging off of controller N. |
|
5511 |
*/ |
|
5512 |
for (np = setp->headnumeral; np != NULL; np = np->next) { |
|
5513 |
if (strcmp(numeral_id, np->id) == 0) { |
|
5514 |
vprint(RSRV_MID, "ID: %s, already reserved\n", np->id); |
|
5515 |
assert(np->flags == NUMERAL_RESERVED); |
|
5516 |
return; |
|
5517 |
} else { |
|
5518 |
assert(np->flags == 0 || |
|
5519 |
np->flags == NUMERAL_RESERVED); |
|
5520 |
} |
|
5521 |
} |
|
5522 |
||
5523 |
/* NOT on list, so add it */ |
|
5524 |
np = s_malloc(sizeof (numeral_t)); |
|
5525 |
np->id = s_strdup(numeral_id); |
|
5526 |
np->full_path = NULL; |
|
5527 |
np->rule_index = 0; |
|
5528 |
np->cmp_str = NULL; |
|
5529 |
np->flags = NUMERAL_RESERVED; |
|
5530 |
np->next = setp->headnumeral; |
|
5531 |
setp->headnumeral = np; |
|
5532 |
||
5533 |
vprint(RSRV_MID, "Reserved numeral ID: %s\n", np->id); |
|
5534 |
} |
|
5535 |
||
0 | 5536 |
/* |
5537 |
* This function is called for every file which matched the leaf |
|
5538 |
* component of the RE. If the "numeral_id" is not already on the |
|
5539 |
* numeral set's numeral list, add it and its physical path. |
|
5540 |
*/ |
|
5541 |
static void |
|
5542 |
create_cached_numeral(char *path, numeral_set_t *setp, char *numeral_id, |
|
5543 |
devfsadm_enumerate_t rules[], int index) |
|
5544 |
{ |
|
5545 |
char linkbuf[PATH_MAX + 1]; |
|
5546 |
char lpath[PATH_MAX + 1]; |
|
5547 |
char *linkptr, *cmp_str; |
|
5548 |
numeral_t *np; |
|
5549 |
int linksize; |
|
5550 |
struct stat sb; |
|
5551 |
const char *fcn = "create_cached_numeral"; |
|
5552 |
||
5553 |
assert(index >= 0 && index < setp->re_count); |
|
5554 |
assert(strcmp(rules[index].re, setp->re[index]) == 0); |
|
5555 |
||
5556 |
/* |
|
5557 |
* We found a numeral_id from an entry in /dev which matched |
|
5558 |
* the re passed in from devfsadm_enumerate. We only need to make sure |
|
5559 |
* ONE copy of numeral_id exists on the numeral list. We only need |
|
5560 |
* to store /dev/dsk/cNtod0s0 and no other entries hanging off |
|
5561 |
* of controller N. |
|
5562 |
*/ |
|
5563 |
for (np = setp->headnumeral; np != NULL; np = np->next) { |
|
4876 | 5564 |
assert(np->flags == 0 || np->flags == NUMERAL_RESERVED); |
0 | 5565 |
if (strcmp(numeral_id, np->id) == 0) { |
4876 | 5566 |
/* |
5567 |
* Note that we can't assert that the flags field |
|
5568 |
* of the numeral is 0, since both reserved and |
|
5569 |
* unreserved links in /dev come here |
|
5570 |
*/ |
|
5571 |
if (np->flags == NUMERAL_RESERVED) { |
|
5572 |
vprint(RSRV_MID, "ID derived from /dev link is" |
|
5573 |
" reserved: %s\n", np->id); |
|
5574 |
} else { |
|
5575 |
vprint(RSRV_MID, "ID derived from /dev link is" |
|
5576 |
" NOT reserved: %s\n", np->id); |
|
5577 |
} |
|
0 | 5578 |
return; |
5579 |
} |
|
5580 |
} |
|
5581 |
||
5582 |
/* NOT on list, so add it */ |
|
5583 |
||
5584 |
(void) strcpy(lpath, path); |
|
5585 |
/* |
|
5586 |
* If path is a dir, it is changed to the first symbolic link it find |
|
5587 |
* if it finds one. |
|
5588 |
*/ |
|
5589 |
if (get_stat_info(lpath, &sb) == DEVFSADM_FAILURE) { |
|
5590 |
return; |
|
5591 |
} |
|
5592 |
||
5593 |
/* If we get here, we found a symlink */ |
|
5594 |
linksize = readlink(lpath, linkbuf, PATH_MAX); |
|
5595 |
||
5596 |
if (linksize <= 0) { |
|
5597 |
err_print(READLINK_FAILED, fcn, lpath, strerror(errno)); |
|
5598 |
return; |
|
5599 |
} |
|
5600 |
||
5601 |
linkbuf[linksize] = '\0'; |
|
5602 |
||
5603 |
/* |
|
5604 |
* the following just points linkptr to the root of the /devices |
|
5605 |
* node if it is a minor node, otherwise, to the first char of |
|
5606 |
* linkbuf if it is a link. |
|
5607 |
*/ |
|
5608 |
(void) is_minor_node(linkbuf, &linkptr); |
|
5609 |
||
5610 |
cmp_str = alloc_cmp_str(linkptr, &rules[index]); |
|
5611 |
if (cmp_str == NULL) { |
|
5612 |
return; |
|
5613 |
} |
|
5614 |
||
5615 |
np = s_malloc(sizeof (numeral_t)); |
|
5616 |
||
5617 |
np->id = s_strdup(numeral_id); |
|
5618 |
np->full_path = s_strdup(linkptr); |
|
5619 |
np->rule_index = index; |
|
5620 |
np->cmp_str = cmp_str; |
|
4876 | 5621 |
np->flags = 0; |
0 | 5622 |
|
5623 |
np->next = setp->headnumeral; |
|
5624 |
setp->headnumeral = np; |
|
5625 |
} |
|
5626 |
||
5627 |
||
5628 |
/* |
|
5629 |
* This should be called either before or after granting access to a |
|
5630 |
* command line version of devfsadm running, since it may have changed |
|
5631 |
* the state of /dev. It forces future enumerate calls to re-build |
|
5632 |
* cached information from /dev. |
|
5633 |
*/ |
|
5634 |
void |
|
5635 |
invalidate_enumerate_cache(void) |
|
5636 |
{ |
|
5637 |
numeral_set_t *setp; |
|
5638 |
numeral_set_t *savedsetp; |
|
5639 |
numeral_t *savednumset; |
|
5640 |
numeral_t *numset; |
|
5641 |
int i; |
|
5642 |
||
5643 |
for (setp = head_numeral_set; setp != NULL; ) { |
|
5644 |
/* |
|
5645 |
* check all regexp's passed in function against |
|
5646 |
* those in cached set. |
|
5647 |
*/ |
|
5648 |
||
5649 |
savedsetp = setp; |
|
5650 |
setp = setp->next; |
|
5651 |
||
5652 |
for (i = 0; i < savedsetp->re_count; i++) { |
|
5653 |
free(savedsetp->re[i]); |
|
5654 |
} |
|
5655 |
free(savedsetp->re); |
|
5656 |
||
5657 |
for (numset = savedsetp->headnumeral; numset != NULL; ) { |
|
5658 |
savednumset = numset; |
|
5659 |
numset = numset->next; |
|
5660 |
assert(savednumset->rule_index < savedsetp->re_count); |
|
5661 |
free(savednumset->id); |
|
5662 |
free(savednumset->full_path); |
|
5663 |
free(savednumset->cmp_str); |
|
5664 |
free(savednumset); |
|
5665 |
} |
|
5666 |
free(savedsetp); |
|
5667 |
} |
|
5668 |
head_numeral_set = NULL; |
|
5669 |
} |
|
5670 |
||
5671 |
/* |
|
5672 |
* Copies over links from /dev to <root>/dev and device special files in |
|
5673 |
* /devices to <root>/devices, preserving the existing file modes. If |
|
5674 |
* the link or special file already exists on <root>, skip the copy. (it |
|
5675 |
* would exist only if a package hard coded it there, so assume package |
|
5676 |
* knows best?). Use /etc/name_to_major and <root>/etc/name_to_major to |
|
5677 |
* make translations for major numbers on device special files. No need to |
|
5678 |
* make a translation on minor_perm since if the file was created in the |
|
5679 |
* miniroot then it would presumably have the same minor_perm entry in |
|
5680 |
* <root>/etc/minor_perm. To be used only by install. |
|
5681 |
*/ |
|
5682 |
int |
|
5683 |
devfsadm_copy(void) |
|
5684 |
{ |
|
5685 |
char filename[PATH_MAX + 1]; |
|
5686 |
||
5687 |
/* load the installed root's name_to_major for translations */ |
|
5688 |
(void) snprintf(filename, sizeof (filename), "%s%s", root_dir, |
|
5689 |
NAME_TO_MAJOR); |
|
5690 |
if (load_n2m_table(filename) == DEVFSADM_FAILURE) { |
|
5691 |
return (DEVFSADM_FAILURE); |
|
5692 |
} |
|
5693 |
||
5694 |
/* Copy /dev to target disk. No need to copy /devices with devfs */ |
|
5695 |
(void) nftw(DEV, devfsadm_copy_file, 20, FTW_PHYS); |
|
5696 |
||
5697 |
/* Let install handle copying over path_to_inst */ |
|
5698 |
||
5699 |
return (DEVFSADM_SUCCESS); |
|
5700 |
} |
|
5701 |
||
5702 |
/* |
|
5703 |
* This function copies links, dirs, and device special files. |
|
5704 |
* Note that it always returns DEVFSADM_SUCCESS, so that nftw doesn't |
|
5705 |
* abort. |
|
5706 |
*/ |
|
5707 |
/*ARGSUSED*/ |
|
5708 |
static int |
|
5709 |
devfsadm_copy_file(const char *file, const struct stat *stat, |
|
5710 |
int flags, struct FTW *ftw) |
|
5711 |
{ |
|
5712 |
struct stat sp; |
|
5713 |
dev_t newdev; |
|
5714 |
char newfile[PATH_MAX + 1]; |
|
5715 |
char linkcontents[PATH_MAX + 1]; |
|
5716 |
int bytes; |
|
5717 |
const char *fcn = "devfsadm_copy_file"; |
|
5718 |
||
5719 |
(void) strcpy(newfile, root_dir); |
|
5720 |
(void) strcat(newfile, "/"); |
|
5721 |
(void) strcat(newfile, file); |
|
5722 |
||
5723 |
if (lstat(newfile, &sp) == 0) { |
|
5724 |
/* newfile already exists, so no need to continue */ |
|
5725 |
return (DEVFSADM_SUCCESS); |
|
5726 |
} |
|
5727 |
||
5728 |
if (((stat->st_mode & S_IFMT) == S_IFBLK) || |
|
5729 |
((stat->st_mode & S_IFMT) == S_IFCHR)) { |
|
5730 |
if (translate_major(stat->st_rdev, &newdev) == |
|
5731 |
DEVFSADM_FAILURE) { |
|
5732 |
return (DEVFSADM_SUCCESS); |
|
5733 |
} |
|
5734 |
if (mknod(newfile, stat->st_mode, newdev) == -1) { |
|
5735 |
err_print(MKNOD_FAILED, newfile, strerror(errno)); |
|
5736 |
return (DEVFSADM_SUCCESS); |
|
5737 |
} |
|
5738 |
} else if ((stat->st_mode & S_IFMT) == S_IFDIR) { |
|
5739 |
if (mknod(newfile, stat->st_mode, 0) == -1) { |
|
5740 |
err_print(MKNOD_FAILED, newfile, strerror(errno)); |
|
5741 |
return (DEVFSADM_SUCCESS); |
|
5742 |
} |
|
5743 |
} else if ((stat->st_mode & S_IFMT) == S_IFLNK) { |
|
5744 |
if ((bytes = readlink(file, linkcontents, PATH_MAX)) == -1) { |
|
5745 |
err_print(READLINK_FAILED, fcn, file, strerror(errno)); |
|
5746 |
return (DEVFSADM_SUCCESS); |
|
5747 |
} |
|
5748 |
linkcontents[bytes] = '\0'; |
|
5749 |
if (symlink(linkcontents, newfile) == -1) { |
|
5750 |
err_print(SYMLINK_FAILED, newfile, newfile, |
|
5751 |
strerror(errno)); |
|
5752 |
return (DEVFSADM_SUCCESS); |
|
5753 |
} |
|
5754 |
} |
|
5755 |
||
5756 |
(void) lchown(newfile, stat->st_uid, stat->st_gid); |
|
5757 |
return (DEVFSADM_SUCCESS); |
|
5758 |
} |
|
5759 |
||
5760 |
/* |
|
5761 |
* Given a dev_t from the running kernel, return the new_dev_t |
|
5762 |
* by translating to the major number found on the installed |
|
5763 |
* target's root name_to_major file. |
|
5764 |
*/ |
|
5765 |
static int |
|
5766 |
translate_major(dev_t old_dev, dev_t *new_dev) |
|
5767 |
{ |
|
5768 |
major_t oldmajor; |
|
5769 |
major_t newmajor; |
|
5770 |
minor_t oldminor; |
|
5771 |
minor_t newminor; |
|
5772 |
char cdriver[FILENAME_MAX + 1]; |
|
5773 |
char driver[FILENAME_MAX + 1]; |
|
5774 |
char *fcn = "translate_major: "; |
|
5775 |
||
5776 |
oldmajor = major(old_dev); |
|
5777 |
if (modctl(MODGETNAME, driver, sizeof (driver), |
|
5778 |
&oldmajor) != 0) { |
|
5779 |
return (DEVFSADM_FAILURE); |
|
5780 |
} |
|
5781 |
||
5782 |
if (strcmp(driver, "clone") != 0) { |
|
5783 |
/* non-clone case */ |
|
5784 |
||
5785 |
/* look up major number is target's name2major */ |
|
5786 |
if (get_major_no(driver, &newmajor) == DEVFSADM_FAILURE) { |
|
5787 |
return (DEVFSADM_FAILURE); |
|
5788 |
} |
|
5789 |
||
5790 |
*new_dev = makedev(newmajor, minor(old_dev)); |
|
5791 |
if (old_dev != *new_dev) { |
|
5792 |
vprint(CHATTY_MID, "%sdriver: %s old: %lu,%lu " |
|
5793 |
"new: %lu,%lu\n", fcn, driver, major(old_dev), |
|
5794 |
minor(old_dev), major(*new_dev), |
|
5795 |
minor(*new_dev)); |
|
5796 |
} |
|
5797 |
return (DEVFSADM_SUCCESS); |
|
5798 |
} else { |
|
5799 |
/* |
|
5800 |
* The clone is a special case. Look at its minor |
|
5801 |
* number since it is the major number of the real driver. |
|
5802 |
*/ |
|
5803 |
if (get_major_no(driver, &newmajor) == DEVFSADM_FAILURE) { |
|
5804 |
return (DEVFSADM_FAILURE); |
|
5805 |
} |
|
5806 |
||
5807 |
oldminor = minor(old_dev); |
|
5808 |
if (modctl(MODGETNAME, cdriver, sizeof (cdriver), |
|
5809 |
&oldminor) != 0) { |
|
5810 |
err_print(MODGETNAME_FAILED, oldminor); |
|
5811 |
return (DEVFSADM_FAILURE); |
|
5812 |
} |
|
5813 |
||
5814 |
if (get_major_no(cdriver, &newminor) == DEVFSADM_FAILURE) { |
|
5815 |
return (DEVFSADM_FAILURE); |
|
5816 |
} |
|
5817 |
||
5818 |
*new_dev = makedev(newmajor, newminor); |
|
5819 |
if (old_dev != *new_dev) { |
|
5820 |
vprint(CHATTY_MID, "%sdriver: %s old: " |
|
5821 |
"%lu,%lu new: %lu,%lu\n", fcn, driver, |
|
5822 |
major(old_dev), minor(old_dev), |
|
5823 |
major(*new_dev), minor(*new_dev)); |
|
5824 |
} |
|
5825 |
return (DEVFSADM_SUCCESS); |
|
5826 |
} |
|
5827 |
} |
|
5828 |
||
5829 |
/* |
|
5830 |
* |
|
5831 |
* Find the major number for driver, searching the n2m_list that was |
|
5832 |
* built in load_n2m_table(). |
|
5833 |
*/ |
|
5834 |
static int |
|
5835 |
get_major_no(char *driver, major_t *major) |
|
5836 |
{ |
|
5837 |
n2m_t *ptr; |
|
5838 |
||
5839 |
for (ptr = n2m_list; ptr != NULL; ptr = ptr->next) { |
|
5840 |
if (strcmp(ptr->driver, driver) == 0) { |
|
5841 |
*major = ptr->major; |
|
5842 |
return (DEVFSADM_SUCCESS); |
|
5843 |
} |
|
5844 |
} |
|
5845 |
err_print(FIND_MAJOR_FAILED, driver); |
|
5846 |
return (DEVFSADM_FAILURE); |
|
5847 |
} |
|
5848 |
||
5849 |
/* |
|
5850 |
* Loads a name_to_major table into memory. Used only for suninstall's |
|
5851 |
* private -R option to devfsadm, to translate major numbers from the |
|
5852 |
* running to the installed target disk. |
|
5853 |
*/ |
|
5854 |
static int |
|
5855 |
load_n2m_table(char *file) |
|
5856 |
{ |
|
5857 |
FILE *fp; |
|
2805
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
5858 |
char line[1024], *cp; |
0 | 5859 |
char driver[PATH_MAX + 1]; |
5860 |
major_t major; |
|
5861 |
n2m_t *ptr; |
|
5862 |
int ln = 0; |
|
5863 |
||
5864 |
if ((fp = fopen(file, "r")) == NULL) { |
|
5865 |
err_print(FOPEN_FAILED, file, strerror(errno)); |
|
5866 |
return (DEVFSADM_FAILURE); |
|
5867 |
} |
|
5868 |
||
5869 |
while (fgets(line, sizeof (line), fp) != NULL) { |
|
5870 |
ln++; |
|
2805
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
5871 |
/* cut off comments starting with '#' */ |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
5872 |
if ((cp = strchr(line, '#')) != NULL) |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
5873 |
*cp = '\0'; |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
5874 |
/* ignore comment or blank lines */ |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
5875 |
if (is_blank(line)) |
0 | 5876 |
continue; |
2805
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
5877 |
/* sanity-check */ |
0 | 5878 |
if (sscanf(line, "%1024s%lu", driver, &major) != 2) { |
5879 |
err_print(IGNORING_LINE_IN, ln, file); |
|
5880 |
continue; |
|
5881 |
} |
|
5882 |
ptr = (n2m_t *)s_malloc(sizeof (n2m_t)); |
|
5883 |
ptr->major = major; |
|
5884 |
ptr->driver = s_strdup(driver); |
|
5885 |
ptr->next = n2m_list; |
|
5886 |
n2m_list = ptr; |
|
5887 |
} |
|
5888 |
if (fclose(fp) == EOF) { |
|
5889 |
err_print(FCLOSE_FAILED, file, strerror(errno)); |
|
5890 |
} |
|
5891 |
return (DEVFSADM_SUCCESS); |
|
5892 |
} |
|
5893 |
||
5894 |
/* |
|
4876 | 5895 |
* Called at devfsadm startup to read the file /etc/dev/enumerate_reserved |
5896 |
* Creates a linked list of devlinks from which reserved IDs can be derived |
|
5897 |
*/ |
|
5898 |
static void |
|
5899 |
read_enumerate_file(void) |
|
5900 |
{ |
|
5901 |
FILE *fp; |
|
5902 |
int linenum; |
|
5903 |
char line[PATH_MAX+1]; |
|
5904 |
enumerate_file_t *entry; |
|
5905 |
struct stat current_sb; |
|
5906 |
static struct stat cached_sb; |
|
5907 |
static int cached = FALSE; |
|
5908 |
||
5909 |
assert(enumerate_file); |
|
5910 |
||
5911 |
if (stat(enumerate_file, ¤t_sb) == -1) { |
|
5912 |
vprint(RSRV_MID, "No reserved file: %s\n", enumerate_file); |
|
5913 |
cached = FALSE; |
|
5914 |
if (enumerate_reserved != NULL) { |
|
5915 |
vprint(RSRV_MID, "invalidating %s cache\n", |
|
5916 |
enumerate_file); |
|
5917 |
} |
|
5918 |
while (enumerate_reserved != NULL) { |
|
5919 |
entry = enumerate_reserved; |
|
5920 |
enumerate_reserved = entry->er_next; |
|
5921 |
free(entry->er_file); |
|
5922 |
free(entry->er_id); |
|
5923 |
free(entry); |
|
5924 |
} |
|
5925 |
return; |
|
5926 |
} |
|
5927 |
||
5928 |
/* if already cached, check to see if it is still valid */ |
|
5929 |
if (cached == TRUE) { |
|
5930 |
||
5931 |
if (current_sb.st_mtime == cached_sb.st_mtime) { |
|
5932 |
vprint(RSRV_MID, "%s cache valid\n", enumerate_file); |
|
5933 |
vprint(FILES_MID, "%s cache valid\n", enumerate_file); |
|
5934 |
return; |
|
5935 |
} |
|
5936 |
||
5937 |
vprint(RSRV_MID, "invalidating %s cache\n", enumerate_file); |
|
5938 |
vprint(FILES_MID, "invalidating %s cache\n", enumerate_file); |
|
5939 |
||
5940 |
while (enumerate_reserved != NULL) { |
|
5941 |
entry = enumerate_reserved; |
|
5942 |
enumerate_reserved = entry->er_next; |
|
5943 |
free(entry->er_file); |
|
5944 |
free(entry->er_id); |
|
5945 |
free(entry); |
|
5946 |
} |
|
5947 |
vprint(RSRV_MID, "Recaching file: %s\n", enumerate_file); |
|
5948 |
} else { |
|
5949 |
vprint(RSRV_MID, "Caching file (first time): %s\n", |
|
5950 |
enumerate_file); |
|
5951 |
cached = TRUE; |
|
5952 |
} |
|
5953 |
||
5954 |
(void) stat(enumerate_file, &cached_sb); |
|
5955 |
||
5956 |
if ((fp = fopen(enumerate_file, "r")) == NULL) { |
|
5957 |
err_print(FOPEN_FAILED, enumerate_file, strerror(errno)); |
|
5958 |
return; |
|
5959 |
} |
|
5960 |
||
5961 |
vprint(RSRV_MID, "Reading reserve file: %s\n", enumerate_file); |
|
5962 |
linenum = 0; |
|
5963 |
while (fgets(line, sizeof (line), fp) != NULL) { |
|
5964 |
char *cp, *ncp; |
|
5965 |
||
5966 |
linenum++; |
|
5967 |
||
5968 |
/* remove newline */ |
|
5969 |
cp = strchr(line, '\n'); |
|
5970 |
if (cp) |
|
5971 |
*cp = '\0'; |
|
5972 |
||
5973 |
vprint(RSRV_MID, "Reserve file: line %d: %s\n", |
|
5974 |
linenum, line); |
|
5975 |
||
5976 |
/* skip over space and tab */ |
|
5977 |
for (cp = line; *cp == ' ' || *cp == '\t'; cp++); |
|
5978 |
||
5979 |
if (*cp == '\0' || *cp == '#') { |
|
5980 |
vprint(RSRV_MID, "Skipping line: '%s'\n", line); |
|
5981 |
continue; /* blank line or comment line */ |
|
5982 |
} |
|
5983 |
||
5984 |
ncp = cp; |
|
5985 |
||
5986 |
/* delete trailing blanks */ |
|
5987 |
for (; *cp != ' ' && *cp != '\t' && *cp != '\0'; cp++); |
|
5988 |
*cp = '\0'; |
|
5989 |
||
5990 |
entry = s_zalloc(sizeof (enumerate_file_t)); |
|
5991 |
entry->er_file = s_strdup(ncp); |
|
5992 |
entry->er_id = NULL; |
|
5993 |
entry->er_next = enumerate_reserved; |
|
5994 |
enumerate_reserved = entry; |
|
5995 |
} |
|
5996 |
||
5997 |
if (fclose(fp) == EOF) { |
|
5998 |
err_print(FCLOSE_FAILED, enumerate_file, strerror(errno)); |
|
5999 |
} |
|
6000 |
} |
|
6001 |
||
6002 |
/* |
|
0 | 6003 |
* Called at devfsadm startup to read in the devlink.tab file. Creates |
6004 |
* a linked list of devlinktab_list structures which will be |
|
6005 |
* searched for every minor node. |
|
6006 |
*/ |
|
6007 |
static void |
|
6008 |
read_devlinktab_file(void) |
|
6009 |
{ |
|
6010 |
devlinktab_list_t *headp = NULL; |
|
6011 |
devlinktab_list_t *entryp; |
|
6012 |
devlinktab_list_t **previous; |
|
6013 |
devlinktab_list_t *save; |
|
2805
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
6014 |
char line[MAX_DEVLINK_LINE], *cp; |
0 | 6015 |
char *selector; |
6016 |
char *p_link; |
|
6017 |
char *s_link; |
|
6018 |
FILE *fp; |
|
6019 |
int i; |
|
6020 |
static struct stat cached_sb; |
|
6021 |
struct stat current_sb; |
|
6022 |
static int cached = FALSE; |
|
6023 |
||
6024 |
if (devlinktab_file == NULL) { |
|
6025 |
return; |
|
6026 |
} |
|
6027 |
||
6028 |
(void) stat(devlinktab_file, ¤t_sb); |
|
6029 |
||
6030 |
/* if already cached, check to see if it is still valid */ |
|
6031 |
if (cached == TRUE) { |
|
6032 |
||
6033 |
if (current_sb.st_mtime == cached_sb.st_mtime) { |
|
6034 |
vprint(FILES_MID, "%s cache valid\n", devlinktab_file); |
|
6035 |
return; |
|
6036 |
} |
|
6037 |
||
6038 |
vprint(FILES_MID, "invalidating %s cache\n", devlinktab_file); |
|
6039 |
||
6040 |
while (devlinktab_list != NULL) { |
|
6041 |
free_link_list(devlinktab_list->p_link); |
|
6042 |
free_link_list(devlinktab_list->s_link); |
|
6043 |
free_selector_list(devlinktab_list->selector); |
|
6044 |
free(devlinktab_list->selector_pattern); |
|
6045 |
free(devlinktab_list->p_link_pattern); |
|
6046 |
if (devlinktab_list->s_link_pattern != NULL) { |
|
6047 |
free(devlinktab_list->s_link_pattern); |
|
6048 |
} |
|
6049 |
save = devlinktab_list; |
|
6050 |
devlinktab_list = devlinktab_list->next; |
|
6051 |
free(save); |
|
6052 |
} |
|
6053 |
} else { |
|
6054 |
cached = TRUE; |
|
6055 |
} |
|
6056 |
||
6057 |
(void) stat(devlinktab_file, &cached_sb); |
|
6058 |
||
6059 |
if ((fp = fopen(devlinktab_file, "r")) == NULL) { |
|
6060 |
err_print(FOPEN_FAILED, devlinktab_file, strerror(errno)); |
|
6061 |
return; |
|
6062 |
} |
|
6063 |
||
6064 |
previous = &headp; |
|
6065 |
||
6066 |
while (fgets(line, sizeof (line), fp) != NULL) { |
|
6067 |
devlinktab_line++; |
|
6068 |
i = strlen(line); |
|
6069 |
if (line[i-1] == NEWLINE) { |
|
6070 |
line[i-1] = '\0'; |
|
6071 |
} else if (i == sizeof (line-1)) { |
|
6072 |
err_print(LINE_TOO_LONG, devlinktab_line, |
|
6073 |
devlinktab_file, sizeof (line)-1); |
|
6074 |
while (((i = getc(fp)) != '\n') && (i != EOF)); |
|
6075 |
continue; |
|
6076 |
} |
|
6077 |
||
2805
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
6078 |
/* cut off comments starting with '#' */ |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
6079 |
if ((cp = strchr(line, '#')) != NULL) |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
6080 |
*cp = '\0'; |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
6081 |
/* ignore comment or blank lines */ |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
6082 |
if (is_blank(line)) |
0 | 6083 |
continue; |
6084 |
||
6085 |
vprint(DEVLINK_MID, "table: %s line %d: '%s'\n", |
|
6086 |
devlinktab_file, devlinktab_line, line); |
|
6087 |
||
6088 |
/* break each entry into fields. s_link may be NULL */ |
|
6089 |
if (split_devlinktab_entry(line, &selector, &p_link, |
|
6090 |
&s_link) == DEVFSADM_FAILURE) { |
|
6091 |
vprint(DEVLINK_MID, "split_entry returns failure\n"); |
|
6092 |
continue; |
|
6093 |
} else { |
|
6094 |
vprint(DEVLINK_MID, "split_entry selector='%s' " |
|
6095 |
"p_link='%s' s_link='%s'\n\n", selector, |
|
6096 |
p_link, (s_link == NULL) ? "" : s_link); |
|
6097 |
} |
|
6098 |
||
6099 |
entryp = (devlinktab_list_t *) |
|
6100 |
s_malloc(sizeof (devlinktab_list_t)); |
|
6101 |
||
6102 |
entryp->line_number = devlinktab_line; |
|
6103 |
||
6104 |
if ((entryp->selector = |
|
6105 |
create_selector_list(selector)) == NULL) { |
|
6106 |
free(entryp); |
|
6107 |
continue; |
|
6108 |
} |
|
6109 |
entryp->selector_pattern = s_strdup(selector); |
|
6110 |
||
6111 |
if ((entryp->p_link = create_link_list(p_link)) == NULL) { |
|
6112 |
free_selector_list(entryp->selector); |
|
6113 |
free(entryp->selector_pattern); |
|
6114 |
free(entryp); |
|
6115 |
continue; |
|
6116 |
} |
|
6117 |
||
6118 |
entryp->p_link_pattern = s_strdup(p_link); |
|
6119 |
||
6120 |
if (s_link != NULL) { |
|
6121 |
if ((entryp->s_link = |
|
6122 |
create_link_list(s_link)) == NULL) { |
|
6123 |
free_selector_list(entryp->selector); |
|
6124 |
free_link_list(entryp->p_link); |
|
6125 |
free(entryp->selector_pattern); |
|
6126 |
free(entryp->p_link_pattern); |
|
6127 |
free(entryp); |
|
6128 |
continue; |
|
6129 |
} |
|
6130 |
entryp->s_link_pattern = s_strdup(s_link); |
|
6131 |
} else { |
|
6132 |
entryp->s_link = NULL; |
|
6133 |
entryp->s_link_pattern = NULL; |
|
6134 |
||
6135 |
} |
|
6136 |
||
6137 |
/* append to end of list */ |
|
6138 |
||
6139 |
entryp->next = NULL; |
|
6140 |
*previous = entryp; |
|
6141 |
previous = &(entryp->next); |
|
6142 |
} |
|
6143 |
if (fclose(fp) == EOF) { |
|
6144 |
err_print(FCLOSE_FAILED, devlinktab_file, strerror(errno)); |
|
6145 |
} |
|
6146 |
devlinktab_list = headp; |
|
6147 |
} |
|
6148 |
||
6149 |
/* |
|
6150 |
* |
|
6151 |
* For a single line entry in devlink.tab, split the line into fields |
|
6152 |
* selector, p_link, and an optionally s_link. If s_link field is not |
|
6153 |
* present, then return NULL in s_link (not NULL string). |
|
6154 |
*/ |
|
6155 |
static int |
|
6156 |
split_devlinktab_entry(char *entry, char **selector, char **p_link, |
|
6157 |
char **s_link) |
|
6158 |
{ |
|
6159 |
char *tab; |
|
6160 |
||
6161 |
*selector = entry; |
|
6162 |
||
6163 |
if ((tab = strchr(entry, TAB)) != NULL) { |
|
6164 |
*tab = '\0'; |
|
6165 |
*p_link = ++tab; |
|
6166 |
} else { |
|
6167 |
err_print(MISSING_TAB, devlinktab_line, devlinktab_file); |
|
6168 |
return (DEVFSADM_FAILURE); |
|
6169 |
} |
|
6170 |
||
6171 |
if (*p_link == '\0') { |
|
6172 |
err_print(MISSING_DEVNAME, devlinktab_line, devlinktab_file); |
|
6173 |
return (DEVFSADM_FAILURE); |
|
6174 |
} |
|
6175 |
||
6176 |
if ((tab = strchr(*p_link, TAB)) != NULL) { |
|
6177 |
*tab = '\0'; |
|
6178 |
*s_link = ++tab; |
|
6179 |
if (strchr(*s_link, TAB) != NULL) { |
|
6180 |
err_print(TOO_MANY_FIELDS, devlinktab_line, |
|
6181 |
devlinktab_file); |
|
6182 |
return (DEVFSADM_FAILURE); |
|
6183 |
} |
|
6184 |
} else { |
|
6185 |
*s_link = NULL; |
|
6186 |
} |
|
6187 |
||
6188 |
return (DEVFSADM_SUCCESS); |
|
6189 |
} |
|
6190 |
||
6191 |
/* |
|
6192 |
* For a given devfs_spec field, for each element in the field, add it to |
|
6193 |
* a linked list of devfs_spec structures. Return the linked list in |
|
6194 |
* devfs_spec_list. |
|
6195 |
*/ |
|
6196 |
static selector_list_t * |
|
6197 |
create_selector_list(char *selector) |
|
6198 |
{ |
|
6199 |
char *key; |
|
6200 |
char *val; |
|
6201 |
int error = FALSE; |
|
6202 |
selector_list_t *head_selector_list = NULL; |
|
6203 |
selector_list_t *selector_list; |
|
6204 |
||
6205 |
/* parse_devfs_spec splits the next field into keyword & value */ |
|
6206 |
while ((*selector != NULL) && (error == FALSE)) { |
|
6207 |
if (parse_selector(&selector, &key, |
|
6208 |
&val) == DEVFSADM_FAILURE) { |
|
6209 |
error = TRUE; |
|
6210 |
break; |
|
6211 |
} else { |
|
6212 |
selector_list = (selector_list_t *) |
|
6213 |
s_malloc(sizeof (selector_list_t)); |
|
6214 |
if (strcmp(NAME_S, key) == 0) { |
|
6215 |
selector_list->key = NAME; |
|
6216 |
} else if (strcmp(TYPE_S, key) == 0) { |
|
6217 |
selector_list->key = TYPE; |
|
6218 |
} else if (strncmp(ADDR_S, key, ADDR_S_LEN) == 0) { |
|
6219 |
selector_list->key = ADDR; |
|
6220 |
if (key[ADDR_S_LEN] == '\0') { |
|
6221 |
selector_list->arg = 0; |
|
6222 |
} else if (isdigit(key[ADDR_S_LEN]) != |
|
6223 |
FALSE) { |
|
6224 |
selector_list->arg = |
|
6225 |
atoi(&key[ADDR_S_LEN]); |
|
6226 |
} else { |
|
6227 |
error = TRUE; |
|
6228 |
free(selector_list); |
|
6229 |
err_print(BADKEYWORD, key, |
|
6230 |
devlinktab_line, |
|
6231 |
devlinktab_file); |
|
6232 |
break; |
|
6233 |
} |
|
6234 |
} else if (strncmp(MINOR_S, key, |
|
6235 |
MINOR_S_LEN) == 0) { |
|
6236 |
selector_list->key = MINOR; |
|
6237 |
if (key[MINOR_S_LEN] == '\0') { |
|
6238 |
selector_list->arg = 0; |
|
6239 |
} else if (isdigit(key[MINOR_S_LEN]) != |
|
6240 |
FALSE) { |
|
6241 |
selector_list->arg = |
|
6242 |
atoi(&key[MINOR_S_LEN]); |
|
6243 |
} else { |
|
6244 |
error = TRUE; |
|
6245 |
free(selector_list); |
|
6246 |
err_print(BADKEYWORD, key, |
|
6247 |
devlinktab_line, |
|
6248 |
devlinktab_file); |
|
6249 |
break; |
|
6250 |
} |
|
6251 |
vprint(DEVLINK_MID, "MINOR = %s\n", val); |
|
6252 |
} else { |
|
6253 |
err_print(UNRECOGNIZED_KEY, key, |
|
6254 |
devlinktab_line, devlinktab_file); |
|
6255 |
error = TRUE; |
|
6256 |
free(selector_list); |
|
6257 |
break; |
|
6258 |
} |
|
6259 |
selector_list->val = s_strdup(val); |
|
6260 |
selector_list->next = head_selector_list; |
|
6261 |
head_selector_list = selector_list; |
|
6262 |
vprint(DEVLINK_MID, "key='%s' val='%s' arg=%d\n", |
|
6263 |
key, val, selector_list->arg); |
|
6264 |
} |
|
6265 |
} |
|
6266 |
||
6267 |
if ((error == FALSE) && (head_selector_list != NULL)) { |
|
6268 |
return (head_selector_list); |
|
6269 |
} else { |
|
6270 |
/* parse failed. Free any allocated structs */ |
|
6271 |
free_selector_list(head_selector_list); |
|
6272 |
return (NULL); |
|
6273 |
} |
|
6274 |
} |
|
6275 |
||
6276 |
/* |
|
6277 |
* Takes a semicolon separated list of selector elements and breaks up |
|
6278 |
* into a keyword-value pair. semicolon and equal characters are |
|
6279 |
* replaced with NULL's. On success, selector is updated to point to the |
|
6280 |
* terminating NULL character terminating the keyword-value pair, and the |
|
6281 |
* function returns DEVFSADM_SUCCESS. If there is a syntax error, |
|
6282 |
* devfs_spec is not modified and function returns DEVFSADM_FAILURE. |
|
6283 |
*/ |
|
6284 |
static int |
|
6285 |
parse_selector(char **selector, char **key, char **val) |
|
6286 |
{ |
|
6287 |
char *equal; |
|
6288 |
char *semi_colon; |
|
6289 |
||
6290 |
*key = *selector; |
|
6291 |
||
6292 |
if ((equal = strchr(*key, '=')) != NULL) { |
|
6293 |
*equal = '\0'; |
|
6294 |
} else { |
|
6295 |
err_print(MISSING_EQUAL, devlinktab_line, devlinktab_file); |
|
6296 |
return (DEVFSADM_FAILURE); |
|
6297 |
} |
|
6298 |
||
6299 |
*val = ++equal; |
|
6300 |
if ((semi_colon = strchr(equal, ';')) != NULL) { |
|
6301 |
*semi_colon = '\0'; |
|
6302 |
*selector = semi_colon + 1; |
|
6303 |
} else { |
|
6304 |
*selector = equal + strlen(equal); |
|
6305 |
} |
|
6306 |
return (DEVFSADM_SUCCESS); |
|
6307 |
} |
|
6308 |
||
6309 |
/* |
|
6310 |
* link is either the second or third field of devlink.tab. Parse link |
|
6311 |
* into a linked list of devlink structures and return ptr to list. Each |
|
6312 |
* list element is either a constant string, or one of the following |
|
6313 |
* escape sequences: \M, \A, \N, or \D. The first three escape sequences |
|
6314 |
* take a numerical argument. |
|
6315 |
*/ |
|
6316 |
static link_list_t * |
|
6317 |
create_link_list(char *link) |
|
6318 |
{ |
|
6319 |
int x = 0; |
|
6320 |
int error = FALSE; |
|
6321 |
int counter_found = FALSE; |
|
6322 |
link_list_t *head = NULL; |
|
6323 |
link_list_t **ptr; |
|
6324 |
link_list_t *link_list; |
|
6325 |
char constant[MAX_DEVLINK_LINE]; |
|
6326 |
char *error_str; |
|
6327 |
||
6328 |
if (link == NULL) { |
|
6329 |
return (NULL); |
|
6330 |
} |
|
6331 |
||
6332 |
while ((*link != '\0') && (error == FALSE)) { |
|
6333 |
link_list = (link_list_t *)s_malloc(sizeof (link_list_t)); |
|
6334 |
link_list->next = NULL; |
|
6335 |
||
6336 |
while ((*link != '\0') && (*link != '\\')) { |
|
6337 |
/* a non-escaped string */ |
|
6338 |
constant[x++] = *(link++); |
|
6339 |
} |
|
6340 |
if (x != 0) { |
|
6341 |
constant[x] = '\0'; |
|
6342 |
link_list->type = CONSTANT; |
|
6343 |
link_list->constant = s_strdup(constant); |
|
6344 |
x = 0; |
|
6345 |
vprint(DEVLINK_MID, "CONSTANT FOUND %s\n", constant); |
|
6346 |
} else { |
|
6347 |
switch (*(++link)) { |
|
6348 |
case 'M': |
|
6349 |
link_list->type = MINOR; |
|
6350 |
break; |
|
6351 |
case 'A': |
|
6352 |
link_list->type = ADDR; |
|
6353 |
break; |
|
6354 |
case 'N': |
|
6355 |
if (counter_found == TRUE) { |
|
6356 |
error = TRUE; |
|
6357 |
error_str = "multiple counters " |
|
6358 |
"not permitted"; |
|
6359 |
free(link_list); |
|
6360 |
} else { |
|
6361 |
counter_found = TRUE; |
|
6362 |
link_list->type = COUNTER; |
|
6363 |
} |
|
6364 |
break; |
|
6365 |
case 'D': |
|
6366 |
link_list->type = NAME; |
|
6367 |
break; |
|
6368 |
default: |
|
6369 |
error = TRUE; |
|
6370 |
free(link_list); |
|
6371 |
error_str = "unrecognized escape sequence"; |
|
6372 |
break; |
|
6373 |
} |
|
6374 |
if (*(link++) != 'D') { |
|
6375 |
if (isdigit(*link) == FALSE) { |
|
6376 |
error_str = "escape sequence must be " |
|
6377 |
"followed by a digit\n"; |
|
6378 |
error = TRUE; |
|
6379 |
free(link_list); |
|
6380 |
} else { |
|
6381 |
link_list->arg = |
|
6382 |
(int)strtoul(link, &link, 10); |
|
6383 |
vprint(DEVLINK_MID, "link_list->arg = " |
|
6384 |
"%d\n", link_list->arg); |
|
6385 |
} |
|
6386 |
} |
|
6387 |
} |
|
6388 |
/* append link_list struct to end of list */ |
|
6389 |
if (error == FALSE) { |
|
6390 |
for (ptr = &head; *ptr != NULL; ptr = &((*ptr)->next)); |
|
6391 |
*ptr = link_list; |
|
6392 |
} |
|
6393 |
} |
|
6394 |
||
6395 |
if (error == FALSE) { |
|
6396 |
return (head); |
|
6397 |
} else { |
|
6398 |
err_print(CONFIG_INCORRECT, devlinktab_line, devlinktab_file, |
|
6399 |
error_str); |
|
6400 |
free_link_list(head); |
|
6401 |
return (NULL); |
|
6402 |
} |
|
6403 |
} |
|
6404 |
||
6405 |
/* |
|
6406 |
* Called for each minor node devfsadm processes; for each minor node, |
|
6407 |
* look for matches in the devlinktab_list list which was created on |
|
6408 |
* startup read_devlinktab_file(). If there is a match, call build_links() |
|
6409 |
* to build a logical devlink and a possible extra devlink. |
|
6410 |
*/ |
|
6411 |
static int |
|
6412 |
process_devlink_compat(di_minor_t minor, di_node_t node) |
|
6413 |
{ |
|
6414 |
int link_built = FALSE; |
|
6415 |
devlinktab_list_t *entry; |
|
6416 |
char *nodetype; |
|
6417 |
char *dev_path; |
|
6418 |
||
6419 |
if (devlinks_debug == TRUE) { |
|
6420 |
nodetype = di_minor_nodetype(minor); |
|
6421 |
assert(nodetype != NULL); |
|
6422 |
if ((dev_path = di_devfs_path(node)) != NULL) { |
|
6423 |
vprint(INFO_MID, "'%s' entry: %s:%s\n", nodetype, |
|
6424 |
dev_path, |
|
6425 |
di_minor_name(minor) ? di_minor_name(minor) : |
|
6426 |
""); |
|
6427 |
di_devfs_path_free(dev_path); |
|
6428 |
} |
|
6429 |
||
6430 |
} |
|
6431 |
||
6432 |
||
6433 |
/* don't process devlink.tab if devfsadm invoked with -c <class> */ |
|
6434 |
if (num_classes > 0) { |
|
6435 |
return (FALSE); |
|
6436 |
} |
|
6437 |
||
6438 |
for (entry = devlinktab_list; entry != NULL; entry = entry->next) { |
|
6439 |
if (devlink_matches(entry, minor, node) == DEVFSADM_SUCCESS) { |
|
6440 |
link_built = TRUE; |
|
6441 |
(void) build_links(entry, minor, node); |
|
6442 |
} |
|
6443 |
} |
|
6444 |
return (link_built); |
|
6445 |
} |
|
6446 |
||
6447 |
/* |
|
6448 |
* For a given devlink.tab devlinktab_list entry, see if the selector |
|
6449 |
* field matches this minor node. If it does, return DEVFSADM_SUCCESS, |
|
6450 |
* otherwise DEVFSADM_FAILURE. |
|
6451 |
*/ |
|
6452 |
static int |
|
6453 |
devlink_matches(devlinktab_list_t *entry, di_minor_t minor, di_node_t node) |
|
6454 |
{ |
|
6455 |
selector_list_t *selector = entry->selector; |
|
6456 |
char *addr; |
|
6457 |
char *minor_name; |
|
6458 |
char *node_type; |
|
6459 |
||
6460 |
for (; selector != NULL; selector = selector->next) { |
|
6461 |
switch (selector->key) { |
|
6462 |
case NAME: |
|
6463 |
if (strcmp(di_node_name(node), selector->val) != 0) { |
|
6464 |
return (DEVFSADM_FAILURE); |
|
6465 |
} |
|
6466 |
break; |
|
6467 |
case TYPE: |
|
6468 |
node_type = di_minor_nodetype(minor); |
|
6469 |
assert(node_type != NULL); |
|
6470 |
if (strcmp(node_type, selector->val) != 0) { |
|
6471 |
return (DEVFSADM_FAILURE); |
|
6472 |
} |
|
6473 |
break; |
|
6474 |
case ADDR: |
|
6475 |
if ((addr = di_bus_addr(node)) == NULL) { |
|
6476 |
return (DEVFSADM_FAILURE); |
|
6477 |
} |
|
6478 |
if (selector->arg == 0) { |
|
6479 |
if (strcmp(addr, selector->val) != 0) { |
|
6480 |
return (DEVFSADM_FAILURE); |
|
6481 |
} |
|
6482 |
} else { |
|
6483 |
if (compare_field(addr, selector->val, |
|
6484 |
selector->arg) == DEVFSADM_FAILURE) { |
|
6485 |
return (DEVFSADM_FAILURE); |
|
6486 |
} |
|
6487 |
} |
|
6488 |
break; |
|
6489 |
case MINOR: |
|
6490 |
if ((minor_name = di_minor_name(minor)) == NULL) { |
|
6491 |
return (DEVFSADM_FAILURE); |
|
6492 |
} |
|
6493 |
if (selector->arg == 0) { |
|
6494 |
if (strcmp(minor_name, selector->val) != 0) { |
|
6495 |
return (DEVFSADM_FAILURE); |
|
6496 |
} |
|
6497 |
} else { |
|
6498 |
if (compare_field(minor_name, selector->val, |
|
6499 |
selector->arg) == DEVFSADM_FAILURE) { |
|
6500 |
return (DEVFSADM_FAILURE); |
|
6501 |
} |
|
6502 |
} |
|
6503 |
break; |
|
6504 |
default: |
|
6505 |
return (DEVFSADM_FAILURE); |
|
6506 |
} |
|
6507 |
} |
|
6508 |
||
6509 |
return (DEVFSADM_SUCCESS); |
|
6510 |
} |
|
6511 |
||
6512 |
/* |
|
6513 |
* For the given minor node and devlinktab_list entry from devlink.tab, |
|
6514 |
* build a logical dev link and a possible extra devlink. |
|
6515 |
* Return DEVFSADM_SUCCESS if link is created, otherwise DEVFSADM_FAILURE. |
|
6516 |
*/ |
|
6517 |
static int |
|
6518 |
build_links(devlinktab_list_t *entry, di_minor_t minor, di_node_t node) |
|
6519 |
{ |
|
6520 |
char secondary_link[PATH_MAX + 1]; |
|
6521 |
char primary_link[PATH_MAX + 1]; |
|
6522 |
char contents[PATH_MAX + 1]; |
|
6523 |
char *dev_path; |
|
6524 |
||
6525 |
if ((dev_path = di_devfs_path(node)) == NULL) { |
|
6526 |
err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); |
|
6527 |
devfsadm_exit(1); |
|
6528 |
} |
|
6529 |
(void) strcpy(contents, dev_path); |
|
6530 |
di_devfs_path_free(dev_path); |
|
6531 |
||
6532 |
(void) strcat(contents, ":"); |
|
6533 |
(void) strcat(contents, di_minor_name(minor)); |
|
6534 |
||
6535 |
if (construct_devlink(primary_link, entry->p_link, contents, |
|
6536 |
minor, node, |
|
6537 |
entry->p_link_pattern) == DEVFSADM_FAILURE) { |
|
6538 |
return (DEVFSADM_FAILURE); |
|
6539 |
} |
|
6540 |
(void) devfsadm_mklink(primary_link, node, minor, 0); |
|
6541 |
||
6542 |
if (entry->s_link == NULL) { |
|
6543 |
return (DEVFSADM_SUCCESS); |
|
6544 |
} |
|
6545 |
||
6546 |
if (construct_devlink(secondary_link, entry->s_link, |
|
6547 |
primary_link, minor, node, |
|
6548 |
entry->s_link_pattern) == DEVFSADM_FAILURE) { |
|
6549 |
return (DEVFSADM_FAILURE); |
|
6550 |
} |
|
6551 |
||
6552 |
(void) devfsadm_secondary_link(secondary_link, primary_link, 0); |
|
6553 |
||
6554 |
return (DEVFSADM_SUCCESS); |
|
6555 |
} |
|
6556 |
||
6557 |
/* |
|
6558 |
* The counter rule for devlink.tab entries is implemented via |
|
6559 |
* devfsadm_enumerate_int_start(). One of the arguments to this function |
|
6560 |
* is a path, where each path component is treated as a regular expression. |
|
6561 |
* For devlink.tab entries, this path regular expression is derived from |
|
6562 |
* the devlink spec. get_anchored_re() accepts path regular expressions derived |
|
6563 |
* from devlink.tab entries and inserts the anchors '^' and '$' at the beginning |
|
6564 |
* and end respectively of each path component. This is done to prevent |
|
6565 |
* false matches. For example, without anchors, "a/([0-9]+)" will match "ab/c9" |
|
6566 |
* and incorrect links will be generated. |
|
6567 |
*/ |
|
6568 |
static int |
|
6569 |
get_anchored_re(char *link, char *anchored_re, char *pattern) |
|
6570 |
{ |
|
6571 |
if (*link == '/' || *link == '\0') { |
|
6572 |
err_print(INVALID_DEVLINK_SPEC, pattern); |
|
6573 |
return (DEVFSADM_FAILURE); |
|
6574 |
} |
|
6575 |
||
6576 |
*anchored_re++ = '^'; |
|
6577 |
for (; *link != '\0'; ) { |
|
6578 |
if (*link == '/') { |
|
6579 |
while (*link == '/') |
|
6580 |
link++; |
|
6581 |
*anchored_re++ = '$'; |
|
6582 |
*anchored_re++ = '/'; |
|
6583 |
if (*link != '\0') { |
|
6584 |
*anchored_re++ = '^'; |
|
6585 |
} |
|
6586 |
} else { |
|
6587 |
*anchored_re++ = *link++; |
|
6588 |
if (*link == '\0') { |
|
6589 |
*anchored_re++ = '$'; |
|
6590 |
} |
|
6591 |
} |
|
6592 |
} |
|
6593 |
*anchored_re = '\0'; |
|
6594 |
||
6595 |
return (DEVFSADM_SUCCESS); |
|
6596 |
} |
|
6597 |
||
6598 |
static int |
|
6599 |
construct_devlink(char *link, link_list_t *link_build, char *contents, |
|
6600 |
di_minor_t minor, di_node_t node, char *pattern) |
|
6601 |
{ |
|
6602 |
int counter_offset = -1; |
|
6603 |
devfsadm_enumerate_t rules[1] = {NULL}; |
|
6604 |
char templink[PATH_MAX + 1]; |
|
6605 |
char *buff; |
|
6606 |
char start[10]; |
|
6607 |
char *node_path; |
|
6608 |
char anchored_re[PATH_MAX + 1]; |
|
6609 |
||
6610 |
link[0] = '\0'; |
|
6611 |
||
6612 |
for (; link_build != NULL; link_build = link_build->next) { |
|
6613 |
switch (link_build->type) { |
|
6614 |
case NAME: |
|
6615 |
(void) strcat(link, di_node_name(node)); |
|
6616 |
break; |
|
6617 |
case CONSTANT: |
|
6618 |
(void) strcat(link, link_build->constant); |
|
6619 |
break; |
|
6620 |
case ADDR: |
|
6621 |
if (component_cat(link, di_bus_addr(node), |
|
6622 |
link_build->arg) == DEVFSADM_FAILURE) { |
|
6623 |
node_path = di_devfs_path(node); |
|
6624 |
err_print(CANNOT_BE_USED, pattern, node_path, |
|
6625 |
di_minor_name(minor)); |
|
6626 |
di_devfs_path_free(node_path); |
|
6627 |
return (DEVFSADM_FAILURE); |
|
6628 |
} |
|
6629 |
break; |
|
6630 |
case MINOR: |
|
6631 |
if (component_cat(link, di_minor_name(minor), |
|
6632 |
link_build->arg) == DEVFSADM_FAILURE) { |
|
6633 |
node_path = di_devfs_path(node); |
|
6634 |
err_print(CANNOT_BE_USED, pattern, node_path, |
|
6635 |
di_minor_name(minor)); |
|
6636 |
di_devfs_path_free(node_path); |
|
6637 |
return (DEVFSADM_FAILURE); |
|
6638 |
} |
|
6639 |
break; |
|
6640 |
case COUNTER: |
|
6641 |
counter_offset = strlen(link); |
|
6642 |
(void) strcat(link, "([0-9]+)"); |
|
6643 |
(void) sprintf(start, "%d", link_build->arg); |
|
6644 |
break; |
|
6645 |
default: |
|
6646 |
return (DEVFSADM_FAILURE); |
|
6647 |
} |
|
6648 |
} |
|
6649 |
||
6650 |
if (counter_offset != -1) { |
|
6651 |
/* |
|
6652 |
* copy anything appended after "([0-9]+)" into |
|
6653 |
* templink |
|
6654 |
*/ |
|
6655 |
||
6656 |
(void) strcpy(templink, |
|
6657 |
&link[counter_offset + strlen("([0-9]+)")]); |
|
6658 |
if (get_anchored_re(link, anchored_re, pattern) |
|
6659 |
!= DEVFSADM_SUCCESS) { |
|
6660 |
return (DEVFSADM_FAILURE); |
|
6661 |
} |
|
6662 |
rules[0].re = anchored_re; |
|
6663 |
rules[0].subexp = 1; |
|
6664 |
rules[0].flags = MATCH_ALL; |
|
6665 |
if (devfsadm_enumerate_int_start(contents, 0, &buff, |
|
6666 |
rules, 1, start) == DEVFSADM_FAILURE) { |
|
6667 |
return (DEVFSADM_FAILURE); |
|
6668 |
} |
|
6669 |
(void) strcpy(&link[counter_offset], buff); |
|
6670 |
free(buff); |
|
6671 |
(void) strcat(link, templink); |
|
6672 |
vprint(DEVLINK_MID, "COUNTER is %s\n", link); |
|
6673 |
} |
|
6674 |
return (DEVFSADM_SUCCESS); |
|
6675 |
} |
|
6676 |
||
6677 |
/* |
|
6678 |
* Compares "field" number of the comma separated list "full_name" with |
|
6679 |
* field_item. Returns DEVFSADM_SUCCESS for match, |
|
6680 |
* DEVFSADM_FAILURE for no match. |
|
6681 |
*/ |
|
6682 |
static int |
|
6683 |
compare_field(char *full_name, char *field_item, int field) |
|
6684 |
{ |
|
6685 |
--field; |
|
6686 |
while ((*full_name != '\0') && (field != 0)) { |
|
6687 |
if (*(full_name++) == ',') { |
|
6688 |
field--; |
|
6689 |
} |
|
6690 |
} |
|
6691 |
||
6692 |
if (field != 0) { |
|
6693 |
return (DEVFSADM_FAILURE); |
|
6694 |
} |
|
6695 |
||
6696 |
while ((*full_name != '\0') && (*field_item != '\0') && |
|
6697 |
(*full_name != ',')) { |
|
6698 |
if (*(full_name++) != *(field_item++)) { |
|
6699 |
return (DEVFSADM_FAILURE); |
|
6700 |
} |
|
6701 |
} |
|
6702 |
||
6703 |
if (*field_item != '\0') { |
|
6704 |
return (DEVFSADM_FAILURE); |
|
6705 |
} |
|
6706 |
||
6707 |
if ((*full_name == '\0') || (*full_name == ',')) |
|
6708 |
return (DEVFSADM_SUCCESS); |
|
6709 |
||
6710 |
return (DEVFSADM_FAILURE); |
|
6711 |
} |
|
6712 |
||
6713 |
/* |
|
6714 |
* strcat() field # "field" of comma separated list "name" to "link". |
|
6715 |
* Field 0 is the entire name. |
|
6716 |
* Return DEVFSADM_SUCCESS or DEVFSADM_FAILURE. |
|
6717 |
*/ |
|
6718 |
static int |
|
6719 |
component_cat(char *link, char *name, int field) |
|
6720 |
{ |
|
6721 |
||
6722 |
if (name == NULL) { |
|
6723 |
return (DEVFSADM_FAILURE); |
|
6724 |
} |
|
6725 |
||
6726 |
if (field == 0) { |
|
6727 |
(void) strcat(link, name); |
|
6728 |
return (DEVFSADM_SUCCESS); |
|
6729 |
} |
|
6730 |
||
6731 |
while (*link != '\0') { |
|
6732 |
link++; |
|
6733 |
} |
|
6734 |
||
6735 |
--field; |
|
6736 |
while ((*name != '\0') && (field != 0)) { |
|
6737 |
if (*(name++) == ',') { |
|
6738 |
--field; |
|
6739 |
} |
|
6740 |
} |
|
6741 |
||
6742 |
if (field != 0) { |
|
6743 |
return (DEVFSADM_FAILURE); |
|
6744 |
} |
|
6745 |
||
6746 |
while ((*name != '\0') && (*name != ',')) { |
|
6747 |
*(link++) = *(name++); |
|
6748 |
} |
|
6749 |
||
6750 |
*link = '\0'; |
|
6751 |
return (DEVFSADM_SUCCESS); |
|
6752 |
} |
|
6753 |
||
6754 |
static void |
|
6755 |
free_selector_list(selector_list_t *head) |
|
6756 |
{ |
|
6757 |
selector_list_t *temp; |
|
6758 |
||
6759 |
while (head != NULL) { |
|
6760 |
temp = head; |
|
6761 |
head = head->next; |
|
6762 |
free(temp->val); |
|
6763 |
free(temp); |
|
6764 |
} |
|
6765 |
} |
|
6766 |
||
6767 |
static void |
|
6768 |
free_link_list(link_list_t *head) |
|
6769 |
{ |
|
6770 |
link_list_t *temp; |
|
6771 |
||
6772 |
while (head != NULL) { |
|
6773 |
temp = head; |
|
6774 |
head = head->next; |
|
6775 |
if (temp->type == CONSTANT) { |
|
6776 |
free(temp->constant); |
|
6777 |
} |
|
6778 |
free(temp); |
|
6779 |
} |
|
6780 |
} |
|
6781 |
||
6782 |
/* |
|
6783 |
* Prints only if level matches one of the debug levels |
|
6784 |
* given on command line. INFO_MID is always printed. |
|
6785 |
* |
|
6786 |
* See devfsadm.h for a listing of globally defined levels and |
|
6787 |
* meanings. Modules should prefix the level with their |
|
6788 |
* module name to prevent collisions. |
|
6789 |
*/ |
|
6790 |
/*PRINTFLIKE2*/ |
|
6791 |
void |
|
6792 |
devfsadm_print(char *msgid, char *message, ...) |
|
6793 |
{ |
|
6794 |
va_list ap; |
|
6795 |
static int newline = TRUE; |
|
6796 |
int x; |
|
6797 |
||
6798 |
if (msgid != NULL) { |
|
6799 |
for (x = 0; x < num_verbose; x++) { |
|
6800 |
if (strcmp(verbose[x], msgid) == 0) { |
|
6801 |
break; |
|
6802 |
} |
|
6803 |
if (strcmp(verbose[x], ALL_MID) == 0) { |
|
6804 |
break; |
|
6805 |
} |
|
6806 |
} |
|
6807 |
if (x == num_verbose) { |
|
6808 |
return; |
|
6809 |
} |
|
6810 |
} |
|
6811 |
||
6812 |
va_start(ap, message); |
|
6813 |
||
6814 |
if (msgid == NULL) { |
|
6815 |
if (logflag == TRUE) { |
|
6816 |
(void) vsyslog(LOG_NOTICE, message, ap); |
|
6817 |
} else { |
|
6818 |
(void) vfprintf(stdout, message, ap); |
|
6819 |
} |
|
6820 |
||
6821 |
} else { |
|
6822 |
if (logflag == TRUE) { |
|
6823 |
(void) syslog(LOG_DEBUG, "%s[%ld]: %s: ", |
|
6824 |
prog, getpid(), msgid); |
|
6825 |
(void) vsyslog(LOG_DEBUG, message, ap); |
|
6826 |
} else { |
|
6827 |
if (newline == TRUE) { |
|
6828 |
(void) fprintf(stdout, "%s[%ld]: %s: ", |
|
6829 |
prog, getpid(), msgid); |
|
6830 |
} |
|
6831 |
(void) vfprintf(stdout, message, ap); |
|
6832 |
} |
|
6833 |
} |
|
6834 |
||
6835 |
if (message[strlen(message) - 1] == '\n') { |
|
6836 |
newline = TRUE; |
|
6837 |
} else { |
|
6838 |
newline = FALSE; |
|
6839 |
} |
|
6840 |
va_end(ap); |
|
6841 |
} |
|
6842 |
||
6843 |
/* |
|
6844 |
* print error messages to the terminal or to syslog |
|
6845 |
*/ |
|
6846 |
/*PRINTFLIKE1*/ |
|
6847 |
void |
|
6848 |
devfsadm_errprint(char *message, ...) |
|
6849 |
{ |
|
6850 |
va_list ap; |
|
6851 |
||
6852 |
va_start(ap, message); |
|
6853 |
||
6854 |
if (logflag == TRUE) { |
|
6855 |
(void) vsyslog(LOG_ERR, message, ap); |
|
6856 |
} else { |
|
6857 |
(void) fprintf(stderr, "%s: ", prog); |
|
6858 |
(void) vfprintf(stderr, message, ap); |
|
6859 |
} |
|
6860 |
va_end(ap); |
|
6861 |
} |
|
6862 |
||
6863 |
/* |
|
6864 |
* return noupdate state (-s) |
|
6865 |
*/ |
|
6866 |
int |
|
6867 |
devfsadm_noupdate(void) |
|
6868 |
{ |
|
6869 |
return (file_mods == TRUE ? DEVFSADM_TRUE : DEVFSADM_FALSE); |
|
6870 |
} |
|
6871 |
||
6872 |
/* |
|
6873 |
* return current root update path (-r) |
|
6874 |
*/ |
|
6875 |
const char * |
|
6876 |
devfsadm_root_path(void) |
|
6877 |
{ |
|
6878 |
if (root_dir[0] == '\0') { |
|
6879 |
return ("/"); |
|
6880 |
} else { |
|
6881 |
return ((const char *)root_dir); |
|
6882 |
} |
|
6883 |
} |
|
6884 |
||
2587
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6885 |
void |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6886 |
devfsadm_free_dev_names(char **dev_names, int len) |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6887 |
{ |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6888 |
int i; |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6889 |
|
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6890 |
for (i = 0; i < len; i++) |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6891 |
free(dev_names[i]); |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6892 |
free(dev_names); |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6893 |
} |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6894 |
|
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6895 |
/* |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6896 |
* Return all devlinks corresponding to phys_path as an array of strings. |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6897 |
* The number of entries in the array is returned through lenp. |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6898 |
* devfsadm_free_dev_names() is used to free the returned array. |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6899 |
* NULL is returned on failure or when there are no matching devlinks. |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6900 |
* |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6901 |
* re is an extended regular expression in regex(5) format used to further |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6902 |
* match devlinks pointing to phys_path; it may be NULL to match all |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6903 |
*/ |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6904 |
char ** |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6905 |
devfsadm_lookup_dev_names(char *phys_path, char *re, int *lenp) |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6906 |
{ |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6907 |
struct devlink_cb_arg cb_arg; |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6908 |
char **dev_names = NULL; |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6909 |
int i; |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6910 |
|
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6911 |
*lenp = 0; |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6912 |
cb_arg.count = 0; |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6913 |
cb_arg.rv = 0; |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6914 |
(void) di_devlink_cache_walk(devlink_cache, re, phys_path, |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6915 |
DI_PRIMARY_LINK, &cb_arg, devlink_cb); |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6916 |
|
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6917 |
if (cb_arg.rv == -1 || cb_arg.count <= 0) |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6918 |
return (NULL); |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6919 |
|
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6920 |
dev_names = s_malloc(cb_arg.count * sizeof (char *)); |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6921 |
if (dev_names == NULL) |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6922 |
goto out; |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6923 |
|
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6924 |
for (i = 0; i < cb_arg.count; i++) { |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6925 |
dev_names[i] = s_strdup(cb_arg.dev_names[i]); |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6926 |
if (dev_names[i] == NULL) { |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6927 |
devfsadm_free_dev_names(dev_names, i); |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6928 |
dev_names = NULL; |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6929 |
goto out; |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6930 |
} |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6931 |
} |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6932 |
*lenp = cb_arg.count; |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6933 |
|
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6934 |
out: |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6935 |
free_dev_names(&cb_arg); |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6936 |
return (dev_names); |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6937 |
} |
93d8b810a71d
6425514 Invalid slot number message on FF2 could be hardware programming issue
pjha
parents:
2441
diff
changeset
|
6938 |
|
0 | 6939 |
/* common exit function which ensures releasing locks */ |
6940 |
static void |
|
6941 |
devfsadm_exit(int status) |
|
6942 |
{ |
|
6943 |
if (DEVFSADM_DEBUG_ON) { |
|
6944 |
vprint(INFO_MID, "exit status = %d\n", status); |
|
6945 |
} |
|
6946 |
||
6947 |
if (rcm_hdl) { |
|
6948 |
if (thr_self() != process_rcm_events_tid) { |
|
6949 |
(void) mutex_lock(&rcm_eventq_lock); |
|
6950 |
need_to_exit_rcm_event_thread = 1; |
|
6951 |
(void) cond_broadcast(&rcm_eventq_cv); |
|
6952 |
(void) mutex_unlock(&rcm_eventq_lock); |
|
6953 |
||
6954 |
/* wait until process_rcm_events() thread exits */ |
|
6955 |
(void) thr_join(process_rcm_events_tid, NULL, NULL); |
|
6956 |
} |
|
6957 |
librcm_free_handle(rcm_hdl); |
|
6958 |
(void) dlclose(librcm_hdl); |
|
6959 |
} |
|
6960 |
||
6961 |
exit_dev_lock(); |
|
6962 |
exit_daemon_lock(); |
|
6963 |
||
6964 |
if (logflag == TRUE) { |
|
6965 |
closelog(); |
|
6966 |
} |
|
6967 |
||
6968 |
exit(status); |
|
6969 |
} |
|
6970 |
||
6971 |
/* |
|
2621 | 6972 |
* set root_dir, devices_dir, dev_dir using optarg. |
0 | 6973 |
*/ |
6974 |
static void |
|
2621 | 6975 |
set_root_devices_dev_dir(char *dir) |
0 | 6976 |
{ |
6977 |
size_t len; |
|
6978 |
||
6979 |
root_dir = s_strdup(dir); |
|
6980 |
len = strlen(dir) + strlen(DEVICES) + 1; |
|
6981 |
devices_dir = s_malloc(len); |
|
6982 |
(void) snprintf(devices_dir, len, "%s%s", root_dir, DEVICES); |
|
6983 |
len = strlen(root_dir) + strlen(DEV) + 1; |
|
6984 |
dev_dir = s_malloc(len); |
|
6985 |
(void) snprintf(dev_dir, len, "%s%s", root_dir, DEV); |
|
6986 |
} |
|
6987 |
||
6988 |
/* |
|
6989 |
* Removes quotes. |
|
6990 |
*/ |
|
6991 |
static char * |
|
6992 |
dequote(char *src) |
|
6993 |
{ |
|
6994 |
char *dst; |
|
6995 |
int len; |
|
6996 |
||
6997 |
len = strlen(src); |
|
6998 |
dst = s_malloc(len + 1); |
|
6999 |
if (src[0] == '\"' && src[len - 1] == '\"') { |
|
7000 |
len -= 2; |
|
7001 |
(void) strncpy(dst, &src[1], len); |
|
7002 |
dst[len] = '\0'; |
|
7003 |
} else { |
|
7004 |
(void) strcpy(dst, src); |
|
7005 |
} |
|
7006 |
return (dst); |
|
7007 |
} |
|
7008 |
||
7009 |
/* |
|
7010 |
* For a given physical device pathname and spectype, return the |
|
7011 |
* ownership and permissions attributes by looking in data from |
|
7012 |
* /etc/minor_perm. If currently in installation mode, check for |
|
7013 |
* possible major number translations from the miniroot to the installed |
|
7014 |
* root's name_to_major table. Note that there can be multiple matches, |
|
7015 |
* but the last match takes effect. pts seems to rely on this |
|
7016 |
* implementation behavior. |
|
7017 |
*/ |
|
7018 |
static void |
|
7019 |
getattr(char *phy_path, char *aminor, int spectype, dev_t dev, mode_t *mode, |
|
7020 |
uid_t *uid, gid_t *gid) |
|
7021 |
{ |
|
7022 |
char devname[PATH_MAX + 1]; |
|
7023 |
char *node_name; |
|
7024 |
char *minor_name; |
|
7025 |
int match = FALSE; |
|
7026 |
int is_clone; |
|
7027 |
int mp_drvname_matches_node_name; |
|
7028 |
int mp_drvname_matches_minor_name; |
|
7029 |
int mp_drvname_is_clone; |
|
7030 |
int mp_drvname_matches_drvname; |
|
7031 |
struct mperm *mp; |
|
7032 |
major_t major_no; |
|
7033 |
char driver[PATH_MAX + 1]; |
|
7034 |
||
7035 |
/* |
|
7036 |
* Get the driver name based on the major number since the name |
|
7037 |
* in /devices may be generic. Could be running with more major |
|
7038 |
* numbers than are in /etc/name_to_major, so get it from the kernel |
|
7039 |
*/ |
|
7040 |
major_no = major(dev); |
|
7041 |
||
7042 |
if (modctl(MODGETNAME, driver, sizeof (driver), &major_no) != 0) { |
|
7043 |
/* return default values */ |
|
7044 |
goto use_defaults; |
|
7045 |
} |
|
7046 |
||
7047 |
(void) strcpy(devname, phy_path); |
|
7048 |
||
7049 |
node_name = strrchr(devname, '/'); /* node name is the last */ |
|
7050 |
/* component */ |
|
7051 |
if (node_name == NULL) { |
|
7052 |
err_print(NO_NODE, devname); |
|
7053 |
goto use_defaults; |
|
7054 |
} |
|
7055 |
||
7056 |
minor_name = strchr(++node_name, '@'); /* see if it has address part */ |
|
7057 |
||
7058 |
if (minor_name != NULL) { |
|
7059 |
*minor_name++ = '\0'; |
|
7060 |
} else { |
|
7061 |
minor_name = node_name; |
|
7062 |
} |
|
7063 |
||
7064 |
minor_name = strchr(minor_name, ':'); /* look for minor name */ |
|
7065 |
||
7066 |
if (minor_name == NULL) { |
|
7067 |
err_print(NO_MINOR, devname); |
|
7068 |
goto use_defaults; |
|
7069 |
} |
|
7070 |
*minor_name++ = '\0'; |
|
7071 |
||
7072 |
/* |
|
7073 |
* mp->mp_drvname = device name from minor_perm |
|
7074 |
* mp->mp_minorname = minor part of device name from |
|
7075 |
* minor_perm |
|
7076 |
* drvname = name of driver for this device |
|
7077 |
*/ |
|
7078 |
||
7079 |
is_clone = (strcmp(node_name, "clone") == 0 ? TRUE : FALSE); |
|
7080 |
for (mp = minor_perms; mp != NULL; mp = mp->mp_next) { |
|
7081 |
mp_drvname_matches_node_name = |
|
7082 |
(strcmp(mp->mp_drvname, node_name) == 0 ? TRUE : FALSE); |
|
7083 |
mp_drvname_matches_minor_name = |
|
7084 |
(strcmp(mp->mp_drvname, minor_name) == 0 ? TRUE:FALSE); |
|
7085 |
mp_drvname_is_clone = |
|
7086 |
(strcmp(mp->mp_drvname, "clone") == 0 ? TRUE : FALSE); |
|
7087 |
mp_drvname_matches_drvname = |
|
7088 |
(strcmp(mp->mp_drvname, driver) == 0 ? TRUE : FALSE); |
|
7089 |
||
7090 |
/* |
|
7091 |
* If one of the following cases is true, then we try to change |
|
7092 |
* the permissions if a "shell global pattern match" of |
|
7093 |
* mp_>mp_minorname matches minor_name. |
|
7094 |
* |
|
7095 |
* 1. mp->mp_drvname matches driver. |
|
7096 |
* |
|
7097 |
* OR |
|
7098 |
* |
|
7099 |
* 2. mp->mp_drvname matches node_name and this |
|
7100 |
* name is an alias of the driver name |
|
7101 |
* |
|
7102 |
* OR |
|
7103 |
* |
|
7104 |
* 3. /devices entry is the clone device and either |
|
7105 |
* minor_perm entry is the clone device or matches |
|
7106 |
* the minor part of the clone device. |
|
7107 |
*/ |
|
7108 |
||
7109 |
if ((mp_drvname_matches_drvname == TRUE)|| |
|
7110 |
((mp_drvname_matches_node_name == TRUE) && |
|
7111 |
(alias(driver, node_name) == TRUE)) || |
|
7112 |
((is_clone == TRUE) && |
|
7113 |
((mp_drvname_is_clone == TRUE) || |
|
7114 |
(mp_drvname_matches_minor_name == TRUE)))) { |
|
7115 |
/* |
|
7116 |
* Check that the minor part of the |
|
7117 |
* device name from the minor_perm |
|
7118 |
* entry matches and if so, set the |
|
7119 |
* permissions. |
|
7120 |
* |
|
7121 |
* Under real devfs, clone minor name is changed |
|
7122 |
* to match the driver name, but minor_perm may |
|
7123 |
* not match. We reconcile it here. |
|
7124 |
*/ |
|
7125 |
if (aminor != NULL) |
|
7126 |
minor_name = aminor; |
|
7127 |
||
7128 |
if (gmatch(minor_name, mp->mp_minorname) != 0) { |
|
7129 |
*uid = mp->mp_uid; |
|
7130 |
*gid = mp->mp_gid; |
|
7131 |
*mode = spectype | mp->mp_mode; |
|
7132 |
match = TRUE; |
|
7133 |
} |
|
7134 |
} |
|
7135 |
} |
|
7136 |
||
7137 |
if (match == TRUE) { |
|
7138 |
return; |
|
7139 |
} |
|
7140 |
||
7141 |
use_defaults: |
|
7142 |
/* not found in minor_perm, so just use default values */ |
|
7143 |
*uid = root_uid; |
|
7144 |
*gid = sys_gid; |
|
7145 |
*mode = (spectype | 0600); |
|
7146 |
} |
|
7147 |
||
7148 |
/* |
|
7149 |
* Called by devfs_read_minor_perm() to report errors |
|
7150 |
* key is: |
|
7151 |
* line number: ignoring line number error |
|
7152 |
* errno: open/close errors |
|
7153 |
* size: alloc errors |
|
7154 |
*/ |
|
7155 |
static void |
|
7156 |
minorperm_err_cb(minorperm_err_t mp_err, int key) |
|
7157 |
{ |
|
7158 |
switch (mp_err) { |
|
7159 |
case MP_FOPEN_ERR: |
|
7160 |
err_print(FOPEN_FAILED, MINOR_PERM_FILE, strerror(key)); |
|
7161 |
break; |
|
7162 |
case MP_FCLOSE_ERR: |
|
7163 |
err_print(FCLOSE_FAILED, MINOR_PERM_FILE, strerror(key)); |
|
7164 |
break; |
|
7165 |
case MP_IGNORING_LINE_ERR: |
|
7166 |
err_print(IGNORING_LINE_IN, key, MINOR_PERM_FILE); |
|
7167 |
break; |
|
7168 |
case MP_ALLOC_ERR: |
|
7169 |
err_print(MALLOC_FAILED, key); |
|
7170 |
break; |
|
7171 |
case MP_NVLIST_ERR: |
|
7172 |
err_print(NVLIST_ERROR, MINOR_PERM_FILE, strerror(key)); |
|
7173 |
break; |
|
7174 |
case MP_CANT_FIND_USER_ERR: |
|
7175 |
err_print(CANT_FIND_USER, DEFAULT_DEV_USER); |
|
7176 |
break; |
|
7177 |
case MP_CANT_FIND_GROUP_ERR: |
|
7178 |
err_print(CANT_FIND_GROUP, DEFAULT_DEV_GROUP); |
|
7179 |
break; |
|
7180 |
} |
|
7181 |
} |
|
7182 |
||
7183 |
static void |
|
7184 |
read_minor_perm_file(void) |
|
7185 |
{ |
|
7186 |
static int cached = FALSE; |
|
7187 |
static struct stat cached_sb; |
|
7188 |
struct stat current_sb; |
|
7189 |
||
7190 |
(void) stat(MINOR_PERM_FILE, ¤t_sb); |
|
7191 |
||
7192 |
/* If already cached, check to see if it is still valid */ |
|
7193 |
if (cached == TRUE) { |
|
7194 |
||
7195 |
if (current_sb.st_mtime == cached_sb.st_mtime) { |
|
7196 |
vprint(FILES_MID, "%s cache valid\n", MINOR_PERM_FILE); |
|
7197 |
return; |
|
7198 |
} |
|
7199 |
devfs_free_minor_perm(minor_perms); |
|
7200 |
minor_perms = NULL; |
|
7201 |
} else { |
|
7202 |
cached = TRUE; |
|
7203 |
} |
|
7204 |
||
7205 |
(void) stat(MINOR_PERM_FILE, &cached_sb); |
|
7206 |
||
7207 |
vprint(FILES_MID, "loading binding file: %s\n", MINOR_PERM_FILE); |
|
7208 |
||
7209 |
minor_perms = devfs_read_minor_perm(minorperm_err_cb); |
|
7210 |
} |
|
7211 |
||
7212 |
static void |
|
7213 |
load_minor_perm_file(void) |
|
7214 |
{ |
|
7215 |
read_minor_perm_file(); |
|
7216 |
if (devfs_load_minor_perm(minor_perms, minorperm_err_cb) != 0) |
|
7217 |
err_print(gettext("minor_perm load failed\n")); |
|
7218 |
} |
|
7219 |
||
7220 |
static char * |
|
7221 |
convert_to_re(char *dev) |
|
7222 |
{ |
|
7223 |
char *p, *l, *out; |
|
7224 |
int i; |
|
7225 |
||
7226 |
out = s_malloc(PATH_MAX); |
|
7227 |
||
7228 |
for (l = p = dev, i = 0; (*p != '\0') && (i < (PATH_MAX - 1)); |
|
7229 |
++p, i++) { |
|
7230 |
if ((*p == '*') && ((l != p) && (*l == '/'))) { |
|
7231 |
out[i++] = '.'; |
|
7232 |
out[i] = '+'; |
|
7233 |
} else { |
|
7234 |
out[i] = *p; |
|
7235 |
} |
|
7236 |
l = p; |
|
7237 |
} |
|
7238 |
out[i] = '\0'; |
|
7239 |
p = (char *)s_malloc(strlen(out) + 1); |
|
7240 |
(void) strlcpy(p, out, strlen(out) + 1); |
|
7241 |
free(out); |
|
7242 |
||
7243 |
vprint(FILES_MID, "converted %s -> %s\n", dev, p); |
|
7244 |
||
7245 |
return (p); |
|
7246 |
} |
|
7247 |
||
7248 |
static void |
|
7249 |
read_logindevperm_file(void) |
|
7250 |
{ |
|
7251 |
static int cached = FALSE; |
|
7252 |
static struct stat cached_sb; |
|
7253 |
struct stat current_sb; |
|
7254 |
struct login_dev *ldev; |
|
7255 |
FILE *fp; |
|
7256 |
char line[MAX_LDEV_LINE]; |
|
7257 |
int ln, perm, rv; |
|
4400
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
7258 |
char *cp, *console, *dlist, *dev; |
0 | 7259 |
char *lasts, *devlasts, *permstr, *drv; |
7260 |
struct driver_list *list, *next; |
|
7261 |
||
7262 |
/* Read logindevperm only when enabled */ |
|
7263 |
if (login_dev_enable != TRUE) |
|
7264 |
return; |
|
7265 |
||
7266 |
if (cached == TRUE) { |
|
7267 |
if (stat(LDEV_FILE, ¤t_sb) == 0 && |
|
7268 |
current_sb.st_mtime == cached_sb.st_mtime) { |
|
7269 |
vprint(FILES_MID, "%s cache valid\n", LDEV_FILE); |
|
7270 |
return; |
|
7271 |
} |
|
7272 |
vprint(FILES_MID, "invalidating %s cache\n", LDEV_FILE); |
|
7273 |
while (login_dev_cache != NULL) { |
|
7274 |
||
7275 |
ldev = login_dev_cache; |
|
7276 |
login_dev_cache = ldev->ldev_next; |
|
7277 |
free(ldev->ldev_console); |
|
7278 |
free(ldev->ldev_device); |
|
7279 |
regfree(&ldev->ldev_device_regex); |
|
7280 |
list = ldev->ldev_driver_list; |
|
7281 |
while (list) { |
|
7282 |
next = list->next; |
|
7283 |
free(list); |
|
7284 |
list = next; |
|
7285 |
} |
|
7286 |
free(ldev); |
|
7287 |
} |
|
7288 |
} else { |
|
7289 |
cached = TRUE; |
|
7290 |
} |
|
7291 |
||
7292 |
assert(login_dev_cache == NULL); |
|
7293 |
||
7294 |
if (stat(LDEV_FILE, &cached_sb) != 0) { |
|
7295 |
cached = FALSE; |
|
7296 |
return; |
|
7297 |
} |
|
7298 |
||
7299 |
vprint(FILES_MID, "loading file: %s\n", LDEV_FILE); |
|
7300 |
||
7301 |
if ((fp = fopen(LDEV_FILE, "r")) == NULL) { |
|
7302 |
/* Not fatal to devfsadm */ |
|
7303 |
cached = FALSE; |
|
7304 |
err_print(FOPEN_FAILED, LDEV_FILE, strerror(errno)); |
|
7305 |
return; |
|
7306 |
} |
|
7307 |
||
7308 |
ln = 0; |
|
7309 |
while (fgets(line, MAX_LDEV_LINE, fp) != NULL) { |
|
7310 |
ln++; |
|
7311 |
||
7312 |
/* Remove comments */ |
|
7313 |
if ((cp = strchr(line, '#')) != NULL) |
|
7314 |
*cp = '\0'; |
|
7315 |
||
7316 |
if ((console = strtok_r(line, LDEV_DELIMS, &lasts)) == NULL) |
|
7317 |
continue; /* Blank line */ |
|
7318 |
||
7319 |
if ((permstr = strtok_r(NULL, LDEV_DELIMS, &lasts)) == NULL) { |
|
7320 |
err_print(IGNORING_LINE_IN, ln, LDEV_FILE); |
|
7321 |
continue; /* Malformed line */ |
|
7322 |
} |
|
7323 |
||
7324 |
/* |
|
7325 |
* permstr is string in octal format. Convert to int |
|
7326 |
*/ |
|
7327 |
cp = NULL; |
|
7328 |
errno = 0; |
|
7329 |
perm = strtol(permstr, &cp, 8); |
|
7330 |
if (errno || perm < 0 || perm > 0777 || *cp != '\0') { |
|
7331 |
err_print(IGNORING_LINE_IN, ln, LDEV_FILE); |
|
7332 |
continue; |
|
7333 |
} |
|
7334 |
||
4400
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
7335 |
if ((dlist = strtok_r(NULL, LDEV_DELIMS, &lasts)) == NULL) { |
0 | 7336 |
err_print(IGNORING_LINE_IN, ln, LDEV_FILE); |
7337 |
continue; |
|
7338 |
} |
|
7339 |
||
4400
a2a727ce4dcc
6486759 TX - hot plugging USB device can lead to inaccessible cdrom
aj
parents:
4211
diff
changeset
|
7340 |
dev = strtok_r(dlist, LDEV_DEV_DELIM, &devlasts); |
0 | 7341 |
while (dev) { |
7342 |
||
7343 |
ldev = (struct login_dev *)s_zalloc( |
|
7344 |
sizeof (struct login_dev)); |
|
7345 |
ldev->ldev_console = s_strdup(console); |
|
7346 |
ldev->ldev_perms = perm; |
|
7347 |
||
7348 |
/* |
|
7349 |
* the logical device name may contain '*' which |
|
7350 |
* we convert to a regular expression |
|
7351 |
*/ |
|
7352 |
ldev->ldev_device = convert_to_re(dev); |
|
7353 |
if (ldev->ldev_device && |
|
7354 |
(rv = regcomp(&ldev->ldev_device_regex, |
|
7355 |
ldev->ldev_device, REG_EXTENDED))) { |
|
7356 |
bzero(&ldev->ldev_device_regex, |
|
7357 |
sizeof (ldev->ldev_device_regex)); |
|
7358 |
err_print(REGCOMP_FAILED, |
|
7359 |
ldev->ldev_device, rv); |
|
7360 |
} |
|
7361 |
ldev->ldev_next = login_dev_cache; |
|
7362 |
login_dev_cache = ldev; |
|
7363 |
dev = strtok_r(NULL, LDEV_DEV_DELIM, &devlasts); |
|
7364 |
} |
|
7365 |
||
7366 |
drv = strtok_r(NULL, LDEV_DRVLIST_DELIMS, &lasts); |
|
7367 |
if (drv) { |
|
7368 |
if (strcmp(drv, LDEV_DRVLIST_NAME) == 0) { |
|
7369 |
||
7370 |
drv = strtok_r(NULL, LDEV_DRV_DELIMS, |
|
7371 |
&lasts); |
|
7372 |
||
7373 |
while (drv) { |
|
7374 |
vprint(FILES_MID, |
|
7375 |
"logindevperm driver=%s\n", |
|
7376 |
drv); |
|
7377 |
||
7378 |
/* |
|
7379 |
* create a linked list of driver |
|
7380 |
* names |
|
7381 |
*/ |
|
7382 |
list = (struct driver_list *) |
|
7383 |
s_zalloc( |
|
7384 |
sizeof (struct driver_list)); |
|
7385 |
(void) strlcpy(list->driver_name, drv, |
|
7386 |
sizeof (list->driver_name)); |
|
7387 |
list->next = ldev->ldev_driver_list; |
|
7388 |
ldev->ldev_driver_list = list; |
|
7389 |
drv = strtok_r(NULL, LDEV_DRV_DELIMS, |
|
7390 |
&lasts); |
|
7391 |
} |
|
7392 |
} |
|
7393 |
} |
|
7394 |
} |
|
7395 |
(void) fclose(fp); |
|
7396 |
} |
|
7397 |
||
7398 |
/* |
|
7399 |
* Tokens are separated by ' ', '\t', ':', '=', '&', '|', ';', '\n', or '\0' |
|
7400 |
* |
|
7401 |
* Returns DEVFSADM_SUCCESS if token found, DEVFSADM_FAILURE otherwise. |
|
7402 |
*/ |
|
7403 |
static int |
|
7404 |
getnexttoken(char *next, char **nextp, char **tokenpp, char *tchar) |
|
7405 |
{ |
|
7406 |
char *cp; |
|
7407 |
char *cp1; |
|
7408 |
char *tokenp; |
|
7409 |
||
7410 |
cp = next; |
|
7411 |
while (*cp == ' ' || *cp == '\t') { |
|
7412 |
cp++; /* skip leading spaces */ |
|
7413 |
} |
|
7414 |
tokenp = cp; /* start of token */ |
|
7415 |
while (*cp != '\0' && *cp != '\n' && *cp != ' ' && *cp != '\t' && |
|
7416 |
*cp != ':' && *cp != '=' && *cp != '&' && |
|
7417 |
*cp != '|' && *cp != ';') { |
|
7418 |
cp++; /* point to next character */ |
|
7419 |
} |
|
7420 |
/* |
|
7421 |
* If terminating character is a space or tab, look ahead to see if |
|
7422 |
* there's another terminator that's not a space or a tab. |
|
7423 |
* (This code handles trailing spaces.) |
|
7424 |
*/ |
|
7425 |
if (*cp == ' ' || *cp == '\t') { |
|
7426 |
cp1 = cp; |
|
7427 |
while (*++cp1 == ' ' || *cp1 == '\t') |
|
7428 |
; |
|
7429 |
if (*cp1 == '=' || *cp1 == ':' || *cp1 == '&' || *cp1 == '|' || |
|
7430 |
*cp1 == ';' || *cp1 == '\n' || *cp1 == '\0') { |
|
7431 |
*cp = NULL; /* terminate token */ |
|
7432 |
cp = cp1; |
|
7433 |
} |
|
7434 |
} |
|
7435 |
if (tchar != NULL) { |
|
7436 |
*tchar = *cp; /* save terminating character */ |
|
7437 |
if (*tchar == '\0') { |
|
7438 |
*tchar = '\n'; |
|
7439 |
} |
|
7440 |
} |
|
7441 |
*cp++ = '\0'; /* terminate token, point to next */ |
|
7442 |
*nextp = cp; /* set pointer to next character */ |
|
7443 |
if (cp - tokenp - 1 == 0) { |
|
7444 |
return (DEVFSADM_FAILURE); |
|
7445 |
} |
|
7446 |
*tokenpp = tokenp; |
|
7447 |
return (DEVFSADM_SUCCESS); |
|
7448 |
} |
|
7449 |
||
7450 |
/* |
|
7451 |
* read or reread the driver aliases file |
|
7452 |
*/ |
|
7453 |
static void |
|
7454 |
read_driver_aliases_file(void) |
|
7455 |
{ |
|
7456 |
||
7457 |
driver_alias_t *save; |
|
7458 |
driver_alias_t *lst_tail; |
|
7459 |
driver_alias_t *ap; |
|
7460 |
static int cached = FALSE; |
|
7461 |
FILE *afd; |
|
7462 |
char line[256]; |
|
7463 |
char *cp; |
|
7464 |
char *p; |
|
7465 |
char t; |
|
7466 |
int ln = 0; |
|
7467 |
static struct stat cached_sb; |
|
7468 |
struct stat current_sb; |
|
7469 |
||
7470 |
(void) stat(ALIASFILE, ¤t_sb); |
|
7471 |
||
7472 |
/* If already cached, check to see if it is still valid */ |
|
7473 |
if (cached == TRUE) { |
|
7474 |
||
7475 |
if (current_sb.st_mtime == cached_sb.st_mtime) { |
|
7476 |
vprint(FILES_MID, "%s cache valid\n", ALIASFILE); |
|
7477 |
return; |
|
7478 |
} |
|
7479 |
||
7480 |
vprint(FILES_MID, "invalidating %s cache\n", ALIASFILE); |
|
7481 |
while (driver_aliases != NULL) { |
|
7482 |
free(driver_aliases->alias_name); |
|
7483 |
free(driver_aliases->driver_name); |
|
7484 |
save = driver_aliases; |
|
7485 |
driver_aliases = driver_aliases->next; |
|
7486 |
free(save); |
|
7487 |
} |
|
7488 |
} else { |
|
7489 |
cached = TRUE; |
|
7490 |
} |
|
7491 |
||
7492 |
(void) stat(ALIASFILE, &cached_sb); |
|
7493 |
||
7494 |
vprint(FILES_MID, "loading binding file: %s\n", ALIASFILE); |
|
7495 |
||
7496 |
if ((afd = fopen(ALIASFILE, "r")) == NULL) { |
|
7497 |
err_print(FOPEN_FAILED, ALIASFILE, strerror(errno)); |
|
7498 |
devfsadm_exit(1); |
|
7499 |
} |
|
7500 |
||
2805
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
7501 |
while (fgets(line, sizeof (line), afd) != NULL) { |
0 | 7502 |
ln++; |
2805
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
7503 |
/* cut off comments starting with '#' */ |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
7504 |
if ((cp = strchr(line, '#')) != NULL) |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
7505 |
*cp = '\0'; |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
7506 |
/* ignore comment or blank lines */ |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
7507 |
if (is_blank(line)) |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
7508 |
continue; |
0 | 7509 |
cp = line; |
7510 |
if (getnexttoken(cp, &cp, &p, &t) == DEVFSADM_FAILURE) { |
|
7511 |
err_print(IGNORING_LINE_IN, ln, ALIASFILE); |
|
7512 |
continue; |
|
7513 |
} |
|
7514 |
if (t == '\n' || t == '\0') { |
|
7515 |
err_print(DRV_BUT_NO_ALIAS, ln, ALIASFILE); |
|
7516 |
continue; |
|
7517 |
} |
|
7518 |
ap = (struct driver_alias *) |
|
7519 |
s_zalloc(sizeof (struct driver_alias)); |
|
7520 |
ap->driver_name = s_strdup(p); |
|
7521 |
if (getnexttoken(cp, &cp, &p, &t) == DEVFSADM_FAILURE) { |
|
7522 |
err_print(DRV_BUT_NO_ALIAS, ln, ALIASFILE); |
|
7523 |
free(ap->driver_name); |
|
7524 |
free(ap); |
|
7525 |
continue; |
|
7526 |
} |
|
7527 |
if (*p == '"') { |
|
7528 |
if (p[strlen(p) - 1] == '"') { |
|
7529 |
p[strlen(p) - 1] = '\0'; |
|
7530 |
p++; |
|
7531 |
} |
|
7532 |
} |
|
7533 |
ap->alias_name = s_strdup(p); |
|
7534 |
if (driver_aliases == NULL) { |
|
7535 |
driver_aliases = ap; |
|
7536 |
lst_tail = ap; |
|
7537 |
} else { |
|
7538 |
lst_tail->next = ap; |
|
7539 |
lst_tail = ap; |
|
7540 |
} |
|
7541 |
} |
|
7542 |
if (fclose(afd) == EOF) { |
|
7543 |
err_print(FCLOSE_FAILED, ALIASFILE, strerror(errno)); |
|
7544 |
} |
|
7545 |
} |
|
7546 |
||
7547 |
/* |
|
7548 |
* return TRUE if alias_name is an alias for driver_name, otherwise |
|
7549 |
* return FALSE. |
|
7550 |
*/ |
|
7551 |
static int |
|
7552 |
alias(char *driver_name, char *alias_name) |
|
7553 |
{ |
|
7554 |
driver_alias_t *alias; |
|
7555 |
||
7556 |
/* |
|
7557 |
* check for a match |
|
7558 |
*/ |
|
7559 |
for (alias = driver_aliases; alias != NULL; alias = alias->next) { |
|
7560 |
if ((strcmp(alias->driver_name, driver_name) == 0) && |
|
7561 |
(strcmp(alias->alias_name, alias_name) == 0)) { |
|
7562 |
return (TRUE); |
|
7563 |
} |
|
7564 |
} |
|
7565 |
return (FALSE); |
|
7566 |
} |
|
7567 |
||
7568 |
/* |
|
7569 |
* convenience functions |
|
7570 |
*/ |
|
2621 | 7571 |
static int |
7572 |
s_stat(const char *path, struct stat *sbufp) |
|
7573 |
{ |
|
7574 |
int rv; |
|
7575 |
retry: |
|
7576 |
if ((rv = stat(path, sbufp)) == -1) { |
|
7577 |
if (errno == EINTR) |
|
7578 |
goto retry; |
|
7579 |
} |
|
7580 |
return (rv); |
|
7581 |
} |
|
7582 |
||
0 | 7583 |
static void * |
7584 |
s_malloc(const size_t size) |
|
7585 |
{ |
|
7586 |
void *rp; |
|
7587 |
||
7588 |
rp = malloc(size); |
|
7589 |
if (rp == NULL) { |
|
7590 |
err_print(MALLOC_FAILED, size); |
|
7591 |
devfsadm_exit(1); |
|
7592 |
} |
|
7593 |
return (rp); |
|
7594 |
} |
|
7595 |
||
7596 |
/* |
|
7597 |
* convenience functions |
|
7598 |
*/ |
|
7599 |
static void * |
|
7600 |
s_realloc(void *ptr, const size_t size) |
|
7601 |
{ |
|
7602 |
ptr = realloc(ptr, size); |
|
7603 |
if (ptr == NULL) { |
|
7604 |
err_print(REALLOC_FAILED, size); |
|
7605 |
devfsadm_exit(1); |
|
7606 |
} |
|
7607 |
return (ptr); |
|
7608 |
} |
|
7609 |
||
7610 |
static void * |
|
7611 |
s_zalloc(const size_t size) |
|
7612 |
{ |
|
7613 |
void *rp; |
|
7614 |
||
7615 |
rp = calloc(1, size); |
|
7616 |
if (rp == NULL) { |
|
7617 |
err_print(CALLOC_FAILED, size); |
|
7618 |
devfsadm_exit(1); |
|
7619 |
} |
|
7620 |
return (rp); |
|
7621 |
} |
|
7622 |
||
7623 |
char * |
|
7624 |
s_strdup(const char *ptr) |
|
7625 |
{ |
|
7626 |
void *rp; |
|
7627 |
||
7628 |
rp = strdup(ptr); |
|
7629 |
if (rp == NULL) { |
|
7630 |
err_print(STRDUP_FAILED, ptr); |
|
7631 |
devfsadm_exit(1); |
|
7632 |
} |
|
7633 |
return (rp); |
|
7634 |
} |
|
7635 |
||
7636 |
static void |
|
7637 |
s_closedir(DIR *dirp) |
|
7638 |
{ |
|
7639 |
retry: |
|
7640 |
if (closedir(dirp) != 0) { |
|
7641 |
if (errno == EINTR) |
|
7642 |
goto retry; |
|
7643 |
err_print(CLOSEDIR_FAILED, strerror(errno)); |
|
7644 |
} |
|
7645 |
} |
|
7646 |
||
7647 |
static void |
|
7648 |
s_mkdirp(const char *path, const mode_t mode) |
|
7649 |
{ |
|
7650 |
vprint(CHATTY_MID, "mkdirp(%s, 0x%lx)\n", path, mode); |
|
7651 |
if (mkdirp(path, mode) == -1) { |
|
7652 |
if (errno != EEXIST) { |
|
7653 |
err_print(MKDIR_FAILED, path, mode, strerror(errno)); |
|
7654 |
} |
|
7655 |
} |
|
7656 |
} |
|
7657 |
||
7658 |
static void |
|
7659 |
s_unlink(const char *file) |
|
7660 |
{ |
|
7661 |
retry: |
|
7662 |
if (unlink(file) == -1) { |
|
7663 |
if (errno == EINTR || errno == EAGAIN) |
|
7664 |
goto retry; |
|
7665 |
if (errno != ENOENT) { |
|
7666 |
err_print(UNLINK_FAILED, file, strerror(errno)); |
|
7667 |
} |
|
7668 |
} |
|
7669 |
} |
|
7670 |
||
7671 |
static void |
|
7672 |
add_verbose_id(char *mid) |
|
7673 |
{ |
|
7674 |
num_verbose++; |
|
7675 |
verbose = s_realloc(verbose, num_verbose * sizeof (char *)); |
|
7676 |
verbose[num_verbose - 1] = mid; |
|
7677 |
} |
|
7678 |
||
7679 |
/* |
|
7680 |
* returns DEVFSADM_TRUE if contents is a minor node in /devices. |
|
7681 |
* If mn_root is not NULL, mn_root is set to: |
|
7682 |
* if contents is a /dev node, mn_root = contents |
|
7683 |
* OR |
|
7684 |
* if contents is a /devices node, mn_root set to the '/' |
|
7685 |
* following /devices. |
|
7686 |
*/ |
|
7687 |
static int |
|
7688 |
is_minor_node(char *contents, char **mn_root) |
|
7689 |
{ |
|
7690 |
char *ptr; |
|
7691 |
char device_prefix[100]; |
|
7692 |
||
7693 |
(void) snprintf(device_prefix, sizeof (device_prefix), "../devices/"); |
|
7694 |
||
7695 |
if ((ptr = strstr(contents, device_prefix)) != NULL) { |
|
7696 |
if (mn_root != NULL) { |
|
7697 |
/* mn_root should point to the / following /devices */ |
|
7698 |
*mn_root = ptr += strlen(device_prefix) - 1; |
|
7699 |
} |
|
7700 |
return (DEVFSADM_TRUE); |
|
7701 |
} |
|
7702 |
||
7703 |
(void) snprintf(device_prefix, sizeof (device_prefix), "/devices/"); |
|
7704 |
||
7705 |
if (strncmp(contents, device_prefix, strlen(device_prefix)) == 0) { |
|
7706 |
if (mn_root != NULL) { |
|
7707 |
/* mn_root should point to the / following /devices */ |
|
7708 |
*mn_root = contents + strlen(device_prefix) - 1; |
|
7709 |
} |
|
7710 |
return (DEVFSADM_TRUE); |
|
7711 |
} |
|
7712 |
||
7713 |
if (mn_root != NULL) { |
|
7714 |
*mn_root = contents; |
|
7715 |
} |
|
7716 |
return (DEVFSADM_FALSE); |
|
7717 |
} |
|
7718 |
||
7719 |
/* |
|
7720 |
* Lookup nvpair corresponding to the given name and type: |
|
7721 |
* |
|
7722 |
* The standard nvlist_lookup functions in libnvpair don't work as our |
|
7723 |
* nvlist is not allocated with NV_UNIQUE_NAME or NV_UNIQUE_NAME_TYPE. |
|
7724 |
*/ |
|
7725 |
static nvpair_t * |
|
7726 |
lookup_nvpair(nvlist_t *nvl, char *name, data_type_t type) |
|
7727 |
{ |
|
7728 |
nvpair_t *nvp; |
|
7729 |
||
7730 |
for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; |
|
7731 |
nvp = nvlist_next_nvpair(nvl, nvp)) { |
|
7732 |
if (strcmp(name, nvpair_name(nvp)) == 0 && |
|
7733 |
nvpair_type(nvp) == type) |
|
7734 |
return (nvp); |
|
7735 |
} |
|
7736 |
||
7737 |
return (NULL); |
|
7738 |
} |
|
7739 |
||
7740 |
/*ARGSUSED*/ |
|
7741 |
static void |
|
7742 |
process_rcm_events(void *arg) |
|
7743 |
{ |
|
7744 |
struct rcm_eventq *ev, *ev_next; |
|
269
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7745 |
nvpair_t *nvp; |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7746 |
char *path, *driver; |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7747 |
int instance; |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7748 |
int err; |
0 | 7749 |
int need_to_exit; |
7750 |
||
7751 |
for (;;) { |
|
7752 |
(void) mutex_lock(&rcm_eventq_lock); |
|
7753 |
while (rcm_eventq_head == NULL && |
|
7754 |
need_to_exit_rcm_event_thread == 0) |
|
7755 |
(void) cond_wait(&rcm_eventq_cv, &rcm_eventq_lock); |
|
7756 |
||
7757 |
need_to_exit = need_to_exit_rcm_event_thread; |
|
7758 |
ev = rcm_eventq_head; |
|
7759 |
rcm_eventq_head = rcm_eventq_tail = NULL; |
|
7760 |
(void) mutex_unlock(&rcm_eventq_lock); |
|
7761 |
||
7762 |
for (; ev != NULL; ev = ev_next) { |
|
7763 |
/* |
|
7764 |
* Private notification interface to RCM: |
|
7765 |
* Do not retry the RCM notification on an error since |
|
7766 |
* we do not know whether the failure occurred in |
|
7767 |
* librcm, rcm_daemon or rcm modules or scripts. |
|
7768 |
*/ |
|
269
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7769 |
if (librcm_notify_event(rcm_hdl, |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7770 |
RCM_RESOURCE_NETWORK_NEW, 0, ev->nvl, NULL) |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7771 |
!= RCM_SUCCESS) { |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7772 |
|
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7773 |
err = errno; |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7774 |
|
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7775 |
if (((nvp = lookup_nvpair(ev->nvl, |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7776 |
RCM_NV_DEVFS_PATH, DATA_TYPE_STRING)) |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7777 |
== NULL) || |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7778 |
(nvpair_value_string(nvp, &path) != 0)) |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7779 |
path = "unknown"; |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7780 |
|
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7781 |
if (((nvp = lookup_nvpair(ev->nvl, |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7782 |
RCM_NV_DRIVER_NAME, DATA_TYPE_STRING)) |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7783 |
== NULL) || |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7784 |
(nvpair_value_string(nvp, &driver) != 0)) |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7785 |
driver = "unknown"; |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7786 |
if (((nvp = lookup_nvpair(ev->nvl, |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7787 |
RCM_NV_INSTANCE, DATA_TYPE_INT32)) |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7788 |
== NULL) || |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7789 |
(nvpair_value_int32(nvp, &instance) != 0)) |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7790 |
instance = -1; |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7791 |
|
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7792 |
err_print(RCM_NOTIFY_FAILED, path, driver, |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7793 |
instance, strerror(err)); |
7ed63f24aa15
PSARC 2005/365 Nemo drivers interface simplification
ericheng
parents:
0
diff
changeset
|
7794 |
} |
0 | 7795 |
|
7796 |
ev_next = ev->next; |
|
7797 |
nvlist_free(ev->nvl); |
|
7798 |
free(ev); |
|
7799 |
} |
|
7800 |
||
7801 |
if (need_to_exit) |
|
7802 |
return; |
|
7803 |
} |
|
7804 |
} |
|
7805 |
||
7806 |
/* |
|
7807 |
* Initialize rcm related handles and function pointers. |
|
7808 |
* Since RCM need not present in miniroot, we dlopen librcm. |
|
7809 |
*/ |
|
7810 |
static int |
|
7811 |
rcm_init(void) |
|
7812 |
{ |
|
5895
f251acdd9bdc
PSARC/2006/499 Clearview Nemo unification and vanity naming
yz147064
parents:
5032
diff
changeset
|
7813 |
#define LIBRCM_PATH "/lib/librcm.so" |
0 | 7814 |
rcm_handle_t *hdl = NULL; |
7815 |
int err; |
|
7816 |
||
7817 |
if ((librcm_hdl = dlopen(LIBRCM_PATH, RTLD_LAZY)) == NULL) { |
|
7818 |
/* |
|
7819 |
* don't log an error here, since librcm may not be present |
|
7820 |
* in miniroot. |
|
7821 |
*/ |
|
7822 |
return (-1); |
|
7823 |
} |
|
7824 |
||
7825 |
librcm_alloc_handle = (int (*)())dlsym(librcm_hdl, "rcm_alloc_handle"); |
|
7826 |
librcm_free_handle = (void (*)())dlsym(librcm_hdl, "rcm_free_handle"); |
|
7827 |
librcm_notify_event = (int (*)())dlsym(librcm_hdl, "rcm_notify_event"); |
|
7828 |
||
7829 |
if (librcm_alloc_handle == NULL || librcm_notify_event == NULL || |
|
7830 |
librcm_free_handle == NULL) { |
|
7831 |
err_print(MISSING_SYMBOLS, LIBRCM_PATH); |
|
7832 |
goto out; |
|
7833 |
} |
|
7834 |
||
7835 |
/* Initialize the rcm handle */ |
|
7836 |
if (librcm_alloc_handle(NULL, 0, NULL, &hdl) != RCM_SUCCESS) { |
|
7837 |
err_print(RCM_ALLOC_HANDLE_ERROR); |
|
7838 |
goto out; |
|
7839 |
} |
|
7840 |
||
7841 |
(void) cond_init(&rcm_eventq_cv, USYNC_THREAD, 0); |
|
7842 |
(void) mutex_init(&rcm_eventq_lock, USYNC_THREAD, 0); |
|
7843 |
||
7844 |
/* create a thread to notify RCM of events */ |
|
7845 |
if ((err = thr_create(NULL, 0, (void *(*)(void *))process_rcm_events, |
|
7846 |
NULL, 0, &process_rcm_events_tid)) != 0) { |
|
7847 |
err_print(CANT_CREATE_THREAD, "process_rcm_events", |
|
7848 |
strerror(err)); |
|
7849 |
goto out; |
|
7850 |
} |
|
7851 |
||
7852 |
rcm_hdl = hdl; |
|
7853 |
return (0); |
|
7854 |
||
7855 |
out: |
|
7856 |
if (hdl) |
|
7857 |
librcm_free_handle(hdl); |
|
7858 |
(void) dlclose(librcm_hdl); |
|
7859 |
return (-1); |
|
7860 |
} |
|
7861 |
||
7862 |
/* |
|
7863 |
* Build an nvlist using the minor data. Pack it and add the packed nvlist |
|
7864 |
* as a byte array to nv_list parameter. |
|
7865 |
* Return 0 on success, errno on failure. |
|
7866 |
*/ |
|
7867 |
static int |
|
7868 |
add_minor_data_to_nvl(nvlist_t *nv_list, di_minor_t minor) |
|
7869 |
{ |
|
7870 |
nvlist_t *nvl = NULL; |
|
7871 |
int32_t minor_type; |
|
7872 |
char *minor_name, *minor_node_type; |
|
7873 |
int err; |
|
7874 |
char *buf = NULL; |
|
7875 |
size_t buflen = 0; |
|
7876 |
||
7877 |
if ((err = nvlist_alloc(&nvl, 0, 0)) != 0) |
|
7878 |
return (err); |
|
7879 |
||
7880 |
minor_type = (int32_t)di_minor_type(minor); |
|
7881 |
if ((err = nvlist_add_int32(nvl, RCM_NV_MINOR_TYPE, minor_type)) != 0) |
|
7882 |
goto error; |
|
7883 |
||
7884 |
minor_name = di_minor_name(minor); |
|
7885 |
if ((err = nvlist_add_string(nvl, RCM_NV_MINOR_NAME, minor_name)) != 0) |
|
7886 |
goto error; |
|
7887 |
||
7888 |
if ((minor_node_type = di_minor_nodetype(minor)) == NULL) |
|
7889 |
minor_node_type = ""; |
|
7890 |
if ((err = nvlist_add_string(nvl, RCM_NV_MINOR_NODE_TYPE, |
|
7891 |
minor_node_type)) != 0) |
|
7892 |
goto error; |
|
7893 |
||
7894 |
if ((err = nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_NATIVE, 0)) != 0) |
|
7895 |
goto error; |
|
7896 |
||
7897 |
err = nvlist_add_byte_array(nv_list, RCM_NV_MINOR_DATA, |
|
7898 |
(uchar_t *)(buf), (uint_t)(buflen)); |
|
7899 |
||
7900 |
error: |
|
7901 |
nvlist_free(nvl); |
|
7902 |
if (buf) |
|
7903 |
free(buf); |
|
7904 |
return (err); |
|
7905 |
} |
|
7906 |
||
7907 |
static void |
|
7908 |
enqueue_rcm_event(nvlist_t *nvl) |
|
7909 |
{ |
|
7910 |
struct rcm_eventq *ev; |
|
7911 |
||
7912 |
ev = (struct rcm_eventq *)s_zalloc(sizeof (struct rcm_eventq)); |
|
7913 |
ev->nvl = nvl; |
|
7914 |
||
7915 |
(void) mutex_lock(&rcm_eventq_lock); |
|
7916 |
if (rcm_eventq_head == NULL) |
|
7917 |
rcm_eventq_head = ev; |
|
7918 |
else |
|
7919 |
rcm_eventq_tail->next = ev; |
|
7920 |
rcm_eventq_tail = ev; |
|
7921 |
(void) cond_broadcast(&rcm_eventq_cv); |
|
7922 |
(void) mutex_unlock(&rcm_eventq_lock); |
|
7923 |
} |
|
7924 |
||
7925 |
/* |
|
7926 |
* Generate an nvlist using the information given in node and minor_name. |
|
7927 |
* If minor_name is NULL the nvlist will contain information on |
|
7928 |
* all minor nodes. Otherwise the nvlist will contain information |
|
7929 |
* only on the given minor_name. Notify RCM passing the nvlist. |
|
7930 |
* |
|
7931 |
* Return 0 upon successfully notifying RCM, errno on failure. |
|
7932 |
*/ |
|
7933 |
static int |
|
7934 |
notify_rcm(di_node_t node, char *minor_name) |
|
7935 |
{ |
|
7936 |
nvlist_t *nvl = NULL; |
|
7937 |
char *path, *driver_name; |
|
7938 |
char *node_name; |
|
7939 |
int err; |
|
7940 |
int32_t instance; |
|
7941 |
di_minor_t minor; |
|
7942 |
||
7943 |
if ((driver_name = di_driver_name(node)) == NULL) |
|
7944 |
driver_name = ""; |
|
7945 |
||
7946 |
instance = (int32_t)di_instance(node); |
|
7947 |
||
7948 |
if ((path = di_devfs_path(node)) == NULL) { |
|
7949 |
err = errno; |
|
7950 |
goto error; |
|
7951 |
} |
|
7952 |
||
7953 |
if ((err = nvlist_alloc(&nvl, 0, 0)) != 0) |
|
7954 |
goto error; |
|
7955 |
||
7956 |
if ((err = nvlist_add_string(nvl, RCM_NV_DRIVER_NAME, driver_name)) |
|
7957 |
!= 0) |
|
7958 |
goto error; |
|
7959 |
||
7960 |
if ((err = nvlist_add_int32(nvl, RCM_NV_INSTANCE, instance)) != 0) |
|
7961 |
goto error; |
|
7962 |
||
7963 |
if ((node_name = di_node_name(node)) == NULL) |
|
7964 |
node_name = ""; |
|
7965 |
if ((err = nvlist_add_string(nvl, RCM_NV_NODE_NAME, node_name)) != 0) |
|
7966 |
goto error; |
|
7967 |
||
7968 |
if ((err = nvlist_add_string(nvl, RCM_NV_DEVFS_PATH, path)) != 0) |
|
7969 |
goto error; |
|
7970 |
||
7971 |
minor = di_minor_next(node, DI_MINOR_NIL); |
|
7972 |
while (minor != DI_MINOR_NIL) { |
|
7973 |
if ((minor_name == NULL) || |
|
7974 |
(strcmp(minor_name, di_minor_name(minor)) == 0)) { |
|
7975 |
if ((err = add_minor_data_to_nvl(nvl, minor)) != 0) |
|
7976 |
goto error; |
|
7977 |
} |
|
7978 |
minor = di_minor_next(node, minor); |
|
7979 |
} |
|
7980 |
||
7981 |
enqueue_rcm_event(nvl); |
|
7982 |
di_devfs_path_free(path); |
|
7983 |
return (0); |
|
7984 |
||
7985 |
error: |
|
7986 |
err_print(RCM_NVLIST_BUILD_ERROR, ((path != NULL) ? path : "unknown"), |
|
7987 |
driver_name, instance, strerror(err)); |
|
7988 |
||
7989 |
if (path) |
|
7990 |
di_devfs_path_free(path); |
|
7991 |
if (nvl) |
|
7992 |
nvlist_free(nvl); |
|
7993 |
return (err); |
|
7994 |
} |
|
7995 |
||
7996 |
/* |
|
7997 |
* Add the specified property to nvl. |
|
7998 |
* Returns: |
|
7999 |
* 0 successfully added |
|
8000 |
* -1 an error occurred |
|
8001 |
* 1 could not add the property for reasons not due to errors. |
|
8002 |
*/ |
|
8003 |
static int |
|
8004 |
add_property(nvlist_t *nvl, di_prop_t prop) |
|
8005 |
{ |
|
8006 |
char *name; |
|
8007 |
char *attr_name; |
|
8008 |
int n, len; |
|
8009 |
int32_t *int32p; |
|
8010 |
int64_t *int64p; |
|
8011 |
char *str; |
|
8012 |
char **strarray; |
|
8013 |
uchar_t *bytep; |
|
8014 |
int rv = 0; |
|
8015 |
int i; |
|
8016 |
||
8017 |
if ((name = di_prop_name(prop)) == NULL) |
|
8018 |
return (-1); |
|
8019 |
||
8020 |
len = sizeof (DEV_PROP_PREFIX) + strlen(name); |
|
8021 |
if ((attr_name = malloc(len)) == NULL) |
|
8022 |
return (-1); |
|
8023 |
||
8024 |
(void) strlcpy(attr_name, DEV_PROP_PREFIX, len); |
|
8025 |
(void) strlcat(attr_name, name, len); |
|
8026 |
||
8027 |
switch (di_prop_type(prop)) { |
|
8028 |
case DI_PROP_TYPE_BOOLEAN: |
|
8029 |
if (nvlist_add_boolean(nvl, attr_name) != 0) |
|
8030 |
goto out; |
|
8031 |
break; |
|
8032 |
||
8033 |
case DI_PROP_TYPE_INT: |
|
8034 |
if ((n = di_prop_ints(prop, &int32p)) < 1) |
|
8035 |
goto out; |
|
8036 |
||
8037 |
if (n <= (PROP_LEN_LIMIT / sizeof (int32_t))) { |
|
8038 |
if (nvlist_add_int32_array(nvl, attr_name, int32p, |
|
8039 |
n) != 0) |
|
8040 |
goto out; |
|
8041 |
} else |
|
8042 |
rv = 1; |
|
8043 |
break; |
|
8044 |
||
8045 |
case DI_PROP_TYPE_INT64: |
|
8046 |
if ((n = di_prop_int64(prop, &int64p)) < 1) |
|
8047 |
goto out; |
|
8048 |
||
8049 |
if (n <= (PROP_LEN_LIMIT / sizeof (int64_t))) { |
|
8050 |
if (nvlist_add_int64_array(nvl, attr_name, int64p, |
|
8051 |
n) != 0) |
|
8052 |
goto out; |
|
8053 |
} else |
|
8054 |
rv = 1; |
|
8055 |
break; |
|
8056 |
||
8057 |
case DI_PROP_TYPE_BYTE: |
|
8058 |
case DI_PROP_TYPE_UNKNOWN: |
|
8059 |
if ((n = di_prop_bytes(prop, &bytep)) < 1) |
|
8060 |
goto out; |
|
8061 |
||
8062 |
if (n <= PROP_LEN_LIMIT) { |
|
8063 |
if (nvlist_add_byte_array(nvl, attr_name, bytep, n) |
|
8064 |
!= 0) |
|
8065 |
goto out; |
|
8066 |
} else |
|
8067 |
rv = 1; |
|
8068 |
break; |
|
8069 |
||
8070 |
case DI_PROP_TYPE_STRING: |
|
8071 |
if ((n = di_prop_strings(prop, &str)) < 1) |
|
8072 |
goto out; |
|
8073 |
||
8074 |
if ((strarray = malloc(n * sizeof (char *))) == NULL) |
|
8075 |
goto out; |
|
8076 |
||
8077 |
len = 0; |
|
8078 |
for (i = 0; i < n; i++) { |
|
8079 |
strarray[i] = str + len; |
|
8080 |
len += strlen(strarray[i]) + 1; |
|
8081 |
} |
|
8082 |
||
8083 |
if (len <= PROP_LEN_LIMIT) { |
|
8084 |
if (nvlist_add_string_array(nvl, attr_name, strarray, |
|
8085 |
n) != 0) { |
|
8086 |
free(strarray); |
|
8087 |
goto out; |
|
8088 |
} |
|
8089 |
} else |
|
8090 |
rv = 1; |
|
8091 |
free(strarray); |
|
8092 |
break; |
|
8093 |
||
8094 |
default: |
|
8095 |
rv = 1; |
|
8096 |
break; |
|
8097 |
} |
|
8098 |
||
8099 |
free(attr_name); |
|
8100 |
return (rv); |
|
8101 |
||
8102 |
out: |
|
8103 |
free(attr_name); |
|
8104 |
return (-1); |
|
8105 |
} |
|
8106 |
||
8107 |
static void |
|
8108 |
free_dev_names(struct devlink_cb_arg *x) |
|
8109 |
{ |
|
8110 |
int i; |
|
8111 |
||
8112 |
for (i = 0; i < x->count; i++) { |
|
8113 |
free(x->dev_names[i]); |
|
8114 |
free(x->link_contents[i]); |
|
8115 |
} |
|
8116 |
} |
|
8117 |
||
8118 |
/* callback function for di_devlink_cache_walk */ |
|
8119 |
static int |
|
8120 |
devlink_cb(di_devlink_t dl, void *arg) |
|
8121 |
{ |
|
8122 |
struct devlink_cb_arg *x = (struct devlink_cb_arg *)arg; |
|
8123 |
const char *path; |
|
8124 |
const char *content; |
|
8125 |
||
8126 |
if ((path = di_devlink_path(dl)) == NULL || |
|
8127 |
(content = di_devlink_content(dl)) == NULL || |
|
2253
2f994cfe3cdf
6431523 devfsadm: lookup_disk_dev_name() may cause core-dump
jg
parents:
1676
diff
changeset
|
8128 |
(x->dev_names[x->count] = s_strdup(path)) == NULL) |
0 | 8129 |
goto out; |
8130 |
||
2253
2f994cfe3cdf
6431523 devfsadm: lookup_disk_dev_name() may cause core-dump
jg
parents:
1676
diff
changeset
|
8131 |
if ((x->link_contents[x->count] = s_strdup(content)) == NULL) { |
0 | 8132 |
free(x->dev_names[x->count]); |
8133 |
goto out; |
|
8134 |
} |
|
8135 |
||
8136 |
x->count++; |
|
8137 |
if (x->count >= MAX_DEV_NAME_COUNT) |
|
8138 |
return (DI_WALK_TERMINATE); |
|
8139 |
||
8140 |
return (DI_WALK_CONTINUE); |
|
8141 |
||
8142 |
out: |
|
8143 |
x->rv = -1; |
|
8144 |
free_dev_names(x); |
|
8145 |
return (DI_WALK_TERMINATE); |
|
8146 |
} |
|
8147 |
||
8148 |
/* |
|
8149 |
* Lookup dev name corresponding to the phys_path. |
|
8150 |
* phys_path is path to a node or minor node. |
|
8151 |
* Returns: |
|
8152 |
* 0 with *dev_name set to the dev name |
|
8153 |
* Lookup succeeded and dev_name found |
|
8154 |
* 0 with *dev_name set to NULL |
|
8155 |
* Lookup encountered no errors but dev name not found |
|
8156 |
* -1 |
|
8157 |
* Lookup failed |
|
8158 |
*/ |
|
8159 |
static int |
|
8160 |
lookup_dev_name(char *phys_path, char **dev_name) |
|
8161 |
{ |
|
8162 |
struct devlink_cb_arg cb_arg; |
|
8163 |
||
8164 |
*dev_name = NULL; |
|
8165 |
||
8166 |
cb_arg.count = 0; |
|
8167 |
cb_arg.rv = 0; |
|
8168 |
(void) di_devlink_cache_walk(devlink_cache, NULL, phys_path, |
|
8169 |
DI_PRIMARY_LINK, &cb_arg, devlink_cb); |
|
8170 |
||
8171 |
if (cb_arg.rv == -1) |
|
8172 |
return (-1); |
|
8173 |
||
8174 |
if (cb_arg.count > 0) { |
|
2253
2f994cfe3cdf
6431523 devfsadm: lookup_disk_dev_name() may cause core-dump
jg
parents:
1676
diff
changeset
|
8175 |
*dev_name = s_strdup(cb_arg.dev_names[0]); |
0 | 8176 |
free_dev_names(&cb_arg); |
8177 |
if (*dev_name == NULL) |
|
8178 |
return (-1); |
|
8179 |
} |
|
8180 |
||
8181 |
return (0); |
|
8182 |
} |
|
8183 |
||
8184 |
static char * |
|
8185 |
lookup_disk_dev_name(char *node_path) |
|
8186 |
{ |
|
8187 |
struct devlink_cb_arg cb_arg; |
|
8188 |
char *dev_name = NULL; |
|
8189 |
int i; |
|
8190 |
char *p; |
|
8191 |
int len1, len2; |
|
8192 |
||
8193 |
#define DEV_RDSK "/dev/rdsk/" |
|
8194 |
#define DISK_RAW_MINOR ",raw" |
|
8195 |
||
8196 |
cb_arg.count = 0; |
|
8197 |
cb_arg.rv = 0; |
|
8198 |
(void) di_devlink_cache_walk(devlink_cache, NULL, node_path, |
|
8199 |
DI_PRIMARY_LINK, &cb_arg, devlink_cb); |
|
8200 |
||
8201 |
if (cb_arg.rv == -1 || cb_arg.count == 0) |
|
8202 |
return (NULL); |
|
8203 |
||
8204 |
/* first try lookup based on /dev/rdsk name */ |
|
8205 |
for (i = 0; i < cb_arg.count; i++) { |
|
8206 |
if (strncmp(cb_arg.dev_names[i], DEV_RDSK, |
|
8207 |
sizeof (DEV_RDSK) - 1) == 0) { |
|
2253
2f994cfe3cdf
6431523 devfsadm: lookup_disk_dev_name() may cause core-dump
jg
parents:
1676
diff
changeset
|
8208 |
dev_name = s_strdup(cb_arg.dev_names[i]); |
0 | 8209 |
break; |
8210 |
} |
|
8211 |
} |
|
8212 |
||
8213 |
if (dev_name == NULL) { |
|
8214 |
/* now try lookup based on a minor name ending with ",raw" */ |
|
8215 |
len1 = sizeof (DISK_RAW_MINOR) - 1; |
|
8216 |
for (i = 0; i < cb_arg.count; i++) { |
|
8217 |
len2 = strlen(cb_arg.link_contents[i]); |
|
8218 |
if (len2 >= len1 && |
|
8219 |
strcmp(cb_arg.link_contents[i] + len2 - len1, |
|
8220 |
DISK_RAW_MINOR) == 0) { |
|
2253
2f994cfe3cdf
6431523 devfsadm: lookup_disk_dev_name() may cause core-dump
jg
parents:
1676
diff
changeset
|
8221 |
dev_name = s_strdup(cb_arg.dev_names[i]); |
0 | 8222 |
break; |
8223 |
} |
|
8224 |
} |
|
8225 |
} |
|
8226 |
||
8227 |
free_dev_names(&cb_arg); |
|
8228 |
||
2253
2f994cfe3cdf
6431523 devfsadm: lookup_disk_dev_name() may cause core-dump
jg
parents:
1676
diff
changeset
|
8229 |
if (dev_name == NULL) |
2f994cfe3cdf
6431523 devfsadm: lookup_disk_dev_name() may cause core-dump
jg
parents:
1676
diff
changeset
|
8230 |
return (NULL); |
0 | 8231 |
if (strlen(dev_name) == 0) { |
8232 |
free(dev_name); |
|
8233 |
return (NULL); |
|
8234 |
} |
|
8235 |
||
8236 |
/* if the name contains slice or partition number strip it */ |
|
8237 |
p = dev_name + strlen(dev_name) - 1; |
|
8238 |
if (isdigit(*p)) { |
|
8239 |
while (p != dev_name && isdigit(*p)) |
|
8240 |
p--; |
|
8241 |
if (*p == 's' || *p == 'p') |
|
8242 |
*p = '\0'; |
|
8243 |
} |
|
8244 |
||
8245 |
return (dev_name); |
|
8246 |
} |
|
8247 |
||
8248 |
static char * |
|
4211 | 8249 |
lookup_lofi_dev_name(char *node_path, char *minor) |
8250 |
{ |
|
8251 |
struct devlink_cb_arg cb_arg; |
|
8252 |
char *dev_name = NULL; |
|
8253 |
int i; |
|
8254 |
int len1, len2; |
|
8255 |
||
8256 |
cb_arg.count = 0; |
|
8257 |
cb_arg.rv = 0; |
|
8258 |
(void) di_devlink_cache_walk(devlink_cache, NULL, node_path, |
|
8259 |
DI_PRIMARY_LINK, &cb_arg, devlink_cb); |
|
8260 |
||
8261 |
if (cb_arg.rv == -1 || cb_arg.count == 0) |
|
8262 |
return (NULL); |
|
8263 |
||
8264 |
/* lookup based on a minor name ending with ",raw" */ |
|
8265 |
len1 = strlen(minor); |
|
8266 |
for (i = 0; i < cb_arg.count; i++) { |
|
8267 |
len2 = strlen(cb_arg.link_contents[i]); |
|
8268 |
if (len2 >= len1 && |
|
8269 |
strcmp(cb_arg.link_contents[i] + len2 - len1, |
|
8270 |
minor) == 0) { |
|
8271 |
dev_name = s_strdup(cb_arg.dev_names[i]); |
|
8272 |
break; |
|
8273 |
} |
|
8274 |
} |
|
8275 |
||
8276 |
free_dev_names(&cb_arg); |
|
8277 |
||
8278 |
if (dev_name == NULL) |
|
8279 |
return (NULL); |
|
8280 |
if (strlen(dev_name) == 0) { |
|
8281 |
free(dev_name); |
|
8282 |
return (NULL); |
|
8283 |
} |
|
8284 |
||
8285 |
return (dev_name); |
|
8286 |
} |
|
8287 |
||
8288 |
static char * |
|
0 | 8289 |
lookup_network_dev_name(char *node_path, char *driver_name) |
8290 |
{ |
|
8291 |
char *dev_name = NULL; |
|
8292 |
char phys_path[MAXPATHLEN]; |
|
8293 |
||
8294 |
if (lookup_dev_name(node_path, &dev_name) == -1) |
|
8295 |
return (NULL); |
|
8296 |
||
8297 |
if (dev_name == NULL) { |
|
8298 |
/* dlpi style-2 only interface */ |
|
8299 |
(void) snprintf(phys_path, sizeof (phys_path), |
|
8300 |
"/pseudo/clone@0:%s", driver_name); |
|
8301 |
if (lookup_dev_name(phys_path, &dev_name) == -1 || |
|
8302 |
dev_name == NULL) |
|
8303 |
return (NULL); |
|
8304 |
} |
|
8305 |
||
8306 |
return (dev_name); |
|
8307 |
} |
|
8308 |
||
2441
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8309 |
static char * |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8310 |
lookup_printer_dev_name(char *node_path) |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8311 |
{ |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8312 |
struct devlink_cb_arg cb_arg; |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8313 |
char *dev_name = NULL; |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8314 |
int i; |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8315 |
|
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8316 |
#define DEV_PRINTERS "/dev/printers/" |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8317 |
|
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8318 |
cb_arg.count = 0; |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8319 |
cb_arg.rv = 0; |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8320 |
(void) di_devlink_cache_walk(devlink_cache, NULL, node_path, |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8321 |
DI_PRIMARY_LINK, &cb_arg, devlink_cb); |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8322 |
|
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8323 |
if (cb_arg.rv == -1 || cb_arg.count == 0) |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8324 |
return (NULL); |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8325 |
|
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8326 |
/* first try lookup based on /dev/printers name */ |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8327 |
for (i = 0; i < cb_arg.count; i++) { |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8328 |
if (strncmp(cb_arg.dev_names[i], DEV_PRINTERS, |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8329 |
sizeof (DEV_PRINTERS) - 1) == 0) { |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8330 |
dev_name = s_strdup(cb_arg.dev_names[i]); |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8331 |
break; |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8332 |
} |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8333 |
} |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8334 |
|
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8335 |
/* fallback to the first name */ |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8336 |
if ((dev_name == NULL) && (cb_arg.count > 0)) |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8337 |
dev_name = s_strdup(cb_arg.dev_names[0]); |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8338 |
|
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8339 |
free_dev_names(&cb_arg); |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8340 |
|
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8341 |
return (dev_name); |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8342 |
} |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8343 |
|
0 | 8344 |
/* |
8345 |
* Build an nvlist containing all attributes for devfs events. |
|
8346 |
* Returns nvlist pointer on success, NULL on failure. |
|
8347 |
*/ |
|
8348 |
static nvlist_t * |
|
8349 |
build_event_attributes(char *class, char *subclass, char *node_path, |
|
4211 | 8350 |
di_node_t node, char *driver_name, int instance, char *minor) |
0 | 8351 |
{ |
8352 |
nvlist_t *nvl; |
|
8353 |
int err = 0; |
|
8354 |
di_prop_t prop; |
|
8355 |
int count; |
|
8356 |
char *prop_name; |
|
8357 |
int x; |
|
8358 |
char *dev_name = NULL; |
|
8359 |
int dev_name_lookup_err = 0; |
|
8360 |
||
8361 |
if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) != 0) { |
|
8362 |
nvl = NULL; |
|
8363 |
goto out; |
|
8364 |
} |
|
8365 |
||
8366 |
if ((err = nvlist_add_int32(nvl, EV_VERSION, EV_V1)) != 0) |
|
8367 |
goto out; |
|
8368 |
||
8369 |
if ((err = nvlist_add_string(nvl, DEV_PHYS_PATH, node_path)) != 0) |
|
8370 |
goto out; |
|
8371 |
||
8372 |
if (strcmp(class, EC_DEV_ADD) != 0 && |
|
8373 |
strcmp(class, EC_DEV_REMOVE) != 0) |
|
8374 |
return (nvl); |
|
8375 |
||
8376 |
if (driver_name == NULL || instance == -1) |
|
8377 |
goto out; |
|
8378 |
||
8379 |
if (strcmp(subclass, ESC_DISK) == 0) { |
|
8380 |
if ((dev_name = lookup_disk_dev_name(node_path)) == NULL) { |
|
8381 |
dev_name_lookup_err = 1; |
|
8382 |
goto out; |
|
8383 |
} |
|
8384 |
} else if (strcmp(subclass, ESC_NETWORK) == 0) { |
|
8385 |
if ((dev_name = lookup_network_dev_name(node_path, driver_name)) |
|
8386 |
== NULL) { |
|
8387 |
dev_name_lookup_err = 1; |
|
8388 |
goto out; |
|
8389 |
} |
|
2441
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8390 |
} else if (strcmp(subclass, ESC_PRINTER) == 0) { |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8391 |
if ((dev_name = lookup_printer_dev_name(node_path)) == NULL) { |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8392 |
dev_name_lookup_err = 1; |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8393 |
goto out; |
5de3659dcf9f
6450793 printer hotplug events should be handled properly
jacobs
parents:
2253
diff
changeset
|
8394 |
} |
4211 | 8395 |
} else if (strcmp(subclass, ESC_LOFI) == 0) { |
8396 |
/* |
|
8397 |
* The raw minor node is created or removed after the block |
|
8398 |
* node. Lofi devfs events are dependent on this behavior. |
|
8399 |
* Generate the sysevent only for the raw minor node. |
|
8400 |
*/ |
|
8401 |
if (strstr(minor, "raw") == NULL) { |
|
8402 |
if (nvl) { |
|
8403 |
nvlist_free(nvl); |
|
8404 |
} |
|
8405 |
return (NULL); |
|
8406 |
} |
|
8407 |
if ((dev_name = lookup_lofi_dev_name(node_path, minor)) == |
|
8408 |
NULL) { |
|
8409 |
dev_name_lookup_err = 1; |
|
8410 |
goto out; |
|
8411 |
} |
|
0 | 8412 |
} |
8413 |
||
8414 |
if (dev_name) { |
|
8415 |
if ((err = nvlist_add_string(nvl, DEV_NAME, dev_name)) != 0) |
|
8416 |
goto out; |
|
8417 |
free(dev_name); |
|
8418 |
dev_name = NULL; |
|
8419 |
} |
|
8420 |
||
8421 |
if ((err = nvlist_add_string(nvl, DEV_DRIVER_NAME, driver_name)) != 0) |
|
8422 |
goto out; |
|
8423 |
||
8424 |
if ((err = nvlist_add_int32(nvl, DEV_INSTANCE, instance)) != 0) |
|
8425 |
goto out; |
|
8426 |
||
8427 |
if (strcmp(class, EC_DEV_ADD) == 0) { |
|
8428 |
/* add properties */ |
|
8429 |
count = 0; |
|
8430 |
for (prop = di_prop_next(node, DI_PROP_NIL); |
|
8431 |
prop != DI_PROP_NIL && count < MAX_PROP_COUNT; |
|
8432 |
prop = di_prop_next(node, prop)) { |
|
8433 |
||
8434 |
if (di_prop_devt(prop) != DDI_DEV_T_NONE) |
|
8435 |
continue; |
|
8436 |
||
8437 |
if ((x = add_property(nvl, prop)) == 0) |
|
8438 |
count++; |
|
8439 |
else if (x == -1) { |
|
8440 |
if ((prop_name = di_prop_name(prop)) == NULL) |
|
8441 |
prop_name = ""; |
|
8442 |
err_print(PROP_ADD_FAILED, prop_name); |
|
8443 |
goto out; |
|
8444 |
} |
|
8445 |
} |
|
8446 |
} |
|
8447 |
||
8448 |
return (nvl); |
|
8449 |
||
8450 |
out: |
|
8451 |
if (nvl) |
|
8452 |
nvlist_free(nvl); |
|
8453 |
||
8454 |
if (dev_name) |
|
8455 |
free(dev_name); |
|
8456 |
||
8457 |
if (dev_name_lookup_err) |
|
8458 |
err_print(DEV_NAME_LOOKUP_FAILED, node_path); |
|
8459 |
else |
|
8460 |
err_print(BUILD_EVENT_ATTR_FAILED, (err) ? strerror(err) : ""); |
|
8461 |
return (NULL); |
|
8462 |
} |
|
8463 |
||
8464 |
static void |
|
8465 |
log_event(char *class, char *subclass, nvlist_t *nvl) |
|
8466 |
{ |
|
8467 |
sysevent_id_t eid; |
|
8468 |
||
8469 |
if (sysevent_post_event(class, subclass, "SUNW", DEVFSADMD, |
|
8470 |
nvl, &eid) != 0) { |
|
8471 |
err_print(LOG_EVENT_FAILED, strerror(errno)); |
|
8472 |
} |
|
8473 |
} |
|
8474 |
||
3854 | 8475 |
/* |
8476 |
* When devfsadmd needs to generate sysevents, they are queued for later |
|
8477 |
* delivery this allows them to be delivered after the devlinks db cache has |
|
8478 |
* been flushed guaranteeing that applications consuming these events have |
|
8479 |
* access to an accurate devlinks db. The queue is a FIFO, sysevents to be |
|
8480 |
* inserted in the front of the queue and consumed off the back. |
|
8481 |
*/ |
|
0 | 8482 |
static void |
3854 | 8483 |
enqueue_sysevent(char *class, char *subclass, nvlist_t *nvl) |
8484 |
{ |
|
8485 |
syseventq_t *tmp; |
|
8486 |
||
8487 |
if ((tmp = s_zalloc(sizeof (*tmp))) == NULL) |
|
8488 |
return; |
|
8489 |
||
8490 |
tmp->class = s_strdup(class); |
|
8491 |
tmp->subclass = s_strdup(subclass); |
|
8492 |
tmp->nvl = nvl; |
|
8493 |
||
8494 |
(void) mutex_lock(&syseventq_mutex); |
|
8495 |
if (syseventq_front != NULL) |
|
8496 |
syseventq_front->next = tmp; |
|
8497 |
else |
|
8498 |
syseventq_back = tmp; |
|
8499 |
syseventq_front = tmp; |
|
8500 |
(void) mutex_unlock(&syseventq_mutex); |
|
8501 |
} |
|
8502 |
||
8503 |
static void |
|
8504 |
process_syseventq() |
|
8505 |
{ |
|
8506 |
(void) mutex_lock(&syseventq_mutex); |
|
8507 |
while (syseventq_back != NULL) { |
|
8508 |
syseventq_t *tmp = syseventq_back; |
|
8509 |
||
8510 |
vprint(CHATTY_MID, "sending queued event: %s, %s\n", |
|
8511 |
tmp->class, tmp->subclass); |
|
8512 |
||
8513 |
log_event(tmp->class, tmp->subclass, tmp->nvl); |
|
8514 |
||
8515 |
if (tmp->class != NULL) |
|
8516 |
free(tmp->class); |
|
8517 |
if (tmp->subclass != NULL) |
|
8518 |
free(tmp->subclass); |
|
8519 |
if (tmp->nvl != NULL) |
|
8520 |
nvlist_free(tmp->nvl); |
|
8521 |
syseventq_back = syseventq_back->next; |
|
8522 |
if (syseventq_back == NULL) |
|
8523 |
syseventq_front = NULL; |
|
8524 |
free(tmp); |
|
8525 |
} |
|
8526 |
(void) mutex_unlock(&syseventq_mutex); |
|
8527 |
} |
|
8528 |
||
8529 |
static void |
|
8530 |
build_and_enq_event(char *class, char *subclass, char *node_path, |
|
4211 | 8531 |
di_node_t node, char *minor) |
0 | 8532 |
{ |
8533 |
nvlist_t *nvl; |
|
8534 |
||
3854 | 8535 |
vprint(CHATTY_MID, "build_and_enq_event(%s, %s, %s, 0x%8.8x)\n", |
8536 |
class, subclass, node_path, (int)node); |
|
8537 |
||
0 | 8538 |
if (node != DI_NODE_NIL) |
8539 |
nvl = build_event_attributes(class, subclass, node_path, node, |
|
4211 | 8540 |
di_driver_name(node), di_instance(node), minor); |
0 | 8541 |
else |
8542 |
nvl = build_event_attributes(class, subclass, node_path, node, |
|
4211 | 8543 |
NULL, -1, minor); |
0 | 8544 |
|
8545 |
if (nvl) { |
|
3854 | 8546 |
enqueue_sysevent(class, subclass, nvl); |
0 | 8547 |
} |
8548 |
} |
|
2621 | 8549 |
|
2805
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8550 |
/* |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8551 |
* is_blank() returns 1 (true) if a line specified is composed of |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8552 |
* whitespace characters only. otherwise, it returns 0 (false). |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8553 |
* |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8554 |
* Note. the argument (line) must be null-terminated. |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8555 |
*/ |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8556 |
static int |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8557 |
is_blank(char *line) |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8558 |
{ |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8559 |
for (/* nothing */; *line != '\0'; line++) |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8560 |
if (!isspace(*line)) |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8561 |
return (0); |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8562 |
return (1); |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8563 |
} |
a4be0ff24d1f
6311701 /etc/minor_perm is ignored if it contains comments
eota
parents:
2729
diff
changeset
|
8564 |
|
2846
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8565 |
/* |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8566 |
* Functions to deal with the no-further-processing hash |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8567 |
*/ |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8568 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8569 |
static void |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8570 |
nfphash_create(void) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8571 |
{ |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8572 |
assert(nfp_hash == NULL); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8573 |
nfp_hash = s_zalloc(NFP_HASH_SZ * sizeof (item_t *)); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8574 |
} |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8575 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8576 |
static int |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8577 |
nfphash_fcn(char *key) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8578 |
{ |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8579 |
int i; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8580 |
uint64_t sum = 0; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8581 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8582 |
for (i = 0; key[i] != '\0'; i++) { |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8583 |
sum += (uchar_t)key[i]; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8584 |
} |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8585 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8586 |
return (sum % NFP_HASH_SZ); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8587 |
} |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8588 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8589 |
static item_t * |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8590 |
nfphash_lookup(char *key) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8591 |
{ |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8592 |
int index; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8593 |
item_t *ip; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8594 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8595 |
index = nfphash_fcn(key); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8596 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8597 |
assert(index >= 0); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8598 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8599 |
for (ip = nfp_hash[index]; ip; ip = ip->i_next) { |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8600 |
if (strcmp(ip->i_key, key) == 0) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8601 |
return (ip); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8602 |
} |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8603 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8604 |
return (NULL); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8605 |
} |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8606 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8607 |
static void |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8608 |
nfphash_insert(char *key) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8609 |
{ |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8610 |
item_t *ip; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8611 |
int index; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8612 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8613 |
index = nfphash_fcn(key); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8614 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8615 |
assert(index >= 0); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8616 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8617 |
ip = s_zalloc(sizeof (item_t)); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8618 |
ip->i_key = s_strdup(key); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8619 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8620 |
ip->i_next = nfp_hash[index]; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8621 |
nfp_hash[index] = ip; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8622 |
} |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8623 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8624 |
static void |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8625 |
nfphash_destroy(void) |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8626 |
{ |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8627 |
int i; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8628 |
item_t *ip; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8629 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8630 |
for (i = 0; i < NFP_HASH_SZ; i++) { |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8631 |
/*LINTED*/ |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8632 |
while (ip = nfp_hash[i]) { |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8633 |
nfp_hash[i] = ip->i_next; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8634 |
free(ip->i_key); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8635 |
free(ip); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8636 |
} |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8637 |
} |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8638 |
|
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8639 |
free(nfp_hash); |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8640 |
nfp_hash = NULL; |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8641 |
} |
d2693e8a5243
6462748 devfsadm link removal does not provide full interpose support
vikram
parents:
2805
diff
changeset
|
8642 |
|
2621 | 8643 |
static int |
8644 |
devname_kcall(int subcmd, void *args) |
|
8645 |
{ |
|
8646 |
int error = 0; |
|
8647 |
char *nvlbuf = NULL; |
|
8648 |
size_t nvlsize; |
|
8649 |
||
8650 |
switch (subcmd) { |
|
8651 |
case MODDEVNAME_NSMAPS: |
|
8652 |
error = nvlist_pack((nvlist_t *)args, &nvlbuf, &nvlsize, 0, 0); |
|
8653 |
if (error) { |
|
8654 |
err_print("packing MODDEVNAME_NSMAPS failed\n"); |
|
8655 |
break; |
|
8656 |
} |
|
8657 |
error = modctl(MODDEVNAME, subcmd, nvlbuf, nvlsize); |
|
8658 |
if (error) { |
|
8659 |
vprint(INFO_MID, "modctl(MODDEVNAME, " |
|
8660 |
"MODDEVNAME_NSMAPS) failed - %s\n", |
|
8661 |
strerror(errno)); |
|
8662 |
} |
|
8663 |
free(nvlbuf); |
|
8664 |
nvlist_free(args); |
|
8665 |
break; |
|
8666 |
case MODDEVNAME_LOOKUPDOOR: |
|
8667 |
error = modctl(MODDEVNAME, subcmd, (uintptr_t)args); |
|
8668 |
if (error) { |
|
8669 |
vprint(INFO_MID, "modctl(MODDEVNAME, " |
|
8670 |
"MODDEVNAME_LOOKUPDOOR) failed - %s\n", |
|
8671 |
strerror(errno)); |
|
8672 |
} |
|
8673 |
break; |
|
8674 |
default: |
|
8675 |
error = EINVAL; |
|
8676 |
break; |
|
8677 |
} |
|
8678 |
return (error); |
|
8679 |
} |
|
8680 |
||
8681 |
static void |
|
8682 |
devname_setup_nsmaps(void) |
|
8683 |
{ |
|
8684 |
int error = 0; |
|
8685 |
||
8686 |
if (devname_first_call) { |
|
8687 |
devname_first_call = 0; |
|
8688 |
} |
|
8689 |
||
8690 |
error = di_devname_get_mapinfo(DEVNAME_MASTER_MAP, &devname_maps); |
|
8691 |
||
8692 |
if (error) { |
|
2729
aeda30620271
6467958 inappropriate error message displayed from Devfsadm
llai1
parents:
2621
diff
changeset
|
8693 |
vprint(DEVNAME_MID, "devname_setup_nsmaps: non-existing/empty" |
aeda30620271
6467958 inappropriate error message displayed from Devfsadm
llai1
parents:
2621
diff
changeset
|
8694 |
"%s\n", DEVNAME_MASTER_MAP); |
2621 | 8695 |
} else { |
8696 |
di_devname_print_mapinfo(devname_maps); |
|
2729
aeda30620271
6467958 inappropriate error message displayed from Devfsadm
llai1
parents:
2621
diff
changeset
|
8697 |
|
2621 | 8698 |
/* pass down the existing map names to kernel */ |
8699 |
(void) devname_kcall(MODDEVNAME_NSMAPS, (void *)devname_maps); |
|
8700 |
} |
|
8701 |
} |
|
8702 |
||
8703 |
static void |
|
8704 |
devname_ns_services(uint8_t cmd, char *key, char *map) |
|
8705 |
{ |
|
8706 |
nvlist_t *nvl = NULL; |
|
8707 |
int32_t error = 0; |
|
8708 |
sdev_door_res_t res; |
|
8709 |
||
8710 |
vprint(DEVNAME_MID, "devname_ns_services: cmd %d key %s map %s\n", |
|
8711 |
cmd, key, map); |
|
8712 |
||
8713 |
switch (cmd) { |
|
8714 |
case DEVFSADMD_NS_LOOKUP: |
|
8715 |
vprint(DEVNAME_MID, "calling di_devname_get_mapent\n"); |
|
8716 |
error = di_devname_get_mapent(key, map, &nvl); |
|
8717 |
if (nvl == NULL) { |
|
8718 |
error = DEVFSADM_NS_FAILED; |
|
8719 |
goto done; |
|
8720 |
} |
|
8721 |
||
8722 |
if (error) { |
|
8723 |
nvlist_free(nvl); |
|
8724 |
goto done; |
|
8725 |
} |
|
8726 |
||
8727 |
if (devname_debug_msg) |
|
8728 |
di_devname_print_mapinfo(nvl); |
|
8729 |
||
8730 |
vprint(DEVNAME_MID, "calling di_devname_action_on_key for %d\n", |
|
8731 |
cmd); |
|
8732 |
error = di_devname_action_on_key(nvl, cmd, key, (void *)&res); |
|
8733 |
nvlist_free(nvl); |
|
8734 |
break; |
|
8735 |
case DEVFSADMD_NS_READDIR: |
|
8736 |
vprint(DEVNAME_MID, "calling di_devname_get_mapinfo for cmd %d" |
|
8737 |
"\n", cmd); |
|
8738 |
error = di_devname_get_mapinfo(map, &nvl); |
|
8739 |
if (nvl == NULL) { |
|
8740 |
error = DEVFSADM_NS_FAILED; |
|
8741 |
goto done; |
|
8742 |
} |
|
8743 |
||
8744 |
if (error) { |
|
8745 |
nvlist_free(nvl); |
|
8746 |
goto done; |
|
8747 |
} |
|
8748 |
||
8749 |
if (devname_debug_msg) |
|
8750 |
di_devname_print_mapinfo(nvl); |
|
8751 |
||
8752 |
vprint(DEVNAME_MID, "calling di_devname_action_on_key\n"); |
|
8753 |
error = di_devname_action_on_key(nvl, cmd, key, (void *)&res); |
|
8754 |
nvlist_free(nvl); |
|
8755 |
break; |
|
8756 |
default: |
|
8757 |
error = DEVFSADM_RUN_NOTSUP; |
|
8758 |
break; |
|
8759 |
} |
|
8760 |
||
8761 |
done: |
|
8762 |
vprint(DEVNAME_MID, "error %d\n", error); |
|
8763 |
res.devfsadm_error = error; |
|
8764 |
(void) door_return((char *)&res, sizeof (struct sdev_door_res), |
|
8765 |
NULL, 0); |
|
8766 |
} |
|
8767 |
||
8768 |
/* ARGSUSED */ |
|
8769 |
static void |
|
8770 |
devname_lookup_handler(void *cookie, char *argp, size_t arg_size, |
|
8771 |
door_desc_t *dp, uint_t n_desc) |
|
8772 |
{ |
|
8773 |
int32_t error = 0; |
|
8774 |
door_cred_t dcred; |
|
8775 |
struct dca_impl dci; |
|
8776 |
uint8_t cmd; |
|
8777 |
char *ns_map, *ns_name; |
|
8778 |
sdev_door_res_t res; |
|
8779 |
sdev_door_arg_t *args; |
|
8780 |
||
8781 |
if (argp == NULL || arg_size == 0) { |
|
8782 |
vprint(DEVNAME_MID, "devname_lookup_handler: argp wrong\n"); |
|
8783 |
error = DEVFSADM_RUN_INVALID; |
|
8784 |
goto done; |
|
8785 |
} |
|
8786 |
vprint(DEVNAME_MID, "devname_lookup_handler\n"); |
|
8787 |
||
8788 |
if (door_cred(&dcred) != 0 || dcred.dc_euid != 0) { |
|
8789 |
vprint(DEVNAME_MID, "devname_lookup_handler: cred wrong\n"); |
|
8790 |
error = DEVFSADM_RUN_EPERM; |
|
8791 |
goto done; |
|
8792 |
} |
|
8793 |
||
8794 |
args = (sdev_door_arg_t *)argp; |
|
8795 |
cmd = args->devfsadm_cmd; |
|
8796 |
||
8797 |
vprint(DEVNAME_MID, "devname_lookup_handler: cmd %d\n", cmd); |
|
8798 |
switch (cmd) { |
|
8799 |
case DEVFSADMD_NS_LOOKUP: |
|
8800 |
case DEVFSADMD_NS_READDIR: |
|
8801 |
ns_name = s_strdup(args->ns_hdl.ns_name); |
|
8802 |
ns_map = s_strdup(args->ns_hdl.ns_map); |
|
8803 |
||
8804 |
vprint(DEVNAME_MID, " ns_name %s ns_map %s\n", ns_name, ns_map); |
|
8805 |
if (ns_name == NULL || ns_map == NULL) { |
|
8806 |
error = DEVFSADM_RUN_INVALID; |
|
8807 |
goto done; |
|
8808 |
} |
|
8809 |
||
8810 |
devname_ns_services(cmd, ns_name, ns_map); |
|
8811 |
return; |
|
8812 |
case DEVFSADMD_RUN_ALL: |
|
8813 |
/* |
|
8814 |
* run "devfsadm" |
|
8815 |
*/ |
|
8816 |
dci.dci_root = "/"; |
|
8817 |
dci.dci_minor = NULL; |
|
8818 |
dci.dci_driver = NULL; |
|
8819 |
dci.dci_error = 0; |
|
8820 |
dci.dci_flags = 0; |
|
8821 |
dci.dci_arg = NULL; |
|
8822 |
||
8823 |
lock_dev(); |
|
8824 |
update_drvconf((major_t)-1); |
|
8825 |
dci.dci_flags |= DCA_FLUSH_PATHINST; |
|
8826 |
||
8827 |
pre_and_post_cleanup(RM_PRE); |
|
8828 |
devi_tree_walk(&dci, DINFOFORCE|DI_CACHE_SNAPSHOT_FLAGS, NULL); |
|
8829 |
error = (int32_t)dci.dci_error; |
|
8830 |
if (!error) { |
|
8831 |
pre_and_post_cleanup(RM_POST); |
|
8832 |
update_database = TRUE; |
|
8833 |
unlock_dev(SYNC_STATE); |
|
8834 |
update_database = FALSE; |
|
8835 |
} else { |
|
8836 |
if (DEVFSADM_DEBUG_ON) { |
|
8837 |
vprint(INFO_MID, "devname_lookup_handler: " |
|
8838 |
"DEVFSADMD_RUN_ALL failed\n"); |
|
8839 |
} |
|
8840 |
||
8841 |
unlock_dev(SYNC_STATE); |
|
8842 |
} |
|
8843 |
break; |
|
8844 |
default: |
|
8845 |
/* log an error here? */ |
|
8846 |
error = DEVFSADM_RUN_NOTSUP; |
|
8847 |
break; |
|
8848 |
} |
|
8849 |
||
8850 |
done: |
|
8851 |
vprint(DEVNAME_MID, "devname_lookup_handler: error %d\n", error); |
|
8852 |
res.devfsadm_error = error; |
|
8853 |
(void) door_return((char *)&res, sizeof (struct sdev_door_res), |
|
8854 |
NULL, 0); |
|
8855 |
} |
|
4876 | 8856 |
|
8857 |
||
8858 |
di_devlink_handle_t |
|
8859 |
devfsadm_devlink_cache(void) |
|
8860 |
{ |
|
8861 |
return (devlink_cache); |
|
8862 |
} |
|
8863 |
||
8864 |
int |
|
8865 |
devfsadm_reserve_id_cache(devlink_re_t re_array[], enumerate_file_t *head) |
|
8866 |
{ |
|
8867 |
enumerate_file_t *entry; |
|
8868 |
int nelem; |
|
8869 |
int i; |
|
8870 |
int subex; |
|
8871 |
char *re; |
|
8872 |
size_t size; |
|
8873 |
regmatch_t *pmch; |
|
8874 |
||
8875 |
/* |
|
8876 |
* Check the <RE, subexp> array passed in and compile it. |
|
8877 |
*/ |
|
8878 |
for (i = 0; re_array[i].d_re; i++) { |
|
8879 |
if (re_array[i].d_subexp == 0) { |
|
8880 |
err_print("bad subexp value in RE: %s\n", |
|
8881 |
re_array[i].d_re); |
|
8882 |
goto bad_re; |
|
8883 |
} |
|
8884 |
||
8885 |
re = re_array[i].d_re; |
|
8886 |
if (regcomp(&re_array[i].d_rcomp, re, REG_EXTENDED) != 0) { |
|
8887 |
err_print("reg. exp. failed to compile: %s\n", re); |
|
8888 |
goto bad_re; |
|
8889 |
} |
|
8890 |
subex = re_array[i].d_subexp; |
|
8891 |
nelem = subex + 1; |
|
8892 |
re_array[i].d_pmatch = s_malloc(sizeof (regmatch_t) * nelem); |
|
8893 |
} |
|
8894 |
||
8895 |
entry = head ? head : enumerate_reserved; |
|
8896 |
for (; entry; entry = entry->er_next) { |
|
8897 |
if (entry->er_id) { |
|
8898 |
vprint(RSBY_MID, "entry %s already has ID %s\n", |
|
8899 |
entry->er_file, entry->er_id); |
|
8900 |
continue; |
|
8901 |
} |
|
8902 |
for (i = 0; re_array[i].d_re; i++) { |
|
8903 |
subex = re_array[i].d_subexp; |
|
8904 |
pmch = re_array[i].d_pmatch; |
|
8905 |
if (regexec(&re_array[i].d_rcomp, entry->er_file, |
|
8906 |
subex + 1, pmch, 0) != 0) { |
|
8907 |
/* No match */ |
|
8908 |
continue; |
|
8909 |
} |
|
8910 |
size = pmch[subex].rm_eo - pmch[subex].rm_so; |
|
8911 |
entry->er_id = s_malloc(size + 1); |
|
8912 |
(void) strncpy(entry->er_id, |
|
8913 |
&entry->er_file[pmch[subex].rm_so], size); |
|
8914 |
entry->er_id[size] = '\0'; |
|
8915 |
if (head) { |
|
8916 |
vprint(RSBY_MID, "devlink(%s) matches RE(%s). " |
|
8917 |
"ID is %s\n", entry->er_file, |
|
8918 |
re_array[i].d_re, entry->er_id); |
|
8919 |
} else { |
|
8920 |
vprint(RSBY_MID, "rsrv entry(%s) matches " |
|
8921 |
"RE(%s) ID is %s\n", entry->er_file, |
|
8922 |
re_array[i].d_re, entry->er_id); |
|
8923 |
} |
|
8924 |
break; |
|
8925 |
} |
|
8926 |
} |
|
8927 |
||
8928 |
for (i = 0; re_array[i].d_re; i++) { |
|
8929 |
regfree(&re_array[i].d_rcomp); |
|
8930 |
assert(re_array[i].d_pmatch); |
|
8931 |
free(re_array[i].d_pmatch); |
|
8932 |
} |
|
8933 |
||
8934 |
entry = head ? head : enumerate_reserved; |
|
8935 |
for (; entry; entry = entry->er_next) { |
|
8936 |
if (entry->er_id == NULL) |
|
8937 |
continue; |
|
8938 |
if (head) { |
|
8939 |
vprint(RSBY_MID, "devlink: %s\n", entry->er_file); |
|
8940 |
vprint(RSBY_MID, "ID: %s\n", entry->er_id); |
|
8941 |
} else { |
|
8942 |
vprint(RSBY_MID, "reserve file entry: %s\n", |
|
8943 |
entry->er_file); |
|
8944 |
vprint(RSBY_MID, "reserve file id: %s\n", |
|
8945 |
entry->er_id); |
|
8946 |
} |
|
8947 |
} |
|
8948 |
||
8949 |
return (DEVFSADM_SUCCESS); |
|
8950 |
||
8951 |
bad_re: |
|
8952 |
for (i = i-1; i >= 0; i--) { |
|
8953 |
regfree(&re_array[i].d_rcomp); |
|
8954 |
assert(re_array[i].d_pmatch); |
|
8955 |
free(re_array[i].d_pmatch); |
|
8956 |
} |
|
8957 |
return (DEVFSADM_FAILURE); |
|
8958 |
} |
|
8959 |
||
8960 |
/* |
|
6065 | 8961 |
* Return 1 if we have reserved links. |
8962 |
*/ |
|
8963 |
int |
|
8964 |
devfsadm_have_reserved() |
|
8965 |
{ |
|
8966 |
return (enumerate_reserved ? 1 : 0); |
|
8967 |
} |
|
8968 |
||
8969 |
/* |
|
4876 | 8970 |
* This functions errs on the side of caution. If there is any error |
8971 |
* we assume that the devlink is *not* reserved |
|
8972 |
*/ |
|
8973 |
int |
|
8974 |
devfsadm_is_reserved(devlink_re_t re_array[], char *devlink) |
|
8975 |
{ |
|
8976 |
int match; |
|
8977 |
enumerate_file_t estruct = {NULL}; |
|
8978 |
enumerate_file_t *entry; |
|
8979 |
||
8980 |
match = 0; |
|
8981 |
estruct.er_file = devlink; |
|
8982 |
estruct.er_id = NULL; |
|
8983 |
estruct.er_next = NULL; |
|
8984 |
||
8985 |
if (devfsadm_reserve_id_cache(re_array, &estruct) != DEVFSADM_SUCCESS) { |
|
8986 |
err_print("devfsadm_is_reserved: devlink (%s) does not " |
|
8987 |
"match RE\n", devlink); |
|
8988 |
return (0); |
|
8989 |
} |
|
8990 |
if (estruct.er_id == NULL) { |
|
8991 |
err_print("devfsadm_is_reserved: ID derived from devlink %s " |
|
8992 |
"is NULL\n", devlink); |
|
8993 |
return (0); |
|
8994 |
} |
|
8995 |
||
8996 |
entry = enumerate_reserved; |
|
8997 |
for (; entry; entry = entry->er_next) { |
|
8998 |
if (entry->er_id == NULL) |
|
8999 |
continue; |
|
9000 |
if (strcmp(entry->er_id, estruct.er_id) != 0) |
|
9001 |
continue; |
|
9002 |
match = 1; |
|
9003 |
vprint(RSBY_MID, "reserve file entry (%s) and devlink (%s) " |
|
9004 |
"match\n", entry->er_file, devlink); |
|
9005 |
break; |
|
9006 |
} |
|
9007 |
||
9008 |
free(estruct.er_id); |
|
9009 |
return (match); |
|
9010 |
} |