fb: epson1355fb: kill off dead sh support
[safe/jmp/linux-2.6] / drivers / char / tty_io.c
index 65672c5..de37ebc 100644 (file)
@@ -141,8 +141,6 @@ static DECLARE_MUTEX(allocated_ptys_lock);
 static int ptmx_open(struct inode *, struct file *);
 #endif
 
-extern void disable_early_printk(void);
-
 static void initialize_tty_struct(struct tty_struct *tty);
 
 static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
@@ -153,10 +151,16 @@ static int tty_open(struct inode *, struct file *);
 static int tty_release(struct inode *, struct file *);
 int tty_ioctl(struct inode * inode, struct file * file,
              unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file * file, unsigned int cmd,
+                               unsigned long arg);
+#else
+#define tty_compat_ioctl NULL
+#endif
 static int tty_fasync(int fd, struct file * filp, int on);
 static void release_tty(struct tty_struct *tty, int idx);
-static struct pid *__proc_set_tty(struct task_struct *tsk,
-                               struct tty_struct *tty);
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
 
 /**
  *     alloc_tty_struct        -       allocate a tty object
@@ -365,6 +369,29 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
 }
 
 /**
+ *     tty_buffer_flush                -       flush full tty buffers
+ *     @tty: tty to flush
+ *
+ *     flush all the buffers containing receive data
+ *
+ *     Locking: none
+ */
+
+static void tty_buffer_flush(struct tty_struct *tty)
+{
+       struct tty_buffer *thead;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       while((thead = tty->buf.head) != NULL) {
+               tty->buf.head = thead->next;
+               tty_buffer_free(tty, thead);
+       }
+       tty->buf.tail = NULL;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+}
+
+/**
  *     tty_buffer_find         -       find a free tty buffer
  *     @tty: tty owning the buffer
  *     @size: characters wanted
@@ -936,13 +963,6 @@ restart:
                return -EINVAL;
 
        /*
-        *      No more input please, we are switching. The new ldisc
-        *      will update this value in the ldisc open function
-        */
-
-       tty->receive_room = 0;
-
-       /*
         *      Problem: What do we do if this blocks ?
         */
 
@@ -953,6 +973,13 @@ restart:
                return 0;
        }
 
+       /*
+        *      No more input please, we are switching. The new ldisc
+        *      will update this value in the ldisc open function
+        */
+
+       tty->receive_room = 0;
+
        o_ldisc = tty->ldisc;
        o_tty = tty->link;
 
@@ -1121,7 +1148,8 @@ int tty_check_change(struct tty_struct * tty)
                return 0;
        if (is_current_pgrp_orphaned())
                return -EIO;
-       (void) kill_pgrp(task_pgrp(current), SIGTTOU, 1);
+       kill_pgrp(task_pgrp(current), SIGTTOU, 1);
+       set_thread_flag(TIF_SIGPENDING);
        return -ERESTARTSYS;
 }
 
@@ -1151,12 +1179,19 @@ static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
        return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
 }
 
