tty_compat.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * (tty_compat.c)
  7. * The compatible layer which interacts with process management core (lwp)
  8. *
  9. * Change Logs:
  10. * Date Author Notes
  11. * 2023-11-13 Shell init ver.
  12. */
  13. #define DBG_TAG "lwp.tty"
  14. #define DBG_LVL DBG_INFO
  15. #include <rtdbg.h>
  16. #include "../tty_config.h"
  17. #include "../tty_internal.h"
  18. #include "../terminal.h"
  19. /*-
  20. * SPDX-License-Identifier: BSD-2-Clause
  21. *
  22. * Copyright (c) 1994-1995 Søren Schmidt
  23. * All rights reserved.
  24. *
  25. * Redistribution and use in source and binary forms, with or without
  26. * modification, are permitted provided that the following conditions
  27. * are met:
  28. * 1. Redistributions of source code must retain the above copyright
  29. * notice, this list of conditions and the following disclaimer.
  30. * 2. Redistributions in binary form must reproduce the above copyright
  31. * notice, this list of conditions and the following disclaimer in the
  32. * documentation and/or other materials provided with the distribution.
  33. *
  34. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  35. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  36. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  37. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  38. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  39. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  40. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  41. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  42. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  43. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  44. * SUCH DAMAGE.
  45. */
  46. /* is the tty and session leader already binding ? */
  47. static rt_bool_t _is_already_binding(lwp_tty_t tp, rt_lwp_t p)
  48. {
  49. rt_bool_t rc;
  50. rt_processgroup_t pgrp = p->pgrp;
  51. /* lwp is already locked */
  52. RT_ASSERT(pgrp);
  53. /* Note: pgrp->session is constant after process group is created */
  54. if (tp->t_session && tp->t_session == pgrp->session)
  55. {
  56. rc = RT_TRUE;
  57. }
  58. else
  59. {
  60. rc = RT_FALSE;
  61. }
  62. return rc;
  63. }
  64. static rt_bool_t _is_tty_or_sess_busy(lwp_tty_t tp, rt_lwp_t p)
  65. {
  66. rt_bool_t rc;
  67. rt_session_t sess = p->pgrp->session;
  68. SESS_LOCK(sess);
  69. if (sess->ctty)
  70. {
  71. rc = RT_TRUE;
  72. }
  73. else if (tp->t_session)
  74. {
  75. /**
  76. * TODO: allow TTY stolen if the sess leader is killed while resource
  77. * had not been collected
  78. */
  79. if (tp->t_session->leader == RT_NULL)
  80. rc = RT_FALSE;
  81. else
  82. rc = RT_TRUE;
  83. }
  84. else
  85. {
  86. rc = RT_FALSE;
  87. }
  88. SESS_UNLOCK(sess);
  89. return rc;
  90. }
  91. int lwp_tty_bg_stop(struct lwp_tty *tp, struct rt_condvar *cv)
  92. {
  93. int error;
  94. int revokecnt = tp->t_revokecnt;
  95. rt_lwp_t self_lwp;
  96. rt_thread_t header_thr;
  97. rt_thread_t cur_thr = rt_thread_self();
  98. int jobctl_stopped;
  99. self_lwp = cur_thr->lwp;
  100. RT_ASSERT(self_lwp);
  101. jobctl_stopped = self_lwp->jobctl_stopped;
  102. tty_lock_assert(tp, MA_OWNED | MA_NOTRECURSED);
  103. MPASS(!tty_gone(tp));
  104. LWP_LOCK(self_lwp);
  105. header_thr = rt_list_entry(self_lwp->t_grp.prev, struct rt_thread, sibling);
  106. if (!jobctl_stopped && header_thr == cur_thr &&
  107. cur_thr->sibling.prev == &self_lwp->t_grp)
  108. {
  109. /* update lwp status */
  110. jobctl_stopped = self_lwp->jobctl_stopped = RT_TRUE;
  111. }
  112. LWP_UNLOCK(self_lwp);
  113. error = cv_wait(cv, tp->t_mtx);
  114. if (jobctl_stopped)
  115. {
  116. self_lwp->jobctl_stopped = RT_FALSE;
  117. }
  118. /* Bail out when the device slipped away. */
  119. if (tty_gone(tp))
  120. return -ENXIO;
  121. /* Restart the system call when we may have been revoked. */
  122. if (tp->t_revokecnt != revokecnt)
  123. return -ERESTART;
  124. return error;
  125. }
  126. /* process management */
  127. int lwp_tty_set_ctrl_proc(lwp_tty_t tp, rt_thread_t td)
  128. {
  129. int rc = -1;
  130. struct rt_lwp *p = td->lwp;
  131. tty_unlock(tp);
  132. LWP_LOCK(p);
  133. tty_lock(tp);
  134. if (is_sess_leader(p))
  135. {
  136. if (_is_already_binding(tp, p))
  137. {
  138. rc = 0;
  139. }
  140. else if (_is_tty_or_sess_busy(tp, p))
  141. {
  142. rc = -EPERM;
  143. }
  144. else
  145. {
  146. /**
  147. * Binding controlling process
  148. * note: p->pgrp is protected by lwp lock;
  149. * pgrp->session is always constant.
  150. */
  151. tp->t_session = p->pgrp->session;
  152. tp->t_session->ctty = tp;
  153. tp->t_sessioncnt++;
  154. /* Assign foreground process group */
  155. tp->t_pgrp = p->pgrp;
  156. p->term_ctrlterm = RT_TRUE;
  157. LOG_D("%s(sid=%d)", __func__, tp->t_session->sid);
  158. rc = 0;
  159. }
  160. }
  161. else
  162. {
  163. rc = -EPERM;
  164. }
  165. LWP_UNLOCK(p);
  166. return rc;
  167. }
  168. int lwp_tty_assign_foreground(lwp_tty_t tp, rt_thread_t td, int pgid)
  169. {
  170. struct rt_processgroup *pg;
  171. rt_lwp_t cur_lwp = td->lwp;
  172. tty_unlock(tp);
  173. pg = lwp_pgrp_find_and_inc_ref(pgid);
  174. if (pg == NULL || cur_lwp == NULL)
  175. {
  176. tty_lock(tp);
  177. return -EPERM;
  178. }
  179. else
  180. {
  181. PGRP_LOCK(pg);
  182. if (pg->sid != cur_lwp->sid)
  183. {
  184. PGRP_UNLOCK(pg);
  185. lwp_pgrp_dec_ref(pg);
  186. LOG_D("%s: NoPerm current process (pid=%d, pgid=%d, sid=%d), "
  187. "tagget group (pgid=%d, sid=%d)", __func__,
  188. cur_lwp->pid, cur_lwp->pgid, cur_lwp->sid, pgid, pg->sid);
  189. tty_lock(tp);
  190. return -EPERM;
  191. }
  192. }
  193. tty_lock(tp);
  194. /**
  195. * Determine if this TTY is the controlling TTY after
  196. * relocking the TTY.
  197. */
  198. if (!tty_is_ctty(tp, td->lwp))
  199. {
  200. PGRP_UNLOCK(pg);
  201. LOG_D("%s: NoCTTY current process (pid=%d, pgid=%d, sid=%d), "
  202. "tagget group (pgid=%d, sid=%d)", __func__,
  203. cur_lwp->pid, cur_lwp->pgid, cur_lwp->sid, pgid, pg->sid);
  204. return -ENOTTY;
  205. }
  206. tp->t_pgrp = pg;
  207. PGRP_UNLOCK(pg);
  208. lwp_pgrp_dec_ref(pg);
  209. /* Wake up the background process groups. */
  210. cv_broadcast(&tp->t_bgwait);
  211. LOG_D("%s: Foreground group %p (pgid=%d)", __func__, tp->t_pgrp,
  212. tp->t_pgrp ? tp->t_pgrp->pgid : -1);
  213. return 0;
  214. }
  215. /**
  216. * Signalling processes.
  217. */
  218. void lwp_tty_signal_sessleader(struct lwp_tty *tp, int sig)
  219. {
  220. struct rt_lwp *p;
  221. struct rt_session *s;
  222. tty_assert_locked(tp);
  223. MPASS(sig >= 1 && sig < _LWP_NSIG);
  224. /* Make signals start output again. */
  225. tp->t_flags &= ~TF_STOPPED;
  226. tp->t_termios.c_lflag &= ~FLUSHO;
  227. /**
  228. * Load s.leader exactly once to avoid race where s.leader is
  229. * set to NULL by a concurrent invocation of killjobc() by the
  230. * session leader. Note that we are not holding t_session's
  231. * lock for the read.
  232. */
  233. if ((s = tp->t_session) != NULL &&
  234. (p = (void *)rt_atomic_load((rt_atomic_t *)&s->leader)) != NULL)
  235. {
  236. lwp_signal_kill(p, sig, SI_KERNEL, 0);
  237. }
  238. }
  239. void lwp_tty_signal_pgrp(struct lwp_tty *tp, int sig)
  240. {
  241. tty_assert_locked(tp);
  242. MPASS(sig >= 1 && sig < _LWP_NSIG);
  243. /* Make signals start output again. */
  244. tp->t_flags &= ~TF_STOPPED;
  245. tp->t_termios.c_lflag &= ~FLUSHO;
  246. #ifdef USING_BSD_SIGINFO
  247. if (sig == SIGINFO && !(tp->t_termios.c_lflag & NOKERNINFO))
  248. tty_info(tp);
  249. #endif /* USING_BSD_SIGINFO */
  250. if (tp->t_pgrp != NULL)
  251. {
  252. PGRP_LOCK(tp->t_pgrp);
  253. lwp_pgrp_signal_kill(tp->t_pgrp, sig, SI_KERNEL, 0);
  254. PGRP_UNLOCK(tp->t_pgrp);
  255. }
  256. }
  257. /* bsd_ttydev_methods.d_ioctl */
  258. rt_inline size_t _copy_to_user(void *to, void *from, size_t n)
  259. {
  260. return lwp_put_to_user(to, from, n) == n ? 0 : -EFAULT;
  261. }
  262. rt_inline size_t _copy_from_user(void *to, void *from, size_t n)
  263. {
  264. return lwp_get_from_user(to, from, n) == n ? 0 : -EFAULT;
  265. }
  266. static void termios_to_termio(struct termios *tios, struct termio *tio)
  267. {
  268. memset(tio, 0, sizeof(*tio));
  269. tio->c_iflag = tios->c_iflag;
  270. tio->c_oflag = tios->c_oflag;
  271. tio->c_cflag = tios->c_cflag;
  272. tio->c_lflag = tios->c_lflag;
  273. tio->c_line = tios->c_line;
  274. memcpy(tio->c_cc, tios->c_cc, NCC);
  275. }
  276. static void termio_to_termios(struct termio *tio, struct termios *tios)
  277. {
  278. int i;
  279. tios->c_iflag = tio->c_iflag;
  280. tios->c_oflag = tio->c_oflag;
  281. tios->c_cflag = tio->c_cflag;
  282. tios->c_lflag = tio->c_lflag;
  283. for (i = NCC; i < NCCS; i++)
  284. tios->c_cc[i] = _POSIX_VDISABLE;
  285. memcpy(tios->c_cc, tio->c_cc, NCC);
  286. }
  287. #define IOCTL(cmd, data, fflags, td) \
  288. bsd_ttydev_methods.d_ioctl(tp, cmd, data, fflags, td)
  289. int lwp_tty_ioctl_adapter(lwp_tty_t tp, int cmd, int oflags, void *args, rt_thread_t td)
  290. {
  291. long fflags = FFLAGS(oflags);
  292. struct termios tios;
  293. struct termio tio;
  294. int error;
  295. LOG_D("%s(cmd=0x%x, args=%p)", __func__, cmd, args);
  296. switch (cmd & 0xffff)
  297. {
  298. case TCGETS:
  299. error = IOCTL(TIOCGETA, (rt_caddr_t)&tios, fflags, td);
  300. if (error)
  301. break;
  302. error = _copy_to_user(args, &tios, sizeof(tios));
  303. break;
  304. case TCSETS:
  305. error = _copy_from_user(&tios, args, sizeof(tios));
  306. if (error)
  307. break;
  308. error = (IOCTL(TIOCSETA, (rt_caddr_t)&tios, fflags, td));
  309. break;
  310. case TCSETSW:
  311. error = _copy_from_user(&tios, args, sizeof(tios));
  312. if (error)
  313. break;
  314. error = (IOCTL(TIOCSETAW, (rt_caddr_t)&tios, fflags, td));
  315. break;
  316. case TCSETSF:
  317. error = _copy_from_user(&tios, args, sizeof(tios));
  318. if (error)
  319. break;
  320. error = (IOCTL(TIOCSETAF, (rt_caddr_t)&tios, fflags, td));
  321. break;
  322. case TCGETA:
  323. error = IOCTL(TIOCGETA, (rt_caddr_t)&tios, fflags, td);
  324. if (error)
  325. break;
  326. termios_to_termio(&tios, &tio);
  327. error = _copy_to_user((void *)args, &tio, sizeof(tio));
  328. break;
  329. case TCSETA:
  330. error = _copy_from_user(&tio, (void *)args, sizeof(tio));
  331. if (error)
  332. break;
  333. termio_to_termios(&tio, &tios);
  334. error = (IOCTL(TIOCSETA, (rt_caddr_t)&tios, fflags, td));
  335. break;
  336. case TCSETAW:
  337. error = _copy_from_user(&tio, (void *)args, sizeof(tio));
  338. if (error)
  339. break;
  340. termio_to_termios(&tio, &tios);
  341. error = (IOCTL(TIOCSETAW, (rt_caddr_t)&tios, fflags, td));
  342. break;
  343. case TCSETAF:
  344. error = _copy_from_user(&tio, (void *)args, sizeof(tio));
  345. if (error)
  346. break;
  347. termio_to_termios(&tio, &tios);
  348. error = (IOCTL(TIOCSETAF, (rt_caddr_t)&tios, fflags, td));
  349. break;
  350. case TCSBRK:
  351. if (args != 0)
  352. {
  353. /**
  354. * Linux manual: SVr4, UnixWare, Solaris, and Linux treat
  355. * tcsendbreak(fd,arg) with nonzero arg like tcdrain(fd).
  356. */
  357. error = IOCTL(TIOCDRAIN, (rt_caddr_t)&tios, fflags, td);
  358. }
  359. else
  360. {
  361. /**
  362. * Linux manual: If the terminal is using asynchronous serial
  363. * data transmission, and arg is zero, then send a break (a
  364. * stream of zero bits) for between 0.25 and 0.5 seconds.
  365. */
  366. LOG_D("%s: ioctl TCSBRK arg 0 not implemented", __func__);
  367. error = -ENOSYS;
  368. }
  369. break;
  370. #ifdef USING_BSD_IOCTL_EXT
  371. /* Software flow control */
  372. case TCXONC: {
  373. switch (args->arg)
  374. {
  375. case TCOOFF:
  376. args->cmd = TIOCSTOP;
  377. break;
  378. case TCOON:
  379. args->cmd = TIOCSTART;
  380. break;
  381. case TCIOFF:
  382. case TCION: {
  383. int c;
  384. struct write_args wr;
  385. error = IOCTL(TIOCGETA, (rt_caddr_t)&tios, fflags,
  386. td);
  387. if (error)
  388. break;
  389. fdrop(fp, td);
  390. c = (args->arg == TCIOFF) ? VSTOP : VSTART;
  391. c = tios.c_cc[c];
  392. if (c != _POSIX_VDISABLE)
  393. {
  394. wr.fd = args->fd;
  395. wr.buf = &c;
  396. wr.nbyte = sizeof(c);
  397. return (sys_write(td, &wr));
  398. }
  399. else
  400. return 0;
  401. }
  402. default:
  403. fdrop(fp, td);
  404. return -EINVAL;
  405. }
  406. args->arg = 0;
  407. error = (sys_ioctl(td, (struct ioctl_args *)args));
  408. break;
  409. }
  410. #endif /* USING_BSD_IOCTL_EXT */
  411. case TCFLSH: {
  412. int val;
  413. error = 0;
  414. switch ((rt_base_t)args)
  415. {
  416. case TCIFLUSH:
  417. val = FREAD;
  418. break;
  419. case TCOFLUSH:
  420. val = FWRITE;
  421. break;
  422. case TCIOFLUSH:
  423. val = FREAD | FWRITE;
  424. break;
  425. default:
  426. error = -EINVAL;
  427. break;
  428. }
  429. if (!error)
  430. error = (IOCTL(TIOCFLUSH, (rt_caddr_t)&val, fflags, td));
  431. break;
  432. }
  433. #ifdef USING_BSD_IOCTL_EXT
  434. case TIOCEXCL:
  435. args->cmd = TIOCEXCL;
  436. error = (sys_ioctl(td, (struct ioctl_args *)args));
  437. break;
  438. case TIOCNXCL:
  439. args->cmd = TIOCNXCL;
  440. error = (sys_ioctl(td, (struct ioctl_args *)args));
  441. break;
  442. #endif /* USING_BSD_IOCTL_EXT */
  443. /* Controlling terminal */
  444. case TIOCSCTTY:
  445. case TIOCNOTTY:
  446. /* Process group and session ID */
  447. case TIOCGPGRP:
  448. case TIOCSPGRP:
  449. case TIOCGSID:
  450. /* TIOCOUTQ */
  451. /* TIOCSTI */
  452. case TIOCGWINSZ:
  453. case TIOCSWINSZ:
  454. error = IOCTL(cmd, (rt_caddr_t)args, fflags, td);
  455. break;
  456. #ifdef USING_BSD_IOCTL_EXT
  457. case TIOCMGET:
  458. args->cmd = TIOCMGET;
  459. error = (sys_ioctl(td, (struct ioctl_args *)args));
  460. break;
  461. case TIOCMBIS:
  462. args->cmd = TIOCMBIS;
  463. error = (sys_ioctl(td, (struct ioctl_args *)args));
  464. break;
  465. case TIOCMBIC:
  466. args->cmd = TIOCMBIC;
  467. error = (sys_ioctl(td, (struct ioctl_args *)args));
  468. break;
  469. case TIOCMSET:
  470. args->cmd = TIOCMSET;
  471. error = (sys_ioctl(td, (struct ioctl_args *)args));
  472. break;
  473. /* TIOCGSOFTCAR */
  474. /* TIOCSSOFTCAR */
  475. case FIONREAD: /* TIOCINQ */
  476. args->cmd = FIONREAD;
  477. error = (sys_ioctl(td, (struct ioctl_args *)args));
  478. break;
  479. /* TIOCLINUX */
  480. case TIOCCONS:
  481. args->cmd = TIOCCONS;
  482. error = (sys_ioctl(td, (struct ioctl_args *)args));
  483. break;
  484. case TIOCGSERIAL: {
  485. struct linux_serial_struct lss;
  486. bzero(&lss, sizeof(lss));
  487. lss.type = PORT_16550A;
  488. lss.flags = 0;
  489. lss.close_delay = 0;
  490. error = copyout(&lss, (void *)args->arg, sizeof(lss));
  491. break;
  492. }
  493. case TIOCSSERIAL: {
  494. struct linux_serial_struct lss;
  495. error = copyin((void *)args->arg, &lss, sizeof(lss));
  496. if (error)
  497. break;
  498. /* XXX - It really helps to have an implementation that
  499. * does nothing. NOT!
  500. */
  501. error = 0;
  502. break;
  503. }
  504. case TIOCPKT:
  505. args->cmd = TIOCPKT;
  506. error = (sys_ioctl(td, (struct ioctl_args *)args));
  507. break;
  508. case FIONBIO:
  509. args->cmd = FIONBIO;
  510. error = (sys_ioctl(td, (struct ioctl_args *)args));
  511. break;
  512. case TIOCSETD: {
  513. int line;
  514. switch (args->arg)
  515. {
  516. case N_TTY:
  517. line = TTYDISC;
  518. break;
  519. case N_SLIP:
  520. line = SLIPDISC;
  521. break;
  522. case N_PPP:
  523. line = PPPDISC;
  524. break;
  525. default:
  526. fdrop(fp, td);
  527. return -EINVAL;
  528. }
  529. error = (ioctl_emit(TIOCSETD, (rt_caddr_t)&line, fflags, td));
  530. break;
  531. }
  532. case TIOCGETD: {
  533. int linux_line;
  534. int bsd_line = TTYDISC;
  535. error =
  536. ioctl_emit(TIOCGETD, (rt_caddr_t)&bsd_line, fflags, td);
  537. if (error)
  538. break;
  539. switch (bsd_line)
  540. {
  541. case TTYDISC:
  542. linux_line = N_TTY;
  543. break;
  544. case SLIPDISC:
  545. linux_line = N_SLIP;
  546. break;
  547. case PPPDISC:
  548. linux_line = N_PPP;
  549. break;
  550. default:
  551. fdrop(fp, td);
  552. return -EINVAL;
  553. }
  554. error = (copyout(&linux_line, (void *)args->arg, sizeof(int)));
  555. break;
  556. }
  557. /* TCSBRKP */
  558. /* TIOCTTYGSTRUCT */
  559. case FIONCLEX:
  560. args->cmd = FIONCLEX;
  561. error = (sys_ioctl(td, (struct ioctl_args *)args));
  562. break;
  563. case FIOCLEX:
  564. args->cmd = FIOCLEX;
  565. error = (sys_ioctl(td, (struct ioctl_args *)args));
  566. break;
  567. case FIOASYNC:
  568. args->cmd = FIOASYNC;
  569. error = (sys_ioctl(td, (struct ioctl_args *)args));
  570. break;
  571. /* TIOCSERCONFIG */
  572. /* TIOCSERGWILD */
  573. /* TIOCSERSWILD */
  574. /* TIOCGLCKTRMIOS */
  575. /* TIOCSLCKTRMIOS */
  576. case TIOCSBRK:
  577. args->cmd = TIOCSBRK;
  578. error = (sys_ioctl(td, (struct ioctl_args *)args));
  579. break;
  580. case TIOCCBRK:
  581. args->cmd = TIOCCBRK;
  582. error = (sys_ioctl(td, (struct ioctl_args *)args));
  583. break;
  584. case TIOCGPTN: {
  585. int nb;
  586. error = ioctl_emit(TIOCGPTN, (rt_caddr_t)&nb, fflags, td);
  587. if (!error)
  588. error = copyout(&nb, (void *)args->arg, sizeof(int));
  589. break;
  590. }
  591. case TIOCGPTPEER:
  592. linux_msg(td, "unsupported ioctl TIOCGPTPEER");
  593. error = -ENOIOCTL;
  594. break;
  595. case TIOCSPTLCK:
  596. /*
  597. * Our unlockpt() does nothing. Check that fd refers
  598. * to a pseudo-terminal master device.
  599. */
  600. args->cmd = TIOCPTMASTER;
  601. error = (sys_ioctl(td, (struct ioctl_args *)args));
  602. break;
  603. #endif /* USING_BSD_IOCTL_EXT */
  604. /**
  605. * those are for current implementation of devfs, and we dont want to
  606. * log them
  607. */
  608. case F_DUPFD:
  609. case F_DUPFD_CLOEXEC:
  610. case F_GETFD:
  611. case F_SETFD:
  612. case F_GETFL:
  613. case F_SETFL:
  614. /* fall back to fs */
  615. error = -ENOIOCTL;
  616. break;
  617. default:
  618. LOG_I("%s: unhandle commands 0x%x", __func__, cmd);
  619. error = -ENOSYS;
  620. break;
  621. }
  622. return (error);
  623. }