ioctl32.c
来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 812 行 · 第 1/2 页
C
812 行
/* * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * S390 version * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Gerhard Tonn (ton@de.ibm.com) * * Heavily inspired by the 32-bit Sparc compat code which is * Copyright (C) 2000 Silicon Graphics, Inc. * Written by Ulf Carlsson (ulfc@engr.sgi.com) * */#include <linux/types.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/init.h>#include <linux/file.h>#include <linux/vt.h>#include <linux/kd.h>#include <linux/netdevice.h>#include <linux/route.h>#include <linux/ext2_fs.h>#include <linux/hdreg.h>#include <linux/if_bonding.h>#include <linux/loop.h>#include <linux/blkpg.h>#include <linux/blk.h>#include <linux/elevator.h>#include <linux/raw.h>#include <asm/types.h>#include <asm/uaccess.h>#include <asm/dasd.h>#include <asm/sockios.h>#include "../../../drivers/s390/char/tubio.h"#include "linux32.h"long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);struct hd_geometry32 { unsigned char heads; unsigned char sectors; unsigned short cylinders; __u32 start;}; static inline int hd_geometry_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg){ struct hd_geometry32 *hg32 = (struct hd_geometry32 *) A(arg); struct hd_geometry hg; int ret; mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_ioctl (fd, cmd, (long)&hg); set_fs (old_fs); if (ret) return ret; ret = put_user (hg.heads, &(hg32->heads)); ret |= __put_user (hg.sectors, &(hg32->sectors)); ret |= __put_user (hg.cylinders, &(hg32->cylinders)); ret |= __put_user (hg.start, &(hg32->start)); return ret;}struct timeval32 { int tv_sec; int tv_usec;};#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int)#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int)#define EXT2_IOC32_GETVERSION _IOR('v', 1, int)#define EXT2_IOC32_SETVERSION _IOW('v', 2, int)struct ifmap32 { unsigned int mem_start; unsigned int mem_end; unsigned short base_addr; unsigned char irq; unsigned char dma; unsigned char port;};struct ifreq32 {#define IFHWADDRLEN 6#define IFNAMSIZ 16 union { char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ } ifr_ifrn; union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; struct sockaddr ifru_netmask; struct sockaddr ifru_hwaddr; short ifru_flags; int ifru_ivalue; int ifru_mtu; struct ifmap32 ifru_map; char ifru_slave[IFNAMSIZ]; /* Just fits the size */ char ifru_newname[IFNAMSIZ]; __u32 ifru_data; } ifr_ifru;};struct ifconf32 { int ifc_len; /* size of buffer */ __u32 ifcbuf;};static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg){ struct ireq32 *uir32 = (struct ireq32 *) A(arg); struct net_device *dev; struct ifreq32 ifr32; if (copy_from_user(&ifr32, uir32, sizeof(struct ifreq32))) return -EFAULT; read_lock(&dev_base_lock); dev = __dev_get_by_index(ifr32.ifr_ifindex); if (!dev) { read_unlock(&dev_base_lock); return -ENODEV; } strcpy(ifr32.ifr_name, dev->name); read_unlock(&dev_base_lock); if (copy_to_user(uir32, &ifr32, sizeof(struct ifreq32))) return -EFAULT; return 0;}static inline int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg){ struct ioconf32 *uifc32 = (struct ioconf32 *) A(arg); struct ifconf32 ifc32; struct ifconf ifc; struct ifreq32 *ifr32; struct ifreq *ifr; mm_segment_t old_fs; int len; int err; if (copy_from_user(&ifc32, uifc32, sizeof(struct ifconf32))) return -EFAULT; if(ifc32.ifcbuf == 0) { ifc32.ifc_len = 0; ifc.ifc_len = 0; ifc.ifc_buf = NULL; } else { ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32))) * sizeof (struct ifreq); ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); if (!ifc.ifc_buf) return -ENOMEM; } ifr = ifc.ifc_req; ifr32 = (struct ifreq32 *) A(ifc32.ifcbuf); len = ifc32.ifc_len / sizeof (struct ifreq32); while (len--) { if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) { err = -EFAULT; goto out; } } old_fs = get_fs(); set_fs (KERNEL_DS); err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc); set_fs (old_fs); if (err) goto out; ifr = ifc.ifc_req; ifr32 = (struct ifreq32 *) A(ifc32.ifcbuf); len = ifc.ifc_len / sizeof (struct ifreq); ifc32.ifc_len = len * sizeof (struct ifreq32); while (len--) { if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) { err = -EFAULT; goto out; } } if (copy_to_user(uifc32, &ifc32, sizeof(struct ifconf32))) { err = -EFAULT; goto out; }out: if(ifc.ifc_buf != NULL) kfree (ifc.ifc_buf); return err;}static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg){ struct ifreq ifr; mm_segment_t old_fs; int err, len; u32 data; if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) return -EFAULT; ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); if (!ifr.ifr_data) return -EAGAIN; switch (cmd) { case SIOCBONDENSLAVE: case SIOCBONDRELEASE: case SIOCBONDSETHWADDR: case SIOCBONDCHANGEACTIVE: len = IFNAMSIZ * sizeof(char); break; case SIOCBONDSLAVEINFOQUERY: len = sizeof(struct ifslave); break; case SIOCBONDINFOQUERY: len = sizeof(struct ifbond); break; default: err = -EINVAL; goto out; }; __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) { err = -EFAULT; goto out; } old_fs = get_fs(); set_fs (KERNEL_DS); err = sys_ioctl (fd, cmd, (unsigned long)&ifr); set_fs (old_fs); if (!err) { len = copy_to_user((char *)A(data), ifr.ifr_data, len); if (len) err = -EFAULT; }out: free_page((unsigned long)ifr.ifr_data); return err;}static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg){ struct ifreq32 *uifr = (struct ifreq32 *) A(arg); struct ifreq ifr; mm_segment_t old_fs; int err; switch (cmd) { case SIOCSIFMAP: err = copy_from_user(&ifr, uifr, sizeof(ifr.ifr_name)); err |= __get_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start)); err |= __get_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end)); err |= __get_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr)); err |= __get_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq)); err |= __get_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma)); err |= __get_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port)); if (err) return -EFAULT; break; default: if (copy_from_user(&ifr, uifr, sizeof(struct ifreq32))) return -EFAULT; break; } old_fs = get_fs(); set_fs (KERNEL_DS); err = sys_ioctl (fd, cmd, (unsigned long)&ifr); set_fs (old_fs); if (!err) { switch (cmd) { case SIOCGIFFLAGS: case SIOCGIFMETRIC: case SIOCGIFMTU: case SIOCGIFMEM: case SIOCGIFHWADDR: case SIOCGIFINDEX: case SIOCGIFADDR: case SIOCGIFBRDADDR: case SIOCGIFDSTADDR: case SIOCGIFNETMASK: case SIOCGIFTXQLEN: if (copy_to_user(uifr, &ifr, sizeof(struct ifreq32))) return -EFAULT; break; case SIOCGIFMAP: err = copy_to_user(uifr, &ifr, sizeof(ifr.ifr_name)); err |= __put_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start)); err |= __put_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end)); err |= __put_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr)); err |= __put_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq)); err |= __put_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma)); err |= __put_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port)); if (err) err = -EFAULT; break; } } return err;}struct rtentry32{ unsigned int rt_pad1; struct sockaddr rt_dst; /* target address */ struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ struct sockaddr rt_genmask; /* target network mask (IP) */ unsigned short rt_flags; short rt_pad2; unsigned int rt_pad3; unsigned int rt_pad4; short rt_metric; /* +1 for binary compatibility! */ unsigned int rt_dev; /* forcing the device at add */ unsigned int rt_mtu; /* per route MTU/Window */#ifndef __KERNEL__#define rt_mss rt_mtu /* Compatibility :-( */#endif unsigned int rt_window; /* Window clamping */ unsigned short rt_irtt; /* Initial RTT */};static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg){ struct rtentry32 *ur = (struct rtentry32 *) A(arg); struct rtentry r; char devname[16]; u32 rtdev; int ret; mm_segment_t old_fs = get_fs(); ret = copy_from_user (&r.rt_dst, &(ur->rt_dst), 3 * sizeof(struct sockaddr)); ret |= __get_user (r.rt_flags, &(ur->rt_flags)); ret |= __get_user (r.rt_metric, &(ur->rt_metric)); ret |= __get_user (r.rt_mtu, &(ur->rt_mtu)); ret |= __get_user (r.rt_window, &(ur->rt_window)); ret |= __get_user (r.rt_irtt, &(ur->rt_irtt)); ret |= __get_user (rtdev, &(ur->rt_dev)); if (rtdev) { ret |= copy_from_user (devname, (char *) A(rtdev), 15); r.rt_dev = devname; devname[15] = 0; } else r.rt_dev = 0; if (ret) return -EFAULT; set_fs (KERNEL_DS); ret = sys_ioctl (fd, cmd, (long)&r); set_fs (old_fs); return ret;}static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg){ /* These are just misnamed, they actually get/put from/to user an int */ switch (cmd) { case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break; case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break; case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break; case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break; } return sys_ioctl(fd, cmd, arg);}struct loop_info32 { int lo_number; /* ioctl r/o */ __kernel_dev_t32 lo_device; /* ioctl r/o */ unsigned int lo_inode; /* ioctl r/o */ __kernel_dev_t32 lo_rdevice; /* ioctl r/o */ int lo_offset; int lo_encrypt_type; int lo_encrypt_key_size; /* ioctl w/o */ int lo_flags; /* ioctl r/o */ char lo_name[LO_NAME_SIZE]; unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ unsigned int lo_init[2]; char reserved[4];};static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg){ mm_segment_t old_fs = get_fs(); struct loop_info l; int err = -EINVAL; switch(cmd) { case LOOP_SET_STATUS: err = get_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number); err |= __get_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?