Commit | Line | Data |
---|---|---|
e3b3d0f5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
a1235b3e NP |
2 | /* |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | |
4 | */ | |
5 | ||
6 | #include <linux/types.h> | |
7 | #include <linux/errno.h> | |
8 | #include <linux/signal.h> | |
9 | #include <linux/sched/signal.h> | |
10 | #include <linux/sched/task.h> | |
11 | #include <linux/tty.h> | |
12 | #include <linux/fcntl.h> | |
13 | #include <linux/uaccess.h> | |
98602c01 | 14 | #include "tty.h" |
a1235b3e NP |
15 | |
16 | static int is_ignored(int sig) | |
17 | { | |
18 | return (sigismember(¤t->blocked, sig) || | |
19 | current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); | |
20 | } | |
21 | ||
22 | /** | |
23 | * tty_check_change - check for POSIX terminal changes | |
24 | * @tty: tty to check | |
bc38fe24 | 25 | * @sig: signal to send |
a1235b3e NP |
26 | * |
27 | * If we try to write to, or set the state of, a terminal and we're | |
28 | * not in the foreground, send a SIGTTOU. If the signal is blocked or | |
29 | * ignored, go ahead and perform the operation. (POSIX 7.2) | |
30 | * | |
31 | * Locking: ctrl_lock | |
32 | */ | |
33 | int __tty_check_change(struct tty_struct *tty, int sig) | |
34 | { | |
35 | unsigned long flags; | |
36 | struct pid *pgrp, *tty_pgrp; | |
37 | int ret = 0; | |
38 | ||
39 | if (current->signal->tty != tty) | |
40 | return 0; | |
41 | ||
42 | rcu_read_lock(); | |
43 | pgrp = task_pgrp(current); | |
44 | ||
45 | spin_lock_irqsave(&tty->ctrl_lock, flags); | |
46 | tty_pgrp = tty->pgrp; | |
47 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | |
48 | ||
cf90c06f | 49 | if (tty_pgrp && pgrp != tty_pgrp) { |
a1235b3e NP |
50 | if (is_ignored(sig)) { |
51 | if (sig == SIGTTIN) | |
52 | ret = -EIO; | |
53 | } else if (is_current_pgrp_orphaned()) | |
54 | ret = -EIO; | |
55 | else { | |
56 | kill_pgrp(pgrp, sig, 1); | |
57 | set_thread_flag(TIF_SIGPENDING); | |
58 | ret = -ERESTARTSYS; | |
59 | } | |
60 | } | |
61 | rcu_read_unlock(); | |
62 | ||
63 | if (!tty_pgrp) | |
64 | tty_warn(tty, "sig=%d, tty->pgrp == NULL!\n", sig); | |
65 | ||
66 | return ret; | |
67 | } | |
68 | ||
69 | int tty_check_change(struct tty_struct *tty) | |
70 | { | |
71 | return __tty_check_change(tty, SIGTTOU); | |
72 | } | |
73 | EXPORT_SYMBOL(tty_check_change); | |
74 | ||
75 | void proc_clear_tty(struct task_struct *p) | |
76 | { | |
77 | unsigned long flags; | |
78 | struct tty_struct *tty; | |
d4e1d903 | 79 | |
a1235b3e NP |
80 | spin_lock_irqsave(&p->sighand->siglock, flags); |
81 | tty = p->signal->tty; | |
82 | p->signal->tty = NULL; | |
83 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | |
84 | tty_kref_put(tty); | |
85 | } | |
86 | ||
87 | /** | |
88 | * proc_set_tty - set the controlling terminal | |
bc38fe24 | 89 | * @tty: tty structure |
a1235b3e NP |
90 | * |
91 | * Only callable by the session leader and only if it does not already have | |
92 | * a controlling terminal. | |
93 | * | |
94 | * Caller must hold: tty_lock() | |
95 | * a readlock on tasklist_lock | |
96 | * sighand lock | |
97 | */ | |
98 | static void __proc_set_tty(struct tty_struct *tty) | |
99 | { | |
100 | unsigned long flags; | |
101 | ||
102 | spin_lock_irqsave(&tty->ctrl_lock, flags); | |
103 | /* | |
104 | * The session and fg pgrp references will be non-NULL if | |
105 | * tiocsctty() is stealing the controlling tty | |
106 | */ | |
107 | put_pid(tty->session); | |
108 | put_pid(tty->pgrp); | |
109 | tty->pgrp = get_pid(task_pgrp(current)); | |
a1235b3e | 110 | tty->session = get_pid(task_session(current)); |
c8bcd9c5 | 111 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); |
a1235b3e NP |
112 | if (current->signal->tty) { |
113 | tty_debug(tty, "current tty %s not NULL!!\n", | |
114 | current->signal->tty->name); | |
115 | tty_kref_put(current->signal->tty); | |
116 | } | |
117 | put_pid(current->signal->tty_old_pgrp); | |
118 | current->signal->tty = tty_kref_get(tty); | |
119 | current->signal->tty_old_pgrp = NULL; | |
120 | } | |
121 | ||
122 | static void proc_set_tty(struct tty_struct *tty) | |
123 | { | |
124 | spin_lock_irq(¤t->sighand->siglock); | |
125 | __proc_set_tty(tty); | |
126 | spin_unlock_irq(¤t->sighand->siglock); | |
127 | } | |
128 | ||
129 | /* | |
130 | * Called by tty_open() to set the controlling tty if applicable. | |
131 | */ | |
132 | void tty_open_proc_set_tty(struct file *filp, struct tty_struct *tty) | |
133 | { | |
134 | read_lock(&tasklist_lock); | |
135 | spin_lock_irq(¤t->sighand->siglock); | |
136 | if (current->signal->leader && | |
137 | !current->signal->tty && | |
138 | tty->session == NULL) { | |
139 | /* | |
140 | * Don't let a process that only has write access to the tty | |
141 | * obtain the privileges associated with having a tty as | |
142 | * controlling terminal (being able to reopen it with full | |
143 | * access through /dev/tty, being able to perform pushback). | |
144 | * Many distributions set the group of all ttys to "tty" and | |
145 | * grant write-only access to all terminals for setgid tty | |
146 | * binaries, which should not imply full privileges on all ttys. | |
147 | * | |
148 | * This could theoretically break old code that performs open() | |
149 | * on a write-only file descriptor. In that case, it might be | |
150 | * necessary to also permit this if | |
151 | * inode_permission(inode, MAY_READ) == 0. | |
152 | */ | |
153 | if (filp->f_mode & FMODE_READ) | |
154 | __proc_set_tty(tty); | |
155 | } | |
156 | spin_unlock_irq(¤t->sighand->siglock); | |
157 | read_unlock(&tasklist_lock); | |
158 | } | |
159 | ||
160 | struct tty_struct *get_current_tty(void) | |
161 | { | |
162 | struct tty_struct *tty; | |
163 | unsigned long flags; | |
164 | ||
165 | spin_lock_irqsave(¤t->sighand->siglock, flags); | |
166 | tty = tty_kref_get(current->signal->tty); | |
167 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | |
168 | return tty; | |
169 | } | |
170 | EXPORT_SYMBOL_GPL(get_current_tty); | |
171 | ||
172 | /* | |
173 | * Called from tty_release(). | |
174 | */ | |
175 | void session_clear_tty(struct pid *session) | |
176 | { | |
177 | struct task_struct *p; | |
d4e1d903 | 178 | |
a1235b3e NP |
179 | do_each_pid_task(session, PIDTYPE_SID, p) { |
180 | proc_clear_tty(p); | |
181 | } while_each_pid_task(session, PIDTYPE_SID, p); | |
182 | } | |
183 | ||
184 | /** | |
185 | * tty_signal_session_leader - sends SIGHUP to session leader | |
fa441954 JS |
186 | * @tty: controlling tty |
187 | * @exit_session: if non-zero, signal all foreground group processes | |
a1235b3e NP |
188 | * |
189 | * Send SIGHUP and SIGCONT to the session leader and its process group. | |
190 | * Optionally, signal all processes in the foreground process group. | |
191 | * | |
192 | * Returns the number of processes in the session with this tty | |
193 | * as their controlling terminal. This value is used to drop | |
194 | * tty references for those processes. | |
195 | */ | |
196 | int tty_signal_session_leader(struct tty_struct *tty, int exit_session) | |
197 | { | |
198 | struct task_struct *p; | |
199 | int refs = 0; | |
200 | struct pid *tty_pgrp = NULL; | |
201 | ||
202 | read_lock(&tasklist_lock); | |
203 | if (tty->session) { | |
204 | do_each_pid_task(tty->session, PIDTYPE_SID, p) { | |
205 | spin_lock_irq(&p->sighand->siglock); | |
206 | if (p->signal->tty == tty) { | |
207 | p->signal->tty = NULL; | |
63eeafd4 XT |
208 | /* |
209 | * We defer the dereferences outside of | |
210 | * the tasklist lock. | |
211 | */ | |
a1235b3e NP |
212 | refs++; |
213 | } | |
214 | if (!p->signal->leader) { | |
215 | spin_unlock_irq(&p->sighand->siglock); | |
216 | continue; | |
217 | } | |
218 | __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); | |
219 | __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); | |
220 | put_pid(p->signal->tty_old_pgrp); /* A noop */ | |
221 | spin_lock(&tty->ctrl_lock); | |
222 | tty_pgrp = get_pid(tty->pgrp); | |
223 | if (tty->pgrp) | |
224 | p->signal->tty_old_pgrp = get_pid(tty->pgrp); | |
225 | spin_unlock(&tty->ctrl_lock); | |
226 | spin_unlock_irq(&p->sighand->siglock); | |
227 | } while_each_pid_task(tty->session, PIDTYPE_SID, p); | |
228 | } | |
229 | read_unlock(&tasklist_lock); | |
230 | ||
231 | if (tty_pgrp) { | |
232 | if (exit_session) | |
233 | kill_pgrp(tty_pgrp, SIGHUP, exit_session); | |
234 | put_pid(tty_pgrp); | |
235 | } | |
236 | ||
237 | return refs; | |
238 | } | |
239 | ||
240 | /** | |
241 | * disassociate_ctty - disconnect controlling tty | |
242 | * @on_exit: true if exiting so need to "hang up" the session | |
243 | * | |
244 | * This function is typically called only by the session leader, when | |
245 | * it wants to disassociate itself from its controlling tty. | |
246 | * | |
247 | * It performs the following functions: | |
96d50825 XT |
248 | * (1) Sends a SIGHUP and SIGCONT to the foreground process group |
249 | * (2) Clears the tty from being controlling the session | |
250 | * (3) Clears the controlling tty for all processes in the | |
251 | * session group. | |
a1235b3e NP |
252 | * |
253 | * The argument on_exit is set to 1 if called when a process is | |
254 | * exiting; it is 0 if called by the ioctl TIOCNOTTY. | |
255 | * | |
256 | * Locking: | |
257 | * BTM is taken for hysterical raisons, and held when | |
258 | * called from no_tty(). | |
259 | * tty_mutex is taken to protect tty | |
260 | * ->siglock is taken to protect ->signal/->sighand | |
261 | * tasklist_lock is taken to walk process list for sessions | |
262 | * ->siglock is taken to protect ->signal/->sighand | |
263 | */ | |
264 | void disassociate_ctty(int on_exit) | |
265 | { | |
266 | struct tty_struct *tty; | |
267 | ||
268 | if (!current->signal->leader) | |
269 | return; | |
270 | ||
271 | tty = get_current_tty(); | |
272 | if (tty) { | |
273 | if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) { | |
274 | tty_vhangup_session(tty); | |
275 | } else { | |
276 | struct pid *tty_pgrp = tty_get_pgrp(tty); | |
d4e1d903 | 277 | |
a1235b3e NP |
278 | if (tty_pgrp) { |
279 | kill_pgrp(tty_pgrp, SIGHUP, on_exit); | |
280 | if (!on_exit) | |
281 | kill_pgrp(tty_pgrp, SIGCONT, on_exit); | |
282 | put_pid(tty_pgrp); | |
283 | } | |
284 | } | |
285 | tty_kref_put(tty); | |
286 | ||
287 | } else if (on_exit) { | |
288 | struct pid *old_pgrp; | |
d4e1d903 | 289 | |
a1235b3e NP |
290 | spin_lock_irq(¤t->sighand->siglock); |
291 | old_pgrp = current->signal->tty_old_pgrp; | |
292 | current->signal->tty_old_pgrp = NULL; | |
293 | spin_unlock_irq(¤t->sighand->siglock); | |
294 | if (old_pgrp) { | |
295 | kill_pgrp(old_pgrp, SIGHUP, on_exit); | |
296 | kill_pgrp(old_pgrp, SIGCONT, on_exit); | |
297 | put_pid(old_pgrp); | |
298 | } | |
299 | return; | |
300 | } | |
301 | ||
302 | spin_lock_irq(¤t->sighand->siglock); | |
303 | put_pid(current->signal->tty_old_pgrp); | |
304 | current->signal->tty_old_pgrp = NULL; | |
a1235b3e | 305 | tty = tty_kref_get(current->signal->tty); |
c8bcd9c5 JH |
306 | spin_unlock_irq(¤t->sighand->siglock); |
307 | ||
a1235b3e NP |
308 | if (tty) { |
309 | unsigned long flags; | |
c8bcd9c5 JH |
310 | |
311 | tty_lock(tty); | |
a1235b3e NP |
312 | spin_lock_irqsave(&tty->ctrl_lock, flags); |
313 | put_pid(tty->session); | |
314 | put_pid(tty->pgrp); | |
315 | tty->session = NULL; | |
316 | tty->pgrp = NULL; | |
317 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | |
c8bcd9c5 | 318 | tty_unlock(tty); |
a1235b3e NP |
319 | tty_kref_put(tty); |
320 | } | |
321 | ||
a1235b3e NP |
322 | /* Now clear signal->tty under the lock */ |
323 | read_lock(&tasklist_lock); | |
324 | session_clear_tty(task_session(current)); | |
325 | read_unlock(&tasklist_lock); | |
326 | } | |
327 | ||
3adf2aa8 | 328 | /* |
a1235b3e NP |
329 | * |
330 | * no_tty - Ensure the current process does not have a controlling tty | |
331 | */ | |
332 | void no_tty(void) | |
333 | { | |
63eeafd4 XT |
334 | /* |
335 | * FIXME: Review locking here. The tty_lock never covered any race | |
336 | * between a new association and proc_clear_tty but possibly we need | |
337 | * to protect against this anyway. | |
338 | */ | |
a1235b3e | 339 | struct task_struct *tsk = current; |
d4e1d903 | 340 | |
a1235b3e NP |
341 | disassociate_ctty(0); |
342 | proc_clear_tty(tsk); | |
343 | } | |
344 | ||
345 | /** | |
346 | * tiocsctty - set controlling tty | |
347 | * @tty: tty structure | |
bc38fe24 | 348 | * @file: file structure used to check permissions |
a1235b3e NP |
349 | * @arg: user argument |
350 | * | |
351 | * This ioctl is used to manage job control. It permits a session | |
352 | * leader to set this tty as the controlling tty for the session. | |
353 | * | |
354 | * Locking: | |
355 | * Takes tty_lock() to serialize proc_set_tty() for this tty | |
356 | * Takes tasklist_lock internally to walk sessions | |
357 | * Takes ->siglock() when updating signal->tty | |
358 | */ | |
359 | static int tiocsctty(struct tty_struct *tty, struct file *file, int arg) | |
360 | { | |
361 | int ret = 0; | |
362 | ||
363 | tty_lock(tty); | |
364 | read_lock(&tasklist_lock); | |
365 | ||
366 | if (current->signal->leader && (task_session(current) == tty->session)) | |
367 | goto unlock; | |
368 | ||
369 | /* | |
370 | * The process must be a session leader and | |
371 | * not have a controlling tty already. | |
372 | */ | |
373 | if (!current->signal->leader || current->signal->tty) { | |
374 | ret = -EPERM; | |
375 | goto unlock; | |
376 | } | |
377 | ||
378 | if (tty->session) { | |
379 | /* | |
380 | * This tty is already the controlling | |
381 | * tty for another session group! | |
382 | */ | |
383 | if (arg == 1 && capable(CAP_SYS_ADMIN)) { | |
384 | /* | |
385 | * Steal it away | |
386 | */ | |
387 | session_clear_tty(tty->session); | |
388 | } else { | |
389 | ret = -EPERM; | |
390 | goto unlock; | |
391 | } | |
392 | } | |
393 | ||
394 | /* See the comment in tty_open_proc_set_tty(). */ | |
395 | if ((file->f_mode & FMODE_READ) == 0 && !capable(CAP_SYS_ADMIN)) { | |
396 | ret = -EPERM; | |
397 | goto unlock; | |
398 | } | |
399 | ||
400 | proc_set_tty(tty); | |
401 | unlock: | |
402 | read_unlock(&tasklist_lock); | |
403 | tty_unlock(tty); | |
404 | return ret; | |
405 | } | |
406 | ||
407 | /** | |
408 | * tty_get_pgrp - return a ref counted pgrp pid | |
409 | * @tty: tty to read | |
410 | * | |
411 | * Returns a refcounted instance of the pid struct for the process | |
412 | * group controlling the tty. | |
413 | */ | |
414 | struct pid *tty_get_pgrp(struct tty_struct *tty) | |
415 | { | |
416 | unsigned long flags; | |
417 | struct pid *pgrp; | |
418 | ||
419 | spin_lock_irqsave(&tty->ctrl_lock, flags); | |
420 | pgrp = get_pid(tty->pgrp); | |
421 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | |
422 | ||
423 | return pgrp; | |
424 | } | |
425 | EXPORT_SYMBOL_GPL(tty_get_pgrp); | |
426 | ||
427 | /* | |
428 | * This checks not only the pgrp, but falls back on the pid if no | |
429 | * satisfactory pgrp is found. I dunno - gdb doesn't work correctly | |
430 | * without this... | |
431 | * | |
432 | * The caller must hold rcu lock or the tasklist lock. | |
433 | */ | |
434 | static struct pid *session_of_pgrp(struct pid *pgrp) | |
435 | { | |
436 | struct task_struct *p; | |
437 | struct pid *sid = NULL; | |
438 | ||
439 | p = pid_task(pgrp, PIDTYPE_PGID); | |
440 | if (p == NULL) | |
441 | p = pid_task(pgrp, PIDTYPE_PID); | |
442 | if (p != NULL) | |
443 | sid = task_session(p); | |
444 | ||
445 | return sid; | |
446 | } | |
447 | ||
448 | /** | |
449 | * tiocgpgrp - get process group | |
450 | * @tty: tty passed by user | |
451 | * @real_tty: tty side of the tty passed by the user if a pty else the tty | |
452 | * @p: returned pid | |
453 | * | |
454 | * Obtain the process group of the tty. If there is no process group | |
455 | * return an error. | |
456 | * | |
457 | * Locking: none. Reference to current->signal->tty is safe. | |
458 | */ | |
459 | static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) | |
460 | { | |
461 | struct pid *pid; | |
462 | int ret; | |
463 | /* | |
464 | * (tty == real_tty) is a cheap way of | |
465 | * testing if the tty is NOT a master pty. | |
466 | */ | |
467 | if (tty == real_tty && current->signal->tty != real_tty) | |
468 | return -ENOTTY; | |
469 | pid = tty_get_pgrp(real_tty); | |
470 | ret = put_user(pid_vnr(pid), p); | |
471 | put_pid(pid); | |
472 | return ret; | |
473 | } | |
474 | ||
475 | /** | |
476 | * tiocspgrp - attempt to set process group | |
477 | * @tty: tty passed by user | |
478 | * @real_tty: tty side device matching tty passed by user | |
479 | * @p: pid pointer | |
480 | * | |
481 | * Set the process group of the tty to the session passed. Only | |
482 | * permitted where the tty session is our session. | |
483 | * | |
484 | * Locking: RCU, ctrl lock | |
485 | */ | |
486 | static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) | |
487 | { | |
488 | struct pid *pgrp; | |
489 | pid_t pgrp_nr; | |
490 | int retval = tty_check_change(real_tty); | |
491 | ||
492 | if (retval == -EIO) | |
493 | return -ENOTTY; | |
494 | if (retval) | |
495 | return retval; | |
c8bcd9c5 | 496 | |
a1235b3e NP |
497 | if (get_user(pgrp_nr, p)) |
498 | return -EFAULT; | |
499 | if (pgrp_nr < 0) | |
500 | return -EINVAL; | |
c8bcd9c5 JH |
501 | |
502 | spin_lock_irq(&real_tty->ctrl_lock); | |
503 | if (!current->signal->tty || | |
504 | (current->signal->tty != real_tty) || | |
505 | (real_tty->session != task_session(current))) { | |
506 | retval = -ENOTTY; | |
507 | goto out_unlock_ctrl; | |
508 | } | |
a1235b3e NP |
509 | rcu_read_lock(); |
510 | pgrp = find_vpid(pgrp_nr); | |
511 | retval = -ESRCH; | |
512 | if (!pgrp) | |
513 | goto out_unlock; | |
514 | retval = -EPERM; | |
515 | if (session_of_pgrp(pgrp) != task_session(current)) | |
516 | goto out_unlock; | |
517 | retval = 0; | |
a1235b3e NP |
518 | put_pid(real_tty->pgrp); |
519 | real_tty->pgrp = get_pid(pgrp); | |
a1235b3e NP |
520 | out_unlock: |
521 | rcu_read_unlock(); | |
c8bcd9c5 JH |
522 | out_unlock_ctrl: |
523 | spin_unlock_irq(&real_tty->ctrl_lock); | |
a1235b3e NP |
524 | return retval; |
525 | } | |
526 | ||
527 | /** | |
528 | * tiocgsid - get session id | |
529 | * @tty: tty passed by user | |
530 | * @real_tty: tty side of the tty passed by the user if a pty else the tty | |
531 | * @p: pointer to returned session id | |
532 | * | |
533 | * Obtain the session id of the tty. If there is no session | |
534 | * return an error. | |
a1235b3e NP |
535 | */ |
536 | static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) | |
537 | { | |
c8bcd9c5 JH |
538 | unsigned long flags; |
539 | pid_t sid; | |
540 | ||
a1235b3e NP |
541 | /* |
542 | * (tty == real_tty) is a cheap way of | |
543 | * testing if the tty is NOT a master pty. | |
63eeafd4 | 544 | */ |
a1235b3e NP |
545 | if (tty == real_tty && current->signal->tty != real_tty) |
546 | return -ENOTTY; | |
c8bcd9c5 JH |
547 | |
548 | spin_lock_irqsave(&real_tty->ctrl_lock, flags); | |
a1235b3e | 549 | if (!real_tty->session) |
c8bcd9c5 JH |
550 | goto err; |
551 | sid = pid_vnr(real_tty->session); | |
552 | spin_unlock_irqrestore(&real_tty->ctrl_lock, flags); | |
553 | ||
554 | return put_user(sid, p); | |
555 | ||
556 | err: | |
557 | spin_unlock_irqrestore(&real_tty->ctrl_lock, flags); | |
558 | return -ENOTTY; | |
a1235b3e NP |
559 | } |
560 | ||
561 | /* | |
562 | * Called from tty_ioctl(). If tty is a pty then real_tty is the slave side, | |
563 | * if not then tty == real_tty. | |
564 | */ | |
565 | long tty_jobctrl_ioctl(struct tty_struct *tty, struct tty_struct *real_tty, | |
566 | struct file *file, unsigned int cmd, unsigned long arg) | |
567 | { | |
568 | void __user *p = (void __user *)arg; | |
569 | ||
570 | switch (cmd) { | |
571 | case TIOCNOTTY: | |
572 | if (current->signal->tty != tty) | |
573 | return -ENOTTY; | |
574 | no_tty(); | |
575 | return 0; | |
576 | case TIOCSCTTY: | |
577 | return tiocsctty(real_tty, file, arg); | |
578 | case TIOCGPGRP: | |
579 | return tiocgpgrp(tty, real_tty, p); | |
580 | case TIOCSPGRP: | |
581 | return tiocspgrp(tty, real_tty, p); | |
582 | case TIOCGSID: | |
583 | return tiocgsid(tty, real_tty, p); | |
584 | } | |
585 | return -ENOIOCTLCMD; | |
586 | } |