Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.30-rc3 233 lines 5.6 kB view raw
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/capability.h> 24#include <linux/bitops.h> 25#include <linux/blkdev.h> 26 27#include <scsi/scsi.h> 28#include <linux/cdrom.h> 29 30int blk_verify_command(struct blk_cmd_filter *filter, 31 unsigned char *cmd, fmode_t has_write_perm) 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 */ 46 if (test_bit(cmd[0], filter->write_ok) && has_write_perm) 47 return 0; 48 49 return -EPERM; 50} 51EXPORT_SYMBOL(blk_verify_command); 52 53#if 0 54/* and now, the sysfs stuff */ 55static ssize_t rcf_cmds_show(struct blk_cmd_filter *filter, char *page, 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)) { 69 npage += sprintf(npage, "0x%02x", i); 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 81static ssize_t rcf_readcmds_show(struct blk_cmd_filter *filter, char *page) 82{ 83 return rcf_cmds_show(filter, page, READ); 84} 85 86static ssize_t rcf_writecmds_show(struct blk_cmd_filter *filter, 87 char *page) 88{ 89 return rcf_cmds_show(filter, page, WRITE); 90} 91 92static ssize_t rcf_cmds_store(struct blk_cmd_filter *filter, 93 const char *page, size_t count, int rw) 94{ 95 unsigned long okbits[BLK_SCSI_CMD_PER_LONG], *target_okbits; 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 119 /* either of these cases means invalid input, so do nothing. */ 120 if ((status == p) || cmd >= BLK_SCSI_MAX_CMDS) 121 return -EINVAL; 122 123 if (set) 124 __set_bit(cmd, okbits); 125 else 126 __clear_bit(cmd, okbits); 127 } 128 129 memcpy(target_okbits, okbits, sizeof(okbits)); 130 return count; 131} 132 133static ssize_t rcf_readcmds_store(struct blk_cmd_filter *filter, 134 const char *page, size_t count) 135{ 136 return rcf_cmds_store(filter, page, count, READ); 137} 138 139static ssize_t rcf_writecmds_store(struct blk_cmd_filter *filter, 140 const char *page, size_t count) 141{ 142 return rcf_cmds_store(filter, page, count, WRITE); 143} 144 145struct rcf_sysfs_entry { 146 struct attribute attr; 147 ssize_t (*show)(struct blk_cmd_filter *, char *); 148 ssize_t (*store)(struct blk_cmd_filter *, const char *, size_t); 149}; 150 151static 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 157static 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 163static 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 171static ssize_t 172rcf_attr_show(struct kobject *kobj, struct attribute *attr, char *page) 173{ 174 struct rcf_sysfs_entry *entry = to_rcf(attr); 175 struct blk_cmd_filter *filter; 176 177 filter = container_of(kobj, struct blk_cmd_filter, kobj); 178 if (entry->show) 179 return entry->show(filter, page); 180 181 return 0; 182} 183 184static ssize_t 185rcf_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); 189 struct blk_cmd_filter *filter; 190 191 if (!capable(CAP_SYS_RAWIO)) 192 return -EPERM; 193 194 if (!entry->store) 195 return -EINVAL; 196 197 filter = container_of(kobj, struct blk_cmd_filter, kobj); 198 return entry->store(filter, page, length); 199} 200 201static struct sysfs_ops rcf_sysfs_ops = { 202 .show = rcf_attr_show, 203 .store = rcf_attr_store, 204}; 205 206static struct kobj_type rcf_ktype = { 207 .sysfs_ops = &rcf_sysfs_ops, 208 .default_attrs = default_attrs, 209}; 210 211int blk_register_filter(struct gendisk *disk) 212{ 213 int ret; 214 struct blk_cmd_filter *filter = &disk->queue->cmd_filter; 215 216 ret = kobject_init_and_add(&filter->kobj, &rcf_ktype, 217 &disk_to_dev(disk)->kobj, 218 "%s", "cmd_filter"); 219 if (ret < 0) 220 return ret; 221 222 return 0; 223} 224EXPORT_SYMBOL(blk_register_filter); 225 226void blk_unregister_filter(struct gendisk *disk) 227{ 228 struct blk_cmd_filter *filter = &disk->queue->cmd_filter; 229 230 kobject_put(&filter->kobj); 231} 232EXPORT_SYMBOL(blk_unregister_filter); 233#endif