arg_t _ioctl(void) { inoptr ino; uint16_t dev; if ((ino = getinode(fd)) == NULLINODE) return -1; if (!(isdevice(ino))) { udata.u_error = ENOTTY; return -1; } if ((request & IOCTL_SUPER) && esuper()) return -1; if (!(getperm(ino) & OTH_WR)) { udata.u_error = EPERM; return -1; } dev = ino->c_node.i_addr[0]; /* top bit of request is reserved for kernel originated magic */ return d_ioctl(dev, request & 0x7FFF, data); }
int vt_ioctl(uint8_t minor, uarg_t request, char *data) { /* FIXME: need to address the multiple vt switching case here.. probably need to switch vt */ if (minor <= MAX_VT) { switch(request) { #ifdef KEY_ROWS case KBMAPSIZE: return KEY_ROWS << 8 | KEY_COLS; case KBMAPGET: return uput(keymap, data, sizeof(keymap)); case KBSETTRANS: if (esuper()) return -1; if (uget(keyboard, data, sizeof(keyboard)) == -1) return -1; return uget(shiftkeyboard, data + sizeof(keyboard), sizeof(shiftkeyboard)); #endif case VTSIZE: return VT_HEIGHT << 8 | VT_WIDTH; case VTATTRS: return vtattr_cap; } } return tty_ioctl(minor, request, data); }
arg_t _setrlimit(void) { staticfast struct rlimit r; struct rlimit *o; if (res < 0 || res >= NRLIMIT) goto bad; if (uget(rlim, &r, sizeof(struct rlimit))) return -1; o = udata.u_rlimit + res; if (r.rlim_cur > r.rlim_max) goto bad; /* Securit check */ if ((r.rlim_cur > o->rlim_max || r.rlim_max > o->rlim_max) && esuper()) return -1; o->rlim_cur = r.rlim_cur; o->rlim_max = r.rlim_max; return 0; bad: udata.u_error = EINVAL; return -1; }
arg_t _acct(void) { #ifdef CONFIG_ACCT inoptr inode; if (esuper()) return -1; if (acct_fh != -1) oft_deref(acct_fh); if (fd != -1) { if ((inode = getinode(fd)) == NULLINODE) return -1; if (getmode(inode) != F_REG) { udata.u_error = EINVAL; return -1; } if (inode->c_flags & CRDONLY) { udata.u_error = EROFS; return -1; } acct_fh = udata.u_files[fd]; ++of_tab[acct_fh].o_refs; } return 0; #else udata.u_error = EINVAL; return -1; #endif }
arg_t make_socket(struct sockinfo *s, struct socket **np) { struct socket *n; int8_t uindex; int8_t oftindex; inoptr ino; /* RAW sockets are superuser */ if (s->priv && esuper()) return -1; if (np) n = *np; else { n = alloc_socket(); if (n == NULL) return -1; } n->s_type = s - socktypes; /* Pointer or uint8_t best ? */ n->s_state = SS_INIT; if (net_init(n) == -1) goto nosock; /* Start by getting the file and inode table entries */ if ((uindex = uf_alloc()) == -1) goto nosock; if ((oftindex = oft_alloc()) == -1) goto nooft; /* We need an inode : FIXME - do we want a pipedev aka Unix ? */ if (!(ino = i_open(root_dev, 0))) goto noalloc; /* All good - now set it up */ /* The nlink cheat needs to be taught to fsck! */ ino->c_node.i_mode = F_SOCK | 0777; ino->c_node.i_nlink = n->s_num; /* Cheat !! */ ino->c_readers = 1; ino->c_writers = 1; of_tab[oftindex].o_inode = ino; of_tab[oftindex].o_access = O_RDWR; udata.u_files[uindex] = oftindex; sock_wait_leave(n, 0, SS_INIT); if (np) *np = n; return uindex; noalloc: oft_deref(oftindex); /* Will call i_deref! */ nooft: udata.u_files[uindex] = NO_FILE; nosock: n->s_state = SS_UNUSED; return -1; }
arg_t _chroot(void) { inoptr newroot; if (esuper()) return (-1); if (!(newroot = n_open(dir, NULLINOPTR))) return (-1); return chdiroot_op(newroot, &udata.u_root); }
arg_t _link(void) { inoptr ino; inoptr ino2; inoptr parent2; char fname[FILENAME_LEN + 1]; if (!(ino = n_open(name1, NULLINOPTR))) return (-1); if (getmode(ino) == F_DIR && esuper()) goto nogood; if (ino->c_node.i_nlink == 0xFFFF) { udata.u_error = EMLINK; goto nogood; } /* Make sure file2 doesn't exist, and get its parent */ if ((ino2 = n_open(name2, &parent2)) != NULL) { i_deref(ino2); i_deref(parent2); udata.u_error = EEXIST; goto nogood; } if (!parent2) goto nogood; if (ino->c_dev != parent2->c_dev) { i_deref(parent2); udata.u_error = EXDEV; goto nogood; } filename(name2, fname); if (!ch_link(parent2, "", fname, ino)) { i_deref(parent2); goto nogood; } /* Update the link count. */ ++ino->c_node.i_nlink; wr_inode(ino); setftime(ino, C_TIME); i_deref(parent2); i_deref(ino); return 0; nogood: i_deref(ino); return -1; }
static int chown_op(inoptr ino) { if (ino->c_node.i_uid != udata.u_euid && esuper()) { i_deref(ino); return (-1); } ino->c_node.i_uid = owner; ino->c_node.i_gid = group; setftime(ino, C_TIME); return 0; }
arg_t _stime(void) { time_t t; if (type != 0) { udata.u_error = EINVAL; return -1; } if (uget(&t, tvec, sizeof(t)) || esuper()) return -1; wrtime(&t); return (-1); }
static int16_t chmod_op(inoptr ino) { if (ino->c_node.i_uid != udata.u_euid && esuper()) { i_deref(ino); return (-1); } ino->c_node.i_mode = (mode & MODE_MASK) | (ino->c_node.i_mode & F_MASK); setftime(ino, C_TIME); return 0; }
arg_t _setgroups(void) { if (esuper()) return -1; if (ngroup < 0 || ngroup > NGROUP) { udata.u_error = EINVAL; return -1; } if (ngroup && uget(groups, udata.u_groups, ngroup * sizeof(uint16_t))) return -1; udata.u_ngroup = ngroup; return 0; }
static int chown_op(inoptr ino) { if (ino->c_node.i_uid != udata.u_euid && esuper()) return (-1); if (ino->c_flags & CRDONLY) { udata.u_error = EROFS; return -1; } ino->c_node.i_uid = owner; ino->c_node.i_gid = group; setftime(ino, C_TIME); return 0; }
arg_t make_socket(struct sockinfo *s, int8_t *np) { int8_t n; int8_t uindex; int8_t oftindex; inoptr ino; /* RAW sockets are superuser */ if (s->priv && esuper()) return -1; /* Start by getting the file and inode table entries */ if ((uindex = uf_alloc()) == -1) return -1; if ((oftindex = oft_alloc()) == -1) goto nooft; if (np) n = *np; else { n = alloc_socket(); if (n == -1) goto noalloc; } /* We need an inode : FIXME - do we want a pipedev aka Unix ? */ if (!(ino = i_open(root_dev, 0))) goto noalloc; /* All good - now set it up */ /* The nlink cheat needs to be taught to fsck! */ ino->c_node.i_mode = F_SOCK | 0777; ino->c_node.i_nlink = n; /* Cheat !! */ of_tab[oftindex].o_inode = ino; of_tab[oftindex].o_access = O_RDWR; udata.u_files[uindex] = oftindex; sockets[n].s_inode = ino; sockets[n].s_type = s - socktypes; /* Pointer or uint8_t best ? */ sockets[n].s_state = SS_UNCONNECTED; if (np) *np = n; return uindex; noalloc: oft_deref(oftindex); /* Will call i_deref! */ nooft: udata.u_files[uindex] = NO_FILE; return -1; }
static arg_t chmod_op(inoptr ino) { if (ino->c_node.i_uid != udata.u_euid && esuper()) return (-1); if (ino->c_flags & CRDONLY) { udata.u_error = EROFS; return -1; } ino->c_node.i_mode = (mode & MODE_MASK) | (ino->c_node.i_mode & F_MASK); setftime(ino, C_TIME); return 0; }
int16_t _utime(void) { inoptr ino; time_t t[2]; if (!valaddr(buf, 2 * sizeof(time_t))) return (-1); if (!(ino = n_open(file, NULLINOPTR))) return (-1); if (ino->c_node.i_uid != udata.u_euid && esuper()) { i_deref(ino); return (-1); } uget(buf, t, 2 * sizeof(time_t)); /* FIXME: needs updating once we pack top bits elsewhere in the inode */ ino->c_node.i_atime = t[0]; ino->c_node.i_mtime = t[1]; setftime(ino, C_TIME); i_deref(ino); return (0); }
arg_t _utime(void) { inoptr ino; time_t t[2]; if (!(ino = n_open(file, NULLINOPTR))) return (-1); if (ino->c_flags & CRDONLY) { udata.u_error = EROFS; goto out2; } /* Special case in the Unix API - NULL means now */ if (buf) { if (ino->c_node.i_uid != udata.u_euid && esuper()) goto out; if (!valaddr(buf, 2 * sizeof(time_t))) goto out2; uget(buf, t, 2 * sizeof(time_t)); } else { if (!(getperm(ino) & OTH_WR)) goto out; rdtime(&t[0]); memcpy(&t[1], &t[0], sizeof(t[1])); } /* FIXME: needs updating once we pack top bits elsewhere in the inode */ ino->c_node.i_atime = t[0].low; ino->c_node.i_mtime = t[1].low; setftime(ino, C_TIME); i_deref(ino); return (0); out: udata.u_error = EPERM; out2: i_deref(ino); return -1; }