#include <asm/uaccess.h>
#include <asm/system.h>
-#include <linux/bitops.h>
+#include <asm/bitops.h>
#include <linux/devpts_fs.h>
/* These are global because they are accessed in tty_io.c */
if (!tty->link)
return;
tty->link->packet = 0;
- set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
wake_up_interruptible(&tty->link->read_wait);
wake_up_interruptible(&tty->link->write_wait);
+ set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
if (tty->driver->subtype == PTY_TYPE_MASTER) {
set_bit(TTY_OTHER_CLOSED, &tty->flags);
#ifdef CONFIG_UNIX98_PTYS
* not our partners. We can't just take the other one blindly without
* risking deadlocks. There is also the small matter of TTY_DONT_FLIP
*/
-static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count)
+static int pty_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
{
struct tty_struct *to = tty->link;
- int c;
+ int c=0, n, room;
+ char *temp_buffer;
if (!to || tty->stopped)
return 0;
- c = to->ldisc.receive_room(to);
- if (c > count)
- c = count;
- to->ldisc.receive_buf(to, buf, NULL, c);
+ if (from_user) {
+ down(&tty->flip.pty_sem);
+ temp_buffer = &tty->flip.char_buf[0];
+ while (count > 0) {
+ /* check space so we don't copy needlessly */
+ n = to->ldisc.receive_room(to);
+ if (n > count)
+ n = count;
+ if (!n) break;
+
+ n = min(n, PTY_BUF_SIZE);
+ n -= copy_from_user(temp_buffer, buf, n);
+ if (!n) {
+ if (!c)
+ c = -EFAULT;
+ break;
+ }
+
+ /* check again in case the buffer filled up */
+ room = to->ldisc.receive_room(to);
+ if (n > room)
+ n = room;
+ if (!n) break;
+ buf += n;
+ c += n;
+ count -= n;
+ to->ldisc.receive_buf(to, temp_buffer, NULL, n);
+ }
+ up(&tty->flip.pty_sem);
+ } else {
+ c = to->ldisc.receive_room(to);
+ if (c > count)
+ c = count;
+ to->ldisc.receive_buf(to, buf, NULL, c);
+ }
return c;
}