fileops.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. #include <bits/ioctl.h>
  2. #include <errno.h>
  3. #include <poll.h>
  4. #include <sys/mman.h>
  5. #include <unistd.h>
  6. #include <types/path.hpp>
  7. #include <kernel/log.hpp>
  8. #include <kernel/mem/vm_area.hpp>
  9. #include <kernel/process.hpp>
  10. #include <kernel/syscall.hpp>
  11. #include <kernel/vfs.hpp>
  12. #define NOT_IMPLEMENTED not_implemented(__FILE__, __LINE__)
  13. static inline void not_implemented(const char* pos, int line) {
  14. kmsgf(
  15. "[kernel] the function at %s:%d is not implemented, killing the "
  16. "pid%d...",
  17. pos, line, current_process->pid);
  18. current_thread->send_signal(SIGSYS);
  19. }
  20. ssize_t kernel::syscall::do_write(int fd, const char __user* buf, size_t n) {
  21. auto* file = current_process->files[fd];
  22. if (!file)
  23. return -EBADF;
  24. return file->write(buf, n);
  25. }
  26. ssize_t kernel::syscall::do_read(int fd, char __user* buf, size_t n) {
  27. auto* file = current_process->files[fd];
  28. if (!file)
  29. return -EBADF;
  30. return file->read(buf, n);
  31. }
  32. int kernel::syscall::do_close(int fd) {
  33. current_process->files.close(fd);
  34. return 0;
  35. }
  36. int kernel::syscall::do_dup(int old_fd) {
  37. return current_process->files.dup(old_fd);
  38. }
  39. int kernel::syscall::do_dup2(int old_fd, int new_fd) {
  40. return current_process->files.dup(old_fd, new_fd, 0);
  41. }
  42. int kernel::syscall::do_pipe(int __user* pipefd) {
  43. // TODO: use copy_from_user and copy_to_user
  44. return current_process->files.pipe(*(int(*)[2])pipefd);
  45. }
  46. ssize_t kernel::syscall::do_getdents(int fd, char __user* buf, size_t cnt) {
  47. auto* dir = current_process->files[fd];
  48. if (!dir)
  49. return -EBADF;
  50. return dir->getdents(buf, cnt);
  51. }
  52. ssize_t kernel::syscall::do_getdents64(int fd, char __user* buf, size_t cnt) {
  53. auto* dir = current_process->files[fd];
  54. if (!dir)
  55. return -EBADF;
  56. return dir->getdents64(buf, cnt);
  57. }
  58. int kernel::syscall::do_open(const char __user* path, int flags, mode_t mode) {
  59. mode &= ~current_process->umask;
  60. // TODO: use copy_from_user
  61. return current_process->files.open(current_process->cwd.get(), path, flags,
  62. mode);
  63. }
  64. int kernel::syscall::do_symlink(const char __user* target,
  65. const char __user* linkpath) {
  66. // TODO: use copy_from_user
  67. auto [dent, status] = current_open(linkpath);
  68. if (!dent || status != -ENOENT)
  69. return status;
  70. return fs::symlink(dent.get(), target);
  71. }
  72. int kernel::syscall::do_readlink(const char __user* pathname, char __user* buf,
  73. size_t buf_size) {
  74. // TODO: use copy_from_user
  75. auto [dent, status] = current_open(pathname, false);
  76. if (!dent || status)
  77. return status;
  78. if (buf_size <= 0 || !S_ISLNK(dent->inode->mode))
  79. return -EINVAL;
  80. // TODO: use copy_to_user
  81. return fs::readlink(dent->inode, buf, buf_size);
  82. }
  83. int kernel::syscall::do_ioctl(int fd, unsigned long request, uintptr_t arg3) {
  84. // TODO: check fd type and get tty* from fd
  85. //
  86. // we use a trick for now, check whether
  87. // the file that fd points to is a pipe or
  88. // not. and we suppose that stdin will be
  89. // either a tty or a pipe.
  90. auto* file = current_process->files[fd];
  91. if (!file || !S_ISCHR(file->mode))
  92. return -ENOTTY;
  93. switch (request) {
  94. case TIOCGPGRP: {
  95. auto* pgid = (pid_t __user*)arg3;
  96. auto* ctrl_tty = current_process->control_tty;
  97. if (!ctrl_tty)
  98. return -ENOTTY;
  99. // TODO: copy_to_user
  100. *pgid = ctrl_tty->get_pgrp();
  101. break;
  102. }
  103. case TIOCSPGRP: {
  104. // TODO: copy_from_user
  105. auto pgid = *(const pid_t __user*)arg3;
  106. auto* ctrl_tty = current_process->control_tty;
  107. if (!ctrl_tty)
  108. return -ENOTTY;
  109. ctrl_tty->set_pgrp(pgid);
  110. break;
  111. }
  112. case TIOCGWINSZ: {
  113. auto* ws = (winsize __user*)arg3;
  114. // TODO: copy_to_user
  115. ws->ws_col = 80;
  116. ws->ws_row = 10;
  117. break;
  118. }
  119. case TCGETS: {
  120. auto* argp = (struct termios __user*)arg3;
  121. auto* ctrl_tty = current_process->control_tty;
  122. if (!ctrl_tty)
  123. return -EINVAL;
  124. // TODO: use copy_to_user
  125. memcpy(argp, &ctrl_tty->termio, sizeof(ctrl_tty->termio));
  126. break;
  127. }
  128. case TCSETS: {
  129. auto* argp = (const struct termios __user*)arg3;
  130. auto* ctrl_tty = current_process->control_tty;
  131. if (!ctrl_tty)
  132. return -EINVAL;
  133. // TODO: use copy_from_user
  134. memcpy(&ctrl_tty->termio, argp, sizeof(ctrl_tty->termio));
  135. break;
  136. }
  137. default:
  138. kmsgf("[error] the ioctl() function %x is not implemented",
  139. request);
  140. return -EINVAL;
  141. }
  142. return 0;
  143. }
  144. ssize_t kernel::syscall::do_readv(int fd, const iovec* iov, int iovcnt) {
  145. auto* file = current_process->files[fd];
  146. if (!file)
  147. return -EBADF;
  148. // TODO: fix fake EOF
  149. ssize_t totn = 0;
  150. for (int i = 0; i < iovcnt; ++i) {
  151. ssize_t ret = file->read((char*)iov[i].iov_base, iov[i].iov_len);
  152. if (ret < 0)
  153. return ret;
  154. if (ret == 0)
  155. break;
  156. totn += ret;
  157. if ((size_t)ret != iov[i].iov_len)
  158. break;
  159. }
  160. return totn;
  161. }
  162. // TODO: this operation SHOULD be atomic
  163. ssize_t kernel::syscall::do_writev(int fd, const iovec* iov, int iovcnt) {
  164. auto* file = current_process->files[fd];
  165. if (!file)
  166. return -EBADF;
  167. ssize_t totn = 0;
  168. for (int i = 0; i < iovcnt; ++i) {
  169. ssize_t ret = file->write((const char*)iov[i].iov_base, iov[i].iov_len);
  170. if (ret < 0)
  171. return ret;
  172. totn += ret;
  173. }
  174. return totn;
  175. }
  176. off_t kernel::syscall::do_lseek(int fd, off_t offset, int whence) {
  177. auto* file = current_process->files[fd];
  178. if (!file)
  179. return -EBADF;
  180. return file->seek(offset, whence);
  181. }
  182. uintptr_t kernel::syscall::do_mmap_pgoff(uintptr_t addr, size_t len, int prot,
  183. int flags, int fd, off_t pgoffset) {
  184. if (addr & 0xfff)
  185. return -EINVAL;
  186. if (len == 0)
  187. return -EINVAL;
  188. len = (len + 0xfff) & ~0xfff;
  189. // TODO: shared mappings
  190. if (flags & MAP_SHARED)
  191. return -ENOMEM;
  192. if (flags & MAP_ANONYMOUS) {
  193. if (fd != -1)
  194. return -EINVAL;
  195. if (pgoffset != 0)
  196. return -EINVAL;
  197. // TODO: shared mappings
  198. if (!(flags & MAP_PRIVATE))
  199. return -EINVAL;
  200. auto& mms = current_process->mms;
  201. // do unmapping, equal to munmap, MAP_FIXED set
  202. if (prot == PROT_NONE) {
  203. if (int ret = mms.unmap(addr, len, true); ret != 0)
  204. return ret;
  205. } else {
  206. // TODO: add NULL check in mm_list
  207. if (!addr || !mms.is_avail(addr, len)) {
  208. if (flags & MAP_FIXED)
  209. return -ENOMEM;
  210. addr = mms.find_avail(addr, len);
  211. }
  212. // TODO: check current cs
  213. if (addr + len > 0x100000000ULL)
  214. return -ENOMEM;
  215. mem::mm_list::map_args args{};
  216. args.vaddr = addr;
  217. args.length = len;
  218. args.flags = mem::MM_ANONYMOUS;
  219. if (prot & PROT_WRITE)
  220. args.flags |= mem::MM_WRITE;
  221. if (prot & PROT_EXEC)
  222. args.flags |= mem::MM_EXECUTE;
  223. if (int ret = mms.mmap(args); ret != 0)
  224. return ret;
  225. }
  226. }
  227. return addr;
  228. }
  229. int kernel::syscall::do_munmap(uintptr_t addr, size_t len) {
  230. if (addr & 0xfff)
  231. return -EINVAL;
  232. return current_process->mms.unmap(addr, len, true);
  233. }
  234. ssize_t kernel::syscall::do_sendfile(int out_fd, int in_fd,
  235. off_t __user* offset, size_t count) {
  236. auto* out_file = current_process->files[out_fd];
  237. auto* in_file = current_process->files[in_fd];
  238. if (!out_file || !in_file)
  239. return -EBADF;
  240. // TODO: check whether in_fd supports mmapping
  241. if (!S_ISREG(in_file->mode) && !S_ISBLK(in_file->mode))
  242. return -EINVAL;
  243. if (offset) {
  244. NOT_IMPLEMENTED;
  245. return -EINVAL;
  246. }
  247. constexpr size_t bufsize = 4096;
  248. std::vector<char> buf(bufsize);
  249. size_t totn = 0;
  250. while (totn < count) {
  251. if (current_thread->signals.pending_signal() != 0)
  252. return (totn == 0) ? -EINTR : totn;
  253. size_t n = std::min(count - totn, bufsize);
  254. ssize_t ret = in_file->read(buf.data(), n);
  255. if (ret < 0)
  256. return ret;
  257. if (ret == 0)
  258. break;
  259. ret = out_file->write(buf.data(), ret);
  260. if (ret < 0)
  261. return ret;
  262. totn += ret;
  263. }
  264. return totn;
  265. }
  266. int kernel::syscall::do_statx(int dirfd, const char __user* path, int flags,
  267. unsigned int mask, statx __user* statxbuf) {
  268. // AT_STATX_SYNC_AS_STAT is the default value
  269. if ((flags & AT_STATX_SYNC_TYPE) != AT_STATX_SYNC_AS_STAT) {
  270. NOT_IMPLEMENTED;
  271. return -EINVAL;
  272. }
  273. if (dirfd != AT_FDCWD) {
  274. NOT_IMPLEMENTED;
  275. return -EINVAL;
  276. }
  277. auto [dent, status] = current_open(path, !(flags & AT_SYMLINK_NOFOLLOW));
  278. if (!dent || status)
  279. return status;
  280. // TODO: copy to user
  281. return fs::statx(dent->inode, statxbuf, mask);
  282. }
  283. int kernel::syscall::do_fcntl(int fd, int cmd, unsigned long arg) {
  284. auto* file = current_process->files[fd];
  285. if (!file)
  286. return -EBADF;
  287. switch (cmd) {
  288. case F_SETFD:
  289. return current_process->files.set_flags(fd, arg);
  290. case F_DUPFD:
  291. case F_DUPFD_CLOEXEC: {
  292. return current_process->files.dupfd(fd, arg, FD_CLOEXEC);
  293. }
  294. default:
  295. NOT_IMPLEMENTED;
  296. return -EINVAL;
  297. }
  298. }
  299. int kernel::syscall::do_mkdir(const char __user* pathname, mode_t mode) {
  300. mode &= (~current_process->umask & 0777);
  301. // TODO: use copy_from_user
  302. auto [dent, status] = current_open(pathname);
  303. if (!dent || status != -ENOENT)
  304. return status;
  305. return fs::mkdir(dent.get(), mode);
  306. }
  307. int kernel::syscall::do_truncate(const char __user* pathname, long length) {
  308. auto [dent, status] = current_open(pathname);
  309. if (!dent || status)
  310. return status;
  311. if (S_ISDIR(dent->inode->mode))
  312. return -EISDIR;
  313. return fs::truncate(dent->inode, length);
  314. }
  315. int kernel::syscall::do_unlink(const char __user* pathname) {
  316. auto [dent, status] = current_open(pathname, false);
  317. if (!dent || status)
  318. return status;
  319. if (S_ISDIR(dent->inode->mode))
  320. return -EISDIR;
  321. return fs::unlink(dent.get());
  322. }
  323. int kernel::syscall::do_access(const char __user* pathname, int mode) {
  324. auto [dent, status] = current_open(pathname);
  325. if (!dent || status)
  326. return status;
  327. switch (mode) {
  328. case F_OK:
  329. return 0;
  330. case R_OK:
  331. case W_OK:
  332. case X_OK:
  333. // TODO: check privilege
  334. return 0;
  335. default:
  336. return -EINVAL;
  337. }
  338. }
  339. int kernel::syscall::do_mknod(const char __user* pathname, mode_t mode,
  340. dev_t dev) {
  341. mode &= S_IFMT | (~current_process->umask & 0777);
  342. auto [dent, status] = current_open(pathname);
  343. if (!dent || status != -ENOENT)
  344. return status;
  345. return fs::mknod(dent.get(), mode, dev);
  346. }
  347. int kernel::syscall::do_poll(pollfd __user* fds, nfds_t nfds, int timeout) {
  348. if (nfds == 0)
  349. return 0;
  350. if (nfds > 1) {
  351. NOT_IMPLEMENTED;
  352. return -EINVAL;
  353. }
  354. // TODO: handle timeout
  355. // if (timeout != -1) {
  356. // }
  357. (void)timeout;
  358. // for now, we will poll from console only
  359. int ret = tty::console->poll();
  360. if (ret < 0)
  361. return ret;
  362. fds[0].revents = POLLIN;
  363. return ret;
  364. // TODO: check address validity
  365. // TODO: poll multiple fds and other type of files
  366. // for (nfds_t i = 0; i < nfds; ++i) {
  367. // auto& pfd = fds[i];
  368. // auto* file = current_process->files[pfd.fd];
  369. // if (!file || !S_ISCHR(file->mode))
  370. // return -EINVAL;
  371. // // poll the fds
  372. // }
  373. //
  374. // return 0;
  375. }
  376. int kernel::syscall::do_socket(int domain, int type, int protocol) {
  377. return -EINVAL;
  378. }
  379. /* TODO: implement vfs_stat(stat*)
  380. int do_stat(const char __user* pathname, stat __user* buf)
  381. {
  382. auto* dent = fs::vfs_open(*current_process->root,
  383. types::make_path(pathname, current_process->pwd));
  384. if (!dent)
  385. return -ENOENT;
  386. return fs::vfs_stat(dent, buf);
  387. }
  388. */
  389. /* TODO: implement vfs_stat(stat*)
  390. int do_fstat(int fd, stat __user* buf)
  391. {
  392. auto* file = current_process->files[fd];
  393. if (!file)
  394. return -EBADF;
  395. return fs::vfs_stat(file, buf);
  396. }
  397. */