static int set_window_size(struct tty_struct * tty, struct winsize * ws) { int i,changed; char c, * tmp; if (!ws) return -EINVAL; tmp = (char *) &tty->winsize; changed = 0; for (i = 0; i < sizeof (*ws) ; i++,tmp++) { c = get_fs_byte(i + (char *) ws); if (c == *tmp) continue; changed = 1; *tmp = c; } if (changed) kill_pg(tty->pgrp, SIGWINCH, 1); return 0; }
/* * This only works as the 386 is low-byte-first */ static int set_termio(struct tty_struct * tty, struct termio * termio, int channel) { int i; struct termio tmp_termio; struct termios old_termios = *tty->termios; i = check_change(tty, channel); if (i) return i; for (i=0 ; i< (sizeof (*termio)) ; i++) ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio); /* take care of the packet stuff. */ if ((tmp_termio.c_iflag & IXON) && ~(tty->termios->c_iflag & IXON)) { tty->status_changed = 1; tty->ctrl_status |= TIOCPKT_DOSTOP; } if (~(tmp_termio.c_iflag & IXON) && (tty->termios->c_iflag & IXON)) { tty->status_changed = 1; tty->ctrl_status |= TIOCPKT_NOSTOP; } *(unsigned short *)&tty->termios->c_iflag = tmp_termio.c_iflag; *(unsigned short *)&tty->termios->c_oflag = tmp_termio.c_oflag; *(unsigned short *)&tty->termios->c_cflag = tmp_termio.c_cflag; *(unsigned short *)&tty->termios->c_lflag = tmp_termio.c_lflag; tty->termios->c_line = tmp_termio.c_line; for(i=0 ; i < NCC ; i++) tty->termios->c_cc[i] = tmp_termio.c_cc[i]; if (tty->set_termios) (*tty->set_termios)(tty, &old_termios); return 0; }
/** * for console, channel = 0. 指定的是使用哪个tty_table来输出,0指定的是控制台 nr=0 number of bytes ,指定buf有多少个字节。 */ int tty_write(unsigned channel, char * buf, int nr) { static int cr_flag=0; struct tty_struct * tty; char c, *b=buf; if (channel>2 || nr<0) return -1; tty = channel + tty_table; /*使用控制台输出*/ /**/ while (nr>0) { sleep_if_full(&tty->write_q); /*if (current->signal) break; */ while (nr>0 && !FULL(tty->write_q)) { c=get_fs_byte(b); if (O_POST(tty)) { if (c=='\r' && O_CRNL(tty)) c='\n'; else if (c=='\n' && O_NLRET(tty)) c='\r'; if (c=='\n' && !cr_flag && O_NLCR(tty)) { cr_flag = 1; PUTCH(13,tty->write_q); continue; } if (O_LCUC(tty)) c=toupper(c); } b++; nr--; cr_flag = 0; PUTCH(c,tty->write_q); } tty->write(tty); if (nr>0) /*schedule()*/; } return (b-buf); }
static int set_termios(struct tty_struct * tty, struct termios * termios, int channel) { int i; struct termios old_termios = *tty->termios; i = check_change(tty, channel); if (i) return i; for (i=0 ; i< (sizeof (*termios)) ; i++) ((char *)tty->termios)[i]=get_fs_byte(i+(char *)termios); /* puting mpty's into echo mode is very bad, and I think under some situations can cause the kernel to do nothing but copy characters back and forth. -RAB */ if (IS_A_PTY_MASTER(channel)) tty->termios->c_lflag &= ~ECHO; if (tty->set_termios) (*tty->set_termios)(tty, &old_termios); return 0; }
/* 块设备写 块设备写,写入高速缓存中(buffer_head指向的告诉缓存) 值得注意的是,写入高速缓存块时,只有第一次写入其偏移才可能不是0,后续的都是0 */ int block_write(int dev, long * pos, char * buf, int count) { int block = *pos >> BLOCK_SIZE_BITS; int offset = *pos & (BLOCK_SIZE-1); int chars; int written = 0; int size; struct buffer_head * bh; register char * p; if (blk_size[MAJOR(dev)]) size = blk_size[MAJOR(dev)][MINOR(dev)]; else size = 0x7fffffff; while (count>0) { if (block >= size) return written?written:-EIO; chars = BLOCK_SIZE - offset; if (chars > count) chars=count; if (chars == BLOCK_SIZE) bh = getblk(dev,block); else bh = breada(dev,block,block+1,block+2,-1); block++; if (!bh) return written?written:-EIO; p = offset + bh->b_data; offset = 0; *pos += chars; written += chars; count -= chars; while (chars-->0) *(p++) = get_fs_byte(buf++); bh->b_dirt = 1; brelse(bh); } return written; }
/* * This only works as the 386 is low-byt-first */ static int set_termio(struct tty_struct * tty, struct termio * termio, int channel) { int i, retsig; struct termio tmp_termio; if ((current->tty == channel) && (tty->pgrp != current->pgrp)) { retsig = tty_signal(SIGTTOU, tty); if (retsig == -ERESTARTSYS || retsig == -EINTR) return retsig; } for (i=0 ; i< (sizeof (*termio)) ; i++) ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio); *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag; *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag; *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag; *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag; tty->termios.c_line = tmp_termio.c_line; for(i=0 ; i < NCC ; i++) tty->termios.c_cc[i] = tmp_termio.c_cc[i]; change_speed(tty); return 0; }
int sys_iam(const char* name) { int len = 0; int tmp[30]; int i = 0; for ( len = 0; len < 30; len++) { tmp[len] = get_fs_byte(name+len); if (tmp[len] == '\0' || tmp[len] == '\n') { break; } } if (len >= 24) { return -EINVAL; } for(i=0;i <= len;i++) { msg[i] = tmp[i]; } return len; }
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 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 }
unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, int ibcs) { unsigned long *argv,*envp, *dlinfo; unsigned long * sp; struct vm_area_struct *mpnt; mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL); if (mpnt) { mpnt->vm_task = current; mpnt->vm_start = PAGE_MASK & (unsigned long) p; mpnt->vm_end = TASK_SIZE; mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY; mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_share = NULL; mpnt->vm_ops = NULL; mpnt->vm_inode = NULL; mpnt->vm_offset = 0; mpnt->vm_pte = 0; insert_vm_struct(current, mpnt); } sp = (unsigned long *) (0xfffffffc & (unsigned long) p); if(exec) sp -= DLINFO_ITEMS*2; dlinfo = sp; sp -= envc+1; envp = sp; sp -= argc+1; argv = sp; if (!ibcs) { put_fs_long((unsigned long)envp,--sp); put_fs_long((unsigned long)argv,--sp); } /* The constant numbers (0-9) that we are writing here are described in the header file sys/auxv.h on at least some versions of SVr4 */ if(exec) { /* Put this here for an ELF program interpreter */ struct elf_phdr * eppnt; eppnt = (struct elf_phdr *) exec->e_phoff; put_fs_long(3,dlinfo++); put_fs_long(load_addr + exec->e_phoff,dlinfo++); put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++); put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++); put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++); put_fs_long(7,dlinfo++); put_fs_long(SHM_RANGE_START,dlinfo++); put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++); put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++); put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++); }; put_fs_long((unsigned long)argc,--sp); current->mm->arg_start = (unsigned long) p; while (argc-->0) { put_fs_long((unsigned long) p,argv++); while (get_fs_byte(p++)) /* nothing */ ; } put_fs_long(0,argv); current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { put_fs_long((unsigned long) p,envp++); while (get_fs_byte(p++)) /* nothing */ ; } put_fs_long(0,envp); current->mm->env_end = (unsigned long) p; return sp; }
static int math_emulate(struct trapframe * info) { unsigned short code; temp_real tmp; char * address; u_int32_t 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, (u_long)oldeip); panic("?Math emulation needed in kernel?"); } /* completely ignore an operand-size prefix */ if (get_fs_byte((char *) info->tf_eip) == 0x66) info->tf_eip++; code = get_fs_word((unsigned short *) info->tf_eip); 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++) { ((int32_t *) & I387)[code] = get_fs_long((u_int32_t *) 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( ((int32_t *) & I387)[code], (u_int32_t *) 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++) { ((int32_t *) & I387)[code] = get_fs_long((u_int32_t *) address); address += 4; } return(0); case 0xa6: address = ea(info,code); /*verify_area(address,108);*/ for (code = 0 ; code < 27 ; code++) { put_fs_long( ((int32_t *) & I387)[code], (u_int32_t *) 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); }
int proc_dodebug(ctl_table *table, int write, struct file *file, void *buffer, size_t *lenp) { char tmpbuf[20], *p, c; unsigned int value; int left, len; if ((file->f_pos && !write) || !*lenp) { *lenp = 0; return 0; } left = *lenp; if (write) { if (!access_ok(VERIFY_READ, buffer, left)) return -EFAULT; p = (char *) buffer; #if LINUX_VERSION_CODE >= 0x020100 while (left && __get_user(c, p) >= 0 && isspace(c)) left--, p++; #else while (left && (c = get_fs_byte(p)) >= 0 && isspace(c)) left--, p++; #endif if (!left) goto done; if (left > sizeof(tmpbuf) - 1) return -EINVAL; copy_from_user(tmpbuf, p, left); tmpbuf[left] = '\0'; for (p = tmpbuf, value = 0; '0' <= *p && *p <= '9'; p++, left--) value = 10 * value + (*p - '0'); if (*p && !isspace(*p)) return -EINVAL; while (left && isspace(*p)) left--, p++; *(unsigned int *) table->data = value; /* Display the RPC tasks on writing to rpc_debug */ if (table->ctl_name == CTL_RPCDEBUG) { rpc_show_tasks(); } } else { if (!access_ok(VERIFY_WRITE, buffer, left)) return -EFAULT; len = sprintf(tmpbuf, "%d", *(unsigned int *) table->data); if (len > left) len = left; copy_to_user(buffer, tmpbuf, len); if ((left -= len) > 0) { put_user('\n', (char *)buffer + len); left--; } } done: *lenp -= left; file->f_pos += *lenp; return 0; }
/* Write to a file either from user space */ int msdos_file_write( struct inode *inode, struct file *filp, const char *buf, int count) { struct super_block *sb = inode->i_sb; int sector,offset,size,left,written; int error,carry; char *start,*to,ch; struct buffer_head *bh; int binary_mode = MSDOS_I(inode)->i_binary; if (!inode) { printk("msdos_file_write: inode = NULL\n"); return -EINVAL; } /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */ if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) { printk("msdos_file_write: mode = %07o\n",inode->i_mode); return -EINVAL; } /* * ok, append may not work when many processes are writing at the same time * but so what. That way leads to madness anyway. */ if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size; if (count <= 0) return 0; error = carry = 0; for (start = (char *)buf; count || carry; count -= size) { while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS))) if ((error = msdos_add_cluster(inode)) < 0) break; if (error) { msdos_truncate(inode); break; } offset = filp->f_pos & (SECTOR_SIZE-1); size = MIN(SECTOR_SIZE-offset,MAX(carry,count)); if (binary_mode && offset == 0 && (size == SECTOR_SIZE || filp->f_pos + size >= inode->i_size)){ /* No need to read the block first since we will */ /* completely overwrite it */ /* or at least write past the end of file */ if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){ error = -EIO; break; } }else if (!(bh = bread(inode->i_dev,sector,SECTOR_SIZE))) { error = -EIO; break; } if (binary_mode) { memcpy_fromfs(bh->b_data+offset,buf,written = size); buf += size; } else { written = left = SECTOR_SIZE-offset; to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1)); if (carry) { *to++ = '\n'; left--; carry = 0; } for (size = 0; size < count && left; size++) { if ((ch = get_fs_byte(buf++)) == '\n') { *to++ = '\r'; left--; } if (!left) carry = 1; else { *to++ = ch; left--; } } written -= left; } filp->f_pos += written; if (filp->f_pos > inode->i_size) { inode->i_size = filp->f_pos; inode->i_dirt = 1; } msdos_set_uptodate(sb,bh,1); mark_buffer_dirty(bh, 0); brelse(bh); } if (start == buf) return error; inode->i_mtime = inode->i_ctime = FS_CURRENT_TIME; MSDOS_I(inode)->i_attrs |= ATTR_ARCH; inode->i_dirt = 1; return buf-start; }
//// 文件写函数 - 根据i节点和文件结构信息,将用户数据写入文件中。 // 由i节点我们可以知道设备号,而由file结构可以知道文件中当前读写指针位置。buf指定 // 用户态缓冲区的位置,count为需要写入的字节数。返回值是实际写入的字节数,或出错号。 int file_write(struct m_inode * inode, struct file * filp, char * buf, int count) { off_t pos; int block,c; struct buffer_head * bh; char * p; int i=0; /* * ok, append may not work when many processes are writing at the same time * but so what. That way leads to madness anyway. */ // 首先确定数据写入文件的位置。如果是要向文件后添加数据,则将文件读写指针移到 // 文件尾部。否则就将在文件当前读写指针处写入。 if (filp->f_flags & O_APPEND) pos = inode->i_size; else pos = filp->f_pos; // 然后在已写入字节数i(刚开始为0)小于指定写入字节数count时,循环执行以下操作。 // 在循环操作过程中,我们先取文件数据块号(pos/BLOCK_SIZE)在设备上对应的逻辑 // 块号block。如果对应的逻辑块不存在就创建一块。如果得到的逻辑块号=0,则表示 // 创建失败,于是退出循环。否则我们根据该逻辑块号读取设备上的相应逻辑块,若出 // 错也退出循环。 while (i<count) { if (!(block = create_block(inode,pos/BLOCK_SIZE))) break; if (!(bh=bread(inode->i_dev,block))) break; // 此时缓冲块指针bh正指向刚读入的文件数据库。现在再求出文件当前读写指针在该 // 数据块中的偏移值c,并将指针p指向缓冲块中开始写入数据的位置,并置该缓冲块已 // 修改标志。对于块中当前指针,从开始读写位置到块末共可写入c=(BLOCK_SIZE - c) // 个字节。若c大于剩余还需写入的字节数(count - i),则此次只需再写入c = (count - i) // 个字节即可。 c = pos % BLOCK_SIZE; p = c + bh->b_data; bh->b_dirt = 1; c = BLOCK_SIZE-c; if (c > count-i) c = count-i; // 在写入数据之前,我们先预先设置好下一次循环操作要读写文件中的位置。因此我们 // 把pos指针前移此次需写入的字节数。如果此时pos位置值超过了文件当前长度,则 // 修改i节点中文件长度字段,并置i节点已修改标志。然后把此次要写入的字节数c累加到 // 已写入字节计数值i中,供循环判断使用。接着从用户缓冲区buf中复制c个字节到告诉缓 // 冲块中p指向的开始位置处。复制完后就释放该缓冲块。 pos += c; if (pos > inode->i_size) { inode->i_size = pos; inode->i_dirt = 1; } i += c; while (c-->0) *(p++) = get_fs_byte(buf++); brelse(bh); } // 当数据已全部写入文件或者在写操作工程中发生问题时就会退出循环。此时我们更改文件修改 // 时间为当前时间,并调整文件读写指针。如果此次操作不是在文件尾部添加数据,则把文件 // 读写指针调整到当前读写位置pos处,并更改文件i节点的修改时间为当前时间。最后返回写入 // 的字节数,若写入字节数为0,则返回出错号-1. inode->i_mtime = CURRENT_TIME; if (!(filp->f_flags & O_APPEND)) { filp->f_pos = pos; inode->i_ctime = CURRENT_TIME; } return (i?i:-1); }
static int load_svr3_binary (struct linux_binprm *bprm, struct pt_regs *regs) { struct file *file; int error, retval, i, j, shlibs; int fd[1+SHLIB_MAX]; long entry; unsigned long rlim; unsigned long p = bprm->p; struct filehdr *fh; struct aouthdr *ah; struct scnhdr *sh; char *buf, *libs_buf; /* Main binary + SHLIB_MAX */ struct bin_info bin_info[SHLIB_MAX + 1]; /* Cheking accessable headers by bprm->buf (128 bytes). */ fh = (struct filehdr *) bprm->buf; if (fh->f_magic != MC68MAGIC || fh->f_opthdr < AOUTSZ || fh->f_nscns < 3 || !(fh->f_flags & F_AR32W) || !(fh->f_flags & F_EXEC) ) return -ENOEXEC; ah = (struct aouthdr *) ((char *) bprm->buf + FILHSZ); if (ah->magic == SHMAGIC) return -ELIBEXEC; if ((ah->magic != DMAGIC && ah->magic != ZMAGIC) || !ah->tsize || ah->tsize + ah->dsize + FILHSZ + fh->f_opthdr + SCNHSZ * fh->f_nscns > bprm->inode->i_size || ah->text_start + ah->tsize > ah->data_start ) return -ENOEXEC; if (fh->f_nscns > 24) { printk ("Too many sections in svr3 binary file\n"); return -ENOEXEC; } /* Touch main binary file (which has # 0). */ fd[0] = open_inode (bprm->inode, O_RDONLY); if (fd[0] < 0) return fd[0]; buf = (char *) kmalloc (2*1024, GFP_KERNEL); if (!buf) { sys_close (fd[0]); return -ENOMEM; } libs_buf = buf + 1024; retval = touch_svr3_binary (fd[0], buf, &bin_info[0], 0); if (retval < 0) { sys_close(fd[0]); kfree (buf); return retval; } /* Looking for STYP_LIB section for shared libraries. */ sh = (struct scnhdr *) (buf + FILHSZ + fh->f_opthdr); for (i = 0; i < fh->f_nscns; i++) if (sh[i].s_flags == STYP_LIB) break; if (i == fh->f_nscns) shlibs = 0; else shlibs = sh[i].s_nlib; /* Touch target shared library binary files (## 1--SHLIB_MAX). */ if (shlibs) { void *p; int slib_size = sh[i].s_size; if (shlibs > SHLIB_MAX) { retval = -ELIBMAX; goto error_close; } file = bin_info[0].file; retval = sys_lseek (fd[0], sh[i].s_scnptr, 0); if (retval < 0) goto error_close; if (retval != sh[i].s_scnptr) { retval = -EACCES; goto error_close; } set_fs (KERNEL_DS); retval = file->f_op->read (file->f_inode, file, libs_buf, 1024); set_fs (USER_DS); if (retval < 0) goto error_close; if (retval < slib_size) { retval = -ELIBSCN; goto error_close; } for (p = libs_buf, j = 1; j <= shlibs; j++) { int len; char *name; struct slib *slibh = (struct slib *) p; p += slibh->sl_pathndx * 4; len = (slibh->sl_entsz - slibh->sl_pathndx) * 4; if (len <= 0 || p + len > (void *) libs_buf + slib_size) { retval = -ELIBSCN; goto error_close; } /* Target shared library path name. Must be followed by one or more zeroes. */ name = (char *) p; /* Try to access this library. */ set_fs (KERNEL_DS); fd[j] = sys_open (name, 0, 0); set_fs (USER_DS); if (fd[j] < 0) { retval = fd[j]; goto error_close; } retval = touch_svr3_binary (fd[j],buf,&bin_info[j],SHMAGIC); if (retval < 0) { /* Renumbering for shared library context. */ if (retval == -ENOEXEC) retval = -ELIBBAD; else if (retval == -EACCES) retval = -ELIBACC; goto error_close; } p += len; } } /* if (shlibs) .... */ /* Check initial limits. This avoids letting people circumvent * size limits imposed on them by creating programs with large * arrays in the data or bss. */ rlim = current->rlim[RLIMIT_DATA].rlim_cur; if (rlim >= RLIM_INFINITY) rlim = ~0; if (ah->dsize + ah->bsize > rlim) { /* XXX: but in shlibs too */ retval = -ENOMEM; goto error_close; } kfree (buf); /* OK, this is the point of noreturn. */ entry = ah->entry & ~0x1; /* Avoids possibly hult after `rte' ??? */ flush_old_exec (bprm); current->personality = PER_SVR3; current->mm->end_code = bin_info[0].text_len + (current->mm->start_code = bin_info[0].text_addr); current->mm->end_data = bin_info[0].data_len + (current->mm->start_data = bin_info[0].data_addr); current->mm->brk = bin_info[0].bss_len + (current->mm->start_brk = current->mm->end_data); current->mm->rss = 0; current->mm->mmap = NULL; current->suid = current->euid = current->fsuid = bprm->e_uid; current->sgid = current->egid = current->fsgid = bprm->e_gid; current->flags &= ~PF_FORKNOEXEC; /* mmap all binaries */ for (i = 0; i < 1 + shlibs; i++) { struct bin_info *binf = &bin_info[i]; unsigned int blocksize = binf->file->f_inode->i_sb->s_blocksize; unsigned int start_bss, end_bss; if (binf->text_addr & (PAGE_SIZE - 1) || binf->data_addr & (PAGE_SIZE - 1) || binf->text_offs & (blocksize - 1) || binf->data_offs & (blocksize - 1) || !binf->file->f_op->mmap ) { /* cannot mmap immediatly */ do_mmap (NULL, PAGE_ROUND(binf->text_addr), binf->text_len + (binf->text_addr - PAGE_ROUND(binf->text_addr)), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); read_exec (binf->file->f_inode, binf->text_offs, (char *) binf->text_addr, binf->text_len, 0); do_mmap (NULL, PAGE_ROUND(binf->data_addr), binf->data_len + (binf->data_addr - PAGE_ROUND(binf->data_addr)), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); read_exec (binf->file->f_inode, binf->data_offs, (char *) binf->data_addr, binf->data_len, 0); /* there's no nice way of flushing a number of user pages to ram 8*( */ flush_cache_all(); } else { error = do_mmap (binf->file, binf->text_addr, binf->text_len, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, binf->text_offs); if (error != binf->text_addr) goto error_kill_close; error = do_mmap (binf->file, binf->data_addr, binf->data_len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, binf->data_offs); if (error != binf->data_addr) goto error_kill_close; #ifdef DMAGIC_NODEMAND /* DMAGIC is for pure executable (not demand loading). But let the shared libraries be demand load ??? */ if (i == 0 && ah->magic == DMAGIC) { volatile char c; unsigned long addr; /* Touch all pages in .text and .data segments. */ for (addr = binf->text_addr; addr < binf->text_addr + binf->text_len; addr += PAGE_SIZE ) c = get_fs_byte ((char *) addr); for (addr = binf->data_addr; addr < binf->data_addr + binf->data_len; addr += PAGE_SIZE ) c = get_fs_byte ((char *) addr); } #endif } sys_close (fd[i]); start_bss = PAGE_ALIGN(binf->data_addr + binf->data_len); end_bss = PAGE_ALIGN(binf->data_addr + binf->data_len + binf->bss_len); /* svr3 binaries very hope that .bss section had been initialized by zeroes. Oh... */ if (binf->bss_len != 0) { /* Because there may be skipped heap by alignment. */ int addr = binf->data_addr + binf->data_len; int i = start_bss - addr; /* start_bss is aligned, addr may be no */ while (i & 0x3) { put_fs_byte (0, (char *) addr); addr++; i--; } i >>= 2; while (i--) { put_fs_long (0, (long *) addr); addr += sizeof (long); } } if (end_bss >= start_bss) do_mmap (NULL, start_bss, end_bss - start_bss, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); #ifdef DMAGIC_NODEMAND /* The same reason as above. */ if (i == 0 && ah->magic == DMAGIC) { volatile char c; unsigned long addr; for (addr = start_bss; addr < end_bss; addr += PAGE_SIZE) c = get_fs_byte ((char *) addr); } #endif /* OK, now all is mmapped for binary # i */ } /* for (i = ... ) */
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; } }
static int elksfs_add_entry(register struct inode *dir, char *name, size_t namelen, struct buffer_head **res_buf, struct elksfs_dir_entry **res_dir) { struct buffer_head *bh; struct elksfs_dir_entry *de; struct elksfs_sb_info *info; unsigned long int i; block_t block; loff_t offset; *res_buf = NULL; *res_dir = NULL; if (!dir || !dir->i_sb) return -ENOENT; info = &dir->i_sb->u.elksfs_sb; if (namelen > info->s_namelen) { #ifdef NO_TRUNCATE return -ENAMETOOLONG; #else namelen = info->s_namelen; #endif } if (!namelen) return -ENOENT; bh = NULL; block = 0; offset = 0; while (1) { if (!bh) { bh = elksfs_bread(dir, block, 1); if (!bh) return -ENOSPC; } map_buffer(bh); de = (struct elksfs_dir_entry *) (bh->b_data + offset); offset += info->s_dirsize; if (block * 1024 + offset > dir->i_size) { de->inode = 0; dir->i_size = block * 1024 + offset; dir->i_dirt = 1; } if (de->inode) { if (namecompare(namelen, (size_t) info->s_namelen, name, de->name)) { debug2("ELKSFSadd_entry: file %t==%s (already exists)\n", name, de->name); unmap_brelse(bh); return -EEXIST; } } else { dir->i_mtime = dir->i_ctime = CURRENT_TIME; dir->i_dirt = 1; for (i = 0; i < info->s_namelen; i++) de->name[i] = (i < namelen) ? (char) get_fs_byte((unsigned char *) name + i) : 0; #ifdef BLOAT_FS dir->i_version = ++event; #endif unmap_buffer(bh); mark_buffer_dirty(bh, 1); *res_dir = de; break; } if (offset < 1024) continue; printk("elksfs_add_entry may need another unmap_buffer :)\n"); brelse(bh); bh = NULL; offset = 0; block++; } *res_buf = bh; return 0; }
static int minix_add_entry(register struct inode *dir, char *name, size_t namelen, struct buffer_head **res_buf, struct minix_dir_entry **res_dir) { unsigned short block; loff_t offset; register struct buffer_head *bh; struct minix_dir_entry *de; struct minix_sb_info *info; *res_buf = NULL; *res_dir = NULL; if (!dir || !dir->i_sb) return -ENOENT; info = &dir->i_sb->u.minix_sb; if (namelen > info->s_namelen) { #ifdef NO_TRUNCATE return -ENAMETOOLONG; #else namelen = info->s_namelen; #endif } if (!namelen) return -ENOENT; bh = NULL; block = 0; offset = 0L; while (1) { if (!bh) { bh = minix_bread(dir, block, 1); if (!bh) return -ENOSPC; map_buffer(bh); } de = (struct minix_dir_entry *) (bh->b_data + offset); offset += info->s_dirsize; if (block * 1024L + offset > dir->i_size) { de->inode = 0; dir->i_size = block * 1024L + offset; dir->i_dirt = 1; } if (de->inode) { if (namecompare(namelen, info->s_namelen, name, de->name)) { debug2("MINIXadd_entry: file %t==%s (already exists)\n", name, de->name); unmap_brelse(bh); return -EEXIST; } } else { size_t i; dir->i_mtime = dir->i_ctime = CURRENT_TIME; dir->i_dirt = 1; for (i = 0; i < info->s_namelen; i++) de->name[i] = (i < namelen) ? (char) get_fs_byte(name + i) : '\0'; #ifdef BLOAT_FS dir->i_version = ++event; #endif unmap_buffer(bh); mark_buffer_dirty(bh, 1); *res_dir = de; break; } if (offset < 1024) continue; unmap_brelse(bh); bh = NULL; offset = 0; block++; } *res_buf = bh; 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; } }
static int msdos_format_name(char conv,const char *name,int len,char *res) { char *walk,**reserved; char c; int space; if (get_fs_byte(name) == DELETED_FLAG) return -EINVAL; if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 && get_fs_byte(name+1) == '.'))) { memset(res+1,' ',10); while (len--) *res++ = '.'; return 0; } space = 0; /* to make GCC happy */ c = 0; for (walk = res; len && walk-res < 8; walk++) { c = get_fs_byte(name++); len--; if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL; if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL; if (c >= 'A' && c <= 'Z') { if (conv == 's') return -EINVAL; c += 32; } if (c < ' ' || c == ':' || c == '\\') return -EINVAL; if (c == '.') break; space = c == ' '; *walk = c >= 'a' && c <= 'z' ? c-32 : c; } if (space) return -EINVAL; if (conv == 's' && len && c != '.') { c = get_fs_byte(name++); len--; if (c != '.') return -EINVAL; } while (c != '.' && len--) c = get_fs_byte(name++); if (walk == res) return -EINVAL; if (c == '.') { while (walk-res < 8) *walk++ = ' '; while (len > 0 && walk-res < MSDOS_NAME) { c = get_fs_byte(name++); len--; if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL; if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL; if (c < ' ' || c == ':' || c == '\\' || c == '.') return -EINVAL; if (c >= 'A' && c <= 'Z') { if (conv == 's') return -EINVAL; c += 32; } space = c == ' '; *walk++ = c >= 'a' && c <= 'z' ? c-32 : c; } if (space) return -EINVAL; if (conv == 's' && len) return -EINVAL; } while (walk-res < MSDOS_NAME) *walk++ = ' '; for (reserved = reserved_names; *reserved; reserved++) if (!strncmp(res,*reserved,8)) return -EINVAL; return 0; }