fileops.cc 12 KB

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