1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2013 Damian Bogel. All rights reserved.
14 */
15
16 /*
17 * Kernel module part of the Hello World pseudo-device driver for illumos.
18 */
19
20 /*
21 * TODO:
22 * - fsd_open(): check privilages
23 */
24
25 #include <sys/conf.h>
26 #include <sys/cred.h>
27 #include <sys/ddi.h>
28 #include <sys/devops.h>
29 #include <sys/errno.h>
30 #include <sys/file.h>
31 #include <sys/fsd.h>
32 #include <sys/modctl.h>
33 #include <sys/open.h>
34 #include <sys/stat.h>
35 #include <sys/sunddi.h>
36 #include <sys/types.h>
37
38 #include "fsd_impl.h"
39
40 /* Internal fsd world variables */
41 static dev_info_t *fsd_devinfo;
42
43 static int
44 fsd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
45 {
46 if (cmd != DDI_ATTACH)
47 return (DDI_FAILURE);
48
49 if (fsd_devinfo != NULL)
50 return (DDI_FAILURE);
51
52 int instance;
53 instance = ddi_get_instance(dip);
54 if (ddi_create_minor_node(dip, "fsd", S_IFCHR, instance,
55 DDI_PSEUDO, 0) == DDI_FAILURE) {
56 fsd_print("Failed to create minor node\n");
57 return (DDI_FAILURE);
58 }
59 fsd_devinfo = dip;
60 return (DDI_SUCCESS);
61 }
62
63 static int
64 fsd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
65 {
66 if (cmd != DDI_DETACH)
67 return (DDI_FAILURE);
68 ddi_remove_minor_node(dip, NULL);
69 fsd_devinfo = NULL;
70 return (DDI_SUCCESS);
71 }
72
73 static int
74 fsd_getinfo(
75 dev_info_t *dip,
76 ddi_info_cmd_t infocmd,
77 void *arg,
78 void **resultp
79 )
80 {
81 _NOTE(ARGUNUSED(dip));
82 switch (infocmd) {
83 case DDI_INFO_DEVT2DEVINFO:
84 *resultp = (void*)(uintptr_t)getminor((dev_t)arg);
85 return (DDI_SUCCESS);
86 case DDI_INFO_DEVT2INSTANCE:
87 *resultp = fsd_devinfo;
88 return (DDI_SUCCESS);
89 default:
90 return (DDI_FAILURE);
91 }
92 }
93
94 static int
95 fsd_open(dev_t *devp, int oflag, int sflag, cred_t *cred_p)
96 {
97 _NOTE(ARGUNUSED(devp));
98 _NOTE(ARGUNUSED(oflag));
99 _NOTE(ARGUNUSED(sflag));
100 _NOTE(ARGUNUSED(cred_p));
101 return (0);
102 }
103
104 static int
105 fsd_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
106 {
107 _NOTE(ARGUNUSED(dev));
108 _NOTE(ARGUNUSED(flag));
109 _NOTE(ARGUNUSED(otyp));
110 _NOTE(ARGUNUSED(cred_p));
111 return (0);
112 }
113
114 static int
115 fsd_ioctl(
116 dev_t dev,
117 int cmd,
118 intptr_t arg,
119 int mode,
120 cred_t *cred_p,
121 int *rval_p
122 )
123 {
124 _NOTE(ARGUNUSED(dev));
125 _NOTE(ARGUNUSED(cred_p));
126 _NOTE(ARGUNUSED(rval_p));
127
128 switch (cmd) {
129 case FSD_PRINT_MSG:
130 {
131 struct fsd_msg m;
132 if (ddi_copyin(
133 (void*)arg, &m.len, sizeof (m.len), mode) != 0)
134 return (EFAULT);
135 if (m.len > FSD_MAX_MSG_LEN)
136 return (EINVAL);
137 if (ddi_copyin(
138 (void*)((uintptr_t)arg + sizeof (m.len)),
139 m.s, m.len, mode) != 0)
140 return (EFAULT);
141 m.s[m.len] = '\0';
142 fsd_print(m.s);
143 break;
144 }
145 default:
146 return (EINVAL);
147 }
148 return (0);
149 }
150
151
152 static struct cb_ops cb_ops = {
153 fsd_open, /* open(9E) */
154 fsd_close, /* close(9E) */
155 nodev, /* strategy(9E) */
156 nodev, /* print(9E) */
157 nodev, /* dump(9E) */
158 nodev, /* read(9E) */
159 nodev, /* write(9E) */
160 fsd_ioctl, /* ioctl(9E) */
161 nodev, /* devmap(9E) */
162 nodev, /* mmap(9E) */
163 nodev, /* segmap(9E) */
164 nochpoll, /* chpoll(9E) */
165 ddi_prop_op, /* prop_op(9E) */
166 NULL, /* streamtab(9E) */
167 D_MP | D_64BIT, /* cb_flag(9E) */
168 CB_REV, /* cb_rev(9E) */
169 nodev, /* aread(9E) */
170 nodev, /* awrite(9E) */
171 };
172
173 static struct dev_ops dev_ops = {
174 DEVO_REV, /* driver build version */
175 0, /* reference count */
176 fsd_getinfo, /* getinfo */
177 nulldev,
178 nulldev, /* probe */
179 fsd_attach, /* attach */
180 fsd_detach, /* detach */
181 nodev,
182 &cb_ops, /* cb_ops */
183 NULL, /* bus_ops */
184 NULL, /* power */
185 ddi_quiesce_not_needed, /* quiesce */
186 };
187
188 static struct modldrv modldrv = {
189 &mod_driverops, "Filesystem Disturber Driver", &dev_ops
190 };
191
192 static struct modlinkage modlinkage = {
193 MODREV_1, &modldrv, NULL
194 };
195
196 int
197 _init(void)
198 {
199 return (mod_install(&modlinkage));
200 }
201
202 int
203 _info(struct modinfo *modinfop)
204 {
205 return (mod_info(&modlinkage, modinfop));
206 }
207
208 int
209 _fini(void)
210 {
211 return (mod_remove(&modlinkage));
212 }