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