]>
Commit | Line | Data |
---|---|---|
0b07de85 AG |
1 | /* |
2 | * Copyright 2004 Peter M. Jones <pjones@redhat.com> | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License version 2 as | |
6 | * published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public Licens | |
15 | * along with this program; if not, write to the Free Software | |
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- | |
17 | * | |
18 | */ | |
19 | ||
20 | #include <linux/list.h> | |
21 | #include <linux/genhd.h> | |
22 | #include <linux/spinlock.h> | |
0b07de85 AG |
23 | #include <linux/capability.h> |
24 | #include <linux/bitops.h> | |
f290f197 | 25 | #include <linux/blkdev.h> |
0b07de85 AG |
26 | |
27 | #include <scsi/scsi.h> | |
28 | #include <linux/cdrom.h> | |
29 | ||
4beab5c6 | 30 | int blk_verify_command(struct blk_cmd_filter *filter, |
aeb5d727 | 31 | unsigned char *cmd, fmode_t has_write_perm) |
0b07de85 AG |
32 | { |
33 | /* root can do any command. */ | |
34 | if (capable(CAP_SYS_RAWIO)) | |
35 | return 0; | |
36 | ||
37 | /* if there's no filter set, assume we're filtering everything out */ | |
38 | if (!filter) | |
39 | return -EPERM; | |
40 | ||
41 | /* Anybody who can open the device can do a read-safe command */ | |
42 | if (test_bit(cmd[0], filter->read_ok)) | |
43 | return 0; | |
44 | ||
45 | /* Write-safe commands require a writable open */ | |
abf54393 | 46 | if (test_bit(cmd[0], filter->write_ok) && has_write_perm) |
0b07de85 AG |
47 | return 0; |
48 | ||
49 | return -EPERM; | |
50 | } | |
0b07de85 AG |
51 | EXPORT_SYMBOL(blk_verify_command); |
52 | ||
2dc75d3c | 53 | #if 0 |
0b07de85 | 54 | /* and now, the sysfs stuff */ |
4beab5c6 | 55 | static ssize_t rcf_cmds_show(struct blk_cmd_filter *filter, char *page, |
0b07de85 AG |
56 | int rw) |
57 | { | |
58 | char *npage = page; | |
59 | unsigned long *okbits; | |
60 | int i; | |
61 | ||
62 | if (rw == READ) | |
63 | okbits = filter->read_ok; | |
64 | else | |
65 | okbits = filter->write_ok; | |
66 | ||
67 | for (i = 0; i < BLK_SCSI_MAX_CMDS; i++) { | |
68 | if (test_bit(i, okbits)) { | |
a4a77897 | 69 | npage += sprintf(npage, "0x%02x", i); |
0b07de85 AG |
70 | if (i < BLK_SCSI_MAX_CMDS - 1) |
71 | sprintf(npage++, " "); | |
72 | } | |
73 | } | |
74 | ||
75 | if (npage != page) | |
76 | npage += sprintf(npage, "\n"); | |
77 | ||
78 | return npage - page; | |
79 | } | |
80 | ||
4beab5c6 | 81 | static ssize_t rcf_readcmds_show(struct blk_cmd_filter *filter, char *page) |
0b07de85 AG |
82 | { |
83 | return rcf_cmds_show(filter, page, READ); | |
84 | } | |
85 | ||
4beab5c6 | 86 | static ssize_t rcf_writecmds_show(struct blk_cmd_filter *filter, |
0b07de85 AG |
87 | char *page) |
88 | { | |
89 | return rcf_cmds_show(filter, page, WRITE); | |
90 | } | |
91 | ||
4beab5c6 | 92 | static ssize_t rcf_cmds_store(struct blk_cmd_filter *filter, |
0b07de85 AG |
93 | const char *page, size_t count, int rw) |
94 | { | |
0b07de85 | 95 | unsigned long okbits[BLK_SCSI_CMD_PER_LONG], *target_okbits; |
a4a77897 AG |
96 | int cmd, set; |
97 | char *p, *status; | |
98 | ||
99 | if (rw == READ) { | |
100 | memcpy(&okbits, filter->read_ok, sizeof(okbits)); | |
101 | target_okbits = filter->read_ok; | |
102 | } else { | |
103 | memcpy(&okbits, filter->write_ok, sizeof(okbits)); | |
104 | target_okbits = filter->write_ok; | |
105 | } | |
106 | ||
107 | while ((p = strsep((char **)&page, " ")) != NULL) { | |
108 | set = 1; | |
109 | ||
110 | if (p[0] == '+') { | |
111 | p++; | |
112 | } else if (p[0] == '-') { | |
113 | set = 0; | |
114 | p++; | |
115 | } | |
116 | ||
117 | cmd = simple_strtol(p, &status, 16); | |
118 | ||
0b07de85 | 119 | /* either of these cases means invalid input, so do nothing. */ |
a4a77897 | 120 | if ((status == p) || cmd >= BLK_SCSI_MAX_CMDS) |
0b07de85 AG |
121 | return -EINVAL; |
122 | ||
a4a77897 AG |
123 | if (set) |
124 | __set_bit(cmd, okbits); | |
125 | else | |
126 | __clear_bit(cmd, okbits); | |
0b07de85 AG |
127 | } |
128 | ||
a4a77897 | 129 | memcpy(target_okbits, okbits, sizeof(okbits)); |
0b07de85 AG |
130 | return count; |
131 | } | |
132 | ||
4beab5c6 | 133 | static ssize_t rcf_readcmds_store(struct blk_cmd_filter *filter, |
0b07de85 AG |
134 | const char *page, size_t count) |
135 | { | |
136 | return rcf_cmds_store(filter, page, count, READ); | |
137 | } | |
138 | ||
4beab5c6 | 139 | static ssize_t rcf_writecmds_store(struct blk_cmd_filter *filter, |
0b07de85 AG |
140 | const char *page, size_t count) |
141 | { | |
142 | return rcf_cmds_store(filter, page, count, WRITE); | |
143 | } | |
144 | ||
145 | struct rcf_sysfs_entry { | |
146 | struct attribute attr; | |
4beab5c6 FT |
147 | ssize_t (*show)(struct blk_cmd_filter *, char *); |
148 | ssize_t (*store)(struct blk_cmd_filter *, const char *, size_t); | |
0b07de85 AG |
149 | }; |
150 | ||
151 | static struct rcf_sysfs_entry rcf_readcmds_entry = { | |
152 | .attr = { .name = "read_table", .mode = S_IRUGO | S_IWUSR }, | |
153 | .show = rcf_readcmds_show, | |
154 | .store = rcf_readcmds_store, | |
155 | }; | |
156 | ||
157 | static struct rcf_sysfs_entry rcf_writecmds_entry = { | |
158 | .attr = {.name = "write_table", .mode = S_IRUGO | S_IWUSR }, | |
159 | .show = rcf_writecmds_show, | |
160 | .store = rcf_writecmds_store, | |
161 | }; | |
162 | ||
163 | static struct attribute *default_attrs[] = { | |
164 | &rcf_readcmds_entry.attr, | |
165 | &rcf_writecmds_entry.attr, | |
166 | NULL, | |
167 | }; | |
168 | ||
169 | #define to_rcf(atr) container_of((atr), struct rcf_sysfs_entry, attr) | |
170 | ||
171 | static ssize_t | |
172 | rcf_attr_show(struct kobject *kobj, struct attribute *attr, char *page) | |
173 | { | |
174 | struct rcf_sysfs_entry *entry = to_rcf(attr); | |
4beab5c6 | 175 | struct blk_cmd_filter *filter; |
0b07de85 | 176 | |
4beab5c6 | 177 | filter = container_of(kobj, struct blk_cmd_filter, kobj); |
0b07de85 AG |
178 | if (entry->show) |
179 | return entry->show(filter, page); | |
180 | ||
181 | return 0; | |
182 | } | |
183 | ||
184 | static ssize_t | |
185 | rcf_attr_store(struct kobject *kobj, struct attribute *attr, | |
186 | const char *page, size_t length) | |
187 | { | |
188 | struct rcf_sysfs_entry *entry = to_rcf(attr); | |
4beab5c6 | 189 | struct blk_cmd_filter *filter; |
0b07de85 AG |
190 | |
191 | if (!capable(CAP_SYS_RAWIO)) | |
192 | return -EPERM; | |
193 | ||
194 | if (!entry->store) | |
195 | return -EINVAL; | |
196 | ||
4beab5c6 | 197 | filter = container_of(kobj, struct blk_cmd_filter, kobj); |
0b07de85 AG |
198 | return entry->store(filter, page, length); |
199 | } | |
200 | ||
201 | static struct sysfs_ops rcf_sysfs_ops = { | |
202 | .show = rcf_attr_show, | |
203 | .store = rcf_attr_store, | |
204 | }; | |
205 | ||
206 | static struct kobj_type rcf_ktype = { | |
207 | .sysfs_ops = &rcf_sysfs_ops, | |
208 | .default_attrs = default_attrs, | |
209 | }; | |
210 | ||
0b07de85 AG |
211 | int blk_register_filter(struct gendisk *disk) |
212 | { | |
213 | int ret; | |
4beab5c6 | 214 | struct blk_cmd_filter *filter = &disk->queue->cmd_filter; |
0b07de85 | 215 | |
4c46501d TH |
216 | ret = kobject_init_and_add(&filter->kobj, &rcf_ktype, |
217 | &disk_to_dev(disk)->kobj, | |
abf54393 | 218 | "%s", "cmd_filter"); |
0b07de85 AG |
219 | if (ret < 0) |
220 | return ret; | |
221 | ||
0b07de85 AG |
222 | return 0; |
223 | } | |
bb23b431 | 224 | EXPORT_SYMBOL(blk_register_filter); |
0b07de85 AG |
225 | |
226 | void blk_unregister_filter(struct gendisk *disk) | |
227 | { | |
4beab5c6 | 228 | struct blk_cmd_filter *filter = &disk->queue->cmd_filter; |
0b07de85 AG |
229 | |
230 | kobject_put(&filter->kobj); | |
0b07de85 | 231 | } |
bb23b431 | 232 | EXPORT_SYMBOL(blk_unregister_filter); |
2dc75d3c | 233 | #endif |