int ptrace_set_bpt(struct task_struct *child) { unsigned long pc,next; unsigned short insn; pc = get_reg(child,PT_PC); next = insn_length((unsigned char *)pc) + pc; insn = get_fs_word(pc); if (insn == 0x5470) { /* rts */ unsigned long sp; sp = get_reg(child,PT_USP); next = get_fs_long(sp); } else if ((insn & 0xfb00) != 0x5800) { /* jmp / jsr */ int regs; const short reg_tbl[]={PT_ER0,PT_ER1,PT_ER2,PT_ER3, PT_ER4,PT_ER5,PT_ER6,PT_USP}; switch(insn & 0xfb00) { case 0x5900: regs = (insn & 0x0070) >> 8; next = get_reg(child,reg_tbl[regs]); break; case 0x5a00: next = get_fs_long(pc+2) & 0x00ffffff; break; case 0x5b00: /* unneccessary? */ next = *(unsigned long *)(insn & 0xff); break; } } else if (((insn & 0xf000) == 0x4000) || ((insn &0xff00) == 0x5500)) {
/* 向文件发送一个命令,如获取文件信息的命令, * 将文件的信息拷贝到arg所指向的内存,如关于文件的flag和版本等信息 */ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); switch (cmd) { case EXT2_IOC_GETFLAGS: put_fs_long (inode->u.ext2_i.i_flags, (long *) arg); return 0; case EXT2_IOC_SETFLAGS: if ((current->euid != inode->i_uid) && !suser()) return -EPERM; if (IS_RDONLY(inode)) return -EROFS; inode->u.ext2_i.i_flags = get_fs_long ((long *) arg); inode->i_ctime = CURRENT_TIME; inode->i_dirt = 1; return 0; case EXT2_IOC_GETVERSION: put_fs_long (inode->u.ext2_i.i_version, (long *) arg); return 0; case EXT2_IOC_SETVERSION: if ((current->euid != inode->i_uid) && !suser()) return -EPERM; if (IS_RDONLY(inode)) return -EROFS; inode->u.ext2_i.i_version = get_fs_long ((long *) arg); inode->i_ctime = CURRENT_TIME; inode->i_dirt = 1; return 0; default: return -EINVAL; } }
/* * gets the current name or the name of the connected socket. */ static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr, int *usockaddr_len, int peer) { struct unix_proto_data *upd; int len; PRINTK("unix_proto_getname: socket 0x%x for %s\n", sock, peer ? "peer" : "self"); if (peer) { if (sock->state != SS_CONNECTED) { PRINTK("unix_proto_getname: socket not connected\n"); return -EINVAL; } upd = UN_DATA(sock->conn); } else upd = UN_DATA(sock); verify_area(usockaddr_len, sizeof(*usockaddr_len)); if ((len = get_fs_long(usockaddr_len)) <= 0) return -EINVAL; if (len > upd->sockaddr_len) len = upd->sockaddr_len; if (len) { verify_area(usockaddr, len); memcpy_tofs(usockaddr, &upd->sockaddr_un, len); } put_fs_long(len, usockaddr_len); return 0; }
int sys_stime(long * tptr) { if (!suser()) return -EPERM; startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ; return 0; }
static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) { int block; switch (cmd) { case FIBMAP: if (filp->f_inode->i_op == NULL) return -EBADF; if (filp->f_inode->i_op->bmap == NULL) return -EINVAL; verify_area((void *) arg,4); block = get_fs_long((long *) arg); block = filp->f_inode->i_op->bmap(filp->f_inode,block); put_fs_long(block,(long *) arg); return 0; case FIGETBSZ: if (filp->f_inode->i_sb == NULL) return -EBADF; verify_area((void *) arg,4); put_fs_long(filp->f_inode->i_sb->s_blocksize, (long *) arg); return 0; case FIONREAD: verify_area((void *) arg,4); put_fs_long(filp->f_inode->i_size - filp->f_pos, (long *) arg); return 0; default: return -EINVAL; } }
/* * The first time we set the timezone, we will warp the clock so that * it is ticking GMT time instead of local time. Presumably, * if someone is setting the timezone then we are running in an * environment where the programs understand about timezones. * This should be done at boot time in the /etc/rc script, as * soon as possible, so that the clock can be set right. Otherwise, * various programs will get confused when the clock gets warped. */ asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz) { static int firsttime = 1; //if (!suser()) // return -EPERM; if (tz) { sys_tz.tz_minuteswest = get_fs_long((unsigned long *) tz); sys_tz.tz_dsttime = get_fs_long(((unsigned long *) tz)+1); if (firsttime) { firsttime = 0; if (!tv) warp_clock(); } } if (tv) { int sec, usec; sec = get_fs_long((unsigned long *)tv); usec = get_fs_long(((unsigned long *)tv)+1); cli(); /* This is revolting. We need to set the xtime.tv_usec * correctly. However, the value in this location is * is value at the last tick. * Discover what correction gettimeofday * would have done, and then undo it! */ usec -= do_gettimeoffset(); if (usec < 0) { usec += 1000000; sec--; } xtime.tv_sec = sec; xtime.tv_usec = usec; time_status = TIME_BAD; time_maxerror = 0x70000000; time_esterror = 0x70000000; sti(); } return 0; }
asmlinkage int sys_stime(long *tptr) { //if (!suser()) // return -EPERM; cli(); xtime.tv_sec = get_fs_long((unsigned long *) tptr); xtime.tv_usec = 0; time_status = TIME_BAD; time_maxerror = 0x70000000; time_esterror = 0x70000000; sti(); return 0; }
static int ioctl_probe(int dev, void *buffer) { int temp; unsigned int len,slen; const char * string; if ((temp = scsi_hosts[dev].present) && buffer) { len = get_fs_long ((int *) buffer); string = scsi_hosts[dev].info(); slen = strlen(string); if (len > slen) len = slen + 1; verify_area(VERIFY_WRITE, buffer, len); memcpy_tofs (buffer, string, len); } return temp; }
static int ioctl_probe(struct Scsi_Host * host, void *buffer) { int temp; unsigned int len,slen; const char * string; if ((temp = host->hostt->present) && buffer) { len = get_fs_long ((unsigned long *) buffer); string = host->hostt->info(); slen = strlen(string); if (len > slen) len = slen + 1; verify_area(VERIFY_WRITE, buffer, len); memcpy_tofs (buffer, string, len); } return temp; }
loff_t sys_lseek(unsigned int fd, loff_t * p_offset, unsigned int origin) { register struct file *file; register struct file_operations *fop; loff_t offset, tmp; offset = (loff_t) get_fs_long(p_offset); if (fd >= NR_OPEN || !(file = current->files.fd[fd]) || !(file->f_inode)) return -EBADF; if (origin > 2) return -EINVAL; fop = file->f_op; if (fop && fop->lseek) return fop->lseek(file->f_inode, file, offset, origin); /* this is the default handler if no lseek handler is present */ /* Note: We already determined above that origin is in range. */ if (origin == 2) { if (!file->f_inode) return -EINVAL; tmp = file->f_inode->i_size + offset; } else { tmp = (!origin) ? offset : file->f_pos + offset; } if (tmp < 0) return -EINVAL; if (tmp != file->f_pos) { file->f_pos = tmp; #ifdef BLOAT_FS file->f_reada = 0; file->f_version = ++event; #endif } memcpy_tofs(p_offset, &tmp, 4); return 0; }
int dac0800_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { long speed; int rc = 0; switch (cmd) { case SNDCTL_DSP_SPEED: rc = verify_area(VERIFY_READ, (void *) arg, sizeof(speed)); if (rc == 0) { speed = get_fs_long((unsigned long *) arg); dac0800_setclk(speed); } break; default: rc = -EINVAL; break; } return(rc); }
static int net_ioctl(unsigned int cmd, unsigned long arg) { int er; switch(cmd) { case DDIOCSDBG: er=verify_area(VERIFY_READ, (void *)arg, sizeof(long)); if(er) return er; net_debug = get_fs_long((long *)arg); if (net_debug != 0 && net_debug != 1) { net_debug = 0; return(-EINVAL); } return(0); default: return(-EINVAL); } /*NOTREACHED*/ return(0); }
static int ip_proto_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sockaddr_in sin; volatile struct sock *sk; int len; verify_area(uaddr_len, sizeof (len)); len = get_fs_long(uaddr_len); /* check this error. */ if (len < sizeof (sin)) return (-EINVAL); verify_area (uaddr, len); sin.sin_family=AF_INET; sk = sock->data; if (sk == NULL) { printk ("Warning: sock->data = NULL: %d\n" ,__LINE__); return (0); } if (peer) { if (sk->state != TCP_ESTABLISHED) return (-ENOTCONN); sin.sin_port = sk->dummy_th.dest; sin.sin_addr.s_addr = sk->daddr; } else { sin.sin_port = sk->dummy_th.source; sin.sin_addr.s_addr = sk->saddr; } len = sizeof (sin); memcpy_tofs(uaddr, &sin, sizeof (sin)); put_fs_long (len, uaddr_len); return (0); }
static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk=(struct sock *)sock->data; int err, pid; switch(cmd) { case FIOSETOWN: case SIOCSPGRP: err=verify_area(VERIFY_READ,(int *)arg,sizeof(long)); if(err) return err; pid = get_fs_long((int *) arg); /* see inet_fcntl */ if (current->pid != pid && current->pgrp != -pid && !suser()) return -EPERM; sk->proc = pid; return(0); case FIOGETOWN: case SIOCGPGRP: err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(long)); if(err) return err; put_fs_long(sk->proc,(int *)arg); return(0); case SIOCGSTAMP: if(sk->stamp.tv_sec==0) return -ENOENT; err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval)); if(err) return err; memcpy_tofs((void *)arg,&sk->stamp,sizeof(struct timeval)); return 0; case SIOCADDRT: case SIOCADDRTOLD: case SIOCDELRT: case SIOCDELRTOLD: return(ip_rt_ioctl(cmd,(void *) arg)); case SIOCDARP: case SIOCGARP: case SIOCSARP: return(arp_ioctl(cmd,(void *) arg)); #ifdef CONFIG_INET_RARP case SIOCDRARP: case SIOCGRARP: case SIOCSRARP: return(rarp_ioctl(cmd,(void *) arg)); #endif case SIOCGIFCONF: case SIOCGIFFLAGS: case SIOCSIFFLAGS: case SIOCGIFADDR: case SIOCSIFADDR: /* begin multicast support change */ case SIOCADDMULTI: case SIOCDELMULTI: /* end multicast support change */ case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCGIFMETRIC: case SIOCSIFMETRIC: case SIOCGIFMEM: case SIOCSIFMEM: case SIOCGIFMTU: case SIOCSIFMTU: case SIOCSIFLINK: case SIOCGIFHWADDR: case SIOCSIFHWADDR: case OLD_SIOCGIFHWADDR: case SIOCSIFMAP: case SIOCGIFMAP: case SIOCSIFSLAVE: case SIOCGIFSLAVE: return(dev_ioctl(cmd,(void *) arg)); default: if ((cmd >= SIOCDEVPRIVATE) && (cmd <= (SIOCDEVPRIVATE + 15))) return(dev_ioctl(cmd,(void *) arg)); if (sk->prot->ioctl==NULL) return(-EINVAL); return(sk->prot->ioctl(sk, cmd, arg)); } /*NOTREACHED*/ return(0); }
static int gbatxt_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { struct gbatxt_serial * info = (struct gbatxt_serial *)tty->driver_data; unsigned int val; int retval, error; int dtr, rts; if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); if (!arg) send_break(info, HZ/4); /* 1/4 second */ return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); send_break(info, arg ? arg*(HZ/10) : HZ/4); return 0; case TIOCGSOFTCAR: error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); if (error) return error; put_fs_long(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); return 0; case TIOCSSOFTCAR: arg = get_fs_long((unsigned long *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; case TIOCGSERIAL: error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct)); if (error) return error; return get_serial_info(info, (struct serial_struct *) arg); case TIOCSSERIAL: return set_serial_info(info, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)); if (error) return error; else return get_lsr_info(info, (unsigned int *) arg); case TIOCSERGSTRUCT: error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct gbatxt_serial)); if (error) return error; memcpy_tofs((struct gbatxt_serial *) arg, info, sizeof(struct gbatxt_serial)); return 0; case TIOCMGET: if ((error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)))) return(error); val = gbatxt_getsignals(info); put_user(val, (unsigned int *) arg); break; case TIOCMBIS: if ((error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)))) return(error); val = get_user((unsigned int *) arg); rts = (val & TIOCM_RTS) ? 1 : -1; dtr = (val & TIOCM_DTR) ? 1 : -1; gbatxt_setsignals(info, dtr, rts); break; case TIOCMBIC: if ((error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)))) return(error); val = get_user((unsigned int *) arg); rts = (val & TIOCM_RTS) ? 0 : -1; dtr = (val & TIOCM_DTR) ? 0 : -1; gbatxt_setsignals(info, dtr, rts); break; case TIOCMSET: if ((error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)))) return(error); val = get_user((unsigned int *) arg); rts = (val & TIOCM_RTS) ? 1 : 0; dtr = (val & TIOCM_DTR) ? 1 : 0; gbatxt_setsignals(info, dtr, rts); break; default: return -ENOIOCTLCMD; } return 0; }
asmlinkage int sys_ipc (uint call, int first, int second, int third, void* ptr, long fifth) { int version; version = call >> 16; call &= 0xffff; if (call <= SEMCTL) switch (call) { case SEMOP: return sys_semop (first, (struct sembuf *)ptr, second); case SEMGET: return sys_semget (first, second, third); case SEMCTL: { union semun fourth; int err; if (!ptr) return -EINVAL; if ((err = verify_area (VERIFY_READ, ptr, sizeof(long)))) return err; fourth.__pad = (void *) get_fs_long(ptr); return sys_semctl (first, second, third, fourth); } default: return -EINVAL; } if (call <= MSGCTL) switch (call) { case MSGSND: return sys_msgsnd (first, (struct msgbuf *) ptr, second, third); case MSGRCV: switch (version) { case 0: { struct ipc_kludge tmp; int err; if (!ptr) return -EINVAL; if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp)))) return err; memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr, sizeof (tmp)); return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); } case 1: default: return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); } case MSGGET: return sys_msgget ((key_t) first, second); case MSGCTL: return sys_msgctl (first, second, (struct msqid_ds *) ptr); default: return -EINVAL; } if (call <= SHMCTL) switch (call) { case SHMAT: switch (version) { case 0: default: { ulong raddr; int err; if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong)))) return err; err = sys_shmat (first, (char *) ptr, second, &raddr); if (err) return err; put_fs_long (raddr, (ulong *) third); return 0; } case 1: /* iBCS2 emulator entry point */ if (get_fs() != get_ds()) return -EINVAL; return sys_shmat (first, (char *) ptr, second, (ulong *) third); } case SHMDT: return sys_shmdt ((char *)ptr); case SHMGET: return sys_shmget (first, second, third); case SHMCTL: return sys_shmctl (first, second, (struct shmid_ds *) ptr); default: return -EINVAL; } return -EINVAL; }
/* * System call vectors. Since I (RIB) want to rewrite sockets as streams, * we have this level of indirection. Not a lot of overhead, since more of * the work is done via read/write/select directly. */ asmlinkage int sys_socketcall(int call, unsigned long *args) { int er; switch(call) { case SYS_SOCKET: er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); if(er) return er; return(sock_socket(get_fs_long(args+0), get_fs_long(args+1), get_fs_long(args+2))); case SYS_BIND: er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); if(er) return er; return(sock_bind(get_fs_long(args+0), (struct sockaddr *)get_fs_long(args+1), get_fs_long(args+2))); case SYS_CONNECT: er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); if(er) return er; return(sock_connect(get_fs_long(args+0), (struct sockaddr *)get_fs_long(args+1), get_fs_long(args+2))); case SYS_LISTEN: er=verify_area(VERIFY_READ, args, 2 * sizeof(long)); if(er) return er; return(sock_listen(get_fs_long(args+0), get_fs_long(args+1))); case SYS_ACCEPT: er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); if(er) return er; return(sock_accept(get_fs_long(args+0), (struct sockaddr *)get_fs_long(args+1), (int *)get_fs_long(args+2))); case SYS_GETSOCKNAME: er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); if(er) return er; return(sock_getsockname(get_fs_long(args+0), (struct sockaddr *)get_fs_long(args+1), (int *)get_fs_long(args+2))); case SYS_GETPEERNAME: er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); if(er) return er; return(sock_getpeername(get_fs_long(args+0), (struct sockaddr *)get_fs_long(args+1), (int *)get_fs_long(args+2))); case SYS_SOCKETPAIR: er=verify_area(VERIFY_READ, args, 4 * sizeof(long)); if(er) return er; return(sock_socketpair(get_fs_long(args+0), get_fs_long(args+1), get_fs_long(args+2), (unsigned long *)get_fs_long(args+3))); case SYS_SEND: er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long)); if(er) return er; return(sock_send(get_fs_long(args+0), (void *)get_fs_long(args+1), get_fs_long(args+2), get_fs_long(args+3))); case SYS_SENDTO: er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long)); if(er) return er; return(sock_sendto(get_fs_long(args+0), (void *)get_fs_long(args+1), get_fs_long(args+2), get_fs_long(args+3), (struct sockaddr *)get_fs_long(args+4), get_fs_long(args+5))); case SYS_RECV: er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long)); if(er) return er; return(sock_recv(get_fs_long(args+0), (void *)get_fs_long(args+1), get_fs_long(args+2), get_fs_long(args+3))); case SYS_RECVFROM: er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long)); if(er) return er; return(sock_recvfrom(get_fs_long(args+0), (void *)get_fs_long(args+1), get_fs_long(args+2), get_fs_long(args+3), (struct sockaddr *)get_fs_long(args+4), (int *)get_fs_long(args+5))); case SYS_SHUTDOWN: er=verify_area(VERIFY_READ, args, 2* sizeof(unsigned long)); if(er) return er; return(sock_shutdown(get_fs_long(args+0), get_fs_long(args+1))); case SYS_SETSOCKOPT: er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long)); if(er) return er; return(sock_setsockopt(get_fs_long(args+0), get_fs_long(args+1), get_fs_long(args+2), (char *)get_fs_long(args+3), get_fs_long(args+4))); case SYS_GETSOCKOPT: er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long)); if(er) return er; return(sock_getsockopt(get_fs_long(args+0), get_fs_long(args+1), get_fs_long(args+2), (char *)get_fs_long(args+3), (int *)get_fs_long(args+4))); default: return(-EINVAL); } }
int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { struct tty_struct * tty; struct tty_struct * other_tty; struct tty_struct * termios_tty; pid_t pgrp; int dev; int termios_dev; int retval; if (MAJOR(file->f_rdev) != TTY_MAJOR) { printk("tty_ioctl: tty pseudo-major != TTY_MAJOR\n"); return -EINVAL; } dev = MINOR(file->f_rdev); tty = TTY_TABLE(dev); if (!tty) return -EINVAL; if (IS_A_PTY(dev)) other_tty = tty_table[PTY_OTHER(dev)]; else other_tty = NULL; if (IS_A_PTY_MASTER(dev)) { termios_tty = other_tty; termios_dev = PTY_OTHER(dev); } else { termios_tty = tty; termios_dev = dev; } switch (cmd) { case TCGETS: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (struct termios)); if (retval) return retval; memcpy_tofs((struct termios *) arg, termios_tty->termios, sizeof (struct termios)); return 0; case TCSETSF: case TCSETSW: case TCSETS: retval = check_change(termios_tty, termios_dev); if (retval) return retval; if (cmd == TCSETSF || cmd == TCSETSW) { if (cmd == TCSETSF) flush_input(termios_tty); wait_until_sent(termios_tty, 0); } return set_termios(termios_tty, (struct termios *) arg, termios_dev); case TCGETA: return get_termio(termios_tty,(struct termio *) arg); case TCSETAF: case TCSETAW: case TCSETA: retval = check_change(termios_tty, termios_dev); if (retval) return retval; if (cmd == TCSETAF || cmd == TCSETAW) { if (cmd == TCSETAF) flush_input(termios_tty); wait_until_sent(termios_tty, 0); } return set_termio(termios_tty, (struct termio *) arg, termios_dev); case TCXONC: retval = check_change(tty, dev); if (retval) return retval; switch (arg) { case TCOOFF: stop_tty(tty); break; case TCOON: start_tty(tty); break; case TCIOFF: if (STOP_CHAR(tty) != __DISABLED_CHAR) put_tty_queue(STOP_CHAR(tty), &tty->write_q); break; case TCION: if (START_CHAR(tty) != __DISABLED_CHAR) put_tty_queue(START_CHAR(tty), &tty->write_q); break; default: return -EINVAL; } return 0; case TCFLSH: retval = check_change(tty, dev); if (retval) return retval; switch (arg) { case TCIFLUSH: flush_input(tty); break; case TCIOFLUSH: flush_input(tty); /* fall through */ case TCOFLUSH: flush_output(tty); break; default: return -EINVAL; } return 0; case TIOCEXCL: set_bit(TTY_EXCLUSIVE, &tty->flags); return 0; case TIOCNXCL: clear_bit(TTY_EXCLUSIVE, &tty->flags); return 0; case TIOCSCTTY: if (current->leader && (current->session == tty->session)) return 0; /* * The process must be a session leader and * not have a controlling tty already. */ if (!current->leader || (current->tty >= 0)) return -EPERM; if (tty->session > 0) { /* * This tty is already the controlling * tty for another session group! */ if ((arg == 1) && suser()) { /* * Steal it away */ struct task_struct *p; for_each_task(p) if (p->tty == dev) p->tty = -1; } else return -EPERM; } current->tty = dev; tty->session = current->session; tty->pgrp = current->pgrp; return 0; case TIOCGPGRP: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (pid_t)); if (retval) return retval; if (current->tty != termios_dev) return -ENOTTY; put_fs_long(termios_tty->pgrp, (pid_t *) arg); return 0; case TIOCSPGRP: retval = check_change(termios_tty, termios_dev); if (retval) return retval; if ((current->tty < 0) || (current->tty != termios_dev) || (termios_tty->session != current->session)) return -ENOTTY; pgrp = get_fs_long((pid_t *) arg); if (pgrp < 0) return -EINVAL; if (session_of_pgrp(pgrp) != current->session) return -EPERM; termios_tty->pgrp = pgrp; return 0; case TIOCOUTQ: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (unsigned long)); if (retval) return retval; put_fs_long(CHARS(&tty->write_q), (unsigned long *) arg); return 0; case TIOCINQ: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (unsigned long)); if (retval) return retval; if (L_ICANON(tty)) put_fs_long(inq_canon(tty), (unsigned long *) arg); else put_fs_long(CHARS(&tty->secondary), (unsigned long *) arg); return 0; case TIOCSTI: if ((current->tty != dev) && !suser()) return -EPERM; retval = verify_area(VERIFY_READ, (void *) arg, 1); if (retval) return retval; put_tty_queue(get_fs_byte((char *) arg), &tty->read_q); TTY_READ_FLUSH(tty); return 0; case TIOCGWINSZ: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (struct winsize)); if (retval) return retval; memcpy_tofs((struct winsize *) arg, &tty->winsize, sizeof (struct winsize)); return 0; case TIOCSWINSZ: if (IS_A_PTY_MASTER(dev)) set_window_size(other_tty,(struct winsize *) arg); return set_window_size(tty,(struct winsize *) arg); case TIOCLINUX: switch (get_fs_byte((char *)arg)) { case 0: return do_screendump(arg); case 1: return do_get_ps_info(arg); #ifdef CONFIG_SELECTION case 2: return set_selection(arg); case 3: return paste_selection(tty); case 4: unblank_screen(); return 0; #endif /* CONFIG_SELECTION */ default: return -EINVAL; } case TIOCCONS: if (IS_A_CONSOLE(dev)) { if (!suser()) return -EPERM; redirect = NULL; return 0; } if (redirect) return -EBUSY; if (!suser()) return -EPERM; if (IS_A_PTY_MASTER(dev)) redirect = other_tty; else if (IS_A_PTY_SLAVE(dev)) redirect = tty; else return -ENOTTY; return 0; case FIONBIO: arg = get_fs_long((unsigned long *) arg); if (arg) file->f_flags |= O_NONBLOCK; else file->f_flags &= ~O_NONBLOCK; return 0; case TIOCNOTTY: if (current->tty != dev) return -ENOTTY; if (current->leader) disassociate_ctty(0); current->tty = -1; return 0; case TIOCGETD: retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (unsigned long)); if (retval) return retval; put_fs_long(tty->disc, (unsigned long *) arg); return 0; case TIOCSETD: retval = check_change(tty, dev); if (retval) return retval; arg = get_fs_long((unsigned long *) arg); return tty_set_ldisc(tty, arg); case TIOCGLCKTRMIOS: arg = get_fs_long((unsigned long *) arg); retval = verify_area(VERIFY_WRITE, (void *) arg, sizeof (struct termios)); if (retval) return retval; memcpy_tofs((struct termios *) arg, &termios_locked[termios_dev], sizeof (struct termios)); return 0; case TIOCSLCKTRMIOS: if (!suser()) return -EPERM; arg = get_fs_long((unsigned long *) arg); memcpy_fromfs(&termios_locked[termios_dev], (struct termios *) arg, sizeof (struct termios)); return 0; case TIOCPKT: if (!IS_A_PTY_MASTER(dev)) return -ENOTTY; retval = verify_area(VERIFY_READ, (void *) arg, sizeof (unsigned long)); if (retval) return retval; if (get_fs_long(arg)) { if (!tty->packet) { tty->packet = 1; tty->link->ctrl_status = 0; } } else tty->packet = 0; return 0; case TCSBRK: case TCSBRKP: retval = check_change(tty, dev); if (retval) return retval; wait_until_sent(tty, 0); if (!tty->ioctl) return 0; tty->ioctl(tty, file, cmd, arg); return 0; default: if (tty->ioctl) { retval = (tty->ioctl)(tty, file, cmd, arg); if (retval != -EINVAL) return retval; } if (ldiscs[tty->disc].ioctl) { retval = (ldiscs[tty->disc].ioctl) (tty, file, cmd, arg); return retval; } return -EINVAL; }
static int ip_proto_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) { volatile struct sock *sk; int val; /* This should really pass things on to the other levels. */ if (level != SOL_SOCKET) return (-EOPNOTSUPP); sk = sock->data; if (sk == NULL) { printk ("Warning: sock->data = NULL: %d\n" ,__LINE__); return (0); } verify_area (optval, sizeof (int)); val = get_fs_long ((unsigned long *)optval); switch (optname) { case SO_TYPE: case SO_ERROR: default: return (-ENOPROTOOPT); case SO_DEBUG: /* not implemented. */ case SO_DONTROUTE: case SO_BROADCAST: case SO_SNDBUF: case SO_RCVBUF: return (0); case SO_REUSEADDR: if (val) sk->reuse = 1; else sk->reuse = 1; return (0); case SO_KEEPALIVE: if (val) sk->keepopen = 1; else sk->keepopen = 0; return (0); case SO_OOBINLINE: if (val) sk->urginline = 1; else sk->urginline = 0; return (0); case SO_NO_CHECK: if (val) sk->no_check = 1; else sk->no_check = 0; return (0); case SO_PRIORITY: if (val >= 0 && val < DEV_NUMBUFFS) { sk->priority = val; } else { return (-EINVAL); } return (0); } }
/* * We can actually return ERESTARTSYS insetad of EINTR, but I'd * like to be certain this leads to no problems. So I return * EINTR just for safety. */ int sys_select( unsigned long *buffer ) { /* Perform the select(nd, in, out, ex, tv) system call. */ int i; fd_set res_in, in = 0, *inp; fd_set res_out, out = 0, *outp; fd_set res_ex, ex = 0, *exp; fd_set mask; struct timeval *tvp; unsigned long timeout; mask = get_fs_long(buffer++); if (mask >= 32) mask = ~0; else mask = ~((~0) << mask); inp = (fd_set *) get_fs_long(buffer++); outp = (fd_set *) get_fs_long(buffer++); exp = (fd_set *) get_fs_long(buffer++); tvp = (struct timeval *) get_fs_long(buffer); if (inp) in = mask & get_fs_long(inp); if (outp) out = mask & get_fs_long(outp); if (exp) ex = mask & get_fs_long(exp); timeout = 0xffffffff; if (tvp) { timeout = get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ); timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ; timeout += jiffies; } current->timeout = timeout; i = do_select(in, out, ex, &res_in, &res_out, &res_ex); if (current->timeout > jiffies) timeout = current->timeout - jiffies; else timeout = 0; current->timeout = 0; if (tvp) { verify_area(tvp, sizeof(*tvp)); put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec); timeout %= HZ; timeout *= (1000000/HZ); put_fs_long(timeout, (unsigned long *) &tvp->tv_usec); } if (i < 0) return i; if (!i && (current->signal & ~current->blocked)) return -EINTR; if (inp) { verify_area(inp, 4); put_fs_long(res_in,inp); } if (outp) { verify_area(outp,4); put_fs_long(res_out,outp); } if (exp) { verify_area(exp,4); put_fs_long(res_ex,exp); } return i; }
static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { int error; struct LEON_serial * info = (struct LEON_serial *)tty->driver_data; int retval; if (serial_paranoia_check(info, tty->device, "rs_ioctl")) return -ENODEV; if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); if (!arg) send_break(info, HZ/4); /* 1/4 second */ return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); send_break(info, arg ? arg*(HZ/10) : HZ/4); return 0; case TIOCGSOFTCAR: error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); if (error) return error; put_fs_long(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); return 0; case TIOCSSOFTCAR: arg = get_fs_long((unsigned long *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; case TIOCGSERIAL: error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct)); if (error) return error; return get_serial_info(info, (struct serial_struct *) arg); case TIOCSSERIAL: return set_serial_info(info, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)); if (error) return error; else return get_lsr_info(info, (unsigned int *) arg); case TIOCSERGSTRUCT: error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct LEON_serial)); if (error) return error; memcpy_tofs((struct LEON_serial *) arg, info, sizeof(struct LEON_serial)); return 0; default: return -ENOIOCTLCMD; } return 0; }
int sys_mmap(unsigned long *buffer) { unsigned long base, addr; unsigned long len, limit, off; int prot, flags, mask, fd, error; struct file *file; addr = (unsigned long) get_fs_long(buffer); /* user address space*/ len = (size_t) get_fs_long(buffer+1); /* nbytes of mapping */ prot = (int) get_fs_long(buffer+2); /* protection */ flags = (int) get_fs_long(buffer+3); /* mapping type */ fd = (int) get_fs_long(buffer+4); /* object to map */ off = (unsigned long) get_fs_long(buffer+5); /* offset in object */ if (fd >= NR_OPEN || fd < 0 || !(file = current->filp[fd])) return -EBADF; if (addr > TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE-len) return -EINVAL; /* * do simple checking here so the lower-level routines won't have * to. we assume access permissions have been handled by the open * of the memory object, so we don't do any here. */ switch (flags & MAP_TYPE) { case MAP_SHARED: if ((prot & PROT_WRITE) && !(file->f_mode & 2)) return -EINVAL; /* fall through */ case MAP_PRIVATE: if (!(file->f_mode & 1)) return -EINVAL; break; default: return -EINVAL; } /* * obtain the address to map to. we verify (or select) it and ensure * that it represents a valid section of the address space. we assume * that if PROT_EXEC is specified this should be in the code segment. */ if (prot & PROT_EXEC) { base = get_base(current->ldt[1]); /* cs */ limit = get_limit(0x0f); /* cs limit */ } else { base = get_base(current->ldt[2]); /* ds */ limit = get_limit(0x17); /* ds limit */ } if (flags & MAP_FIXED) { /* * if MAP_FIXED is specified, we have to map exactly at this * address. it must be page aligned and not ambiguous. */ if ((addr & 0xfff) || addr > 0x7fffffff || addr == 0 || (off & 0xfff)) return -EINVAL; if (addr + len > limit) return -ENOMEM; } else { /* * we're given a hint as to where to put the address. * that we still need to search for a range of pages which * are not mapped and which won't impact the stack or data * segment. * in linux, we only have a code segment and data segment. * since data grows up and stack grows down, we're sort of * stuck. placing above the data will break malloc, below * the stack will cause stack overflow. because of this * we don't allow nonspecified mappings... */ return -ENOMEM; } /* * determine the object being mapped and call the appropriate * specific mapper. the address has already been validated, but * not unmapped */ if (!file->f_op || !file->f_op->mmap) return -ENODEV; mask = 0; if (prot & (PROT_READ | PROT_EXEC)) mask |= PAGE_READONLY; if (prot & PROT_WRITE) mask |= PAGE_RW; if (!mask) return -EINVAL; if ((flags & MAP_TYPE) == MAP_PRIVATE) { mask |= PAGE_COW; mask &= ~PAGE_RW; } error = file->f_op->mmap(file->f_inode, file, base + addr, len, mask, off); if (error) return error; return addr; }
static int ioctl_command(Scsi_Device *dev, void *buffer) { char * buf; char cmd[12]; char * cmd_in; Scsi_Cmnd * SCpnt; unsigned char opcode; int inlen, outlen, cmdlen; int needed; int result; if (!buffer) return -EINVAL; inlen = get_fs_long((unsigned long *) buffer); outlen = get_fs_long( ((unsigned long *) buffer) + 1); cmd_in = (char *) ( ((int *)buffer) + 2); opcode = get_fs_byte(cmd_in); needed = (inlen > outlen ? inlen : outlen); if(needed){ needed = (needed + 511) & ~511; if (needed > MAX_BUF) needed = MAX_BUF; buf = (char *) scsi_malloc(needed); if (!buf) return -ENOMEM; } else buf = NULL; memcpy_fromfs ((void *) cmd, cmd_in, cmdlen = COMMAND_SIZE (opcode)); memcpy_fromfs ((void *) buf, (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen); cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5); #ifndef DEBUG_NO_CMD SCpnt = allocate_device(NULL, dev->index, 1); scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, MAX_TIMEOUT, MAX_RETRIES); if (SCpnt->request.dev != 0xfffe){ SCpnt->request.waiting = current; current->state = TASK_UNINTERRUPTIBLE; while (SCpnt->request.dev != 0xfffe) schedule(); }; /* If there was an error condition, pass the info back to the user. */ if(SCpnt->result) { result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer)); if (result) return result; memcpy_tofs((void *) cmd_in, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer)); } else { result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF : outlen); if (result) return result; memcpy_tofs ((void *) cmd_in, buf, (outlen > MAX_BUF) ? MAX_BUF : outlen); }; result = SCpnt->result; SCpnt->request.dev = -1; /* Mark as not busy */ if (buf) scsi_free(buf, needed); wake_up(&scsi_devices[SCpnt->index].device_wait); return result; #else { int i; printk("scsi_ioctl : device %d. command = ", dev->id); for (i = 0; i < 12; ++i) printk("%02x ", cmd[i]); printk("\nbuffer ="); for (i = 0; i < 20; ++i) printk("%02x ", buf[i]); printk("\n"); printk("inlen = %d, outlen = %d, cmdlen = %d\n", inlen, outlen, cmdlen); printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in); } return 0; #endif }
int tty_ioctl(int dev, int cmd, int arg) { struct tty_struct * tty; if (MAJOR(dev) == 5) { dev=current->tty; if (dev<0) panic("tty_ioctl: dev<0"); } else dev=MINOR(dev); tty = dev + tty_table; switch (cmd) { case TCGETS: return get_termios(tty,(struct termios *) arg); case TCSETSF: flush(&tty->read_q); /* fallthrough */ case TCSETSW: wait_until_sent(tty); /* fallthrough */ case TCSETS: return set_termios(tty,(struct termios *) arg); case TCGETA: return get_termio(tty,(struct termio *) arg); case TCSETAF: flush(&tty->read_q); /* fallthrough */ case TCSETAW: wait_until_sent(tty); /* fallthrough */ case TCSETA: return set_termio(tty,(struct termio *) arg); case TCSBRK: if (!arg) { wait_until_sent(tty); send_break(tty); } return 0; case TCXONC: return -EINVAL; /* not implemented */ case TCFLSH: if (arg==0) flush(&tty->read_q); else if (arg==1) flush(&tty->write_q); else if (arg==2) { flush(&tty->read_q); flush(&tty->write_q); } else return -EINVAL; return 0; case TIOCEXCL: return -EINVAL; /* not implemented */ case TIOCNXCL: return -EINVAL; /* not implemented */ case TIOCSCTTY: return -EINVAL; /* set controlling term NI */ case TIOCGPGRP: verify_area((void *) arg,4); put_fs_long(tty->pgrp,(unsigned long *) arg); return 0; case TIOCSPGRP: tty->pgrp=get_fs_long((unsigned long *) arg); return 0; case TIOCOUTQ: verify_area((void *) arg,4); put_fs_long(CHARS(tty->write_q),(unsigned long *) arg); return 0; case TIOCSTI: return -EINVAL; /* not implemented */ case TIOCGWINSZ: return -EINVAL; /* not implemented */ case TIOCSWINSZ: return -EINVAL; /* not implemented */ case TIOCMGET: return -EINVAL; /* not implemented */ case TIOCMBIS: return -EINVAL; /* not implemented */ case TIOCMBIC: return -EINVAL; /* not implemented */ case TIOCMSET: return -EINVAL; /* not implemented */ case TIOCGSOFTCAR: return -EINVAL; /* not implemented */ case TIOCSSOFTCAR: return -EINVAL; /* not implemented */ default: return -EINVAL; } }
static int math_emulate(struct trapframe * info) { unsigned short code; temp_real tmp; char * address; u_long oldeip; /* ever used fp? */ if ((((struct pcb *)curproc->p_addr)->pcb_flags & FP_SOFTFP) == 0) { ((struct pcb *)curproc->p_addr)->pcb_flags |= FP_SOFTFP; I387.cwd = 0x037f; I387.swd = 0x0000; I387.twd = 0x0000; } if (I387.cwd & I387.swd & 0x3f) I387.swd |= 0x8000; else I387.swd &= 0x7fff; oldeip = info->tf_eip; /* 0x001f means user code space */ if ((u_short)info->tf_cs != 0x001F) { printf("math_emulate: %04x:%08lx\n", (u_short)info->tf_cs, oldeip); panic("?Math emulation needed in kernel?"); } code = get_fs_word((unsigned short *) oldeip); bswapw(code); code &= 0x7ff; I387.fip = oldeip; *(unsigned short *) &I387.fcs = (u_short) info->tf_cs; *(1+(unsigned short *) &I387.fcs) = code; info->tf_eip += 2; switch (code) { case 0x1d0: /* fnop */ return(0); case 0x1d1: case 0x1d2: case 0x1d3: /* fst to 32-bit mem */ case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: math_abort(info,SIGILL); case 0x1e0: /* fchs */ ST(0).exponent ^= 0x8000; return(0); case 0x1e1: /* fabs */ ST(0).exponent &= 0x7fff; return(0); case 0x1e2: case 0x1e3: math_abort(info,SIGILL); case 0x1e4: /* ftst */ ftst(PST(0)); return(0); case 0x1e5: /* fxam */ printf("fxam not implemented\n"); math_abort(info,SIGILL); case 0x1e6: case 0x1e7: /* fldenv */ math_abort(info,SIGILL); case 0x1e8: /* fld1 */ fpush(); ST(0) = CONST1; return(0); case 0x1e9: /* fld2t */ fpush(); ST(0) = CONSTL2T; return(0); case 0x1ea: /* fld2e */ fpush(); ST(0) = CONSTL2E; return(0); case 0x1eb: /* fldpi */ fpush(); ST(0) = CONSTPI; return(0); case 0x1ec: /* fldlg2 */ fpush(); ST(0) = CONSTLG2; return(0); case 0x1ed: /* fldln2 */ fpush(); ST(0) = CONSTLN2; return(0); case 0x1ee: /* fldz */ fpush(); ST(0) = CONSTZ; return(0); case 0x1ef: math_abort(info,SIGILL); case 0x1f0: /* f2xm1 */ case 0x1f1: /* fyl2x */ case 0x1f2: /* fptan */ case 0x1f3: /* fpatan */ case 0x1f4: /* fxtract */ case 0x1f5: /* fprem1 */ case 0x1f6: /* fdecstp */ case 0x1f7: /* fincstp */ case 0x1f8: /* fprem */ case 0x1f9: /* fyl2xp1 */ case 0x1fa: /* fsqrt */ case 0x1fb: /* fsincos */ case 0x1fe: /* fsin */ case 0x1ff: /* fcos */ uprintf( "math_emulate: instruction %04x not implemented\n", code + 0xd800); math_abort(info,SIGILL); case 0x1fc: /* frndint */ frndint(PST(0),&tmp); real_to_real(&tmp,&ST(0)); return(0); case 0x1fd: /* fscale */ /* incomplete and totally inadequate -wfj */ Fscale(PST(0), PST(1), &tmp); real_to_real(&tmp,&ST(0)); return(0); /* 19 Sep 92*/ case 0x2e9: /* ????? */ /* if this should be a fucomp ST(0),ST(1) , it must be a 0x3e9 ATS */ fucom(PST(1),PST(0)); fpop(); fpop(); return(0); case 0x3d0: case 0x3d1: /* fist ?? */ return(0); case 0x3e2: /* fclex */ I387.swd &= 0x7f00; return(0); case 0x3e3: /* fninit */ I387.cwd = 0x037f; I387.swd = 0x0000; I387.twd = 0x0000; return(0); case 0x3e4: return(0); case 0x6d9: /* fcompp */ fcom(PST(1),PST(0)); fpop(); fpop(); return(0); case 0x7e0: /* fstsw ax */ *(short *) &info->tf_eax = I387.swd; return(0); } switch (code >> 3) { case 0x18: /* fadd */ fadd(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(0)); return(0); case 0x19: /* fmul */ fmul(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(0)); return(0); case 0x1a: /* fcom */ fcom(PST(code & 7),PST(0)); return(0); case 0x1b: /* fcomp */ fcom(PST(code & 7),PST(0)); fpop(); return(0); case 0x1c: /* fsubr */ real_to_real(&ST(code & 7),&tmp); tmp.exponent ^= 0x8000; fadd(PST(0),&tmp,&tmp); real_to_real(&tmp,&ST(0)); return(0); case 0x1d: /* fsub */ ST(0).exponent ^= 0x8000; fadd(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(0)); return(0); case 0x1e: /* fdivr */ fdiv(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(0)); return(0); case 0x1f: /* fdiv */ fdiv(PST(code & 7),PST(0),&tmp); real_to_real(&tmp,&ST(0)); return(0); case 0x38: /* fld */ fpush(); ST(0) = ST((code & 7)+1); /* why plus 1 ????? ATS */ return(0); case 0x39: /* fxch */ fxchg(&ST(0),&ST(code & 7)); return(0); case 0x3b: /* ??? ??? wrong ???? ATS */ ST(code & 7) = ST(0); fpop(); return(0); case 0x98: /* fadd */ fadd(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(code & 7)); return(0); case 0x99: /* fmul */ fmul(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(code & 7)); return(0); case 0x9a: /* ???? , my manual don't list a direction bit for fcom , ??? ATS */ fcom(PST(code & 7),PST(0)); return(0); case 0x9b: /* same as above , ATS */ fcom(PST(code & 7),PST(0)); fpop(); return(0); case 0x9c: /* fsubr */ ST(code & 7).exponent ^= 0x8000; fadd(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(code & 7)); return(0); case 0x9d: /* fsub */ real_to_real(&ST(0),&tmp); tmp.exponent ^= 0x8000; fadd(PST(code & 7),&tmp,&tmp); real_to_real(&tmp,&ST(code & 7)); return(0); case 0x9e: /* fdivr */ fdiv(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(code & 7)); return(0); case 0x9f: /* fdiv */ fdiv(PST(code & 7),PST(0),&tmp); real_to_real(&tmp,&ST(code & 7)); return(0); case 0xb8: /* ffree */ printf("ffree not implemented\n"); math_abort(info,SIGILL); case 0xb9: /* fstp ???? where is the pop ? ATS */ fxchg(&ST(0),&ST(code & 7)); return(0); case 0xba: /* fst */ ST(code & 7) = ST(0); return(0); case 0xbb: /* ????? encoding of fstp to mem ? ATS */ ST(code & 7) = ST(0); fpop(); return(0); case 0xbc: /* fucom */ fucom(PST(code & 7),PST(0)); return(0); case 0xbd: /* fucomp */ fucom(PST(code & 7),PST(0)); fpop(); return(0); case 0xd8: /* faddp */ fadd(PST(code & 7),PST(0),&tmp); real_to_real(&tmp,&ST(code & 7)); fpop(); return(0); case 0xd9: /* fmulp */ fmul(PST(code & 7),PST(0),&tmp); real_to_real(&tmp,&ST(code & 7)); fpop(); return(0); case 0xda: /* ??? encoding of ficom with 16 bit mem ? ATS */ fcom(PST(code & 7),PST(0)); fpop(); return(0); case 0xdc: /* fsubrp */ ST(code & 7).exponent ^= 0x8000; fadd(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(code & 7)); fpop(); return(0); case 0xdd: /* fsubp */ real_to_real(&ST(0),&tmp); tmp.exponent ^= 0x8000; fadd(PST(code & 7),&tmp,&tmp); real_to_real(&tmp,&ST(code & 7)); fpop(); return(0); case 0xde: /* fdivrp */ fdiv(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(code & 7)); fpop(); return(0); case 0xdf: /* fdivp */ fdiv(PST(code & 7),PST(0),&tmp); real_to_real(&tmp,&ST(code & 7)); fpop(); return(0); case 0xf8: /* fild 16-bit mem ???? ATS */ printf("ffree not implemented\n"); math_abort(info,SIGILL); fpop(); return(0); case 0xf9: /* ????? ATS */ fxchg(&ST(0),&ST(code & 7)); return(0); case 0xfa: /* fist 16-bit mem ? ATS */ case 0xfb: /* fistp 16-bit mem ? ATS */ ST(code & 7) = ST(0); fpop(); return(0); } switch ((code>>3) & 0xe7) { case 0x22: put_short_real(PST(0),info,code); return(0); case 0x23: put_short_real(PST(0),info,code); fpop(); return(0); case 0x24: address = ea(info,code); for (code = 0 ; code < 7 ; code++) { ((long *) & I387)[code] = get_fs_long((unsigned long *) address); address += 4; } return(0); case 0x25: address = ea(info,code); *(unsigned short *) &I387.cwd = get_fs_word((unsigned short *) address); return(0); case 0x26: address = ea(info,code); /*verify_area(address,28);*/ for (code = 0 ; code < 7 ; code++) { put_fs_long( ((long *) & I387)[code], (unsigned long *) address); address += 4; } return(0); case 0x27: address = ea(info,code); /*verify_area(address,2);*/ put_fs_word(I387.cwd,(short *) address); return(0); case 0x62: put_long_int(PST(0),info,code); return(0); case 0x63: put_long_int(PST(0),info,code); fpop(); return(0); case 0x65: fpush(); get_temp_real(&tmp,info,code); real_to_real(&tmp,&ST(0)); return(0); case 0x67: put_temp_real(PST(0),info,code); fpop(); return(0); case 0xa2: put_long_real(PST(0),info,code); return(0); case 0xa3: put_long_real(PST(0),info,code); fpop(); return(0); case 0xa4: address = ea(info,code); for (code = 0 ; code < 27 ; code++) { ((long *) & I387)[code] = get_fs_long((unsigned long *) address); address += 4; } return(0); case 0xa6: address = ea(info,code); /*verify_area(address,108);*/ for (code = 0 ; code < 27 ; code++) { put_fs_long( ((long *) & I387)[code], (unsigned long *) address); address += 4; } I387.cwd = 0x037f; I387.swd = 0x0000; I387.twd = 0x0000; return(0); case 0xa7: address = ea(info,code); /*verify_area(address,2);*/ put_fs_word(I387.swd,(short *) address); return(0); case 0xe2: put_short_int(PST(0),info,code); return(0); case 0xe3: put_short_int(PST(0),info,code); fpop(); return(0); case 0xe4: fpush(); get_BCD(&tmp,info,code); real_to_real(&tmp,&ST(0)); return(0); case 0xe5: fpush(); get_longlong_int(&tmp,info,code); real_to_real(&tmp,&ST(0)); return(0); case 0xe6: put_BCD(PST(0),info,code); fpop(); return(0); case 0xe7: put_longlong_int(PST(0),info,code); fpop(); return(0); } switch (code >> 9) { case 0: get_short_real(&tmp,info,code); break; case 1: get_long_int(&tmp,info,code); break; case 2: get_long_real(&tmp,info,code); break; case 4: get_short_int(&tmp,info,code); } switch ((code>>3) & 0x27) { case 0: fadd(&tmp,PST(0),&tmp); real_to_real(&tmp,&ST(0)); return(0); case 1: fmul(&tmp,PST(0),&tmp); real_to_real(&tmp,&ST(0)); return(0); case 2: fcom(&tmp,PST(0)); return(0); case 3: fcom(&tmp,PST(0)); fpop(); return(0); case 4: tmp.exponent ^= 0x8000; fadd(&tmp,PST(0),&tmp); real_to_real(&tmp,&ST(0)); return(0); case 5: ST(0).exponent ^= 0x8000; fadd(&tmp,PST(0),&tmp); real_to_real(&tmp,&ST(0)); return(0); case 6: fdiv(PST(0),&tmp,&tmp); real_to_real(&tmp,&ST(0)); return(0); case 7: fdiv(&tmp,PST(0),&tmp); real_to_real(&tmp,&ST(0)); return(0); } if ((code & 0x138) == 0x100) { fpush(); real_to_real(&tmp,&ST(0)); return(0); } printf("Unknown math-insns: %04x:%08x %04x\n",(u_short)info->tf_cs, info->tf_eip,code); math_abort(info,SIGFPE); }
static int timer_ioctl (int dev, unsigned int cmd, caddr_t arg) { switch (cmd) { case SNDCTL_TMR_SOURCE: return snd_ioctl_return ((int *) arg, TMR_INTERNAL); break; case SNDCTL_TMR_START: tmr_reset (); tmr_running = 1; return 0; break; case SNDCTL_TMR_STOP: tmr_running = 0; return 0; break; case SNDCTL_TMR_CONTINUE: tmr_running = 1; return 0; break; case SNDCTL_TMR_TIMEBASE: { int val = get_fs_long ((long *) arg); if (val) { if (val < 1) val = 1; if (val > 1000) val = 1000; curr_timebase = val; } return snd_ioctl_return ((int *) arg, curr_timebase); } break; case SNDCTL_TMR_TEMPO: { int val = get_fs_long ((long *) arg); if (val) { if (val < 8) val = 8; if (val > 250) val = 250; tmr_offs = tmr_ctr; ticks_offs += tmr2ticks (tmr_ctr); tmr_ctr = 0; curr_tempo = val; reprogram_timer (); } return snd_ioctl_return ((int *) arg, curr_tempo); } break; case SNDCTL_SEQ_CTRLRATE: if (get_fs_long ((long *) arg) != 0) /* Can't change */ return -(EINVAL); return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60); break; case SNDCTL_TMR_METRONOME: /* NOP */ break; default:; } return -(EINVAL); }
static void do_emu(struct info * info) { unsigned short code; temp_real tmp; char * address; if (I387.cwd & I387.swd & 0x3f) I387.swd |= 0x8000; else I387.swd &= 0x7fff; ORIG_EIP = EIP; /* 0x0007 means user code space */ if (CS != 0x000F) { printk("math_emulate: %04x:%08x\n\r",CS,EIP); panic("Math emulation needed in kernel"); } code = get_fs_word((unsigned short *) EIP); bswapw(code); code &= 0x7ff; I387.fip = EIP; *(unsigned short *) &I387.fcs = CS; *(1+(unsigned short *) &I387.fcs) = code; EIP += 2; switch (code) { case 0x1d0: /* fnop */ return; case 0x1d1: case 0x1d2: case 0x1d3: case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: math_abort(info,1<<(SIGILL-1)); case 0x1e0: ST(0).exponent ^= 0x8000; return; case 0x1e1: ST(0).exponent &= 0x7fff; return; case 0x1e2: case 0x1e3: math_abort(info,1<<(SIGILL-1)); case 0x1e4: ftst(PST(0)); return; case 0x1e5: printk("fxam not implemented\n\r"); math_abort(info,1<<(SIGILL-1)); case 0x1e6: case 0x1e7: math_abort(info,1<<(SIGILL-1)); case 0x1e8: fpush(); ST(0) = CONST1; return; case 0x1e9: fpush(); ST(0) = CONSTL2T; return; case 0x1ea: fpush(); ST(0) = CONSTL2E; return; case 0x1eb: fpush(); ST(0) = CONSTPI; return; case 0x1ec: fpush(); ST(0) = CONSTLG2; return; case 0x1ed: fpush(); ST(0) = CONSTLN2; return; case 0x1ee: fpush(); ST(0) = CONSTZ; return; case 0x1ef: math_abort(info,1<<(SIGILL-1)); case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3: case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7: case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb: case 0x1fc: case 0x1fd: case 0x1fe: case 0x1ff: printk("%04x fxxx not implemented\n\r",code + 0xc800); math_abort(info,1<<(SIGILL-1)); case 0x2e9: fucom(PST(1),PST(0)); fpop(); fpop(); return; case 0x3d0: case 0x3d1: return; case 0x3e2: I387.swd &= 0x7f00; return; case 0x3e3: I387.cwd = 0x037f; I387.swd = 0x0000; I387.twd = 0x0000; return; case 0x3e4: return; case 0x6d9: fcom(PST(1),PST(0)); fpop(); fpop(); return; case 0x7e0: *(short *) &EAX = I387.swd; return; } switch (code >> 3) { case 0x18: fadd(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(0)); return; case 0x19: fmul(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(0)); return; case 0x1a: fcom(PST(code & 7),&tmp); real_to_real(&tmp,&ST(0)); return; case 0x1b: fcom(PST(code & 7),&tmp); real_to_real(&tmp,&ST(0)); fpop(); return; case 0x1c: real_to_real(&ST(code & 7),&tmp); tmp.exponent ^= 0x8000; fadd(PST(0),&tmp,&tmp); real_to_real(&tmp,&ST(0)); return; case 0x1d: ST(0).exponent ^= 0x8000; fadd(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(0)); return; case 0x1e: fdiv(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(0)); return; case 0x1f: fdiv(PST(code & 7),PST(0),&tmp); real_to_real(&tmp,&ST(0)); return; case 0x38: fpush(); ST(0) = ST((code & 7)+1); return; case 0x39: fxchg(&ST(0),&ST(code & 7)); return; case 0x3b: ST(code & 7) = ST(0); fpop(); return; case 0x98: fadd(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(code & 7)); return; case 0x99: fmul(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(code & 7)); return; case 0x9a: fcom(PST(code & 7),PST(0)); return; case 0x9b: fcom(PST(code & 7),PST(0)); fpop(); return; case 0x9c: ST(code & 7).exponent ^= 0x8000; fadd(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(code & 7)); return; case 0x9d: real_to_real(&ST(0),&tmp); tmp.exponent ^= 0x8000; fadd(PST(code & 7),&tmp,&tmp); real_to_real(&tmp,&ST(code & 7)); return; case 0x9e: fdiv(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(code & 7)); return; case 0x9f: fdiv(PST(code & 7),PST(0),&tmp); real_to_real(&tmp,&ST(code & 7)); return; case 0xb8: printk("ffree not implemented\n\r"); math_abort(info,1<<(SIGILL-1)); case 0xb9: fxchg(&ST(0),&ST(code & 7)); return; case 0xba: ST(code & 7) = ST(0); return; case 0xbb: ST(code & 7) = ST(0); fpop(); return; case 0xbc: fucom(PST(code & 7),PST(0)); return; case 0xbd: fucom(PST(code & 7),PST(0)); fpop(); return; case 0xd8: fadd(PST(code & 7),PST(0),&tmp); real_to_real(&tmp,&ST(code & 7)); fpop(); return; case 0xd9: fmul(PST(code & 7),PST(0),&tmp); real_to_real(&tmp,&ST(code & 7)); fpop(); return; case 0xda: fcom(PST(code & 7),PST(0)); fpop(); return; case 0xdc: ST(code & 7).exponent ^= 0x8000; fadd(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(code & 7)); fpop(); return; case 0xdd: real_to_real(&ST(0),&tmp); tmp.exponent ^= 0x8000; fadd(PST(code & 7),&tmp,&tmp); real_to_real(&tmp,&ST(code & 7)); fpop(); return; case 0xde: fdiv(PST(0),PST(code & 7),&tmp); real_to_real(&tmp,&ST(code & 7)); fpop(); return; case 0xdf: fdiv(PST(code & 7),PST(0),&tmp); real_to_real(&tmp,&ST(code & 7)); fpop(); return; case 0xf8: printk("ffree not implemented\n\r"); math_abort(info,1<<(SIGILL-1)); fpop(); return; case 0xf9: fxchg(&ST(0),&ST(code & 7)); return; case 0xfa: case 0xfb: ST(code & 7) = ST(0); fpop(); return; } switch ((code>>3) & 0xe7) { case 0x22: put_short_real(PST(0),info,code); return; case 0x23: put_short_real(PST(0),info,code); fpop(); return; case 0x24: address = ea(info,code); for (code = 0 ; code < 7 ; code++) { ((long *) & I387)[code] = get_fs_long((unsigned long *) address); address += 4; } return; case 0x25: address = ea(info,code); *(unsigned short *) &I387.cwd = get_fs_word((unsigned short *) address); return; case 0x26: address = ea(info,code); verify_area(address,28); for (code = 0 ; code < 7 ; code++) { put_fs_long( ((long *) & I387)[code], (unsigned long *) address); address += 4; } return; case 0x27: address = ea(info,code); verify_area(address,2); put_fs_word(I387.cwd,(short *) address); return; case 0x62: put_long_int(PST(0),info,code); return; case 0x63: put_long_int(PST(0),info,code); fpop(); return; case 0x65: fpush(); get_temp_real(&tmp,info,code); real_to_real(&tmp,&ST(0)); return; case 0x67: put_temp_real(PST(0),info,code); fpop(); return; case 0xa2: put_long_real(PST(0),info,code); return; case 0xa3: put_long_real(PST(0),info,code); fpop(); return; case 0xa4: address = ea(info,code); for (code = 0 ; code < 27 ; code++) { ((long *) & I387)[code] = get_fs_long((unsigned long *) address); address += 4; } return; case 0xa6: address = ea(info,code); verify_area(address,108); for (code = 0 ; code < 27 ; code++) { put_fs_long( ((long *) & I387)[code], (unsigned long *) address); address += 4; } I387.cwd = 0x037f; I387.swd = 0x0000; I387.twd = 0x0000; return; case 0xa7: address = ea(info,code); verify_area(address,2); put_fs_word(I387.swd,(short *) address); return; case 0xe2: put_short_int(PST(0),info,code); return; case 0xe3: put_short_int(PST(0),info,code); fpop(); return; case 0xe4: fpush(); get_BCD(&tmp,info,code); real_to_real(&tmp,&ST(0)); return; case 0xe5: fpush(); get_longlong_int(&tmp,info,code); real_to_real(&tmp,&ST(0)); return; case 0xe6: put_BCD(PST(0),info,code); fpop(); return; case 0xe7: put_longlong_int(PST(0),info,code); fpop(); return; } switch (code >> 9) { case 0: get_short_real(&tmp,info,code); break; case 1: get_long_int(&tmp,info,code); break; case 2: get_long_real(&tmp,info,code); break; case 4: get_short_int(&tmp,info,code); } switch ((code>>3) & 0x27) { case 0: fadd(&tmp,PST(0),&tmp); real_to_real(&tmp,&ST(0)); return; case 1: fmul(&tmp,PST(0),&tmp); real_to_real(&tmp,&ST(0)); return; case 2: fcom(&tmp,PST(0)); return; case 3: fcom(&tmp,PST(0)); fpop(); return; case 4: tmp.exponent ^= 0x8000; fadd(&tmp,PST(0),&tmp); real_to_real(&tmp,&ST(0)); return; case 5: ST(0).exponent ^= 0x8000; fadd(&tmp,PST(0),&tmp); real_to_real(&tmp,&ST(0)); return; case 6: fdiv(PST(0),&tmp,&tmp); real_to_real(&tmp,&ST(0)); return; case 7: fdiv(&tmp,PST(0),&tmp); real_to_real(&tmp,&ST(0)); return; } if ((code & 0x138) == 0x100) { fpush(); real_to_real(&tmp,&ST(0)); return; } printk("Unknown math-insns: %04x:%08x %04x\n\r",CS,EIP,code); math_abort(info,1<<(SIGFPE-1)); }
int sys_semctl (int semid, int semnum, int cmd, void *arg) { int i, id, val = 0; struct semid_ds *sma, *buf = NULL, tbuf; struct ipc_perm *ipcp; struct sem *curr; struct sem_undo *un; ushort nsems, *array = NULL; ushort sem_io[SEMMSL]; if (semid < 0 || semnum < 0 || cmd < 0) return -EINVAL; switch (cmd) { case IPC_INFO: case SEM_INFO: { struct seminfo seminfo, *tmp; if (!arg || ! (tmp = (struct seminfo *) get_fs_long((int *)arg))) return -EFAULT; seminfo.semmni = SEMMNI; seminfo.semmns = SEMMNS; seminfo.semmsl = SEMMSL; seminfo.semopm = SEMOPM; seminfo.semvmx = SEMVMX; seminfo.semmnu = SEMMNU; seminfo.semmap = SEMMAP; seminfo.semume = SEMUME; seminfo.semusz = SEMUSZ; seminfo.semaem = SEMAEM; if (cmd == SEM_INFO) { seminfo.semusz = used_semids; seminfo.semaem = used_sems; } i= verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo)); if (i) return i; memcpy_tofs (tmp, &seminfo, sizeof(struct seminfo)); return max_semid; } case SEM_STAT: if (!arg || ! (buf = (struct semid_ds *) get_fs_long((int *) arg))) return -EFAULT; i = verify_area (VERIFY_WRITE, buf, sizeof (*sma)); if (i) return i; if (semid > max_semid) return -EINVAL; sma = semary[semid]; if (sma == IPC_UNUSED || sma == IPC_NOID) return -EINVAL; if (ipcperms (&sma->sem_perm, S_IRUGO)) return -EACCES; id = semid + sma->sem_perm.seq * SEMMNI; memcpy_tofs (buf, sma, sizeof(*sma)); return id; } id = semid % SEMMNI; sma = semary [id]; if (sma == IPC_UNUSED || sma == IPC_NOID) return -EINVAL; ipcp = &sma->sem_perm; nsems = sma->sem_nsems; if (ipcp->seq != semid / SEMMNI) return -EIDRM; if (semnum >= nsems) return -EINVAL; curr = &sma->sem_base[semnum]; switch (cmd) { case GETVAL: case GETPID: case GETNCNT: case GETZCNT: case GETALL: if (ipcperms (ipcp, S_IRUGO)) return -EACCES; switch (cmd) { case GETVAL : return curr->semval; case GETPID : return curr->sempid; case GETNCNT: return curr->semncnt; case GETZCNT: return curr->semzcnt; case GETALL: if (!arg || ! (array = (ushort *) get_fs_long((int *) arg))) return -EFAULT; i = verify_area (VERIFY_WRITE, array, nsems*sizeof(short)); if (i) return i; } break; case SETVAL: if (!arg) return -EFAULT; if ((val = (int) get_fs_long ((int *) arg)) > SEMVMX || val < 0) return -ERANGE; break; case IPC_RMID: if (suser() || current->euid == ipcp->cuid || current->euid == ipcp->uid) { freeary (id); return 0; } return -EPERM; case SETALL: /* arg is a pointer to an array of ushort */ if (!arg || ! (array = (ushort *) get_fs_long ((int *) arg)) ) return -EFAULT; if ((i = verify_area (VERIFY_READ, array, sizeof tbuf))) return i; memcpy_fromfs (sem_io, array, nsems*sizeof(ushort)); for (i=0; i< nsems; i++) if (sem_io[i] > SEMVMX) return -ERANGE; break; case IPC_STAT: if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg))) return -EFAULT; if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*sma)))) return i; break; case IPC_SET: if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg))) return -EFAULT; if ((i = verify_area (VERIFY_READ, buf, sizeof tbuf))) return i; memcpy_fromfs (&tbuf, buf, sizeof tbuf); break; } if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID) return -EIDRM; if (ipcp->seq != semid / SEMMNI) return -EIDRM; switch (cmd) { case GETALL: if (ipcperms (ipcp, S_IRUGO)) return -EACCES; for (i=0; i< sma->sem_nsems; i++) sem_io[i] = sma->sem_base[i].semval; memcpy_tofs (array, sem_io, nsems*sizeof(ushort)); break; case SETVAL: if (ipcperms (ipcp, S_IWUGO)) return -EACCES; for (un = sma->undo; un; un = un->id_next) if (semnum == un->sem_num) un->semadj = 0; sma->sem_ctime = CURRENT_TIME; curr->semval = val; if (sma->eventn) wake_up (&sma->eventn); if (sma->eventz) wake_up (&sma->eventz); break; case IPC_SET: if (suser() || current->euid == ipcp->cuid || current->euid == ipcp->uid) { ipcp->uid = tbuf.sem_perm.uid; ipcp->gid = tbuf.sem_perm.gid; ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | (tbuf.sem_perm.mode & S_IRWXUGO); sma->sem_ctime = CURRENT_TIME; return 0; } return -EPERM; case IPC_STAT: if (ipcperms (ipcp, S_IRUGO)) return -EACCES; memcpy_tofs (buf, sma, sizeof (*sma)); break; case SETALL: if (ipcperms (ipcp, S_IWUGO)) return -EACCES; for (i=0; i<nsems; i++) sma->sem_base[i].semval = sem_io[i]; for (un = sma->undo; un; un = un->id_next) un->semadj = 0; if (sma->eventn) wake_up (&sma->eventn); if (sma->eventz) wake_up (&sma->eventz); sma->sem_ctime = CURRENT_TIME; break; default: return -EINVAL; } return 0; }
int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned int arg) { struct tty_struct * tty; struct tty_struct * other_tty; int pgrp; int dev; if (MAJOR(file->f_rdev) != 4) { printk("tty_ioctl: tty pseudo-major != 4\n"); return -EINVAL; } dev = MINOR(file->f_rdev); tty = TTY_TABLE(dev); if (!tty) return -EINVAL; if (IS_A_PTY(dev)) other_tty = tty_table[PTY_OTHER(dev)]; else other_tty = NULL; switch (cmd) { case TCGETS: return get_termios(tty,(struct termios *) arg); case TCSETSF: flush_input(tty); /* fallthrough */ case TCSETSW: wait_until_sent(tty); /* fallthrough */ case TCSETS: return set_termios(tty,(struct termios *) arg, dev); case TCGETA: return get_termio(tty,(struct termio *) arg); case TCSETAF: flush_input(tty); /* fallthrough */ case TCSETAW: wait_until_sent(tty); /* fallthrough */ case TCSETA: return set_termio(tty,(struct termio *) arg, dev); case TCXONC: switch (arg) { case TCOOFF: tty->stopped = 1; TTY_WRITE_FLUSH(tty); return 0; case TCOON: tty->stopped = 0; TTY_WRITE_FLUSH(tty); return 0; case TCIOFF: if (STOP_CHAR(tty)) put_tty_queue(STOP_CHAR(tty), &tty->write_q); return 0; case TCION: if (START_CHAR(tty)) put_tty_queue(START_CHAR(tty), &tty->write_q); return 0; } return -EINVAL; /* not implemented */ case TCFLSH: if (arg==0) flush_input(tty); else if (arg==1) flush_output(tty); else if (arg==2) { flush_input(tty); flush_output(tty); } else return -EINVAL; return 0; case TIOCEXCL: return -EINVAL; /* not implemented */ case TIOCNXCL: return -EINVAL; /* not implemented */ case TIOCSCTTY: return -EINVAL; /* set controlling term NI */ case TIOCGPGRP: verify_area((void *) arg,4); put_fs_long(tty->pgrp,(unsigned long *) arg); return 0; case TIOCSPGRP: if ((current->tty < 0) || (current->tty != dev) || (tty->session != current->session)) return -ENOTTY; pgrp=get_fs_long((unsigned long *) arg); if (pgrp < 0) return -EINVAL; if (session_of_pgrp(pgrp) != current->session) return -EPERM; tty->pgrp = pgrp; return 0; case TIOCOUTQ: verify_area((void *) arg,4); put_fs_long(CHARS(&tty->write_q), (unsigned long *) arg); return 0; case TIOCINQ: verify_area((void *) arg,4); if (L_CANON(tty) && !tty->secondary.data) put_fs_long(0, (unsigned long *) arg); else put_fs_long(CHARS(&tty->secondary), (unsigned long *) arg); return 0; case TIOCSTI: return -EINVAL; /* not implemented */ case TIOCGWINSZ: return get_window_size(tty,(struct winsize *) arg); case TIOCSWINSZ: if (IS_A_PTY_MASTER(dev)) set_window_size(other_tty,(struct winsize *) arg); return set_window_size(tty,(struct winsize *) arg); case TIOCGSOFTCAR: return -EINVAL; /* not implemented */ case TIOCSSOFTCAR: return -EINVAL; /* not implemented */ case TIOCLINUX: switch (get_fs_byte((char *)arg)) { case 0: return do_screendump(arg); case 1: return do_get_ps_info(arg); default: return -EINVAL; } case TIOCCONS: if (!IS_A_PTY(dev)) return -EINVAL; if (redirect) return -EBUSY; if (!suser()) return -EPERM; if (IS_A_PTY_MASTER(dev)) redirect = other_tty; else redirect = tty; return 0; case FIONBIO: if (arg) file->f_flags |= O_NONBLOCK; else file->f_flags &= ~O_NONBLOCK; return 0; case TIOCNOTTY: if (MINOR(file->f_rdev) != current->tty) return -EINVAL; current->tty = -1; if (current->leader) { if (tty->pgrp > 0) kill_pg(tty->pgrp, SIGHUP, 0); tty->pgrp = -1; tty->session = 0; } return 0; case TIOCPKT: { int on; if (!IS_A_PTY_MASTER(dev)) return (-EINVAL); verify_area ((unsigned long *)arg, sizeof (int)); on=get_fs_long ((unsigned long *)arg); if (on ) tty->packet = 1; else tty->packet = 0; return (0); } default: if (tty->ioctl) return (tty->ioctl)(tty, file, cmd, arg); else return -EINVAL; } }
int tty_ioctl(int dev, int cmd, int arg) { struct tty_struct * tty; struct tty_struct * other_tty; int pgrp; if (MAJOR(dev) == 5) { dev = current->tty; if (dev<0) return -EINVAL; } else dev=MINOR(dev); tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console); if (IS_A_PTY(dev)) other_tty = tty_table + PTY_OTHER(dev); else other_tty = NULL; if (!(tty->write_q && tty->read_q && tty->secondary && tty->write)) return -EINVAL; switch (cmd) { case TCGETS: return get_termios(tty,(struct termios *) arg); case TCSETSF: flush(tty->read_q); flush(tty->secondary); if (other_tty) flush(other_tty->write_q); /* fallthrough */ case TCSETSW: wait_until_sent(tty); /* fallthrough */ case TCSETS: return set_termios(tty,(struct termios *) arg, dev); case TCGETA: return get_termio(tty,(struct termio *) arg); case TCSETAF: flush(tty->read_q); flush(tty->secondary); if (other_tty) flush(other_tty->write_q); /* fallthrough */ case TCSETAW: wait_until_sent(tty); /* fallthrough */ case TCSETA: return set_termio(tty,(struct termio *) arg, dev); case TCSBRK: if (!arg) { wait_until_sent(tty); send_break(tty); } return 0; case TCXONC: switch (arg) { case TCOOFF: tty->stopped = 1; tty->write(tty); return 0; case TCOON: tty->stopped = 0; tty->write(tty); return 0; case TCIOFF: if (STOP_CHAR(tty)) PUTCH(STOP_CHAR(tty),tty->write_q); return 0; case TCION: if (START_CHAR(tty)) PUTCH(START_CHAR(tty),tty->write_q); return 0; } return -EINVAL; /* not implemented */ case TCFLSH: if (arg==0) { flush(tty->read_q); flush(tty->secondary); if (other_tty) flush(other_tty->write_q); } else if (arg==1) flush(tty->write_q); else if (arg==2) { flush(tty->read_q); flush(tty->secondary); flush(tty->write_q); if (other_tty) flush(other_tty->write_q); } else return -EINVAL; return 0; case TIOCEXCL: return -EINVAL; /* not implemented */ case TIOCNXCL: return -EINVAL; /* not implemented */ case TIOCSCTTY: return -EINVAL; /* set controlling term NI */ case TIOCGPGRP: verify_area((void *) arg,4); put_fs_long(tty->pgrp,(unsigned long *) arg); return 0; case TIOCSPGRP: if ((current->tty < 0) || (current->tty != dev) || (tty->session != current->session)) return -ENOTTY; pgrp=get_fs_long((unsigned long *) arg); if (pgrp < 0) return -EINVAL; if (session_of_pgrp(pgrp) != current->session) return -EPERM; tty->pgrp = pgrp; return 0; case TIOCOUTQ: verify_area((void *) arg,4); put_fs_long(CHARS(tty->write_q),(unsigned long *) arg); return 0; case TIOCINQ: verify_area((void *) arg,4); put_fs_long(CHARS(tty->secondary), (unsigned long *) arg); return 0; case TIOCSTI: return -EINVAL; /* not implemented */ case TIOCGWINSZ: return get_window_size(tty,(struct winsize *) arg); case TIOCSWINSZ: if (other_tty) set_window_size(other_tty,(struct winsize *) arg); return set_window_size(tty,(struct winsize *) arg); case TIOCMGET: return -EINVAL; /* not implemented */ case TIOCMBIS: return -EINVAL; /* not implemented */ case TIOCMBIC: return -EINVAL; /* not implemented */ case TIOCMSET: return -EINVAL; /* not implemented */ case TIOCGSOFTCAR: return -EINVAL; /* not implemented */ case TIOCSSOFTCAR: return -EINVAL; /* not implemented */ case TIOCLINUX: switch (get_fs_byte((char *)arg)) { case 0: return do_screendump(arg); case 1: return do_get_ps_info(arg); default: return -EINVAL; } default: return -EINVAL; } }