chan_user.c revision b16895b63c504698b0c3ab26ca3c41a4fa162a42
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Licensed under the GPL
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <unistd.h>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <stdlib.h>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <errno.h>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <termios.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <string.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <signal.h>
121d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike#include <sched.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sys/stat.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sys/ioctl.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sys/socket.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "kern_util.h"
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "user_util.h"
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "chan_user.h"
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "user.h"
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "os.h"
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "choose-mode.h"
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "mode.h"
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2455c033c1f6cdedc350c79c3198b542e3ab496899Paolo 'Blaisorblade' Giarrussoint generic_console_write(int fd, const char *buf, int n)
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct termios save, new;
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(isatty(fd)){
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CATCH_EINTR(err = tcgetattr(fd, &save));
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err)
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new = save;
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The terminal becomes a bit less raw, to handle \n also as
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * "Carriage Return", not only as "New Line". Otherwise, the new
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * line won't start at the first column.*/
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new.c_oflag |= OPOST;
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &new));
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err)
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = generic_write(fd, buf, n, NULL);
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore raw mode, in any case; we *must* ignore any error apart
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * EINTR, except for debug.*/
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(isatty(fd))
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CATCH_EINTR(tcsetattr(fd, TCSAFLUSH, &save));
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(err);
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror:
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(-errno);
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * UML SIGWINCH handling
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The point of this is to handle SIGWINCH on consoles which have host ttys and
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * relay them inside UML to whatever might be running on the console and cares
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * about the window size (since SIGWINCH notifies about terminal size changes).
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * So, we have a separate thread for each host tty attached to a UML device
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (side-issue - I'm annoyed that one thread can't have multiple controlling
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ttys for purposed of handling SIGWINCH, but I imagine there are other reasons
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that doesn't make any sense).
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SIGWINCH can't be received synchronously, so you have to set up to receive it
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as a signal.  That being the case, if you are going to wait for it, it is
66ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser * convenient to sit in sigsuspend() and wait for the signal to bounce you out of
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it (see below for how we make sure to exit only on SIGWINCH).
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void winch_handler(int sig)
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct winch_data {
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pty_fd;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pipe_fd;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int winch_thread(void *arg)
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct winch_data *data = arg;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigset_t sigs;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pty_fd, pipe_fd;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count, err;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c = 1;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pty_fd = data->pty_fd;
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pipe_fd = data->pipe_fd;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = os_write_file(pipe_fd, &c, sizeof(c));
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(count != sizeof(c))
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_thread : failed to write synchronization "
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "byte, err = %d\n", -count);
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We are not using SIG_IGN on purpose, so don't fix it as I thought to
95ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser	 * do! If using SIG_IGN, the sigsuspend() call below would not stop on
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SIGWINCH. */
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	signal(SIGWINCH, winch_handler);
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigfillset(&sigs);
100ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser	/* Block all signals possible. */
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_thread : sigprocmask failed, errno = %d\n",
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       errno);
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		exit(1);
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
106ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser	/* In sigsuspend(), block anything else than SIGWINCH. */
107ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser	sigdelset(&sigs, SIGWINCH);
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(setsid() < 0){
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_thread : setsid failed, errno = %d\n", errno);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		exit(1);
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = os_new_tty_pgrp(pty_fd, os_getpid());
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(err < 0){
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err);
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		exit(1);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* These are synchronization calls between various UML threads on the
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * host - since they are not different kernel threads, we cannot use
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * kernel semaphores. We don't use SysV semaphores because they are
12303a67a46af8647b2c7825107045ecae641e103d3Jan Engelhardt	 * persistent. */
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = os_read_file(pipe_fd, &c, sizeof(c));
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(count != sizeof(c))
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_thread : failed to read synchronization byte, "
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "err = %d\n", -count);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while(1){
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* This will be interrupted by SIGWINCH only, since other signals
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * are blocked.*/
132ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser		sigsuspend(&sigs);
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		count = os_write_file(pipe_fd, &c, sizeof(c));
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(count != sizeof(c))
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("winch_thread : write failed, err = %d\n",
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       -count);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int winch_tramp(int fd, struct tty_struct *tty, int *fd_out)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct winch_data data;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long stack;
1451f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	int fds[2], n, err;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = os_pipe(fds, 1, 1);
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(err < 0){
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_tramp : os_pipe failed, err = %d\n", -err);
1511f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike		goto out;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = ((struct winch_data) { .pty_fd 		= fd,
1551d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike				      .pipe_fd 		= fds[1] } );
1561d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike	/* CLONE_FILES so this thread doesn't hold open files which are open
1571d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike	 * now, but later closed.  This is a problem with /dev/net/tun.
1581d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike	 */
1591d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike	err = run_helper_thread(winch_thread, &data, CLONE_FILES, &stack, 0);
1601f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	if(err < 0){
161b16895b63c504698b0c3ab26ca3c41a4fa162a42Andrew Morton		printk("fork of winch_thread failed - errno = %d\n", -err);
1621f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike		goto out_close;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*fd_out = fds[0];
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	n = os_read_file(fds[0], &c, sizeof(c));
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(n != sizeof(c)){
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_tramp : failed to read synchronization byte\n");
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("read failed, err = %d\n", -n);
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("fd %d will not support SIGWINCH\n", fd);
1711f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike                err = -EINVAL;
1721d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike		goto out_close;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1741f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	return err ;
1751f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike
1761f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike out_close:
1771f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	os_close_file(fds[1]);
1781f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	os_close_file(fds[0]);
1791f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike out:
1801f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	return err;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid register_winch(int fd, struct tty_struct *tty)
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1851f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	int pid, thread, thread_fd = -1;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c = 1;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(!isatty(fd))
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pid = tcgetpgrp(fd);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd,
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     tty) && (pid == -1)){
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		thread = winch_tramp(fd, tty, &thread_fd);
196da00d9a5466558ccd9e7b7d04b13d7cb9160c876Jeff Dike		if(thread > 0){
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			register_winch_irq(thread_fd, fd, thread, tty);
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			count = os_write_file(thread_fd, &c, sizeof(c));
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(count != sizeof(c))
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("register_winch : failed to write "
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       "synchronization byte, err = %d\n",
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					-count);
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Overrides for Emacs so that we follow Linus's tabbing style.
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Emacs will notice this stuff at the end of the file and automatically
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * adjust the settings for this buffer only.  This must remain at the end
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the file.
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ---------------------------------------------------------------------------
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Local variables:
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * c-file-style: "linux"
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * End:
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
218