+static long hung_up_tty_compat_ioctl(struct file * file,
+                                    unsigned int cmd, unsigned long arg)
+{
+       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
+}
+
 static const struct file_operations tty_fops = {
        .llseek         = no_llseek,
        .read           = tty_read,
        .write          = tty_write,
        .poll           = tty_poll,
        .ioctl          = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
        .open           = tty_open,
        .release        = tty_release,
        .fasync         = tty_fasync,
@@ -1169,6 +1204,7 @@ static const struct file_operations ptmx_fops = {
        .write          = tty_write,
        .poll           = tty_poll,
        .ioctl          = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
        .open           = ptmx_open,
        .release        = tty_release,
        .fasync         = tty_fasync,
@@ -1181,6 +1217,7 @@ static const struct file_operations console_fops = {
        .write          = redirected_tty_write,
        .poll           = tty_poll,
        .ioctl          = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
        .open           = tty_open,
        .release        = tty_release,
        .fasync         = tty_fasync,
@@ -1192,6 +1229,7 @@ static const struct file_operations hung_up_tty_fops = {
        .write          = hung_up_tty_write,
        .poll           = hung_up_tty_poll,
        .ioctl          = hung_up_tty_ioctl,
+       .compat_ioctl   = hung_up_tty_compat_ioctl,
        .release        = tty_release,
 };
 
@@ -1240,6 +1278,7 @@ void tty_ldisc_flush(struct tty_struct *tty)
                        ld->flush_buffer(tty);
                tty_ldisc_deref(ld);
        }
+       tty_buffer_flush(tty);
 }
 
 EXPORT_SYMBOL_GPL(tty_ldisc_flush);
@@ -1376,6 +1415,8 @@ static void do_tty_hangup(struct work_struct *work)
        read_unlock(&tasklist_lock);
 
        tty->flags = 0;
+       put_pid(tty->session);
+       put_pid(tty->pgrp);
        tty->session = NULL;
        tty->pgrp = NULL;
        tty->ctrl_status = 0;
@@ -1462,6 +1503,15 @@ int tty_hung_up_p(struct file * filp)
 
 EXPORT_SYMBOL(tty_hung_up_p);
 
+/**
+ * is_tty      -       checker whether file is a TTY
+ */
+int is_tty(struct file *filp)
+{
+       return filp->f_op->read == tty_read
+               || filp->f_op->read == hung_up_tty_read;
+}
+
 static void session_clear_tty(struct pid *session)
 {
        struct task_struct *p;
@@ -1532,10 +1582,9 @@ void disassociate_ctty(int on_exit)
        }
 
        spin_lock_irq(&current->sighand->siglock);
-       tty_pgrp = current->signal->tty_old_pgrp;
-       current->signal->tty_old_pgrp = 0;
+       put_pid(current->signal->tty_old_pgrp);
+       current->signal->tty_old_pgrp = NULL;
        spin_unlock_irq(&current->sighand->siglock);
-       put_pid(tty_pgrp);
 
        mutex_lock(&tty_mutex);
        /* It is possible that do_tty_hangup has free'd this tty */
@@ -1560,13 +1609,25 @@ void disassociate_ctty(int on_exit)
        unlock_kernel();
 }
 
