title: How does xv6 write to the terminal?
body: <p>The <code>printf</code> function calls <code>write</code> (re. <a href="https://github.com/mit-pdos/xv6-public/blob/master/forktest.c" rel="nofollow noreferrer">forktest.c</a>):</p>
  
  <pre><code>void printf ( int fd, char *s, ... )
  {
      write( fd, s, strlen(s) );
  }
  </code></pre>
  
  <p>Passing <code>1</code> as the <code>fd</code> writes to the console (as <code>1</code> maps to stdout). But where is <code>write</code> defined? I only see its declaration in <a href="https://github.com/mit-pdos/xv6-public/blob/master/user.h" rel="nofollow noreferrer">user.h</a>.</p>
  
  <pre><code>int write ( int, void*, int );
  </code></pre>
  
  <p>I'm assuming it somehow gets redirected to <code>filewrite</code> in <a href="https://github.com/mit-pdos/xv6-public/blob/master/file.c" rel="nofollow noreferrer">file.c</a>.</p>
  
  <pre><code>int filewrite (struct file *f, char *addr, int n )
  {
      int r;
  
        if ( f-&gt;writable == 0 )
            return -1;
  
        if ( f-&gt;type == FD_PIPE )
            return pipewrite( f-&gt;pipe, addr, n );
  
      if ( f-&gt;type == FD_INODE )
      {
          // write a few blocks at a time to avoid exceeding
          // the maximum log transaction size, including
          // i-node, indirect block, allocation blocks,
          // and 2 blocks of slop for non-aligned writes.
          // this really belongs lower down, since writei()
          // might be writing a device like the console.
          int max = ( ( MAXOPBLOCKS - 1 - 1 - 2 ) / 2 ) * 512;
          int i = 0;
          while ( i &lt; n )
          {
              int n1 = n - i;
              if ( n1 &gt; max )
                  n1 = max;
  
              begin_op();
              ilock( f-&gt;ip );
              if ( ( r = writei( f-&gt;ip, addr + i, f-&gt;off, n1 ) ) &gt; 0 )
                  f-&gt;off += r;
              iunlock( f-&gt;ip );
              end_op();
  
              if ( r &lt; 0 )
                  break;
              if ( r != n1 )
                  panic( "short filewrite" );
              i += r;
          }
          return i == n ? n : -1;
      }
      panic( "filewrite" );
  }
  </code></pre>
  
  <p>And <code>filewrite</code> calls <code>writei</code> which is defined in <a href="https://github.com/mit-pdos/xv6-public/blob/master/fs.c" rel="nofollow noreferrer">fs.c</a>.</p>
  
  <pre><code>int writei ( struct inode *ip, char *src, uint off, uint n )
  {
      uint tot, m;
      struct buf *bp;
  
      if ( ip-&gt;type == T_DEV )
      {
          if ( ip-&gt;major &lt; 0 || ip-&gt;major &gt;= NDEV || !devsw[ ip-&gt;major ].write )
              return -1;
          return devsw[ ip-&gt;major ].write( ip, src, n );
      }
  
      if ( off &gt; ip-&gt;size || off + n &lt; off )
          return -1;
      if ( off + n &gt; MAXFILE*BSIZE )
          return -1;
  
      for ( tot = 0; tot &lt; n; tot += m, off += m, src += m )
      {
          bp = bread( ip-&gt;dev, bmap( ip, off/BSIZE ) );
          m = min( n - tot, BSIZE - off%BSIZE );
          memmove( bp-&gt;data + off%BSIZE, src, m );
          log_write( bp );
          brelse( bp );
      }
  
      if ( n &gt; 0 &amp;&amp; off &gt; ip-&gt;size )
      {
          ip-&gt;size = off;
          iupdate( ip );
      }
      return n;
  }
  </code></pre>
  
  <p>How does all this result in the terminal displaying the characters? How does the terminal know to read fd 1 for display, and where to find fd 1? What is the format of fd 1? Is it a standard?</p>