Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/sysevent.c
+++ new/usr/src/uts/common/io/sysevent.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25
26 26 /*
27 27 * Sysevent Driver for GPEC
28 28 */
29 29
30 30 #include <sys/types.h>
31 31 #include <sys/param.h>
32 32 #include <sys/cred.h>
33 33 #include <sys/file.h>
34 34 #include <sys/stat.h>
35 35 #include <sys/conf.h>
36 36 #include <sys/ddi.h>
37 37 #include <sys/sunddi.h>
38 38 #include <sys/modctl.h>
39 39 #include <sys/open.h> /* OTYP_CHR definition */
40 40 #include <sys/sysmacros.h> /* L_BITSMINOR definition */
41 41 #include <sys/bitmap.h>
42 42 #include <sys/sysevent.h>
43 43 #include <sys/sysevent_impl.h>
44 44
45 45 static dev_info_t *sysevent_devi;
46 46
47 47 /* Definitions for binding handle array */
48 48 static ulong_t sysevent_bitmap_initial = 1; /* index 0 indicates error */
49 49 static ulong_t *sysevent_minor_bitmap = &sysevent_bitmap_initial;
50 50 static size_t sysevent_minor_bits = BT_NBIPUL;
51 51 static kmutex_t sysevent_minor_mutex;
52 52
53 53 /*
54 54 * evchan_ctl acts as a container for the binding handle
55 55 */
56 56 typedef struct evchan_ctl {
57 57 evchan_t *chp;
58 58 } evchan_ctl_t;
59 59
60 60 static void *evchan_ctlp;
61 61
62 62 /*
63 63 * Check if it's a null terminated array - to avoid DoS attack
64 64 * It is supposed that string points to an array with
65 65 * a minimum length of len. len must be strlen + 1.
66 66 * Checks for printable characters are already done in library.
67 67 */
68 68 static int
69 69 sysevent_isstrend(char *string, size_t len)
70 70 {
71 71 /* Return 0 if string has length of zero */
72 72 if (len > 0) {
73 73 return (string[len - 1] == '\0' ? 1 : 0);
74 74 } else {
75 75 return (0);
76 76 }
77 77 }
78 78
79 79 /*
80 80 * Following sysevent_minor_* routines map
81 81 * a binding handle (evchan_t *) to a minor number
82 82 * Has to be called w/ locks held.
83 83 */
84 84 static ulong_t *
85 85 sysevent_minor_alloc(void)
86 86 {
87 87 ulong_t *bhst = sysevent_minor_bitmap;
88 88
89 89 /* Increase bitmap by one BT_NBIPUL */
90 90 if (sysevent_minor_bits + BT_NBIPUL > SYSEVENT_MINOR_MAX) {
91 91 return ((ulong_t *)NULL);
92 92 }
93 93 sysevent_minor_bitmap = kmem_zalloc(
94 94 BT_SIZEOFMAP(sysevent_minor_bits + BT_NBIPUL), KM_SLEEP);
95 95 bcopy(bhst, sysevent_minor_bitmap, BT_SIZEOFMAP(sysevent_minor_bits));
96 96 if (bhst != &sysevent_bitmap_initial)
97 97 kmem_free(bhst, BT_SIZEOFMAP(sysevent_minor_bits));
98 98 sysevent_minor_bits += BT_NBIPUL;
99 99
100 100 return (sysevent_minor_bitmap);
101 101 }
102 102
103 103 static void
104 104 sysevent_minor_free(ulong_t *bitmap)
105 105 {
106 106 if (bitmap != &sysevent_bitmap_initial)
107 107 kmem_free(bitmap, BT_SIZEOFMAP(sysevent_minor_bits));
108 108 }
109 109
110 110 static index_t
111 111 sysevent_minor_get(void)
112 112 {
113 113 index_t idx;
114 114 ulong_t *bhst;
115 115
116 116 /* Search for an available index */
117 117 mutex_enter(&sysevent_minor_mutex);
118 118 if ((idx = bt_availbit(sysevent_minor_bitmap,
119 119 sysevent_minor_bits)) == -1) {
120 120 /* All busy - allocate additional binding handle bitmap space */
121 121 if ((bhst = sysevent_minor_alloc()) == NULL) {
122 122 /* Reached our maximum of id's == SHRT_MAX */
123 123 mutex_exit(&sysevent_minor_mutex);
124 124 return (0);
125 125 } else {
126 126 sysevent_minor_bitmap = bhst;
127 127 }
128 128 idx = bt_availbit(sysevent_minor_bitmap, sysevent_minor_bits);
129 129 }
130 130 BT_SET(sysevent_minor_bitmap, idx);
131 131 mutex_exit(&sysevent_minor_mutex);
132 132 return (idx);
133 133 }
134 134
135 135 static void
136 136 sysevent_minor_rele(index_t idx)
137 137 {
138 138 mutex_enter(&sysevent_minor_mutex);
139 139 ASSERT(BT_TEST(sysevent_minor_bitmap, idx) == 1);
140 140 BT_CLEAR(sysevent_minor_bitmap, idx);
141 141 mutex_exit(&sysevent_minor_mutex);
142 142 }
143 143
144 144 static void
145 145 sysevent_minor_init(void)
146 146 {
147 147 mutex_init(&sysevent_minor_mutex, NULL, MUTEX_DEFAULT, NULL);
148 148 }
149 149
150 150 /* ARGSUSED */
151 151 static int
152 152 sysevent_publish(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr)
153 153 {
154 154 int km_flags;
155 155 sev_publish_args_t uargs;
156 156 sysevent_impl_t *ev;
157 157 evchan_ctl_t *ctl;
158 158
159 159 ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev));
160 160 if (ctl == NULL || ctl->chp == NULL)
161 161 return (ENXIO);
162 162
163 163 if (copyin(arg, &uargs, sizeof (sev_publish_args_t)) != 0)
164 164 return (EFAULT);
165 165
166 166 /*
167 167 * This limits the size of an event
168 168 */
169 169 if (uargs.ev.len > MAX_EV_SIZE_LEN)
170 170 return (EOVERFLOW);
171 171
172 172 /*
173 173 * Check for valid uargs.flags
174 174 */
175 175 if (uargs.flags & ~(EVCH_NOSLEEP | EVCH_SLEEP | EVCH_QWAIT))
176 176 return (EINVAL);
177 177
178 178 /*
179 179 * Check that at least one of EVCH_NOSLEEP or EVCH_SLEEP is
180 180 * specified
181 181 */
182 182 km_flags = uargs.flags & (EVCH_NOSLEEP | EVCH_SLEEP);
183 183 if (km_flags != EVCH_NOSLEEP && km_flags != EVCH_SLEEP)
184 184 return (EINVAL);
185 185
186 186 ev = evch_usrallocev(uargs.ev.len, uargs.flags);
187 187
188 188 if (copyin((void *)(uintptr_t)uargs.ev.name, ev, uargs.ev.len) != 0) {
189 189 evch_usrfreeev(ev);
190 190 return (EFAULT);
191 191 }
192 192
193 193 return (evch_usrpostevent(ctl->chp, ev, uargs.flags));
194 194
195 195 /* Event will be freed internally */
196 196 }
197 197
198 198 /*
199 199 * sysevent_chan_open - used to open a channel in the GPEC channel layer
200 200 */
201 201
202 202 /* ARGSUSED */
203 203 static int
204 204 sysevent_chan_open(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr)
205 205 {
206 206 sev_bind_args_t uargs;
207 207 evchan_ctl_t *ctl;
208 208 char *chan_name;
209 209 int ec;
210 210
211 211 ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev));
212 212 if (ctl == NULL) {
213 213 return (ENXIO);
214 214 }
215 215
216 216 if (copyin(arg, &uargs, sizeof (sev_bind_args_t)) != 0)
217 217 return (EFAULT);
218 218
219 219 if (uargs.chan_name.len > MAX_CHNAME_LEN)
220 220 return (EINVAL);
221 221
222 222 chan_name = kmem_alloc(uargs.chan_name.len, KM_SLEEP);
223 223
224 224 if (copyin((void *)(uintptr_t)uargs.chan_name.name, chan_name,
225 225 uargs.chan_name.len) != 0) {
226 226 kmem_free(chan_name, uargs.chan_name.len);
227 227 return (EFAULT);
228 228 }
229 229
230 230 if (!sysevent_isstrend(chan_name, uargs.chan_name.len)) {
231 231 kmem_free(chan_name, uargs.chan_name.len);
232 232 return (EINVAL);
233 233 }
234 234
235 235 /*
236 236 * Check of uargs.flags and uargs.perms just to avoid DoS attacks.
237 237 * libsysevent does this carefully
238 238 */
239 239 ctl->chp = evch_usrchanopen((const char *)chan_name,
240 240 uargs.flags & EVCH_B_FLAGS, &ec);
241 241
242 242 kmem_free(chan_name, uargs.chan_name.len);
243 243
244 244 if (ec != 0) {
245 245 return (ec);
246 246 }
247 247
248 248 return (0);
249 249 }
250 250
251 251 /* ARGSUSED */
252 252 static int
253 253 sysevent_chan_control(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr)
254 254 {
255 255 sev_control_args_t uargs;
256 256 evchan_ctl_t *ctl;
257 257 int rc;
258 258
259 259 ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev));
260 260 if (ctl == NULL || ctl->chp == NULL)
261 261 return (ENXIO);
262 262
263 263 if (copyin(arg, &uargs, sizeof (sev_control_args_t)) != 0)
264 264 return (EFAULT);
265 265
266 266 switch (uargs.cmd) {
267 267 case EVCH_GET_CHAN_LEN:
268 268 case EVCH_GET_CHAN_LEN_MAX:
269 269 rc = evch_usrcontrol_get(ctl->chp, uargs.cmd, &uargs.value);
270 270 if (rc == 0) {
271 271 if (copyout((void *)&uargs, arg,
272 272 sizeof (sev_control_args_t)) != 0) {
273 273 rc = EFAULT;
274 274 }
275 275 }
276 276 break;
277 277 case EVCH_SET_CHAN_LEN:
278 278 rc = evch_usrcontrol_set(ctl->chp, uargs.cmd, uargs.value);
279 279 break;
280 280 default:
281 281 rc = EINVAL;
282 282 }
283 283 return (rc);
284 284 }
285 285
286 286 /* ARGSUSED */
287 287 static int
288 288 sysevent_subscribe(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr)
289 289 {
290 290 sev_subscribe_args_t uargs;
291 291 char *sid;
292 292 char *class_info = NULL;
293 293 evchan_ctl_t *ctl;
294 294 int rc;
295 295
296 296 ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev));
297 297 if (ctl == NULL || ctl->chp == NULL)
298 298 return (ENXIO);
299 299
300 300 if (copyin(arg, &uargs, sizeof (sev_subscribe_args_t)) != 0)
301 301 return (EFAULT);
302 302
303 303 if (uargs.sid.len > MAX_SUBID_LEN ||
304 304 uargs.class_info.len > MAX_CLASS_LEN)
305 305 return (EINVAL);
306 306
307 307 sid = kmem_alloc(uargs.sid.len, KM_SLEEP);
308 308 if (copyin((void *)(uintptr_t)uargs.sid.name,
309 309 sid, uargs.sid.len) != 0) {
310 310 kmem_free(sid, uargs.sid.len);
311 311 return (EFAULT);
312 312 }
313 313 if (!sysevent_isstrend(sid, uargs.sid.len)) {
314 314 kmem_free(sid, uargs.sid.len);
315 315 return (EINVAL);
316 316 }
317 317
318 318 /* If class string empty then class EC_ALL is assumed */
319 319 if (uargs.class_info.len != 0) {
320 320 class_info = kmem_alloc(uargs.class_info.len, KM_SLEEP);
321 321 if (copyin((void *)(uintptr_t)uargs.class_info.name, class_info,
322 322 uargs.class_info.len) != 0) {
323 323 kmem_free(class_info, uargs.class_info.len);
324 324 kmem_free(sid, uargs.sid.len);
325 325 return (EFAULT);
326 326 }
327 327 if (!sysevent_isstrend(class_info, uargs.class_info.len)) {
328 328 kmem_free(class_info, uargs.class_info.len);
329 329 kmem_free(sid, uargs.sid.len);
330 330 return (EINVAL);
331 331 }
332 332 }
333 333
334 334 /*
335 335 * Check of uargs.flags just to avoid DoS attacks
336 336 * libsysevent does this carefully.
337 337 */
338 338 rc = evch_usrsubscribe(ctl->chp, sid, class_info,
339 339 (int)uargs.door_desc, uargs.flags);
340 340
341 341 kmem_free(class_info, uargs.class_info.len);
342 342 kmem_free(sid, uargs.sid.len);
343 343
344 344 return (rc);
345 345 }
346 346
347 347 /* ARGSUSED */
348 348 static int
349 349 sysevent_unsubscribe(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr)
350 350 {
351 351 sev_unsubscribe_args_t uargs;
352 352 char *sid;
353 353 evchan_ctl_t *ctl;
354 354
355 355 if (copyin(arg, &uargs, sizeof (sev_unsubscribe_args_t)) != 0)
356 356 return (EFAULT);
357 357
358 358 ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev));
359 359 if (ctl == NULL || ctl->chp == NULL)
360 360 return (ENXIO);
361 361
362 362 if (uargs.sid.len > MAX_SUBID_LEN)
363 363 return (EINVAL);
364 364
365 365 /* Unsubscribe for all */
366 366 if (uargs.sid.len == 0) {
367 367 evch_usrunsubscribe(ctl->chp, NULL, 0);
368 368 return (0);
369 369 }
370 370
371 371 sid = kmem_alloc(uargs.sid.len, KM_SLEEP);
372 372
373 373 if (copyin((void *)(uintptr_t)uargs.sid.name,
374 374 sid, uargs.sid.len) != 0) {
375 375 kmem_free(sid, uargs.sid.len);
376 376 return (EFAULT);
377 377 }
378 378
379 379 evch_usrunsubscribe(ctl->chp, sid, 0);
380 380
381 381 kmem_free(sid, uargs.sid.len);
382 382
383 383 return (0);
384 384 }
385 385
386 386 /* ARGSUSED */
387 387 static int
388 388 sysevent_channames(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr)
389 389 {
390 390 sev_chandata_args_t uargs;
391 391 char *buf;
392 392 int len;
393 393 int rc = 0;
394 394
395 395 if (copyin(arg, &uargs, sizeof (sev_chandata_args_t)) != 0)
396 396 return (EFAULT);
397 397
398 398 if (uargs.out_data.len == 0 || uargs.out_data.len > EVCH_MAX_DATA_SIZE)
399 399 return (EINVAL);
400 400
401 401 buf = kmem_alloc(uargs.out_data.len, KM_SLEEP);
402 402
403 403 if ((len = evch_usrgetchnames(buf, uargs.out_data.len)) == -1) {
404 404 rc = EOVERFLOW;
405 405 }
406 406
407 407 if (rc == 0) {
408 408 ASSERT(len <= uargs.out_data.len);
409 409 if (copyout(buf,
410 410 (void *)(uintptr_t)uargs.out_data.name, len) != 0) {
411 411 rc = EFAULT;
412 412 }
413 413 }
414 414
415 415 kmem_free(buf, uargs.out_data.len);
416 416
417 417 return (rc);
418 418 }
419 419
420 420 /* ARGSUSED */
421 421 static int
422 422 sysevent_chandata(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr)
423 423 {
424 424 sev_chandata_args_t uargs;
425 425 char *channel;
426 426 char *buf;
427 427 int len;
428 428 int rc = 0;
429 429
430 430 if (copyin(arg, &uargs, sizeof (sev_chandata_args_t)) != 0)
431 431 return (EFAULT);
432 432
433 433 if (uargs.in_data.len > MAX_CHNAME_LEN ||
434 434 uargs.out_data.len > EVCH_MAX_DATA_SIZE)
435 435 return (EINVAL);
436 436
437 437 channel = kmem_alloc(uargs.in_data.len, KM_SLEEP);
438 438
439 439 if (copyin((void *)(uintptr_t)uargs.in_data.name, channel,
440 440 uargs.in_data.len) != 0) {
441 441 kmem_free(channel, uargs.in_data.len);
442 442 return (EFAULT);
443 443 }
444 444
445 445 if (!sysevent_isstrend(channel, uargs.in_data.len)) {
446 446 kmem_free(channel, uargs.in_data.len);
447 447 return (EINVAL);
448 448 }
449 449
450 450 buf = kmem_alloc(uargs.out_data.len, KM_SLEEP);
451 451
452 452 len = evch_usrgetchdata(channel, buf, uargs.out_data.len);
453 453 if (len == 0) {
454 454 rc = EOVERFLOW;
455 455 } else if (len == -1) {
456 456 rc = ENOENT;
457 457 }
458 458
459 459 if (rc == 0) {
460 460 ASSERT(len <= uargs.out_data.len);
461 461 if (copyout(buf,
462 462 (void *)(uintptr_t)uargs.out_data.name, len) != 0) {
463 463 rc = EFAULT;
464 464 }
465 465 }
466 466
467 467 kmem_free(buf, uargs.out_data.len);
468 468 kmem_free(channel, uargs.in_data.len);
469 469
470 470 return (rc);
471 471 }
472 472
473 473 /* ARGSUSED */
474 474 static int
475 475 sysevent_setpropnvl(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr)
476 476 {
477 477 sev_propnvl_args_t uargs;
478 478 nvlist_t *nvl = NULL;
479 479 evchan_ctl_t *ctl;
480 480 size_t bufsz;
481 481 char *buf;
482 482
483 483 ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev));
484 484 if (ctl == NULL || ctl->chp == NULL)
485 485 return (ENXIO);
486 486
487 487 if (copyin(arg, &uargs, sizeof (uargs)) != 0)
488 488 return (EFAULT);
489 489
490 490 if (uargs.packednvl.name != 0) {
491 491 bufsz = uargs.packednvl.len;
492 492
493 493 if (bufsz == 0)
494 494 return (EINVAL);
495 495
496 496 if (bufsz > EVCH_MAX_DATA_SIZE)
497 497 return (EOVERFLOW);
498 498
499 499 buf = kmem_alloc(bufsz, KM_SLEEP);
500 500
501 501 if (copyin((void *)(uintptr_t)uargs.packednvl.name, buf,
502 502 bufsz) != 0 ||
503 503 nvlist_unpack(buf, bufsz, &nvl, KM_SLEEP) != 0) {
504 504 kmem_free(buf, bufsz);
505 505 return (EFAULT);
506 506 }
507 507
508 508 kmem_free(buf, bufsz);
509 509
510 510 if (nvl == NULL)
511 511 return (EINVAL);
512 512 }
513 513
514 514 evch_usrsetpropnvl(ctl->chp, nvl);
515 515 return (0);
516 516 }
517 517
518 518 /* ARGSUSED */
519 519 static int
520 520 sysevent_getpropnvl(dev_t dev, int *rvalp, void *arg, int flag, cred_t *cr)
521 521 {
522 522 sev_propnvl_args_t uargs;
523 523 size_t reqsz, avlsz;
524 524 evchan_ctl_t *ctl;
525 525 nvlist_t *nvl;
526 526 int64_t gen;
527 527 int rc;
528 528
529 529 ctl = ddi_get_soft_state(evchan_ctlp, getminor(dev));
530 530
531 531 if (ctl == NULL || ctl->chp == NULL)
532 532 return (ENXIO);
533 533
534 534 if (copyin(arg, &uargs, sizeof (uargs)) != 0)
535 535 return (EFAULT);
536 536
537 537 if ((rc = evch_usrgetpropnvl(ctl->chp, &nvl, &gen)) != 0)
538 538 return (rc);
539 539
540 540 if (nvl != NULL) {
541 541 avlsz = uargs.packednvl.len;
542 542
543 543 if (nvlist_size(nvl, &reqsz, NV_ENCODE_NATIVE) != 0) {
544 544 nvlist_free(nvl);
545 545 return (EINVAL);
546 546 }
547 547
548 548 if (reqsz > EVCH_MAX_DATA_SIZE) {
549 549 nvlist_free(nvl);
550 550 return (E2BIG);
551 551 }
552 552
553 553 if (reqsz <= avlsz) {
554 554 char *buf = kmem_alloc(reqsz, KM_SLEEP);
555 555
556 556 if (nvlist_pack(nvl, &buf, &reqsz,
557 557 NV_ENCODE_NATIVE, 0) != 0 || copyout(buf,
558 558 (void *)(uintptr_t)uargs.packednvl.name,
559 559 reqsz) != 0) {
560 560 kmem_free(buf, reqsz);
561 561 nvlist_free(nvl);
562 562 return (EFAULT);
563 563 }
564 564 kmem_free(buf, reqsz);
565 565 rc = 0;
566 566 } else {
567 567 rc = EOVERFLOW;
568 568 }
569 569 uargs.packednvl.len = (uint32_t)reqsz;
570 570 nvlist_free(nvl);
571 571 } else {
572 572 uargs.packednvl.len = 0;
573 573 rc = 0;
574 574 }
575 575
576 576 uargs.generation = gen;
577 577 if (copyout((void *)&uargs, arg, sizeof (uargs)) != 0)
578 578 rc = EFAULT;
579 579
580 580 return (rc);
581 581 }
582 582
583 583 /*ARGSUSED*/
584 584 static int
585 585 sysevent_ioctl(dev_t dev, int cmd, intptr_t arg,
586 586 int flag, cred_t *cr, int *rvalp)
587 587 {
588 588 int rc;
589 589
590 590 switch (cmd) {
591 591 case SEV_PUBLISH:
592 592 rc = sysevent_publish(dev, rvalp, (void *)arg, flag, cr);
593 593 break;
594 594 case SEV_CHAN_OPEN:
595 595 rc = sysevent_chan_open(dev, rvalp, (void *)arg, flag, cr);
596 596 break;
597 597 case SEV_CHAN_CONTROL:
598 598 rc = sysevent_chan_control(dev, rvalp, (void *)arg, flag, cr);
599 599 break;
600 600 case SEV_SUBSCRIBE:
601 601 rc = sysevent_subscribe(dev, rvalp, (void *)arg, flag, cr);
602 602 break;
603 603 case SEV_UNSUBSCRIBE:
604 604 rc = sysevent_unsubscribe(dev, rvalp, (void *)arg, flag, cr);
605 605 break;
606 606 case SEV_CHANNAMES:
607 607 rc = sysevent_channames(dev, rvalp, (void *)arg, flag, cr);
608 608 break;
609 609 case SEV_CHANDATA:
610 610 rc = sysevent_chandata(dev, rvalp, (void *)arg, flag, cr);
611 611 break;
612 612 case SEV_SETPROPNVL:
613 613 rc = sysevent_setpropnvl(dev, rvalp, (void *)arg, flag, cr);
614 614 break;
615 615 case SEV_GETPROPNVL:
616 616 rc = sysevent_getpropnvl(dev, rvalp, (void *)arg, flag, cr);
617 617 break;
618 618 default:
619 619 rc = EINVAL;
620 620 }
621 621
622 622 return (rc);
623 623 }
624 624
625 625 /*ARGSUSED*/
626 626 static int
627 627 sysevent_open(dev_t *devp, int flag, int otyp, cred_t *cr)
628 628 {
629 629 int minor;
630 630
631 631 if (otyp != OTYP_CHR)
632 632 return (EINVAL);
633 633
634 634 if (getminor(*devp) != 0)
635 635 return (ENXIO);
636 636
637 637 minor = sysevent_minor_get();
638 638 if (minor == 0)
639 639 /* All minors are busy */
640 640 return (EBUSY);
641 641
642 642 if (ddi_soft_state_zalloc(evchan_ctlp, minor)
643 643 != DDI_SUCCESS) {
644 644 sysevent_minor_rele(minor);
645 645 return (ENOMEM);
646 646 }
647 647
648 648 *devp = makedevice(getmajor(*devp), minor);
649 649
650 650 return (0);
651 651 }
652 652
653 653 /*ARGSUSED*/
654 654 static int
655 655 sysevent_close(dev_t dev, int flag, int otyp, cred_t *cr)
656 656 {
657 657 int minor = (int)getminor(dev);
658 658 evchan_ctl_t *ctl;
659 659
660 660 if (otyp != OTYP_CHR)
661 661 return (EINVAL);
662 662
663 663 ctl = ddi_get_soft_state(evchan_ctlp, minor);
664 664 if (ctl == NULL) {
665 665 return (ENXIO);
666 666 }
667 667
668 668 if (ctl->chp) {
669 669 /* Release all non-persistant subscriptions */
670 670 evch_usrunsubscribe(ctl->chp, NULL, EVCH_SUB_KEEP);
671 671 evch_usrchanclose(ctl->chp);
672 672 }
673 673
674 674 ddi_soft_state_free(evchan_ctlp, minor);
675 675 sysevent_minor_rele(minor);
676 676
677 677 return (0);
678 678 }
679 679
680 680 /* ARGSUSED */
681 681 static int
682 682 sysevent_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
683 683 void *arg, void **result)
684 684 {
685 685 switch (infocmd) {
686 686 case DDI_INFO_DEVT2DEVINFO:
687 687 *result = sysevent_devi;
688 688 return (DDI_SUCCESS);
689 689 case DDI_INFO_DEVT2INSTANCE:
690 690 *result = 0;
691 691 return (DDI_SUCCESS);
692 692 }
693 693 return (DDI_FAILURE);
694 694 }
695 695
696 696 /* ARGSUSED */
697 697 static int
698 698 sysevent_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
699 699 {
700 700
701 701 if (cmd != DDI_ATTACH) {
702 702 return (DDI_FAILURE);
703 703 }
704 704
705 705 if (ddi_create_minor_node(devi, "sysevent", S_IFCHR,
706 706 0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
707 707 ddi_remove_minor_node(devi, NULL);
708 708 return (DDI_FAILURE);
709 709 }
710 710 sysevent_devi = devi;
711 711
712 712 sysevent_minor_init();
713 713
714 714 return (DDI_SUCCESS);
715 715 }
716 716
717 717 static int
718 718 sysevent_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
719 719 {
720 720 if (cmd != DDI_DETACH) {
721 721 return (DDI_FAILURE);
722 722 }
723 723
724 724 sysevent_minor_free(sysevent_minor_bitmap);
725 725 ddi_remove_minor_node(devi, NULL);
726 726 return (DDI_SUCCESS);
727 727 }
728 728
729 729 static struct cb_ops sysevent_cb_ops = {
730 730 sysevent_open, /* open */
731 731 sysevent_close, /* close */
732 732 nodev, /* strategy */
733 733 nodev, /* print */
734 734 nodev, /* dump */
735 735 nodev, /* read */
736 736 nodev, /* write */
737 737 sysevent_ioctl, /* ioctl */
738 738 nodev, /* devmap */
739 739 nodev, /* mmap */
740 740 nodev, /* segmap */
741 741 nochpoll, /* poll */
742 742 ddi_prop_op, /* prop_op */
743 743 0, /* streamtab */
744 744 D_NEW|D_MP, /* flag */
745 745 NULL, /* aread */
746 746 NULL /* awrite */
747 747 };
748 748
749 749 static struct dev_ops sysevent_ops = {
750 750 DEVO_REV, /* devo_rev */
751 751 0, /* refcnt */
752 752 sysevent_info, /* info */
753 753 nulldev, /* identify */
754 754 nulldev, /* probe */
755 755 sysevent_attach, /* attach */
756 756 sysevent_detach, /* detach */
757 757 nodev, /* reset */
758 758 &sysevent_cb_ops, /* driver operations */
↓ open down ↓ |
758 lines elided |
↑ open up ↑ |
759 759 (struct bus_ops *)0, /* no bus operations */
760 760 nulldev, /* power */
761 761 ddi_quiesce_not_needed, /* quiesce */
762 762 };
763 763
764 764 static struct modldrv modldrv = {
765 765 &mod_driverops, "sysevent driver", &sysevent_ops
766 766 };
767 767
768 768 static struct modlinkage modlinkage = {
769 - MODREV_1, &modldrv, NULL
769 + MODREV_1, { &modldrv, NULL }
770 770 };
771 771
772 772 int
773 773 _init(void)
774 774 {
775 775 int s;
776 776
777 777 s = ddi_soft_state_init(&evchan_ctlp, sizeof (evchan_ctl_t), 1);
778 778 if (s != 0)
779 779 return (s);
780 780
781 781 if ((s = mod_install(&modlinkage)) != 0)
782 782 ddi_soft_state_fini(&evchan_ctlp);
783 783 return (s);
784 784 }
785 785
786 786 int
787 787 _fini(void)
788 788 {
789 789 int s;
790 790
791 791 if ((s = mod_remove(&modlinkage)) != 0)
792 792 return (s);
793 793
794 794 ddi_soft_state_fini(&evchan_ctlp);
795 795 return (s);
796 796 }
797 797
798 798 int
799 799 _info(struct modinfo *modinfop)
800 800 {
801 801 return (mod_info(&modlinkage, modinfop));
802 802 }
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX