block: rename blk_scsi_cmd_filter to blk_cmd_filter
[linux-2.6-block.git] / block / cmd-filter.c
CommitLineData
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>
23#include <linux/parser.h>
24#include <linux/capability.h>
25#include <linux/bitops.h>
26
27#include <scsi/scsi.h>
28#include <linux/cdrom.h>
29
4beab5c6 30int blk_verify_command(struct blk_cmd_filter *filter,
abf54393 31 unsigned char *cmd, int 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
51EXPORT_SYMBOL(blk_verify_command);
52
53/* and now, the sysfs stuff */
4beab5c6 54static ssize_t rcf_cmds_show(struct blk_cmd_filter *filter, char *page,
0b07de85
AG
55 int rw)
56{
57 char *npage = page;
58 unsigned long *okbits;
59 int i;
60
61 if (rw == READ)
62 okbits = filter->read_ok;
63 else
64 okbits = filter->write_ok;
65
66 for (i = 0; i < BLK_SCSI_MAX_CMDS; i++) {
67 if (test_bit(i, okbits)) {
68 sprintf(npage, "%02x", i);
69 npage += 2;
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 81static 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 86static 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 92static ssize_t rcf_cmds_store(struct blk_cmd_filter *filter,
0b07de85
AG
93 const char *page, size_t count, int rw)
94{
95 ssize_t ret = 0;
96 unsigned long okbits[BLK_SCSI_CMD_PER_LONG], *target_okbits;
97 int cmd, status, len;
98 substring_t ss;
99
100 memset(&okbits, 0, sizeof(okbits));
101
102 for (len = strlen(page); len > 0; len -= 3) {
103 if (len < 2)
104 break;
105 ss.from = (char *) page + ret;
106 ss.to = (char *) page + ret + 2;
107 ret += 3;
108 status = match_hex(&ss, &cmd);
109 /* either of these cases means invalid input, so do nothing. */
110 if (status || cmd >= BLK_SCSI_MAX_CMDS)
111 return -EINVAL;
112
113 __set_bit(cmd, okbits);
114 }
115
116 if (rw == READ)
117 target_okbits = filter->read_ok;
118 else
119 target_okbits = filter->write_ok;
120
121 memmove(target_okbits, okbits, sizeof(okbits));
122 return count;
123}
124
4beab5c6 125static ssize_t rcf_readcmds_store(struct blk_cmd_filter *filter,
0b07de85
AG
126 const char *page, size_t count)
127{
128 return rcf_cmds_store(filter, page, count, READ);
129}
130
4beab5c6 131static ssize_t rcf_writecmds_store(struct blk_cmd_filter *filter,
0b07de85
AG
132 const char *page, size_t count)
133{
134 return rcf_cmds_store(filter, page, count, WRITE);
135}
136
137struct rcf_sysfs_entry {
138 struct attribute attr;
4beab5c6
FT
139 ssize_t (*show)(struct blk_cmd_filter *, char *);
140 ssize_t (*store)(struct blk_cmd_filter *, const char *, size_t);
0b07de85
AG
141};
142
143static struct rcf_sysfs_entry rcf_readcmds_entry = {
144 .attr = { .name = "read_table", .mode = S_IRUGO | S_IWUSR },
145 .show = rcf_readcmds_show,
146 .store = rcf_readcmds_store,
147};
148
149static struct rcf_sysfs_entry rcf_writecmds_entry = {
150 .attr = {.name = "write_table", .mode = S_IRUGO | S_IWUSR },
151 .show = rcf_writecmds_show,
152 .store = rcf_writecmds_store,
153};
154
155static struct attribute *default_attrs[] = {
156 &rcf_readcmds_entry.attr,
157 &rcf_writecmds_entry.attr,
158 NULL,
159};
160
161#define to_rcf(atr) container_of((atr), struct rcf_sysfs_entry, attr)
162
163static ssize_t
164rcf_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
165{
166 struct rcf_sysfs_entry *entry = to_rcf(attr);
4beab5c6 167 struct blk_cmd_filter *filter;
0b07de85 168
4beab5c6 169 filter = container_of(kobj, struct blk_cmd_filter, kobj);
0b07de85
AG
170 if (entry->show)
171 return entry->show(filter, page);
172
173 return 0;
174}
175
176static ssize_t
177rcf_attr_store(struct kobject *kobj, struct attribute *attr,
178 const char *page, size_t length)
179{
180 struct rcf_sysfs_entry *entry = to_rcf(attr);
4beab5c6 181 struct blk_cmd_filter *filter;
0b07de85
AG
182
183 if (!capable(CAP_SYS_RAWIO))
184 return -EPERM;
185
186 if (!entry->store)
187 return -EINVAL;
188
4beab5c6 189 filter = container_of(kobj, struct blk_cmd_filter, kobj);
0b07de85
AG
190 return entry->store(filter, page, length);
191}
192
193static struct sysfs_ops rcf_sysfs_ops = {
194 .show = rcf_attr_show,
195 .store = rcf_attr_store,
196};
197
198static struct kobj_type rcf_ktype = {
199 .sysfs_ops = &rcf_sysfs_ops,
200 .default_attrs = default_attrs,
201};
202
0b07de85
AG
203int blk_register_filter(struct gendisk *disk)
204{
205 int ret;
4beab5c6 206 struct blk_cmd_filter *filter = &disk->queue->cmd_filter;
0b07de85
AG
207 struct kobject *parent = kobject_get(disk->holder_dir->parent);
208
209 if (!parent)
210 return -ENODEV;
211
212 ret = kobject_init_and_add(&filter->kobj, &rcf_ktype, parent,
abf54393 213 "%s", "cmd_filter");
0b07de85
AG
214
215 if (ret < 0)
216 return ret;
217
0b07de85
AG
218 return 0;
219}
220
221void blk_unregister_filter(struct gendisk *disk)
222{
4beab5c6 223 struct blk_cmd_filter *filter = &disk->queue->cmd_filter;
0b07de85
AG
224
225 kobject_put(&filter->kobj);
226 kobject_put(disk->holder_dir->parent);
227}
228