+/**
+ *
+ *     no_tty  - Ensure the current process does not have a controlling tty
+ */
+void no_tty(void)
+{
+       struct task_struct *tsk = current;
+       if (tsk->signal->leader)
+               disassociate_ctty(0);
+       proc_clear_tty(tsk);
+}
+
 
 /**
- *     stop_tty        -       propogate flow control
+ *     stop_tty        -       propagate flow control
  *     @tty: tty to stop
  *
  *     Perform flow control to the driver. For PTY/TTY pairs we
- *     must also propogate the TIOCKPKT status. May be called
+ *     must also propagate the TIOCKPKT status. May be called
  *     on an already stopped device and will not re-call the driver
  *     method.
  *
@@ -1596,11 +1657,11 @@ void stop_tty(struct tty_struct *tty)
 EXPORT_SYMBOL(stop_tty);
 
 /**
- *     start_tty       -       propogate flow control
+ *     start_tty       -       propagate flow control
  *     @tty: tty to start
  *
  *     Start a tty that has been stopped if at all possible. Perform
- *     any neccessary wakeups and propogate the TIOCPKT status. If this
+ *     any neccessary wakeups and propagate the TIOCPKT status. If this
  *     is the tty was previous stopped and is being started then the
  *     driver start method is invoked and the line discipline woken.
  *
@@ -1674,6 +1735,23 @@ static ssize_t tty_read(struct file * file, char __user * buf, size_t count,
        return i;
 }
 
+void tty_write_unlock(struct tty_struct *tty)
+{
+       mutex_unlock(&tty->atomic_write_lock);
+       wake_up_interruptible(&tty->write_wait);
+}
+
+int tty_write_lock(struct tty_struct *tty, int ndelay)
+{
+       if (!mutex_trylock(&tty->atomic_write_lock)) {
+               if (ndelay)
+                       return -EAGAIN;
+               if (mutex_lock_interruptible(&tty->atomic_write_lock))
+                       return -ERESTARTSYS;
+       }
+       return 0;
+}
+
 /*
  * Split writes up in sane blocksizes to avoid
  * denial-of-service type attacks
@@ -1685,13 +1763,12 @@ static inline ssize_t do_tty_write(
        const char __user *buf,
        size_t count)
 {
-       ssize_t ret = 0, written = 0;
+       ssize_t ret, written = 0;
        unsigned int chunk;
        
-       /* FIXME: O_NDELAY ... */
-       if (mutex_lock_interruptible(&tty->atomic_write_lock)) {
-               return -ERESTARTSYS;
-       }
+       ret = tty_write_lock(tty, file->f_flags & O_NDELAY);
+       if (ret < 0)
+               return ret;
 
        /*
         * We chunk up writes into a temporary buffer. This
@@ -1724,8 +1801,8 @@ static inline ssize_t do_tty_write(
 
                buf = kmalloc(chunk, GFP_KERNEL);
                if (!buf) {
-                       mutex_unlock(&tty->atomic_write_lock);
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto out;
                }
                kfree(tty->write_buf);
                tty->write_cnt = chunk;
@@ -1760,7 +1837,8 @@ static inline ssize_t do_tty_write(
                inode->i_mtime = current_fs_time(inode->i_sb);
                ret = written;
        }
-       mutex_unlock(&tty->atomic_write_lock);
+out:
+       tty_write_unlock(tty);
        return ret;
 }
 
@@ -1901,6 +1979,20 @@ static int init_dev(struct tty_driver *driver, int idx,
        /* check whether we're reopening an existing tty */
        if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
                tty = devpts_get_tty(idx);
+               /*
+                * If we don't have a tty here on a slave open, it's because
+                * the master already started the close process and there's
+                * no relation between devpts file and tty anymore.
+                */
+               if (!tty && driver->subtype == PTY_TYPE_SLAVE) {
+                       retval = -EIO;
+                       goto end_init;
+               }
+               /*
+                * It's safe from now on because init_dev() is called with
+                * tty_mutex held and release_dev() won't change tty->count
+                * or tty->flags without having to grab tty_mutex
+                */
                if (tty && driver->subtype == PTY_TYPE_MASTER)
                        tty = tty->link;
        } else {
@@ -1950,11 +2042,9 @@ static int init_dev(struct tty_driver *driver, int idx,
        }
 
        if (!*ltp_loc) {
-               ltp = (struct ktermios *) kmalloc(sizeof(struct ktermios),
-                                                GFP_KERNEL);
+               ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
                if (!ltp)
                        goto free_mem_out;
-               memset(ltp, 0, sizeof(struct ktermios));
        }
 
        if (driver->type == TTY_DRIVER_TYPE_PTY) {
@@ -1983,11 +2073,9 @@ static int init_dev(struct tty_driver *driver, int idx,
                }
 
                if (!*o_ltp_loc) {
-                       o_ltp = (struct ktermios *)
-                               kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+                       o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
                        if (!o_ltp)
                                goto free_mem_out;
-                       memset(o_ltp, 0, sizeof(struct ktermios));
                }
 
                /*
@@ -2492,7 +2580,6 @@ static int tty_open(struct inode * inode, struct file * filp)
        int index;
        dev_t device = inode->i_rdev;
        unsigned short saved_flags = filp->f_flags;
-       struct pid *old_pgrp;
 
        nonseekable_open(inode, filp);
        
@@ -2586,17 +2673,16 @@ got_driver:
                goto retry_open;
        }
 
-       old_pgrp = NULL;
        mutex_lock(&tty_mutex);
        spin_lock_irq(&current->sighand->siglock);
        if (!noctty &&
            current->signal->leader &&
            !current->signal->tty &&
            tty->session == NULL)
-               old_pgrp = __proc_set_tty(current, tty);
+               __proc_set_tty(current, tty);
        spin_unlock_irq(&current->sighand->siglock);
        mutex_unlock(&tty_mutex);
-       put_pid(old_pgrp);
+       tty_audit_opening();
        return 0;
 }
 
@@ -2659,8 +2745,10 @@ static int ptmx_open(struct inode * inode, struct file * filp)
 
        check_tty_count(tty, "tty_open");
        retval = ptm_driver->open(tty, filp);
-       if (!retval)
+       if (!retval) {
+               tty_audit_opening();
                return 0;
+       }
 out1:
        release_dev(filp);
        return retval;
@@ -3100,14 +3188,13 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
 
 static int send_break(struct tty_struct *tty, unsigned int duration)
 {
-       if (mutex_lock_interruptible(&tty->atomic_write_lock))
+       if (tty_write_lock(tty, 0) < 0)
                return -EINTR;
        tty->driver->break_ctl(tty, -1);
-       if (!signal_pending(current)) {
+       if (!signal_pending(current))
                msleep_interruptible(duration);
-       }
        tty->driver->break_ctl(tty, 0);
-       mutex_unlock(&tty->atomic_write_lock);
+       tty_write_unlock(tty);
        if (signal_pending(current))
                return -EINTR;
        return 0;
@@ -3271,9 +3358,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
                case TIOCNOTTY:
                        if (current->signal->tty != tty)
                                return -ENOTTY;
-                       if (current->signal->leader)
-                               disassociate_ctty(0);
-                       proc_clear_tty(current);
+                       no_tty();
                        return 0;
                case TIOCSCTTY:
                        return tiocsctty(tty, arg);
@@ -3320,6 +3405,15 @@ int tty_ioctl(struct inode * inode, struct file * file,
                case TIOCMBIC:
                case TIOCMBIS:
                        return tty_tiocmset(tty, file, cmd, p);
+               case TCFLSH:
+                       switch (arg) {
+                       case TCIFLUSH:
+                       case TCIOFLUSH:
+                               /* flush tty buffer and allow ldisc to process ioctl */
+                               tty_buffer_flush(tty);
+                               break;
+                       }
+                       break;
        }
        if (tty->driver->ioctl) {
                retval = (tty->driver->ioctl)(tty, file, cmd, arg);
@@ -3337,6 +3431,32 @@ int tty_ioctl(struct inode * inode, struct file * file,
        return retval;
 }
 
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file * file, unsigned int cmd,
+                               unsigned long arg)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct tty_struct *tty = file->private_data;
+       struct tty_ldisc *ld;
+       int retval = -ENOIOCTLCMD;
+
+       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+               return -EINVAL;
+
+       if (tty->driver->compat_ioctl) {
+               retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg);
+               if (retval != -ENOIOCTLCMD)
+                       return retval;
+       }
+
+       ld = tty_ldisc_ref_wait(tty);
+       if (ld->compat_ioctl)
+               retval = ld->compat_ioctl(tty, file, cmd, arg);
+       tty_ldisc_deref(ld);
+
+       return retval;
+}
+#endif
 
 /*
  * This implements the "Secure Attention Key" ---  the idea is to
@@ -3442,7 +3562,6 @@ void do_SAK(struct tty_struct *tty)
 {
        if (!tty)
                return;
-       PREPARE_WORK(&tty->SAK_work, do_SAK_work);
        schedule_work(&tty->SAK_work);
 }
 
@@ -3568,7 +3687,7 @@ static void initialize_tty_struct(struct tty_struct *tty)
        mutex_init(&tty->atomic_write_lock);
        spin_lock_init(&tty->read_lock);
        INIT_LIST_HEAD(&tty->tty_files);
-       INIT_WORK(&tty->SAK_work, NULL);
+       INIT_WORK(&tty->SAK_work, do_SAK_work);
 }
 
 /*
@@ -3644,9 +3763,8 @@ struct tty_driver *alloc_tty_driver(int lines)
 {
        struct tty_driver *driver;
 
-       driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL);
+       driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
        if (driver) {
-               memset(driver, 0, sizeof(struct tty_driver));
                driver->magic = TTY_DRIVER_MAGIC;
                driver->num = lines;
                /* later we'll move allocation of tables here */
@@ -3670,6 +3788,7 @@ void tty_set_operations(struct tty_driver *driver,
        driver->write_room = op->write_room;
        driver->chars_in_buffer = op->chars_in_buffer;
        driver->ioctl = op->ioctl;
+       driver->compat_ioctl = op->compat_ioctl;
        driver->set_termios = op->set_termios;
        driver->throttle = op->throttle;
        driver->unthrottle = op->unthrottle;
@@ -3705,24 +3824,22 @@ int tty_register_driver(struct tty_driver *driver)
        if (driver->flags & TTY_DRIVER_INSTALLED)
                return 0;
 
-       if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
-               p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
+       if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
+               p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
                if (!p)
                        return -ENOMEM;
-               memset(p, 0, driver->num * 3 * sizeof(void *));
        }
 
        if (!driver->major) {
                error = alloc_chrdev_region(&dev, driver->minor_start, driver->num,
-                                               (char*)driver->name);
+                                               driver->name);
                if (!error) {
                        driver->major = MAJOR(dev);
                        driver->minor_start = MINOR(dev);
                }
        } else {
                dev = MKDEV(driver->major, driver->minor_start);
-               error = register_chrdev_region(dev, driver->num,
-                                               (char*)driver->name);
+               error = register_chrdev_region(dev, driver->num, driver->name);
        }
        if (error < 0) {
                kfree(p);
@@ -3753,7 +3870,9 @@ int tty_register_driver(struct tty_driver *driver)
        if (!driver->put_char)
                driver->put_char = tty_default_put_char;
        
+       mutex_lock(&tty_mutex);
        list_add(&driver->tty_drivers, &tty_drivers);
+       mutex_unlock(&tty_mutex);
        
        if ( !(driver->flags & TTY_DRIVER_DYNAMIC_DEV) ) {
                for(i = 0; i < driver->num; i++)
@@ -3779,8 +3898,9 @@ int tty_unregister_driver(struct tty_driver *driver)
 
        unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
                                driver->num);
-
+       mutex_lock(&tty_mutex);
        list_del(&driver->tty_drivers);
+       mutex_unlock(&tty_mutex);
 
        /*
         * Free the termios and termios_locked structures because
@@ -3825,28 +3945,25 @@ void proc_clear_tty(struct task_struct *p)
 }
 EXPORT_SYMBOL(proc_clear_tty);
 
-static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
 {
-       struct pid *old_pgrp;
        if (tty) {
+               /* We should not have a session or pgrp to here but.... */
+               put_pid(tty->session);
+               put_pid(tty->pgrp);
                tty->session = get_pid(task_session(tsk));
                tty->pgrp = get_pid(task_pgrp(tsk));
        }
-       old_pgrp = tsk->signal->tty_old_pgrp;
+       put_pid(tsk->signal->tty_old_pgrp);
        tsk->signal->tty = tty;
        tsk->signal->tty_old_pgrp = NULL;
-       return old_pgrp;
 }
 
-void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
 {
-       struct pid *old_pgrp;
-
        spin_lock_irq(&tsk->sighand->siglock);
-       old_pgrp = __proc_set_tty(tsk, tty);
+       __proc_set_tty(tsk, tty);
        spin_unlock_irq(&tsk->sighand->siglock);
-
-       put_pid(old_pgrp);
 }
 
 struct tty_struct *get_current_tty(void)
@@ -3881,9 +3998,6 @@ void __init console_init(void)
         * set up the console device so that later boot sequences can 
         * inform about problems etc..
         */
-#ifdef CONFIG_EARLY_PRINTK
-       disable_early_printk();
-#endif
        call = __con_initcall_start;
        while (call < __con_initcall_end) {
                (*call)();