<?xml version="1.0"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Jonathan Perkin</title>
    <link>//www.perkin.org.uk/</link>
    <atom:link href="//www.perkin.org.uk/rss.xml" rel="self" type="application/rss+xml" />
    <description>learn | understand | share</description>
    <language>en-gb</language>
    <pubDate>Wed, 04 Dec 2019 10:21:18 +0000</pubDate>
    <lastBuildDate>Wed, 04 Dec 2019 10:21:18 +0000</lastBuildDate>

    
    <item>
      <title>Reducing RAM usage in pkgin</title>
      <link>//www.perkin.org.uk/posts/reducing-ram-usage-in-pkgin.html</link>
      <pubDate>Thu, 16 Jul 2015 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/reducing-ram-usage-in-pkgin.html</guid>
      <description>&lt;p&gt;Recently I’ve had a number of users complain about pkgin running out of memory
when installing packages.  This turned into a nice example of how to use
DTrace to show memory allocations and help track down excessive use.&lt;/p&gt;

&lt;p&gt;My test case was &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin -y install gcc47&lt;/code&gt;.  This is usually one of the first
commands I run in a new SmartOS zone anyway, and as &lt;code class=&quot;highlighter-rouge&quot;&gt;gcc47&lt;/code&gt; happens to be one
of the largest packages we ship it will help to exaggerate any memory
allocation.&lt;/p&gt;

&lt;h3 id=&quot;trace-heap-allocations&quot;&gt;Trace heap allocations&lt;/h3&gt;

&lt;p&gt;As a first step I wanted to answer the question of how much memory was being
allocated for pkgin.  A simple and naive way to do this would be to run tools
such as &lt;code class=&quot;highlighter-rouge&quot;&gt;ps(1)&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;prstat(1)&lt;/code&gt; (the SmartOS equivalent to &lt;code class=&quot;highlighter-rouge&quot;&gt;top(1)&lt;/code&gt;) whilst
pkgin is running, and monitor the memory columns.  This may give you a very
rough idea of how much memory is being used, but it’s not very accurate and
you may miss a large allocation just before the process exits.&lt;/p&gt;

&lt;p&gt;Instead we can use DTrace to trace the &lt;code class=&quot;highlighter-rouge&quot;&gt;brk()&lt;/code&gt; system calls and calculate the
exact amount of memory that has been allocated.  &lt;code class=&quot;highlighter-rouge&quot;&gt;brk()&lt;/code&gt; is where libc memory
allocation functions such as &lt;code class=&quot;highlighter-rouge&quot;&gt;malloc()&lt;/code&gt; end up on SmartOS, so by tracing that
single system call we can see exactly what has been allocated by the process.&lt;/p&gt;

&lt;p&gt;Tracing &lt;code class=&quot;highlighter-rouge&quot;&gt;brk()&lt;/code&gt; has the additional advantage of only showing heap growth.  If
we traced all the libc &lt;code class=&quot;highlighter-rouge&quot;&gt;*alloc()&lt;/code&gt; calls, we would have to perform additional
analysis to determine whether we actually allocated more memory or whether an
existing allocation was reused.  For more information about the different ways
to trace memory allocations, see Brendan Gregg’s excellent &lt;a href=&quot;http://www.brendangregg.com/FlameGraphs/memoryflamegraphs.html&quot;&gt;Memory Flame
Graphs&lt;/a&gt; page,
which is where many of the DTrace scripts in this post are based on.&lt;/p&gt;

&lt;p&gt;I used the following DTrace script to output 3 pieces of information over the
lifetime of the target process:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A quantized set of &lt;code class=&quot;highlighter-rouge&quot;&gt;brk()&lt;/code&gt; allocation sizes.&lt;/li&gt;
  &lt;li&gt;The total heap allocation.&lt;/li&gt;
  &lt;li&gt;The number of &lt;code class=&quot;highlighter-rouge&quot;&gt;brk()&lt;/code&gt; calls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Comments are inline.  &lt;code class=&quot;highlighter-rouge&quot;&gt;pid == $target&lt;/code&gt; ensures we only log &lt;code class=&quot;highlighter-rouge&quot;&gt;brk()&lt;/code&gt; calls made
by the process we specify as opposed to all &lt;code class=&quot;highlighter-rouge&quot;&gt;brk()&lt;/code&gt; calls across the entire
system, and &lt;code class=&quot;highlighter-rouge&quot;&gt;arg0&lt;/code&gt; is the argument to the &lt;code class=&quot;highlighter-rouge&quot;&gt;brk()&lt;/code&gt; system call.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#!/usr/sbin/dtrace -qs
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;heap_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * The first brk() call by this application.  As we do not know the initial
 * value of the heap pointer, and thus be able to calculate the increase made
 * by this call, all we can do is save it.
 */&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;syscall&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;brk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;heap_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;heap_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * A subsequent brk() call.  Calculate the size of the allocation and
 * update our running totals.
 */&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;syscall&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;brk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;heap_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;cm&quot;&gt;/* The heap grows up, so the size is simply (new addr - old addr) */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;heap_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* A quantized distribution of allocation sizes. */&lt;/span&gt;
	&lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sizes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;brk() allocation sizes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;quantize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* A running total of allocated bytes. */&lt;/span&gt;
	&lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Total bytes allocated&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* The total number of calls to brk(). */&lt;/span&gt;
	&lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;brks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Total number of brk() calls&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* Update our heap pointer for the next call. */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;heap_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Saving the script as &lt;code class=&quot;highlighter-rouge&quot;&gt;brkquantize.d&lt;/code&gt; and running it gives us the following
output:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Start with a clean pkgin cache.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; /var/db/pkgin
&lt;span class=&quot;go&quot;&gt;
: Ensure gcc47 is not installed, plus its dependency (binutils).
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_delete binutils gcc47
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./brkquantize.d &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;./pkgin-orig -py install gcc47&quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;
  brk() allocation sizes
           value  ------------- Distribution ------------- count
           32768 |                                         0
           65536 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@       573
          131072 |@@                                       32
          262144 |@                                        23
          524288 |@@                                       39
         1048576 |                                         1
         2097152 |                                         2
         4194304 |                                         1
         8388608 |                                         2
        16777216 |                                         1
        33554432 |                                         0
        67108864 |                                         0
       134217728 |                                         1
       268435456 |                                         0

  Total bytes allocated                                     401752064
  Total number of brk() calls                                     675&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Wow, that’s a lot of memory.  383MB has been allocated on the heap, with one
of those allocations alone being between 128MB and 256MB.  No wonder users are
running out of memory!&lt;/p&gt;

&lt;p&gt;This answers the questions regarding how much memory is being allocated, but
doesn’t answer the question of what is causing it.  I have my suspicions at
this point (the gcc47 package tarball is 250MB, is pkgin caching the entire
thing?), but in order to prove my suspicion I want to produce a flame graph.&lt;/p&gt;

&lt;h3 id=&quot;memory-flame-graph&quot;&gt;Memory flame graph&lt;/h3&gt;

&lt;p&gt;If you didn’t read the earlier link to Brendan Gregg’s “Memory Flame Graphs”
page, go and do that now.  The reason for creating one is to see visually and
easily which code paths are responsible for the allocations.&lt;/p&gt;

&lt;p&gt;To create the memory flame graph I used a slightly modified version of
Brendan’s &lt;code class=&quot;highlighter-rouge&quot;&gt;brkbytes.d&lt;/code&gt; with additional comments:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#!/usr/sbin/dtrace -qs
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;syscall&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;brk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;cm&quot;&gt;/* On entry, record the current heap pointer. */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cur&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;syscall&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;brk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prev&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;cm&quot;&gt;/* On return log the stack ordered by allocation size. */&lt;/span&gt;
	&lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ustack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cur&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;syscall&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;brk&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;cm&quot;&gt;/* Save the previous heap pointer. */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prev&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cur&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Again we execute the script with &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin&lt;/code&gt; as our target, after ensuring a clean
environment:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; /var/db/pkgin/cache&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; pkg_delete binutils gcc47
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./brkbytes.d &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;./pkgin-orig -py install gcc47&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;pkgin-orig.brkbytes
&lt;span class=&quot;go&quot;&gt;
: Remove any pkgin output, we just want the stack traces.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi pkgin-orig.brkbytes&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now we can use a couple of tools from Brendan’s
&lt;a href=&quot;https://github.com/brendangregg/FlameGraph&quot;&gt;FlameGraph&lt;/a&gt; repository to convert
the stack traces into a flame graph:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Download Brendan Gregg's &quot;FlameGraph&quot; repository
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; git clone https://github.com/brendangregg/FlameGraph.git
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;FlameGraph
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./stackcollapse.pl ~/pkgin-orig.brkbytes &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    | ./flamegraph.pl &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;--countname&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;bytes &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;--title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&quot;pkgin install&quot; heap expansion - original'&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;--colors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;mem &lt;span class=&quot;nt&quot;&gt;--width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;696 &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ~/pkgin-orig-brkbytes.svg&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The resulting SVG is below, you should be able to mouse-over the individual
elements for further details.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;object data=&quot;/files/images/pkgin-orig-brkbytes.svg&quot; type=&quot;image/svg+xml&quot;&gt;
  &lt;/object&gt;
&lt;/div&gt;

&lt;p&gt;From the flame graph it’s clear that the majority of allocations are coming
from &lt;code class=&quot;highlighter-rouge&quot;&gt;download_file()&lt;/code&gt;, and we now have an accurate count of how much memory is
being allocated by that function.&lt;/p&gt;

&lt;p&gt;We can further drill down on our hypothesis by comparing sizes.  The command we
are running is downloading and installing these two files:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;-rw-r--r--   1 root     root     9774130 Jul 10 10:47 binutils-2.24nb3.tgz
-rw-r--r--   1 root     root     261890422 Jul 10 10:47 gcc47-4.7.4.tgz&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s a total of 271,664,552 bytes.  According to the flame graph,
&lt;code class=&quot;highlighter-rouge&quot;&gt;download_file()&lt;/code&gt; allocated 271,671,296 bytes.  So it seems highly likely it is
caching those files, the 6,744 byte descrepancy likely due to rounding to the
nearest page size (4K on SmartOS) and an additional page for something else.&lt;/p&gt;

&lt;p&gt;Let’s go to the source to confirm.&lt;/p&gt;

&lt;h3 id=&quot;optimising-download_file&quot;&gt;Optimising &lt;code class=&quot;highlighter-rouge&quot;&gt;download_file()&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;download_file()&lt;/code&gt; function is reasonably straight-foward, and it’s quite
clear that we are indeed reading the entire file into RAM before writing it out
to disk.  Source edited for clarity and added comments &lt;a href=&quot;https://github.com/NetBSDfr/pkgin/blob/v0.8.0/download.c#L39..L136&quot;&gt;(full version
here)&lt;/a&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;n&quot;&gt;Dlfile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;download_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;cm&quot;&gt;/* Get information about the remote file. */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fetchXGet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;cm&quot;&gt;/*
	 * Allocate our Dlfile structure, as well as a buffer equal to the size
	 * of the remote file.
	 */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;buf_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;XMALLOC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dlfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;XMALLOC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;cm&quot;&gt;/* Download the file 1024 bytes at a time into our allocated buffer */&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf_fetched&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;cur_fetched&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fetchIO_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf_fetched&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;buf_fetched&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cur_fetched&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;cm&quot;&gt;/* NUL-terminate the buffer and return the buffer and size. */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;'\0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;On return to the caller it writes the returned buffer to a file descriptor and
then frees the buffer.&lt;/p&gt;

&lt;p&gt;Optimising this is pretty straight-foward.  We will instead pass an open file
descriptor to a new &lt;code class=&quot;highlighter-rouge&quot;&gt;download_pkg()&lt;/code&gt; function, which will stream to it directly
from each successful &lt;code class=&quot;highlighter-rouge&quot;&gt;fetchIO_read()&lt;/code&gt; via a static 4K buffer.  The commit to
implement this is
&lt;a href=&quot;https://github.com/joyent/pkgin/commit/0e421ba4bbb144fd0be11db856618af2919824cf&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Running &lt;code class=&quot;highlighter-rouge&quot;&gt;brkquantize.d&lt;/code&gt; on the new implementation we see significantly reduced
memory usage:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./brkquantize.d &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;./pkgin-dlpkg -py install gcc47&quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;
  brk() allocation sizes
           value  ------------- Distribution ------------- count
           32768 |                                         0
           65536 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@        511
          131072 |@@                                       32
          262144 |@                                        23
          524288 |@@@                                      43
         1048576 |                                         1
         2097152 |                                         2
         4194304 |                                         2
         8388608 |                                         1
        16777216 |                                         1
        33554432 |                                         0

  Total bytes allocated                                     134299648
  Total number of brk() calls                                     616&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We’ve reduced our initial 383MB usage down to 128MB, and saved around 60 calls
to &lt;code class=&quot;highlighter-rouge&quot;&gt;brk()&lt;/code&gt; in the process - a good start.&lt;/p&gt;

&lt;h3 id=&quot;optimising-pkg_summary-handling&quot;&gt;Optimising &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_summary&lt;/code&gt; handling&lt;/h3&gt;

&lt;p&gt;However 128MB still seems a lot for what the software is doing, can we do even
better?&lt;/p&gt;

&lt;p&gt;Let’s start with an updated memory flame graph to see where we stand with the
new version:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;object data=&quot;/files/images/pkgin-dlpkg-brkbytes.svg&quot; type=&quot;image/svg+xml&quot;&gt;
  &lt;/object&gt;
&lt;/div&gt;

&lt;p&gt;It’s clear that our &lt;code class=&quot;highlighter-rouge&quot;&gt;download_*()&lt;/code&gt; functions are no longer on the scene, and
now the majority of the memory usage is caused by &lt;code class=&quot;highlighter-rouge&quot;&gt;update_db()&lt;/code&gt;, accounting for
97MB.  This function handles fetching the remote &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_summary.bz2&lt;/code&gt; file and
transferring its contents into pkgin’s local sqlite3 database, which is then
used for local queries.&lt;/p&gt;

&lt;p&gt;Analysing &lt;code class=&quot;highlighter-rouge&quot;&gt;update_db()&lt;/code&gt; is a little more involved than &lt;code class=&quot;highlighter-rouge&quot;&gt;download_file()&lt;/code&gt;, but
we can use flame graphs to help us identify which functions to look at.  In
this case we want to take a closer look at &lt;code class=&quot;highlighter-rouge&quot;&gt;decompress_buffer()&lt;/code&gt; and
&lt;code class=&quot;highlighter-rouge&quot;&gt;insert_summary()&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;decompress_buffer&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;decompress_buffer()&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;After calling &lt;code class=&quot;highlighter-rouge&quot;&gt;download_file()&lt;/code&gt; to fetch the the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_summary.bz2&lt;/code&gt; file, the
&lt;code class=&quot;highlighter-rouge&quot;&gt;decompress_buffer()&lt;/code&gt; function is called to decompress it into memory and then
free the &lt;code class=&quot;highlighter-rouge&quot;&gt;download_file()&lt;/code&gt; allocation.&lt;/p&gt;

&lt;p&gt;However, why uncompress the entire file before parsing it?  Instead we can use
&lt;a href=&quot;http://www.libarchive.org/&quot;&gt;libarchive&lt;/a&gt; to stream the decompression and
process chunks at a time.  As it turns out pkgin already links against
libarchive but doesn’t actually use it, so this is easy enough to add.&lt;/p&gt;

&lt;h4 id=&quot;insert_summary&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;insert_summary()&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;While parsing the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_summary&lt;/code&gt; buffer, a set of &lt;code class=&quot;highlighter-rouge&quot;&gt;INSERT&lt;/code&gt; statements are
constructed by this function.  However, again we are buffering the whole lot,
when instead we could just stream them one by one.&lt;/p&gt;

&lt;h3 id=&quot;testing-streaming-updates&quot;&gt;Testing streaming updates&lt;/h3&gt;

&lt;p&gt;I made &lt;a href=&quot;https://github.com/joyent/pkgin/commit/bb51acbab56929b7c40bb3a450e276de1a268a3d&quot;&gt;some
changes&lt;/a&gt;
to implement streaming updates at each end, reading chunks of our compressed
&lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_summary&lt;/code&gt; file and, once we’d read a complete record, stream an update to
the database.  Here’s how the allocations look afterwards:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./brkquantize.d &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;./pkgin-streamsum -y up&quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  brk() allocation sizes
           value  ------------- Distribution ------------- count
           32768 |                                         0
           65536 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 375
          131072 |                                         2
          262144 |                                         0
          524288 |                                         0
         1048576 |                                         1
         2097152 |                                         1
         4194304 |                                         0

  Total bytes allocated                                      30502912
  Total number of brk() calls                                     379&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s better, now just 29MB to perform an update.  However, that still seems
quite a lot, so let’s generate an updated flame graph to see where the rest of
the memory is being used.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;object data=&quot;/files/images/pkgin-streamsum-brkbytes.svg&quot; type=&quot;image/svg+xml&quot;&gt;
  &lt;/object&gt;
&lt;/div&gt;

&lt;p&gt;Ok, so it’s clear the rest of the memory is being used by sqlite.  Anything we
can optimise there?&lt;/p&gt;

&lt;p&gt;Turns out there is.  I looked through pkgin to see if it was setting any
non-default sqlite parameters, and the very first one immediately caught my
eye:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pragmaopts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;cache_size = 1000000&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;a href=&quot;https://www.sqlite.org/pragma.html&quot;&gt;manual&lt;/a&gt; says that this value is in
pages, with a default of 2000, and that the page size defaults to 1024 bytes,
so we’re setting up a 976MB cache instead of the default 2MB.  This seems to be
rather larger than we need, so let’s try just removing that &lt;code class=&quot;highlighter-rouge&quot;&gt;PRAGMA&lt;/code&gt; and using
the default.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./brkquantize.d &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;./pkgin-nocache -y up&quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  brk() allocation sizes
           value  ------------- Distribution ------------- count
           32768 |                                         0
           65536 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   55
          131072 |@                                        1
          262144 |                                         0
          524288 |                                         0
         1048576 |@                                        1
         2097152 |@                                        1
         4194304 |                                         0

  Total bytes allocated                                       9388032
  Total number of brk() calls                                      58&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s worked out very well, and we’re now down to just 9MB, which seems
entirely reasonable to me.  One final flame graph:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;object data=&quot;/files/images/pkgin-nocache-brkbytes.svg&quot; type=&quot;image/svg+xml&quot;&gt;
  &lt;/object&gt;
&lt;/div&gt;

&lt;p&gt;The majority of our usage is now handling the compressed &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_summary.bz2&lt;/code&gt;
file.  For now we will stop there as it’s only 2MB, but future work could
include looking at streaming it directly from libfetch to libarchive rather
than having to load it all into memory first.&lt;/p&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h2&gt;

&lt;p&gt;Given we’ve changed a lot of code, and especially options around cache sizes,
how have they affected performance?  We can’t be as accurate as with our DTrace
measurements here, but we can perform a real-world benchmark of timing a &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin
update&lt;/code&gt; run against a localhost repository.  I ran each multiple times and took
the fastest result:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Original
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt; ./pkgin-orig up
&lt;span class=&quot;go&quot;&gt;real	0m42.401s
user	0m40.835s
sys	0m0.829s

: Modified
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;time&lt;/span&gt; ./pkgin-nocache up
&lt;span class=&quot;go&quot;&gt;real	0m9.912s
user	0m9.005s
sys	0m0.652s&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Less RAM &lt;strong&gt;and&lt;/strong&gt; significantly faster?  I’ll take that!&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;By using DTrace and Flame Graphs we are able to quickly identify code paths
using large resources.  By streaming data instead of caching we are able to
significantly reduce the amount of RAM required and simultaneously boost
performance.&lt;/p&gt;

&lt;p&gt;With these commits in place:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/joyent/pkgin/commit/0e421ba4bbb144fd0be11db856618af2919824cf&quot;&gt;Stream package downloads&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/joyent/pkgin/commit/bb51acbab56929b7c40bb3a450e276de1a268a3d&quot;&gt;Stream INSERTs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/joyent/pkgin/commit/65485dda594c27c8e5ad09121825114dcfbb8362&quot;&gt;Use default sqlite cache_size&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;the amount of RAM required to run &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin install gcc47&lt;/code&gt; on a clean SmartOS
install reduces from 383MB to just 16MB.&lt;/p&gt;

&lt;p&gt;I am hoping to get these changes in to the version of pkgin we ship for our
2015Q2 package sets, and will work to get these changes into upstream pkgin.&lt;/p&gt;

&lt;h2 id=&quot;august-2015-update-streaming-pkg_summary&quot;&gt;August 2015 update (streaming &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_summary&lt;/code&gt;)&lt;/h2&gt;

&lt;p&gt;Since writing this post I revisited the improvement I mentioned where we can
use libarchive to stream directly from libfetch rather than downloading the
entire &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_summary&lt;/code&gt; file first.&lt;/p&gt;

&lt;p&gt;Let’s see where things stand with the 2015Q2 pkgin which includes all of the
fixes described above:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; /var/db/pkgin&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ./brkquantize.d &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;pkgin up&quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  brk() allocation sizes
           value  ------------- Distribution ------------- count
           32768 |                                         0
           65536 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   55
          131072 |@                                        1
          262144 |                                         0
          524288 |                                         0
         1048576 |@                                        1
         2097152 |@                                        1
         4194304 |                                         0

  Total bytes allocated                                       9388032
  Total number of brk() calls                                      58&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To integrate libfetch directly into libarchive, we split our
&lt;code class=&quot;highlighter-rouge&quot;&gt;download_summary()&lt;/code&gt; function into separate &lt;code class=&quot;highlighter-rouge&quot;&gt;archive_read_open()&lt;/code&gt; callbacks.
These callbacks are called when the archive is opened, read, and closed.  Not
only does this reduce our memory requirements, it also simplifies the code a
little as libarchive can handle &lt;code class=&quot;highlighter-rouge&quot;&gt;EOF&lt;/code&gt; and detect download failures.&lt;/p&gt;

&lt;p&gt;The commit to implement this is
&lt;a href=&quot;https://github.com/joyent/pkgin/commit/72cd8345953c083cb4b79a180e8be1b38db9d8d9&quot;&gt;here&lt;/a&gt;.
One side-effect of this change is that now the remote INSERTions are performed
inline, we need to remove the separate progress meter as it conflicts with the
libfetch one.&lt;/p&gt;

&lt;p&gt;With that change applied we can see the RSS has decreased by a further 2MB
which corresponds to the size of the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_summary.bz2&lt;/code&gt; file we were previously
caching in RAM first:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; /var/db/pkgin&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; ./brkquantize.d &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;./pkgin up&quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  brk() allocation sizes
           value  ------------- Distribution ------------- count
           32768 |                                         0
           65536 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  57
          131072 |@                                        1
          262144 |                                         0
          524288 |                                         0
         1048576 |                                         0
         2097152 |@                                        1
         4194304 |                                         0

  Total bytes allocated                                       7495680
  Total number of brk() calls                                      59&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And for completeness sake, a final flame graph:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;object data=&quot;/files/images/pkgin-stream-fetch-brkbytes.svg&quot; type=&quot;image/svg+xml&quot;&gt;
  &lt;/object&gt;
&lt;/div&gt;

&lt;p&gt;How does it affect runtime?  Again I ran each multiple times against a
localhost repository and took the fastest time:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Original
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ptime pkgin up
&lt;span class=&quot;go&quot;&gt;real       10.912125551
user        9.672048265
sys         0.778736990

: Modified
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ptime ./pkgin up
&lt;span class=&quot;go&quot;&gt;real        9.487046885
user        9.069830722
sys         0.419527343&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s another clear win, with a 2MB reduction in RSS usage, and 1.5 seconds
shaved off the runtime.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>pkgsrc-2014Q4: LTS, signed packages, and more</title>
      <link>//www.perkin.org.uk/posts/pkgsrc-2014Q4-lts-signed-packages-and-more.html</link>
      <pubDate>Tue, 03 Mar 2015 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/pkgsrc-2014Q4-lts-signed-packages-and-more.html</guid>
      <description>&lt;p&gt;The latest quarterly release of our &lt;a href=&quot;http://pkgsrc.joyent.com/&quot;&gt;binary package
sets&lt;/a&gt; for SmartOS and illumos introduces a number of
new features that I’m excited to announce.&lt;/p&gt;

&lt;h2 id=&quot;long-term-support&quot;&gt;Long Term Support&lt;/h2&gt;

&lt;p&gt;We have produced quarterly releases of pkgsrc for a number of years, and since
the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc-2013Q2&lt;/code&gt; release have built every package available (10,000+), but
until now have not formalised our support for them.&lt;/p&gt;

&lt;p&gt;This has meant that when serious security issues such as
&lt;a href=&quot;http://en.wikipedia.org/wiki/Heartbleed&quot;&gt;Heartbleed&lt;/a&gt; are disclosed, we are
obliged to backport these fixes to every branch we have ever produced.  Despite
all our efforts on &lt;a href=&quot;/posts/building-packages-at-scale.html&quot;&gt;performance
improvements&lt;/a&gt; this is still a large
effort and takes a long time on older branches where we do not have huge
resources available and backports can be tricker due to the differences
involved.&lt;/p&gt;

&lt;p&gt;We’ve tried as best we can to keep these older branches updated, but as we’ve
added new branches each quarter the load increases further, and we cannot keep
doing this forever.&lt;/p&gt;

&lt;p&gt;So, from &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc-2014Q4&lt;/code&gt; (SmartOS 14.4.x images) we are introducing a new
yearly Long Term Support (LTS) model, which can be summarised as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Each &lt;code class=&quot;highlighter-rouge&quot;&gt;Q4&lt;/code&gt; release (&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc-2014Q4&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc-2015Q4&lt;/code&gt;, …) will be an LTS
release, and will receive suitable backports for 3 years from the time it is
made available.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We will continue to produce the other quarterly releases (SmartOS 15.1.x
images and onwards), so that users can get the latest packages available, but
each of those releases will be closed for updates as soon as the next one is
available.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What is a “suitable” backport?  Anything which is a security or build fix, and
which does not affect API or ABI compatibility.  For example, we would not
introduce a new major version of OpenSSL or PHP into an LTS release, but we
would update OpenSSL from &lt;code class=&quot;highlighter-rouge&quot;&gt;1.0.1j&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;1.0.1k&lt;/code&gt; or PHP from &lt;code class=&quot;highlighter-rouge&quot;&gt;5.4.37&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;5.4.38&lt;/code&gt;
as they are minor releases which only introduce fixes.  We may also introduce
new leaf packages (i.e. those with no dependencies), for example new releases
of nodejs.&lt;/p&gt;

&lt;p&gt;Who is the target market for each type of release?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;LTS is primarily useful for people who have a very static set of
requirements, do not like changes, and are primarily interested in ensuring
that the software they run does not have active vulnerabilities.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Latest quarterly releases are for everyone else, users who want the latest
stuff (and the latest security fixes), and are happy to reprovision their
applications onto the newest images at regular intervals.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We hope the introduction of LTS releases satisfies both types of users, and
that by freeing up our resources spent on maintaining our legacy branches, we
can invest more time into ensuring the stability and security of the LTS
releases.&lt;/p&gt;

&lt;p&gt;For SmartOS users, the LTS releases will receive an additional &lt;code class=&quot;highlighter-rouge&quot;&gt;-lts&lt;/code&gt; suffix on
the image name to make it even easier to identify which are LTS.&lt;/p&gt;

&lt;h2 id=&quot;image-name-changes&quot;&gt;Image Name Changes&lt;/h2&gt;

&lt;p&gt;Related to LTS, we are also slightly changing our naming scheme for the base
images.  This is to accommodate the new &lt;code class=&quot;highlighter-rouge&quot;&gt;-lts&lt;/code&gt; suffix, and also to allow us to
introduce a new “minimal” image, and make it clear which is which.&lt;/p&gt;

&lt;p&gt;The current base image names are:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;arch&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;name&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;32-bit&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;base&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;64-bit&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;base64&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;32-bit multiarch&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;multiarch&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;With the introduction of the “minimal” image, the new names will be:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;arch&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;base name&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;minimal name&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;32-bit&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;base-32&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;minimal-32&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;64-bit&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;base-64&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;minimal-64&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;32-bit multiarch&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;base-multiarch&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;minimal-multiarch&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;And for LTS releases:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;arch&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;base name&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;minimal name&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;32-bit&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;base-32-lts&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;minimal-32-lts&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;64-bit&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;base-64-lts&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;minimal-64-lts&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;32-bit multiarch&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;base-multiarch-lts&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;minimal-multiarch-lts&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;What’s the new “minimal” image?  It’s effectively a stripped down “base”, with
only the pkgsrc bootstrap and a couple of packages installed which are required
for the zone to boot correctly.  This will be of primary interest to users who
have custom requirements for their zones and/or produce their own images, and
want to ensure they are building on the smallest possible foundation.&lt;/p&gt;

&lt;p&gt;As a quick comparison:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;image&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;packages installed&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;image size (compressed)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;base-multiarch-lts 14.4.0&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;58&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;161M&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;minimal-multiarch-lts 14.4.0&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;25&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;31M&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The “minimal” images are fully functional and use the same package set, the
only difference is fewer packages are installed by default.&lt;/p&gt;

&lt;h2 id=&quot;updated-smartos-build-hosts&quot;&gt;Updated SmartOS Build Hosts&lt;/h2&gt;

&lt;p&gt;Up until now we have built all our package sets on an old
&lt;a href=&quot;https://github.com/joyent/sdc&quot;&gt;SDC&lt;/a&gt; 6.5 install, to ensure that the packages
we built can run across all hosts in the Joyent Public Cloud.  Building on the
lowest common denominator is great for compatibility, but has meant we are
running on a limited number of older machines, and each quarterly release added
yet more strain to already overloadeded systems.&lt;/p&gt;

&lt;p&gt;Starting with 2014Q4 LTS we have moved to newer build hosts, running
&lt;code class=&quot;highlighter-rouge&quot;&gt;joyent_20141030T081701Z&lt;/code&gt;.  This will soon be the most common platform
available in the Joyent cloud, and ensures we aren’t tied to a legacy release
for another 3 years.  The next 3 quarterly releases (2015Q1-3) will also be
produced on this platform, and we will then evaluate which platform to choose
for the next LTS in 2015Q4.&lt;/p&gt;

&lt;p&gt;This may mean incompatibilities if you are either running an older SmartOS
release, or if you are running a different illumos distribution which does not
have some of the newer SmartOS features.  You are most likely to see issues
where packages have picked up support for newer interfaces such as epoll or
inotify, which have been introduced as part of the LX brand work.&lt;/p&gt;

&lt;p&gt;Please feel free to raise a &lt;a href=&quot;https://github.com/joyent/pkgsrc/issues&quot;&gt;GitHub
issue&lt;/a&gt; if this is causing problems for
you.  We are happy to turn off support for newer features if it improves
compatibility, as often these features are picked up by autoconf checks but
either aren’t used correctly or should be using different interfaces on illumos
platforms anyway.&lt;/p&gt;

&lt;h2 id=&quot;signed-packages&quot;&gt;Signed Packages&lt;/h2&gt;

&lt;p&gt;One of the primary concerns in recent times is provenance, and ensuring that
what you are receiving hasn’t been tampered with in any way.  Until now our
packages have been protected by checksums, so that it is difficult for an
attacker to modify packages in-flight and deliver something we did not provide.&lt;/p&gt;

&lt;p&gt;However, it isn’t impossible, and to further ensure that what you are
installing came from Joyent we have implemented signed packages for 2014Q4
onwards.  Here’s how it works:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;During the package build process, a detached package hash file is created
which contains a SHA512 checksum of the package.&lt;/li&gt;
  &lt;li&gt;This hash file is then signed with our PGP key.&lt;/li&gt;
  &lt;li&gt;All three files are bundled into an &lt;code class=&quot;highlighter-rouge&quot;&gt;ar(1)&lt;/code&gt; archive and delivered as the
&lt;code class=&quot;highlighter-rouge&quot;&gt;package.tgz&lt;/code&gt; file.&lt;/li&gt;
  &lt;li&gt;At package install time, the archive is unpacked, the hash file is verified
against our public PGP key, and then the package is checksummed against the
recorded checksum in the hash file.  If all these checks pass, the package is
installed, otherwise the installation is aborted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s take a look at a package file (digest) to see in more detail:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: We need to use GNU ar(1) from binutils as the Sun format is too limited.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; gar xv /path/to/digest-20121220.tgz
&lt;span class=&quot;go&quot;&gt;x - +PKG_HASH
x - +PKG_GPG_SIGNATURE
x - digest-20121220.tgz&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;+PKG_HASH&lt;/code&gt; file contains all the details about the actual digest package
which is stored in the archive.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; +PKG_HASH
&lt;span class=&quot;go&quot;&gt;pkgsrc signature

version: 1
pkgname: digest-20121220
algorithm: SHA512
block size: 65536
file size: 49083

b011cb5e9cdea303f3958a7338b37fd85252313da354ff86a82170974f384700634c5fbe9d5f7035f67ff8a4eecacc6cfbff43ba4d62b4e4743837d72612feef
end pkgsrc signature&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We can verify that the checksum is correct.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; /usr/bin/digest &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; sha512 digest-20121220.tgz
&lt;span class=&quot;go&quot;&gt;b011cb5e9cdea303f3958a7338b37fd85252313da354ff86a82170974f384700634c5fbe9d5f7035f67ff8a4eecacc6cfbff43ba4d62b4e4743837d72612feef&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So we know that the &lt;code class=&quot;highlighter-rouge&quot;&gt;+PKG_HASH&lt;/code&gt; file matches the &lt;code class=&quot;highlighter-rouge&quot;&gt;digest-20121220.tgz&lt;/code&gt; package
file.  However, how do we know that both haven’t been tampered with?  That’s
where the &lt;code class=&quot;highlighter-rouge&quot;&gt;+PKG_GPG_SIGNATURE&lt;/code&gt; file comes in.  It is a detached signature of
the &lt;code class=&quot;highlighter-rouge&quot;&gt;+PKG_HASH&lt;/code&gt; file, signed with the Joyent key, so that if a malicious user
has tampered with the package file and generated a new checksum, the
&lt;code class=&quot;highlighter-rouge&quot;&gt;+PKG_HASH&lt;/code&gt; file will no longer be verified and we know that it isn’t what was
originally built.&lt;/p&gt;

&lt;p&gt;We can verify that on the command line with GPG, as long as you have imported
the public key for that package set:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; gpg &lt;span class=&quot;nt&quot;&gt;--verify&lt;/span&gt; +PKG_GPG_SIGNATURE +PKG_HASH
&lt;span class=&quot;go&quot;&gt;gpg: Signature made Sat Feb 21 02:10:43 2015 UTC using RSA key ID DE817B8E
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;gpg: Good signature from &quot;Joyent Package Signing &amp;lt;pkgsrc@joyent.com&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 74C4 F303 BB45 7421 E42C  4DC4 FAE5 0048 FAA6 6EE0
     Subkey fingerprint: 2163 0D8B 4486 4587 9655  3748 76FA BBBB DE81 7B8E&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A quick note about the warnings shown above.  This is where the PGP web of
trust comes in.  We know that the files were signed with the &lt;code class=&quot;highlighter-rouge&quot;&gt;DE817B8E&lt;/code&gt; key,
but how do we know that the key belongs to &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc@joyent.com&lt;/code&gt;?  It essentially
comes down to trust, and whether you believe this is really our key, or whether
someone has tricked you to believe that when it’s not.  We can help persuade
you in a few ways:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The bootstrap packages and our SmartOS images will come by default with that
key installed in &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local/etc/gnupg/pkgsrc.gpg&lt;/code&gt;.  This is required so that
you can start installing signed packages out of the box with no setup
necessary.&lt;/li&gt;
  &lt;li&gt;The public keys will be published to PGP key servers, and I will sign them
with my key (&lt;code class=&quot;highlighter-rouge&quot;&gt;D532A578&lt;/code&gt;).  My key in turn is signed by a number of other
people, so that you can verify whether you believe I am who I say I am.&lt;/li&gt;
  &lt;li&gt;We will publish the keys in a couple of other places, certainly on the main
&lt;a href=&quot;http://pkgsrc.joyent.com/&quot;&gt;http://pkgsrc.joyent.com/&lt;/a&gt; site.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, if you are a diligent user who checks all of these sources, an attacker
would need to infiltrate every single one of them simultaneously to have a
chance of delivering you a malicious packages which bypasses all of the checks.
Hopefully you are convinced that this would be extremely difficult.&lt;/p&gt;

&lt;p&gt;Finally, how is all of this used in practise?  We’ve worked hard to make this
as transparent as possible, including integration of Alistair Crooks’ excellent
&lt;a href=&quot;http://netbsd.gw.com/cgi-bin/man-cgi?libnetpgpverify++NetBSD-current&quot;&gt;libnetpgpverify&lt;/a&gt;
library into &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_install&lt;/code&gt;, so as a user you should never be aware of any of it
unless there is a problem (a core Unix philosophy):&lt;/p&gt;

&lt;p&gt;As mentioned above, the PGP key is distributed by default, so you don’t need to
import keys or anything to get started.  We have added the following to
&lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local/etc/pkg_install.conf&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;GPG_KEYRING_VERIFY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/local/etc/gnupg/pkgsrc.gpg
&lt;span class=&quot;nv&quot;&gt;VERIFIED_INSTALLATION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;trusted&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;GPG_KEYRING_VERIFY&lt;/code&gt; is set to our public key, and
&lt;code class=&quot;highlighter-rouge&quot;&gt;VERIFIED_INSTALLATION=trusted&lt;/code&gt; means that a signature is required, and if one
isn’t available then you are prompted for how to proceed.  Trying to install
the package file from our &lt;code class=&quot;highlighter-rouge&quot;&gt;ar(1)&lt;/code&gt; archive example above shows what happens:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_add ./digest-20121220.tgz
&lt;span class=&quot;go&quot;&gt;No valid signature found for digest-20121220.
Do you want to proceed with the installation [y/n]?
n
Cancelling installation
pkg_add: 1 package addition failed&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And if we try to install a package with an incorrect signature/hash:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ed +PKG_HASH &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;/^b011/s/b011/b010/
w
q
EOF
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; gar r test.tgz +PKG_HASH +PKG_GPG_SIGNATURE digest-20121220.tgz
&lt;span class=&quot;go&quot;&gt;gar: creating test.tgz
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_add ./test.tgz
&lt;span class=&quot;go&quot;&gt;pkg_add: unable to verify signature: Signature on data did not match&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you build your own packages then you’re going to want to handle this
properly.  The simplest option is to use a custom &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_install.conf&lt;/code&gt; when
installing your own packages, for example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;VERIFIED_INSTALLATION=never&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;pkg_install_noverify.conf
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_add &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; ./pkg_install_noverify.conf ./digest-20121220.tgz&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The alternative is to sign your own packages.  This is reasonably
straight-forward:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Enable &lt;code class=&quot;highlighter-rouge&quot;&gt;SIGN_PACKAGES&lt;/code&gt; in &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local/etc/mk.conf&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;nv&quot;&gt;SIGN_PACKAGES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	gpg&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;Install GPG, create a signing key, and then configure
&lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local/etc/pkg_install.conf&lt;/code&gt; with:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;GPG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/path/to/gpg
&lt;span class=&quot;nv&quot;&gt;GPG_SIGN_AS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;your_pgp_key_id&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With those additions, pkgsrc will prompt you for your PGP passphrase at package
time, and then sign the package with the key you have configured.  You can use
&lt;code class=&quot;highlighter-rouge&quot;&gt;gpg-agent&lt;/code&gt; to automate this in a controlled environment.&lt;/p&gt;

&lt;h2 id=&quot;bundled-pkg-vulnerabilities-verification&quot;&gt;Bundled &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg-vulnerabilities&lt;/code&gt; Verification&lt;/h2&gt;

&lt;p&gt;Closely related to package signing, now that we have infrastructure support for
verification in our bootstrap packages, we’ve also enabled easy verification of
the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg-vulnerabilities&lt;/code&gt; file.  For those who aren’t aware, there is a team of
volunteers for pkgsrc who maintain a list of security vulnerabilities, which
can be checked against the list of installed packages and show you which ones
are currently vulnerable.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Fetch the latest pkg-vulnerabilities file.  SmartOS images have a crontab
: entry which does this nightly by default.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_admin fetch-pkg-vulnerabilities
&lt;span class=&quot;go&quot;&gt;
: The file is a compressed signed message containing a list of all known
: vulnerabilities.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-dc&lt;/span&gt; /opt/local/pkg/pkg-vulnerabilities | &lt;span class=&quot;nb&quot;&gt;nl&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ba&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1,4p'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'27,28p'&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;     1  -----BEGIN PGP SIGNED MESSAGE-----
     2  Hash: SHA1
     3
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;     4  #&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$NetBSD&lt;/span&gt;: pkg-vulnerabilities,v 1.6187 2015/03/02 14:22:28 ryoon Exp &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;    27  #&lt;/span&gt; package               &lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;of exploit         URL
&lt;span class=&quot;go&quot;&gt;    28  cfengine&amp;lt;1.5.3nb3       remote-root-shell       ftp://ftp.NetBSD.org/pub/NetBSD/security/advisories/NetBSD-SA2000-013.txt.asc

: Show list of current known vulnerabilities
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_admin audit
&lt;span class=&quot;go&quot;&gt;Package gcc47-4.7.3nb6 has a denial-of-service vulnerability, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61601
Package gcc47-4.7.3nb6 has a memory-corruption vulnerability, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61582
Package mit-krb5-1.10.7nb4 has a denial-of-service vulnerability, see http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-5353
[...]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This provides you as the administrator with the information necessary to decide
whether the current vulnerabilities are acceptable in your environment.&lt;/p&gt;

&lt;p&gt;However, there is a missing piece.  As you can see above, the vulnerabilities
file is signed.  This is important as an attacker with access to modify this
file could hide vulnerabilities from you and leave your system exposed.  With
the verification infrastructure now in place, we can now provide the
pkgsrc-security PGP key for you to easily verify that the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg-vulnerabilities&lt;/code&gt;
file is as expected.&lt;/p&gt;

&lt;p&gt;First we need to install the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc-security@pkgsrc.org&lt;/code&gt; PGP key on the
system.  As this key changes quite frequently, we cannot include it directly in
the bootstrap tarball as we have done with the package signing key, as it will
eventually be out of date.  So we instead provide a new &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc-gnupg-keys&lt;/code&gt;
package which includes it, bundle that in the bootstrap, and we can then
distribute updates to this package as normal via &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin upgrade&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: The package contains a PGP keyring with the current pkgsrc-security key.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-qL&lt;/span&gt; pkgsrc-gnupg-keys
&lt;span class=&quot;go&quot;&gt;/opt/local/share/gnupg/pkgsrc-security.gpg&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We then add that file to our &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local/etc/pkg_install.conf&lt;/code&gt; file with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;GPG_KEYRING_PKGVULN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/local/share/gnupg/pkgsrc-security.gpg&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To verify the pkg-vulnerabilities file, use &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_admin&lt;/code&gt; again:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Verify the basic checksum, looks good.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_admin check-pkg-vulnerabilities /opt/local/pkg/pkg-vulnerabilities
&lt;span class=&quot;go&quot;&gt;
: Verify the PGP signature, looks good.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_admin check-pkg-vulnerabilities &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /opt/local/pkg/pkg-vulnerabilities
&lt;span class=&quot;go&quot;&gt;
: Modify the file and try again, checks fail.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-dc&lt;/span&gt; /opt/local/pkg/pkg-vulnerabilities &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'mutt.*denial-of-service'&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  | &lt;span class=&quot;nb&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-9&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/var/tmp/pkg-vulnerabilities-test
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_admin check-pkg-vulnerabilities /var/tmp/pkg-vulnerabilities-test
&lt;span class=&quot;go&quot;&gt;pkg_admin: SHA1 hash doesn't match

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_admin check-pkg-vulnerabilities &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /var/tmp/pkg-vulnerabilities-test
&lt;span class=&quot;go&quot;&gt;pkg_admin: unable to verify signature: Signature on data did not match&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Add these checks to your automated reports to ensure you aren’t being lied to
about possible vulnerabilities.&lt;/p&gt;

&lt;h2 id=&quot;reduced-package-requires&quot;&gt;Reduced Package REQUIRES&lt;/h2&gt;

&lt;p&gt;Each package lists the libraries that it requires, and those are checked prior
to installation to ensure the package will work correctly on the target host.
Recently we’ve seen a few issues where some illumos distributions have moved
platform libraries to a different location (but still in the default search
path), which means the &lt;code class=&quot;highlighter-rouge&quot;&gt;REQUIRES&lt;/code&gt; no longer match and the package won’t
install.&lt;/p&gt;

&lt;p&gt;From 2014Q4 we have reduced the way that &lt;code class=&quot;highlighter-rouge&quot;&gt;REQUIRES&lt;/code&gt; are computed.  Previously
every library that was pulled in was recorded, essentially using the output of
&lt;code class=&quot;highlighter-rouge&quot;&gt;ldd&lt;/code&gt;, so for example with the &lt;code class=&quot;highlighter-rouge&quot;&gt;libpcap&lt;/code&gt; package you end up with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-Q&lt;/span&gt; REQUIRES libpcap
&lt;span class=&quot;go&quot;&gt;/lib/libavl.so.1
/lib/libc.so.1
/lib/libcurses.so.1
/lib/libdevinfo.so.1
/lib/libdladm.so.1
/lib/libdlpi.so.1
/lib/libgen.so.1
/lib/libinetutil.so.1
/lib/libkstat.so.1
/lib/libm.so.2
/lib/libmd.so.1
/lib/libmp.so.2
/lib/libnsl.so.1
/lib/libnvpair.so.1
/lib/libpthread.so.1
/lib/librcm.so.1
/lib/libscf.so.1
/lib/libsec.so.1
/lib/libsocket.so.1
/lib/libumem.so.1
/lib/libuutil.so.1
/lib/libxml2.so.2
/lib/libz.so.1
/opt/local/gcc47/i386-sun-solaris2.11/lib/./libgcc_s.so.1
/usr/lib/libexacct.so.1
/usr/lib/libidmap.so.1
/usr/lib/libpool.so.1
/usr/lib/libsmbios.so.1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In 2014Q4 we have stopped using &lt;code class=&quot;highlighter-rouge&quot;&gt;ldd&lt;/code&gt; to resolve the library dependencies, and
instead use &lt;code class=&quot;highlighter-rouge&quot;&gt;elfdump&lt;/code&gt; to only look at the &lt;code class=&quot;highlighter-rouge&quot;&gt;NEEDED&lt;/code&gt; entries that are recorded in
the &lt;code class=&quot;highlighter-rouge&quot;&gt;SHT_DYNAMIC&lt;/code&gt; section for each executable.  This results in a much simpler
and direct list:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-Q&lt;/span&gt; REQUIRES libpcap
&lt;span class=&quot;go&quot;&gt;/lib/libc.so.1
/lib/libdlpi.so.1
/lib/libnsl.so.1
/lib/libsocket.so.1
/lib/libumem.so.1
/opt/local/gcc47/i486-sun-solaris2.11/lib/./libgcc_s.so.1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;due to excluding all of &lt;code class=&quot;highlighter-rouge&quot;&gt;/lib/libdlpi.so.1&lt;/code&gt;’s dependencies, and increases the
portability of our packages across illumos distributions.&lt;/p&gt;

&lt;p&gt;We also get a side benefit of being able to easily identify packages which are
incorrectly linking against system versions of e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;libxml2.so.2&lt;/code&gt; when they
should instead be using the pkgsrc version.&lt;/p&gt;

&lt;h2 id=&quot;miscellaneous-improvements&quot;&gt;Miscellaneous Improvements&lt;/h2&gt;

&lt;p&gt;There is the usual grab bag of updates in 2014Q4/14.4.x:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;go-1.4.2&lt;/code&gt; now includes Keith Wesolowski’s patches to add support for cgo.
This brings Go for illumos up to feature parity with other operating systems
and increases the amount of Go software that will build and run.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;SmartOS 14.4.x images now deliver an SSL bundle in &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc&lt;/code&gt; which makes Go work
correctly, and we also ensure that &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/bin/curl&lt;/code&gt; has access to
certificates.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;libgo&lt;/code&gt; has been removed from the &lt;code class=&quot;highlighter-rouge&quot;&gt;gcc47-libs&lt;/code&gt; package.  It is unused, and
doing this saves 40MB from the bootstrap kits and images.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We now build with cwrappers, as detailed in my
&lt;a href=&quot;/posts/building-packages-at-scale.html&quot;&gt;performance&lt;/a&gt; post.  This speeds up
the builds a lot, so in the event of another Heartbleed we should be able to
deliver updated packages a lot faster.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin&lt;/code&gt; is now at version 0.8.0 including support for the new
&lt;code class=&quot;highlighter-rouge&quot;&gt;preferred.conf&lt;/code&gt;, plus a number of important bug fixes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A number of small internal improvements to the build infrastructure.  As a
user you shouldn’t notice any changes, if you do please let us know!&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus all the usual upstream pkgsrc changes as announced
&lt;a href=&quot;https://mail-index.netbsd.org/pkgsrc-users/2015/01/02/msg020854.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As always, please raise a &lt;a href=&quot;https://github.com/joyent/pkgsrc/issues&quot;&gt;GitHub
issue&lt;/a&gt; if you run into any problems or
have any suggestions on ways we can improve any of this stuff.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Building packages at scale</title>
      <link>//www.perkin.org.uk/posts/building-packages-at-scale.html</link>
      <pubDate>Mon, 06 Oct 2014 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/building-packages-at-scale.html</guid>
      <description>&lt;p&gt;&lt;strong&gt;tl;dr We are able to build 14,000 packages across 6 zones in 4.5 hours&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At Joyent we have long had a focus on high performance, whether it’s through
innovations in &lt;a href=&quot;http://smartos.org&quot;&gt;SmartOS&lt;/a&gt;, carefully selecting our
&lt;a href=&quot;http://eng.joyent.com/manufacturing/bom.html&quot;&gt;hardware&lt;/a&gt;, or providing
customers with tools such as &lt;a href=&quot;http://en.wikipedia.org/wiki/DTrace&quot;&gt;DTrace&lt;/a&gt; to
identify bottlenecks in their application stacks.&lt;/p&gt;

&lt;p&gt;When it comes to building packages for SmartOS it is no different.  We want to
build them as quickly as possible, using the fewest resources, but without
sacrificing quality or consistency.&lt;/p&gt;

&lt;p&gt;To give you an idea of how many packages we build, here are the numbers:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Branch&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Arch&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Success&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Fail&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Total&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2012Q4&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;i386&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2,245&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;20&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2,265&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2012Q4&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;x86_64&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2,244&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;18&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2,262&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2013Q1&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;i386&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2,303&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;40&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2,343&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2013Q1&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;x86_64&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2,302&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;39&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2,341&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2013Q2&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;i386&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;10,479&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1,277&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;11,756&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2013Q2&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;x86_64&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;10,290&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1,272&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;11,562&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2013Q3&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;i386&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;11,286&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1,317&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;12,603&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2013Q3&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;x86_64&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;11,203&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1,308&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;12,511&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2013Q4&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;i386&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;11,572&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1,277&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;12,849&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2013Q4&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;x86_64&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;11,498&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1,270&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;12,786&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2014Q1&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;i386&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;12,450&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1,171&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;13,621&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2014Q1&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;x86_64&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;12,356&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1,150&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;13,506&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2014Q2&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;i386&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;13,132&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1,252&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;14,384&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2014Q2&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;x86_64&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;13,102&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1,231&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;14,333&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Total&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt; &lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;139,122&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Now of course we don’t continuously attempt to build 139,122 packages.
However, when something like
&lt;a href=&quot;http://en.wikipedia.org/wiki/Heartbleed&quot;&gt;Heartbleed&lt;/a&gt; happens, we backport the
fix to all of these branches, and a rebuild of something as heavily depended
upon as OpenSSL can cause around 100,000 packages to be rebuilt.&lt;/p&gt;

&lt;p&gt;Each quarter we add another release branch to our builds, and as you can see
from the numbers above (2013Q1 and earlier were limited builds) the total
number of packages in pkgsrc grows with each release.&lt;/p&gt;

&lt;p&gt;Recently I’ve been focussing on improving the bulk build performance, both to
ensure that fixes such as Heartbleed are delivered as quickly as possible, and
also to ensure we aren’t wasteful in our resource usage as our package count
grows.  All of our builds happen in the Joyent public cloud, so any resources
we are using are taking away from the available pool to sell to customers.&lt;/p&gt;

&lt;p&gt;Let’s first take a walk through pkgsrc bulk build history, and then look at
some of the performance wins I’ve been working on.&lt;/p&gt;

&lt;h2 id=&quot;pkgsrc-bulk-builds-2004&quot;&gt;pkgsrc bulk builds, 2004&lt;/h2&gt;

&lt;p&gt;The oldest bulk build I performed that I can find is &lt;a href=&quot;http://mail-index.netbsd.org/pkgsrc-bulk/2004/05/11/msg000099.html&quot;&gt;this
one&lt;/a&gt;.  My
memory is a little fuzzy on what hardware I was using at the time, but I
believe it was a SunFire v120 (1 x UltraSPARCIIi CPU @ 650MHz) with 2GB RAM.
This particular build was on Solaris 8.&lt;/p&gt;

&lt;p&gt;As you can see from the results page, it took 13.5 days to build 1,810 (and
attempt but fail to build 1,128) packages!&lt;/p&gt;

&lt;p&gt;Back then the build would have been single threaded with only one package being
built at a time.  There was no support for concurrent builds, &lt;code class=&quot;highlighter-rouge&quot;&gt;make -j&lt;/code&gt;
wouldn’t have helped much, and essentially you just needed to be very patient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;May 2004: 2,938 packages in 13.5 days&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;pkgsrc-bulk-builds-2010&quot;&gt;pkgsrc bulk builds, 2010&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://mail-index.netbsd.org/pkgsrc-bulk/2010/05/05/msg007404.html&quot;&gt;Fast forward 6
years&lt;/a&gt;.  At
this point I’m building on much faster x86-based hardware (a Q9550 Core2Quad @
2.83GHz and 16G RAM) running Solaris 10, however the builds are still single
threaded and take 4 days to build 5,524 (and attempt but fail to build 1,325)
packages.&lt;/p&gt;

&lt;p&gt;All of the speed increase is coming directly from faster hardware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;May 2010: 6,849 packages in 4 days&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;pkgsrc--joyent-2012-onwards&quot;&gt;pkgsrc @ Joyent, 2012 onwards&lt;/h2&gt;

&lt;p&gt;Shortly after &lt;a href=&quot;http://www.perkin.org.uk/posts/goodbye-oracle-hello-joyent.html&quot;&gt;joining
Joyent&lt;/a&gt;, I
started setting up our bulk build infrastructure.  The first official build
from this was for &lt;a href=&quot;http://www.perkin.org.uk/posts/9000-packages-for-smartos-and-illumos.html&quot;&gt;general illumos
use&lt;/a&gt;.
We were able to provide over 9,000 binary packages which took around &lt;a href=&quot;http://mail-index.netbsd.org/pkgsrc-bulk/2012/07/09/msg008990.html&quot;&gt;7 days to
build&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At this point we’re starting to see the introduction of very large packages
such as qt4, kde4, webkit, etc.  These packages take a significant amount of
time to build, so even though we are building on faster hardware than
previously, the combination of an increased package count as well as individual
package build times increasing mean we’re not seeing a reduction in total build
time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;July 2012: 10,554 packages in 7 days&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;performance-improvements&quot;&gt;Performance improvements&lt;/h2&gt;

&lt;p&gt;At this point we start to look at ways of speeding up the builds themselves.
As we have the ability to create build zones as required, the first step was to
introduce distributed builds.&lt;/p&gt;

&lt;h3 id=&quot;pbulk-distributed-builds&quot;&gt;pbulk distributed builds&lt;/h3&gt;

&lt;p&gt;For pkgsrc in the 2007 Google Summer of Code &lt;a href=&quot;http://www.sonnenberger.org/&quot;&gt;Jörg
Sonnenberger&lt;/a&gt; wrote pbulk, a replacement for the
older bulk build infrastructure that had been serving us well since 2004 but
had started to show its age.  One of the primary benefits of pbulk was that it
supported a client/server setup to distribute builds, and so I worked on
building across 6 separate zones.  From my work log:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;2012-09-25 (Tuesday)

 - New pbulk setup managed a full bulk build (9,414 packages) in 54 hours,
   since then I've added another 2 clients which should get us well under 2
   days.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;September 2012: 10,634 packages in 2 days&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;distributed-chrooted-builds&quot;&gt;Distributed chrooted builds&lt;/h3&gt;

&lt;p&gt;By far the biggest win so far was in June 2013, however I’m somewhat ashamed
that it took me so long to think of it.  By this time we were already using
chroots for builds, as it ensures a clean and consistent build environment,
keeps the host zone clean, and also allowed us to perform concurrent branch
builds (e.g. building i386 and x86_64 packages simultaneously on the same host
but in separate chroots).&lt;/p&gt;

&lt;p&gt;What it took me 9 months to realise, however, was that we could simply use
multiple chroots for each branch build!  This snippet from my log is
enlightening:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;2013-06-06 (Thursday)

 - Apply &quot;duh, why didn't I think of that earlier&quot; patch to the pbulk cluster
   which will give us massively improved concurrency and much faster builds.

2013-06-07 (Friday)

 - Initial results from the re-configured pbulk cluster show it can chew
   through 10,000 packages in about 6 hours, producing 9,000 binary pkgs.
   Not bad.  Continue tweaking to avoid build stalls with large dependent
   packages (e.g. gcc/webkit/qt4).&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Not bad indeed.  The comment is somewhat misleading, though, as this comment I
made on IRC on June 15th alludes to:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;22:27 &amp;lt; jperkin&amp;gt; jeez lang/mercury is a monster
22:28 &amp;lt; jperkin&amp;gt; I can build over 10,000 packages in 18 hours, but that
                 one package alone takes 7.5 hours before failing.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Multiple distributed chroots get us an awfully long way, but now we’re stuck
with big packages which ruin our total build times, and no amount of additional
zones or chroots will help.&lt;/p&gt;

&lt;p&gt;However, we are now under 24 hours for a full build for the first time.  This
is of massive benefit, as we can now do regular daily builds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;June 2013: 11,372 packages in 18 hours&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;make--j-vs-number-of-chroots&quot;&gt;make -j vs number of chroots&lt;/h3&gt;

&lt;p&gt;An ongoing effort has been to optimise the &lt;code class=&quot;highlighter-rouge&quot;&gt;MAKE_JOBS&lt;/code&gt; setting used for each
package build, balanced against the number of concurrent chroots.  There are a
number of factors to consider:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The vast majority of &lt;code class=&quot;highlighter-rouge&quot;&gt;./configure&lt;/code&gt; scripts are single threaded, so generally
you should trade extra chroots for less &lt;code class=&quot;highlighter-rouge&quot;&gt;MAKE_JOBS&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;The same goes for other phases of the package build (fetch, checksum,
extract, patch, install, package).&lt;/li&gt;
  &lt;li&gt;Packages which are highly depended upon (e.g. GCC, Perl, OpenSSL) should have
a high &lt;code class=&quot;highlighter-rouge&quot;&gt;MAKE_JOBS&lt;/code&gt; as even with a large number of chroots enabled, most of
them will be idle waiting for those builds to complete.&lt;/li&gt;
  &lt;li&gt;Larger packages are built towards the end of a bulk build run (e.g. KDE,
Firefox) and these tend to be large builds.  Similar to above, as they are
later in the build there will be fewer chroots active, so a higher MAKE_JOBS
can be afforded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Large packages like webkit will happily burn as many cores as you give them and
return you with faster build times, however giving them 24 dedicated cores
isn’t cost-effective.  Our 6 build zones are sized at 16 cores / 16GB DRAM, and
so far the sweet spot seems to be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;8 chroots per build (bump to 16 if the build is performed whilst no other
builds are happening).&lt;/li&gt;
  &lt;li&gt;Default &lt;code class=&quot;highlighter-rouge&quot;&gt;MAKE_JOBS=2&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;MAKE_JOBS=4&lt;/code&gt; for packages which don’t have many dependents but are generally
large builds which benefit from additional parallelism.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;MAKE_JOBS=6&lt;/code&gt; for webkit.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;MAKE_JOBS=8&lt;/code&gt; for highly-dependent packages which stall the build, and/or are
built right at the end.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;MAKE_JOBS&lt;/code&gt; value is determined based on the current &lt;code class=&quot;highlighter-rouge&quot;&gt;PKGPATH&lt;/code&gt; and is
dynamically generated so we can easily test new hypotheses.&lt;/p&gt;

&lt;p&gt;With various tweaks in place, fixes to packages etc., we were running steady at
around 12 hrs for a full build.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;August 2014: 14,017 packages in 12 hours&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;cwrappers&quot;&gt;cwrappers&lt;/h3&gt;

&lt;p&gt;There are a number of unique technologies in pkgsrc that have been incredibly
useful over the years.  Probably the most useful has been the wrappers in our
&lt;a href=&quot;https://www.netbsd.org/docs/pkgsrc/buildlink.html&quot;&gt;buildlink&lt;/a&gt; framework, which
allows compiler and linker commands to be analysed and modified before being
passed to the real tool.  For example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Remove any hardcoded GNU ld arguments unsupported by the SunOS linker
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;${OPSYS}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;SunOS&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;BUILDLINK_TRANSFORM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt;:-Wl,--as-needed
&lt;span class=&quot;err&quot;&gt;.endif&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Stop using -fomit-frame-pointer and producing useless binaries!  Transform
# it to &quot;-g&quot; instead, just in case they forgot to add that too.
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BUILDLINK_TRANSFORM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt;  opt:-fomit-frame-pointer:-g&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There are a number of other features of the wrapper framework, however it
doesn’t come without cost.  The wrappers are written in shell, and fork a large
number of &lt;code class=&quot;highlighter-rouge&quot;&gt;sed&lt;/code&gt; and other commands to perform replacements.  On platforms with
an expensive &lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt; implementation this can have quite a detrimental effect
on performance.&lt;/p&gt;

&lt;p&gt;Jörg again was heavily involved in a fix for this, with his work on
&lt;a href=&quot;http://www.netbsd.org/gallery/presentations/joerg/eurobsdcon2009/wrapper.pdf&quot;&gt;cwrappers&lt;/a&gt;,
which replaced the shell scripts with C implementations.  Despite being 99%
complete, the final effort to get it over the line and integrated into pkgsrc
hadn’t been finished, so in September 2014 I took on the task and the sample
package results speak for themselves:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Package&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;Legacy wrappers&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;C wrappers&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Speedup&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;wireshark&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;3,376 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1,098 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;3.07x&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;webkit1-gtk&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;11,684 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;4,622 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2.52x&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;qt4-libs&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;11,866 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;5,134 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2.31x&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;xulrunner24&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;10,574 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;5,058 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2.09x&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ghc6&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2,026 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1,328 seconds&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;1.52x&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;As well as reducing the overall build time, the significant reduction in number
of forks meant the system time was a lot lower, allowing us to increase the
number of build chroots.  The end result was a reduction of over 50% in overall
build time!&lt;/p&gt;

&lt;p&gt;The work is still ongoing to integrate this into pkgsrc, and we hope to have it
done for pkgsrc-2014Q4.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;September 2014: 14,011 packages in 5 hours 20 minutes&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;miscellaneous-fork-improvements&quot;&gt;Miscellaneous fork improvements&lt;/h2&gt;

&lt;p&gt;Prior to working on cwrappers I was looking at other ways to reduce the number
of forks, using DTrace to monitor each internal pkgsrc phase.  For example the
&lt;code class=&quot;highlighter-rouge&quot;&gt;bmake wrapper&lt;/code&gt; phase generates a shadow tree of symlinks, and in packages with
a large number of dependencies this was taking a long time.&lt;/p&gt;

&lt;p&gt;Running DTrace to count totals of execnames showed:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ dtrace -n 'syscall::exece:return { @num[execname] = count(); }'
  [...]
  grep                                                             94
  sort                                                            164
  nbsed                                                           241
  mkdir                                                           399
  bash                                                            912
  cat                                                            3893
  ln                                                             7631
  rm                                                             7766
  dirname                                                        7769&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Looking through the code showed a number of ways to reduce the large number of
forks happening here&lt;/p&gt;

&lt;h3 id=&quot;cat---echo&quot;&gt;cat -&amp;gt; echo&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;cat&lt;/code&gt; was being used to generate a &lt;code class=&quot;highlighter-rouge&quot;&gt;sed&lt;/code&gt; script, which sections such as:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
s|^&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;\(/[^&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_sep&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;]*\.la[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_sep&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;]\)|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$2&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;\1|g
s|^&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;\(/[^&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_sep&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;]*\.la\)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$|$2&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;\1|g
EOF&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There’s no need to fork here, we can just use the builtin &lt;code class=&quot;highlighter-rouge&quot;&gt;echo&lt;/code&gt; command instead:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s|^&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/[^&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_sep&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]*&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;la[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_sep&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$2&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;|g&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s|^&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/[^&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_sep&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]*&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;la&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$|$2&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;|g&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;use-shell-substitution-where-possible&quot;&gt;Use shell substitution where possible&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;dirname&lt;/code&gt; commands were being operated on full paths to files, and in this
case we can simply use POSIX shell substitution instead, i.e.:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nb&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;dirname&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;becomes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;nb&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;%/*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Again, this saves a fork each time.  This substitution isn’t always possible,
for example if you have trailing slashes, but in our case we were sure that
&lt;code class=&quot;highlighter-rouge&quot;&gt;$file&lt;/code&gt; was correctly formed.&lt;/p&gt;

&lt;h3 id=&quot;test-before-exec&quot;&gt;Test before exec&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;rm&lt;/code&gt; commands were being unconditionally executed in a loop:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;file&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
	&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;
	..create file..
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is an expensive operation when you are running it on thousands of files
each time, so simply test for the file first and use a cheap (and builtin)
&lt;code class=&quot;highlighter-rouge&quot;&gt;stat(2)&lt;/code&gt; call instead of forking an expensive &lt;code class=&quot;highlighter-rouge&quot;&gt;unlink(2)&lt;/code&gt; for the majority of
cases.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;file&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
	if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
		&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
	..create file..
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;At this point we had removed most of the forks, with DTrace confirming:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ dtrace -n 'syscall::exece:return { @num[execname] = count(); }'
  [...]
  [ full output snipped for brevity ]
  grep                                                             94
  cat                                                             106
  sort                                                            164
  nbsed                                                           241
  mkdir                                                           399
  bash                                                            912
  ln                                                             7631&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The result was a big improvement, going from this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ptime bmake wrapper
&lt;span class=&quot;go&quot;&gt;  real     2:26.094442113
  user       32.463077360
  sys      1:48.647178135&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;to this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ptime bmake wrapper
&lt;span class=&quot;go&quot;&gt;  real       49.648642097
  user       14.952946135
  sys        33.989975053&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Again note, not only are we reducing the overall runtime, but the system time
is significantly less, improving overall throughput and reducing contention on
the build zones.&lt;/p&gt;

&lt;h3 id=&quot;batch-up-commands&quot;&gt;Batch up commands&lt;/h3&gt;

&lt;p&gt;The most recent changes I’ve been working on have been to further reduce forks
both by caching results and batching up commands where possible.  Taking the
previous example again, the &lt;code class=&quot;highlighter-rouge&quot;&gt;ln&lt;/code&gt; commands are a result of a loop similar to:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;src dst&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
	&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;..modify src..
	&lt;span class=&quot;nv&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;..modify dst..
	&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$src&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dst&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Initially I didn’t see any way to optimise this, but upon reading the &lt;code class=&quot;highlighter-rouge&quot;&gt;ln&lt;/code&gt;
manpage I observed the second form of the command which allows you to symlink
multiple files into a directory at once, for example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /one /two /three &lt;span class=&quot;nb&quot;&gt;dir&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;dir&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;lrwxr-xr-x 1 jperkin staff 4 Oct  3 15:40 one -&amp;gt;&lt;/span&gt; /one
&lt;span class=&quot;gp&quot;&gt;lrwxr-xr-x 1 jperkin staff 6 Oct  3 15:40 three -&amp;gt;&lt;/span&gt; /three
&lt;span class=&quot;gp&quot;&gt;lrwxr-xr-x 1 jperkin staff 4 Oct  3 15:40 two -&amp;gt;&lt;/span&gt; /two&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As it happens, this is ideally suited to our task as &lt;code class=&quot;highlighter-rouge&quot;&gt;$src&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;$dst&lt;/code&gt; will for
the most part have the same basename.&lt;/p&gt;

&lt;p&gt;Writing some &lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt; allows us to batch up the commands and do something like
this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;src dst&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
	&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;..modify src..
	&lt;span class=&quot;nv&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;..modify dst..
	&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$src&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$dst&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;: &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-awk&quot; data-lang=&quot;awk&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;srcfile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;destfile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;destdir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/.*&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\/&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;srcfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/.*&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\/&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;destfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\/[^\/]&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;destdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;# &lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;# If the files have the same name, add them to the per-directory list&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;# and use the 'ln file1 file2 file3 dir/' style, otherwise perform a&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;# standard 'ln file1 dir/link1' operation.&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;srcfile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;destfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;destdir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;destdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;destdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot; &quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;destdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;renames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;# Keep a list of directories we've seen, so that we can batch them up&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;# into a single 'mkdir -p' command.&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;destdir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;seendirs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;seendirs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;destdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dirs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;dirs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dirs&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot; &quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;destdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
			&lt;span class=&quot;nx&quot;&gt;dirs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;destdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;# Print output suitable for piping to sh.&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dirs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;mkdir -p &quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dirs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dir&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ln -fs &quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot; &quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ln -fs &quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot; &quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;s1&quot;&gt;' | sh&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There’s an additional optimisation here too - we keep track of all the
directories we need to create, and then batch them up into a single &lt;code class=&quot;highlighter-rouge&quot;&gt;mkdir -p&lt;/code&gt;
command.&lt;/p&gt;

&lt;p&gt;Whilst this adds a considerable amount of code to what was originally a simple
loop, the results are certainly worth it.  The time for &lt;code class=&quot;highlighter-rouge&quot;&gt;bmake wrapper&lt;/code&gt; in
kde-workspace4 which has a large number of dependencies (and therefore symlinks
required) reduces from 2m11s to just 19 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batching wrapper creation: 7x speedup&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;cache-results&quot;&gt;Cache results&lt;/h3&gt;

&lt;p&gt;One of the biggest recent wins was in a piece of code which checks each ELF
binary’s &lt;code class=&quot;highlighter-rouge&quot;&gt;DT_NEEDED&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;DT_RPATH&lt;/code&gt; to ensure they are correct and that we have
recorded the correct dependencies.  Written in awk there were a couple of
locations where it forked a shell to run commands:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-awk&quot; data-lang=&quot;awk&quot;&gt;&lt;span class=&quot;nx&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;pkg_info -Fe &quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;getline&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pkg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;test -f &quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;These were in functions that were called repeatedly for each file we were
checking, and in a large package there may be lots of binaries and libraries
which need checking.  By caching the results like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-awk&quot; data-lang=&quot;awk&quot;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pkgcache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;pkg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pkgcache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;pkg_info -Fe &quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;getline&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pkg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		 &lt;span class=&quot;nx&quot;&gt;pkgcache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pkg&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;libfile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libcache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;libcache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;libfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;test -f &quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;libcache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;libfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This simple change made a massive difference!  The kde-workspace4 package
includes a large number of files to be checked, and the results went from this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ ptime bmake _check-shlibs
=&amp;gt; Checking for missing run-time search paths in kde-workspace4-4.11.5nb5

real     7:55.251878017
user     2:08.013799404
sys      5:14.145580838

$ dtrace -n 'syscall::exece:return { @num[execname] = count(); }'
dtrace: description 'syscall::exece:return ' matched 1 probe
  [...]
  greadelf                                                        298
  pkg_info                                                       5809
  ksh93                                                         95612&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;to this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ ptime bmake _check-shlibs
=&amp;gt; Checking for missing run-time search paths in kde-workspace4-4.11.5nb5

real       18.503489661
user        6.115494568
sys        11.551809938

$ dtrace -n 'syscall::exece:return { @num[execname] = count(); }'
dtrace: description 'syscall::exece:return ' matched 1 probe
  [...]
  pkg_info                                                        114
  greadelf                                                        298
  ksh93                                                          3028&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Cache awk system() results: 25x speedup&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;avoid-unnecessary-tests&quot;&gt;Avoid unnecessary tests&lt;/h3&gt;

&lt;p&gt;The biggest win so far though was also the simplest.  One of the pkgsrc tests
checks all files in a newly-created package for any &lt;code class=&quot;highlighter-rouge&quot;&gt;#!&lt;/code&gt; paths which point to
non-existent interpreters.  However, do we really need to test &lt;em&gt;all&lt;/em&gt; files?
Some packages have thousands of files, and in my opinion, there’s no need to
check files which are not executable.&lt;/p&gt;

&lt;p&gt;We went from this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
	..test &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;..&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;  real     1:36.154904091
  user       17.554778405
  sys      1:10.566866515&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;to this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
	..test &lt;span class=&quot;nv&quot;&gt;$file&lt;/span&gt;..&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;  real        2.658741177
  user        1.339411743
  sys         1.236949825&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Again DTrace helped in identifying the hot path (30,000+ &lt;code class=&quot;highlighter-rouge&quot;&gt;sed&lt;/code&gt; calls in this
case) and narrowing down where to concentrate efforts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Only test shebang in executable files: ~50x speedup&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;miscellaneous-system-improvements&quot;&gt;Miscellaneous system improvements&lt;/h2&gt;

&lt;p&gt;Finally, there have been some other general improvements I’ve implemented over
the past few months.&lt;/p&gt;

&lt;h3 id=&quot;bash---dash&quot;&gt;bash -&amp;gt; dash&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;dash&lt;/code&gt; is renowned as being a leaner, faster shell than &lt;code class=&quot;highlighter-rouge&quot;&gt;bash&lt;/code&gt;, and I’ve
certainly observed this when switching to it as the default &lt;code class=&quot;highlighter-rouge&quot;&gt;$SHELL&lt;/code&gt; in builds.
The normal concern is that there may be non-POSIX shell constructs in use, e.g.
brace expansion, but I’ve observed relatively few of these, with the results
being (prior to some of the other performance changes going in):&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Shell&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Successful packages&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Average total build time&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;bash&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;13,050&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;5hr 25m&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;dash&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;13,020&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;5hr 10m&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;It’s likely with a small bit of work fixing non-portable constructs we can
bring the package count for &lt;code class=&quot;highlighter-rouge&quot;&gt;dash&lt;/code&gt; up to the same level.  Note that the
slightly reduced package count does not explain the reduced build time, as
those failed packages have enough time to complete successfully before other
larger builds we’re waiting on are completed anyway.&lt;/p&gt;

&lt;h3 id=&quot;fix-libtool-to-use-printf-builtin&quot;&gt;Fix libtool to use printf builtin&lt;/h3&gt;

&lt;p&gt;libtool has a build-time test to see which command it should call for advanced printing:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Test print first, because it will be a builtin if present.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;X&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; print &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; X-n &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;X&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;print &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ECHO&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;X&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ECHO&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
  &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ECHO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'print -r --'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;elif &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;X&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; %s &lt;span class=&quot;nv&quot;&gt;$ECHO&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;X&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ECHO&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
  &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ECHO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'printf %s\n'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# Use this function as a fallback that always works.&lt;/span&gt;
  func_fallback_echo &lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'cat &amp;lt;&amp;lt;_LTECHO_EOF
$[]1
_LTECHO_EOF'&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;ECHO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'func_fallback_echo'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Unfortunately on SunOS, there is an actual &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/bin/print&lt;/code&gt; command, thanks to
ksh93 polluting the namespace.  libtool finds it and so prefers it over printf,
which is a problem as there is no &lt;code class=&quot;highlighter-rouge&quot;&gt;print&lt;/code&gt; in the POSIX spec, so neither dash
nor bash implement it as a builtin.&lt;/p&gt;

&lt;p&gt;Again, this is unnecessary forking that we want to fix (libtool is called a
&lt;strong&gt;lot&lt;/strong&gt; during a full bulk build!)  Thankfully pkgsrc makes this easy - we can
just create a broken &lt;code class=&quot;highlighter-rouge&quot;&gt;print&lt;/code&gt; command which will be found before
&lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/bin/print&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;nl&quot;&gt;.PHONY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create-print-wrapper&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;post-wrapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create-print-wrapper&lt;/span&gt;
&lt;span class=&quot;nl&quot;&gt;create-print-wrapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PRINTF&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#!/bin/sh\nfalse\n'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;WRAPPER_DIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/bin/print
	&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CHMOD&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; +x &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;WRAPPER_DIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/bin/print&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;saving us millions of needless execs.&lt;/p&gt;

&lt;h3 id=&quot;parallelise-where-possible&quot;&gt;Parallelise where possible&lt;/h3&gt;

&lt;p&gt;There are a couple of areas where the pkgsrc bulk build was single threaded:&lt;/p&gt;

&lt;h4 id=&quot;initial-package-tools-bootstrap&quot;&gt;Initial package tools bootstrap&lt;/h4&gt;

&lt;p&gt;It was possible to speed up the bootstrap phase by adding custom &lt;code class=&quot;highlighter-rouge&quot;&gt;make -j&lt;/code&gt;
support, reducing the time by a few minutes.&lt;/p&gt;

&lt;h4 id=&quot;package-checksum-generation&quot;&gt;Package checksum generation&lt;/h4&gt;

&lt;p&gt;Checksum generation was initially performed at the end of the build running
across all of the generated packages, so an obvious fix for this was to perform
individual package checksum generation in each build chroot after the package
build had finished and then simply gather up the results at the end.&lt;/p&gt;

&lt;h4 id=&quot;pkg_summarygz-generation&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_summary.gz&lt;/code&gt; generation&lt;/h4&gt;

&lt;p&gt;Similarly for &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_summary.gz&lt;/code&gt; we can generate individual per-package &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_info
-X&lt;/code&gt; output and then collate it at the end.&lt;/p&gt;

&lt;p&gt;Optimising these single-threaded sections of the build resulted in around 20
minutes being taken off the total runtime.&lt;/p&gt;

&lt;h1 id=&quot;summary&quot;&gt;Summary&lt;/h1&gt;

&lt;p&gt;The most recent build with all these improvements integrated together is
&lt;a href=&quot;http://mail-index.netbsd.org/pkgsrc-bulk/2014/10/01/msg011025.html&quot;&gt;here&lt;/a&gt;,
showing a full from-scratch bulk build taking under 5 hours to build over
14,000 packages.  We’ve come a long way since 2004:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Date&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Package Builds&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Total Build Time (hours)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2004/05&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2,938&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;322&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2010/05&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;6,849&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;100.5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2012/07&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;10,554&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;166.5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2012/10&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;10,634&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;48&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2013/06&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;11,372&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;18&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2014/08&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;14,017&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;12&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;2014/10&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;14,162&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;4.5&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;We’ve achieved this through a number of efforts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Distributed builds to scale across multiple hosts.&lt;/li&gt;
  &lt;li&gt;Chrooted builds to scale on individual hosts.&lt;/li&gt;
  &lt;li&gt;Tweaking &lt;code class=&quot;highlighter-rouge&quot;&gt;make -j&lt;/code&gt; according to per-package effectiveness.&lt;/li&gt;
  &lt;li&gt;Replacing scripts with C implementations in critical paths.&lt;/li&gt;
  &lt;li&gt;Reducing forks by caching, batching commands, and using shell builtins where
possible.&lt;/li&gt;
  &lt;li&gt;Using faster shells.&lt;/li&gt;
  &lt;li&gt;Parallelising single-threaded sections where possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What’s next?  There are plenty of areas for further improvements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Improved scheduling to avoid builds with high &lt;code class=&quot;highlighter-rouge&quot;&gt;MAKE_JOBS&lt;/code&gt; from sharing the
same build zone.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;make(1)&lt;/code&gt; variable caching between sub-makes.&lt;/li&gt;
  &lt;li&gt;Replace &lt;code class=&quot;highlighter-rouge&quot;&gt;/bin/sh&lt;/code&gt; on illumos (ksh93) with dash (even if there is no appetite
for this upstream, thanks to chroots we can just mount it as &lt;code class=&quot;highlighter-rouge&quot;&gt;/bin/sh&lt;/code&gt; inside
each chroot!)&lt;/li&gt;
  &lt;li&gt;Dependency graph analysis to focus on packages with the most dependencies.&lt;/li&gt;
  &lt;li&gt;Avoid the “long tail” by getting the final few large packages building as
early as possible.&lt;/li&gt;
  &lt;li&gt;Building in memory file systems if build size permits.&lt;/li&gt;
  &lt;li&gt;Avoid building multiple copies of libnbcompat during bootstrap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many thanks to Jörg for writing pbulk and cwrappers, Google for sponsoring the
pbulk GSoC , the pkgsrc developers for all their hard work in adding and
updating packages, and of course Joyent for employing me to work on this stuff.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A node.js-powered 8-bit CPU - part four</title>
      <link>//www.perkin.org.uk/posts/a-nodejs-powered-8-bit-cpu-part-four.html</link>
      <pubDate>Wed, 04 Dec 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/a-nodejs-powered-8-bit-cpu-part-four.html</guid>
      <description>&lt;p&gt;This post is part four of a series, the other posts available are&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-one.html&quot;&gt;Part one - introduction and GPIO&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-two.html&quot;&gt;Part two - shift registers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-three.html&quot;&gt;Part three - the CPU&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In part two we constructed a circuit using shift registers whereby we could
write a byte of data and then read it back in.  In part three we booted a 6309
CPU and ran it with a hard-coded operation on the data bus.  In this final
post, we will put the two together so that we can write arbitrary data onto the
data bus and then read back any results.&lt;/p&gt;

&lt;p&gt;First, we need to introduce one more 7400-series IC, the 74HC14 hex inverter.&lt;/p&gt;

&lt;h2 id=&quot;inverters&quot;&gt;Inverters&lt;/h2&gt;

&lt;p&gt;These are really simple chips, all they do is take input on a pin, and then
output the opposite onto another pin.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-74hc14-pinout.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-74hc14-pinout.jpg&quot; alt=&quot;74HC14 Pinout&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;The “A”s are input and “Y”s are output.  So, inputting a &lt;code class=&quot;highlighter-rouge&quot;&gt;0&lt;/code&gt; into 1A/Pin1
results in a &lt;code class=&quot;highlighter-rouge&quot;&gt;1&lt;/code&gt; being output from 1Y/Pin2.  No need for any clocks, just
power, and we have 6 converters available.&lt;/p&gt;

&lt;h2 id=&quot;hooking-it-all-up&quot;&gt;Hooking It All Up&lt;/h2&gt;

&lt;p&gt;Ok, let’s connect everything up.  Here’s what we need to do:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Connect the two bread boards together, with the shift register board above
the CPU board.  The bread boards have tongue and groove joints for a snug
fit.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Wire up +5V and ground rails between the two so that they both have power
from a single source.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Wire up the D0-D7 data bus from the 6309 to the data bus on the shift
register board - it is easiest to hook them in just below the green LEDs.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The GPIO pins from the Raspberry Pi are connected as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;GPIO17/Pin11 goes to Q on the 6309.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;GPIO18/Pin12 goes to E on the 6309.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;GPIO21/Pin13 goes to STCP on the 74HC595.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;GPIO22/Pin15 goes to DS on the 74HC595.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;GPIO23/Pin16 goes to Q7 on the 74HC165.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;GPIO24/Pin18 goes to RESET on the 6309.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are 4 more connections we need to make, which is where the 74HC14 comes
in.&lt;/p&gt;

&lt;h2 id=&quot;rw-on-the-6309&quot;&gt;RW On The 6309&lt;/h2&gt;

&lt;p&gt;The RW pin on the 6309 denotes whether from the 6309’s point of view the bus is
being written to or read from.  When high, the 6309 is reading, and when low,
it is writing.&lt;/p&gt;

&lt;p&gt;We can use this feature to automatically switch the OE (“output enable”) pin on
the 74HC595 on or off, so that when the 6309 is reading OE is enabled, and when
it is writing OE is disabled, leaving the data bus clear for the 6309s data.
In this way the bus can be shared between devices.&lt;/p&gt;

&lt;p&gt;However, we cannot connect them directly, as the logic is the wrong way around&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;we want OE to be low when RW is high and vice versa.  So, we use the 74HC14,
and by connecting them through pins 1A and 1Y on the 74HC14, we get the logic
we want.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;pl-on-the-74hc165&quot;&gt;PL On The 74HC165&lt;/h2&gt;

&lt;p&gt;The final connection we need to make is a way to trigger the 74HC165 to read
from the data bus, so that we can get data back into the Raspberry Pi.&lt;/p&gt;

&lt;p&gt;The solution for this is to wire the 74HC165’s PL pin to clock E on the 6309.
This isn’t immediately obvious, but is determined by careful reading of the
6309’s datasheet.  The quality of the image below isn’t great, but it shows
when data from the 6309 is valid.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-read-data.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-read-data.jpg&quot; alt=&quot;Valid Data Waveform&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;The part we are interested in is the “Data” line, and the timing when the data
is readable is the time between the Q clock going low and the E clock going
low.&lt;/p&gt;

&lt;p&gt;So, for my design, I have hooked up the PL pin to the inverse (again, going
through the 74HC14 to invert the logic) of the Q clock, using pins 2A and 2Y.
This way, whenever Q goes low, the 74HC165 reads whatever is on the data bus at
that time, and if this happens to be at a point when we want to grab data from
the 6309, it should be valid at that point in time and we then just need to
shift the data out of the 74HC165 before the next Q clock when the data will be
replaced.&lt;/p&gt;

&lt;p&gt;The finished boards should look something like this:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-board-done.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-board-done.jpg&quot; alt=&quot;Finished Boards&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;The 74HC14 is at the top left, with the orange and white jumper wires used for
the inverted connections.&lt;/p&gt;

&lt;h2 id=&quot;software&quot;&gt;Software&lt;/h2&gt;

&lt;p&gt;At this point we are done with the hardware, and can move to software.  First
we need to come up with a program, and for this I have chosen a very simple one&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;add two numbers together and return the result.  The code is below.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-nasm&quot; data-lang=&quot;nasm&quot;&gt;&lt;span class=&quot;c&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;; Add two 16-bit numbers (doubles) together.  The final version will accept&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;; arbitrary numbers on the command line, but for now we hard code two numbers&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;; which helps us to understand the opcodes.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;LDD&lt;/span&gt;	&lt;span class=&quot;err&quot;&gt;#$&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;04&lt;/span&gt;	&lt;span class=&quot;c&quot;&gt;; Load 4 into the D register (D=4)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ADDD&lt;/span&gt;	&lt;span class=&quot;err&quot;&gt;#$&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;05&lt;/span&gt;	&lt;span class=&quot;c&quot;&gt;; Add 5 to D and save the result (D=D+5)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;STD&lt;/span&gt;	&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B6B7&lt;/span&gt;	&lt;span class=&quot;c&quot;&gt;; Store the value of D to address 0xB6B7&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;By using &lt;code class=&quot;highlighter-rouge&quot;&gt;asm6809.pl&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;od&lt;/code&gt; we can look at what the instruction opcodes need
to be.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; asm6809.pl &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; 6309-adder 6309-adder.s
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;od&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; x1 6309-adder
&lt;span class=&quot;go&quot;&gt;0000000    cc  00  04  c3  00  05  fd  b6  b7
0000011&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;From this we can determine:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;0xcc&lt;/code&gt; is the opcode for &lt;code class=&quot;highlighter-rouge&quot;&gt;LDD&lt;/code&gt; with an immediate value.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;0xc3&lt;/code&gt; is the opcode for &lt;code class=&quot;highlighter-rouge&quot;&gt;ADDD&lt;/code&gt; with an immediate value.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;0xfd&lt;/code&gt; is the opcode for &lt;code class=&quot;highlighter-rouge&quot;&gt;STD&lt;/code&gt; to store at an extended address.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An immediate value is one that is used as-is for the data, rather than being an
address containing the data.  An extended address is where a full address is
specified, rather than an offset.  Different addressing modes result in
different opcodes, as the instruction needs to do different things.&lt;/p&gt;

&lt;p&gt;Now that we have our opcodes, we need to find out how many cycles each of them
take to complete.  As we are hard coding every clock cycle in this set up, it
is critical that we read and write data at exactly the right time.  The best
reference I’ve found for the 6809/6309 is
&lt;a href=&quot;http://public.logica.com/~burgins/emulator/com/m6809.html&quot;&gt;here&lt;/a&gt; and it gives
the number of bytes and clock cycles for every instruction.&lt;/p&gt;

&lt;p&gt;At this point we have all the information required, and it is a Simple Matter
Of Programming.  My script to add two arbitrary numbers using the 6309 going
via the shift registers for input and output is below.  The comments inline
hopefully explain exactly what is happening.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'rpio'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * The two numbers to add together from command line arguments.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;num1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;num2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Set up our pin mappings and configure them.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;s1&quot;&gt;'clockQ'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;s1&quot;&gt;'clockE'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;s1&quot;&gt;'clockS'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;s1&quot;&gt;'write'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;s1&quot;&gt;'read'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;s1&quot;&gt;'reset'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clockQ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clockE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clockS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setInput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Start everything low.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clockQ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clockE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clockS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Clocks - 'sixclock' for the 6309, 'shiftclock' for the shift registers.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clockQ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clockE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clockQ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clockE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;shiftclock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clockS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clockS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Shift a byte of data out to the 74HC595.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;shiftout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;// Convert the hex to a binary string&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;00000000&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;nx&quot;&gt;bits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;shiftclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;shiftclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Shift a byte of data in from the 74HC165, returning as a hex value.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;shiftin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;inbyte&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;inbyte&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;shiftclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;00&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inbyte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Convert a 16-bit number to an array of two 8-bit hexadecimals.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dec2hex16&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0000&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Initialise the 6309, starting with 10 cycles with the RESET line held down
 * to clear all state.  We then run for 3 cycles after RESET - one to load in
 * the RESET, and two to get the chip ready.
 *
 * The number of cycles required here was determined by experimentation.
 */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * At this point we are ready to read in the first address.  The 6309's RESET
 * vector is at $FFFE-$FFFF, which is the hardcoded location where it reads
 * the first address from.
 *
 * We provide the starting address of $1020, though it is somewhat arbitrary,
 * and we could use any address except for $FFF0-$FFFF which is reserved.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;shiftout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// Load address from $FFFE&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;shiftout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// Load address from $FFFF&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Jump to the first address (0x1020) that we input.  After that we can
 * start to input our first instruction.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * LDD our first number.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;lddbytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dec2hex16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;shiftout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xcc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;		&lt;span class=&quot;c1&quot;&gt;// LDD immediate&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;shiftout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lddbytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// Read in num1's high byte&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;shiftout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lddbytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// Read in num1's low byte&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * ADDD our second number.  ADDD with an immediate is a 4 cycle
 * instruction so we have an additional clock at the end.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;adddbytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dec2hex16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;shiftout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xc3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;		&lt;span class=&quot;c1&quot;&gt;// ADDD immediate&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;shiftout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;adddbytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// Read in num2's high byte&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;shiftout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;adddbytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// Read in num2's low byte&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;				&lt;span class=&quot;c1&quot;&gt;// Clock to perform ADDD operation&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * STD the result to an arbitrary memory location, in this case we have
 * chosen address $C880 but it is irrelevant as we ignore it.
 *
 * STD extended is a 6 clock instruction, with the two byte result available
 * on the data bus during cycles 5 and 6.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;shiftout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;		&lt;span class=&quot;c1&quot;&gt;// STD extended&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;shiftout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xc8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;		&lt;span class=&quot;c1&quot;&gt;// Read in $C8 high byte&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;shiftout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;		&lt;span class=&quot;c1&quot;&gt;// Read in $80 low byte&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;				&lt;span class=&quot;c1&quot;&gt;// Clock operation&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;byte1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;shiftin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;		&lt;span class=&quot;c1&quot;&gt;// Write high byte to memory&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;byte2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;shiftin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;		&lt;span class=&quot;c1&quot;&gt;// Write low byte to memory&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * We are done, output the calculation.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%d + %d = %d&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;num1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;num2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0x&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;byte1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;byte2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Reset the CPU to be nice, and to clear the LEDs.  Four clocks appear to be
 * enough to complete the reset.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;sixclock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We can run the program as follows.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; node 6309-adder.js 1 2
&lt;span class=&quot;go&quot;&gt;1 + 2 = 3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The output appears to be the correct answer.  We now have a fully functioning
co-processor attached to our Raspberry Pi ;)&lt;/p&gt;

&lt;p&gt;Of course, there are some limitations.  As we are dealing with 16-bit numbers,
we can overflow:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; node 6309-adder.js 32768 32767
&lt;span class=&quot;go&quot;&gt;32768 + 32767 = 65535
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; node 6309-adder.js 32768 32768
&lt;span class=&quot;go&quot;&gt;32768 + 32768 = 0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, adding support for that and executing arbitrary instructions is left
as an exercise for the reader!&lt;/p&gt;

&lt;p&gt;Hopefully this was interesting.  It has certainly been very useful for me to
learn exactly what is going on at the hardware level, and I’d strongly
encourage anyone involved in software development to do likewise - it gives you
a new appreciation for the operations involved in running your code.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A node.js-powered 8-bit CPU - part three</title>
      <link>//www.perkin.org.uk/posts/a-nodejs-powered-8-bit-cpu-part-three.html</link>
      <pubDate>Tue, 03 Dec 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/a-nodejs-powered-8-bit-cpu-part-three.html</guid>
      <description>&lt;p&gt;This post is part three of a series, the other posts available are&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-one.html&quot;&gt;Part one - introduction and GPIO&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-two.html&quot;&gt;Part two - shift registers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-four.html&quot;&gt;Part four - putting it all together&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In part two we constructed a circuit using shift registers whereby we could
write a byte of data and then read it back in.  In this post we are going to
look at a more complicated integrated circuit - a CPU - however the principles
are the same.&lt;/p&gt;

&lt;p&gt;In addition to the pieces required for the first two posts, you will need:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;An additional bread board.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Enough LEDs and resistors for 16 more LEDs.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A 0.1µF “smoothing” capacitor.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;An 8-bit CPU.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that said, let’s meet my chosen CPU.&lt;/p&gt;

&lt;h2 id=&quot;68096309&quot;&gt;6809/6309&lt;/h2&gt;

&lt;p&gt;One of the advantages of retro computing is that we can easily (and reasonably
cheaply) pick and choose anything we fancy, and so I’ve chosen the Hitachi
6309, specifically the HD63C09EP.  This is Hitachi’s compatible version of the
venerable 6809, which is considered by many to be the best 8-bit CPU ever made.
Hitachi made it even faster and added some new instructions and registers,
however it was developed right at the end of the 8-bit era, and with the
introduction of 16-bit CPUs soon afterwards it didn’t have time to became as
popular as its 8-bit counterparts such as the Z80, 6502 and 8008.&lt;/p&gt;

&lt;p&gt;Thankfully, it’s still possible to buy them (second hand of course), and I
managed to pick one up from &lt;a href=&quot;http://www.littlediode.com/&quot;&gt;littlediode.com&lt;/a&gt; for
around £20.&lt;/p&gt;

&lt;p&gt;To get started, let’s look at the pinout and describe what each pin does.
Below is an ASCII diagram, with thanks to Jonathan Bowen’s 6809E manual (there
are scanned PDFs of the original datasheets but the quality is not great).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;                       _________    _________
                     _|         \__/         |_  ____
                Vss |_| 1                 40 |_| Halt  &amp;lt;--
                ___  _|                      |_
           --&amp;gt;  NMI |_| 2                 39 |_| TSC   &amp;lt;--
                ___  _|                      |_
           --&amp;gt;  IRQ |_| 3                 38 |_| LIC   --&amp;gt;
               ____  _|                      |_  _____
           --&amp;gt; FIRQ |_| 4                 37 |_| Reset &amp;lt;--
                     _|                      |_
           &amp;lt;--   BS |_| 5                 36 |_| AVMA  --&amp;gt;
                     _|                      |_
           &amp;lt;--   BA |_| 6                 35 |_| Q     &amp;lt;--
                     _|                      |_
                Vcc |_| 7                 34 |_| E     &amp;lt;--
                     _|                      |_
           &amp;lt;--   A0 |_| 8                 33 |_| Busy  --&amp;gt;
                     _|                      |_    _
           &amp;lt;--   A1 |_| 9                 32 |_| R/W   --&amp;gt;
                     _|                      |_
           &amp;lt;--   A2 |_| 10      6809E     31 |_| D0   &amp;lt;--&amp;gt;
                     _|                      |_
           &amp;lt;--   A3 |_| 11                30 |_| D1   &amp;lt;--&amp;gt;
                     _|                      |_
           &amp;lt;--   A4 |_| 12                29 |_| D2   &amp;lt;--&amp;gt;
                     _|                      |_
           &amp;lt;--   A5 |_| 13                28 |_| D3   &amp;lt;--&amp;gt;
                     _|                      |_
           &amp;lt;--   A6 |_| 14                27 |_| D4   &amp;lt;--&amp;gt;
                     _|                      |_
           &amp;lt;--   A7 |_| 15                26 |_| D5   &amp;lt;--&amp;gt;
                     _|                      |_
           &amp;lt;--   A8 |_| 16                25 |_| D6   &amp;lt;--&amp;gt;
                     _|                      |_
           &amp;lt;--   A9 |_| 17                24 |_| D7   &amp;lt;--&amp;gt;
                     _|                      |_
           &amp;lt;--  A10 |_| 18                23 |_| A15   --&amp;gt;
                     _|                      |_
           &amp;lt;--  A11 |_| 19                22 |_| A14   --&amp;gt;
                     _|                      |_
           &amp;lt;--  A12 |_| 20                21 |_| A13   --&amp;gt;
                      |______________________|&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The arrows denote whether each pin is input, output, or both.  Again, if a pin
name has a line above it, for example Halt, it means it is “active low” and the
function is activated when the pin is off/low, as opposed to being active when
the pin is on/high.&lt;/p&gt;

&lt;p&gt;The CPU is placed onto the new bread board as shown below, so that the CPU
straddles the middle of the breadboard, and the bottom side has more holes
available - this helps with wiring as we will need more connections on that
side.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-bare-cpu.jpg&quot;&gt;
    &lt;img height=&quot;280&quot; src=&quot;/files/images/nodejs-cpu-bare-cpu.jpg&quot; alt=&quot;CPU Ready For Wiring&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;We can sort the pins into logical groups, for now only concentrating on the
bare minimum required to get things running.&lt;/p&gt;

&lt;h3 id=&quot;power-vsspin1-vccpin7&quot;&gt;Power (Vss/Pin1, Vcc/Pin7)&lt;/h3&gt;

&lt;p&gt;As with the shift registers, the CPU requires 5V to operate, and so we hook
them up directly to the power rails.  “Vss” is another term for ground.&lt;/p&gt;

&lt;p&gt;One recommended addition is an 0.1µF capacitor between Vss and Vcc.  This acts
like a small power buffer, and helps to smooth out any power fluctuations,
ensuring that the CPU runs more reliably.  Without this, you may notice odd
behaviour, especially if you plug/unplug nearby electric devices.&lt;/p&gt;

&lt;p&gt;To achieve maximum effectiveness, smoothing capacitors should be placed as
close as possible to the input pins, as I’ve done in the picture below (again
using brown/blue wires to denote power):&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-power-pins.jpg&quot;&gt;
    &lt;img height=&quot;280&quot; src=&quot;/files/images/nodejs-cpu-power-pins.jpg&quot; alt=&quot;Power Pins&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;h3 id=&quot;clocks-epin34-qpin35&quot;&gt;Clocks (E/Pin34, Q/Pin35)&lt;/h3&gt;

&lt;p&gt;Again, same deal as with the shift registers - the CPU needs a ticking clock in
order to drive the internal circuitry.  The 6309 has two clocks which must be
driven in a specific order.&lt;/p&gt;

&lt;p&gt;According to the datasheet “Q must lead E; that is, a transition on Q must be
followed by a similar transition on E”.  All that means is that repeating the
following sequence is enough to drive the 6309 clock:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Set Q high&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Set E high&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Set Q low&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Set E low&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The speed at which we repeat this sequence determines the speed of the CPU.  In
the past with NMOS designs we would have had to keep running at a certain
frequency for the chip to function correctly, but with newer CMOS designs we
can run as slowly as we want, which is very helpful for seeing exactly what is
happening.&lt;/p&gt;

&lt;p&gt;By wiring E/Pin34 to GPIO17/Pin11 and Q/Pin35 to GPIO18/Pin12, we can run the
CPU at 2Hz (two clock cycles per second) using a slightly extended version of
our previous clock code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'rpio'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/* 2Hz is slow enough to see what's happening without being overly cautious */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Our repeating clock.  I've used the hour/quarter/half nomenclature as
 * a helpful visualisation of when each pin fires.  setInterval() and
 * setTimeout() take a millisecond argument, so we use parseInt() to ensure
 * no floating point.  This actually means we are limited to a clock speed
 * of 250Hz (one pin changing every millisecond) if we want a regular cycle.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* Set Q high immediately (on the hour) */&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* Set E high at quarter past the hour */&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ehigh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* Set Q low at half past the hour */&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;qlow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* Set E low at quarter to the hour */&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;data-bus-d0-7pin31-24&quot;&gt;Data Bus (D0-7/Pin31-24)&lt;/h3&gt;

&lt;p&gt;With the 6309 being an 8-bit CPU, these are the 8 data pins on which a byte of
data is read (“load”) or written (“store”) at a time.  These are the only pins
which are used for both input and output, and would normally be routed to a
static RAM chip.&lt;/p&gt;

&lt;p&gt;To get a CPU to do some work, we provide instructions (“opcodes”) and operands
(an address or a literal value) on the data bus.  Let’s start with the simplest
program possible, a call to the &lt;code class=&quot;highlighter-rouge&quot;&gt;nop&lt;/code&gt; (“No Operation”) instruction:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-nasm&quot; data-lang=&quot;nasm&quot;&gt;	&lt;span class=&quot;k&quot;&gt;nop&lt;/span&gt;	&lt;span class=&quot;c&quot;&gt;; Do nothing&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We can assemble this program using &lt;a href=&quot;http://www.6809.org.uk/&quot;&gt;Ciaran Anscomb&lt;/a&gt;’s
&lt;a href=&quot;http://www.6809.org.uk/dragon/asm6809.pl&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;asm6809.pl&lt;/code&gt;&lt;/a&gt; assembler and look at
the machine code it generated using &lt;code class=&quot;highlighter-rouge&quot;&gt;od&lt;/code&gt;.  This tells us the corresponding
opcode byte for the &lt;code class=&quot;highlighter-rouge&quot;&gt;nop&lt;/code&gt; instruction:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Assemble the source code in 6309-nop.s into an object file containing raw
: binary data.  No headers or object format data, just pure instructions.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; asm6809.pl &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; 6309-nop 6309-nop.s
&lt;span class=&quot;go&quot;&gt;
: Display the contents of the binary in single-byte hexadecimal (-t x1) format.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;od&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; x1 6309-nop
&lt;span class=&quot;go&quot;&gt;0000000    12
0000001&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So, to execute a &lt;code class=&quot;highlighter-rouge&quot;&gt;nop&lt;/code&gt; instruction on the 6309, we write &lt;code class=&quot;highlighter-rouge&quot;&gt;0x12&lt;/code&gt; onto the data
bus.&lt;/p&gt;

&lt;p&gt;In the final post I will show how we can use our shift register setup to handle
the data bus, however for now we will simply hard-code a &lt;code class=&quot;highlighter-rouge&quot;&gt;nop&lt;/code&gt; instruction on
the data bus, by wiring each bit either to the +5V or ground planes.&lt;/p&gt;

&lt;p&gt;To calculate the pin settings for writing a particular byte, I wrote a small
shell function to convert from hexadecimal to binary:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;hex2bin8&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;%08d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;16 i 2 o &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;tr &lt;/span&gt;a-z A-Z&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; p&quot;&lt;/span&gt; | dc&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;which we can use like so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; hex2bin8 12
&lt;span class=&quot;go&quot;&gt;00010010&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To execute a &lt;code class=&quot;highlighter-rouge&quot;&gt;nop&lt;/code&gt; then,  we set D1 and D4 to high and the rest to low (D0 is
the right-most bit, D7 is the left-most bit).  Below is a picture of mine,
where I am using the green/white strands of the CAT5 cable for the data bus
connections.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-data-bus.jpg&quot;&gt;
    &lt;img height=&quot;280&quot; src=&quot;/files/images/nodejs-cpu-data-bus.jpg&quot; alt=&quot;Data bus hardwired to 'nop'&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Due to the gaps on the power rails, we need to divert the D2 wire up a little
to reach the ground rail, however it should hopefully be clear which rail each
pin is connected to.&lt;/p&gt;

&lt;h3 id=&quot;address-bus-a0-a15pin8-23&quot;&gt;Address Bus (A0-A15/Pin8-23)&lt;/h3&gt;

&lt;p&gt;Whilst it is an 8-bit CPU, it has a 16-bit address bus, and so is able to
directly address up to 65536 bytes of memory.  The current address being read
from or written to is output on these pins.&lt;/p&gt;

&lt;p&gt;Again, these pins would normally be routed to some RAM chip, and by using the
address in conjunction with the data bus, we can either load or store one byte
of RAM at a time, with the address containing the particular area of memory to
load or store, and the data containing the byte to be read or written.&lt;/p&gt;

&lt;p&gt;For now, the most useful thing we can do is hook each of these pins up to an
LED.  By doing this we can simply show what address the CPU is currently at,
even if it does mean converting from binary to hex.&lt;/p&gt;

&lt;p&gt;Here is mine, using orange wire strips to denote the address bus:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-address-bus.jpg&quot;&gt;
    &lt;img height=&quot;280&quot; src=&quot;/files/images/nodejs-cpu-address-bus.jpg&quot; alt=&quot;Address bus hardwired to red LEDs&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;This can be a bit fiddly, due to the number of wires involved, but it should be
possible to wire them all up as shown.&lt;/p&gt;

&lt;p&gt;Note that the LEDs are back to front in terms of reading binary addresses.  We
could put them the other way around, but that would require a lot more cabling
and it might get messy.  This way we also match up the orientation of the data
bus.&lt;/p&gt;

&lt;p&gt;If you wanted to get fancy you could instead attach LED segment displays (or
&lt;a href=&quot;http://en.wikipedia.org/wiki/Nixie_tube&quot;&gt;nixie tubes&lt;/a&gt;!), however I do not have
any of those .. yet :)&lt;/p&gt;

&lt;h3 id=&quot;interrupts-nmipin2-irqpin3-firqpin4&quot;&gt;Interrupts (NMI/Pin2, IRQ/Pin3, FIRQ/Pin4)&lt;/h3&gt;

&lt;p&gt;These pins allow you to send hardware interrupts which interrupt the CPU’s
normal operation and execute specific functions.  These would normally be used
by something like an IO controller to indicate that, for example, some data has
been read from disk and is now available.&lt;/p&gt;

&lt;p&gt;For now we do not need any of these, so we simply disable these by hard wiring
them to +5V (they are all active-low).&lt;/p&gt;

&lt;h3 id=&quot;tscpin39&quot;&gt;TSC/Pin39&lt;/h3&gt;

&lt;p&gt;This is the Tri-State Control pin, and can be used to synchronize data with
other processors or controllers.  As we do not have any of those yet, we simply
hard wire it to GND and ensure this function is disabled.&lt;/p&gt;

&lt;h3 id=&quot;haltreset-resetpin37-haltpin40&quot;&gt;Halt/Reset (Reset/Pin37, Halt/Pin40)&lt;/h3&gt;

&lt;p&gt;These pins are mostly self-explanatory, and are both active-low.  This means
that applying a negative voltage to Reset/Pin37 makes the CPU reset, and to
Halt/Pin40 makes it pause indefinitely until Halt is released (set back to
high).&lt;/p&gt;

&lt;p&gt;For now we will keep things as simple as possible, and wire halt to +5V,
effectively disabling it.  We do however need to handle reset, as when the CPU
is first powered on it needs a reset cycle to initialise correctly.  This is
done by holding reset down for at least one clock cycle, and so we will simply
hook the reset pin to GPIO21/Pin13 and control this from software.&lt;/p&gt;

&lt;p&gt;Alternatively, you could wire up a simple binary switch and have a hard reset
button on your board.&lt;/p&gt;

&lt;h2 id=&quot;pin-summary&quot;&gt;Pin summary&lt;/h2&gt;

&lt;p&gt;So, at this stage we should have the CPU wired up as following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Power (Vss/Pin1 and Vcc/Pin7) wired to +5V and GND.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Clock E/Pin34 wired to GPIO17 (pin 11).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Clock Q/Pin35 wired to GPIO18 (pin 12).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Data bus (D0-D7/Pin31-24) wired to +5V/GND for &lt;code class=&quot;highlighter-rouge&quot;&gt;0x12&lt;/code&gt; (“nop”).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Address bus (A0-A15/Pin8-23) wired to 16 LEDs.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Interrupts (NMI/Pin2, IRQ/Pin3, FIRQ/Pin4) wired to GND.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;TSC/Pin39 wired to GND.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Reset/Pin37 wired to GPIO21 (pin 13).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Halt/Pin40 wired to +5V.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and the board should look something like this:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-board-done.jpg&quot;&gt;
    &lt;img height=&quot;280&quot; src=&quot;/files/images/nodejs-cpu-board-done.jpg&quot; alt=&quot;Completed Board&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;h2 id=&quot;software&quot;&gt;Software&lt;/h2&gt;

&lt;p&gt;We can extend our clock example above and add handling of the reset pin:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'rpio'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Bump this to 2Hz from the clock example.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Start with the reset pin held low while we start up the clock.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// The clock function is the same as before.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ehigh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

	&lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;qlow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

	&lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Ensure we run the clock at least once, then set the reset pin back high,
 * releasing the CPU to execute normally.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resethigh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;start-it-up&quot;&gt;Start It Up!&lt;/h2&gt;

&lt;p&gt;We now have everything in place to get the CPU running.  Below is a video of
mine, running at 2Hz.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;iframe width=&quot;640&quot; height=&quot;400&quot; src=&quot;https://www.youtube.com/embed/cO5izX-90rg?rel=0&quot; frameborder=&quot;0&quot;&gt;
  &lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;At this point we can see and explain what happens right at the start of a CPU’s
execution.  I’ve trimmed the first second or so from the video where the CPU is
running through its pre-initialisation routine.  The video starts at the point
where the CPU is reading the very first instructions from memory.&lt;/p&gt;

&lt;p&gt;The 6309 starts by reading a byte each from &lt;code class=&quot;highlighter-rouge&quot;&gt;0xFFFE&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;0xFFFF&lt;/code&gt;, and this
gives it the first 16-bit address to read from.  You can see these first two
addresses shown by the LEDs at the beginning of the video.  Remember that the
address LEDs are back-to-front, so the least-significant bit is on the left,
not the right.&lt;/p&gt;

&lt;p&gt;Ordinarily there would be a ROM handling this part, and it would direct the CPU
to start reading an area it has set aside to store a basic operating system.
Once the address has been loaded, the CPU jumps to it and starts reading
instructions.&lt;/p&gt;

&lt;p&gt;As we are hard-coding the data bus with &lt;code class=&quot;highlighter-rouge&quot;&gt;0x12&lt;/code&gt;, the first address that the CPU
jumps to is &lt;code class=&quot;highlighter-rouge&quot;&gt;0x1212&lt;/code&gt;, shown by the &lt;code class=&quot;highlighter-rouge&quot;&gt;00010010&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;00010010&lt;/code&gt; on the LEDs.  At this
“address” the CPU again reads data from the data bus ready for its first
instruction, and of course gets another &lt;code class=&quot;highlighter-rouge&quot;&gt;0x12&lt;/code&gt;.  This time it is executed as a
&lt;code class=&quot;highlighter-rouge&quot;&gt;nop&lt;/code&gt; instruction, where the CPU does nothing for an instruction cycle.&lt;/p&gt;

&lt;p&gt;This pattern then continues indefinitely:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;The CPU increments the memory location where it should fetch the current
instruction from.  This is known as the “program counter” or “instruction
pointer”.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The CPU reads an instruction from that location, in our case always reading
&lt;code class=&quot;highlighter-rouge&quot;&gt;0x12&lt;/code&gt; which is its opcode for the &lt;code class=&quot;highlighter-rouge&quot;&gt;nop&lt;/code&gt; instruction.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;nop&lt;/code&gt; is executed, i.e. nothing happens.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sure, it’s not practically useful.  However, we are powering this entirely from
JavaScript, we can see exactly what is happening, and for me at least it is
immensely helpful having a visual overview of exactly how a CPU works.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-four.html&quot;&gt;next and final step&lt;/a&gt; is
to make the data bus controllable, so that we can issue arbitrary instructions
and read back results.  If only we had some way of reading and writing 8 bits
of data using only a couple of GPIO pins… ;)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A node.js-powered 8-bit CPU - part two</title>
      <link>//www.perkin.org.uk/posts/a-nodejs-powered-8-bit-cpu-part-two.html</link>
      <pubDate>Mon, 02 Dec 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/a-nodejs-powered-8-bit-cpu-part-two.html</guid>
      <description>&lt;p&gt;This post is part two of a series, the other posts available are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-one.html&quot;&gt;Part one - introduction and GPIO&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-three.html&quot;&gt;Part three - the CPU&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-four.html&quot;&gt;Part four - putting it all together&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In part one we reached the stage where we were able to control an LED from
node.js.  We’re now going to move forward and control some simple Integrated
Circuits (ICs).  The principles are the same - using GPIO to turn pins on and
off - but we use more pins to control something a bit more complicated.&lt;/p&gt;

&lt;p&gt;The ICs we will look at in this post come from the &lt;a href=&quot;http://en.wikipedia.org/wiki/7400_series&quot;&gt;7400
series&lt;/a&gt; family of chips, which
provide a whole variety of logic functions.&lt;/p&gt;

&lt;p&gt;In addition to the pieces we needed for the introduction, you will need:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Enough LEDs and resistors for 8 lights.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Some wire for creating custom jumper lengths (I use CAT5 cable).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A
&lt;a href=&quot;http://uk.farnell.com/nxp/74hc595n/ic-74hc-cmos-shift-reg-5v-16dip/dp/3166028&quot;&gt;74HC595N&lt;/a&gt;
and
&lt;a href=&quot;http://uk.farnell.com/nxp/74hc165n/ic-8bit-shift-register-16dip/dp/380635&quot;&gt;74HC165N&lt;/a&gt;
shift registers (the ‘N’ denotes that these are
&lt;a href=&quot;http://en.wikipedia.org/wiki/Dual_in-line_package&quot;&gt;DIP&lt;/a&gt; and suitable for our
bread board)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The shift registers can be bought very cheaply, most chips in the 7400 series
cost less than a pound each.&lt;/p&gt;

&lt;p&gt;Before we start, I prepare the breadboard like the picture below, where we
configure both power rails with +5V (red jumper wire going to 5V/Pin2) and
ground (black jumper wire going to GND/Pin6) to the Pi.  The brown and blue
wires come from a CAT5 cable, trimmed with wire cutters to fit, and are
colour-coded to conform to &lt;a href=&quot;http://en.wikipedia.org/wiki/IEC_60446&quot;&gt;IEC 60446&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-power-lines.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-power-lines.jpg&quot; alt=&quot;Power lines&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;This allows us to easily bridge across to individual pins lower down the board.&lt;/p&gt;

&lt;p&gt;I use CAT5 cable as it is a good size for the bread board, is strong enough to
insert into the board yet flexible enough to be shaped to particular angles.
It’s also really helpful that you get 8 different colour combinations to choose
from, so that you can choose particular colours for specific functions, e.g.
power, data, address, etc.  However you could just use a lot of jumper wires if
you prefer, they would certainly be quicker to set up.&lt;/p&gt;

&lt;h2 id=&quot;shift-registers&quot;&gt;Shift Registers&lt;/h2&gt;

&lt;p&gt;A shift register is an integrated circuit which is designed for
serial-to-parallel or parallel-to-serial communication.  Let’s dive straight in
and take a look at an 8-bit serial-to-parallel shift register - the trusty
74HC595.&lt;/p&gt;

&lt;p&gt;We start by placing the chip (be careful to avoid static electricity) onto the
middle of the bread board.  This allows us to connect to each pin, with the gap
down the middle of the bread board used to separate each side.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-74hc595-board.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-74hc595-board.jpg&quot; alt=&quot;74HC595 On Bread Board&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Once we have done that, we need to look at the datasheet which explains the
function of each of the pins.  The full version is
&lt;a href=&quot;http://www.nxp.com/documents/data_sheet/74HC_HCT595.pdf&quot;&gt;here&lt;/a&gt; but for now the
only part we are concerned with is the pinout description:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-74hc595-pinout.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-74hc595-pinout.jpg&quot; alt=&quot;74HC595 Pinout&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;By connecting to these pins and setting them high or low, we can control the
function of this chip.  Let’s go through them and describe what they do.&lt;/p&gt;

&lt;h3 id=&quot;power-vccpin16-gndpin8&quot;&gt;Power (Vcc/Pin16, GND/Pin8)&lt;/h3&gt;

&lt;p&gt;These pins provide the power that the chip requires to operate.  Vcc is +5V and
Vss is ground, so we can connect these directly to the corresponding power
rails.  I use the same colours (brown and blue) as above to make the functions
of these pins clear.&lt;/p&gt;

&lt;p&gt;For the connections to the Raspberry Pi, we use the ground pin as before, and
now move our red wire over to Pin 2 which is +5V power.&lt;/p&gt;

&lt;p&gt;So, to summarise:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Pin 2 on the RPi (+5V power) to one of the pins on either “+” (red line)
power rail.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Pin 6 on the RPi (Ground) to one of the pins on either “-“ (blue line) power
rail.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A small piece of brown wire connecting the nearest +5V rail to the line of Pin
16 (Vcc).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A small piece of blue wire connecting the nearest ground rail to the line of
Pin 8 (GND).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This provides the power that the IC needs to function, now we need to start
controlling its behaviour.&lt;/p&gt;

&lt;h3 id=&quot;serial-inputoutput-dspin14-q7spin9&quot;&gt;Serial Input/Output (DS/Pin14, Q7S/Pin9)&lt;/h3&gt;

&lt;p&gt;DS is the pin where we load our input, one bit at a time, by setting it either
high or low.  Q7S is the serial output pin, and is useful if you want to tie
two 74HC595s together to form one 16-bit register, by taking the output of Q7S
and feeding it to the DS input of the second 74HC595.&lt;/p&gt;

&lt;p&gt;As we are only using one IC for now we can ignore Q7S.  We want to input data
though, so hook the DS pin to GPIO17, that is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Pin 11 on the RPi (GPIO17) to Pin 14 on the 74HC595 (DS).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can leave the Q7S pin unconnected as it is used solely for output, though
for your own experimentation you may want to hook it up and read the values
while following the rest of this post.&lt;/p&gt;

&lt;h3 id=&quot;parallel-out-q0-q7pin151-7&quot;&gt;Parallel Out (Q0-Q7/Pin15,1-7)&lt;/h3&gt;

&lt;p&gt;Once 8 bits of input have been loaded in, those 8 bits can then be output
simultaneously on the parallel out pins.  This gives us our serial-to-parallel
conversion.&lt;/p&gt;

&lt;p&gt;In order to show the output of these pins, we will hook them up to 8 LEDs.
Start by laying out the LEDs on the board and insert a resistor for each,
connecting between the ground rail and the cathode line, like so:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-74hc595-leds.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-74hc595-leds.jpg&quot; alt=&quot;74HC595 LEDs&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Next, cut and strip 8 lengths of wire and hook them up to their corresponding
parallel output pin.  In the picture below I have wired them up so that the LED
furthest away is Q7 and the LED closest to the IC is Q0 (which is located on
the other side, so the wire needs to go around the top of the IC).&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-74hc595-led-wires.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-74hc595-led-wires.jpg&quot; alt=&quot;74HC595 LED Wires&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;The reasons for doing it this way around will become clear later on, but for
now note that in this orientation it means that if we shift in e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;00001111&lt;/code&gt;,
the LEDs will show &lt;code class=&quot;highlighter-rouge&quot;&gt;11110000&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;clocks-shcppin11-stcppin12&quot;&gt;Clocks (SHCP/Pin11, STCP/Pin12)&lt;/h3&gt;

&lt;p&gt;Clocks are what get any integrated circuit running, with each tick/tock of a
clock pin driving the internal circuitry.  All that is required to generate a
clock cycle is to switch a pin on and then off again.  The speed at which a pin
is cycled determines the speed at which the chip functions.&lt;/p&gt;

&lt;p&gt;The 74HC595 contains two 8-bit storage registers, and each has its own
independent clock for loading data.  The diagram below is helpful for having a
visual overview of how the chip is connected.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-74hc595-diagram.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-74hc595-diagram.jpg&quot; alt=&quot;74HC595 functional diagram&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Data is read in from DS, using the SHCP clock to load one bit per clock cycle.
After doing this 8 times, the data we want to load is now ready in the “8-stage
shift register” shown above.&lt;/p&gt;

&lt;p&gt;To load the 8-bits from the shift register into the storage register, a single
clock cycle is required on the STCP clock.  As soon as that happens, the data
is latched into the “8-bit storage register”.&lt;/p&gt;

&lt;p&gt;For simplicity, we will connect the two clock pins together, using a small
piece of wire running vertically and joining the two lines.  By doing this we
can drive both clocks simultaneously from a single GPIO pin on the Raspberry
Pi, which simplifies our software.&lt;/p&gt;

&lt;p&gt;This means that on every clock cycle the data is copied from the shift register
into the storage register, but this is helpful as it shows the data being
loaded in.&lt;/p&gt;

&lt;p&gt;To control the clocks from software, we wire either SHCP or STCP to pin 12
(GPIO18) on the Raspberry Pi.&lt;/p&gt;

&lt;h3 id=&quot;master-reset-mrpin10&quot;&gt;Master Reset (MR/Pin10)&lt;/h3&gt;

&lt;p&gt;MR is useful if you just want to clear (set all to &lt;code class=&quot;highlighter-rouge&quot;&gt;0&lt;/code&gt;) the shift register, by
setting it low for one clock cycle, rather than shifting in &lt;code class=&quot;highlighter-rouge&quot;&gt;0&lt;/code&gt; on the DS pin
for 8 clock cycles.&lt;/p&gt;

&lt;p&gt;You’ll note the line above MR on the diagrams above.  This denotes that this
pin is “active low”, which means that its function is enabled when the pin is
off, whereas all the other pins we have seen so far are “active high”, and they
are active or enabled when on.&lt;/p&gt;

&lt;p&gt;We don’t need to use this pin, so for now it is simply wired high (i.e.
connected to the +5V power rail) and thus disabled.&lt;/p&gt;

&lt;h3 id=&quot;output-enable-oepin13&quot;&gt;Output Enable (OE/Pin13)&lt;/h3&gt;

&lt;p&gt;OE controls whether the data in the storage register is displayed on the
parallel output.  Again this is an “active low” pin, and for now we simply wire
this low, to always enable output.&lt;/p&gt;

&lt;h2 id=&quot;wiring-it-all-up&quot;&gt;Wiring it all up.&lt;/h2&gt;

&lt;p&gt;At this point we have something which looks like this:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-74hc595-wired.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-74hc595-wired.jpg&quot; alt=&quot;74HC595 Wired Up&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;To summarise the various connections:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Power is provided to the bread board power rails from pin 2 (+5V) and pin 6
(GND) on the Pi.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Power is provided to the 74HC595 to pin 16 (Vcc, +5V) and pin 8 (GND) to the
appropriate power rails using small strips of brown and blue wire.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;DS is serial input and is wired using the green jumper wire to pin 11
(GPIO17) on the Pi.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;STCP and SHCP are the clocks, and are joined together with a small piece of
orange wire.  One of them is then chosen (in my picture it is STCP) and
connected using a yellow wire to GPIO18 (pin 12).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The parallel output pins (Q0-Q7) are hooked up to green LEDs using lengths of
green wire.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The MR “master reset” pin 10 is hard wired to the +5V power rail to disable
it (active low).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The OE “output enable” pin 13 is hard wired to the ground rail to enable it
(active high).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only pin which should be left unconnected is Q7S, unless you wish to hook
it up to a spare GPIO pin on the Pi and verify what it is being set to at
various points.&lt;/p&gt;

&lt;h2 id=&quot;software&quot;&gt;Software&lt;/h2&gt;

&lt;p&gt;We now write a small script to write some bits into the shift register.  We
start by setting up the two pins we want to control, and then we define an
array which contains the bits we want to send into the chip.&lt;/p&gt;

&lt;p&gt;One part which may be confusing is that we have one extra bit at the end of the
input array.  The reason for this is due to the clocks being linked together.
According to the datasheet “If both clocks are connected together, the shift
register will always be one clock pulse ahead of the storage register.”  This
means we need an extra clock cycle to update the storage register.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'rpio'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pinDS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pinClk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pinDS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pinClk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Start with the clock pin low&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pinClk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * This is what we want to send through the shift register - start with
 * all zeros to clear the buffer, then insert 10110111, with a final bit
 * to clock in the storage register.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For our clock function we will use something similar to the blinking LED
example I showed in the first post, except this time on each “blink” we pop the
first bit of input onto the DS pin.  This loads the bit in, and we repeat until
the input array is empty.&lt;/p&gt;

&lt;p&gt;We can configure the clock speed with a variable - see the comment below.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/*
 * Configure the speed in Hz.  setInterval() and setTimeout have a maximum
 * resolution of 1ms, and we need a regular clock, so with each 'tick' and
 * 'tock' at a max of 1ms intervals our theoretical top speed is 500Hz.
 *
 * The 74HC595 is rated to 52MHz so we are in no danger of overclocking ;)
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/*
	 * Pop the first bit of input into DS.  If there is no more
	 * input then exit.
	 */&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pinDS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/*
	 * Then cycle the clock at regular intervals, starting by setting it
	 * high then setting a timeout for half way until the next interval
	 * when we set it low.
	 */&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pinClk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;clocklow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pinClk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;ship-it&quot;&gt;Ship It!&lt;/h2&gt;

&lt;p&gt;Running the program at 1Hz allows us to clearly see what happens, as shown in
the video below.  Prior to running the program and taking the video I set all
the bits high, so that it is clear what happens when the first 8 zeros are
shifted in.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;iframe width=&quot;640&quot; height=&quot;400&quot; src=&quot;https://www.youtube.com/embed/SrBOMqwiL8E?rel=0&quot; frameborder=&quot;0&quot;&gt;
  &lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;That’s about it for the 74HC595, they are simple but incredibly useful devices.&lt;/p&gt;

&lt;p&gt;And, as you might expect, there is a similar chip for doing parallel-to-serial
conversion…&lt;/p&gt;

&lt;h2 id=&quot;74hc165&quot;&gt;74HC165&lt;/h2&gt;

&lt;p&gt;The 74HC165 is an 8-bit parallel-to-serial IC, and pretty similar to the
74HC595.  There are just a few differences we can note from the diagrams below:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-74hc165-diagram.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-74hc165-diagram.jpg&quot; alt=&quot;74HC165 Diagram&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Unlike the 74HC595 there is no separate storage register, the data is loaded
straight into the shift register and can then be read out.&lt;/p&gt;

&lt;p&gt;We will hook it up to our bread board and use it to read the data from the
74HC595.  Here is the pinout:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-74hc165-pinout.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-74hc165-pinout.jpg&quot; alt=&quot;74HC165 Pinout&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;And the pins we are concerned with are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Vcc/Pin16 and GND/Pin8 are our power pins, hook up the same as before.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;D0-3/Pins11-14 and D4-7/Pins3-6 are the 8 parallel inputs.  We connect D0 to
the same LED that Q0 from the 74HC595 is output to, D1 to Q1 etc., all the
way up to D7 to Q7.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;PL/Pin1 is the active low “parallel load” pin, and when active reads 8-bits
of data from the parallel input lines into the shift register.  Afterwards,
set it high and read out the data.  We want to hook this up to pin 13
(GPIO21/27) on the Pi.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Q7/Pin9 is the serial output pin where we read data from, and we hook this up
to pin 15 (GPIO22) on the Pi.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;CP/Pin2 is the clock for reading data out.  CE/Pin15 is an active low clock
enable.  As we can use the PL pin to control when to load the parallel input,
we do not need a separate clock for this chip and can simply link it to the
74HC595 clock with a jumper wire.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DS/Pin10 and Q7/Pin7 are serial input/output pins, and can be useful for
daisy-chaining, however we have no need for them, and can leave them
unconnected.&lt;/p&gt;

&lt;p&gt;After performing all of the connections above, it should look something like
this:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-74hc165-board.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-74hc165-board.jpg&quot; alt=&quot;74HC165 On Board&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;As for software, the program below takes a single argument of a byte of data,
loads it into the 74HC595, then reads it out from our data bus using the
74HC165 before displaying the two for comparison.  If everything went well, the
two bytes should be identical.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'rpio'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * The byte we will write and hopefully read back.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;outbyte&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Set up our pin mappings and configure them.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;s1&quot;&gt;'output'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;s1&quot;&gt;'clock'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;s1&quot;&gt;'pload'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;s1&quot;&gt;'input'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setInput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * The clock and parallel read pins are triggered on a transition
 * to high, so we start with them low.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Function to cycle (high then low) a specified pin.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cycle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Ensure that our output is converted to binary and is padded.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;outbyte&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;00000000&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;outbyte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Shift the output onto the 'DS' pin one bit at a time followed by
 * a clock to load it into the shift register.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;outbyte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * If the shift and storage clocks are connected, as they are in our setup,
 * then the storage clock will always trail the shift clock by one pulse, so
 * we need to do one final cycle to syncronise it with our input.
 *
 * We can then cycle the parallel load pin to clock the data into the 74HC165.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Finally, read in the data from the 74HC165, one bit at a time.  As we have
 * read the data from the 74HC595 we can ignore the fact that these clock
 * cycles will now &quot;corrupt&quot; the 74HC595's storage with whatever the last bit
 * we set pin.output to.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;inbyte&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;inbyte&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;cycle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Convert both bytes to hexadecimal and print our final sanity check.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;outbyte&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;outbyte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;send: 0x%s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;00&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;outbyte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;inbyte&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inbyte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;recv: 0x%s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;00&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;inbyte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The output should look like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; node shifty.js 0xb7
&lt;span class=&quot;go&quot;&gt;send: 0xb7
recv: 0xb7&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Congratulations!  You have added 8 bits of storage to your computer! ;)&lt;/p&gt;

&lt;p&gt;As you may appreciate, the 7400 series of chips can be incredibly useful,
somewhat like lego where you can use them for building blocks into larger
things.  One engineer has even used them exclusively to build an &lt;a href=&quot;http://www.homebrewcpu.com/&quot;&gt;entire
computer&lt;/a&gt; - including creating a custom CPU!&lt;/p&gt;

&lt;p&gt;I’m not quite that adventurous, so in the &lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-three.html&quot;&gt;next
post&lt;/a&gt; I will use an existing
CPU and show how we can drive it in a similar way to the shift registers above.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>A node.js-powered 8-bit CPU - part one</title>
      <link>//www.perkin.org.uk/posts/a-nodejs-powered-8-bit-cpu-part-one.html</link>
      <pubDate>Sun, 01 Dec 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/a-nodejs-powered-8-bit-cpu-part-one.html</guid>
      <description>&lt;p&gt;This post is part one of a series, the other posts available are&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-two.html&quot;&gt;Part two - shift registers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-two.html&quot;&gt;Part three - the CPU&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-two.html&quot;&gt;Part four - putting it all together&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;As a child growing up in the 1980s, I was naturally drawn towards the 8-bit
computers of the day.  I spent most of my early childhood on my Atari 400 and
Amstrad CPC 6128, as well as being familiar with the Spectrum, Acorn Electron,
and BBC Model B computers owned by my friends.&lt;/p&gt;

&lt;p&gt;Other than the occasional bit of BASIC and CP/M, however, I was not at the time
that interested in how they worked (I was too busy playing games), and so never
took the chance to learn assembly and electronics at that crucial early age.&lt;/p&gt;

&lt;p&gt;This is something I’ve always regretted, and so recently I’ve found myself more
and more interested in revisiting those older systems.  While computers today
are far more capable and many orders of magnitude faster than those early
systems, they have also become significantly more complicated.  Nowadays, even
if you are curious about exactly how they work, they just are not as accessible
to answer those questions in the same way that computers from my childhood are.&lt;/p&gt;

&lt;p&gt;As a result, there is today quite a large homebrew community, with people
building their own 8-bit systems.  One of my favourites is Matthew Sarnoff’s
&lt;a href=&quot;http://www.msarnoff.org/6809/&quot;&gt;Ultim809&lt;/a&gt; computer, and his work inspired me to
have a go myself.&lt;/p&gt;

&lt;p&gt;Realistically, with a busy job and a family, I’m never going to be able to get
to the level of Matthew’s work, however I’ve had a lot of fun working on the
bits I’ve done so far, and wanted to share it so hopefully others can learn
too.&lt;/p&gt;

&lt;p&gt;So, in these posts we’re going to get to the stage where we can drive an 8-bit
CPU from a Raspberry Pi, using node.js (but any language will suffice).  To
start with, we need to introduce GPIO.&lt;/p&gt;

&lt;h2 id=&quot;gpio&quot;&gt;GPIO&lt;/h2&gt;

&lt;p&gt;Quoting &lt;a href=&quot;http://en.wikipedia.org/wiki/General-purpose_input/output&quot;&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;“General-purpose input/output (GPIO) is a generic pin on an integrated circuit
(commonly called a chip) whose behaviour (including whether it is an input or
output pin) can be controlled (programmed) by the user at run time.”&lt;/p&gt;

&lt;p&gt;Essentially you can think of GPIO pins as small power switches which you can
turn on or off.  On the Raspberry Pi they provide 3.3V, and in our first simple
example we are going to control an LED from one.&lt;/p&gt;

&lt;p&gt;Here’s what you will need to follow along:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;A &lt;a href=&quot;http://www.amazon.co.uk/Raspberry-Pi-RBCA000-1176JZF-S-Motherboard/dp/B008PT4GGC&quot;&gt;Raspberry Pi&lt;/a&gt;
(or similar system with user-programmable GPIO) running Linux.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A &lt;a href=&quot;http://www.amazon.co.uk/BB830-Solderless-Plug--BreadBoard-tie-points/dp/B0040Z4QN8&quot;&gt;BreadBoard&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Some &lt;a href=&quot;http://www.amazon.co.uk/SODIAL-Yellow-Assorted-Emitting-Diodes/dp/B00E34MNYU&quot;&gt;LEDs&lt;/a&gt;,
preferably green, yellow, and red.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Some &lt;a href=&quot;http://www.amazon.co.uk/Conductor-Female-Jumper-Color-Ribbon/dp/B00ATMHU52&quot;&gt;jumper wire&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Some &lt;a href=&quot;http://www.amazon.co.uk/Carbon-Resistor-0-25w-270-270R/dp/B004S0X9YC&quot;&gt;270 Ohm (Ω) resistors&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s take a quick look at the bread board.  These allow fast and re-usable
construction of electronic circuits, and are laid out in rows - the verticals
down the side are for power (positive and negative), and each horizontal row is
for individual components.  In the diagram below, the power lines are indicated
by the red and blue boxes, and the component lines by the green boxes.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-bread-board.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-bread-board.jpg&quot; alt=&quot;Bread Board Layout&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;To construct the simplest possible electronic circuit, wire up the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;An LED vertically, with the anode (positive) above and the cathode (negative)
below.  To determine the correct orientation the bottom side is usually flat,
and/or the anode is longer.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A jumper wire going from pin 1 on the Raspberry Pi (this is the +3.3V line)
to a socket on the positive line.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A jumper wire going from pin 6 on the Raspberry Pi (ground) to the blue
(ground) power rail.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A 270Ω resistor connecting the ground rail to the cathode line.  The resistor
is required to reduce the voltage from 3.3V down to the 2.0V or so that the
LED needs - without it the LED will likely burn brightly for a short time
before blowing.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Doing this should give you a lit LED, and look something like this:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/nodejs-cpu-simple-led.jpg&quot;&gt;
    &lt;img src=&quot;/files/images/nodejs-cpu-simple-led.jpg&quot; alt=&quot;Simple LED&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;I’ve added annotating arrows, with the positive arrows in red and negative
arrows in blue, showing the direction of current.&lt;/p&gt;

&lt;p&gt;This is a good check that everything is working correctly, now let’s move on to
make it software controlled.  To do that, move the red jumper wire from pin 1
to go to pin 11 instead.  This is known as &lt;code class=&quot;highlighter-rouge&quot;&gt;GPIO17&lt;/code&gt; (there are different
numbering schemes for the pins depending on whether you use the physical layout
or the chipset’s view - see
&lt;a href=&quot;http://elinux.org/images/2/2a/GPIOs.png&quot;&gt;http://elinux.org/images/2/2a/GPIOs.png&lt;/a&gt;
for the full layout).&lt;/p&gt;

&lt;h2 id=&quot;software&quot;&gt;Software&lt;/h2&gt;

&lt;p&gt;To turn it on or off, let’s get node up and running.  If you don’t already have
it installed, grab the latest stable version for &lt;code class=&quot;highlighter-rouge&quot;&gt;linux-arm-pi&lt;/code&gt; from
&lt;a href=&quot;http://nodejs.org/dist&quot;&gt;http://nodejs.org/dist&lt;/a&gt; (latest as of writing is
&lt;a href=&quot;http://nodejs.org/dist/v0.10.21/node-v0.10.21-linux-arm-pi.tar.gz&quot;&gt;v0.10.21&lt;/a&gt;):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: You will need to be root to install and use the rpio module.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; http://nodejs.org/dist/v0.10.21/node-v0.10.21-linux-arm-pi.tar.gz
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tar &lt;/span&gt;zxf node-v0.10.21-linux-arm-pi.tar.gz &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; /usr/local
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/local/node-v0.10.21-linux-arm-pi/bin:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Next, install my &lt;a href=&quot;https://npmjs.org/package/rpio&quot;&gt;rpio&lt;/a&gt; module.  There are a
number of GPIO modules available, however mine appears to be the only one which
links against the &lt;a href=&quot;http://www.open.com.au/mikem/bcm2835/&quot;&gt;bcm2835&lt;/a&gt; library
rather than going via the much slower &lt;code class=&quot;highlighter-rouge&quot;&gt;/sys&lt;/code&gt; file system interface.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; rpio&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, write this JavaScript to a file named &lt;code class=&quot;highlighter-rouge&quot;&gt;led-on.js&lt;/code&gt;…&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Load the rpio module&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'rpio'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Configure pin 11 (GPIO17) for output (i.e. read/write).&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Turn GPIO17 on, also known as 'high'.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;…and run it…&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; node led-on.js&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;…which should result in the LED being lit.  You could then create an
&lt;code class=&quot;highlighter-rouge&quot;&gt;led-off.js&lt;/code&gt; which is a copy of &lt;code class=&quot;highlighter-rouge&quot;&gt;led-on.js&lt;/code&gt; except changing this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Turn GPIO17 on (1), also known as 'high'.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;to this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Turn GPIO17 off (0), also known as 'low'.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and then we have a script which will turn the LED off.&lt;/p&gt;

&lt;p&gt;For our final example, we can use &lt;code class=&quot;highlighter-rouge&quot;&gt;setInterval()&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;setTimeout()&lt;/code&gt; to
implement a blinking LED:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'rpio'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setOutput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * Blink the LED quickly (10 times per second).  It is switched on every
 * 100ms, and a timeout is set for 50ms later to switch it off, giving us
 * the regular blink.
 */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;blink&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ledoff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;rpio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here’s a video of my setup running this script.&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;iframe width=&quot;640&quot; height=&quot;400&quot; src=&quot;https://www.youtube.com/embed/tspC6ly4ZUw?rel=0&quot; frameborder=&quot;0&quot;&gt;
  &lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;This covers the introduction to GPIO and getting started with using node to
control pins.&lt;/p&gt;

&lt;p&gt;If you wanted to stay at this level and experiment further, you could use a few
more of the GPIO pins to control additional LEDs, perhaps adding a yellow and a
green for some traffic lights.  I’ve &lt;a href=&quot;https://twitter.com/jperkin/status/310385020818825216&quot;&gt;done
this&lt;/a&gt; with my kids and
it’s a great way for them to play with electronics.  My
&lt;a href=&quot;https://github.com/jperkin/pilights&quot;&gt;pilights&lt;/a&gt; repository on GitHub gives them
an easy to use shell script interface, with some example programs to get
started.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;/posts/a-nodejs-powered-8-bit-cpu-part-two.html&quot;&gt;next post&lt;/a&gt; we move on
to control something a little more complicated.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>MDB support for Go</title>
      <link>//www.perkin.org.uk/posts/mdb-support-for-go.html</link>
      <pubDate>Thu, 21 Nov 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/mdb-support-for-go.html</guid>
      <description>&lt;p&gt;Last week was Joyent Engineering’s inaugural hackathon, where we spent a couple
of days together in San Francisco working in small teams on projects which
interested us and were at least in some way relevant to our business.&lt;/p&gt;

&lt;p&gt;Whilst the obvious choice for me would have been to work on something which
used Manta for pkgsrc analysis (no shortage of ideas or potential there), I
wanted to take advantage of being in the same room as my illustrious co-workers
and work on something a bit more low-level and personally challenging.&lt;/p&gt;

&lt;p&gt;For the past few months Aram Hăvărneanu has been doing some amazing work
porting &lt;a href=&quot;https://bitbucket.org/4ad/go-sunos&quot;&gt;Go to SunOS&lt;/a&gt;, and we wanted to
help out.  So, while &lt;a href=&quot;http://dtrace.org/blogs/bmc/&quot;&gt;Bryan&lt;/a&gt; and
&lt;a href=&quot;http://blog.sysmgr.org/&quot;&gt;Josh&lt;/a&gt; got stuck in with Go core and
&lt;a href=&quot;http://dtrace.org/blogs/brendan/&quot;&gt;Brendan&lt;/a&gt; started cooking up some Go-related
DTrace, I ventured into MDB land to add support for Go stack traces.&lt;/p&gt;

&lt;p&gt;At this point you should go and read &lt;a href=&quot;http://dtrace.org/blogs/dap/&quot;&gt;Dave&lt;/a&gt;’s
excellent &lt;a href=&quot;http://dtrace.org/blogs/dap/2013/11/20/understanding-dtrace-ustack-helpers/&quot;&gt;post on stack traces&lt;/a&gt;,
as it provides a lot of background material and was super helpful for me whilst
working on this.  Done?  Ok.&lt;/p&gt;

&lt;h2 id=&quot;c-stack-traces&quot;&gt;C Stack Traces&lt;/h2&gt;

&lt;p&gt;Let’s start by looking at a contrived example in C.  Here is the code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;stdio.h&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;printout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%d -&amp;gt; %d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;addone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;printout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;addone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;atoi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Compile it with no optimisations to ensure we do not lose any functions to
inlining.  The &lt;code class=&quot;highlighter-rouge&quot;&gt;-g&lt;/code&gt; isn’t strictly necessary for these examples, but is good
practise nonetheless.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gcc &lt;span class=&quot;nt&quot;&gt;-O0&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; test.c &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; test-c&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now we can show a stack trace using MDB.  Comments inline:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ mdb ./test-c

#
# Print a disassembly of the printout() function.  We want to set a break
# point where the stack pointer (`%rsp`) and frame pointer (`%rbp`) have been
# callee saved, so that the stack trace is accurate.  If we simply set the
# break point to the beginning of printout() the stack trace would not show
# the addone() call.
#
# I include the '-b' argument to ::dis to show real address in addition to
# the symbolic ones.
#
&amp;gt; printout::dis -b
401058    printout:             pushq  %rbp
401059    printout+1:           movq   %rsp,%rbp
40105c    printout+4:           subq   $0x10,%rsp
401060    printout+8:           movl   %edi,-0x4(%rbp)
401063    printout+0xb:         movl   %esi,-0x8(%rbp)
401066    printout+0xe:         movl   -0x8(%rbp),%edx
401069    printout+0x11:        movl   -0x4(%rbp),%eax
40106c    printout+0x14:        movl   %eax,%esi
40106e    printout+0x16:        movl   $0x401130,%edi
401073    printout+0x1b:        movl   $0x0,%eax
401078    printout+0x20:        call   -0x21d   &amp;lt;PLT:printf&amp;gt;
40107d    printout+0x25:        leave
40107e    printout+0x26:        ret

#
# Set a break point of the call to printf() within printout()
#
&amp;gt; printout+20::bp

#
# Run the program with an argument of '6'.
#
&amp;gt; ::run 6
mdb: stop at printout+0x20
mdb: target stopped at:
printout+0x20:  call   -0x21d   &amp;lt;PLT:printf&amp;gt;

#
# Print out a stack trace, including stack addresses ('$C').  Using '$c' would
# show just the function calls.
#
&amp;gt; $C
fffffd7fffdff310 printout+0x20()
fffffd7fffdff330 addone+0x1d()
fffffd7fffdff350 main+0x2e()
fffffd7fffdff360 _start+0x6c()

#
# Print out the status of all registers.
#
&amp;gt; ::regs
%rax = 0x0000000000000000       %r8  = 0xfffffd7fffdff596
%rbx = 0xfffffd7fff3fafd8       %r9  = 0xfffffd7fff331ee3
%rcx = 0x0000000000000000       %r10 = 0x0000000000000000
%rdx = 0x0000000000000007       %r11 = 0x00000000000000c0
%rsi = 0x0000000000000006       %r12 = 0x0000000000000000
%rdi = 0x0000000000401130       %r13 = 0x0000000000000000
                                %r14 = 0x0000000000000000
                                %r15 = 0x0000000000000000

%cs = 0x0053    %fs = 0x0000    %gs = 0x0000
%ds = 0x0000    %es = 0x0000    %ss = 0x004b

%rip = 0x0000000000401078 printout+0x20
%rbp = 0xfffffd7fffdff310
%rsp = 0xfffffd7fffdff300

%rflags = 0x00000286
  id=0 vip=0 vif=0 ac=0 vm=0 rf=0 nt=0 iopl=0x0
  status=&amp;lt;of,df,IF,tf,SF,zf,af,PF,cf&amp;gt;

%gsbase = 0x0000000000000000
%fsbase = 0xfffffd7fff172a40
%trapno = 0x3
   %err = 0x0

#
# Print out the contents of the stack in memory.
#
&amp;gt; 0xfffffd7fffdff300,70::dump
                   \/ 1 2 3  4 5 6 7  8 9 a b  c d e f  v123456789abcdef
fffffd7fffdff300:  00000000 00000000 07000000 06000000  ................
fffffd7fffdff310:  30f3dfff 7ffdffff 9c104000 00000000  0.........@.....
fffffd7fffdff320:  50f3dfff 7ffdffff 280936ff 06000000  P.......(.6.....
fffffd7fffdff330:  50f3dfff 7ffdffff cc104000 00000000  P.........@.....
fffffd7fffdff340:  78f3dfff 7ffdffff 78f3dfff 02000000  x.......x.......
fffffd7fffdff350:  60f3dfff 7ffdffff ec0e4000 00000000  `.........@.....
fffffd7fffdff360:  00000000 00000000 00000000 00000000  ................

#
# Print the contents of %rdi.
#
&amp;gt; 401130::dump
         \/ 1 2 3  4 5 6 7  8 9 a b  c d e f  v123456789abcdef
401130:  2564202d 3e202564 0a000000 00000000  %d -&amp;gt; %d........

#
# Print the instruction pointers saved on the stack, with one instruction
# either side for context.
#
&amp;gt; 40109c::dis -b -n 1
401097    addone+0x18:                          call   -0x44    &amp;lt;printout&amp;gt;
40109c    addone+0x1d:                          leave
40109d    addone+0x1e:                          ret
&amp;gt; 4010cc::dis -b -n 1
4010c7    main+0x29:                            call   -0x4d    &amp;lt;addone&amp;gt;
4010cc    main+0x2e:                            leave
4010cd    main+0x2f:                            ret&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;From the output we can match up a few things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;The instruction pointer &lt;code class=&quot;highlighter-rouge&quot;&gt;%rip&lt;/code&gt; is set to our break point, and you can see
both the real (&lt;code class=&quot;highlighter-rouge&quot;&gt;0x401078&lt;/code&gt;) and the symbolic (&lt;code class=&quot;highlighter-rouge&quot;&gt;printout+0x20&lt;/code&gt;) addresses.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The arguments to &lt;code class=&quot;highlighter-rouge&quot;&gt;printf()&lt;/code&gt; are passed in the registers, with &lt;code class=&quot;highlighter-rouge&quot;&gt;%rdx&lt;/code&gt; and
&lt;code class=&quot;highlighter-rouge&quot;&gt;%rsi&lt;/code&gt; containing the integers we are printing, and &lt;code class=&quot;highlighter-rouge&quot;&gt;%rdi&lt;/code&gt; containing a
pointer to the string “&lt;code class=&quot;highlighter-rouge&quot;&gt;%d -&amp;gt; %d&lt;/code&gt;” which we can see using &lt;code class=&quot;highlighter-rouge&quot;&gt;::dump&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The stack contains arguments (&lt;code class=&quot;highlighter-rouge&quot;&gt;7&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;6&lt;/code&gt;), instruction pointers (&lt;code class=&quot;highlighter-rouge&quot;&gt;40109c&lt;/code&gt;,
&lt;code class=&quot;highlighter-rouge&quot;&gt;4010cc&lt;/code&gt;) and frame pointers (&lt;code class=&quot;highlighter-rouge&quot;&gt;fffffd7fffdff330&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;fffffd7fffdff330&lt;/code&gt;).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are wondering where I am getting those addresses from, note that this is
on x86 which is little-endian, and so you need to read each byte backwards -
that is, if you have a dump line which contains a 64-bit value, a 32-bit value,
a 16-bit value and two 8-bit values, then:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;xxxxxxxxxxxxxxxx:  78f3dfff 7ffdffff 78f3dfff 0207410d  ................&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;corresponds to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;0xfffffd7fffdff378 (64-bit)&lt;/li&gt;
  &lt;li&gt;0xffdff378 (32-bit)&lt;/li&gt;
  &lt;li&gt;0x0702 (16-bit)&lt;/li&gt;
  &lt;li&gt;0x41 (8-bit)&lt;/li&gt;
  &lt;li&gt;0x0d (8-bit)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Playing around with MDB like this was super helpful for me to get a visual
representation of memory, and how functions and arguments are passed around.&lt;/p&gt;

&lt;p&gt;Thanks to the frame pointers being saved on the stack, we are able to easily
get useful stack traces by simply following them and printing each frame in
turn.&lt;/p&gt;

&lt;p&gt;At this point it’s worth mentioning the infamous GCC argument
&lt;code class=&quot;highlighter-rouge&quot;&gt;-fomit-frame-pointer&lt;/code&gt;.  If you are of a certain age, you may remember some
Linux distributions using this flag in an attempt to make programs faster.
What happens is that instead of using the frame pointer to record valuable
information about where we came from, it is instead used as a general purpose
register, and the stack information is lost.&lt;/p&gt;

&lt;p&gt;This can be verified pretty easily:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gcc &lt;span class=&quot;nt&quot;&gt;-O0&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-fomit-frame-pointer&lt;/span&gt; test.c &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; test-nofp

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mdb ./test-nofp

&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; printout+0x20::bp

&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ::run 6
mdb: stop at printout+0x20
mdb: target stopped at:
printout+0x20:  call   &lt;span class=&quot;nt&quot;&gt;-0x225&lt;/span&gt;   &amp;lt;PLT:printf&amp;gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$C&lt;/span&gt;
fffffd7fffdff350 printout+0x20&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; ::regs &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'r[ibs]p'&lt;/span&gt;
%rip &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x0000000000401068 printout+0x20
%rbp &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0xfffffd7fffdff350
%rsp &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0xfffffd7fffdff2f0&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s all we have.  &lt;code class=&quot;highlighter-rouge&quot;&gt;%rbp&lt;/code&gt; is no longer used to record the previous &lt;code class=&quot;highlighter-rouge&quot;&gt;%rsp&lt;/code&gt;,
and so after printing the current instruction, we have nowhere else to go, and
the stack is useless.&lt;/p&gt;

&lt;p&gt;Friends don’t let friends go without their frame pointers.  There is very
little to suggest that the extra register provides any performance benefits,
and the cost is way too high.  Just Say No.&lt;/p&gt;

&lt;h2 id=&quot;go-stack-traces&quot;&gt;Go Stack Traces&lt;/h2&gt;

&lt;p&gt;So, let’s look at Go.  One of the nice things about Go is that it compiles
programs down to a self-contained binary, which can then be copied around and
executed.  This may lead you to think that stack traces will simply work, as
there is no dynamic runtime stuff going on.  Well, let’s see.&lt;/p&gt;

&lt;p&gt;Let’s start with a comparative program to the one above, written in Go.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;os&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;strconv&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;printout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num1&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num2&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%d -&amp;gt; %d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;printout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strconv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Atoi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
	&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Compile it and start MDB.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go build &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; test-go test.go
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mdb ./test-go&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The first thing we notice is that we do have symbols, which is good!  We can
also show the first few instructions of our &lt;code class=&quot;highlighter-rouge&quot;&gt;printout()&lt;/code&gt; function:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&amp;gt; ::nm ! egrep 'addone|printout'
0x0000000000400c00|0x00000000000000cb|FUNC |GLOB |0x0  |1       |main.printout
0x0000000000400cd0|0x0000000000000034|FUNC |GLOB |0x0  |1       |main.addone

&amp;gt; main.printout::dis -b -n 8
400c00    main.printout:                        movq   %fs:-0x10,%rcx
400c09    main.printout+9:                      cmpq   (%rcx),%rsp
400c0c    main.printout+0xc:                    ja     +0x7     &amp;lt;main.printout+0x15&amp;gt;
400c0e    main.printout+0xe:                    call   +0x2078d &amp;lt;runtime.morestack16&amp;gt;
400c13    main.printout+0x13:                   jmp    -0x15    &amp;lt;main.printout&amp;gt;
400c15    main.printout+0x15:                   subq   $0x80,%rsp
400c1c    main.printout+0x1c:                   leaq   0x60(%rsp),%rdi
400c21    main.printout+0x21:                   xorq   %rax,%rax
400c24    main.printout+0x24:                   movq   $0x4,%rcx&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, note that the frame pointer is never saved - the function just goes
right ahead and tries to allocate more stack.  And, indeed, if we set a
breakpoint and run the program, we do not get a useful stack trace.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&amp;gt; main.printout::bp

&amp;gt; ::run 6
mdb: stop at main.printout
mdb: target stopped at:
main.printout:  movq   %fs:-0x10,%rcx

&amp;gt; $C
8000000000000000 main.printout()&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The problem is that Go uses a completely different calling convention, so the
usual method of following frame pointers does not work.  At this point we would
normally be stuck, however Go does provide enough information in the binary for
us to calculate the stack in a different way.  We just need to dig it out.&lt;/p&gt;

&lt;p&gt;First, let’s take a look to see what the stack does contain.  I deliberately
set a breakpoint to the start of the &lt;code class=&quot;highlighter-rouge&quot;&gt;printout()&lt;/code&gt; function so that the stack
did not contain any local variables for that function.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&amp;gt; ::regs ! grep rsp
%rsp = 0xfffffd7ffef8ff00

&amp;gt; 0xfffffd7ffef8ff00,b0::dump
                   \/ 1 2 3  4 5 6 7  8 9 a b  c d e f  v123456789abcdef
fffffd7ffef8ff00:  ff0c4000 00000000 06000000 00000000  ..@.............
fffffd7ffef8ff10:  07000000 00000000 610d4000 00000000  ........a.@.....
fffffd7ffef8ff20:  06000000 00000000 01000000 00000000  ................
fffffd7ffef8ff30:  06000000 00000000 00000000 00000000  ................
fffffd7ffef8ff40:  00000000 00000000 ee364100 00000000  .........6A.....
fffffd7ffef8ff50:  c0764100 00000000 00000000 00000000  .vA.............
fffffd7ffef8ff60:  00000000 00000000 00000000 01000000  ................
fffffd7ffef8ff70:  ffffffff ffffffff 00000000 00000000  ................
fffffd7ffef8ff80:  084e5600 00000000 00000000 00000000  .NV.............
fffffd7ffef8ff90:  00000000 00000000 f05b4100 00000000  .........[A.....
fffffd7ffef8ffa0:  00000000 00000000 00000000 00000000  ................&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A few things stood out here.  Knowing the function arguments in advance allows
us to spot the various &lt;code class=&quot;highlighter-rouge&quot;&gt;7&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;6&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;1&lt;/code&gt; integers being passed, so we can take a
guess that the other addresses refer to functions, and we can confirm this with
MDB:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&amp;gt; 400cff::dis -b -n 1
400cfa    main.addone+0x2a:                     call   -0xff    &amp;lt;main.printout&amp;gt;
400cff    main.addone+0x2f:                     addq   $0x10,%rsp
400d03    main.addone+0x33:                     ret

&amp;gt; 400d61::dis -b -n 1
400d5c    main.main+0x4c:                       call   -0x91    &amp;lt;main.addone&amp;gt;
400d61    main.main+0x51:                       addq   $0x28,%rsp
400d65    main.main+0x55:                       ret

&amp;gt; 4136ee::dis -b -n 1
4136e9    runtime.main+0xe9:                    call   -0x129de &amp;lt;main.main&amp;gt;
4136ee    runtime.main+0xee:                    cmpl   $0x0,0x573868
4136f6    runtime.main+0xf6:                    je     +0x20    &amp;lt;runtime.main+0x118&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So, we can dig through the stack and find functions and arguments.  However,
because functions can have differing argument lengths, we can’t step over a
fixed size - we need to know how many arguments a function takes, so that we
know how much of the stack to skip in order to get to the next function.&lt;/p&gt;

&lt;p&gt;Thankfully, Go provides us with the answer, in the form of the pclntab.&lt;/p&gt;

&lt;p&gt;The pclntab is written into the binary by the Go linker, and contains useful
information about each function.  The format is described in &lt;a href=&quot;https://docs.google.com/document/d/1lyPIbmsYbXnpNj57a261hgOYVpNRcgydurVQIyZOz_o/pub&quot;&gt;this
document&lt;/a&gt;
for Go 1.2, which is the version we are targetting.&lt;/p&gt;

&lt;p&gt;Here is the beginning of the pclntab:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&amp;gt; pclntab,50::dump
         \/ 1 2 3  4 5 6 7  8 9 a b  c d e f  v123456789abcdef
524840:  fbffffff 00000108 4d060000 00000000  ........M.......
524850:  000c4000 00000000 f0640000 00000000  ..@......d......
524860:  d00c4000 00000000 58650000 00000000  ..@.....Xe......
524870:  100d4000 00000000 b0650000 00000000  ..@......e......
524880:  700d4000 00000000 10660000 00000000  p.@......f......&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you read the document above you can see and compare the pclntab header
format - we start with the magic number &lt;code class=&quot;highlighter-rouge&quot;&gt;0xfffffffb&lt;/code&gt;, followed by &lt;code class=&quot;highlighter-rouge&quot;&gt;0x0000&lt;/code&gt;.
Then &lt;code class=&quot;highlighter-rouge&quot;&gt;0x01&lt;/code&gt; for the instruction size quantum and &lt;code class=&quot;highlighter-rouge&quot;&gt;0x08&lt;/code&gt; for the size of a
pointer (both accurate for 64-bit x86).  After that we have &lt;code class=&quot;highlighter-rouge&quot;&gt;0x064d&lt;/code&gt; as the
64-bit size of the function symbol table.&lt;/p&gt;

&lt;p&gt;After the header we have pairs of function addresses to function offsets within
the pclntab.  So, for example, we start with &lt;code class=&quot;highlighter-rouge&quot;&gt;0x400c00&lt;/code&gt;, for which the
information is stored at offset &lt;code class=&quot;highlighter-rouge&quot;&gt;0x64f0&lt;/code&gt; within the pclntab.  Decoding the data
at this offset gives us the details we need.&lt;/p&gt;

&lt;p&gt;At this point we need to dig through the Go source code to find how this
information is stored, and thankfully we can mostly lift it directly into our
MDB module.&lt;/p&gt;

&lt;h2 id=&quot;mdb-module&quot;&gt;MDB Module&lt;/h2&gt;

&lt;p&gt;The current version of the MDB module is
&lt;a href=&quot;https://github.com/joyent/mdb_go&quot;&gt;here&lt;/a&gt;, you may want to follow along there.&lt;/p&gt;

&lt;p&gt;We can start by transplanting the layouts for the pclntab and Go function
information.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/*
 * The pclntab header.
 */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pctabhdr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;magic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;		&lt;span class=&quot;cm&quot;&gt;/* 0xfffffffb */&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uint16_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;		&lt;span class=&quot;cm&quot;&gt;/* 0x0000 */&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;quantum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;	&lt;span class=&quot;cm&quot;&gt;/* 1 on x86, 4 on ARM */&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ptrsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;	&lt;span class=&quot;cm&quot;&gt;/* sizeof(uintptr_t) */&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uintptr_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tabsize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;	&lt;span class=&quot;cm&quot;&gt;/* size of function symbol table */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * The function -&amp;gt; offset entries.
 */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go_func_table&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uintptr_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uintptr_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go_functbl_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*
 * The information about each function which is stored in the pclntab.
 */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go_func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uintptr_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nameoff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pcsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pcfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pcln&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;npcdata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nfuncdata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go_func_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Once we have that, we can do the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Start by loading the pclntab and checking it is valid in &lt;code class=&quot;highlighter-rouge&quot;&gt;configure()&lt;/code&gt;.  If
it is good, we store its location and size.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Get the previous instruction from the top of the stack.  In our example this
is &lt;code class=&quot;highlighter-rouge&quot;&gt;0x400cff&lt;/code&gt;, and is done using &lt;code class=&quot;highlighter-rouge&quot;&gt;load_current_context()&lt;/code&gt; which reads the
current value of &lt;code class=&quot;highlighter-rouge&quot;&gt;%rsp&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Perform a binary search through the &lt;code class=&quot;highlighter-rouge&quot;&gt;go_functbl_t&lt;/code&gt; entries for that address.
If our address is larger than the current lookup but less than the next one,
we have a match.  This is implemented in &lt;code class=&quot;highlighter-rouge&quot;&gt;findfunc()&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Read in the function information into our &lt;code class=&quot;highlighter-rouge&quot;&gt;go_func_t&lt;/code&gt; using &lt;code class=&quot;highlighter-rouge&quot;&gt;pcvalue()&lt;/code&gt; and
the information stored at our function offset.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is implemented with the &lt;code class=&quot;highlighter-rouge&quot;&gt;::goframe&lt;/code&gt; dcmd, which we can use after loading
the new &lt;code class=&quot;highlighter-rouge&quot;&gt;go.so&lt;/code&gt; module.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&amp;gt; ::load /root/mdb_go/go.so
Configured Go support

&amp;gt; ::goframe
fffffd7fffdfdf30 = {
	entry = 400cd0,
	nameoff = 6590 (main.addone),
	args = 8 (len=1),
	frame = 18,
	pcsp = 659d (delta=16),
	pcfile = 65a4 (/root/test.go),
	pcln = 65a7 (15),
	npcdata = 0,
	nfuncdata = 2,
}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that we have some additional useful information here, including the
filename and the line number.  I implemented a &lt;code class=&quot;highlighter-rouge&quot;&gt;-p name&lt;/code&gt; argument which pretty
prints this information:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&amp;gt; ::goframe -p name
main.addone(0x6)
	(in /root/test.go line 15)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The final part of the puzzle is to dig out the argument length and skip over
that size, so that we can get to the next function.  This is pretty
straight-forward, we just skip over the size of the &lt;code class=&quot;highlighter-rouge&quot;&gt;frame&lt;/code&gt; entry.&lt;/p&gt;

&lt;p&gt;With this in place we can implement an MDB “walker”, which walks our stack and
prints each address.  MDB makes this really easy, and is implemented in
&lt;code class=&quot;highlighter-rouge&quot;&gt;walk_goframes_init&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;walk_goframes_step&lt;/code&gt;, which simply describe how to
find the first frame and then how to find each subsequent frame.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&amp;gt; ::walk goframe
fffffd7ffef8ff00
fffffd7ffef8ff18
fffffd7ffef8ff48
fffffd7ffef8ff98
fffffd7ffef8ffa8&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And, for the finale, we show the beautiful modularity of MDB by simply piping
those addresses to the &lt;code class=&quot;highlighter-rouge&quot;&gt;::goframe&lt;/code&gt; dcmd:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&amp;gt; ::walk goframe | ::goframe -p name
main.addone(0x6)
	(in /root/test.go line 15)
main.main()
	(in /root/test.go line 20)
runtime.main()
	(in /root/go-sunos/src/pkg/runtime/proc.c line 199)
runtime.goexit()
	(in /root/go-sunos/src/pkg/runtime/proc.c line 1395)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And hey presto, we have a stack trace.&lt;/p&gt;

&lt;h2 id=&quot;future-work&quot;&gt;Future Work&lt;/h2&gt;

&lt;p&gt;So, as you may have noticed, I cheated a little by setting a break point to the
start of the &lt;code class=&quot;highlighter-rouge&quot;&gt;printout()&lt;/code&gt; function.  This allows us to print a full stack
trace, including the current instruction, using the &lt;code class=&quot;highlighter-rouge&quot;&gt;::gostack&lt;/code&gt; dcmd:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&amp;gt; ::gostack -p name
main.printout(0x6, 0x7)
	(in /root/test.go line 9)
main.addone(0x6)
	(in /root/test.go line 15)
main.main()
	(in /root/test.go line 20)
runtime.main()
	(in /root/go-sunos/src/pkg/runtime/proc.c line 199)
runtime.goexit()
	(in /root/go-sunos/src/pkg/runtime/proc.c line 1395)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, if we set the break point to the point where we call &lt;code class=&quot;highlighter-rouge&quot;&gt;fmt.Printf()&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;&amp;gt; main.printout+0xb5::bp

&amp;gt; ::run 6
mdb: stop at main.printout+0xb5
mdb: target stopped at:
main.printout+0xb5:     call   +0x24a26 &amp;lt;fmt.Printf&amp;gt;

&amp;gt; ::gostack -p name
main.printout(0x9, 0xfef8fee0)
	(in /root/test.go line 10)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We are unable to walk the stack, and the arguments to &lt;code class=&quot;highlighter-rouge&quot;&gt;main.printout()&lt;/code&gt; are
incorrect, due to &lt;code class=&quot;highlighter-rouge&quot;&gt;main.printout()&lt;/code&gt; allocating a bunch of the stack for its
local variables which messes up our offsets.&lt;/p&gt;

&lt;p&gt;I need to figure out how to calculate these reliably, plus there are a bunch of
cleanups to do in the module.  It’s also likely that there are lots of edge
cases where things will break.&lt;/p&gt;

&lt;p&gt;It’s also likely that the format of the symbol tables will change, so we will
need to track changes upstream.&lt;/p&gt;

&lt;p&gt;Finally, the most useful work we can do based on this initial implementation
would be to translate the same information into a DTrace ustack helper.  This
would allow us to dynamically instrument running Go programs, and do all sorts
of useful performance and debugging analysis.  The information is all there,
and we can in theory get to it using &lt;code class=&quot;highlighter-rouge&quot;&gt;uregs[]&lt;/code&gt;, but there are a number of
challenges to overcome first, most notably trying to hook into the Plan9 linker
which currently rejects DTrace ELF sections.  Help in this area would be
appreciated :)&lt;/p&gt;

&lt;p&gt;Hopefully this was a useful introduction to MDB and how to implement support
for esoteric languages.  I welcome any feedback and improvements.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>What's new in pkgsrc-2013Q2</title>
      <link>//www.perkin.org.uk/posts/whats-new-in-pkgsrc-2013Q2.html</link>
      <pubDate>Tue, 30 Jul 2013 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/whats-new-in-pkgsrc-2013Q2.html</guid>
      <description>&lt;h2 id=&quot;note&quot;&gt;Note&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This page is obsolete.&lt;/strong&gt;  Please see &lt;a href=&quot;http://pkgsrc.joyent.com/&quot;&gt;http://pkgsrc.joyent.com/&lt;/a&gt; where you
will find the latest package sets and improved instructions.&lt;/p&gt;

&lt;h2 id=&quot;original-article&quot;&gt;Original Article&lt;/h2&gt;

&lt;p&gt;The latest branch of &lt;a href=&quot;http://www.pkgsrc.org/&quot;&gt;pkgsrc&lt;/a&gt; was released at the
beginning of July, and binary packages for SmartOS/illumos and OSX are now
available.&lt;/p&gt;

&lt;p&gt;On OSX there are almost 9,000 binary packages available, whilst on illumos we
finally breached the 10,000 package mark!  Congratulations to everyone who has
worked on SunOS pkgsrc support over the past 15 years, this is a great
milestone.&lt;/p&gt;

&lt;h2 id=&quot;installing&quot;&gt;Installing&lt;/h2&gt;

&lt;p&gt;Please see the individual instruction pages for your platform:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/pages/pkgsrc-binary-packages-for-osx.html&quot;&gt;OSX&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/pages/pkgsrc-binary-packages-for-illumos.html&quot;&gt;illumos&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;whats-new&quot;&gt;What’s New&lt;/h2&gt;

&lt;p&gt;As usual there were many hundreds of changes which went into this quarterly
release of pkgsrc.  Here are some of the more interesting and useful changes.&lt;/p&gt;

&lt;h3 id=&quot;openjdk7-is-now-default&quot;&gt;OpenJDK7 is now default&lt;/h3&gt;

&lt;p&gt;Thanks to the great work by SmartOS user ‘jesse’, we now have a working
OpenJDK7 on illumos, built with GCC.  This is now the default JRE/JDK, as we
are unable to provide updated sun-{jre,jdk} packages due to Oracle’s more
restrictive redistribution policies.&lt;/p&gt;

&lt;p&gt;The only user-visible change from this is that the Java binaries are prefixed
with &lt;code class=&quot;highlighter-rouge&quot;&gt;openjdk7-&lt;/code&gt;, so call e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;openjdk7-java&lt;/code&gt; instead of &lt;code class=&quot;highlighter-rouge&quot;&gt;java&lt;/code&gt;, or
alternatively put &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local/java/openjdk7/bin&lt;/code&gt; at the front of your &lt;code class=&quot;highlighter-rouge&quot;&gt;$PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This allows co-existance with the legacy sun-{jre,jdk} packages.&lt;/p&gt;

&lt;h3 id=&quot;desktop-support&quot;&gt;Desktop support&lt;/h3&gt;

&lt;p&gt;Thanks to many Xorg updates from Richard Palo, Xorg is now functional on
illumos, enabling many common desktop environments to now be used.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Install the meta-package containing Xorg
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;modular-xorg
&lt;span class=&quot;go&quot;&gt;
: On OmniOS these are required on top of the basic install.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;driver/x11/xsvc developer/macro/cpp
&lt;span class=&quot;go&quot;&gt;
: Also on OmniOS 'od' is located in a different location
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'s,/usr/bin/od,/usr/gnu/bin/od,'&lt;/span&gt; /opt/local/bin/startx&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here are some examples and how to install them:&lt;/p&gt;

&lt;h4 id=&quot;gnome-232-with-evolution-and-firefox-22&quot;&gt;GNOME 2.32 with Evolution and Firefox 22.&lt;/h4&gt;

&lt;p&gt;Screenshot:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/2013Q2-gnome.png&quot;&gt;
    &lt;img src=&quot;/files/images/2013Q2-gnome.png&quot; alt=&quot;GNOME 2.32&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Install:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;gnome-session gnome-themes gnome-themes-extras &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
           gnome-terminal gnome-backgrounds evolution
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi .xinitrc
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;/bin/sh
&lt;span class=&quot;gp&quot;&gt;PATH=/opt/local/sbin:/opt/local/bin:$&lt;/span&gt;PATH
&lt;span class=&quot;go&quot;&gt;/opt/local/bin/gnome-session

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; startx
&lt;span class=&quot;go&quot;&gt;
: Currently the pkgsrc firefox22 fails on startup, so for now use the
: pre-built binaries from Mozilla (with some library hacks).
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; http://releases.mozilla.org/pub/mozilla.org/firefox/releases/latest/contrib/solaris_tarball/firefox-22.0.en-US.opensolaris-i386.tar.bz2 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    | bzcat | &lt;span class=&quot;nb&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-xf&lt;/span&gt; -
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /opt/local/lib/libX11.so firefox/libX11.so.4
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /opt/local/lib/libXt.so firefox/libXt.so.4
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;env &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;LD_LIBRARY_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/local/lib ./firefox/firefox&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;kde-4103&quot;&gt;KDE 4.10.3&lt;/h4&gt;

&lt;p&gt;Screenshot:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/2013Q2-kde4.png&quot;&gt;
    &lt;img src=&quot;/files/images/2013Q2-kde4.png&quot; alt=&quot;KDE 4.10.3&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Install:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;kde-runtime4 kde-workspace4 kde-baseapps4 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
           kde-wallpapers4 kde-base-artwork konsole
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi .xinitrc
&lt;span class=&quot;go&quot;&gt;/opt/local/bin/startkde&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;xfce-46-with-gnumeric-and-abiword&quot;&gt;XFCE 4.6 with Gnumeric and Abiword&lt;/h4&gt;

&lt;p&gt;Screenshot:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/2013Q2-xfce4.png&quot;&gt;
    &lt;img src=&quot;/files/images/2013Q2-xfce4.png&quot; alt=&quot;XFCE 4.6&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Install:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;xfce4 gnumeric abiword
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi .xinitrc
&lt;span class=&quot;go&quot;&gt;/opt/local/bin/xfce4-session&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;enlightenment-017-with-gimp&quot;&gt;Enlightenment 0.17 with GIMP&lt;/h4&gt;

&lt;p&gt;Screenshot:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/2013Q2-e17.png&quot;&gt;
    &lt;img src=&quot;/files/images/2013Q2-e17.png&quot; alt=&quot;Enlightenment 0.17&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Install:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;enlightenment-0.17 gimp
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi .xinitrc
&lt;span class=&quot;go&quot;&gt;/opt/local/bin/enlightenment_start&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;awesome-3413&quot;&gt;Awesome 3.4.13&lt;/h4&gt;

&lt;p&gt;And finally, for you terminal fans ;)&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;a href=&quot;/files/images/2013Q2-awesome.png&quot;&gt;
    &lt;img src=&quot;/files/images/2013Q2-awesome.png&quot; alt=&quot;Awesome 3.4.13&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Install:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;awesome
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi .xinitrc
&lt;span class=&quot;go&quot;&gt;/opt/local/bin/awesome&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;finally&quot;&gt;Finally&lt;/h2&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Distributed chrooted pkgsrc bulk builds</title>
      <link>//www.perkin.org.uk/posts/distributed-chrooted-pkgsrc-bulk-builds.html</link>
      <pubDate>Wed, 24 Jul 2013 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/distributed-chrooted-pkgsrc-bulk-builds.html</guid>
      <description>&lt;p&gt;Once you are up and running with pkgsrc, one of the most common requests is a
way to automatically build a number of packages, either a specific list plus
their dependencies, or everything currently available.&lt;/p&gt;

&lt;p&gt;There are a number of ways to accomplish this, but for this tutorial I will
concentrate on &lt;code class=&quot;highlighter-rouge&quot;&gt;pbulk&lt;/code&gt;, as it is used by a number of pkgsrc developers, and 
has support for distributed and chrooted builds.&lt;/p&gt;

&lt;p&gt;In this example I am building a set of &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc-2013Q2&lt;/code&gt; packages, and I have
tested it on:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Linux&lt;/li&gt;
  &lt;li&gt;OSX&lt;/li&gt;
  &lt;li&gt;SmartOS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please let me know if it doesn’t work correctly on your platform.&lt;/p&gt;

&lt;h2 id=&quot;layout&quot;&gt;Layout&lt;/h2&gt;

&lt;p&gt;First, have a think about where you will store pkgsrc, source tarballs,
packages, etc.  I put everything under &lt;code class=&quot;highlighter-rouge&quot;&gt;/content&lt;/code&gt; which makes it easy to then
mount just that directory and have everything below it available:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/content/bulklog&lt;/code&gt; is where pbulk saves the per-package build logs&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/content/distfiles&lt;/code&gt; is where source tarballs are kept&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/content/mk&lt;/code&gt; contains some &lt;code class=&quot;highlighter-rouge&quot;&gt;make&lt;/code&gt; fragment files for configuration&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/content/packages&lt;/code&gt; is the top-level directory of binary packages&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/content/pkgsrc&lt;/code&gt; is where pkgsrc is located&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/content/scripts&lt;/code&gt; to hold some miscellaneous scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pre-create some required directories:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /content/&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;distfiles,mk,packages/bootstrap,scripts&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then write a couple of &lt;code class=&quot;highlighter-rouge&quot;&gt;mk.conf&lt;/code&gt; files which will be used by the packaging tools.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/content/mk/mk-generic.conf&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;nv&quot;&gt;ALLOW_VULNERABLE_PACKAGES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;SKIP_LICENSE_CHECK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;		&lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;DISTDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;			/content/distfiles

&lt;span class=&quot;c&quot;&gt;# If your system has a native curl, this avoids building nbftp
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;FAILOVER_FETCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;		&lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;FETCH_USING&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;		curl

&lt;span class=&quot;c&quot;&gt;# Change this to a closer mirror
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;MASTER_SITE_OVERRIDE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	ftp://ftp2.fr.NetBSD.org/pub/NetBSD/packages/distfiles/

&lt;span class=&quot;c&quot;&gt;# Tweak this for your system, though take into account how many concurrent
# chroots you may want to run too.
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;MAKE_JOBS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;		4&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/content/mk/mk-pbulk.conf&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;err&quot;&gt;.include&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/content/mk/mk-generic.conf&quot;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;PACKAGES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	/content/packages/2013Q2/pbulk
&lt;span class=&quot;nv&quot;&gt;WRKOBJDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	/var/tmp/pkgbuild&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/content/mk/mk-pkg.conf&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;err&quot;&gt;.include&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/content/mk/mk-generic.conf&quot;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;PACKAGES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	/content/packages/2013Q2/x86_64
&lt;span class=&quot;nv&quot;&gt;WRKOBJDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	/home/pbulk/build&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;get-pkgsrc&quot;&gt;Get pkgsrc&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /content&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Either use git..&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; git clone &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; pkgsrc_2013Q2 https://github.com/joyent/pkgsrc.git&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;..or CVS&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; cvs &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; anoncvs@anoncvs.netbsd.org:/cvsroot co &lt;span class=&quot;nt&quot;&gt;-rpkgsrc-2013Q2&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-P&lt;/span&gt; pkgsrc&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;At the present time (&lt;code class=&quot;highlighter-rouge&quot;&gt;2013Q2&lt;/code&gt;) there are a couple of patches you need to apply,
one for mksandbox to support some additional features, and one for pbulk to
support chroots and a couple of other bits we’ve developed at Joyent.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;pkgsrc
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; http://www.netbsd.org/~jperkin/mksandbox-1.3.diff | patch &lt;span class=&quot;nt&quot;&gt;-p0&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; http://www.netbsd.org/~jperkin/pbulk-joyent.diff | patch &lt;span class=&quot;nt&quot;&gt;-p0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;build-pbulk&quot;&gt;Build pbulk&lt;/h2&gt;

&lt;p&gt;pbulk needs to be installed to its own prefix, from where it will manage the
main build.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;bootstrap
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./bootstrap &lt;span class=&quot;nt&quot;&gt;--abi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;64 &lt;span class=&quot;nt&quot;&gt;--prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/pbulk &lt;span class=&quot;nt&quot;&gt;--mk-fragment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/content/mk/mk-pbulk.conf
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./cleanup&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ..&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then build the necessary pacakges&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/pbulk/sbin:/usr/pbulk/bin:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;pkgtools/pbulk
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; bmake package-install
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ../mksandbox
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; bmake package-install&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It is recommended that builds are done as an unprivileged user, which is normally
named &lt;code class=&quot;highlighter-rouge&quot;&gt;pbulk&lt;/code&gt;, so now would be a good time to create that user, usually with
something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; groupadd &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; 500 pbulk
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; useradd &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; 500 &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; 500 &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'pbulk user'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /bin/bash &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; pbulk&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Check the &lt;code class=&quot;highlighter-rouge&quot;&gt;useradd/groupadd&lt;/code&gt; syntax for your system.  The user can be set to
&lt;code class=&quot;highlighter-rouge&quot;&gt;no-password&lt;/code&gt;, it will only be used via &lt;code class=&quot;highlighter-rouge&quot;&gt;su&lt;/code&gt; from the root user.&lt;/p&gt;

&lt;h2 id=&quot;set-up-chroot&quot;&gt;Set up chroot&lt;/h2&gt;

&lt;p&gt;Next, check that the mksandbox script works on your system.  It is designed to
be cross-platform, but on certain systems (e.g. OSX) there is no native support
for loopback mounts, and so you will first need to configure NFS in order to
share system directories to the chroot, usually with &lt;code class=&quot;highlighter-rouge&quot;&gt;/ -alldirs -maproot=root&lt;/code&gt;
in &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/exports&lt;/code&gt; then &lt;code class=&quot;highlighter-rouge&quot;&gt;nfsd enable&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; /chroot
&lt;span class=&quot;go&quot;&gt;
: This command should create the chroot under /chroot/test
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; mksandbox &lt;span class=&quot;nt&quot;&gt;--rodirs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/pbulk &lt;span class=&quot;nt&quot;&gt;--rwdirs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/content &lt;span class=&quot;nt&quot;&gt;--without-pkgsrc&lt;/span&gt; /chroot/test
&lt;span class=&quot;go&quot;&gt;
: This should execute a shell inside the chroot.  Check that directories are
: mounted as expected, and that you can't e.g. write to a read-only file system.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; /chroot/test/sandbox 
&lt;span class=&quot;go&quot;&gt;
: This should unmount the chroot mounts
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; /chroot/test/sandbox umount
&lt;span class=&quot;go&quot;&gt;
: Test that there are no left-over mounts before removing, else you may delete
: files on a read-write mount!  This should return no results.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; mount &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; /chroot/test/
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; /chroot/test&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Once you are happy the chroot is working as expected, write a couple of wrapper
scripts to create and delete them with an optional argument with the name of
the chroot, which will be used by pbulk.  Below are the scripts I use.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/content/scripts/mksandbox&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;chrootdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;shift

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# XXX: limited_list builds can recreate chroots too fast.&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;chrootdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
		&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Chroot &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;chrootdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; exists, retrying in 10 seconds or ^C to quit&quot;&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;10
	&lt;span class=&quot;k&quot;&gt;else
		&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;break
	&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi
done&lt;/span&gt;

/usr/pbulk/sbin/mksandbox &lt;span class=&quot;nt&quot;&gt;--without-pkgsrc&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--rodirs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/pbulk &lt;span class=&quot;nt&quot;&gt;--rwdirs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/content &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;chrootdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1
&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;chrootdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/home/pbulk
&lt;span class=&quot;nb&quot;&gt;chown &lt;/span&gt;pbulk:pbulk &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;chrootdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/home/pbulk&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/content/scripts/rmsandbox&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;chrootdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'s,/$,,'&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;shift

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;chrootdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# Try a few times to unmount the sandbox, just in case there are any&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# lingering processes holding mounts open.&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;retry &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;1 2 3
	&lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;chrootdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/sandbox umount &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1
		&lt;span class=&quot;nv&quot;&gt;mounts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;mount &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;chrootdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&quot;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mounts&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
			&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;chrootdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;break
		&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else
			&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;5
		&lt;span class=&quot;k&quot;&gt;fi
	done
fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;build-pkg-bootstrap&quot;&gt;Build pkg bootstrap&lt;/h2&gt;

&lt;p&gt;Next step is to build the bootstrap for the target packages, i.e. the main
prefix you will be using.  Again we use the bootstrap script, but here you
may want to tweak the settings - check the pkgsrc guide or the &lt;code class=&quot;highlighter-rouge&quot;&gt;--help&lt;/code&gt;
output for more information.&lt;/p&gt;

&lt;p&gt;If the prefix you want to build for (i.e. &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/pkg&lt;/code&gt;) is already in use on the
system, simply do the bootstrap inside a chroot.&lt;/p&gt;

&lt;p&gt;I use something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;/content/scripts/mksandbox /chroot/build-bootstrap
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;/chroot/build-bootstrap/sandbox
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /content/pkgsrc/bootstrap

: Use the defaults of /usr/pkg.  &lt;span class=&quot;nt&quot;&gt;--gzip-binary-kit&lt;/span&gt; is important, it is the
: tarball that pbulk will use &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;builds.
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./bootstrap &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--abi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;64 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--gzip-binary-kit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/content/packages/bootstrap/bootstrap-2013Q2-pbulk.tar.gz &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--mk-fragment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/content/mk/mk-pkg.conf
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./cleanup
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;/content/scripts/rmsandbox /chroot/build-bootstrap&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configure-pbulk&quot;&gt;Configure pbulk&lt;/h2&gt;

&lt;p&gt;Now we’re finally ready to configure pbulk.  There is a single configuration file
you need to edit, and I will show the changes I have made to it.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;diff /usr/pbulk/share/examples/pbulk/pbulk.conf /usr/pbulk/etc/pbulk.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This section adds a &lt;code class=&quot;highlighter-rouge&quot;&gt;ulimit&lt;/code&gt; to stop runaway processes from hanging the build.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;2a3,6
&amp;gt; # Limit processes to an hour of CPU time.  Anything which takes longer than
&amp;gt; # this is most probably broken.
&amp;gt; ulimit -t 3600
&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This section configures the location of the bulk build report.  I upload my
results to Joyent’s &lt;a href=&quot;http://www.joyent.com/products/manta&quot;&gt;Manta&lt;/a&gt; object store
as it allows arbitrary storage plus distributed Unix queries on the data at a
later time.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;11c15
&amp;lt; base_url=http://www.pkgsrc-box.org/reports/current/DragonFly-1.8
---
&amp;gt; base_url=http://us-east.manta.joyent.com/pkgsrc/public/reports/Darwin/2013Q2/x86_64&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Turn on &lt;code class=&quot;highlighter-rouge&quot;&gt;reuse_scan_results&lt;/code&gt;, it makes subsequent runs faster.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;14c18
&amp;lt; reuse_scan_results=no
---
&amp;gt; reuse_scan_results=yes&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In this example I am using a single host which will perform concurrent builds
inside chroots, and so I need to unset &lt;code class=&quot;highlighter-rouge&quot;&gt;scan_clients&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;build_clients&lt;/code&gt; and
set &lt;code class=&quot;highlighter-rouge&quot;&gt;master_ip&lt;/code&gt; to localhost.&lt;/p&gt;

&lt;p&gt;If you have multiple hosts, simple set &lt;code class=&quot;highlighter-rouge&quot;&gt;master_ip&lt;/code&gt; to a public address, and add
the list of slave IP addresses to &lt;code class=&quot;highlighter-rouge&quot;&gt;*_clients&lt;/code&gt;.  They will need to be accessible
via SSH as root from the master, and will need to have their own installs of
&lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/pbulk&lt;/code&gt; as well as sharing the same &lt;code class=&quot;highlighter-rouge&quot;&gt;/content&lt;/code&gt; mount as the master, most
likely over NFS.&lt;/p&gt;

&lt;p&gt;If you wish to completely disable any concurrency or distributed builds, set
&lt;code class=&quot;highlighter-rouge&quot;&gt;master_mode=no&lt;/code&gt;, though note that the build with then run completely
single-threaded and will be much slower.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;22,24c26,28
&amp;lt; master_ip=192.168.75.10
&amp;lt; scan_clients=&quot;192.168.75.21 192.168.75.22 192.168.75.23 192.168.75.24&quot;
&amp;lt; build_clients=&quot;192.168.75.21 192.168.75.22 192.168.75.23 192.168.75.24&quot;
---
&amp;gt; master_ip=127.0.0.1
&amp;gt; scan_clients=&quot;&quot;
&amp;gt; build_clients=&quot;&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you wish to publish to Manta, here are the settings you will need.  I have
installed a local copy of the Manta tools to &lt;code class=&quot;highlighter-rouge&quot;&gt;/content/manta&lt;/code&gt;, as the upload
script will need them.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;28a33,39
&amp;gt; # Manta upload settings
&amp;gt; MANTA_USER=&quot;pkgsrc&quot;
&amp;gt; MANTA_KEY_ID=&quot;40:b7:2e:b5:de:04:17:78:35:0b:d8:72:b9:da:8d:0e&quot;
&amp;gt; MANTA_URL=&quot;https://us-east.manta.joyent.com&quot;
&amp;gt; MANTA_PATH=&quot;/usr/pbulk/bin:/content/manta/node_modules/.bin&quot;
&amp;gt; report_manta_target=&quot;/pkgsrc/public/reports/Darwin/2013Q2/x86_64&quot;
&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Configure the location where to rsync packages to and where to send the report.
If you are not using Manta, then you will want to set &lt;code class=&quot;highlighter-rouge&quot;&gt;report_rsync_target&lt;/code&gt; to
an appropriate location.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;33c44
&amp;lt; pkg_rsync_target=&quot;pkgsrc@192.168.75.1:/public/packages/current/DragonFly-1.8&quot;
---
&amp;gt; pkg_rsync_target=&quot;pkgsrc.joyent.com:/packages/Darwin/2013Q2/x86_64&quot;
36,37c47,48
&amp;lt; report_subject_prefix=&quot;pkgsrc&quot;
&amp;lt; report_recipients=&quot;pkgsrc-bulk@netbsd.org&quot;
---
&amp;gt; report_subject_prefix=&quot;pkgsrc-2013Q2&quot;
&amp;gt; report_recipients=&quot;jperkin@joyent.com&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Where to find the &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/pkg&lt;/code&gt; bootstrap tarball:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;41c52
&amp;lt; bootstrapkit=/usr/pkgsrc/bootstrap/bootstrap.tar.gz
---
&amp;gt; bootstrapkit=/content/packages/bootstrap/bootstrap-2013Q2-pbulk.tar.gz&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Configure build chroots.  Here we set the paths to the &lt;code class=&quot;highlighter-rouge&quot;&gt;mksandbox&lt;/code&gt; and
&lt;code class=&quot;highlighter-rouge&quot;&gt;rmsandbox&lt;/code&gt; scripts we created earlier, and provide a basename of the chroot
directory.  By setting &lt;code class=&quot;highlighter-rouge&quot;&gt;chroot_dir=/chroot/pkgsrc-2013Q2&lt;/code&gt;, pbulk will actually
create &lt;code class=&quot;highlighter-rouge&quot;&gt;/chroot/pkgsrc-2013Q1-build-{1,2,3,4}&lt;/code&gt; and
&lt;code class=&quot;highlighter-rouge&quot;&gt;/chroot/pkgsrc-2013Q1-scan-{1,2,3,4}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You will want to experiment with the tradoffs between &lt;code class=&quot;highlighter-rouge&quot;&gt;MAKE_JOBS&lt;/code&gt; and the
number of chroots.  Generally it will be better to have more chroots compared
to an increase in &lt;code class=&quot;highlighter-rouge&quot;&gt;MAKE_JOBS&lt;/code&gt;, as certain parts of the build will be single
threaded anyway (e.g. large configure scripts).  However, you also need to be
aware of the increased disk I/O caused by too many chroots.&lt;/p&gt;

&lt;p&gt;As long as you have everything correctly shared, there is nothing stopping you
using distributed hosts &lt;em&gt;and&lt;/em&gt; chroots, and it is highly recommended if you can
as clearly it provides the best performance.  With such a setup, at Joyent we
are able to do full bulk builds of all 12,000 packages in pkgsrc in under 12
hours.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;46a58,64
&amp;gt; # Chroot scripts.
&amp;gt; chroot_create=/content/scripts/mksandbox
&amp;gt; chroot_delete=/content/scripts/rmsandbox
&amp;gt; chroot_dir=/chroot/pkgsrc-2013Q2
&amp;gt; build_chroots=4
&amp;gt; scan_chroots=4
&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, configure paths to the ones we have chosen.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;74,75c92,93
&amp;lt; bulklog=/bulklog
&amp;lt; packages=/packages
---
&amp;gt; bulklog=/content/bulklog
&amp;gt; packages=/content/packages/2013Q2/x86_64
77c95
&amp;lt; pkgsrc=/usr/pkgsrc
---
&amp;gt; pkgsrc=/content/pkgsrc&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;One option not mentioned above is &lt;code class=&quot;highlighter-rouge&quot;&gt;limited_list&lt;/code&gt;.  If you only want to build a
subset of packages rather than run a full bulk build, simply set &lt;code class=&quot;highlighter-rouge&quot;&gt;limited_list&lt;/code&gt;
to a file containing paths to packages you want.  It is worth doing this
initially anyway, just to check that everything is working fine, e.g.:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/content/mk/pkglist &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;sysutils/coreutils
EOF&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;45c45
&amp;lt; #limited_list=/limited_list
---
&amp;gt; limited_list=/content/mk/pkglist&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;run-the-bulk-build&quot;&gt;Run the bulk build&lt;/h2&gt;

&lt;p&gt;Assuming everything was done correctly, it should now just be a matter of
running the bulkbuild.  If you have set the &lt;code class=&quot;highlighter-rouge&quot;&gt;chroot_*&lt;/code&gt; variables then this will
run chrooted at the appropriate places, so that your host system’s &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/pkg&lt;/code&gt;
is not affected.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; bulkbuild&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;One of the benefits of the Joyent patch is that it adds support for different
configuration files, so if you really want to you can run concurrent instances
of pbulk.  Just write separate &lt;code class=&quot;highlighter-rouge&quot;&gt;pbulk.conf&lt;/code&gt; files and then pass them as
arguments to &lt;code class=&quot;highlighter-rouge&quot;&gt;bulkbuild&lt;/code&gt;.  Again, we use this to run multiple builds across the
same hosts, all thanks to the chroot support.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; bulkbuild pbulk-32bit.conf
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; bulkbuild pbulk-64bit.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;caveats&quot;&gt;Caveats&lt;/h2&gt;

&lt;p&gt;There are some known issues, I will document them here as they are found.&lt;/p&gt;

&lt;h3 id=&quot;osx-chroot-dns-resolution&quot;&gt;OSX chroot DNS resolution&lt;/h3&gt;

&lt;p&gt;On OSX, name resolution is broken inside a chroot.  This is due to
mDNSResponder being used for DNS lookups, which relies on the
&lt;code class=&quot;highlighter-rouge&quot;&gt;/var/run/mDNSResponder&lt;/code&gt; UNIX socket.  Unfortunately, making that socket
available in the chroot (either by mounting or creating a proxy with &lt;code class=&quot;highlighter-rouge&quot;&gt;socat&lt;/code&gt;)
does not fix the issue, so I would welcome input on this.&lt;/p&gt;

&lt;p&gt;For now you need to set &lt;code class=&quot;highlighter-rouge&quot;&gt;MASTER_SITE_OVERRIDE&lt;/code&gt; and then ensure that the IP
address for that mirror is set in &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/hosts&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;chroot-creation-race-conditions&quot;&gt;Chroot creation race conditions&lt;/h3&gt;

&lt;p&gt;As you can see in my example &lt;code class=&quot;highlighter-rouge&quot;&gt;mksandbox&lt;/code&gt; script, I have to work around a race
condition where a previous scan run may still be cleaning up whilst a new one
is starting.  For now I am simply sleeping until the chroot is free, but this
should be fixed properly, probably with process groups and waiting for them to
complete.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>pkgsrc on SmartOS - creating new packages</title>
      <link>//www.perkin.org.uk/posts/pkgsrc-on-smartos-creating-new-packages.html</link>
      <pubDate>Fri, 07 Jun 2013 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/pkgsrc-on-smartos-creating-new-packages.html</guid>
      <description>&lt;p&gt;Having &lt;a href=&quot;/posts/pkgsrc-on-smartos-zone-creation-and-basic-builds.html&quot;&gt;set up a build
zone&lt;/a&gt; and started
&lt;a href=&quot;/posts/pkgsrc-on-smartos-fixing-broken-builds.html&quot;&gt;fixing packages&lt;/a&gt;, the next
area we will look at is creating new packages.  For this tutorial I will use
&lt;a href=&quot;http://augeas.net/&quot;&gt;augeas&lt;/a&gt; as an example, as it happens to be a package I
recently created.&lt;/p&gt;

&lt;p&gt;First, install the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgtools/url2pkg&lt;/code&gt; package, as this massively simplifies the
task in hand.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: If you have pkgin and binary packages available..
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pkgin &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;url2pkg
&lt;span class=&quot;go&quot;&gt;
: ..else build from source
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;pkgtools/url2pkg&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; bmake &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then create a new package directory, choosing the most appropriate category (in
this case &lt;code class=&quot;highlighter-rouge&quot;&gt;devel&lt;/code&gt;), then run &lt;code class=&quot;highlighter-rouge&quot;&gt;url2pkg&lt;/code&gt; giving it an argument of the source
tarball.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;devel/augeas
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;devel/augeas
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; url2pkg http://download.augeas.net/augeas-1.0.0.tar.gz&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;First it will open an editor session on &lt;code class=&quot;highlighter-rouge&quot;&gt;Makefile&lt;/code&gt;.  You should customise a few
variables:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Set &lt;code class=&quot;highlighter-rouge&quot;&gt;MAINTAINER&lt;/code&gt; either to your email address, or to
&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc-users@NetBSD.org&lt;/code&gt; if you do not want to be the primary maintainer of
the package.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Write a brief one-line &lt;code class=&quot;highlighter-rouge&quot;&gt;COMMENT&lt;/code&gt; describing what the package is.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Set &lt;code class=&quot;highlighter-rouge&quot;&gt;LICENSE&lt;/code&gt; to a list of the licenses the package is made available under
(see &lt;code class=&quot;highlighter-rouge&quot;&gt;mk/license.mk&lt;/code&gt; for an available list).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what I wrote for augeas:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;c&quot;&gt;# $NetBSD$
&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;DISTNAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	augeas-1.0.0
&lt;span class=&quot;nv&quot;&gt;CATEGORIES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	devel
&lt;span class=&quot;nv&quot;&gt;MASTER_SITES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	http://download.augeas.net/

&lt;span class=&quot;nv&quot;&gt;MAINTAINER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	pkgsrc-users@NetBSD.org
&lt;span class=&quot;nv&quot;&gt;HOMEPAGE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	http://download.augeas.net/
&lt;span class=&quot;nv&quot;&gt;COMMENT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	Configuration file editing tool and library
&lt;span class=&quot;nv&quot;&gt;LICENSE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	gnu-lgpl-v2

&lt;span class=&quot;c&quot;&gt;# url2pkg-marker (please do not remove this line.)
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.include&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;../../mk/bsd.pkg.mk&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After writing the file and exiting the editor session, &lt;code class=&quot;highlighter-rouge&quot;&gt;url2pkg&lt;/code&gt; will continue
and download the source tarball, create the &lt;code class=&quot;highlighter-rouge&quot;&gt;DESCR&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;PLIST&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;distinfo&lt;/code&gt;
files, then unpack the source ready for you to start applying patches.&lt;/p&gt;

&lt;p&gt;At this point you should edit &lt;code class=&quot;highlighter-rouge&quot;&gt;DESCR&lt;/code&gt; and put in a few lines which describe the
package.&lt;/p&gt;

&lt;h2 id=&quot;build&quot;&gt;Build&lt;/h2&gt;

&lt;p&gt;The general cycle will then be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Try building the package with &lt;code class=&quot;highlighter-rouge&quot;&gt;bmake&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If something goes wrong, modify the &lt;code class=&quot;highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; or patch the source with &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgdiff&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;until the package builds.  Before running your first &lt;code class=&quot;highlighter-rouge&quot;&gt;bmake&lt;/code&gt;, I would strongly
recommend adding &lt;code class=&quot;highlighter-rouge&quot;&gt;PKG_DEVELOPER=yes&lt;/code&gt; to your &lt;code class=&quot;highlighter-rouge&quot;&gt;mk.conf&lt;/code&gt; to turn on a lot of
additional checks.&lt;/p&gt;

&lt;p&gt;For &lt;code class=&quot;highlighter-rouge&quot;&gt;augeas&lt;/code&gt;, I needed a couple of things.&lt;/p&gt;

&lt;h3 id=&quot;patches&quot;&gt;Patches&lt;/h3&gt;

&lt;p&gt;The first problem I hit was:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; bmake
&lt;span class=&quot;go&quot;&gt;[...]
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Checking &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;portability problems &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;extracted files
&lt;span class=&quot;gp&quot;&gt;ERROR: [check-portability.awk] =&amp;gt;&lt;/span&gt; Found &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; ... &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; ...:
&lt;span class=&quot;go&quot;&gt;ERROR: [check-portability.awk] configure: test &quot;`uname`&quot; == &quot;SunOS&quot; &amp;amp;&amp;amp; \

Explanation:
===========================================================================
The &quot;test&quot; command, as well as the &quot;[&quot; command, are not required to know
the &quot;==&quot; operator. Only a few implementations like bash and some
versions of ksh support it.

When you run &quot;test foo == foo&quot; on a platform that does not support the
&quot;==&quot; operator, the result will be &quot;false&quot; instead of &quot;true&quot;. This can
lead to unexpected behavior.

There are two ways to fix this error message. If the file that contains
the &quot;test ==&quot; is needed for building the package, you should create a
patch for it, replacing the &quot;==&quot; operator with &quot;=&quot;. If the file is not
needed, add its name to the CHECK_PORTABILITY_SKIP variable in the
package Makefile.
===========================================================================&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In this case pkgsrc gives us a very helpful message telling us about the
problem and what needs to be done to fix it (unfortunately not all problems are
handled this well!).  As &lt;code class=&quot;highlighter-rouge&quot;&gt;configure&lt;/code&gt; is pretty important, we’ll need to patch
it.&lt;/p&gt;

&lt;p&gt;This is my usual way of handling patches (ensuring &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgtools/pkgdiff&lt;/code&gt; is
installed first):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Set up patches directory and some useful variables.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;patches
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;patchdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-P&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;/patches
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;wrkdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;bmake show-var &lt;span class=&quot;nv&quot;&gt;VARNAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;WRKSRC&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;
: Edit file and generate patch
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$wrkdir&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgvi configure
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgdiff configure &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$patchdir&lt;/span&gt;/patch-configure
&lt;span class=&quot;go&quot;&gt;
: Return to pkgsrc directory, re-generate distinfo and try again.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; -
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; bmake clean&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; bmake mps&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; bmake&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This was enough to fix the &lt;code class=&quot;highlighter-rouge&quot;&gt;==&lt;/code&gt; problem.  I then ran into other issues.&lt;/p&gt;

&lt;h3 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h3&gt;

&lt;p&gt;Dependencies in pkgsrc are primarily handled in two ways, either with a
&lt;code class=&quot;highlighter-rouge&quot;&gt;buildlink&lt;/code&gt; file when depending upon shared libraries or particular
infrastructure, or a simple &lt;code class=&quot;highlighter-rouge&quot;&gt;DEPENDS&lt;/code&gt; line to pull in a required package.&lt;/p&gt;

&lt;p&gt;The first dependency problem I hit was:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;[...]
checking readline/readline.h usability... no
checking readline/readline.h presence... no
checking for readline/readline.h... no
checking for readline in -lreadline... no
checking for library containing tgetent... -lcurses
checking for rl_initialize in -lreadline... no
configure: WARNING: readline library not found
configure: error: Could not find a working readline library (see config.log for details).
*** Error code 1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ok, so this package depends upon readline.  As that is a library, we are
looking for a suitable &lt;code class=&quot;highlighter-rouge&quot;&gt;buildlink3.mk&lt;/code&gt; file, and one of the easiest ways to do
this is:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-1d&lt;/span&gt; ../../&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;readline&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/buildlink3.mk
&lt;span class=&quot;go&quot;&gt;../../devel/readline/buildlink3.mk&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To use that file, all we need to do is add an &lt;code class=&quot;highlighter-rouge&quot;&gt;.include&lt;/code&gt; line at the bottom of
&lt;code class=&quot;highlighter-rouge&quot;&gt;Makefile&lt;/code&gt;, just above the &lt;code class=&quot;highlighter-rouge&quot;&gt;bsd.pkg.mk&lt;/code&gt; include.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;err&quot;&gt;.include&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;../../devel/readline/buildlink3.mk&quot;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;.include&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;../../mk/bsd.pkg.mk&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After that, &lt;code class=&quot;highlighter-rouge&quot;&gt;bmake clean; bmake&lt;/code&gt; to try again.  I then hit:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;[...]
checking for LIBXML... no
configure: error: Package requirements (libxml-2.0) were not met:

No package 'libxml-2.0' found&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ok, so similar method:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-1d&lt;/span&gt; ../../&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;libxml&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/buildlink3.mk
&lt;span class=&quot;go&quot;&gt;../../textproc/libxml++/buildlink3.mk
../../textproc/libxml++1/buildlink3.mk
../../textproc/libxml/buildlink3.mk
../../textproc/libxml2/buildlink3.mk
../../textproc/py-libxml2/buildlink3.mk&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;configure&lt;/code&gt; message said libxml-2.0, so we’ll pick &lt;code class=&quot;highlighter-rouge&quot;&gt;textproc/libxml2&lt;/code&gt;.  If
you want to be more thorough you can look at the &lt;code class=&quot;highlighter-rouge&quot;&gt;PLIST&lt;/code&gt; files for each of the
possible candidate packages - I just happen to know from experience that
&lt;code class=&quot;highlighter-rouge&quot;&gt;textproc/libxml2&lt;/code&gt; is the one I need.&lt;/p&gt;

&lt;p&gt;The bottom of &lt;code class=&quot;highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; now looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;err&quot;&gt;.include&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;../../devel/readline/buildlink3.mk&quot;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;.include&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;../../textproc/libxml2/buildlink3.mk&quot;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;.include&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;../../mk/bsd.pkg.mk&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You’ll note that we try to keep all includes other than &lt;code class=&quot;highlighter-rouge&quot;&gt;bsd.pkg.mk&lt;/code&gt; (which is
special) sorted alphabetically.&lt;/p&gt;

&lt;p&gt;After this, the package finally completes a &lt;code class=&quot;highlighter-rouge&quot;&gt;bmake&lt;/code&gt; with no problems.  The
final step is to get the &lt;code class=&quot;highlighter-rouge&quot;&gt;install&lt;/code&gt; phase working.&lt;/p&gt;

&lt;h2 id=&quot;install&quot;&gt;Install&lt;/h2&gt;

&lt;p&gt;First we need to run a &lt;code class=&quot;highlighter-rouge&quot;&gt;stage-install&lt;/code&gt; which will execute &lt;code class=&quot;highlighter-rouge&quot;&gt;make install&lt;/code&gt; into a
temporary &lt;code class=&quot;highlighter-rouge&quot;&gt;DESTDIR&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; bmake stage-install&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This will almost certainly fail as we haven’t configured the &lt;code class=&quot;highlighter-rouge&quot;&gt;PLIST&lt;/code&gt; yet, so
pkgsrc has no idea what will be installed from this package.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;[...]
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Automatic manual page handling
&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Generating post-install file lists
&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Checking file-check results &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;augeas-1.0.0
&lt;span class=&quot;go&quot;&gt;ERROR: ************************************************************
ERROR: The following files are in /var/tmp/pkgsrc-build/devel/augeas/work/.destdir/opt/pkg but not in the PLIST:
ERROR:         /var/tmp/pkgsrc-build/devel/augeas/work/.destdir/opt/pkg/bin/augparse
ERROR:         /var/tmp/pkgsrc-build/devel/augeas/work/.destdir/opt/pkg/bin/augtool
[...]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, now that we have a populated &lt;code class=&quot;highlighter-rouge&quot;&gt;DESTDIR&lt;/code&gt;, we can use the &lt;code class=&quot;highlighter-rouge&quot;&gt;print-PLIST&lt;/code&gt;
target to generate it for us:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; bmake print-PLIST &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;PLIST&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, it’s worth doing a full clean and install to ensure everything works
as expected.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; bmake clean
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; bmake &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;[...]
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Creating binary package /var/tmp/pkgsrc-build/devel/augeas/work/.packages/augeas-1.0.0.tgz
&lt;span class=&quot;gp&quot;&gt;===&amp;gt;&lt;/span&gt; Install binary package of augeas-1.0.0&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;buildlink&quot;&gt;buildlink&lt;/h2&gt;

&lt;p&gt;As we are installing a library package, we should provide a &lt;code class=&quot;highlighter-rouge&quot;&gt;buildlink3.mk&lt;/code&gt;
file of our own so that other packages can depend on us correctly.  Again,
there is a package that can help with this - &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgtools/createbuildlink&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; createbuildlink &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;buildlink3.mk&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This will create a template file but you should read and edit, removing the
lines marked with &lt;code class=&quot;highlighter-rouge&quot;&gt;XXX&lt;/code&gt; and making any changes they recommend.&lt;/p&gt;

&lt;h2 id=&quot;verify&quot;&gt;Verify&lt;/h2&gt;

&lt;p&gt;Once we have a working package it’s worth doing a couple of checks to make sure
everything looks ok:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Check the package listing looks ok
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; augeas
&lt;span class=&quot;go&quot;&gt;
: View the included DESCR and homepage
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; augeas
&lt;span class=&quot;go&quot;&gt;
: Check what the package lists as its dependencies
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-N&lt;/span&gt; augeas&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We also should run &lt;code class=&quot;highlighter-rouge&quot;&gt;pkglint&lt;/code&gt; (&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgtools/pkglint&lt;/code&gt;) which will perform some
sanity checks on our infrastructure files prior to us importing the package
into pkgsrc itself.  In my case it pointed out some possible issues:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkglint
&lt;span class=&quot;go&quot;&gt;WARN: PLIST:8: Packages that install libtool libraries should define USE_LIBTOOL.
WARN: PLIST:9: Packages that install libtool libraries should define USE_LIBTOOL.
ERROR: patches/patch-configure:3: Comment expected.
1 errors and 2 warnings found. (Use -e for more details.)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For the first issue, add &lt;code class=&quot;highlighter-rouge&quot;&gt;USE_LIBTOOL=yes&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; which will ensure that
the pkgsrc libtool is used (has better support for cross-platform issues), and
for the second, add a comment at the top of the file explaining what it is for,
then re-generate &lt;code class=&quot;highlighter-rouge&quot;&gt;distinfo&lt;/code&gt; with &lt;code class=&quot;highlighter-rouge&quot;&gt;bmake mps&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After making those changes, everything looks great:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkglint
&lt;span class=&quot;go&quot;&gt;looks fine.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;upstream&quot;&gt;Upstream&lt;/h2&gt;

&lt;p&gt;The final - and sometimes most challenging - part is to get your shiny new
package integrated into pkgsrc.  There are a few options:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Find a NetBSD developer (like myself) who can review your package and put it
straight into pkgsrc.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Get a &lt;a href=&quot;http://pkgsrc-wip.sourceforge.net/&quot;&gt;pkgsrc-wip&lt;/a&gt; account and work on
 your packages there, before getting it reviewed and integrated.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If it’s somewhat niche just publish it up on GitHub or similar for people to
use, in a similar way to what we do with
&lt;a href=&quot;https://github.com/joyent/pkgsrc-joyent&quot;&gt;pkgsrc-joyent&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;further-information&quot;&gt;Further information&lt;/h2&gt;

&lt;p&gt;This post only scratches the surface of adding a new package.  pkgsrc provides
a huge amount of infrastructure to help get packages working on multiple
platforms, and there are lots of options available.&lt;/p&gt;

&lt;p&gt;Certain parts of the infrastructure, like buildlink, are very complicated, and
for more in-depth information you should refer to the &lt;a href=&quot;http://www.netbsd.org/docs/pkgsrc/&quot;&gt;pkgsrc
guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The best way is often just to look at other packages to see what they do and
re-use useful bits you find.  With 12,000 packages there is almost certainly
another package which does something similar to what you need!&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>What's new in pkgsrc-2013Q1</title>
      <link>//www.perkin.org.uk/posts/whats-new-in-pkgsrc-2013Q1.html</link>
      <pubDate>Mon, 15 Apr 2013 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/whats-new-in-pkgsrc-2013Q1.html</guid>
      <description>&lt;h2 id=&quot;note&quot;&gt;Note&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This page is obsolete.&lt;/strong&gt;  Please see &lt;a href=&quot;http://pkgsrc.joyent.com/&quot;&gt;http://pkgsrc.joyent.com/&lt;/a&gt; where you
will find the latest package sets and improved instructions.&lt;/p&gt;

&lt;h2 id=&quot;original-article&quot;&gt;Original Article&lt;/h2&gt;

&lt;p&gt;The latest branch of &lt;a href=&quot;http://www.pkgsrc.org/&quot;&gt;pkgsrc&lt;/a&gt; was released at the
beginning of April, and binary packages for SmartOS/illumos and OSX are now
available.&lt;/p&gt;

&lt;p&gt;Instructions for installing, as well as a list of the major new features in
pkgsrc-2013Q1 are below.&lt;/p&gt;

&lt;h2 id=&quot;installing&quot;&gt;Installing&lt;/h2&gt;

&lt;p&gt;The instructions are similar to previous branches.&lt;/p&gt;

&lt;h3 id=&quot;smartosillumos&quot;&gt;SmartOS/illumos&lt;/h3&gt;

&lt;p&gt;SmartOS users are encouraged to use our pre-built machine images, and
installing your choice of base/standard image with version &lt;code class=&quot;highlighter-rouge&quot;&gt;13.1.x&lt;/code&gt; (available
very soon) will get you a pkgsrc-2013Q1 based image.&lt;/p&gt;

&lt;p&gt;For general illumos users or SmartOS users who want access to a full package
set, the instructions are below:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; curl http://pkgsrc.smartos.org/packages/illumos/bootstrap/bootstrap-2013Q1-illumos.tar.gz | gtar &lt;span class=&quot;nt&quot;&gt;-zxpf&lt;/span&gt; - &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; /
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/pkg/sbin:/opt/pkg/bin:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; update
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; pkgin avail | &lt;span class=&quot;nb&quot;&gt;wc&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    9842
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; pkgin search &amp;lt;package&amp;gt;
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &amp;lt;package&amp;gt; &amp;lt;package...&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;osx&quot;&gt;OSX&lt;/h3&gt;

&lt;p&gt;Beginning with pkgsrc-2013Q1 I will now be providing regular builds for OSX.
Again, the instructions are similar to those &lt;a href=&quot;/posts/7000-packages-for-osx-lion.html&quot;&gt;previously
provided&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These packages are built on OSX Leopard (10.5) but use the &lt;code class=&quot;highlighter-rouge&quot;&gt;PREFER_PKGSRC&lt;/code&gt;
mechanism to ensure that they are portable across OSX releases, and have been
successfully tested on OSX Lion (10.7).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl http://pkgsrc.smartos.org/packages/Darwin/bootstrap/bootstrap-2013Q1-Darwin.tar.gz | &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;gnutar &lt;span class=&quot;nt&quot;&gt;-zxpf&lt;/span&gt; - &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; /
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/pkg/sbin:/usr/pkg/bin:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; update
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin avail | &lt;span class=&quot;nb&quot;&gt;wc&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    8108
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin search &amp;lt;package&amp;gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &amp;lt;package&amp;gt; &amp;lt;package...&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;whats-new&quot;&gt;What’s New&lt;/h2&gt;

&lt;p&gt;As usual there were many hundreds of changes which went into this quarterly
release of pkgsrc.  Here are some of the more interesting and useful changes.&lt;/p&gt;

&lt;h3 id=&quot;openssl-101-with-aes-ni-support&quot;&gt;OpenSSL 1.0.1 with AES-NI support&lt;/h3&gt;

&lt;p&gt;OpenSSL has been upgraded from the 0.9.8 series to the 1.0.1 series.  The
driving reason to pursue this upgrade was to take advantage of AES-NI support
which significantly improves crypto performance on Intel CPUs which provide
that feature.&lt;/p&gt;

&lt;p&gt;On my OSX 10.7 Core i7 laptop the numbers below speak for themselves:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: /usr/bin/openssl 'OpenSSL 0.9.8r 8 Feb 2011'
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; openssl speed &lt;span class=&quot;nt&quot;&gt;-evp&lt;/span&gt; aes-128-cbc
&lt;span class=&quot;go&quot;&gt;  type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
  aes-128-cbc     157297.05k   173874.73k   176805.45k   177719.17k   179441.78k

: pkgsrc openssl 'OpenSSL 1.0.1e 11 Feb 2013'
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; openssl speed &lt;span class=&quot;nt&quot;&gt;-evp&lt;/span&gt; aes-128-cbc
&lt;span class=&quot;go&quot;&gt;  type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes
  aes-128-cbc     643315.29k   685811.37k   696899.67k   699977.39k   693968.90k&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A pretty significant 4x improvement for many hundreds of applications which use
OpenSSL for crypto.&lt;/p&gt;

&lt;h3 id=&quot;gcc-go-support-for-smartosillumos&quot;&gt;GCC Go support for SmartOS/illumos&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://golang.org/&quot;&gt;Go&lt;/a&gt; is a reasonably new programming language from Google
that a number of our users have asked us to support, so we are pleased to
announce that beginning with pkgsrc-2013Q1 you will be able to use the &lt;code class=&quot;highlighter-rouge&quot;&gt;gccgo&lt;/code&gt;
front-end to compile and run Go applications on SmartOS.&lt;/p&gt;

&lt;p&gt;You simply compile the go source code as you would for any other language that
GCC supports, for example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;gcc47
&lt;span class=&quot;go&quot;&gt;
: /opt/pkg for the illumos package set, /opt/local for SmartOS datasets..
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/pkg/gcc47/bin:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; gccgo app.go &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; app
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; ./app&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;networking-utilities-on-smartos&quot;&gt;Networking utilities on SmartOS&lt;/h3&gt;

&lt;p&gt;Thanks to initial work by &lt;a href=&quot;http://twitter.com/postwait&quot;&gt;@postwait&lt;/a&gt; there is now
proper Zone support in libpcap, which has opened up the possibility to run a
number of networking utilities in Joyent SmartMachines.&lt;/p&gt;

&lt;p&gt;Yes, this means you can finally run &lt;code class=&quot;highlighter-rouge&quot;&gt;tcpdump&lt;/code&gt; instead of &lt;code class=&quot;highlighter-rouge&quot;&gt;snoop&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One of my favourites is &lt;code class=&quot;highlighter-rouge&quot;&gt;trafshow&lt;/code&gt; which is a top-like interface for network,
and looks like this:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;img src=&quot;/files/images/trafshow.png&quot; alt=&quot;trafshow screenshot&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Alternatively you can try &lt;code class=&quot;highlighter-rouge&quot;&gt;nicstat&lt;/code&gt; for a more &lt;code class=&quot;highlighter-rouge&quot;&gt;{io,mp,vm}stat&lt;/code&gt; style display.&lt;/p&gt;

&lt;h3 id=&quot;major-package-versions&quot;&gt;Major package versions&lt;/h3&gt;

&lt;p&gt;As usual there was also a slew of version updates, and the most notable package
versions are listed below.  These of course are not exhaustive lists.&lt;/p&gt;

&lt;p&gt;Development:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Clang 3.2&lt;/li&gt;
  &lt;li&gt;GCC 4.7.2&lt;/li&gt;
  &lt;li&gt;Git 1.8.1.5&lt;/li&gt;
  &lt;li&gt;Mercurial 2.5.2&lt;/li&gt;
  &lt;li&gt;Subversion 1.6.20, 1.7.8&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Languages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Lua 5.1.15&lt;/li&gt;
  &lt;li&gt;Node.js 0.8.23, 0.10.2&lt;/li&gt;
  &lt;li&gt;Ocaml 4.00.1&lt;/li&gt;
  &lt;li&gt;Oracle JRE/JDK 6.0.37, 7.0.15&lt;/li&gt;
  &lt;li&gt;Perl 5.16.2&lt;/li&gt;
  &lt;li&gt;PHP 5.3.23, 5.4.13&lt;/li&gt;
  &lt;li&gt;Python 2.6.8, 2.7.3, 3.1.5, 3.2.3, 3.3.0&lt;/li&gt;
  &lt;li&gt;R 2.15.1&lt;/li&gt;
  &lt;li&gt;Ruby 1.8.7.371, 1.9.3p392&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Web Stack:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Apache 1.3.42, 2.0.64, 2.2.24, 2.4.4&lt;/li&gt;
  &lt;li&gt;CouchDB 1.2.1&lt;/li&gt;
  &lt;li&gt;MongoDB 2.2.2&lt;/li&gt;
  &lt;li&gt;MySQL 5.0.96, 5.1.67, 5.5.30, 5.6.10&lt;/li&gt;
  &lt;li&gt;Nginx 1.2.7, 1.3.14&lt;/li&gt;
  &lt;li&gt;PostgreSQL 8.3.23, 8.4.17, 9.0.13, 9.1.9, 9.2.4&lt;/li&gt;
  &lt;li&gt;Riak 1.2.1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Desktop:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;evilwm 1.1.0&lt;/li&gt;
  &lt;li&gt;GNOME 2.32.1, 3.6.2&lt;/li&gt;
  &lt;li&gt;KDE 3.5.10, 4.8.4&lt;/li&gt;
  &lt;li&gt;XFCE 4.6.1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Installing SVR4 packages on SmartOS</title>
      <link>//www.perkin.org.uk/posts/installing-svr4-packages-on-smartos.html</link>
      <pubDate>Tue, 19 Mar 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/installing-svr4-packages-on-smartos.html</guid>
      <description>&lt;p&gt;Up until and including Solaris 10 the default packaging tools on Solaris were
the historical SVR4 &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg*&lt;/code&gt; commands.  First written in the early 1980s they
were standard across commercial Unix systems and provided a simplistic
interface to installing and removing binary packages.&lt;/p&gt;

&lt;p&gt;With the introduction of IPS in OpenSolaris and beyond they have been mostly
consigned to history, however there is still software provided for Solaris
which is only available in the &lt;code class=&quot;highlighter-rouge&quot;&gt;.pkg&lt;/code&gt; format, and thus it is useful to still
be able to handle them.&lt;/p&gt;

&lt;p&gt;Whilst the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg*&lt;/code&gt; tools continue to be maintained in illumos and are provided
by various distributions, they are not all provided in SmartOS.  There are a
few reasons for this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;SmartOS has a different design to other illumos distributions, and some key
differences such as a read-only /usr mean that some packages will simply
break in unexpected ways.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;SmartOS is designed to be a slimmed-down distribution providing only that
which is necessary for the majority of our users and use cases.  Including
the SVR4 tools and metadata would bloat the system.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;SVR4 packages are often available only for older versions of Solaris, and
whilst the excellent ABI compatability in Solaris means that the binaries
themselves will often function correctly, the package may not support newer
features such as SMF, or again make assumptions about the system which could
result in irrevocable damage.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;SmartOS uses pkgsrc to manage third-party software, and we believe it is
better to convert SVR4 packages to pkgsrc format so that all packages on the
system can be managed with a single toolset.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, we do continue to ship the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgtrans&lt;/code&gt; utility with SmartOS, and this
is our gateway into converting SVR4 packages into more useful formats.  The
rest of this post will explore how we can do that.&lt;/p&gt;

&lt;h2 id=&quot;unpacking-svr4-packages&quot;&gt;Unpacking SVR4 packages&lt;/h2&gt;

&lt;p&gt;Let’s start with an example SVR4 package and unpack it to see what it
contains.  I’m going to use Riak, a popular open source database as the
example package.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Download the Solaris 10 SVR4 package from http://docs.basho.com/riak/latest/downloads/
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-Os&lt;/span&gt; http://s3.amazonaws.com/downloads.basho.com/riak/1.3/1.3.0/solaris/10/BASHOriak-1.3.0-1-Solaris10-i386.pkg.gz
&lt;span class=&quot;go&quot;&gt;
: Decompress it
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; BASHOriak-1.3.0-1-Solaris10-i386.pkg.gz
&lt;span class=&quot;go&quot;&gt;
: Use pkgtrans to unpack it into /var/tmp/BASHOriak
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgtrans BASHOriak-1.3.0-1-Solaris10-i386.pkg /var/tmp all&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;SVR4 packages can contain multiple sub-packages, and so the ‘all’ is necessary
to unpack everything in the archive.  If we didn’t specify ‘all’, we would
have seen:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgtrans BASHOriak-1.3.0-1-Solaris10-i386.pkg /var/tmp
&lt;span class=&quot;go&quot;&gt;
The following packages are available:
  1  BASHOriak     riak
                   (i386) 1.3.0-1

Select package(s) you wish to process (or 'all' to process
all packages). (default: all) [?,??,q]:&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So whilst we could have specified ‘riak’, we can always use ‘all’ to avoid
having to first look at the package to see what sub-packages it contains.&lt;/p&gt;

&lt;p&gt;We now have an unpacked package, let’s go through what it contains.&lt;/p&gt;

&lt;h3 id=&quot;install-sub-directory&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;install&lt;/code&gt; sub-directory&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;install/&lt;/code&gt; directory contains some files and scripts:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;/
&lt;span class=&quot;go&quot;&gt;total 29
-rw-------   1 admin    deniedssh   10175 Feb 19 15:17 copyright
-rw-------   1 admin    deniedssh     214 Feb 19 15:17 depend
-rwx------   1 admin    deniedssh     438 Feb 19 15:17 i.preserve
-rwx------   1 admin    deniedssh     339 Feb 19 15:17 preinstall
-rwx------   1 admin    deniedssh     469 Feb 19 15:17 r.preserve&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;copyright&lt;/code&gt; is self-explanatory, and is normally displayed when using the
&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgadd&lt;/code&gt; command to let the admin know what they are agreeing to.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;depend&lt;/code&gt; is a list of other SVR4 packages that this one depends upon.  In
this case they are:&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cat install&lt;/span&gt;/depend
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; Same dependencies as Erlang
&lt;span class=&quot;go&quot;&gt;P SUNWlibmsr    Math &amp;amp; Microtasking Libraries (Root)
P SUNWlibms     Math &amp;amp; Microtasking Libraries (Usr)
P SUNWopensslr  OpenSSL (Root)
P SUNWopenssl-libraries OpenSSL Libraries (Usr)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As this package is originally from Solaris 10 there is a chance that
  dependencies could cause issues.  For example, in SmartOS we have updated
  OpenSSL to 1.0.x.  Additionally, if a third-party dependency was required
  (i.e.  one not beginning with &lt;code class=&quot;highlighter-rouge&quot;&gt;SUNW&lt;/code&gt;) then naturally you would need to
  recursively apply this entire procedure to each dependency.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;i.preserve&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;r.preserve&lt;/code&gt; are scripts executed during install (&lt;code class=&quot;highlighter-rouge&quot;&gt;i.&lt;/code&gt;)
and removal (&lt;code class=&quot;highlighter-rouge&quot;&gt;r.&lt;/code&gt;).  The ones for Riak simply try to retain modified files
from an existing install, so we will ignore these as pkgsrc handles that by
default.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;preinstall&lt;/code&gt; is, as the name suggests, a script which is executed prior to
installing the package.  In Riak’s case it is used to create the ‘riak’ user
and group if they do not already exist.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;pkginfo&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;pkginfo&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;This provides some basic metadata about the package.  The main bits we care
about are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ARCH=i386&lt;/code&gt;.  As long as the package only depends upon libraries provided by
the base OS (&lt;code class=&quot;highlighter-rouge&quot;&gt;SUNW*&lt;/code&gt;) then it shouldn’t matter whether &lt;code class=&quot;highlighter-rouge&quot;&gt;ARCH&lt;/code&gt; is 32-bit or
64-bit.  However, if it requires third-party dependencies then you need to
ensure that the correct ABI is provided.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;BASEDIR=/opt&lt;/code&gt;.  This is where the package would be installed by the
&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgadd&lt;/code&gt; tool.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;DESC=...&lt;/code&gt;.  This would be output by the legacy &lt;code class=&quot;highlighter-rouge&quot;&gt;pkginfo&lt;/code&gt; command, and we
will re-use this text for our &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_info&lt;/code&gt; description.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;VERSION=1.3.0-1&lt;/code&gt;.  Self-explanatory.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;pkgmap&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgmap&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;This is somewhat equivalent to the pkgsrc &lt;code class=&quot;highlighter-rouge&quot;&gt;PLIST&lt;/code&gt; file and is a record of all
the files the package provides, however it also includes file permissions and
a basic checksum:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; less pkgmap
&lt;span class=&quot;go&quot;&gt;: 1 112659
1 i copyright 10175 24223 1361287043
1 i depend 214 18268 1361287043
&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;...
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;1 d none riak 0700 riak riak
1 d none riak/bin 0700 riak riak
1 f none riak/bin/riak 0755 riak riak 9041 51698 1361286795
&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;...
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;1 e preserve riak/etc/app.config 0600 riak riak 14214 8625 1361286647&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The last two lines, the important fields are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;i&lt;/code&gt; is an SVR4 metadata file, &lt;code class=&quot;highlighter-rouge&quot;&gt;f&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;d&lt;/code&gt; denote whether it is a file or a
directory, &lt;code class=&quot;highlighter-rouge&quot;&gt;e&lt;/code&gt; are configuration files.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;none&lt;/code&gt; means no special handling, &lt;code class=&quot;highlighter-rouge&quot;&gt;preserve&lt;/code&gt; does just that, and the next
field is the full path relative to &lt;code class=&quot;highlighter-rouge&quot;&gt;reloc/&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;0700&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;0755&lt;/code&gt; are the file/directory permissions&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;riak riak&lt;/code&gt; are the user and group ownership&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will need to ensure at least the file entries are handled correctly.&lt;/p&gt;

&lt;h3 id=&quot;reloc-sub-directory&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;reloc/&lt;/code&gt; sub-directory&lt;/h3&gt;

&lt;p&gt;This directory contains the binaries etc. which make up the actual package.
The contents of this directory would normally be installed under &lt;code class=&quot;highlighter-rouge&quot;&gt;BASEDIR&lt;/code&gt;
from the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkginfo&lt;/code&gt; file, so in Riak’s case:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: This..
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;reloc
&lt;span class=&quot;go&quot;&gt;riak
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;reloc/riak
&lt;span class=&quot;go&quot;&gt;bin         erts-5.9.1  etc         lib         releases

: ..would result in this
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /opt/riak
&lt;span class=&quot;go&quot;&gt;bin         erts-5.9.1  etc         lib         releases&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This concludes the examination of the SVR4 package.  Let’s turn it into a
useful pkgsrc package.&lt;/p&gt;

&lt;h2 id=&quot;creating-pkgsrc-binary-package&quot;&gt;Creating pkgsrc binary package&lt;/h2&gt;

&lt;p&gt;For more information on creating binary pkgsrc packages from scratch, see
&lt;a href=&quot;/posts/creating-local-smartos-packages.html&quot;&gt;this post&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;pkgsrc-metadata&quot;&gt;pkgsrc metadata&lt;/h3&gt;

&lt;p&gt;Create the necessary pkgsrc metadata files.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; /var/tmp/pkgsrc-riak
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /var/tmp/pkgsrc-riak
&lt;span class=&quot;go&quot;&gt;
: Standard build-info section.  Change MACHINE_ARCH to x86_64 if you are
: using a base64 image.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;build-info &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;MACHINE_ARCH=i386
OPSYS=SunOS
OS_VERSION=5.11
PKGTOOLS_VERSION=20091115
EOF

: Generate comment file directly from the DESC field in pkginfo
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/DESC/ {print $2}'&lt;/span&gt; &amp;lt; /var/tmp/BASHOriak/pkginfo &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;comment
&lt;span class=&quot;go&quot;&gt;
: Generate PLIST directly from pkgmap
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'$2 ~ /[ef]/ {print $4}'&lt;/span&gt; &amp;lt; /var/tmp/BASHOriak/pkgmap &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;plist
&lt;span class=&quot;go&quot;&gt;
: For now just re-use DESC for the description file, however it would normally
: be longer
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;comment descr&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;pkgsrc-install-script&quot;&gt;pkgsrc INSTALL script&lt;/h3&gt;

&lt;p&gt;To handle the Riak preinstall script, we will create a pkgsrc &lt;code class=&quot;highlighter-rouge&quot;&gt;INSTALL&lt;/code&gt; script.&lt;/p&gt;

&lt;p&gt;The existing script can be mostly used as-is, we just need to put the entire
contents of &lt;code class=&quot;highlighter-rouge&quot;&gt;preinstall&lt;/code&gt; inside a &lt;code class=&quot;highlighter-rouge&quot;&gt;PRE-INSTALL&lt;/code&gt; case statement so that it is
executed prior to installing the package:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Start with the existing preinstall script
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; /var/tmp/BASHOriak/install/preinstall inst
&lt;span class=&quot;go&quot;&gt;
: Alter the script to create the 'riak' user/group during PRE-INSTALL, and
: after install to chown everything to 'riak' (which 
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi inst
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;PKGNAME=&quot;$&lt;/span&gt;1&lt;span class=&quot;s2&quot;&gt;&quot;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;STAGE=&quot;$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;2&quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;case $&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;STAGE&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;PRE-INSTALL)
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;	#&lt;/span&gt; Existing preinstall script goes here, changing /opt references
&lt;span class=&quot;gp&quot;&gt;	#&lt;/span&gt; to &lt;span class=&quot;nv&quot;&gt;$PKG_PREFIX&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;	;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we recall from the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgmap&lt;/code&gt; file, the entries there contained a user/group
that each file should be owned by, and we can handle that in the &lt;code class=&quot;highlighter-rouge&quot;&gt;INSTALL&lt;/code&gt;
script too with a &lt;code class=&quot;highlighter-rouge&quot;&gt;POST-INSTALL&lt;/code&gt; action:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;POST-INSTALL)
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;	chown -R riak:riak $&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;PKG_PREFIX&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;/riak
&lt;span class=&quot;gp&quot;&gt;	;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;esac&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;pkgsrc-files&quot;&gt;pkgsrc files&lt;/h3&gt;

&lt;p&gt;First we simply copy everything from the &lt;code class=&quot;highlighter-rouge&quot;&gt;reloc/&lt;/code&gt; directory to a &lt;code class=&quot;highlighter-rouge&quot;&gt;files/&lt;/code&gt;
directory we will use for pkgsrc:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;files
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; rsync &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; /var/tmp/BASHOriak/reloc/ files/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;chown&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-R&lt;/span&gt; root:root files&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Next we can use the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgmap&lt;/code&gt; file to ensure that the file modes are set
correctly with a quick and dirty script:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;line
&lt;span class=&quot;k&quot;&gt;do
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$line&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$3&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;def]&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;chmod&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$5&lt;/span&gt; files/&lt;span class=&quot;nv&quot;&gt;$4&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt; &amp;lt; /var/tmp/BASHOriak/pkgmap&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;create-the-package&quot;&gt;Create the package&lt;/h3&gt;

&lt;p&gt;We should now have everything necessary to create a binary package, taking the
version from the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgmap&lt;/code&gt; file.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_create &lt;span class=&quot;nt&quot;&gt;-B&lt;/span&gt; build-info &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; comment &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; descr &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; plist &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; /opt/local &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; inst &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; files &lt;span class=&quot;nt&quot;&gt;-U&lt;/span&gt; riak-1.3.0.tgz&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;/h2&gt;

&lt;p&gt;If all went well then we should be able to install the package:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_add riak-1.3.0.tgz&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and we will find it under &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local/riak&lt;/code&gt; as expected.  If we try to run the
binary, we get:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; /opt/local/riak/bin/riak
&lt;span class=&quot;go&quot;&gt;/opt/local/riak/bin/riak: line 30: whoami: not found
sudo doesn't appear to be installed and your EUID isn't riak&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This nicely proves my earlier point about packages often not working unmodified
on SmartOS, in this case because &lt;code class=&quot;highlighter-rouge&quot;&gt;whoami&lt;/code&gt; is no longer provided.  Thankfully
this is an easy fix, and we can simply change &lt;code class=&quot;highlighter-rouge&quot;&gt;whoami&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;id -un&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Making that change and trying again, but this time as the riak user:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; su - riak
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; /opt/local/riak/bin/riak
&lt;span class=&quot;go&quot;&gt;!!!!
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;!!!! WARNING: ulimit -n is 1024;&lt;/span&gt; 4096 is the recommended minimum.
&lt;span class=&quot;go&quot;&gt;!!!!
Usage: riak {start|stop|restart|reboot|ping|console|attach|chkconfig|escript|version|getpid}
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; /opt/local/riak/bin/riak start
&lt;span class=&quot;go&quot;&gt;!!!!
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;!!!! WARNING: ulimit -n is 1024;&lt;/span&gt; 4096 is the recommended minimum.
&lt;span class=&quot;go&quot;&gt;!!!!
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pgrep &lt;span class=&quot;nt&quot;&gt;-fl&lt;/span&gt; riak
&lt;span class=&quot;go&quot;&gt;20628 /opt/local/riak/erts-5.9.1/bin/epmd -daemon
20650 /opt/local/riak/erts-5.9.1/bin/beam.smp -K true -A 64 -W w -- -root /opt/local/
20648 /opt/local/riak/erts-5.9.1/bin/run_erl -daemon /tmp//opt/local/riak/ /opt/local
20718 /opt/local/riak/lib/os_mon-2.2.9/priv/bin/cpu_sup
20716 /opt/local/riak/lib/os_mon-2.2.9/priv/bin/memsup&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This seems to work about as well as one can hope, and concludes my basic example.&lt;/p&gt;

&lt;p&gt;## Further work&lt;/p&gt;

&lt;p&gt;I’ve covered the basics here, but there are additional things you could do to
tidy up the conversion:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Fold the &lt;code class=&quot;highlighter-rouge&quot;&gt;whoami&lt;/code&gt; fix back into the source file and re-generate the package.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Turn this into a real pkgsrc package, which would simplify some areas such as
metadata and user creation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Come up with a script to automate a lot of this work.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Turn the &lt;code class=&quot;highlighter-rouge&quot;&gt;riak&lt;/code&gt; script into an SMF service.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also note that Basho very helpfully already provide a native SmartOS package on
their download page, so this example is somewhat pointless, however I hope it
has still proven useful ;)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>SmartOS is Not GNU/Linux</title>
      <link>//www.perkin.org.uk/posts/smartos-is-not-gnu-linux.html</link>
      <pubDate>Wed, 27 Feb 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/smartos-is-not-gnu-linux.html</guid>
      <description>&lt;p&gt;One of the requests we get from time to time is for SmartOS to look more like
GNU/Linux in layout and behaviour.  For example, config files in &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc&lt;/code&gt; instead
of &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local/etc&lt;/code&gt;, binaries under &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr&lt;/code&gt; instead of &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local/{s,}bin&lt;/code&gt;, GNU
userland by default, etc.&lt;/p&gt;

&lt;p&gt;Whilst we believe in the technical merits of our current implementation and the
clean separation and upgrade possibilities it provides, we do recognise that
some users just don’t care about those things and would prefer a system which
looks as close to the GNU/Linux environments they are used to.&lt;/p&gt;

&lt;p&gt;Ordinarily this simply wouldn’t be possible given that &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr&lt;/code&gt; is a read-only
mount from the &lt;a href=&quot;/posts/smartos-and-the-global-zone.html&quot;&gt;global zone&lt;/a&gt;, however
with the highly flexible SmartOS
&lt;a href=&quot;http://wiki.smartos.org/display/DOC/Zones&quot;&gt;Zones&lt;/a&gt; architecture, coupled with
Joyent employing Zones guru &lt;a href=&quot;http://wiki.smartos.org/display/DOC/Jerry+Jelinek&quot;&gt;Jerry
Jelinek&lt;/a&gt;, we are able to
provide you with an option to do exactly this.  As Jerry says, at Sun there was
even a native Linux brand, so pretty much anything is possible!&lt;/p&gt;

&lt;p&gt;We call it ‘SNGL’ (pronounced ‘snuggle’), which is an acronym for ‘SmartOS is
Not GNU/Linux’.  Currently it is somewhat experimental, but we’d love for
people to try it out and provide feedback.&lt;/p&gt;

&lt;p&gt;Here’s how you can get it running.&lt;/p&gt;

&lt;h2 id=&quot;install-the-latest-platform&quot;&gt;Install the latest platform&lt;/h2&gt;

&lt;p&gt;You need to be running SmartOS 20130222 or later.  Older platforms can be
coerced into working, you will just need to work around the lack of &lt;a href=&quot;https://github.com/joyent/illumos-joyent/commit/c6920fb1d0f6cd852da06e049631f1ee274b5b9d&quot;&gt;this
commit&lt;/a&gt;
by creating an empty &lt;code class=&quot;highlighter-rouge&quot;&gt;sngl_base.tar.gz&lt;/code&gt; or so.&lt;/p&gt;

&lt;p&gt;As usual, follow the instructions
&lt;a href=&quot;http://wiki.smartos.org/display/DOC/Remotely+Upgrading+A+USB+Key+Based+Deployment&quot;&gt;here&lt;/a&gt;
to upgrade an existing install.&lt;/p&gt;

&lt;h2 id=&quot;get-the-sngl-dataset&quot;&gt;Get the SNGL dataset&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Fetch the dataset image and manifest files.  The image is 107MB.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /usbkey/images
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /usbkey/images
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; http://pkgsrc.smartos.org/datasets/sngl-0.99.0.dsmanifest
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; http://pkgsrc.smartos.org/datasets/sngl-0.99.0.zfs.bz2
&lt;span class=&quot;go&quot;&gt;
: Import it
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; imgadm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; sngl-0.99.0.dsmanifest &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; sngl-0.99.0.zfs.bz2&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;create-a-new-dataset&quot;&gt;Create a new dataset&lt;/h2&gt;

&lt;p&gt;The important point to note here is that &lt;code class=&quot;highlighter-rouge&quot;&gt;brand&lt;/code&gt; is set to &lt;code class=&quot;highlighter-rouge&quot;&gt;sngl&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Create a new zone using the dataset (change your json to suit).
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vmadm create &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;{
  &quot;brand&quot;: &quot;sngl&quot;,
  &quot;image_uuid&quot;: &quot;4bf9530a-7ae5-11e2-bb4e-3bad5fbc3de9&quot;,
  &quot;ram&quot;: 256,
  &quot;quota&quot;: 10,
  &quot;alias&quot;: &quot;sngl-0.99.0&quot;,
  &quot;nics&quot;: [
    {
      &quot;nic_tag&quot;: &quot;admin&quot;,
      &quot;ip&quot;: &quot;dhcp&quot;
    }
  ]
}
EOF&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;At this point you should be able to log in and start using &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin&lt;/code&gt; etc to
install new software (there are over 2,000 packages available) as normal, but
notice that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;binaries are running from &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/bin&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;configuration files are in &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;the default userland tools are GNU variants (&lt;code class=&quot;highlighter-rouge&quot;&gt;ls&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;sed&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;grep&lt;/code&gt;, etc.)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For those that are interested, here is some further detail on how this is all
implemented.&lt;/p&gt;

&lt;h2 id=&quot;brand-configuration&quot;&gt;Brand configuration&lt;/h2&gt;

&lt;p&gt;The main setup is in &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/lib/brand/sngl&lt;/code&gt;.  Firstly, &lt;code class=&quot;highlighter-rouge&quot;&gt;platform.xml&lt;/code&gt; defines
the mount points to be used inside the zone, and here you can see how we are
able to use &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;        &lt;span class=&quot;nt&quot;&gt;&amp;lt;global_mount&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;special=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/lib&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;directory=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/system/lib&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;opt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ro,nodevices&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;lofs&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;global_mount&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;special=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/sbin&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;directory=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/system/sbin&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;opt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ro,nodevices&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;lofs&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;global_mount&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;special=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/usr&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;directory=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/system/usr&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;opt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ro,nodevices&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;lofs&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We are transplanting the main system directories and mounting them under
&lt;code class=&quot;highlighter-rouge&quot;&gt;/system&lt;/code&gt;.  This leaves &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr&lt;/code&gt; free for us to write packages to.&lt;/p&gt;

&lt;p&gt;In order to support having the OS under &lt;code class=&quot;highlighter-rouge&quot;&gt;/system&lt;/code&gt; there is some additional
configuration in &lt;code class=&quot;highlighter-rouge&quot;&gt;config.xml&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;        &lt;span class=&quot;nt&quot;&gt;&amp;lt;initname&amp;gt;&lt;/span&gt;/system/sbin/init&lt;span class=&quot;nt&quot;&gt;&amp;lt;/initname&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;login_cmd&amp;gt;&lt;/span&gt;/system/usr/bin/login -z %Z %u&lt;span class=&quot;nt&quot;&gt;&amp;lt;/login_cmd&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;forcedlogin_cmd&amp;gt;&lt;/span&gt;/system/usr/bin/login -z %Z -f %u&lt;span class=&quot;nt&quot;&gt;&amp;lt;/forcedlogin_cmd&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;user_cmd&amp;gt;&lt;/span&gt;/system/usr/bin/getent passwd %u&lt;span class=&quot;nt&quot;&gt;&amp;lt;/user_cmd&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is where the flexibility of Zones really shines.  We are able to redefine
the path to init(1M) and others so that the zone can boot correctly.&lt;/p&gt;

&lt;p&gt;In addition, we copy in the &lt;code class=&quot;highlighter-rouge&quot;&gt;crle&lt;/code&gt; configuration files &lt;code class=&quot;highlighter-rouge&quot;&gt;ld.sys.config&lt;/code&gt; and
&lt;code class=&quot;highlighter-rouge&quot;&gt;ld.sys64.config&lt;/code&gt; so that binaries will look in &lt;code class=&quot;highlighter-rouge&quot;&gt;/system/usr/lib&lt;/code&gt; for their
runtime libraries.&lt;/p&gt;

&lt;h2 id=&quot;runtime-and-packages&quot;&gt;Runtime and packages&lt;/h2&gt;

&lt;p&gt;The brand configuration is enough to set the zone up, but in order to make it
boot we need additional files available under &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr&lt;/code&gt;, there are simply too many
hardcoded paths.  For this we just symlink back to &lt;code class=&quot;highlighter-rouge&quot;&gt;/system/usr&lt;/code&gt; from &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr&lt;/code&gt;
any files required.&lt;/p&gt;

&lt;p&gt;Finally, we are able to perform a full pkgsrc bulk build with &lt;code class=&quot;highlighter-rouge&quot;&gt;LOCALBASE&lt;/code&gt; set
to &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr&lt;/code&gt; within a chroot which emulates this layout, and when those packages
are installed they overwrite the compatability symlinks we have configured and
replace them with files from the packages.&lt;/p&gt;

&lt;p&gt;Not all symlinks will be overwritten, though, which is why standard SmartOS
utilities such as &lt;code class=&quot;highlighter-rouge&quot;&gt;prstat(1M)&lt;/code&gt; are still available, as the symlink for it still
exists.&lt;/p&gt;

&lt;h2 id=&quot;reporting-issues&quot;&gt;Reporting issues&lt;/h2&gt;

&lt;p&gt;As I mentioned, this is currently experimental, and there will be plenty of
problems.  However, at least from some initial testing, a reasonable amount of
things appear to work fine, and for users who want this particular layout it
may be good enough.&lt;/p&gt;

&lt;p&gt;Please feel free to give it a try and report issues against &lt;a href=&quot;https://github.com/joyent/pkgsrc/issues&quot;&gt;our GitHub
project&lt;/a&gt;.  Once we have it working
with a reasonable amount of stability we may be able to offer it as an option
in the &lt;a href=&quot;http://www.joyent.com/&quot;&gt;Joyent Public Cloud&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>SmartOS development preview dataset</title>
      <link>//www.perkin.org.uk/posts/smartos-development-preview-dataset.html</link>
      <pubDate>Mon, 18 Feb 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/smartos-development-preview-dataset.html</guid>
      <description>&lt;p&gt;The datasets we produce for SmartOS are usually released on a quarterly
cadence, matching the upstream pkgsrc release branches.  This is often enough
to ensure that people can get up-to-date software with all the usual
improvements and bug fixes.&lt;/p&gt;

&lt;p&gt;Occasionally though, users want the very latest and don’t really want to wait
for 3 months to get it, and so to satisfy those users who crave the bleeding
edge I have produced a new dataset which is based upon pkgsrc trunk.&lt;/p&gt;

&lt;p&gt;The package repository for this dataset will be constantly updated with the
very latest that pkgsrc has to offer, and so you will occasionally see breakage
as we integrate updates for core libraries and add new features.  Think of it
as being similar to Debian ‘unstable’, you get the very latest stuff but you
may need to do some maintenance every so often.&lt;/p&gt;

&lt;p&gt;Here are some reasons why you may want to use this dataset:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;It is based upon the
&lt;a href=&quot;/posts/multiarch-package-support-in-smartos.html&quot;&gt;multiarch&lt;/a&gt; code, so only
one image is necessary.  No more needing to decide between the 32-bit or
64-bit options.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It is a full bulk build, so there are in the region of 9,000 packages to
choose from (depending on the current state of pkgsrc trunk).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It has all the Joyent specific changes integrated, so that means SMF support
for many packages which we have written manifests for, static UID/GID
allocation, various improvements, and uses the standard &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local&lt;/code&gt; prefix.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;There are some nice improvements only available in pkgsrc trunk, for example
OpenSSL 1.0.1e with proper AES-NI support, and libpcap fixes from
&lt;a href=&quot;http://twitter.com/postwait&quot;&gt;@postwait&lt;/a&gt; with a slew of networking utilities
now available and working (these will be documented in a future post).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;how-to-install&quot;&gt;How to install&lt;/h2&gt;

&lt;p&gt;Here is a quick start guide to getting the preview dataset up and running:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Fetch the dataset image and manifest files.  The image is 82MB.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /usbkey/images
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /usbkey/images
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; http://pkgsrc.smartos.org/datasets/trunk-0.99.0.dsmanifest
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; http://pkgsrc.smartos.org/datasets/trunk-0.99.0.zfs.bz2
&lt;span class=&quot;go&quot;&gt;
: Import it
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; imgadm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; trunk-0.99.0.dsmanifest &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; trunk-0.99.0.zfs.bz2
&lt;span class=&quot;go&quot;&gt;
: Create a new zone using the dataset (change your json to suit).
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vmadm create &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;{
  &quot;brand&quot;: &quot;joyent&quot;,
  &quot;image_uuid&quot;: &quot;c91b3752-79c5-11e2-ad33-67667b9ee2c2&quot;,
  &quot;max_physical_memory&quot;: 256,
  &quot;alias&quot;: &quot;trunk-0.99.0&quot;,
  &quot;nics&quot;: [
    {
      &quot;nic_tag&quot;: &quot;admin&quot;,
      &quot;ip&quot;: &quot;dhcp&quot;
    }
  ]
}
EOF&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;then login and start using it as you would with any other dataset.&lt;/p&gt;

&lt;h2 id=&quot;known-issues&quot;&gt;Known issues&lt;/h2&gt;

&lt;p&gt;With this being a bleeding-edge distribution, there will undoubtedly be
problems.The main one I am currently aware of is dependencies upon the GCC
runtime from the &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/pbulk&lt;/code&gt; prefix used to build the packages, which looks
like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; pkgin &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;samba
&lt;span class=&quot;go&quot;&gt;calculating dependencies... done.
/opt/pbulk/gcc47/lib/./libgcc_s.so.1, needed by samba-3.6.12nb1 is not present in this system.
/opt/pbulk/gcc47/lib/./libgcc_s.so.1, needed by tdb-1.2.11 is not present in this system.
[...]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We are actively working on fixing these dependencies, but in the meantime if
you require a package which is broken in this way you can work around it by
installing the &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/pbulk&lt;/code&gt; bootstrap like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; curl http://pkgsrc.smartos.org/packages/SmartOS/bootstrap/bootstrap-pbulk.tar.gz &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    | gtar &lt;span class=&quot;nt&quot;&gt;-zxf&lt;/span&gt; - &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; /
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; /opt/pbulk/bin/pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;gcc47&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The other issue to note is that not all packages have been converted to
multiarch.  Again we are actively working on this, but it will take some time
to go through all of the 12,000 or so packages in pkgsrc.&lt;/p&gt;

&lt;p&gt;If you find any other problems, please feel free to raise them against our
GitHub project &lt;a href=&quot;https://github.com/joyent/pkgsrc/issues&quot;&gt;here&lt;/a&gt;.  Or, even
better, follow my guides on
&lt;a href=&quot;/posts/pkgsrc-on-smartos-zone-creation-and-basic-builds.html&quot;&gt;building&lt;/a&gt;
&lt;a href=&quot;/posts/pkgsrc-on-smartos-fixing-broken-builds.html&quot;&gt;pkgsrc&lt;/a&gt; (you will want the
&lt;code class=&quot;highlighter-rouge&quot;&gt;joyent/release/trunk&lt;/code&gt; branch) and have a go at fixing things yourself, we very
much welcome patches and pull requests!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>pkgsrc on SmartOS - fixing broken builds</title>
      <link>//www.perkin.org.uk/posts/pkgsrc-on-smartos-fixing-broken-builds.html</link>
      <pubDate>Thu, 17 Jan 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/pkgsrc-on-smartos-fixing-broken-builds.html</guid>
      <description>&lt;p&gt;This is the second in a series of posts looking at pkgsrc on SmartOS.  In the
&lt;a href=&quot;/posts/pkgsrc-on-smartos-zone-creation-and-basic-builds.html&quot;&gt;previous post&lt;/a&gt; I
got us up and running with building packages.  This post will focus on what to
do when the build fails.&lt;/p&gt;

&lt;p&gt;Currently pkgsrc is able to build around 9,500 packages on SmartOS, however
pkgsrc carries over 12,000 packages in total, so there is a reasonable chance
that you will come across a package which will not produce a binary package.&lt;/p&gt;

&lt;p&gt;Let’s have a look at some of the most common failure modes and the facilities
pkgsrc provides for them to be fixed.&lt;/p&gt;

&lt;h2 id=&quot;adjusting-the-environment&quot;&gt;Adjusting the environment&lt;/h2&gt;

&lt;p&gt;Probably the most common failures on Solaris are those caused by incorrect
compiler or linker flags, where the author of the software has not taken into
account differences across Unix platforms.  Examples include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;the usage of &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;u_int*&lt;/code&gt;&lt;/strong&gt; types (e.g. &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;u_int32_t&lt;/code&gt;&lt;/strong&gt;) instead of the
portable &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;uint*&lt;/code&gt;&lt;/strong&gt; C99 types (e.g. &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;uint32_t&lt;/code&gt;&lt;/strong&gt;).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;missing &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;-lsocket -lnsl&lt;/code&gt;&lt;/strong&gt; when using the socket interface.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;pkgsrc provides an easy way to pass &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;CFLAGS&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;LDFLAGS&lt;/code&gt;&lt;/strong&gt; and other
common environment variables to the build, and these are often enough to
resolve such issues.&lt;/p&gt;

&lt;p&gt;Taking &lt;code class=&quot;highlighter-rouge&quot;&gt;net/nsd&lt;/code&gt; as an example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;net/nsd
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake package
&lt;span class=&quot;c&quot;&gt;...
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;gcc -I/opt/local/include -I/opt/local/include -I. -I. -O -I/opt/local/include -c ./util.c
./util.c:745:1: error: unknown type name 'u_int32_t'
*** [util.o] Error code 1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we edit the Makefile and add the following line below &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;CONFIGURE_ARGS&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;nv&quot;&gt;CFLAGS.SunOS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt;	&lt;span class=&quot;nt&quot;&gt;-Du_int32_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;uint32_t&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;then a rebuild resolves the problem and results in a binary package:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake clean
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake package
&lt;span class=&quot;c&quot;&gt;...
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Creating binary package /content/packages/All/nsd-3.2.14.tgz&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;By using &lt;code class=&quot;highlighter-rouge&quot;&gt;CFLAGS.SunOS&lt;/code&gt; rather than the global &lt;code class=&quot;highlighter-rouge&quot;&gt;CFLAGS&lt;/code&gt; this is only performed
on systems where &lt;code class=&quot;highlighter-rouge&quot;&gt;uname&lt;/code&gt; is &lt;code class=&quot;highlighter-rouge&quot;&gt;SunOS&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can resolve missing libraries in a similar way, taking &lt;code class=&quot;highlighter-rouge&quot;&gt;net/rootprobe&lt;/code&gt; as an
example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;net/rootprobe
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake package
&lt;span class=&quot;c&quot;&gt;...
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;gcc -Wl,-R/opt/local/lib  rootprobe.o -o rootprobe
Undefined                       first referenced
 symbol                             in file
recv                                rootprobe.o
send                                rootprobe.o
getsockname                         rootprobe.o
socket                              rootprobe.o
getdomainname                       rootprobe.o
connect                             rootprobe.o
recvfrom                            rootprobe.o
inet_aton                           rootprobe.o
inet_ntoa                           rootprobe.o
shutdown                            rootprobe.o
ld: fatal: symbol referencing errors. No output written to rootprobe
collect2: error: ld returned 1 exit status
*** [rootprobe] Error code 1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Add the following to the Makefile:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;nv&quot;&gt;LDFLAGS.SunOS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt;	&lt;span class=&quot;nt&quot;&gt;-lsocket&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-lnsl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and hey presto, out comes a binary package:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake clean
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake package
&lt;span class=&quot;c&quot;&gt;...
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;gcc -lsocket -lnsl -Wl,-R/opt/local/lib  rootprobe.o -o rootprobe
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;/bin/rm -f cctldprobe;&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;ln &lt;/span&gt;rootprobe cctldprobe
&lt;span class=&quot;c&quot;&gt;...
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Creating binary package /content/packages/All/rootprobe-200301.tgz&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Not all packages can be fixed directly like this, only those which obey the
normal &lt;code class=&quot;highlighter-rouge&quot;&gt;${CC}&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;${LD}&lt;/code&gt; environment variables, as pkgsrc creates wrappers
for those commands where it can insert these alterations.  For packages which
directly call e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;gcc&lt;/code&gt;, some additional digging will be required to see how
the arguments can be passed.&lt;/p&gt;

&lt;p&gt;Taking &lt;code class=&quot;highlighter-rouge&quot;&gt;net/3proxy&lt;/code&gt; as an example, the build fails with missing socket
libraries:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;net/3proxy
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake package
&lt;span class=&quot;c&quot;&gt;...
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;gcc -opop3p -Wall -O2 -pthread  sockmap.o pop3p.o sockgetchar.o myalloc.o common.o  
Undefined                       first referenced
 symbol                             in file
bind                                pop3p.o
send                                sockgetchar.o
getsockname                         common.o
accept                              pop3p.o
listen                              pop3p.o
gethostbyname                       common.o
sendto                              sockmap.o
socket                              pop3p.o
setsockopt                          pop3p.o
connect                             common.o
recvfrom                            sockmap.o
shutdown                            sockmap.o
ld: fatal: symbol referencing errors. No output written to pop3p
collect2: error: ld returned 1 exit status
*** [pop3p] Error code 1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;but adding &lt;code class=&quot;highlighter-rouge&quot;&gt;LDFLAGS.SunOS+= -lsocket -lnsl&lt;/code&gt; to the Makefile as before does not
resolve the problem.  Delving further into the Makefile we can see that the
build is driven from a custom Makefile rather than through autoconf/automake:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;nv&quot;&gt;MAKE_FILE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;      Makefile.unix&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and it is there we will need to perform the changes.  First, let’s find the
work area, which we can get from the &lt;code class=&quot;highlighter-rouge&quot;&gt;WRKSRC&lt;/code&gt; variable:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake show-var &lt;span class=&quot;nv&quot;&gt;VARNAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;WRKSRC
&lt;span class=&quot;go&quot;&gt;/var/tmp/pkgsrc-build/net/3proxy/work
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /var/tmp/pkgsrc-build/net/3proxy/work
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; Makefile.unix 
&lt;span class=&quot;go&quot;&gt;-rw-r--r-- 1 11001 10512 675 Apr 30  2005 Makefile.unix&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Picking out the relevant bits from &lt;code class=&quot;highlighter-rouge&quot;&gt;Makefile.unix&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;nv&quot;&gt;CC&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; gcc
&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;CFLAGS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-Wall&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-O2&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-pthread&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-D_THREAD_SAFE&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-D_REENTRANT&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DNOODBC&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DWITH_STD_MALLOC&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DFD_SETSIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4096 &lt;span class=&quot;nt&quot;&gt;-DWITH_POLL&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;LDFLAGS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-Wall&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-O2&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-pthread&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here, the author has provided no functionality for adding to the environment,
and has instead chosen to hardcode a specific compiler and build flags,
significantly reducing the portability of their software - good luck to
Clang/LLVM or SunStudio users!&lt;/p&gt;

&lt;p&gt;If the author had provided a way in to add to these flags, for example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;nv&quot;&gt;LDFLAGS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-Wall&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-O2&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-pthread&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;USER_LDFLAGS&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;then we could have fixed that in the main pkgsrc &lt;code class=&quot;highlighter-rouge&quot;&gt;Makefile&lt;/code&gt; with&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;nv&quot;&gt;MAKE_ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt;	&lt;span class=&quot;nv&quot;&gt;USER_LDFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-lsocket -lnsl&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;or similar, however we now have no choice but to directly edit &lt;code class=&quot;highlighter-rouge&quot;&gt;Makefile.unix&lt;/code&gt;.
Thankfully, pkgsrc provides a couple of ways to easily do this, which we will
look at over the next few sections.&lt;/p&gt;

&lt;h2 id=&quot;the-substitution-framework&quot;&gt;The substitution framework&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;subst&lt;/code&gt; framework allows basic editing of files within the work area.  I
will show the solution for the above problem, and then discuss it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;err&quot;&gt;.include&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;../../mk/bsd.prefs.mk&quot;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;.if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;${OPSYS}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;SunOS&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;SUBST_CLASSES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt;		libs
&lt;span class=&quot;nv&quot;&gt;SUBST_STAGE.libs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	pre-build
&lt;span class=&quot;nv&quot;&gt;SUBST_MESSAGE.libs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	Adding SunOS socket libraries
&lt;span class=&quot;nv&quot;&gt;SUBST_FILES.libs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	Makefile.unix
&lt;span class=&quot;nv&quot;&gt;SUBST_SED.libs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;		&lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/^LDFLAGS/s/$$/ -lsocket -lnsl/'&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;.endif&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Firstly, we need to limit this to SunOS systems, else we would break platforms
which do not have &lt;code class=&quot;highlighter-rouge&quot;&gt;libsocket&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;libnsl&lt;/code&gt;.  Including &lt;code class=&quot;highlighter-rouge&quot;&gt;../../mk/bsd.prefs.mk&lt;/code&gt;
gives us access to the &lt;code class=&quot;highlighter-rouge&quot;&gt;OPSYS&lt;/code&gt; variable so we can test the platform we are
running on.&lt;/p&gt;

&lt;p&gt;Next we set up the substitution framework:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;SUBST_CLASSES&lt;/code&gt;&lt;/strong&gt; creates a new class, which I have named &lt;code class=&quot;highlighter-rouge&quot;&gt;libs&lt;/code&gt;.  This
class name is then appended to the remaining &lt;code class=&quot;highlighter-rouge&quot;&gt;SUBST_*&lt;/code&gt; variables to assign
them to that class.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;SUBST_STAGE&lt;/code&gt;&lt;/strong&gt; defines the make stage when the substitution will be run,
and should almost always be &lt;code class=&quot;highlighter-rouge&quot;&gt;pre-build&lt;/code&gt;, to ensure it is done after any
configuration stage which could rewrite files itself.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;SUBST_MESSAGE&lt;/code&gt;&lt;/strong&gt; is optional, and is simply a line which will be printed
to the user when the substitution takes places.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;SUBST_FILES&lt;/code&gt;&lt;/strong&gt; is a list of files the substitution operates on.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;SUBST_SED&lt;/code&gt;&lt;/strong&gt; is the actual substitution, in the form of a &lt;code class=&quot;highlighter-rouge&quot;&gt;sed(1)&lt;/code&gt;
operation.  Here we append &lt;code class=&quot;highlighter-rouge&quot;&gt;-lsocket -lnsl&lt;/code&gt; to any line beginning with
&lt;code class=&quot;highlighter-rouge&quot;&gt;LDFLAGS&lt;/code&gt;.  Note &lt;code class=&quot;highlighter-rouge&quot;&gt;$$&lt;/code&gt; is required to get &lt;code class=&quot;highlighter-rouge&quot;&gt;make&lt;/code&gt; to escape a &lt;code class=&quot;highlighter-rouge&quot;&gt;$&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake clean
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake package
&lt;span class=&quot;c&quot;&gt;...
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;===&amp;gt;&lt;/span&gt; Building &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;3proxy-0.5.3.11nb1
&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Adding SunOS socket libraries
&lt;span class=&quot;c&quot;&gt;...
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Creating binary package /content/packages/All/3proxy-0.5.3.11nb1.tgz&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Two other &lt;code class=&quot;highlighter-rouge&quot;&gt;subst&lt;/code&gt; features you may want are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;SUBST_VARS.foo= VARNAME&lt;/code&gt;&lt;/strong&gt; is a shortcut for the
&lt;code class=&quot;highlighter-rouge&quot;&gt;-e 's,@VARNAME@,${VARNAME},g'&lt;/code&gt; operation, common with autoconf-based
packages.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;SUBST_FILTER_CMD.foo= &amp;lt;cmd&amp;gt;&lt;/code&gt;&lt;/strong&gt; allows you to run an arbitrary command,
rather than the default of &lt;code class=&quot;highlighter-rouge&quot;&gt;sed&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, see the implementation in &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc/mk/subst.mk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;## Patches&lt;/p&gt;

&lt;p&gt;While &lt;code class=&quot;highlighter-rouge&quot;&gt;CFLAGS&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;LDFLAGS&lt;/code&gt; and the substitution framework allow for simple
one-liner fixes, often more significant changes are required, and in those
cases the only sensible option is to create patches.  Thankfully, there are
some tools provided in pkgsrc to make this a relatively easy process.&lt;/p&gt;

&lt;p&gt;First, let’s take a broken package, &lt;code class=&quot;highlighter-rouge&quot;&gt;devel/bglibs&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;devel/bglibs
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake package
&lt;span class=&quot;c&quot;&gt;...
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;./ltcompile net/cork.c
net/cork.c: In function 'socket_cork':
net/cork.c:39:27: error: 'SOL_TCP' undeclared (first use in this function)
net/cork.c:39:27: note: each undeclared identifier is reported only once for each function it appears in
*** [net/cork.lo] Error code 1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;which comes from the following function:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/*
 * ..It is known to work on Linux (with the TCP_CORK option) and to at least
 * compile on BSD (with the TCP_NOPUSH option).  On OS's which lack either of
 * these two options, this function is essentially a no-op.
 */&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;socket_cork&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#if defined(TCP_CORK)
&lt;/span&gt;  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setsockopt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SOL_TCP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TCP_CORK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#elif defined(TCP_NOPUSH)
&lt;/span&gt;  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setsockopt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SOL_SOCKET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TCP_NOPUSH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#else
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Unfortunately, while SmartOS provides the &lt;code class=&quot;highlighter-rouge&quot;&gt;TCP_CORK&lt;/code&gt; flag, it does not
understand &lt;code class=&quot;highlighter-rouge&quot;&gt;SOL_TCP&lt;/code&gt;, and so we need to modify the test and add an additional
one.&lt;/p&gt;

&lt;p&gt;Before doing this, we should install the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgtools/pkgdiff&lt;/code&gt; package, which
contains a &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgvi&lt;/code&gt; wrapper.  This allows you to edit a file, and if you make
changes, it will save the resulting diff in the pkgsrc &lt;code class=&quot;highlighter-rouge&quot;&gt;patches&lt;/code&gt; directory
ready for use.  Much easier than delving into the work area and creating
patches yourself.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Install via pkgin..
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; pkgin &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;pkgdiff
&lt;span class=&quot;go&quot;&gt;
: ..or through pkgsrc
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ../../pkgtools/pkgdiff &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; bmake &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now edit the offending file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; pkgvi &lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;bmake show-var &lt;span class=&quot;nv&quot;&gt;VARNAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;WRKSRC&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;/net/cork.c&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is what I changed the function to:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;socket_cork&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#if defined(TCP_CORK) &amp;amp;&amp;amp; defined(SOL_TCP)
&lt;/span&gt;  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setsockopt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SOL_TCP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TCP_CORK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#elif defined(TCP_CORK) &amp;amp;&amp;amp; defined(SOL_SOCKET)
&lt;/span&gt;  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setsockopt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SOL_SOCKET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TCP_CORK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#elif defined(TCP_NOPUSH)
&lt;/span&gt;  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setsockopt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SOL_SOCKET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TCP_NOPUSH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#else
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This still isn’t ideal, and would be better converted to a proper autoconf test
where we can test functionality instead of definitions, but it will do for
example purposes.&lt;/p&gt;

&lt;p&gt;After writing, you should get output such as:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;pkgvi: File was modified. For a diff, type:
pkgdiff &quot;/var/tmp/pkgsrc-build/devel/bglibs/work/bglibs-1.106/net/cork.c&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and running the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgdiff&lt;/code&gt; command will show you the diff.&lt;/p&gt;

&lt;p&gt;The final step is storing the diff into a patch file, and that is accomplished
with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; mkpatches
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake mps&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;mkpatches&lt;/code&gt; command creates a new file in the &lt;code class=&quot;highlighter-rouge&quot;&gt;patches&lt;/code&gt; directory called
&lt;code class=&quot;highlighter-rouge&quot;&gt;patch-net_cork.c&lt;/code&gt;, and the &lt;code class=&quot;highlighter-rouge&quot;&gt;bmake mps&lt;/code&gt; (short for the &lt;code class=&quot;highlighter-rouge&quot;&gt;makepatchsum&lt;/code&gt; target)
regenerates the &lt;code class=&quot;highlighter-rouge&quot;&gt;distinfo&lt;/code&gt; file with the correct checksum for that patch.&lt;/p&gt;

&lt;p&gt;Finally, you can rebuild&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake clean
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake package&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and, hey presto .. another failure!&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;--- net/uncork.lo ---
net/uncork.c: In function 'socket_uncork':
net/uncork.c:30:27: error: 'SOL_TCP' undeclared (first use in this function)
net/uncork.c:30:27: note: each undeclared identifier is reported only once for each function it appears in&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now that you know how to fix this, I’ll leave it to you to come up with a patch
;)&lt;/p&gt;

&lt;p&gt;One final word on this, you will perhaps notice during the build some warnings:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Applying pkgsrc patches &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;bglibs-1.106nb1
&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Ignoring patchfile /content/pkgsrc/devel/bglibs/patches/patch-ab.orig
&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Ignoring patchfile /content/pkgsrc/devel/bglibs/patches/patch-ac.orig
&lt;span class=&quot;gp&quot;&gt;=&amp;gt;&lt;/span&gt; Ignoring patchfile /content/pkgsrc/devel/bglibs/patches/patch-net_cork.c.orig&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;These files are left by &lt;code class=&quot;highlighter-rouge&quot;&gt;mkpatches&lt;/code&gt;, and to remove them you can run&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; mkpatches &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Also note that both &lt;code class=&quot;highlighter-rouge&quot;&gt;patch-ab&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;patch-ac&lt;/code&gt; changed, even though we only
modified the &lt;code class=&quot;highlighter-rouge&quot;&gt;net/cork.c&lt;/code&gt; file.  This is due to differences in &lt;code class=&quot;highlighter-rouge&quot;&gt;diff(1)&lt;/code&gt;
output, and is ultimately harmless.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;pkgsrc provides a number of ways to fix up broken software:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;CFLAGS&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;LDFLAGS&lt;/code&gt;, and other environment variables.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;subst.mk&lt;/code&gt; framework for simple file changes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Patch files for more substantial changes.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important thing, after using any of these features, is to feed back your
changes so that we can integrate them into pkgsrc and everyone can benefit.
Probably the easiest way to do that is simply raise an issue against &lt;a href=&quot;https://github.com/joyent/pkgsrc/issues&quot;&gt;our
GitHub pkgsrc fork&lt;/a&gt;, and either myself
or Filip can commit the patch upstream.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>pkgsrc on SmartOS - zone creation and basic builds</title>
      <link>//www.perkin.org.uk/posts/pkgsrc-on-smartos-zone-creation-and-basic-builds.html</link>
      <pubDate>Tue, 15 Jan 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/pkgsrc-on-smartos-zone-creation-and-basic-builds.html</guid>
      <description>&lt;p&gt;Our goal at &lt;a href=&quot;http://www.joyent.com/&quot;&gt;Joyent&lt;/a&gt; is that our binary packages for
&lt;a href=&quot;http://smartos.org/&quot;&gt;SmartOS&lt;/a&gt; fulfill all of our users’ needs.  This isn’t
always possible, however - users may want packages we do not yet provide, or
build with different options.&lt;/p&gt;

&lt;p&gt;To satisfy those demands, it should instead be reasonably straight-forward for
users to build their own packages, and this guide hopefully provides all the
information for them to do just that.&lt;/p&gt;

&lt;p&gt;This is the first in a series of posts, and will focus on getting pkgsrc set up
in a clean SmartOS zone and then building some packages.  Other posts currently
available in the series are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/posts/pkgsrc-on-smartos-fixing-broken-builds.html&quot;&gt;How to fix build failures&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;create-a-build-machine&quot;&gt;Create a build machine&lt;/h2&gt;

&lt;p&gt;For this guide I use a &lt;code class=&quot;highlighter-rouge&quot;&gt;base:1.8.1&lt;/code&gt; SmartMachine, but any recent dataset should
be fine, and it shouldn’t matter whether it’s 32-bit or 64-bit.&lt;/p&gt;

&lt;p&gt;If you are a Joyent customer:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Fill in your SDC details.  You can use the web interface too, if you prefer.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SDC_CLI_ACCOUNT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;account name
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SDC_CLI_IDENTITY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/path/to/ssh/key
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SDC_CLI_KEY_ID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;key identifier
&lt;span class=&quot;go&quot;&gt;: .. or us-west-1 or us-sw-1 or eu-ams-1
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SDC_CLI_URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;https://us-east-1.api.joyentcloud.com
&lt;span class=&quot;go&quot;&gt;
: You really really want json(1), it's awesome
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;npm &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;jsontool
&lt;span class=&quot;go&quot;&gt;
: Get list of 'base' datasets, we'll use the latest
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; sdc-listdatasets | json &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; urn &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; :base: | &lt;span class=&quot;nb&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-1&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;sdc:sdc:base:1.8.1 55330ab4-066f-11e2-bd0f-434f2462fada

: You can use sdc-listpackages to show available machine types.  I want one
: with good CPU performance.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; sdc-createmachine &lt;span class=&quot;nt&quot;&gt;--dataset&lt;/span&gt; 55330ab4-066f-11e2-bd0f-434f2462fada &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;   &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;pkgsrc-build-machine&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--package&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;XL  8GB High CPU&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you are using SmartOS:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;brand&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;joyent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;image_uuid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;55330ab4-066f-11e2-bd0f-434f2462fada&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;max_physical_memory&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;quota&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;alias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;pkgsrc-build-machine&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hostname&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;pkgsrc-build-machine&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nics&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nic_tag&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ip&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;dhcp&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Put the above json into a file, you may want to tweak some values, then&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; imgadm update
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; imgadm import 55330ab4-066f-11e2-bd0f-434f2462fada
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; vmadm create &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /path/to/json/file&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, log into the freshly-created zone.&lt;/p&gt;

&lt;h2 id=&quot;install-dependencies&quot;&gt;Install dependencies&lt;/h2&gt;

&lt;p&gt;First thing you’ll need in the zone are build tools, so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; up
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;gcc47 scmgit-base&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;fetch-pkgsrc&quot;&gt;Fetch pkgsrc&lt;/h2&gt;

&lt;p&gt;We maintain a fork of pkgsrc on github, which includes some additional SmartOS
fixes and improvements, so we recommend using that rather than upstream.&lt;/p&gt;

&lt;p&gt;I put everything under &lt;code class=&quot;highlighter-rouge&quot;&gt;/content&lt;/code&gt;, adjust to your own tastes.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; /content
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /content
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; git clone git://github.com/joyent/pkgsrc.git&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Next, check out the latest stable branch.  Our naming scheme is
&lt;code class=&quot;highlighter-rouge&quot;&gt;joyent/release/YYYYQQ&lt;/code&gt;, and the latest branch at time of writing is
&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc_2012Q4&lt;/code&gt;, so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;pkgsrc
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; git checkout joyent/release/2012Q4&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you want to be particularly adventurous, you could checkout &lt;code class=&quot;highlighter-rouge&quot;&gt;trunk&lt;/code&gt; and get
the very latest pkgsrc code, however pkgsrc is a very fast-moving target and
you may run into unexpected breakages, and you will certainly end up rebuilding
packages very often.&lt;/p&gt;

&lt;h2 id=&quot;fetch-pkgsrc-wip&quot;&gt;Fetch pkgsrc-wip&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://pkgsrc-wip.sourceforge.net/&quot;&gt;pkgsrc-wip&lt;/a&gt; is a set of additional
work-in-progress packages for pkgsrc, and can be useful for trying out the
latest packages.  It is designed to be extracted directly into pkgsrc, and
we maintain a git submodule of it in our release trees, so all you need to
do, assuming you are using a &lt;code class=&quot;highlighter-rouge&quot;&gt;joyent/release/*&lt;/code&gt; tree, is:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; git submodule init
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; git submodule update&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This will also get you a &lt;code class=&quot;highlighter-rouge&quot;&gt;joyent/&lt;/code&gt; directory which is a module of our
&lt;a href=&quot;http://github.com/joyent/pkgsrc-joyent/&quot;&gt;pkgsrc-joyent&lt;/a&gt; tree of additional
packages.&lt;/p&gt;

&lt;p&gt;If you are on &lt;code class=&quot;highlighter-rouge&quot;&gt;trunk&lt;/code&gt; or another tree which does not have the &lt;code class=&quot;highlighter-rouge&quot;&gt;wip&lt;/code&gt; submodule,
you can fetch it manually with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; git clone git://github.com/joyent/pkgsrc-wip.git wip&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configure-mkconf&quot;&gt;Configure mk.conf&lt;/h2&gt;

&lt;p&gt;The primary method of configuring pkgsrc is through the
&lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local/etc/mk.conf&lt;/code&gt; file.  The base image comes with one populated to
handle the basic layout, but there are some additional basic variables you may
want to set prior to building your first package:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;DISTDIR&lt;/code&gt;&lt;/strong&gt; determines where source tarballs are stored, default
&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc/distfiles&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;PACKAGES&lt;/code&gt;&lt;/strong&gt; is where pkgsrc will store binary packages it has built,
default &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc/packages&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;WRKOBJDIR&lt;/code&gt;&lt;/strong&gt; is where pkgsrc performs the builds, default
&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc/&amp;lt;category&amp;gt;/&amp;lt;package&amp;gt;/work&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;ALLOW_VULNERABLE_PACKAGES&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;SKIP_LICENSE_CHECK&lt;/code&gt;&lt;/strong&gt; should both be
set to &lt;code class=&quot;highlighter-rouge&quot;&gt;yes&lt;/code&gt; if you just want the package to be built, and don’t care whether
it is currently vulnerable to security issues or is released under a specific
license.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;MAKE_JOBS&lt;/code&gt;&lt;/strong&gt; determines the argument to &lt;code class=&quot;highlighter-rouge&quot;&gt;make -j&lt;/code&gt;, i.e. the number of
concurrent make threads, default 1.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;FETCH_USING&lt;/code&gt;&lt;/strong&gt; sets the default program to use for fetching source code,
defaulting to an in-tree version of NetBSD’s ftp program.  Setting this to
&lt;code class=&quot;highlighter-rouge&quot;&gt;curl&lt;/code&gt; on SmartOS, which is included in the base platform, will avoid any
dependencies.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;BINPKG_SITES&lt;/code&gt;&lt;/strong&gt; is a URL pointing to binary packages which can be used by
this tree rather than building everything from source, and settings
&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;DEPENDS_TARGET&lt;/code&gt;&lt;/strong&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;bin-install&lt;/code&gt; enables using these binary packages as
dependencies.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thus, this is how I would configure &lt;code class=&quot;highlighter-rouge&quot;&gt;mk.conf&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /content/&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;distfiles,packages&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;
: Do not change the existing entries in this file, they tell pkgsrc
: where to find important files.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; vi /opt/local/etc/mk.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;c&quot;&gt;# ...
# Keep the existing mk.conf entries, they are important.
# ...
&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;DISTDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	/content/distfiles
&lt;span class=&quot;nv&quot;&gt;PACKAGES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	/content/packages
&lt;span class=&quot;nv&quot;&gt;WRKOBJDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	/var/tmp/pkgsrc-build
&lt;span class=&quot;c&quot;&gt;#
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ALLOW_VULNERABLE_PACKAGES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	&lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;SKIP_LICENSE_CHECK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;		&lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;MAKE_JOBS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	8
&lt;span class=&quot;c&quot;&gt;#
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;FETCH_USING&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	curl
&lt;span class=&quot;c&quot;&gt;#
# Adjust BINPKG_SITES, depending upon the dataset chosen, it should be the URL
# from /opt/local/etc/pkgin/repositories.conf without the trailing 'All'.
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BINPKG_SITES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	http://pkgsrc.joyent.com/sdc6/2012Q2/i386/
&lt;span class=&quot;nv&quot;&gt;DEPENDS_TARGET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	bin-install&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;building-a-package&quot;&gt;Building a package&lt;/h2&gt;

&lt;p&gt;Ok, let’s get started and build a package.  pkgsrc is organised into
categories, with all packages following the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc/&amp;lt;category&amp;gt;/&amp;lt;package&amp;gt;&lt;/code&gt;
layout, and everything is driven with &lt;code class=&quot;highlighter-rouge&quot;&gt;bmake&lt;/code&gt;, the BSD implementation of
&lt;code class=&quot;highlighter-rouge&quot;&gt;make(1)&lt;/code&gt;.  I’m going to choose &lt;code class=&quot;highlighter-rouge&quot;&gt;nmap&lt;/code&gt; as an example, as it will show a couple
of things I want to cover.&lt;/p&gt;

&lt;p&gt;First, finding it.  I tend to just do a simple:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;nmap&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;net/nmap&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you want a more featured search, you can do:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake search &lt;span class=&quot;nv&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nmap&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;though the first time you run this it creates the &lt;code class=&quot;highlighter-rouge&quot;&gt;INDEX&lt;/code&gt; file it requires, and
that can take a long time.  Another option is to use the
&lt;a href=&quot;http://pkgsrc.se/&quot;&gt;pkgsrc.se&lt;/a&gt; web interface.&lt;/p&gt;

&lt;p&gt;Once you have found the package, &lt;code class=&quot;highlighter-rouge&quot;&gt;cd&lt;/code&gt; into the package directory.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;net/nmap&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Next, let’s look at any options the package supports.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake show-options&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If the package supports build options, as &lt;code class=&quot;highlighter-rouge&quot;&gt;net/nmap&lt;/code&gt; does, you’ll see
something like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Any of the following general options may be selected:
	inet6	 Enable support for IPv6.
	ndiff	 Enable tool to compare Nmap scans.
	zenmap	 Enable nmap GUI frontend.

These options are enabled by default:
	inet6

These options are currently enabled:
	inet6

You can select which build options to use by setting PKG_DEFAULT_OPTIONS
or PKG_OPTIONS.nmap.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The place to configure these options is again in &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local/etc/mk.conf&lt;/code&gt;, so
if you want to enable ndiff support for example, then you’d add this to
&lt;code class=&quot;highlighter-rouge&quot;&gt;mk.conf&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span class=&quot;nv&quot;&gt;PKG_OPTIONS.nmap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;	ndiff&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Re-running the &lt;code class=&quot;highlighter-rouge&quot;&gt;show-options&lt;/code&gt; command should now print:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;...
These options are currently enabled:
        inet6 ndiff
...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And finally, we can go ahead and build the package.  The output from this will
be long, so you may want to &lt;code class=&quot;highlighter-rouge&quot;&gt;tee&lt;/code&gt; it to a file for reviewing:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;tee&lt;/span&gt; /var/tmp/nmap.log&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Assuming this completes ok, you should note the main stages that make up a
package build:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;bootstrap-depends&lt;/code&gt;&lt;/strong&gt; comes first, and installs all the dependencies
required for pkgsrc to get started.  &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgtools/digest&lt;/code&gt; is required to
calculate the &lt;code class=&quot;highlighter-rouge&quot;&gt;SHA1&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;RMD160&lt;/code&gt; checksums of the source tarball.  If we
hadn’t specified &lt;code class=&quot;highlighter-rouge&quot;&gt;FETCH_USING=curl&lt;/code&gt; in our &lt;code class=&quot;highlighter-rouge&quot;&gt;mk.conf&lt;/code&gt; then it’s likely that
&lt;code class=&quot;highlighter-rouge&quot;&gt;net/tnftp&lt;/code&gt; would have been pulled in during this stage too and used to
fetch the source.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;=&amp;gt; Bootstrap dependency digest&amp;gt;=20010302: NOT found
=&amp;gt; Verifying bin-install for ../../pkgtools/digest
===&amp;gt; Binary install for digest&amp;gt;=20010302
=&amp;gt; Installing digest&amp;gt;=20010302 from /content/packages/All;http://pkgsrc.joyent.com/sdc6/2012Q2/i386//All
pkg_add: Can't process file:///content/packages/All/digest*: No such file or directory
digest-20111104 successfully installed.
...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;fetch&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;checksum&lt;/code&gt;&lt;/strong&gt; then run to download the source tarball for
this particular package, and then verify the checksum matches that stored by
pkgsrc, to ensure it was downloaded from a good source:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;=&amp;gt; Fetching nmap-6.01.tar.bz2
=&amp;gt; Total size: 21640157 bytes
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 20.6M  100 20.6M    0     0   699k      0  0:00:30  0:00:30 --:--:--  721k
=&amp;gt; Checksum SHA1 OK for nmap-6.01.tar.bz2
=&amp;gt; Checksum RMD160 OK for nmap-6.01.tar.bz2&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;depends&lt;/code&gt;&lt;/strong&gt; then installs all packages required for both build and runtime
for the package in question:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;=&amp;gt; Build dependency libtool-base&amp;gt;=2.2.6bnb3: NOT found
=&amp;gt; Verifying bin-install for ../../devel/libtool-base
===&amp;gt; Binary install for libtool-base&amp;gt;=2.2.6bnb3
=&amp;gt; Installing libtool-base&amp;gt;=2.2.6bnb3 from /content/packages/All;http://pkgsrc.joyent.com/sdc6/2012Q2/i386//All
libtool-base-2.2.6bnb6 successfully installed.
...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;extract&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;patch&lt;/code&gt;&lt;/strong&gt; then unpack the source and apply any pkgsrc
patches to the package.  The patches are located in the &lt;code class=&quot;highlighter-rouge&quot;&gt;patches/&lt;/code&gt;
sub-directory for each package:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;===&amp;gt; Extracting for nmap-6.01nb5
===&amp;gt; Patching for nmap-6.01nb5&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;The bulk of the build is performed by &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;configure&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;build&lt;/code&gt;&lt;/strong&gt; which
for most software will consist of &lt;code class=&quot;highlighter-rouge&quot;&gt;./configure &amp;amp;&amp;amp; make&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;===&amp;gt; Configuring for nmap-6.01nb5
...
checking whether NLS is requested... yes
...
Configuration complete.  Type make (or gmake on some *BSD machines) to compile.
...
===&amp;gt; Building for nmap-6.01nb5
...
gmake[1]: Leaving directory `/var/tmp/pkgsrc-build/net/nmap/work/nmap-6.01'
=&amp;gt; Unwrapping files-to-be-installed.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;The final steps are &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;package&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;install&lt;/code&gt;&lt;/strong&gt;, firstly &lt;code class=&quot;highlighter-rouge&quot;&gt;package&lt;/code&gt; does a
fake install of the package to a temporary install directory and creates a
binary package from that, and then &lt;code class=&quot;highlighter-rouge&quot;&gt;install&lt;/code&gt; installs that binary package into
place:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;===&amp;gt; Building binary package for nmap-6.01nb5
=&amp;gt; Creating binary package /content/packages/All/nmap-6.01nb5.tgz
===&amp;gt; Install binary package of nmap-6.01nb5&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can now verify it is installed, and start using your new software:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;nmap
&lt;span class=&quot;go&quot;&gt;nmap is /opt/local/bin/nmap

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; nmap &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 22 localhost
&lt;span class=&quot;go&quot;&gt;
Starting Nmap 6.01 ( http://nmap.org ) at 2013-01-15 15:36 UTC
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00012s latency).
PORT   STATE SERVICE
22/tcp open  ssh

Nmap done: 1 IP address (1 host up) scanned in 0.11 seconds&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;cleanup&quot;&gt;Cleanup&lt;/h2&gt;

&lt;p&gt;Once everything is working, you may want to clean up the build areas.  The
pkgsrc way of doing this is:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; bmake clean clean-depends&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, if you just want to blow everything away without prejudice, you can
simply remove everything under &lt;code class=&quot;highlighter-rouge&quot;&gt;WRKOBJDIR&lt;/code&gt;, so in my case:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; /var/tmp/pkgsrc-build/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This should hopefully be enough to get you started.  Over the next few posts
we’ll investigate some more advanced topics.  Stay tuned!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Multi-architecture package support in SmartOS</title>
      <link>//www.perkin.org.uk/posts/multiarch-package-support-in-smartos.html</link>
      <pubDate>Thu, 10 Jan 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/multiarch-package-support-in-smartos.html</guid>
      <description>&lt;p&gt;&lt;em&gt;[Updated on 2013-01-16 to use the 12.4.1 dataset which fixes some issues.]&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ever since the release of Solaris 7 back in 1998, Solaris has had the ability
to run both 32-bit and 64-bit binaries on the same machine.  Even now, 15 years
later, with much of the world 64-bit only, there are still reasons to retain
32-bit support:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;32-bit binaries can be faster in many cases, and if you do not need the
additional address space afforded by the 64-bit version then there may be no
advantage to running it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Some software you depend upon may only provide a 32-bit version, or may have
better compatability in that mode.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It’s sometimes nice to have a hard 4GB memory limit on a runaway process
instead of it completely trashing your machine ;)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately, while the base &lt;a href=&quot;http://smartos.org/&quot;&gt;SmartOS&lt;/a&gt; platform is set up
to provide both 32-bit and 64-bit binaries, the packaging infrastructure we
use, &lt;a href=&quot;http://www.pkgsrc.org/&quot;&gt;pkgsrc&lt;/a&gt;, has not traditionally supported building
multi-architecture packages.  This has meant we have needed to provide both
32-bit and 64-bit versions of each dataset, which is not ideal:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;It’s confusing to customers and users, who may think it applies to the
kernel and platform version.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Users want the choice to be able to run 32-bit for some applications and
64-bit for others, all on the same machine.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It is additional work and maintenance for us.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to resolve this, I have been working on providing multi-architecture
support to pkgsrc, and this work is now available for preview testing.&lt;/p&gt;

&lt;h2 id=&quot;getting-started&quot;&gt;Getting started&lt;/h2&gt;

&lt;p&gt;Here is a quick start guide to getting the multi-architecture dataset up and
running:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Fetch the dataset image and manifest files.  The image is 85MB.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /usbkey/images
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /usbkey/images
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; http://pkgsrc.smartos.org/datasets/multiarch-12.4.1.dsmanifest
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; http://pkgsrc.smartos.org/datasets/multiarch-12.4.1.zfs.bz2
&lt;span class=&quot;go&quot;&gt;
: Import it
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; imgadm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; multiarch-12.4.1.dsmanifest &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; multiarch-12.4.1.zfs.bz2
&lt;span class=&quot;go&quot;&gt;
: Create a new zone using the dataset (change your json to suit).
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vmadm create &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;{
  &quot;brand&quot;: &quot;joyent&quot;,
  &quot;image_uuid&quot;: &quot;ee1fb198-5fe1-11e2-9cce-e319fd47df7b&quot;,
  &quot;max_physical_memory&quot;: 256,
  &quot;alias&quot;: &quot;multiarch-12.4.1&quot;,
  &quot;nics&quot;: [
    {
      &quot;nic_tag&quot;: &quot;admin&quot;,
      &quot;ip&quot;: &quot;dhcp&quot;
    }
  ]
}
EOF&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;then login and start using it as you would with any other dataset.&lt;/p&gt;

&lt;h2 id=&quot;multi-architecture-libraries&quot;&gt;Multi-architecture libraries&lt;/h2&gt;

&lt;p&gt;Libraries are reasonably straight-forward.  For most packages which provide
shared libraries, you should find both 32-bit and 64-bit libraries are
included, for example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; sqlite3 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'so$'&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;/opt/local/lib/libsqlite3.so
/opt/local/lib/amd64/libsqlite3.so&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Other directories under &lt;code class=&quot;highlighter-rouge&quot;&gt;lib/&lt;/code&gt; should be handled correctly too, such as &lt;code class=&quot;highlighter-rouge&quot;&gt;.pc&lt;/code&gt;
files for &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg-config&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; sqlite3 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'pc$'&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;/opt/local/lib/pkgconfig/sqlite3.pc
/opt/local/lib/amd64/pkgconfig/sqlite3.pc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;multi-architecture-binaries&quot;&gt;Multi-architecture binaries&lt;/h2&gt;

&lt;p&gt;Binaries are similar, but follow a different layout scheme, and have additional
controls to allow the user to select which architecture to use.&lt;/p&gt;

&lt;p&gt;The basic layout is:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; sqlite3 | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;bin
&lt;span class=&quot;go&quot;&gt;/opt/local/bin/i86/sqlite3
/opt/local/bin/amd64/sqlite3
/opt/local/bin/sqlite3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In order to explain this, let us look at how the base platform supports
multi-architecture binaries, using &lt;code class=&quot;highlighter-rouge&quot;&gt;dtrace&lt;/code&gt; as an example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-li&lt;/span&gt; /usr/sbin/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/dtrace /usr/sbin/dtrace /usr/lib/isaexec
&lt;span class=&quot;go&quot;&gt;4255 -r-xr-xr-x 72 root bin 12776 Dec 28 02:38 /usr/lib/isaexec
6330 -r-xr-xr-x  1 root bin 52728 Dec 28 02:38 /usr/sbin/amd64/dtrace
4255 -r-xr-xr-x 72 root bin 12776 Dec 28 02:38 /usr/sbin/dtrace
6640 -r-xr-xr-x  1 root bin 41544 Dec 28 02:38 /usr/sbin/i86/dtrace

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; file /usr/sbin/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/dtrace /usr/lib/isaexec
&lt;span class=&quot;go&quot;&gt;/usr/sbin/amd64/dtrace: ELF 64-bit LSB executable AMD64 Version 1, dynamically linked, not stripped, no debugging information available
/usr/sbin/i86/dtrace:   ELF 32-bit LSB executable 80386 Version 1, dynamically linked, not stripped, no debugging information available
/usr/lib/isaexec:       ELF 32-bit LSB executable 80386 Version 1, dynamically linked, not stripped, no debugging information available&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;i86&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;amd64&lt;/code&gt; hold the per-architecture binaries, and the main
&lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/sbin/dtrace&lt;/code&gt; command is a hardlink to the &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/lib/isaexec&lt;/code&gt; wrapper (as
shown by the inode being identical).  This wrapper detects whether the running
kernel is 32-bit or 64-bit, and calls the appropriate native binary, which
nowadays will almost certainly be the 64-bit version.&lt;/p&gt;

&lt;p&gt;For the pkgsrc implementation, I needed a way to override this behaviour so
that users could select to run the 32-bit version if so desired, without having
to munge their &lt;code class=&quot;highlighter-rouge&quot;&gt;$PATH&lt;/code&gt;.  To do this I took a copy of &lt;code class=&quot;highlighter-rouge&quot;&gt;isaexec&lt;/code&gt; and added it to
pkgsrc, with additional support for an &lt;code class=&quot;highlighter-rouge&quot;&gt;ABI&lt;/code&gt; environment variable.&lt;/p&gt;

&lt;p&gt;You can see the behaviour below with the calls to &lt;code class=&quot;highlighter-rouge&quot;&gt;execve()&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Default is to run 64-bit&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; truss &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; execve sqlite3 &lt;span class=&quot;nt&quot;&gt;-version&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;execve(&quot;/opt/local/bin/sqlite3&quot;, 0x08047DA8, 0x08047DB4)  argc = 2
execve(&quot;/opt/local/bin/amd64/sqlite3&quot;, 0x08047DA8, 0x08047DB4)  argc = 2
3.7.15 2012-12-12 13:36:53 cd0b37c52658bfdf992b1e3dc467bae1835a94ae&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;Set ABI=32 or ABI=i86 to run the 32-bit version&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ABI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;32 truss &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; execve sqlite3 &lt;span class=&quot;nt&quot;&gt;-version&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;execve(&quot;/opt/local/bin/sqlite3&quot;, 0x08047D9C, 0x08047DA8)  argc = 2
execve(&quot;/opt/local/bin/i86/sqlite3&quot;, 0x08047D9C, 0x08047DA8)  argc = 2
3.7.15 2012-12-12 13:36:53 cd0b37c52658bfdf992b1e3dc467bae1835a94ae&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that not all binaries have been converted to multi-architecture.  In fact,
the majority have been left as plain 32-bit binaries.  While all libraries
ultimately have to be provided for both architectures so that users can choose
to compile their own software against either, 64-bit binaries only make sense
for certain classes of software:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Databases such as SQLite, and other servers which may require &amp;gt;4GB address
space.&lt;/li&gt;
  &lt;li&gt;Language interpreters.&lt;/li&gt;
  &lt;li&gt;Software which provides a &lt;code class=&quot;highlighter-rouge&quot;&gt;foo-config&lt;/code&gt; script with hardcoded references to
&lt;code class=&quot;highlighter-rouge&quot;&gt;libdir&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;compiler-support&quot;&gt;Compiler support&lt;/h2&gt;

&lt;p&gt;The GCC 4.7.2 package provided has been made aware of this layout, and will add
the correct library paths depending upon the ABI you target.  For example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;test.c &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;int main(){}
EOF

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; gcc &lt;span class=&quot;nt&quot;&gt;-m32&lt;/span&gt; test.c &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; test32 &lt;span class=&quot;nt&quot;&gt;-lsqlite3&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ldd test32 | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;libsqlite3
&lt;span class=&quot;gp&quot;&gt;        libsqlite3.so.0 =&amp;gt;&lt;/span&gt;       /opt/local/lib/libsqlite3.so.0
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; gcc &lt;span class=&quot;nt&quot;&gt;-m64&lt;/span&gt; test.c &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; test64 &lt;span class=&quot;nt&quot;&gt;-lsqlite3&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ldd test64 | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;libsqlite3
&lt;span class=&quot;gp&quot;&gt;        libsqlite3.so.0 =&amp;gt;&lt;/span&gt;       /opt/local/lib/amd64/libsqlite3.so.0&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;No additional flags or linker settings should be required (if they are, let me
know!)&lt;/p&gt;

&lt;h2 id=&quot;interpreter-support&quot;&gt;Interpreter support&lt;/h2&gt;

&lt;p&gt;For those interpreters which have been converted, their respective module
systems should be multi-architecture aware:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Perl already had reasonable support for multi-architecture files, and all
perl modules provided should be enabled, for example:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;p5-Digest-SHA1
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; p5-Digest-SHA1 | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'so$'&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;/opt/local/lib/perl5/vendor_perl/5.16.0/i386-solaris-thread-multi/auto/Digest/SHA1/SHA1.so
/opt/local/lib/perl5/vendor_perl/5.16.0/x86_64-solaris-thread-multi-64/auto/Digest/SHA1/SHA1.so
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ABI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;32 perl &lt;span class=&quot;nt&quot;&gt;-MDigest&lt;/span&gt;::SHA1 &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'print'&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ABI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;64 perl &lt;span class=&quot;nt&quot;&gt;-MDigest&lt;/span&gt;::SHA1 &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'print'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Python is similar to Perl, but needed a lot more work to support
multi-architecture modules.  Modules provided by pkgin should work fine, but
there may be issues with locally-built modules - let me know!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;node is built as a multi-architecture binary, but &lt;code class=&quot;highlighter-rouge&quot;&gt;npm&lt;/code&gt; has received no
special handling.  This means you need to be careful not to mix-and-match
modules.  I don’t perceive this to be too much of an issue, as the node
community appears to have settled on having one &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; per
application, but again let me know if there are better ways to handle this.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;coverage&quot;&gt;Coverage&lt;/h2&gt;

&lt;p&gt;This work is incomplete, hence it not being available in the default datasets
yet, but a large number of packages have been converted:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Pretty much every package which provides shared libraries.&lt;/li&gt;
  &lt;li&gt;Python, Perl, Lua and node.js interpreters (and a significant number of
modules).&lt;/li&gt;
  &lt;li&gt;MySQL 5.5, PostgreSQL, SQLite and DB4 databases, Apache 2.2.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notable exceptions currently are Ruby and PHP, and I will be working on those
in due course.  There may also be a number of packages which should include
multi-architecture binaries, please let me know if I have missed any obvious
candidates.&lt;/p&gt;

&lt;p&gt;You can raise issues against our GitHub project
&lt;a href=&quot;https://github.com/joyent/pkgsrc/issues&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Solaris portability - cfmakeraw()</title>
      <link>//www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html</link>
      <pubDate>Wed, 09 Jan 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html</guid>
      <description>&lt;p&gt;Converting from &lt;a href=&quot;http://www.perkin.org.uk/posts/solaris-portability-flock.html&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;flock()&lt;/code&gt; to
&lt;code class=&quot;highlighter-rouge&quot;&gt;fcntl()&lt;/code&gt;&lt;/a&gt;
unfortunately wasn’t enough to get tmux to build on Solaris, there was one
additional failure:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;client.c: In function 'client_main':
client.c:246:3: warning: implicit declaration of function 'cfmakeraw' [-Wimplicit-function-declaration]

...

Undefined                       first referenced
 symbol                             in file
cfmakeraw                           client.o
ld: fatal: symbol referencing errors. No output written to tmux
collect2: error: ld returned 1 exit status
*** [tmux] Error code 1&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Let’s look at the code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;	&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;termios&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;cfmakeraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_iflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ICRNL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IXANY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_oflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OPOST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ONLCR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Running &lt;code class=&quot;highlighter-rouge&quot;&gt;man cfmakeraw&lt;/code&gt; on my OSX laptop I can read what this function does,
and where it is implemented (edited for brevity):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;SYNOPSIS
     void
     cfmakeraw(struct termios *termios_p);

DESCRIPTION
     The cfmakeraw() function sets the flags stored in the termios structure
     to a state disabling all input and output processing, giving a ``raw I/O
     path''.

STANDARDS
     The cfmakeraw() and cfsetspeed() functions, as well as the TCSASOFT option
     to the tcsetattr() function are extensions to the IEEE Std 1003.1-1988
     (``POSIX.1'') specification.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ok, so all it’s doing is setting some additional flags in the &lt;code class=&quot;highlighter-rouge&quot;&gt;tio&lt;/code&gt; structure,
and a quick search in the &lt;a href=&quot;http://opengrok.netbsd.org/xref/src/lib/libc/termios/cfmakeraw.c&quot;&gt;NetBSD
OpenGrok&lt;/a&gt;
gives us their implementation (again edited for brevity):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;cfmakeraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;termios&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_iflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IMAXBEL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IGNBRK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BRKINT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PARMRK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ISTRIP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INLCR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IGNCR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ICRNL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IXON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_oflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OPOST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_lflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ECHO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ECHONL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ICANON&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ISIG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IEXTEN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_cflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CSIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PARENB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_cflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CS8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;All that’s left is to patch the tmux code to set those flags.  A good patch
would add a feature test to the tmux autoconf setup and/or provide a
compatability macro, but in this case I simply add a Solaris-specific section
to the code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;	&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;termios&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#ifdef __sun
&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_iflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IMAXBEL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IGNBRK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BRKINT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PARMRK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ISTRIP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INLCR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IGNCR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ICRNL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IXON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_oflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OPOST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_lflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ECHO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ECHONL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ICANON&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ISIG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IEXTEN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_cflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CSIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PARENB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_cflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CS8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#else
&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;cfmakeraw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_iflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ICRNL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IXANY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c_oflag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OPOST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ONLCR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;cfmakeraw()&lt;/code&gt; is an extension to POSIX and thus not fully portable.  If you use
it, please consider including a compatability version for systems which do not
implement it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Solaris portability - flock()</title>
      <link>//www.perkin.org.uk/posts/solaris-portability-flock.html</link>
      <pubDate>Tue, 08 Jan 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/solaris-portability-flock.html</guid>
      <description>&lt;p&gt;This is the first of what I hope will be a regular series of posts looking at
software portability when it comes to Solarish (Solaris, illumos, SmartOS etc.)
systems.  We will begin with &lt;code class=&quot;highlighter-rouge&quot;&gt;flock()&lt;/code&gt;, as it’s what I happen to have been
fixing today.&lt;/p&gt;

&lt;p&gt;The most recent version of &lt;a href=&quot;http://tmux.sourceforge.net/&quot;&gt;tmux&lt;/a&gt; fails with the
following errors:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;client.c: In function 'client_get_lock':
client.c:81:2: warning: implicit declaration of function 'flock' [-Wimplicit-function-declaration]
client.c:81:20: error: 'LOCK_EX' undeclared (first use in this function)
client.c:81:20: note: each undeclared identifier is reported only once for each function it appears in
client.c:81:28: error: 'LOCK_NB' undeclared (first use in this function)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;from this section of code:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;client_get_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;O_WRONLY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;O_CREAT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;0600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;open failed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_EX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LOCK_NB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EWOULDBLOCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_EX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EINTR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;cm&quot;&gt;/* nothing */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This code is reasonably straight-forward, trying to create a lock on a file
descriptor, and if it isn’t able to waits until the lock is released then
fails, ready for the calling function to retry.&lt;/p&gt;

&lt;p&gt;However, the &lt;code class=&quot;highlighter-rouge&quot;&gt;flock()&lt;/code&gt; routine is of BSD heritage and does not exist on
Solaris.  There used to be a compatability version as part of the &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/ucb&lt;/code&gt;
environment, but that no longer exists in newer versions.&lt;/p&gt;

&lt;p&gt;Thankfully, there is an alternative interface which has existed for as long as
&lt;code class=&quot;highlighter-rouge&quot;&gt;flock()&lt;/code&gt; but with the added benefit of being standardised by POSIX and thus
much more portable - enter &lt;code class=&quot;highlighter-rouge&quot;&gt;fcntl()&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;Let’s look at how the two are similar-but-different, and then show how we can
change this code to be more portable.&lt;/p&gt;

&lt;h2 id=&quot;flock-implementation&quot;&gt;flock() implementation&lt;/h2&gt;

&lt;p&gt;As we can see from the NetBSD manual page below, &lt;code class=&quot;highlighter-rouge&quot;&gt;flock()&lt;/code&gt; is very simple, and
this is probably the main reason why people choose to use it over &lt;code class=&quot;highlighter-rouge&quot;&gt;fcntl()&lt;/code&gt; for
file locking.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;NAME
     flock -- apply or remove an advisory lock on an open file

LIBRARY
     Standard C Library (libc, -lc)

SYNOPSIS
     #include &amp;lt;fcntl.h&amp;gt;

     #define   LOCK_SH   1    /* shared lock */
     #define   LOCK_EX   2    /* exclusive lock */
     #define   LOCK_NB   4    /* don't block when locking */
     #define   LOCK_UN   8    /* unlock */

     int
     flock(int fd, int operation);&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There isn’t much to it, you call &lt;code class=&quot;highlighter-rouge&quot;&gt;flock()&lt;/code&gt; specifying either a shared or
exclusive lock, with an option to make the call non-blocking.  Afterwards you
unlock the previously held lock.&lt;/p&gt;

&lt;p&gt;The tmux code in question uses &lt;code class=&quot;highlighter-rouge&quot;&gt;LOCK_NB&lt;/code&gt; for the initial call, then if that
fails reverts to the default blocking operation so that the client can retry as
soon as the lock is released.&lt;/p&gt;

&lt;h2 id=&quot;use-fcntl-instead&quot;&gt;Use fcntl() instead!&lt;/h2&gt;

&lt;p&gt;In contrast to &lt;code class=&quot;highlighter-rouge&quot;&gt;flock()&lt;/code&gt;, setting up &lt;code class=&quot;highlighter-rouge&quot;&gt;fcntl()&lt;/code&gt; is a bit more involved as it
allows finer-grained control over the locking.&lt;/p&gt;

&lt;h3 id=&quot;set-up-struct-flock&quot;&gt;Set up struct flock&lt;/h3&gt;

&lt;p&gt;There is a &lt;code class=&quot;highlighter-rouge&quot;&gt;flock&lt;/code&gt; structure which controls the lock, defined as:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;off_t&lt;/span&gt;       &lt;span class=&quot;n&quot;&gt;l_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;    &lt;span class=&quot;cm&quot;&gt;/* starting offset */&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;off_t&lt;/span&gt;       &lt;span class=&quot;n&quot;&gt;l_len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;      &lt;span class=&quot;cm&quot;&gt;/* len = 0 means until end of file */&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pid_t&lt;/span&gt;       &lt;span class=&quot;n&quot;&gt;l_pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;      &lt;span class=&quot;cm&quot;&gt;/* lock owner */&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;short&lt;/span&gt;       &lt;span class=&quot;n&quot;&gt;l_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;     &lt;span class=&quot;cm&quot;&gt;/* lock type: read/write, etc. */&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;short&lt;/span&gt;       &lt;span class=&quot;n&quot;&gt;l_whence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;cm&quot;&gt;/* type of l_start */&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So, let’s set that up:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;client_get_lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_WRLCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_whence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SEEK_SET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Setting &lt;code class=&quot;highlighter-rouge&quot;&gt;l_start&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;l_len&lt;/code&gt; both to 0 means ‘lock the entire file’,
&lt;code class=&quot;highlighter-rouge&quot;&gt;l_whence&lt;/code&gt; of &lt;code class=&quot;highlighter-rouge&quot;&gt;SEEK_SET&lt;/code&gt; means we are setting absolute values rather than
relative, and we set &lt;code class=&quot;highlighter-rouge&quot;&gt;l_type&lt;/code&gt; to be a write lock.  If we wanted a read lock,
we’d use &lt;code class=&quot;highlighter-rouge&quot;&gt;F_RDLCK&lt;/code&gt; here instead.&lt;/p&gt;

&lt;p&gt;Note that &lt;code class=&quot;highlighter-rouge&quot;&gt;l_pid&lt;/code&gt; is only used for a &lt;code class=&quot;highlighter-rouge&quot;&gt;F_GETLK&lt;/code&gt; operation - we are only
interested in attempting to set a lock, so it is left unset.&lt;/p&gt;

&lt;h3 id=&quot;add-fcntl-calls&quot;&gt;Add fcntl() calls&lt;/h3&gt;

&lt;p&gt;The synopsis for &lt;code class=&quot;highlighter-rouge&quot;&gt;fcntl()&lt;/code&gt; is:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;n&quot;&gt;SYNOPSIS&lt;/span&gt;
     &lt;span class=&quot;cp&quot;&gt;#include &amp;lt;fcntl.h&amp;gt;
&lt;/span&gt;
     &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;fcntl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and the commands available for file locking are (from BSD):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#define F_GETLK         7               &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* get record locking information */&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#define F_SETLK         8               &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* set record locking information */&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#define F_SETLKW        9               &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* F_SETLK; wait if blocked */&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note there is no ‘clear lock’ command.  To clear a lock, you use the &lt;code class=&quot;highlighter-rouge&quot;&gt;F_GETLK&lt;/code&gt;
command with &lt;code class=&quot;highlighter-rouge&quot;&gt;l_type&lt;/code&gt; set to &lt;code class=&quot;highlighter-rouge&quot;&gt;F_UNLCK&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, to show how we would rewrite the &lt;code class=&quot;highlighter-rouge&quot;&gt;flock()&lt;/code&gt; instances to &lt;code class=&quot;highlighter-rouge&quot;&gt;fcntl()&lt;/code&gt; instead,
I’ve put them together below:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#ifdef __sun
&lt;/span&gt;	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fcntl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_SETLK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EAGAIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fcntl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_SETLKW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EINTR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;cm&quot;&gt;/* nothing */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#else
&lt;/span&gt;	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_EX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LOCK_NB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EWOULDBLOCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_EX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EINTR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;cm&quot;&gt;/* nothing */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As you can see, they are very similar, making it relatively straight-forward to
rewrite code to use the more portable &lt;code class=&quot;highlighter-rouge&quot;&gt;fcntl()&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;an-important-note-on-semantics&quot;&gt;An important note on semantics&lt;/h2&gt;

&lt;p&gt;There are two important difference between &lt;code class=&quot;highlighter-rouge&quot;&gt;flock()&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;fcntl()&lt;/code&gt; you need to
be aware of which may affect a simple conversion:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;fcntl()&lt;/code&gt; locks are not held across a &lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt;, so you cannot pass locks down
to child processes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The semantics of &lt;code class=&quot;highlighter-rouge&quot;&gt;fcntl()&lt;/code&gt; are such that &lt;strong&gt;any&lt;/strong&gt; closure of a file descriptor
in your application will release the locks held against that file.  This is
best illustrated with a lock on &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/passwd&lt;/code&gt; that gets released if you call
&lt;code class=&quot;highlighter-rouge&quot;&gt;getpwname()&lt;/code&gt; as that opens and closes the &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/passwd&lt;/code&gt; file.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generally such semantics do not apply, but you should be aware of them, and it
always pays to carefully read the manual pages, preferably those from BSD.&lt;/p&gt;

&lt;h2 id=&quot;flock---fcntl-cheat-sheet&quot;&gt;flock() -&amp;gt; fcntl() cheat sheet&lt;/h2&gt;

&lt;p&gt;To aid your own conversions, here are some further examples (without error
checking for clarity) of &lt;code class=&quot;highlighter-rouge&quot;&gt;flock()&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;fcntl()&lt;/code&gt; equivalents.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#if defined(USING_FLOCK)
&lt;/span&gt;
	&lt;span class=&quot;cm&quot;&gt;/* Blocking */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_SH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Shared (read) lock&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_EX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Exclusive (write) lock&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* Non-blocking */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_SH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LOCK_NB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Shared (read) lock&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_EX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LOCK_NB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Exclusive (write) lock&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* Release */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_UN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;#elif defined(USING_FCNTL)
&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_whence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SEEK_SET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* Blocking */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_RDLCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fcntl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_SETLKW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Shared (read) lock&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_WRLCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fcntl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_SETLKW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Exclusive (write) lock&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* Non-blocking */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_RDLCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fcntl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_SETLK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Shared (read) lock&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_WRLCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fcntl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_SETLK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Exclusive (write) lock&lt;/span&gt;

	&lt;span class=&quot;cm&quot;&gt;/* Release */&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_UNLCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fcntl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lockfd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_GETLK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;#endif&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;flock-wrapper&quot;&gt;flock() wrapper&lt;/h2&gt;

&lt;p&gt;Alternatively, there is a &lt;code class=&quot;highlighter-rouge&quot;&gt;flock()&lt;/code&gt; wrapper which is used by the NetBSD
toolchain, which you could include in a compatability library or so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;flock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;#if defined(F_SETLK) &amp;amp;&amp;amp; defined(F_SETLKW)
&lt;/span&gt;	&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flock&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LOCK_EX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LOCK_SH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LOCK_UN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_EX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_WRLCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_SH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_RDLCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_UN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_UNLCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;nl&quot;&gt;default:&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;errno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EINVAL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;fl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_whence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SEEK_SET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;rc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fcntl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOCK_NB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_SETLK&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_SETLKW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;errno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EAGAIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;errno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EWOULDBLOCK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It might be handy if the illumos folks merged this, it would immediate fix at
least 19 packages in the pkgsrc collection :)&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;flock()&lt;/code&gt; is simpler, and retains locks across &lt;code class=&quot;highlighter-rouge&quot;&gt;fork()&lt;/code&gt; and concurrent access
boundaries, but at the cost of portability.  Please try to use &lt;code class=&quot;highlighter-rouge&quot;&gt;fcntl()&lt;/code&gt; where
possible, it isn’t much harder to use, and makes your software run on more
platforms.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>pkgsrc-2012Q4 illumos packages now available</title>
      <link>//www.perkin.org.uk/posts/pkgsrc-2012Q4-packages-for-illumos.html</link>
      <pubDate>Sun, 06 Jan 2013 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/pkgsrc-2012Q4-packages-for-illumos.html</guid>
      <description>&lt;h2 id=&quot;note&quot;&gt;Note&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This page is obsolete.&lt;/strong&gt;  Please see &lt;a href=&quot;http://pkgsrc.joyent.com/&quot;&gt;http://pkgsrc.joyent.com/&lt;/a&gt; where you
will find the latest package sets and improved instructions.&lt;/p&gt;

&lt;h2 id=&quot;original-article&quot;&gt;Original Article&lt;/h2&gt;

&lt;p&gt;In keeping with the regular quarterly pkgsrc releases, I’m pleased to announce
that packages from the pkgsrc-2012Q4 branch are now available for general
illumos platforms.&lt;/p&gt;

&lt;p&gt;As usual, the quick start instructions are:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; http://pkgsrc.smartos.org/packages/illumos/bootstrap/bootstrap-2012Q4-illumos.tar.gz &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    | gtar &lt;span class=&quot;nt&quot;&gt;-zxf&lt;/span&gt; - &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; /
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/pkg/sbin:/opt/pkg/bin:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; up
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin avail | &lt;span class=&quot;nb&quot;&gt;wc&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    9518
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin search &amp;lt;package&amp;gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &amp;lt;package&amp;gt; &amp;lt;package...&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For those interested in helping to increase the number of packages available,
the bulk build report for this set is available
&lt;a href=&quot;http://pkgsrc.smartos.org/reports/2012Q4-illumos/20130106.1305/meta/report.html&quot;&gt;here&lt;/a&gt;.  It would be great to get past the 10,000 mark!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>SmartOS and the global zone</title>
      <link>//www.perkin.org.uk/posts/smartos-and-the-global-zone.html</link>
      <pubDate>Fri, 23 Nov 2012 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/smartos-and-the-global-zone.html</guid>
      <description>&lt;p&gt;One of the most common issues new users of SmartOS face is understanding the
role and design of the global zone.  Often they will download SmartOS and try
to start using it as they would any other Unix operating system, but quickly
run into basic problems such as installing packages or adding users.  However,
SmartOS is not your usual operating system, and it is imperative that you
understand two key principles:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;SmartOS is specifically designed as an OS for running Virtual Machines&lt;/strong&gt;,
not as a general purpose OS.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;The global zone is effectively a read-only hypervisor&lt;/strong&gt;, and should only be
used for creating and managing Virtual Machines.  Everything else should be
performed inside Virtual Machines.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I should be clear at this point that &lt;em&gt;I am specifically addressing the issue of
downloading and running your own SmartOS installation&lt;/em&gt;.  If you provision a
SmartMachine from Joyent, then you are running inside a Virtual Machine, and
this post does not apply - you are free to start serving up awesome
applications!&lt;/p&gt;

&lt;p&gt;Let’s look at a few aspects of the global zone which make it a great fit for
its intended purpose, and help explain why it doesn’t work as you might expect.&lt;/p&gt;

&lt;h2 id=&quot;the-global-zone-is-a-ramdisk&quot;&gt;The global zone is a ramdisk&lt;/h2&gt;

&lt;p&gt;This is the key reason why things don’t work as you might expect.  SmartOS does
not install to disk like other operating systems, instead it boots directly
from USB/CD/PXE into a mostly read-only environment.&lt;/p&gt;

&lt;p&gt;Why is it done this way?  There are a number of good reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Upgrades are trivial.&lt;/strong&gt;  No more patching, just reboot into a new image!&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Increased disk space.&lt;/strong&gt;  No wasted space on disk to hold the OS, all the
space is dedicated to VMs and user data.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Increased disk performance.&lt;/strong&gt;  It’s common with other systems to have your
OS installed to a pair of mirrored disks and then pool the remaining disks
for data.  With SmartOS you can have all your disks in the same RAIDZ pool,
increasing performance.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Additional security.&lt;/strong&gt;  Most of the system files are read-only, and &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc&lt;/code&gt;
is re-created on each boot, making it much harder to exploit.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Increased stability.&lt;/strong&gt;  Ever had your root disks start to fail and system
commands no longer run?  This doesn’t happen on SmartOS.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Much simpler to install and provision&lt;/strong&gt;,  especially when you have a large
number of machines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, what does this look like, and what are the implications?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; zonename
&lt;span class=&quot;go&quot;&gt;global
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;df&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-h&lt;/span&gt; / /usr
&lt;span class=&quot;go&quot;&gt;Filesystem             size   used  avail capacity  Mounted on
/devices/ramdisk:a     264M   219M    45M    83%    /
/devices/pseudo/lofi@0:1
                       376M   354M    22M    95%    /usr
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; lofiadm
&lt;span class=&quot;go&quot;&gt;Block Device             File                           Options
/dev/lofi/1              /usr.lgz                       Compressed(gzip)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The root file system is a ramdisk, and &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr&lt;/code&gt; is a read-only loopback mount of
a single compressed file held on the ramdisk.&lt;/p&gt;

&lt;p&gt;Apart from a few specific files and directories listed below, this means that
&lt;strong&gt;you cannot change the global zone&lt;/strong&gt;.  To emphasise this point further:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;You cannot add users.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;You cannot write anywhere under /usr.&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;You cannot permanently store or change files under &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;/root&lt;/code&gt;, ..&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Changes to SMF services will be reset each reboot.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are plenty of other things you cannot do, but hopefully this gives you
some idea of the restricted nature of the global zone environment.&lt;/p&gt;

&lt;p&gt;If you are looking for a general purpose OS to serve as a NAS etc, then you can
do worse than give &lt;a href=&quot;http://omnios.omniti.com/&quot;&gt;OmniOS&lt;/a&gt; a spin - it has most of
the same features as SmartOS, but in a normal install-to-disk configuration.&lt;/p&gt;

&lt;p&gt;Having said all that, let’s look at some ways you can manage the global zone,
if you have settled on running SmartOS.&lt;/p&gt;

&lt;h2 id=&quot;so-what-can-i-do&quot;&gt;So what &lt;strong&gt;can&lt;/strong&gt; I do?&lt;/h2&gt;

&lt;p&gt;Firstly, let’s look at the key writeable areas:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;Filesystem             size   used  avail capacity  Mounted on
zones                  2.0T   143M   1.8T     1%    /zones
zones/var              2.0T   4.0G   1.8T     1%    /var
zones/opt              2.0T    55K   1.8T     1%    /opt
zones/usbkey           2.0T   154K   1.8T     1%    /usbkey
/usbkey/shadow         1.8T   154K   1.8T     1%    /etc/shadow
/usbkey/ssh            1.8T   154K   1.8T     1%    /etc/ssh&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;zones&lt;/code&gt; is the big zpool which is spread across all your disks, and SmartOS
will create a number of file systems on it for use in the global zone:&lt;/p&gt;

&lt;h3 id=&quot;zones&quot;&gt;/zones&lt;/h3&gt;

&lt;p&gt;This is where your Virtual Machines are stored, the datasets used to create
them, and some other key files related to zones.  Don’t mess around in here
unless you know what you are doing.&lt;/p&gt;

&lt;h3 id=&quot;var&quot;&gt;/var&lt;/h3&gt;

&lt;p&gt;We all like logs, so those are retained in &lt;code class=&quot;highlighter-rouge&quot;&gt;/var&lt;/code&gt; as normal, as well as various
state files such as the current list of &lt;code class=&quot;highlighter-rouge&quot;&gt;imgadm&lt;/code&gt; datasets and the SSH host keys.&lt;/p&gt;

&lt;h3 id=&quot;opt&quot;&gt;/opt&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/opt&lt;/code&gt; is your main hook into more advanced setup of the global zone.  SmartOS
will import any SMF manifests it finds in &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/custom/smf&lt;/code&gt;, which allows you
to implement &lt;code class=&quot;highlighter-rouge&quot;&gt;rc.local&lt;/code&gt; functionality as demonstrated in &lt;a href=&quot;https://gist.github.com/2606370&quot;&gt;this
gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt&lt;/code&gt; is writeable you can also install packages as per &lt;a href=&quot;http://wiki.smartos.org/display/DOC/Installing+pkgin&quot;&gt;this wiki
page&lt;/a&gt;, however you need
to bear in mind that, as explained earlier, things such as adding users are not
possible, so you may see various errors.&lt;/p&gt;

&lt;h3 id=&quot;usbkey&quot;&gt;/usbkey&lt;/h3&gt;

&lt;p&gt;When you first boot SmartOS and go through the rudimentary installer the
details you provide are stored in &lt;code class=&quot;highlighter-rouge&quot;&gt;/usbkey/config&lt;/code&gt;, which is used during boot
to configure the machine.  If you need to change any of those variables, this
is the file you should edit.&lt;/p&gt;

&lt;p&gt;There are also some variables which aren’t set up by default, so if you want to&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Install an &lt;code class=&quot;highlighter-rouge&quot;&gt;authorized_keys&lt;/code&gt; file for the root user.&lt;/li&gt;
  &lt;li&gt;Set a keyboard map.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;then have a read of &lt;a href=&quot;/posts/smartos-global-zone-tweaks.html&quot;&gt;this post&lt;/a&gt; I wrote
a while ago to find out how to configure those.&lt;/p&gt;

&lt;h3 id=&quot;etcshadow-and-etcssh&quot;&gt;/etc/shadow and /etc/ssh&lt;/h3&gt;

&lt;p&gt;In order to support some very basic configuration, a few &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc&lt;/code&gt; files are their
own mount points onto /usbkey so that changes to them are saved.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/shadow&lt;/code&gt; so that you can change the root password.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/ssh&lt;/code&gt; is initially where the SSH host keys were stored, however they are
now stored under /var/ssh so don’t be surprised if this mount point
disappears at some point.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;

&lt;p&gt;While we’re on the subject, let’s complete this post with a look at how the
global zone is implemented, for interested readers.&lt;/p&gt;

&lt;h3 id=&quot;grub&quot;&gt;GRUB&lt;/h3&gt;

&lt;p&gt;There is a &lt;a href=&quot;http://wiki.smartos.org/display/DOC/Remotely+Upgrading+A+USB+Key+Based+Deployment&quot;&gt;good wiki
guide&lt;/a&gt;
which describes how to mount the USB key.  Once you have done that you can take
a look at the GRUB configuration:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: Assumes your current working directory is the USB key mountpoint.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; less boot/grub/menu.lst
&lt;span class=&quot;c&quot;&gt;...
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;title Live 64-bit (text)
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;   kernel /platform/i86pc/kernel/amd64/unix -B console=text,root_shadow='&amp;lt;crypt&amp;gt;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;',smartos=true
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;   module /platform/i86pc/amd64/boot_archive

title Live 64-bit (noinstall)
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;   kernel /platform/i86pc/kernel/amd64/unix -B console=text,root_shadow='&amp;lt;crypt&amp;gt;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;',standalone=true,noimport=true
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;   module /platform/i86pc/amd64/boot_archive
&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There are a few boot configuration variables which alter how the system is
started, and you can see how they are used by grepping for them in the SMF init
scripts under &lt;code class=&quot;highlighter-rouge&quot;&gt;/lib/svc&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;root_shadowcrypt-string&quot;&gt;root_shadow=’crypt string’&lt;/h4&gt;

&lt;p&gt;This configures the default root password prior to /etc/shadow being mounted,
and changes for each release.  If you need to know what it is, then browse &lt;a href=&quot;https://download.joyent.com/pub/iso/&quot;&gt;the
download site&lt;/a&gt; and look at the
SINGLE_USER_ROOT_PASSWORD.release.txt which correlates with your &lt;code class=&quot;highlighter-rouge&quot;&gt;uname -v&lt;/code&gt;
output, or if you wish you could generate your own password and paste the new
crypted string in here.&lt;/p&gt;

&lt;p&gt;Alternatively as a convenience you can find the default root password inside
the &lt;code class=&quot;highlighter-rouge&quot;&gt;platform&lt;/code&gt; directory:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;platform/root.password
&lt;span class=&quot;go&quot;&gt;seitee3oome4aiPh&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;smartostrue&quot;&gt;smartos=true&lt;/h4&gt;

&lt;p&gt;This variable defines whether to perform the normal SmartOS global zone
initialisation, such as mounting &lt;code class=&quot;highlighter-rouge&quot;&gt;/usbkey&lt;/code&gt; and configuring the system from the
&lt;code class=&quot;highlighter-rouge&quot;&gt;/usbkey/config&lt;/code&gt; file (see &lt;code class=&quot;highlighter-rouge&quot;&gt;/lib/svc/method/fs-joyent&lt;/code&gt; and
&lt;code class=&quot;highlighter-rouge&quot;&gt;/lib/svc/method/smartdc-config&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If left unset (like in the ‘Live 64-bit (noinstall)’ boot option), these will
not be performed.  &lt;code class=&quot;highlighter-rouge&quot;&gt;standalone=true&lt;/code&gt; should be set in those cases to avoid
trying to be a Joyent compute node.&lt;/p&gt;

&lt;h4 id=&quot;noimporttrue&quot;&gt;noimport=true&lt;/h4&gt;

&lt;p&gt;Setting this will skip any configuration and mounting of zpools, and is useful
for if you have issues during the first installation and need to check disks,
etc.&lt;/p&gt;

&lt;p&gt;It’s likely that you do not need to change any of these variables, and if you
hit problems simply use the &lt;code class=&quot;highlighter-rouge&quot;&gt;noinstall&lt;/code&gt; boot option and figure things out from
there.&lt;/p&gt;

&lt;h3 id=&quot;platform-image&quot;&gt;Platform image&lt;/h3&gt;

&lt;p&gt;The only other files on the USB key are:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; find platform &lt;span class=&quot;nt&quot;&gt;-type&lt;/span&gt; f
&lt;span class=&quot;go&quot;&gt;platform/i86pc/kernel/amd64/unix
platform/i86pc/amd64/boot_archive
platform/i86pc/amd64/boot_archive.gitstatus
platform/i86pc/amd64/boot_archive.manifest&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;These are mostly self-explanatory:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;unix&lt;/code&gt; is the SmartOS kernel.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;boot_archive&lt;/code&gt; is the ramdisk image containing the entire OS.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;boot_archive.gitstatus&lt;/code&gt; contains the tip revisions of the &lt;a href=&quot;https://github.com/joyent/&quot;&gt;github
repositories&lt;/a&gt; used to build that particular
image.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;boot_archive.manifest&lt;/code&gt; contains MD5 checksums of the OS files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;upgrades&quot;&gt;Upgrades&lt;/h2&gt;

&lt;p&gt;Given we have just explained about the &lt;code class=&quot;highlighter-rouge&quot;&gt;platform&lt;/code&gt; directory, it is also worth
pointing out that you do not have to reflash your USB key every time, which is
great if your server is inaccessible.  Instead, assuming your USB key is big
enough, you can simply download the newest
&lt;a href=&quot;https://download.joyent.com/pub/iso/platform-latest.tgz&quot;&gt;platform-latest.tgz&lt;/a&gt;
file, move the existing &lt;code class=&quot;highlighter-rouge&quot;&gt;platform&lt;/code&gt; directory out of the way, and unpack
&lt;code class=&quot;highlighter-rouge&quot;&gt;platform-latest.tgz&lt;/code&gt; there instead.  Doing this as an atomic operation is
preferred, for example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;: As of writing this is 20121115T191935Z
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; gtar zxf ~/platform-latest.tgz
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mv &lt;/span&gt;platform platform-&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;uname&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mv &lt;/span&gt;platform-20121115T191935Z platform&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This avoids having no &lt;code class=&quot;highlighter-rouge&quot;&gt;platform&lt;/code&gt; directory, just in case you have a power cut
at that exact point in time!&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;If you want to set up a file server or similar, then SmartOS is probably not
for you.  However, if you are interested in running Virtual Machines and are
able to do all of your work inside them, then SmartOS is perfect for that
purpose, and has a number of advantages over other operating systems.&lt;/p&gt;

&lt;p&gt;Hopefully this has been useful, even if it is to deter you from using SmartOS!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Setting up Samba on SmartOS</title>
      <link>//www.perkin.org.uk/posts/setting-up-samba-on-smartos.html</link>
      <pubDate>Wed, 24 Oct 2012 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/setting-up-samba-on-smartos.html</guid>
      <description>&lt;p&gt;A frequent question on #smartos IRC is how to set up SmartOS as a file server.
Due to the architecture of SmartOS and its focus on virtualisation, this isn’t
as easy as on other systems, and some parts are simply not supported at this
time (e.g. NFS).&lt;/p&gt;

&lt;p&gt;This guide, therefore, is a simple way to get Samba up and running so that you
can at least use a SmartOS machine as a file server, even if it’s perhaps not
the protocol you would initially choose.&lt;/p&gt;

&lt;h2 id=&quot;create-new-virtual-machine&quot;&gt;Create new virtual machine&lt;/h2&gt;

&lt;p&gt;Let’s start by creating a VM, here is what I use locally, you may want to tweak
the settings for your environment.  If you already have a suitable VM
configured you can just skip this step.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Import the base1.8.1 image, though any base image will suffice.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;imgadm update
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;imgadm import 55330ab4-066f-11e2-bd0f-434f2462fada

&lt;span class=&quot;c&quot;&gt;# I store all my VM configs in this directory&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; /usbkey/vmcfg

&lt;span class=&quot;c&quot;&gt;# vmadm configuration for 'store' VM&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi /usbkey/vmcfg/store.json&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;brand&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;joyent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;zfs_io_priority&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;image_uuid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;55330ab4-066f-11e2-bd0f-434f2462fada&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;max_physical_memory&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;quota&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;750&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;alias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;store&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hostname&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;store&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;resolvers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;193.178.223.141&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;208.72.84.24&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;dns_domain&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;adsl.perkin.org.uk&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nics&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nic_tag&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ip&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;192.168.1.11&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;netmask&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;255.255.255.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;gateway&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;192.168.1.1&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Create the VM&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vmadm create &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /usbkey/vmcfg/store.json&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;install-samba-package&quot;&gt;Install Samba package&lt;/h2&gt;

&lt;p&gt;Next, log in to the VM and install the required packages.  These are not
currently available from the default repository, so we will use the generic
illumos package set:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;zlogin &amp;lt;uuid&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Download and unpack bootstrap kit&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; http://pkgsrc.smartos.org/packages/illumos/bootstrap/bootstrap-2012Q3-illumos.tar.gz &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    | gtar &lt;span class=&quot;nt&quot;&gt;-zxf&lt;/span&gt; - &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; /
&lt;span class=&quot;nv&quot;&gt;$ PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/pkg/sbin:/opt/pkg/bin:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Install latest Samba package (others are available if necessary)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; up
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;samba-3.6&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configure-samba&quot;&gt;Configure Samba&lt;/h2&gt;

&lt;p&gt;This part will differ based on your requirements, here are a couple of simple
examples.&lt;/p&gt;

&lt;h4 id=&quot;shared-guest-mount-with-full-readwrite-access&quot;&gt;Shared guest mount with full read/write access&lt;/h4&gt;

&lt;p&gt;For if you just want somewhere to share stuff on a local network with no
security.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Create shared mount user and mountpoint.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;groupadd &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; 500 store
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;useradd &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; 500 &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; 500 &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Store user&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /usr/bin/false &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; /store store
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; /store
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;chown &lt;/span&gt;store:store /store&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Configure Samba&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi /etc/opt/pkg/samba/smb.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;nn&quot;&gt;[global]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;security&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;share&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;printers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;no&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;guest&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;account&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;store&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;; Comment out [homes] section
&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[store]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/store&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;yes&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;only&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;guest&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;yes&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;writable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;yes&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;printable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;no&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;shared-mount-with-per-user-access&quot;&gt;Shared mount with per-user access&lt;/h4&gt;

&lt;p&gt;For a bit more fine-grained control.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Create per-user accounts and mountpoint.&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;groupadd &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; 1000 alice
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;useradd &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; 1000 &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; 1000 &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Alice&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /usr/bin/false &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; /store alice
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;groupadd &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; 1001 bob
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;useradd &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; 1001 &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; 1001 &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Bob&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /usr/bin/false &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; /store bob
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; /store
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;chmod &lt;/span&gt;1777 /store
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;/opt/pkg/bin/smbpasswd &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; alice
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;/opt/pkg/bin/smbpasswd &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; bob&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Configure Samba&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi /etc/opt/pkg/samba/smb.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ini&quot; data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;nn&quot;&gt;[global]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;security&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;user&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;printers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;no&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;; Comment out [homes] section
&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[store]&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/store&lt;/span&gt;
  &lt;span class=&quot;err&quot;&gt;valid&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;alice bob&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;no&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;writable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;yes&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;printable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;no&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Access will be via username and the password set with &lt;code class=&quot;highlighter-rouge&quot;&gt;smbpasswd&lt;/code&gt;.  Users will
be able to create files and read other user files, but will only be able to
modify files they created.&lt;/p&gt;

&lt;h2 id=&quot;startup-scripts&quot;&gt;Startup scripts&lt;/h2&gt;

&lt;p&gt;Okay, so I’m lazy and whilst I should provide some SMF scripts and manifests
for this, it’s simpler to just write an &lt;code class=&quot;highlighter-rouge&quot;&gt;rc.d&lt;/code&gt; script! :-)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;vi /etc/rc2.d/S99samba&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in
&lt;/span&gt;start&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;# Start up Samba daemons&lt;/span&gt;
	/opt/pkg/sbin/nmbd &lt;span class=&quot;nt&quot;&gt;-D&lt;/span&gt;
	/opt/pkg/sbin/smbd &lt;span class=&quot;nt&quot;&gt;-D&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
stop&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	pkill &lt;span class=&quot;nt&quot;&gt;-9&lt;/span&gt; nmbd
	pkill &lt;span class=&quot;nt&quot;&gt;-9&lt;/span&gt; smbd
	&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
reload&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	pkill &lt;span class=&quot;nt&quot;&gt;-HUP&lt;/span&gt; nmbd
	pkill &lt;span class=&quot;nt&quot;&gt;-HUP&lt;/span&gt; smbd
	&lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, start it up!&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;chmod&lt;/span&gt; +x /etc/rc2.d/S99samba
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;/etc/rc2.d/S99samba start&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;multicast-dns&quot;&gt;Multicast DNS&lt;/h2&gt;

&lt;p&gt;In order for shares to automatically show up in e.g. the OSX Finder, you will
need to be running some kind of mDNS service on the server.&lt;/p&gt;

&lt;p&gt;The easiest solution is to simply enable &lt;code class=&quot;highlighter-rouge&quot;&gt;dns/multicast&lt;/code&gt; in the zone, i.e.:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;svcadm &lt;span class=&quot;nb&quot;&gt;enable &lt;/span&gt;dns/multicast&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This will then show up based on the hostname of the server, and clicking on it
should show the &lt;code class=&quot;highlighter-rouge&quot;&gt;store&lt;/code&gt; mount we created.&lt;/p&gt;

&lt;h2 id=&quot;all-done&quot;&gt;All done&lt;/h2&gt;

&lt;p&gt;I hope this proves useful!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>pkgsrc-2012Q3 packages for illumos</title>
      <link>//www.perkin.org.uk/posts/pkgsrc-2012Q3-packages-for-illumos.html</link>
      <pubDate>Wed, 10 Oct 2012 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/pkgsrc-2012Q3-packages-for-illumos.html</guid>
      <description>&lt;h2 id=&quot;note&quot;&gt;Note&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This page is obsolete.&lt;/strong&gt;  Please see &lt;a href=&quot;http://pkgsrc.joyent.com/&quot;&gt;http://pkgsrc.joyent.com/&lt;/a&gt; where you
will find the latest package sets and improved instructions.&lt;/p&gt;

&lt;h2 id=&quot;original-article&quot;&gt;Original Article&lt;/h2&gt;

&lt;p&gt;Continuing from my &lt;a href=&quot;/posts/9000-packages-for-smartos-and-illumos.html&quot;&gt;previous bulk build for
pkgsrc-2012Q2&lt;/a&gt; I’m pleased
to announce that packages from the pkgsrc-2012Q3 branch are now available.&lt;/p&gt;

&lt;p&gt;Quick start:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; http://pkgsrc.smartos.org/packages/illumos/bootstrap/bootstrap-2012Q3-illumos.tar.gz &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    | gtar &lt;span class=&quot;nt&quot;&gt;-zxf&lt;/span&gt; - &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; /
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/pkg/sbin:/opt/pkg/bin:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; up
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin avail | &lt;span class=&quot;nb&quot;&gt;wc&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    9542
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin search &amp;lt;package&amp;gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &amp;lt;package&amp;gt; &amp;lt;package...&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As usual there have been many hundreds of updates since the previous branch,
and hopefully the software you need is included.  If not, please get involved!
We welcome new contributors.&lt;/p&gt;

&lt;p&gt;The bootstrap kit and a number of packages have been tested successfully on
OpenIndiana 151a and OmniOS.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Creating local SmartOS packages</title>
      <link>//www.perkin.org.uk/posts/creating-local-smartos-packages.html</link>
      <pubDate>Thu, 23 Aug 2012 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/creating-local-smartos-packages.html</guid>
      <description>&lt;p&gt;Ok, so you have a &lt;a href=&quot;http://smartos.org/&quot;&gt;SmartOS&lt;/a&gt; machine set up, and are using
&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin&lt;/code&gt; to install packages.  Now you may want to also handle your local
software using the same tools, so that you can take advantage of easily
installing and upgrading packages.  This post describes how you can do this.&lt;/p&gt;

&lt;p&gt;We will be creating a hypothetical package &lt;code class=&quot;highlighter-rouge&quot;&gt;meminfo&lt;/code&gt;, containing a script of
the same name which prints basic memory information, and just enough metadata
for it to be understood by the packaging tools.  This guide assumes you are
running a standard dataset which includes packaging tools in &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local/sbin&lt;/code&gt;,
that is:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; /opt/local/sbin/pkg_info&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;should give you a list of currently installed packages.&lt;/p&gt;

&lt;h3 id=&quot;files-to-install&quot;&gt;Files to install&lt;/h3&gt;

&lt;p&gt;First, let’s start in a clean directory, and then create a &lt;code class=&quot;highlighter-rouge&quot;&gt;files&lt;/code&gt;
sub-directory which will hold the files we want to package.  The files in this
directory will be installed relative to the packaging prefix, which for most
SmartOS installs will be &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/local&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;package
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;package
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; files/bin&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now we create the &lt;code class=&quot;highlighter-rouge&quot;&gt;meminfo&lt;/code&gt; script.  You will probably just copy your binaries
into place at this stage.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi files/bin/meminfo&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/bash&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# This is just a subset of 'sm-summary' from the 'smtools' package.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;SM_UUID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;zonename&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;SM_ID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;zoneadm list &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;: &lt;span class=&quot;s1&quot;&gt;'{ print $1 }'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;SM_MEMCAP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;kstat &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; zone_caps &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; lockedmem_zone_&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SM_ID&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; value | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{print $2/1024/1024 }'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;SM_MEMUSED&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;prstat &lt;span class=&quot;nt&quot;&gt;-Z&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; rss 1 1 | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;zone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SM_UUID&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'$8 ~ zone { printf(&quot;%d&quot;, $4 ) }'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;SM_MEMFREE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SM_MEMCAP&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SM_MEMUSED&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | bc&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
Memory (RSS) Cap    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SM_MEMCAP&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;M
Memory (RSS) Used   &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SM_MEMUSED&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;M
Memory (RSS) Free   &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SM_MEMFREE&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;M
EOF&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ensure the script is executable!&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;chmod&lt;/span&gt; +x files/bin/meminfo&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally for this part, generate a &lt;code class=&quot;highlighter-rouge&quot;&gt;packlist&lt;/code&gt; file which simply contains a list
of files we want packaged, relative to the &lt;code class=&quot;highlighter-rouge&quot;&gt;files&lt;/code&gt; directory:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;files&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; find &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;nt&quot;&gt;-or&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-type&lt;/span&gt; l | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;packlist&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;packlist&lt;/code&gt; file supports many directives which are lines beginning with
&lt;code class=&quot;highlighter-rouge&quot;&gt;@&amp;lt;cmd&amp;gt;&lt;/code&gt;.  These let you do things such as change file permissions once the
file has been installed.  See the ‘PACKING LIST DETAILS’ section of
&lt;a href=&quot;http://netbsd.gw.com/cgi-bin/man-cgi?pkg_create&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_create(1)&lt;/code&gt;&lt;/a&gt; for more
information.&lt;/p&gt;

&lt;h3 id=&quot;package-metadata&quot;&gt;Package metadata&lt;/h3&gt;

&lt;p&gt;In order to successfully create a package, we need a few metadata files which
describe the package.&lt;/p&gt;

&lt;h4 id=&quot;build-info&quot;&gt;build-info&lt;/h4&gt;

&lt;p&gt;This file contains basic information about the package, and is primarily used
to ensure that the package can be installed on the target machine.  The minimum
information required is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;MACHINE_ARCH&lt;/code&gt;.  On SmartOS this is either &lt;code class=&quot;highlighter-rouge&quot;&gt;i386&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;x86_64&lt;/code&gt; depending upon
whether you chose a &lt;code class=&quot;highlighter-rouge&quot;&gt;base/smartos&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;base64/smartos64&lt;/code&gt; dataset.  Attempting
to install a package intended for one architecture with package tools built
for a different architecture will work due to SmartOS being able to run both
32-bit and 64-bit applications, but you will get warnings when installing.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;OPSYS&lt;/code&gt;.  On SmartOS this is &lt;code class=&quot;highlighter-rouge&quot;&gt;SunOS&lt;/code&gt;, i.e. the output of &lt;code class=&quot;highlighter-rouge&quot;&gt;uname -s&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;OS_VERSION&lt;/code&gt;.  On SmartOS this is &lt;code class=&quot;highlighter-rouge&quot;&gt;5.11&lt;/code&gt;, i.e. the output of &lt;code class=&quot;highlighter-rouge&quot;&gt;uname -r&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;PKGTOOLS_VERSION&lt;/code&gt;.  An integer describing the version of the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_install&lt;/code&gt;
tools required to understand this package.  At the current time pkgsrc sets
a base version of &lt;code class=&quot;highlighter-rouge&quot;&gt;20091115&lt;/code&gt; so just use this.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The easiest way to generate this file is simply to get it from an existing
package, for example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; pkg_install &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  | egrep &lt;span class=&quot;s1&quot;&gt;'^(MACHINE_ARCH|OPSYS|OS_VERSION|PKGTOOLS_VERSION)'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;build-info
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;build-info
&lt;span class=&quot;go&quot;&gt;MACHINE_ARCH=i386
OPSYS=SunOS
OS_VERSION=5.11
PKGTOOLS_VERSION=20091115&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;comment&quot;&gt;comment&lt;/h4&gt;

&lt;p&gt;This is a short string describing the package which is shown in the default
&lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_info&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin list&lt;/code&gt; output.  Keep this short, preferably under 60
characters, so that it displays correctly in 80-column terminals.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Show basic memory information on SmartOS&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;comment&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;description&quot;&gt;description&lt;/h4&gt;

&lt;p&gt;This is a longer multi-line description of the package which is output by
&lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_info &amp;lt;package name&amp;gt;&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin pkg-descr &amp;lt;package name&amp;gt;&lt;/code&gt;.  Format this to
80-columns.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;description &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;meminfo prints basic information about available memory on a SmartOS machine,
listing the total memory size, used, and free.  The information provided
should be understood in light of how memory is used and reported on SmartOS,
for more information refer to:

http://wiki.smartos.org/display/DOC/About+Memory+Usage+and+Capping
EOF&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So we should now have:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;build-info          #&lt;/span&gt; basic package information
&lt;span class=&quot;gp&quot;&gt;comment             #&lt;/span&gt; one-line comment
&lt;span class=&quot;gp&quot;&gt;description         #&lt;/span&gt; multi-line comment
&lt;span class=&quot;gp&quot;&gt;files/bin/meminfo   #&lt;/span&gt; the file we wish to package
&lt;span class=&quot;gp&quot;&gt;packlist            #&lt;/span&gt; package listing&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;create-the-package&quot;&gt;Create the package&lt;/h3&gt;

&lt;p&gt;We now have enough information to create a basic package.  The magic invocation
to perform the operation is:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_create &lt;span class=&quot;nt&quot;&gt;-B&lt;/span&gt; build-info &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; comment &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; description &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; packlist &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; /opt/local &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; files &lt;span class=&quot;nt&quot;&gt;-U&lt;/span&gt; meminfo-1.0.tgz&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;-B&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;-c&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;-d&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;-f&lt;/code&gt; arguments simply pull in the metadata files we’ve
written.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;-I&lt;/code&gt; argument specifies the destination prefix.  As we are creating a
package outside of this prefix we need to tell &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_create&lt;/code&gt; of the ultimate
destination.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;-p&lt;/code&gt; argument is used in conjunction with &lt;code class=&quot;highlighter-rouge&quot;&gt;-I&lt;/code&gt; to tell pkg_create where our
files to be packaged can be found.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;-U&lt;/code&gt; argument means we should just create the package, and not register it.&lt;/p&gt;

&lt;p&gt;And finally, we provide the package file.  The packaging tools understand
version numbers, so we can just provide the file name and it will determine the
package name and version from that.&lt;/p&gt;

&lt;p&gt;To verify the package, you can run:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; meminfo-1.0.tgz&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;PKGNAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;meminfo-1.0
&lt;span class=&quot;nv&quot;&gt;COMMENT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;Show basic memory information on SmartOS
&lt;span class=&quot;nv&quot;&gt;MACHINE_ARCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;i386
&lt;span class=&quot;nv&quot;&gt;OPSYS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;SunOS
&lt;span class=&quot;nv&quot;&gt;OS_VERSION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5.11
&lt;span class=&quot;nv&quot;&gt;PKGTOOLS_VERSION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;20091115
&lt;span class=&quot;nv&quot;&gt;FILE_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;meminfo-1.0.tgz
&lt;span class=&quot;nv&quot;&gt;FILE_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;922
&lt;span class=&quot;nv&quot;&gt;DESCRIPTION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;meminfo prints basic information about available memory on a SmartOS machine,
&lt;span class=&quot;nv&quot;&gt;DESCRIPTION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;listing the total memory size, used, and free.  The information provided
&lt;span class=&quot;nv&quot;&gt;DESCRIPTION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;should be understood &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;light of how memory is used and reported on SmartOS,
&lt;span class=&quot;nv&quot;&gt;DESCRIPTION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;more information refer to:
&lt;span class=&quot;nv&quot;&gt;DESCRIPTION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;DESCRIPTION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://wiki.smartos.org/display/DOC/About+Memory+Usage+and+Capping&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;installing&quot;&gt;Installing&lt;/h3&gt;

&lt;p&gt;For a single machine, you can now simply install the package with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_add meminfo-1.0.tgz&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you want to publish the package so that it is available to &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin&lt;/code&gt; you need
to create a &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_summary&lt;/code&gt; file and put it alongside the package for download.
This file is usually compressed to speed things up, and &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin&lt;/code&gt; supports both
&lt;code class=&quot;highlighter-rouge&quot;&gt;.gz&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;.bz2&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_info &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; meminfo-1.0.tgz | &lt;span class=&quot;nb&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-9&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;pkg_summary.gz&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For example purposes I will simply use file://, but of course you can use
http:// instead if you put the packages and pkg_summary file somewhere
accessible:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; /var/tmp/packages
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;meminfo-1.0.tgz pkg_summary.gz /var/tmp/packages&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Add this repository to &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin&lt;/code&gt; and reload:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;file:///var/tmp/packages&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;/opt/local/etc/pkgin/repositories.conf
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pkgin &lt;span class=&quot;nt&quot;&gt;-fy&lt;/span&gt; up&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now the package should show up:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin avail | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;meminfo
&lt;span class=&quot;go&quot;&gt;meminfo-1.0          Show basic memory information on SmartOS&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and be installable:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;meminfo
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; /opt/local/bin/meminfo
&lt;span class=&quot;go&quot;&gt;Memory (RSS) Cap    8192M
Memory (RSS) Used   92M
Memory (RSS) Free   8100M&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This covers the basics and should be enough to get started.  As mentioned,
there are many other options available, and I suggest that if you need
additional functionality you take a look at the
&lt;a href=&quot;http://netbsd.gw.com/cgi-bin/man-cgi?pkg_create&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_create&lt;/code&gt;&lt;/a&gt; manual page, or
simply use &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_info -X&lt;/code&gt; on more complicated packages to see what they do.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>7,000 binary packages for OSX Lion</title>
      <link>//www.perkin.org.uk/posts/7000-packages-for-osx-lion.html</link>
      <pubDate>Tue, 10 Jul 2012 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/7000-packages-for-osx-lion.html</guid>
      <description>&lt;h2 id=&quot;note&quot;&gt;Note&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This page is obsolete.&lt;/strong&gt;  Please see &lt;a href=&quot;http://pkgsrc.joyent.com/&quot;&gt;http://pkgsrc.joyent.com/&lt;/a&gt; where you
will find the latest package sets and improved instructions.&lt;/p&gt;

&lt;h2 id=&quot;original-article&quot;&gt;Original Article&lt;/h2&gt;

&lt;p&gt;For my &lt;a href=&quot;/posts/goodbye-oracle-hello-joyent.html&quot;&gt;day job&lt;/a&gt; I build packages for
our &lt;a href=&quot;http://smartos.org/&quot;&gt;SmartOS&lt;/a&gt; operating system using pkgsrc.  pkgsrc is a
cross-platform package manager which began life as the FreeBSD ports system and
was ported to NetBSD back in 1997.  Since then it has been ported to many other
different systems, 19 at the current count, one of which is OSX/Darwin.&lt;/p&gt;

&lt;p&gt;For the recent pkgsrc-2012Q2 release, I have performed a full bulk build on OSX
Lion, and the result is 7,374 binary packages for you to use as an alternative
to brew/macports/etc.&lt;/p&gt;

&lt;p&gt;To use them, run the following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl http://pkgsrc.smartos.org/packages/Darwin/2012Q2/bootstrap.tar.gz &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    | &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;gnutar &lt;span class=&quot;nt&quot;&gt;-zxpf&lt;/span&gt; -&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/usr/pkg/sbin:/usr/pkg/bin:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; update
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin avail | &lt;span class=&quot;nb&quot;&gt;wc&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    7374
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin search ...
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; ...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgin&lt;/code&gt; is a tool similar to &lt;code class=&quot;highlighter-rouge&quot;&gt;apt-get&lt;/code&gt; and allows you to easily search for and
install/upgrade packages.&lt;/p&gt;

&lt;p&gt;Please let me know if you find them useful, and if you have any feedback.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>9,000 packages for SmartOS and illumos</title>
      <link>//www.perkin.org.uk/posts/9000-packages-for-smartos-and-illumos.html</link>
      <pubDate>Mon, 09 Jul 2012 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/9000-packages-for-smartos-and-illumos.html</guid>
      <description>&lt;h2 id=&quot;note&quot;&gt;Note&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This page is obsolete.&lt;/strong&gt;  Please see &lt;a href=&quot;http://pkgsrc.joyent.com/&quot;&gt;http://pkgsrc.joyent.com/&lt;/a&gt; where you
will find the latest package sets and improved instructions.&lt;/p&gt;

&lt;h2 id=&quot;original-article&quot;&gt;Original Article&lt;/h2&gt;

&lt;p&gt;At &lt;a href=&quot;http://www.joyent.com/&quot;&gt;Joyent&lt;/a&gt;, we provide &lt;a href=&quot;http://smartos.org/&quot;&gt;SmartOS&lt;/a&gt;
users with a set of regularly updated binary packages which are tuned to work
well on our operating system.  The package manager we use, pkgsrc, does not yet
come with native support for e.g. SMF, and so we provide a limited set of
packages, ensuring that those we do we provide include such features.&lt;/p&gt;

&lt;p&gt;However, often users will want packages which are not yet included in our build
set, and so to assist those users we have performed a full bulk build of the
unmodified pkgsrc-2012Q2 release, which resulted in well over 9,000 binary
packages to choose from.&lt;/p&gt;

&lt;p&gt;In addition, thanks to binary compatibility, these packages can also be used on
your illumos distribution of choice (please let me know if this is not the
case!) if your native package manager does not provide the software you want.&lt;/p&gt;

&lt;p&gt;Note that these packages do not come with SMF support, and may be different
from our official packages in terms of build options, etc.  Also, to avoid
conflict with our official packages, these have been built under a different
prefix:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;/opt/pkg	#&lt;/span&gt; main prefix
&lt;span class=&quot;gp&quot;&gt;/etc/opt/pkg	#&lt;/span&gt; configuration files
&lt;span class=&quot;gp&quot;&gt;/var/opt/pkg	#&lt;/span&gt; transient files&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;compared to our official packages:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;/opt/local	#&lt;/span&gt; main prefix
&lt;span class=&quot;gp&quot;&gt;/opt/local/etc	#&lt;/span&gt; configuration files
&lt;span class=&quot;gp&quot;&gt;/var		#&lt;/span&gt; transient files&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To use them, run the following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; For SmartOS use the original build.
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl http://pkgsrc.smartos.org/packages/SmartOS/2012Q2/bootstrap.tar.gz &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    | &lt;span class=&quot;nb&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-dc&lt;/span&gt; | &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-xpf&lt;/span&gt; -&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; For other illumos, use the updated build which should work, but has fewer
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; packages, and you will need to ignore warnings about x86_64 &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; i386.
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; curl http://pkgsrc.smartos.org/packages/SmartOS/2012Q2j1/bootstrap.tar.gz &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    | &lt;span class=&quot;nb&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-dc&lt;/span&gt; | &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-xpf&lt;/span&gt; -&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/pkg/sbin:/opt/pkg/bin:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; update
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin avail | &lt;span class=&quot;nb&quot;&gt;wc&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    9401
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin search ...
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pkgin &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; ...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;What’s included?  Here are just a few highlights:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer tools&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;PHP: 5.4.4, 5.3.14 + ~100 modules for each&lt;/li&gt;
  &lt;li&gt;Perl: 5.14.2 + 1,780 modules&lt;/li&gt;
  &lt;li&gt;Python: 3.2.3, 3.1.5, 2.7.3, 2.6.8, 2.5.6 + ~260 modules for 2.x&lt;/li&gt;
  &lt;li&gt;Ruby: 1.9.3p194, 1.9.2pl320, 1.8.7.358 + ~450 modules for each&lt;/li&gt;
  &lt;li&gt;Editors: (vim 7.2, emacs 23.4 and 24.1, xemacs 21.4)&lt;/li&gt;
  &lt;li&gt;Revision control: (git 1.7.10.5, mercurial 2.2.2, bzr 2.5, svn 1.6.17)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Web stack&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Apache: 2.4.2, 2.2.22, 2.0.64, 1.3.42 + modules&lt;/li&gt;
  &lt;li&gt;MySQL: 5.5.25, 5.1.63, 5.0.96&lt;/li&gt;
  &lt;li&gt;PostgreSQL: 9.1.3, 9.0.7, 8.3.18&lt;/li&gt;
  &lt;li&gt;Wordpress 3.4.1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Desktop&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;GNOME 2.32.1 (not complete)&lt;/li&gt;
  &lt;li&gt;KDE 4.8.4 (not complete)&lt;/li&gt;
  &lt;li&gt;XFCE 4.6.1&lt;/li&gt;
  &lt;li&gt;evilwm 1.1.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;plus thousands of miscellaneous utilities.&lt;/p&gt;

&lt;p&gt;The long-term goal of course is to integrate all of our changes back into the
upstream pkgsrc repository and eventually provide a single package repository,
and we will continue to work on that endeavour.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Goodbye Oracle, Hello Joyent!</title>
      <link>//www.perkin.org.uk/posts/goodbye-oracle-hello-joyent.html</link>
      <pubDate>Mon, 07 May 2012 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/goodbye-oracle-hello-joyent.html</guid>
      <description>&lt;p&gt;Back in 2001 when I started working for the BBC I was given a Sun Ultra 10
workstation running Solaris 8 and
&lt;a href=&quot;https://en.wikipedia.org/wiki/Common_Desktop_Environment&quot;&gt;CDE&lt;/a&gt; to do my job.
As a Linux/FreeBSD user at the time, and someone accustomed to things such as a
working vi implementation, recursive grep and Window Maker, this came as
something of a culture shock, and it wasn’t long before I was compiling my own
software in a rapid attempt to build and configure a more usable desktop
environment - or at least one I was more comfortable in.&lt;/p&gt;

&lt;p&gt;Building all that software by hand quickly became tedious, and so I was
delighted to find that &lt;a href=&quot;http://blog.netbsd.org/tnf/entry/interview_with_christos_zoulas&quot;&gt;Christos
Zoulas&lt;/a&gt; had
written a bunch of portability glue, known as Zoularis, which allowed pkgsrc
(similar to the FreeBSD ports system I was used to) to be used on Solaris.&lt;/p&gt;

&lt;p&gt;It was still early days, however, and so over the next few years I and others
helped to improve Solaris support in pkgsrc.  By 2004 we had over
&lt;a href=&quot;http://mail-index.netbsd.org/pkgsrc-bulk/2004/05/10/0001.html&quot;&gt;1500&lt;/a&gt; packages
building on Solaris 9/SPARC using the Sun Studio compiler, and in 2010 there
were &lt;a href=&quot;/posts/apt-get-and-5000-packages-for-solaris10x86.html&quot;&gt;5000&lt;/a&gt; packages
for Solaris 10/x86, along with a native SFW package including pkgin (an
“apt-get” clone), making it easy to get up and running.&lt;/p&gt;

&lt;p&gt;It was always something of a disappointment to me though that pkgsrc on Solaris
wasn’t more widely deployed as I felt it provided major benefits over Blastwave
or IPS.  So it was great to see &lt;a href=&quot;http://twitter.com/mamash&quot;&gt;Filip Hajný&lt;/a&gt; of
&lt;a href=&quot;http://www.joyent.com/&quot;&gt;Joyent&lt;/a&gt; join the pkgsrc developers in 2009 for his
work on Solaris with Joyent using pkgsrc internally.&lt;/p&gt;

&lt;p&gt;Since then they have:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;hired a &lt;a href=&quot;http://dtrace.org/blogs/bmc/2010/07/30/hello-joyent/&quot;&gt;number&lt;/a&gt;
&lt;a href=&quot;http://dtrace.org/blogs/jerry/2010/09/23/joyent-wow/&quot;&gt;of&lt;/a&gt;
&lt;a href=&quot;http://dtrace.org/blogs/dap/2010/11/17/joining-joyent/&quot;&gt;fantastic&lt;/a&gt;
&lt;a href=&quot;http://dtrace.org/blogs/rm/2010/12/29/started-at-joyent/&quot;&gt;engineers&lt;/a&gt; from
the ashes of Sun Microsystems, who have&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;ported &lt;a href=&quot;http://www.linux-kvm.org/page/Main_Page&quot;&gt;KVM&lt;/a&gt; to their
&lt;a href=&quot;http://smartos.org/&quot;&gt;SmartOS&lt;/a&gt; descendant of Solaris, making it a clear
differentiator in the cloud computing arena (DTrace+ZFS+Zones+KVM is the
perfect combination for multi-tenancy environments), as well as&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;taken stewardship of &lt;a href=&quot;http://nodejs.org/&quot;&gt;node.js&lt;/a&gt; and again hired the
&lt;a href=&quot;http://tinyclouds.org/&quot;&gt;most&lt;/a&gt; &lt;a href=&quot;http://izs.me/&quot;&gt;prominent&lt;/a&gt; engineers involved
in that project&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and thus over that time my desire to work there has only increased.&lt;/p&gt;

&lt;p&gt;So, I am obviously delighted to say that today is my first day working for
Joyent, focusing on making pkgsrc work even better on SmartOS.&lt;/p&gt;

&lt;p&gt;It isn’t just the people and the technology which attracted me, though.  A
recent Twitter post by ex-Sun CEO and co-founder &lt;a href=&quot;https://en.wikipedia.org/wiki/Scott_McNealy&quot;&gt;Scott
McNealy&lt;/a&gt; says it well:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;img src=&quot;/files/images/scottm-tweet.png&quot; alt=&quot;Joyent continue Sun spirit&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;As a long time fan of Sun (I got over the initial shock of Solaris) who was
fortunate enough to work there, and as someone who experienced the fantastic
company culture of MySQL AB, it is this chance to again join an
engineering-driven company that “kicks butt, has fun, doesn’t cheat,
loves its customers, changes computing forever” which excites me the
most.&lt;/p&gt;

&lt;p&gt;Let’s just hope Joyent don’t turn out &lt;em&gt;exactly&lt;/em&gt; the same as Sun Microsystems ;)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>SmartOS global zone tweaks</title>
      <link>//www.perkin.org.uk/posts/smartos-global-zone-tweaks.html</link>
      <pubDate>Fri, 13 Apr 2012 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/smartos-global-zone-tweaks.html</guid>
      <description>&lt;p&gt;The basic premise behind &lt;a href=&quot;http://smartos.org/&quot;&gt;SmartOS&lt;/a&gt; is to provide a
netbooted global zone, and then do actual work inside KVM or zone-based virtual
machines.  This has a number of advantages, not least that it’s trivial to
upgrade to a newer release - you simply boot a newer image.&lt;/p&gt;

&lt;p&gt;However, the read-only nature of the global zone means that if you want to make
changes to the global zone, then they need to be read from permanent storage,
rather than making changes as you would normally.&lt;/p&gt;

&lt;p&gt;SmartOS creates a &lt;code class=&quot;highlighter-rouge&quot;&gt;/usbkey&lt;/code&gt; file system on stable storage which holds
configuration for the global zone, and an init script
&lt;code class=&quot;highlighter-rouge&quot;&gt;/lib/svc/method/smartdc-config&lt;/code&gt; which sources the file &lt;code class=&quot;highlighter-rouge&quot;&gt;/usbkey/config&lt;/code&gt; for
configuration details.  By default this will mostly include details you
provided at install time, however there are additional values you can set to
customise the global zone further.&lt;/p&gt;

&lt;p&gt;Here are a couple that I have found, and need for my personal use.&lt;/p&gt;

&lt;h2 id=&quot;upload-a-root-authorized_keys-file&quot;&gt;Upload a root authorized_keys file&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;root&lt;/code&gt; user’s home directory is provided from the ramdisk, so any changes
you make will be wiped out on the next boot.  This is presumably so that newer
images can make changes to the shell rc files, for example to update &lt;code class=&quot;highlighter-rouge&quot;&gt;$PATH&lt;/code&gt;
without worrying about all users having to merge these changes.&lt;/p&gt;

&lt;p&gt;However, I’m not one for typing in passwords all day, so in order to store a
&lt;code class=&quot;highlighter-rouge&quot;&gt;/root/.ssh/authorized_keys&lt;/code&gt; file you can do this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /usbkey/config.inc
&lt;span class=&quot;c&quot;&gt;# paste your key into this file&lt;/span&gt;
vi /usbkey/config.inc/authorized_keys
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;root_authorized_keys_file=authorized_keys&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;/usbkey/config&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;root_authorized_keys_file&lt;/code&gt; variable points to a file in
&lt;code class=&quot;highlighter-rouge&quot;&gt;/usbkey/config.inc&lt;/code&gt;, you can of course change the name if you wish.&lt;/p&gt;

&lt;h2 id=&quot;set-a-keyboard-map&quot;&gt;Set a keyboard map&lt;/h2&gt;

&lt;p&gt;By default a US keymap will be loaded for the console, if you want to use a
different one then find a suitable layout in &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr/share/lib/keytables/type_6&lt;/code&gt;
(in my case &lt;code class=&quot;highlighter-rouge&quot;&gt;uk&lt;/code&gt;) and then:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;default_keymap=uk&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;/usbkey/config&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;look-for-more-tweaks&quot;&gt;Look for more tweaks&lt;/h2&gt;

&lt;p&gt;As of time of writing (&lt;code class=&quot;highlighter-rouge&quot;&gt;joyent_20120405T204624Z&lt;/code&gt;), these two appear to be the
only tweaks available which aren’t already used by default, however this may
change in the future.  To see if there are any newer ones available, you can:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;CONFIG_ /lib/svc/method/smartdc-config&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and then have a deeper look into the script to see how they are used ;-)&lt;/p&gt;

&lt;h2 id=&quot;run-ad-hoc-scripts&quot;&gt;Run ad-hoc scripts&lt;/h2&gt;

&lt;p&gt;Note that while you may be tempted to think “aha, it’s just a shell
script, I can use it like &lt;code class=&quot;highlighter-rouge&quot;&gt;rc.local&lt;/code&gt;”, you can’t - it’s explicitly parsed
into variables, and trying to put commands in will just break the init script.&lt;/p&gt;

&lt;p&gt;However, the &lt;code class=&quot;highlighter-rouge&quot;&gt;/lib/svc/method/manifest-import&lt;/code&gt; script does import any SMF
manifests it finds in &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/custom/smf&lt;/code&gt;, so if you want to run arbitrary
scripts, then have a look at
&lt;a href=&quot;https://twitter.com/#!/ryancnelson&quot;&gt;@ryancnelson&lt;/a&gt;’s
&lt;a href=&quot;http://www.psychicfriends.net/blog/archives/2012/03/21/smartosorg_run_things_at_boot.html&quot;&gt;example&lt;/a&gt;
and modify to suit your tastes.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Automated VirtualBox SmartOS installs</title>
      <link>//www.perkin.org.uk/posts/automated-virtualbox-smartos-installs.html</link>
      <pubDate>Thu, 12 Apr 2012 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/automated-virtualbox-smartos-installs.html</guid>
      <description>&lt;p&gt;This is a quick script I wrote to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Download the latest live ISO image of &lt;a href=&quot;http://smartos.org/&quot;&gt;SmartOS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Create a VirtualBox VM, or update an existing VM with the latest ISO&lt;/li&gt;
  &lt;li&gt;Configure the VM with a zones disk, and boot it!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the first install you’ll need to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Configure the network (likely just “dhcp”)&lt;/li&gt;
  &lt;li&gt;Add &lt;code class=&quot;highlighter-rouge&quot;&gt;c0d0&lt;/code&gt; as the zones disk&lt;/li&gt;
  &lt;li&gt;Set a root password&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After that it will just update the live ISO and use existing settings.  By
default it will create a port forward so that you can &lt;code class=&quot;highlighter-rouge&quot;&gt;ssh -p 8322
root@localhost&lt;/code&gt; into the VM.&lt;/p&gt;

&lt;p&gt;Here’s the script in full (or you can download it &lt;a href=&quot;/files/mksmartvm&quot;&gt;here&lt;/a&gt;):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Configurables:&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#  - Disk size is in GB&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#  - Memory size is in MB&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#  - SSH port is the local forwarded port to the VM:22&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;disksize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;32&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;memsize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1024&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;sshport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;8322&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SmartOS&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;dlsite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://download.joyent.com/pub/iso&quot;&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;vboxdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;VBoxManage list systemproperties &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/^Default.machine.folder/ { print $4 }'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Find a suitable md5sum program.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;md5 &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;md5sum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'md5'&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'NF'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;elif &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;digest &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
     digest md5 /dev/null &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;md5sum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'digest md5'&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'NF'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;elif &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;digest &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
     digest &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; md5 /dev/null &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;md5sum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'digest -a md5'&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'1'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;elif &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type md5sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;md5sum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'md5sum'&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'1'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;elif &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;openssl &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
     openssl md5 &lt;span class=&quot;nt&quot;&gt;-hex&lt;/span&gt; /dev/null &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;md5sum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'openssl md5 -hex'&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'NF'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ERROR: Sorry, could not find an md5 program&quot;&lt;/span&gt; 1&amp;gt;&amp;amp;2
    &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Download MD5 file and parse it for the latest ISO image and checksum&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
curl &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; smartos-sums.txt &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dlsite&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/md5sums.txt 2&amp;gt;/dev/null
&lt;span class=&quot;nv&quot;&gt;latest_md5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/latest.iso/ { print $1 }'&lt;/span&gt; smartos-sums.txt&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;smartos_version&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ne&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/^&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;latest_md5&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/s/.*-&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.*&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.iso/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/p&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
                    smartos-sums.txt&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;smartos_version&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ERROR: Couldn't determine latest version&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Download the latest ISO image and verify&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vboxdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vboxdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/smartos-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;smartos_version&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.iso&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Downloading &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dlsite&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/smartos-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;smartos_version&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.iso&quot;&lt;/span&gt;
  curl &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vboxdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/smartos-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;smartos_version&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.iso&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dlsite&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/smartos-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;smartos_version&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.iso
  &lt;span class=&quot;nv&quot;&gt;dl_md5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;md5sum&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vboxdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/smartos-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;smartos_version&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.iso&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
             | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{ print $'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;' }'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dl_md5&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ERROR: Couldn't fetch ISO image&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
  &lt;span class=&quot;k&quot;&gt;fi
  if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;latest_md5&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dl_md5&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ERROR: md5 checksums do not match&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
  &lt;span class=&quot;k&quot;&gt;fi
fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Create VirtualBox VM&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Creating/Updating Virtual Machine&quot;&lt;/span&gt;
VBoxManage showvminfo &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-eq&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# VM already exists, just update the ISO image&lt;/span&gt;
    VBoxManage storageattach &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--storagectl&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;IDE Controller&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 1 &lt;span class=&quot;nt&quot;&gt;--device&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; dvddrive &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;--medium&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vboxdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/smartos-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;smartos_version&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.iso&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Create the VM&lt;/span&gt;
    VBoxManage createvm &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--ostype&lt;/span&gt; OpenSolaris_64 &lt;span class=&quot;nt&quot;&gt;--register&lt;/span&gt;
    VBoxManage storagectl &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;IDE Controller&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--add&lt;/span&gt; ide

    &lt;span class=&quot;c&quot;&gt;# Attach the ISO image&lt;/span&gt;
    VBoxManage storageattach &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--storagectl&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;IDE Controller&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 1 &lt;span class=&quot;nt&quot;&gt;--device&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; dvddrive &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;--medium&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vboxdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/smartos-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;smartos_version&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.iso&quot;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;# Create and attach the zone disk&lt;/span&gt;
    VBoxManage createhd &lt;span class=&quot;nt&quot;&gt;--filename&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vboxdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/smartos-zones.vdi&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;--size&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;disksize&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;*1024&quot;&lt;/span&gt; | bc&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    VBoxManage storageattach &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--storagectl&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;IDE Controller&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;--device&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; hdd &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;--medium&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vboxdir&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/smartos-zones.vdi&quot;&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;# Set misc settings&lt;/span&gt;
    VBoxManage modifyvm &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--boot1&lt;/span&gt; dvd &lt;span class=&quot;nt&quot;&gt;--boot2&lt;/span&gt; disk &lt;span class=&quot;nt&quot;&gt;--boot3&lt;/span&gt; none
    VBoxManage modifyvm &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--memory&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;memsize&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
    VBoxManage modifyvm &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--natpf1&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;SSH,tcp,,&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sshport&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,,22&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Start it up&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Starting Virtual Machine&quot;&lt;/span&gt;
VirtualBox &lt;span class=&quot;nt&quot;&gt;--startvm&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;vmname&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &amp;amp;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Hopefully there will be a follow-up post which updates my &lt;a href=&quot;/posts/pkgsrc-on-solaris.html&quot;&gt;pkgsrc on
Solaris&lt;/a&gt; for SmartOS, including zone setup etc.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>iptables script for Debian / Ubuntu</title>
      <link>//www.perkin.org.uk/posts/iptables-script-for-debian-ubuntu.html</link>
      <pubDate>Fri, 30 Mar 2012 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/iptables-script-for-debian-ubuntu.html</guid>
      <description>&lt;p&gt;Most Linux distributions seem to have their own way of handling iptables.  Red
Hat based distributions come with an init script &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/init.d/iptables&lt;/code&gt; which
saves/restores configuration and allows you to check the status.&lt;/p&gt;

&lt;p&gt;Debian / Ubuntu come with .. nothing.&lt;/p&gt;

&lt;p&gt;So, there is a plethora of advice and ways of setting iptables up them, and
this is mine.&lt;/p&gt;

&lt;p&gt;It’s a simple shell script which is installed to
&lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/network/if-pre-up.d/iptables&lt;/code&gt;, meaning it is executed prior to an
interface being brought up - better to do it then than afterwards :)&lt;/p&gt;

&lt;p&gt;I provide a couple of shell functions to make it easy write rules which are to
be applied to both IPv4 and IPv6.&lt;/p&gt;

&lt;p&gt;Here it is in its entirety, feel free to use/copy/whatever, it’s public domain.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# IPTables firewall script.  There are many.  This is mine.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;


&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Ensure sane path&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/sbin:/usr/sbin:/bin:/usr/bin

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# When running from the command line, provide a -v option to print the&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# installed rules at the end.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-v&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;shift
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;on
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Rather than duplicate entries for iptables and ip6tables, have some small&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# wrapper functions do it for us.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# ip4tbl - apply ruleset for just iptables&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# ip6tbl - apply ruleset for just ip6tables&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# iptbl  - apply ruleset for both iptables and ip6tables&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
ip4tbl&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    iptables &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
ip6tbl&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    ip6tables &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
iptbl&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    ip4tbl &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    ip6tbl &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Flush all rulesets&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
iptbl &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;
iptbl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Block by default except outgoing traffic&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
iptbl &lt;span class=&quot;nt&quot;&gt;-P&lt;/span&gt; INPUT DROP
iptbl &lt;span class=&quot;nt&quot;&gt;-P&lt;/span&gt; FORWARD DROP
iptbl &lt;span class=&quot;nt&quot;&gt;-P&lt;/span&gt; OUTPUT ACCEPT

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Allow everything on loopback&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
iptbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; lo &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Permit established connections&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
iptbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; conntrack &lt;span class=&quot;nt&quot;&gt;--ctstate&lt;/span&gt; RELATED,ESTABLISHED &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Permit allowed services on all interfaces.  DNS is restricted to my public&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# DNS servers, this just runs a hidden master.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
iptbl  &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 22   &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
iptbl  &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 25   &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip4tbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 53   &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 85.158.46.77    &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip4tbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; udp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; udp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 53   &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 85.158.46.77    &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip4tbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 53   &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 193.108.199.128 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip4tbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; udp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; udp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 53   &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 193.108.199.128 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip4tbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 53   &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 193.108.199.130 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip4tbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; udp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; udp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 53   &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 193.108.199.130 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip4tbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 53   &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 213.5.89.46     &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip4tbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; udp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; udp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 53   &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 213.5.89.46     &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
iptbl  &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 80   &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
iptbl  &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 113  &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
iptbl  &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 443  &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
iptbl  &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 465  &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
iptbl  &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 993  &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Permit ICMP and traceroute&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
ip4tbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; icmp &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
ip6tbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; ipv6-icmp &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
iptbl  &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; udp &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; udp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 33434:33523 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Log denied connections&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;LOGCOMMON&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-m limit --limit 5/min -j LOG --log-prefix 'iptables: ' --log-level 7&quot;&lt;/span&gt;
iptbl  &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp       &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;LOGCOMMON&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
iptbl  &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; udp       &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;LOGCOMMON&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
ip4tbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; icmp      &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;LOGCOMMON&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
ip6tbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; ipv6-icmp &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;LOGCOMMON&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Finally, reject to keep open connections down&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
iptbl &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; REJECT

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Display INPUT chain if verbose&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;iptables  &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-vn&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--line-numbers&lt;/span&gt;
    ip6tables &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; INPUT &lt;span class=&quot;nt&quot;&gt;-vn&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--line-numbers&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Just remember to make it executable ;-)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>New site design</title>
      <link>//www.perkin.org.uk/posts/new-site-design.html</link>
      <pubDate>Mon, 20 Feb 2012 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/new-site-design.html</guid>
      <description>&lt;p&gt;I am a minimalist at heart, and I love command line interfaces and text files.&lt;/p&gt;

&lt;p&gt;However, I’m also pragmatic, and so for a long time my blog has been powered by
Wordpress, which made it relatively easy to manage content and design.  I just
didn’t want the hassle of maintaining something myself.&lt;/p&gt;

&lt;p&gt;Somewhere along the way recently I stumbled across
&lt;a href=&quot;https://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt;, and the idea of generating a
static site from templates.&lt;/p&gt;

&lt;p&gt;I’d seen a few sites I liked the look of, and I loved the idea of simplifying
my site (and editing posts in vim!), and so the end result is the site you see
now.&lt;/p&gt;

&lt;p&gt;I pondered implementing something like &lt;a href=&quot;http://disqus.com/&quot;&gt;disqus&lt;/a&gt; for
comments, but honestly I get so few proper responses, compared to the hundreds
and hundreds of spam attempts, that it’s not worth it - if you want to comment
on a post, just use twitter (I’ll probably implement a little button to do that
at some point).&lt;/p&gt;

&lt;p&gt;Also, I got rid of categories, simpler to just have tags.&lt;/p&gt;

&lt;p&gt;It’s likely I’ve messed up conversion of my old blog posts, as I did them all
manually.  If you spot anything obviously broken, please let me know.  One of
the great things of the Jekyll approach is that you can simply manage your site
via github, and so if you prefer you can comment on breakages
&lt;a href=&quot;https://github.com/jperkin/www.perkin.org.uk&quot;&gt;here&lt;/a&gt;!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Set up anonymous FTP upload on Oracle Linux</title>
      <link>//www.perkin.org.uk/posts/set-up-anonymous-ftp-upload-on-oracle-linux.html</link>
      <pubDate>Wed, 11 Jan 2012 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/set-up-anonymous-ftp-upload-on-oracle-linux.html</guid>
      <description>&lt;p&gt;Just because this took a little longer than I expected, here’s a quick howto
for setting up an anonymous FTP drop-off on Oracle Linux, which I use as a
simple way to transfer files out of my Virtual Machines.&lt;/p&gt;

&lt;h2 id=&quot;install-vsftpd&quot;&gt;Install vsftpd&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;yum &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;vsftpd&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configure-iptables&quot;&gt;Configure iptables&lt;/h2&gt;

&lt;p&gt;As FTP is a more complicated protocol than most, there is a special netfilter
module required in order to correctly keep track of connections.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; You will perhaps want to change the insert number here.
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;iptables &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt; INPUT 4 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; state &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt; NEW &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; tcp &lt;span class=&quot;nt&quot;&gt;--dport&lt;/span&gt; 21 &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; ACCEPT
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; /etc/init.d/iptables save&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Add &lt;code class=&quot;highlighter-rouge&quot;&gt;nf_conntrack_ftp&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;IPTABLES_MODULES&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;vi /etc/sysconfig/iptables-config&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then load the module rather than reboot&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;modprobe nf_conntrack_ftp&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;create-incoming&quot;&gt;Create /incoming&lt;/h2&gt;

&lt;p&gt;Create &lt;code class=&quot;highlighter-rouge&quot;&gt;/incoming&lt;/code&gt; area and ensure it has the correct file permissions and
SELinux context.  This is the bit which had me stumped for a little while, as I
didn’t know about &lt;code class=&quot;highlighter-rouge&quot;&gt;allow_ftpd_anon_write&lt;/code&gt;, and while I normally just disable
SELinux, I do also like to know how things should work (and be able to write
about them!):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo mkdir&lt;/span&gt; /var/ftp/incoming
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo chown &lt;/span&gt;ftp:ftp /var/ftp/incoming
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; This allows anonymous &lt;span class=&quot;nb&quot;&gt;users &lt;/span&gt;to upload, but not see what is &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;the directory
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo chmod &lt;/span&gt;750 /var/ftp/incoming
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo chcon&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; system_u &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; public_content_rw_t /var/ftp/incoming
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;setsebool &lt;span class=&quot;nv&quot;&gt;allow_ftpd_anon_write&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configure-vsftpd&quot;&gt;Configure vsftpd&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;vi /etc/vsftpd/vsftpd.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;anon_upload_enable=YES&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;startup&quot;&gt;Startup&lt;/h2&gt;

&lt;p&gt;Finally, enable and start vsftpd:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;chkconfig vsftpd on
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; /etc/init.d/vsftpd start&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And that’s it, you should now be able to FTP as anonymous and upload files into &lt;code class=&quot;highlighter-rouge&quot;&gt;/incoming&lt;/code&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Kickstart Oracle Linux in VirtualBox</title>
      <link>//www.perkin.org.uk/posts/kickstart-oracle-linux-in-virtualbox.html</link>
      <pubDate>Mon, 09 Jan 2012 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/kickstart-oracle-linux-in-virtualbox.html</guid>
      <description>&lt;p&gt;In my &lt;a href=&quot;/posts/kickstart-oracle-linux-from-ubuntu.html&quot;&gt;previous post&lt;/a&gt; I
configured an Ubuntu laptop as a Kickstart install server for a physical
machine I wanted to build.&lt;/p&gt;

&lt;p&gt;Now that everything is configured for automated installs, it makes sense to use
the same infrastructure to install virtual machines too.  Everything can be
done from the command line, and new virtual machines can be provisioned very
quickly.&lt;/p&gt;

&lt;p&gt;Again, I will use Oracle Linux 6.2 as an example.&lt;/p&gt;

&lt;h2 id=&quot;create-virtual-machine&quot;&gt;Create Virtual Machine&lt;/h2&gt;

&lt;p&gt;These commands create a new virtual machine, including disk, and configures it
for network booting.  If you don’t already have VirtualBox installed:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;virtualbox&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Set the name of the virtual machine as it appears in VirtualBox, this variable
is then used throughout:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Oracle Linux 6.2&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Create the VM:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage createvm &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--ostype&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Oracle_64&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--register&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Create the hard disk (32GB expanding) and attach it via SATA. Note that I store
my VMs in &lt;code class=&quot;highlighter-rouge&quot;&gt;${HOME}/VirtualBox&lt;/code&gt; rather than the default &lt;code class=&quot;highlighter-rouge&quot;&gt;${HOME}/VirtualBox VMs&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage createhd &lt;span class=&quot;nt&quot;&gt;--filename&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;VirtualBox/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.vdi&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--size&lt;/span&gt; 32768
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage storagectl &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;SATA Controller&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--add&lt;/span&gt; sata &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;   &lt;span class=&quot;nt&quot;&gt;--controller&lt;/span&gt; IntelAHCI
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage storageattach &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--storagectl&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;SATA Controller&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 0 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;   &lt;span class=&quot;nt&quot;&gt;--device&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; hdd &lt;span class=&quot;nt&quot;&gt;--medium&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;VirtualBox/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.vdi&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Default RAM is 128MB, Oracle Linux installer requires at least 512MB however.
Once installed we can drop back down to 256MB or so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage modifyvm &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--memory&lt;/span&gt; 512&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Configure boot order. Put disk first, as on the first boot there is nothing on
it so it falls through to PXE for install, then after the install the disk is
bootable.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage modifyvm &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--boot1&lt;/span&gt; disk &lt;span class=&quot;nt&quot;&gt;--boot2&lt;/span&gt; net &lt;span class=&quot;nt&quot;&gt;--boot3&lt;/span&gt; none &lt;span class=&quot;nt&quot;&gt;--boot4&lt;/span&gt; none&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Change NIC type from the default e1000, as a vanilla VirtualBox install does
not include the firmware necessary to network boot from that device – it is
available in the “VirtualBox Extension Pack” add-on.  Switch to a
plain PCNet Fast III which does include PXE firmware.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage modifyvm &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--nictype1&lt;/span&gt; Am79C973&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;VirtualBox does have the ability to serve TFTP directly from the file system by
placing files inside &lt;code class=&quot;highlighter-rouge&quot;&gt;${HOME}/.VirtualBox/TFTP/&lt;/code&gt; but I prefer to just use the
network as it’s already configured.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage modifyvm &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--nattftpserver1&lt;/span&gt; 10.0.2.2
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage modifyvm &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--nattftpfile1&lt;/span&gt; pxelinux.0&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configure-pxelinuxkickstart&quot;&gt;Configure pxelinux/kickstart&lt;/h2&gt;

&lt;p&gt;We just need a couple of tweaks to the configs from the last blog entry, as the
network addresses are different inside VirtualBox, and we also may want a
different kickstart configuration.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;vi /var/lib/tftpboot/pxelinux.cfg/default&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I just amended the existing entry to point to 10.0.2.2 which is the address of
the machine running VirtualBox, and a different ks-vm.cfg kickstart
configuration file, but you could also create a new label if you wanted to
regularly switch between different configurations:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;LABEL ol6.2
    KERNEL /ol6.2/vmlinuz
    APPEND initrd=/ol6.2/initrd.img ks=http://10.0.2.2/ks-vm.cfg&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For virtual machines I use a slightly different configuration compared to
previously.  I’ve only shown the changes below, not the full file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo cp&lt;/span&gt; /usr/share/nginx/www/ks.cfg /usr/share/nginx/www/ks-vm.cfg&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;# Update network configuration for DHCP instead of static
network --bootproto=dhcp
url --url=http://10.0.2.2/ol6.2

# Don't specify disks, just use default layout
bootloader --location=mbr --driveorder=sda
clearpart --all --initlabel

# Just add 'screen' to the default set of @base and @core packages.
%packages
screen
%end&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;start-virtual-machine&quot;&gt;Start Virtual Machine&lt;/h2&gt;

&lt;p&gt;All that’s left to do is to boot up the VM, and everything else should run automatically.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VirtualBox &lt;span class=&quot;nt&quot;&gt;--startvm&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;All done!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Kickstart Oracle Linux from Ubuntu</title>
      <link>//www.perkin.org.uk/posts/kickstart-oracle-linux-from-ubuntu.html</link>
      <pubDate>Mon, 09 Jan 2012 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/kickstart-oracle-linux-from-ubuntu.html</guid>
      <description>&lt;p&gt;As my new job involves working on Oracle Linux, I figured I should migrate my
home server to it, which would also mean I could move it to a proper RAID10
configuration rather than relying on multiple RAID1s.&lt;/p&gt;

&lt;p&gt;My laptop runs Ubuntu, and I wanted to install the server from it using PXE and
Kickstart, so here’s how I did it.&lt;/p&gt;

&lt;h2 id=&quot;configure-dhcpd&quot;&gt;Configure dhcpd&lt;/h2&gt;

&lt;p&gt;DHCP is required for two things, to give the server its network configuration,
and to point it at the PXE boot loader we want to use.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;isc-dhcp-server
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;vi /etc/dhcp/dhcpd.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here’s the configuration I used, which says to configure 192.168.2.0/24 with a
dynamic DHCP range between 192.168.2.100 – 192.168.2.200, and to boot machines
using pxelinux.0 which is relative to the TFTP root directory (configured in
the next section):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;subnet 192.168.2.0 netmask 255.255.255.0 {
    range 192.168.2.100 192.168.2.200;
    filename &quot;pxelinux.0&quot;;
}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The isc-dhcp-server install automatically tries to start the server, but will
fail as it isn’t configured, so we restart it now that there is a working
configuration installed&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; /etc/init.d/isc-dhcp-server restart&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configure-tftpd&quot;&gt;Configure tftpd&lt;/h2&gt;

&lt;p&gt;TFTP is a simple protocol used to transfer files over the network, and due to
its simplicity it is the primary way to network boot, as it can be easily
embedded into firmware.&lt;/p&gt;

&lt;p&gt;All we need to do is install the TFTP daemon and syslinux which includes the
PXE boot loader, then put the pxelinux file into the tftproot area:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;syslinux tftpd-hpa
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo cp&lt;/span&gt; /usr/lib/syslinux/pxelinux.0 /var/lib/tftpboot&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configure-oracle-linux-dvd&quot;&gt;Configure Oracle Linux DVD&lt;/h2&gt;

&lt;p&gt;To save space on the laptop we can just mount the DVD read-only and install
from that:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo mkdir&lt;/span&gt; /media/ol6.2
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mount &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; loop,ro /path/to/OracleLinux-R6-U2-Server-x86_64-dvd.iso /media/ol6.2&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, we do need to copy the kernel and initrd image from the DVD into the
tftproot as they are required for booting:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo mkdir&lt;/span&gt; /var/lib/tftpboot/ol6.2 /var/lib/tftpboot/pxelinux.cfg
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo cp&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; /mnt/images/pxeboot/&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;initrd.img,vmlinuz&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; /var/lib/tftpboot/ol6.2/&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configure-pxelinux&quot;&gt;Configure pxelinux&lt;/h2&gt;

&lt;p&gt;All that’s left for the PXE stage is to configure the boot loader, and tell it
what kernel and initrd we want to use:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;vi /var/lib/tftpboot/pxelinux.cfg/default&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This configuration has just one entry which is booted after a short wait, but
pxelinux has many more options, including the ability to boot from local disk.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;DEFAULT	ol6.2
PROMPT 1
TIMEOUT 5

LABEL ol6.2
    KERNEL /ol6.2/vmlinuz
    APPEND initrd=/ol6.2/initrd.img ks=http://192.168.2.1/ks.cfg&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note the ks argument which specifies the kickstart file we will use, that and
the web server required to serve it will be set up next.&lt;/p&gt;

&lt;h2 id=&quot;configure-nginx&quot;&gt;Configure nginx&lt;/h2&gt;

&lt;p&gt;I chose nginx as it is small and simple to configure, but any web server will
do.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;nginx
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;vi /etc/nginx/sites-available/default&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The install will be performed over HTTP, so we need to make the DVD we mounted
earlier available.  This entry in the &lt;code class=&quot;highlighter-rouge&quot;&gt;server { }&lt;/code&gt; section makes the DVD
available via http://192.168.2.1/ol6.2/:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;server {
[...]
    location /ol6.2 {
        root /media;
        autoindex on;
        allow all;
    }&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then start nginx (unlike isc-dhcp-server this isn’t done automatically):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ sudo /etc/init.d/nginx start&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;configure-kickstart&quot;&gt;Configure kickstart&lt;/h2&gt;

&lt;p&gt;Finally, we create a kickstart configuration which specifies exactly how our
target machine is to be installed, and this allows a completely unattended
installation.&lt;/p&gt;

&lt;p&gt;Ideally I should create a specific area for holding files like this, but as a
quick hack I simply put it into the default nginx web root (and thus available
as http://192.168.2.1/ks.cfg as configured earlier in the pxelinux.cfg/default
file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;sudo vi /usr/share/nginx/www/ks.cfg&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here is my ks.cfg file in full. The only thing missing is a rootpw line to
automatically set a root password, however for maximum security I am happy to
forego a completely unattended installation and instead have the installer
prompt me to type it in during the install.&lt;/p&gt;

&lt;p&gt;Some notes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;UK keyboard language and timezone selected.&lt;/li&gt;
  &lt;li&gt;Automatically reboot when the installer is finished.&lt;/li&gt;
  &lt;li&gt;Point to the Oracle Linux DVD using the url directive.&lt;/li&gt;
  &lt;li&gt;I have 4 disks configured with RAID1 for /boot, and RAID10 for swap and /.&lt;/li&gt;
  &lt;li&gt;Disks are referred to by path, to ensure correct ordering.&lt;/li&gt;
  &lt;li&gt;A small set of packages are installed, containing just the functionality I require.&lt;/li&gt;
  &lt;li&gt;A small %post section is used to perform any fixes I want for the first boot.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;#
# Miscellaneous options.
#
install
keyboard uk
lang en_GB.UTF-8
reboot
selinux --enforcing
timezone Europe/London

#
# User setup.  I'd create my local user here and configure sudoers, but
# kickstart doesn't yet support creating a user with uid/gid of 1000 (the
# gid is always 500, even if you add the named group first).
#
authconfig --enableshadow --passalgo=sha512

#
# Networking.  The 'network' line needs to be on a single line
# for kickstart to work - it is only split here for the blog.
#
firewall --service=ssh
network --bootproto=static \
        --hostname=gromit.adsl.perkin.org.uk \
        --ip=192.168.2.10 \
        --netmask=255.255.255.0 \
        --gateway=192.168.2.1 \
        --nameserver=193.178.223.141,208.72.84.24 \
        --ipv6=auto
url --url=http://192.168.2.1/ol6.2

#
# Disk configuration.
#
bootloader --location=mbr --driveorder=sda,sdb,sdc,sdd
clearpart --all --initlabel
#
# /boot (RAID1 necessary as booting from RAID10 isn't supported)
#
part raid.00 --asprimary --size=1024 --ondisk=/dev/disk/by-path/pci-*-0*0
part raid.01 --asprimary --size=1024 --ondisk=/dev/disk/by-path/pci-*-1*0
part raid.02 --asprimary --size=1024 --ondisk=/dev/disk/by-path/pci-*-2*0
part raid.03 --asprimary --size=1024 --ondisk=/dev/disk/by-path/pci-*-3*0
raid /boot --level=1 --device=md0 --fstype=ext4 raid.00 raid.01 raid.02 raid.03
#
# swap, RAID10 of size RAM+2GB, give or take..
#
part raid.10 --asprimary --size=6144 --ondisk=/dev/disk/by-path/pci-*-0*0
part raid.11 --asprimary --size=6144 --ondisk=/dev/disk/by-path/pci-*-1*0
part raid.12 --asprimary --size=6144 --ondisk=/dev/disk/by-path/pci-*-2*0
part raid.13 --asprimary --size=6144 --ondisk=/dev/disk/by-path/pci-*-3*0
raid swap --level=10 --device=md1 --fstype=swap raid.10 raid.11 raid.12 raid.13
#
# /, RAID10 of remainder (have to specify an arbitrary --size even with --grow)
#
part raid.20 --asprimary --size=1024 --grow --ondisk=/dev/disk/by-path/pci-*-0*0
part raid.21 --asprimary --size=1024 --grow --ondisk=/dev/disk/by-path/pci-*-1*0
part raid.22 --asprimary --size=1024 --grow --ondisk=/dev/disk/by-path/pci-*-2*0
part raid.23 --asprimary --size=1024 --grow --ondisk=/dev/disk/by-path/pci-*-3*0
raid / --level=10 --device=md2 --fstype=ext4 raid.20 raid.21 raid.22 raid.23

#
# Packages.  @base and @core are pre-selected.
#
%packages
@cifs-file-server
@console-internet --optional
@development
@legacy-unix --optional
@mail-server
@network-server --optional
@network-tools
@nfs-file-server
@web-server
screen
%end

#
# Post-install fix-ups.
#
%post
#
# The 'network' directive doesn't support DNS search paths, so set those
# manually, and disable Network Manager.
#
printf &quot;/^NM_CONTROLLED/s/yes/no/\nw\nq\n&quot; \
  | ed /etc/sysconfig/network-scripts/ifcfg-eth0
printf &quot;/^#/s/.*/search adsl.perkin.org.uk perkin.org.uk/\nw\nq\n&quot; \
  | ed /etc/resolv.conf
#
# Disable unwanted services
#
chkconfig --del cups
%end&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;All done.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Last day at MySQL</title>
      <link>//www.perkin.org.uk/posts/last-day-at-mysql.html</link>
      <pubDate>Thu, 22 Dec 2011 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/last-day-at-mysql.html</guid>
      <description>&lt;p&gt;Today is my final day working on MySQL.  It has been an amazing 4.5 years, and
I’ve loved working on the technical challenges involved in producing a piece of
software which runs on so many different platforms, as well as working with so
many talented individuals.  I have learned a lot, which is just how I like it.&lt;/p&gt;

&lt;p&gt;Times have changed since I first joined MySQL AB, of course.  But despite going
through two acquisitions, the day to day work hasn’t changed much at all.  I
still get to work from home, which is something I am passionate about and feel
many companies are missing out on massively by still being stuck in an outdated
20th century mindset.  Oracle have continued to invest in MySQL, providing
additional headcount and extra hardware.  And the vast majority of people I
started working with back in 2007 are still with the company (don’t believe the
FUD, folks) and working harder than ever.&lt;/p&gt;

&lt;p&gt;I’m most proud of the work we have done internally to ensure our MySQL releases
are in excellent shape.  When I first joined, our internal
“PushBuild” system was very limited, only able to handle a small
number of pushes with reduced testing across a few platforms, and the builds
produced were completely different to those that were released.&lt;/p&gt;

&lt;p&gt;Nowadays, thanks to the investment made by Sun and Oracle, we have a large
server farm producing thousands of builds and hundreds of gigabytes of data
every day across all our supported platforms.  Those which are based on MySQL
5.5 or newer have additional package verification tests, using chroots and
virtual machines, to ensure that the RPM/MSI/etc packages can be installed,
run, and uninstalled, all automatically and on every push by developers.  We
run additional nightly and weekly tests which extend the default set of test
suites.  Our 5.5+ releases are produced directly in PushBuild.  And we are
looking to extend this to all MySQL products, not just the Server.&lt;/p&gt;

&lt;p&gt;If the above sounds fun, keep an eye out for job posts, as the Release
Engineering team is looking to expand, and they are an amazing group of people
to work with.&lt;/p&gt;

&lt;p&gt;I certainly found it fun, which is why I’m going to continue in that line of
work, and stay within Oracle, but move to the Linux group.  To be honest,
databases have never been a passion of mine, however I am rather fond of
Operating Systems, and so I am really looking forward to continuing to work on
continuous integration and testing, but with Oracle Linux and Oracle VM instead
of MySQL.  Plus, it will be nice to go back to a purely technical role – I have
learned over the last year or so that management isn’t really my thing :)&lt;/p&gt;

&lt;p&gt;To all my colleagues, past and present, thank you for the wonderful ride.  I
have many, many good memories, and hopefully we will keep in touch.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Installing OpenBSD with softraid</title>
      <link>//www.perkin.org.uk/posts/installing-openbsd-with-softraid.html</link>
      <pubDate>Thu, 15 Dec 2011 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/installing-openbsd-with-softraid.html</guid>
      <description>&lt;p&gt;This is more of a log for me than anything else, but perhaps someone will find
this useful.&lt;/p&gt;

&lt;p&gt;OpenBSD includes a software RAID implementation which supports booting in newer
snapshots, and I was itching to install the latest version and use it as my
file server, which has 4 750GB disks.  There is a small bit of preparation work
to do prior to installing, which is the bulk of this entry, most of which is
based on &lt;a href=&quot;http://www.undeadly.org/cgi?action=article&amp;amp;sid=20111002154251&quot;&gt;this undeadly.org
article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Grab latest amd64
&lt;a href=&quot;http://mirror.bytemark.co.uk/OpenBSD/snapshots/amd64/install50.iso&quot;&gt;snapshot&lt;/a&gt;,
boot it, drop into (S)hell mode and set up the disks:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /dev
sh MAKEDEV sd1 sd2 sd3 sd4 sd5
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;disk &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;0 1 2 3
&lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# Clear beginning of disks..&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;dd &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/zero &lt;span class=&quot;nv&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/rsd&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;disk&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;c &lt;span class=&quot;nv&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1m &lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10

  &lt;span class=&quot;c&quot;&gt;# ..and initialise new partition table&lt;/span&gt;
  fdisk &lt;span class=&quot;nt&quot;&gt;-iy&lt;/span&gt; sd&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;disk&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# Create BSD disklabel:&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# - 128m partitions at start to hold kernels for booting&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# - 4g spare raid on each disk for testing&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# - rest raid for main OS and data&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;#   - OS and /home on first two mirrored disks&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;#   - /store on second two mirrored disks&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
  print &lt;span class=&quot;s2&quot;&gt;&quot;a a&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;128m&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;4g&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;raid&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a e&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\n\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;raid&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    | disklabel &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; sd&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;disk&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# Clear beginning of raid partitions&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;dd &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/zero &lt;span class=&quot;nv&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/rsd&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;disk&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;d &lt;span class=&quot;nv&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1m &lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10
  &lt;span class=&quot;nb&quot;&gt;dd &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/zero &lt;span class=&quot;nv&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/rsd&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;disk&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;e &lt;span class=&quot;nv&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1m &lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Create RAID1 mirrors&lt;/span&gt;
bioctl &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; 1 &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; sd0e,sd1e softraid0
bioctl &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; 1 &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; sd2e,sd3e softraid0

&lt;span class=&quot;c&quot;&gt;# Exit shell and start the (I)nstall&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As for the install, go with the sensible defaults, other than:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;change keyboard layout to “uk”&lt;/li&gt;
  &lt;li&gt;manually configure network, enable rtsol&lt;/li&gt;
  &lt;li&gt;start ntpd&lt;/li&gt;
  &lt;li&gt;do not expect to run X&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When it comes to disk selection, choose sd4 as the root disk, and use the
following layout:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;# partition  size  mount
  sd4a       1G    /
  sd4b       8G    swap
  sd4d       1G    /tmp
  sd4e       8G    /var
  sd4f       16G   /usr
  sd4h       rest  /home&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;then initialise sd5 with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;# partition  size  mount
  sd5a       2G    /altroot
  sd5d       8G    /scratch
  sd5e       rest  /store&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Install the full OS, set the correct timezone, then before rebooting initialize
the boot partitions and copy the kernels to them.  Doing this on all of them
means we can boot from any disk.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;disk &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;0 1 2 3
&lt;span class=&quot;k&quot;&gt;do
  &lt;/span&gt;newfs sd&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;disk&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;a
  mount /dev/sd&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;disk&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;a /mnt2
  &lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; /mnt/bsd&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; /mnt2
  umount /mnt2
&lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;eject cd0a
reboot&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Job done.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Create VirtualBox VM from the command line</title>
      <link>//www.perkin.org.uk/posts/create-virtualbox-vm-from-the-command-line.html</link>
      <pubDate>Wed, 21 Sep 2011 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/create-virtualbox-vm-from-the-command-line.html</guid>
      <description>&lt;p&gt;As something of a follow-up post to the previous entry, here’s a quick recipe
for creating a Virtual Machine using the VirtualBox command line tools:&lt;/p&gt;

&lt;p&gt;We’re using Windows Server 2008 64bit as an example, modify to taste.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;VM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Windows-2008-64bit'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Create a 32GB “dynamic” disk.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage createhd &lt;span class=&quot;nt&quot;&gt;--filename&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt;.vdi &lt;span class=&quot;nt&quot;&gt;--size&lt;/span&gt; 32768&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can get a list of the OS types VirtualBox recognises using:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage list ostypes&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then copy the most appropriate one into here.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage createvm &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--ostype&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Windows2008_64&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--register&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Add a SATA controller with the dynamic disk attached.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage storagectl &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;SATA Controller&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--add&lt;/span&gt; sata &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;--controller&lt;/span&gt; IntelAHCI
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage storageattach &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--storagectl&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;SATA Controller&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 0 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;--device&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; hdd &lt;span class=&quot;nt&quot;&gt;--medium&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt;.vdi&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Add an IDE controller with a DVD drive attached, and the install ISO inserted
into the drive:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage storagectl &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;IDE Controller&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--add&lt;/span&gt; ide
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage storageattach &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--storagectl&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;IDE Controller&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 0 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;--device&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; dvddrive &lt;span class=&quot;nt&quot;&gt;--medium&lt;/span&gt; /path/to/windows_server_2008.iso&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Misc system settings.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage modifyvm &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--ioapic&lt;/span&gt; on
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage modifyvm &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--boot1&lt;/span&gt; dvd &lt;span class=&quot;nt&quot;&gt;--boot2&lt;/span&gt; disk &lt;span class=&quot;nt&quot;&gt;--boot3&lt;/span&gt; none &lt;span class=&quot;nt&quot;&gt;--boot4&lt;/span&gt; none
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage modifyvm &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--memory&lt;/span&gt; 1024 &lt;span class=&quot;nt&quot;&gt;--vram&lt;/span&gt; 128
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage modifyvm &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--nic1&lt;/span&gt; bridged &lt;span class=&quot;nt&quot;&gt;--bridgeadapter1&lt;/span&gt; e1000g0&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Configuration is all done, boot it up! If you’ve done this one a remote
machine, you can RDP to the console via &lt;code class=&quot;highlighter-rouge&quot;&gt;vboxhost:3389&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxHeadless &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Once you have configured the operating system, you can shutdown and eject the
DVD.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage storageattach &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--storagectl&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;IDE Controller&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--port&lt;/span&gt; 0 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;--device&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;--type&lt;/span&gt; dvddrive &lt;span class=&quot;nt&quot;&gt;--medium&lt;/span&gt; none&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, it’s a good idea to take regular snapshots so that you can always
revert back to a known-good state rather than having to completely re-install.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage snapshot &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt; take &amp;lt;name of snapshot&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And, if you need to revert back to a particular snapshot:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; VBoxManage snapshot &lt;span class=&quot;nv&quot;&gt;$VM&lt;/span&gt; restore &amp;lt;name of snapshot&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Creating chroots for fun and MySQL testing</title>
      <link>//www.perkin.org.uk/posts/creating-chroots-for-fun-and-mysql-testing.html</link>
      <pubDate>Wed, 14 Sep 2011 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/creating-chroots-for-fun-and-mysql-testing.html</guid>
      <description>&lt;p&gt;Virtualisation is all the rage today, however there are still a few cases where
good old-fashioned Unix chroot is still applicable, and testing MySQL across
multiple platforms and architectures is one of those cases.&lt;/p&gt;

&lt;p&gt;At Oracle we do full automated package verification testing of our MySQL server
binaries prior to release, which attempts to install the package, start the
server, run some functionality testing, then uninstall.  It is of course highly
desirable that the testing environment this is performed in is as close to a
clean install of the target operating system as possible, to avoid problems
such as our packages depending upon some local changes or packages we may have
installed which won’t be available on a customer system.&lt;/p&gt;

&lt;p&gt;Given the large number of platforms and architectures that MySQL supports,
going the virtualisation route would mean having to use many different
products: VirtualBox for x86, zones for SPARC, qemu for ia64/PA-RISC/others (if
it even supports them), and this gets complicated quickly and is not very
maintainable.  Thus I chose to use chroot as much as possible.  In addition, it’s
much faster and less intensive on resources to use a chroot than boot up an
entire OS image each time.&lt;/p&gt;

&lt;p&gt;I built all images directly from the original installation images (DVD, ISO,
RPM, etc), to ensure that there was no contamination from our build environment
or local install scripts in the image – they should be as close to what a
normal user or customer will be running in their setup.  From the install image,
the packages are installed to a temporary directory, some final modifications
are made, then the directory is tarred up ready to be extracted by the test
framework and used.&lt;/p&gt;

&lt;p&gt;Here are some operating system specific examples, which set up an extracted
chroot image into &lt;code class=&quot;highlighter-rouge&quot;&gt;${CHROOTDIR}&lt;/code&gt;.  There may be additional steps required to
get a fully functioning chroot, such as copying device files (&lt;code class=&quot;highlighter-rouge&quot;&gt;/dev/zero&lt;/code&gt; and
&lt;code class=&quot;highlighter-rouge&quot;&gt;/dev/null&lt;/code&gt; are usually the minimum requirements) and adding users.&lt;/p&gt;

&lt;h2 id=&quot;freebsd&quot;&gt;FreeBSD&lt;/h2&gt;

&lt;p&gt;FreeBSD 7 and 8 come as a number of sets in tar format, and for our purposes we
only need to extract the base set.  You may wish to add more sets if you want to
use your chroot for building packages:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;mdunit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;mdconfig &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; vnode &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /path/to/dvd1/of/freebsd.iso&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
mount_cd9660 /dev/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mdunit&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; /mnt
&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; /mnt/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/base/base.?? | &lt;span class=&quot;nb&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-xpzf&lt;/span&gt; - &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CHROOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
umount /mnt
mdconfig &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mdunit&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;hp-ux&quot;&gt;HP-UX&lt;/h2&gt;

&lt;p&gt;HP-UX has since been EOL’d for MySQL, however this information might still
prove useful.  The HP-UX installation media contains per-directory packages,
with the contents representing how they are laid out on the destination file
system with each file gzip compressed.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /path/to/extracted/hpux-dvd1
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;pkg &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$LIST_OF_PKGS&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;do
  for &lt;/span&gt;subpkg &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pkg&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;do
    if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;subpkg&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
      continue
    fi
    for &lt;/span&gt;d &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;find &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;subpkg&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-type&lt;/span&gt; d&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;do
      &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CHROOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s#&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;subpkg&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/##g&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
              &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s#usr/newconfig/##g&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;done
    for &lt;/span&gt;f &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;find &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;subpkg&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-type&lt;/span&gt; f&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;do
      &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-dc&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CHROOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s#&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;subpkg&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/##g&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
              &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s#usr/newconfig/##g&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;done
  done
done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Once this is done you’ll need to fix up permissions in bin and lib directories
(make files executable), as well as create a bunch of symlinks for e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;/bin&lt;/code&gt;
and &lt;code class=&quot;highlighter-rouge&quot;&gt;/lib&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;osx&quot;&gt;OSX&lt;/h2&gt;

&lt;p&gt;For OSX we don’t actually use a chroot tarball but instead create a sparse disk
image.  Currently the size of the “chroot” is very large as there’s
no easy way to strip down an OSX install, so mounting a disk image is faster
than unpacking a chroot, plus it preserves various HFS-specific attributes.&lt;/p&gt;

&lt;p&gt;You will likely need at least the BSD, BaseSystem, and Essentials packages.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Create a sparse image to hold the chroot (which isn't really a directory)&lt;/span&gt;
hdiutil create &lt;span class=&quot;nt&quot;&gt;-fs&lt;/span&gt; HFS+ &lt;span class=&quot;nt&quot;&gt;-size&lt;/span&gt; 8g &lt;span class=&quot;nt&quot;&gt;-type&lt;/span&gt; SPARSE &lt;span class=&quot;nt&quot;&gt;-volname&lt;/span&gt; osx-chroot &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CHROOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
hdiutil attach &lt;span class=&quot;nt&quot;&gt;-mountpoint&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CHROOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CHROOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.sparseimage
&lt;span class=&quot;c&quot;&gt;# Either attach a DVD image or the real thing&lt;/span&gt;
hdiutil attach &lt;span class=&quot;nt&quot;&gt;-mountpoint&lt;/span&gt; /Volumes/osx-install /path/to/dvd
&lt;span class=&quot;c&quot;&gt;# Install packages&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;pkg &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;BSD BaseSystem Essentials
&lt;span class=&quot;k&quot;&gt;do
  &lt;/span&gt;installer &lt;span class=&quot;nt&quot;&gt;-verbose&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;-pkg&lt;/span&gt; /Volumes/osx-install/System/Installation/Packages/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;pkg&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.pkg &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;-target&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CHROOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Unmount&lt;/span&gt;
hdiutil detach &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CHROOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
hdiutil detach /Volumes/osx-install&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;red-hat--oracle-linux--suse&quot;&gt;Red Hat / Oracle Linux / SuSE&lt;/h2&gt;

&lt;p&gt;For RPM-based distributions we use rpm to directly install packages into the
chroot.  The list of RPMs we install varies quite a lot from release to release,
usually by having to increase the number:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RH3: 81&lt;/li&gt;
  &lt;li&gt;RH4: 85&lt;/li&gt;
  &lt;li&gt;RH5: 114&lt;/li&gt;
  &lt;li&gt;RH6: 203&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;for the same functionality.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Kludge for 'setup' RPM to install&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CHROOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/var/lock/rpm
&lt;span class=&quot;c&quot;&gt;# If installing from an ISO:&lt;/span&gt;
mount &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; loop /path/to/iso /mnt
&lt;span class=&quot;c&quot;&gt;# Path varies from release to release&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /mnt/path/to/RPMs
rpm &lt;span class=&quot;nt&quot;&gt;--root&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CHROOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-Uvh&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;LIST_OF_RPMS&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;solaris&quot;&gt;Solaris&lt;/h2&gt;

&lt;p&gt;Similar to RPM, we use the native package manager to install packages directly
into the chroot directory:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Avoid prompts&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;s/ask&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$/&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;nocheck/&quot;&lt;/span&gt; /var/sadm/install/admin/default &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; /tmp/admin-&lt;span class=&quot;nv&quot;&gt;$$&lt;/span&gt;
pkgadd &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; /tmp/admin-&lt;span class=&quot;nv&quot;&gt;$$&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-R&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;CHROOTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;LIST_OF_PKGS&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; /tmp/admin-&lt;span class=&quot;nv&quot;&gt;$$&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;windows&quot;&gt;Windows&lt;/h2&gt;

&lt;p&gt;Ok, so of course we can’t use chroot images for Windows, as it doesn’t have
&lt;code class=&quot;highlighter-rouge&quot;&gt;chroot(2)&lt;/code&gt;.  So here we use VirtualBox and its snapshot ability to load a clean
snapshot of a basic Windows install, do the tests, then shut down the virtual
machine, restore the snapshot, and boot up again.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Graphing memory usage during an MTR run</title>
      <link>//www.perkin.org.uk/posts/graphing-memory-usage-during-an-mtr-run.html</link>
      <pubDate>Thu, 30 Jun 2011 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/graphing-memory-usage-during-an-mtr-run.html</guid>
      <description>&lt;p&gt;In order to optimally size the amount of RAM to allocate to a set of new
machines for running MTR, I ran a few tests to check the memory usage of an MTR
run for mysql-trunk and cluster-7.1.  As using a RAM disk considerably speeds
things up, I set the vardir to be on &lt;code class=&quot;highlighter-rouge&quot;&gt;/ramdisk&lt;/code&gt; and logged the usage of that
too.&lt;/p&gt;

&lt;p&gt;The tests were performed on an 8-core E5450 @ 3.00GHz with 24GB RAM, with 8GB
allocated to &lt;code class=&quot;highlighter-rouge&quot;&gt;/ramdisk&lt;/code&gt;.  Each branch ran the &lt;code class=&quot;highlighter-rouge&quot;&gt;default.daily&lt;/code&gt; collection, which
generally contains the most testing we do per-run.  Between each run I rebooted
the machine to clear the buffer cache and &lt;code class=&quot;highlighter-rouge&quot;&gt;/ramdisk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I used something like the script below, which saved the per-second usage of
&lt;code class=&quot;highlighter-rouge&quot;&gt;/ramdisk&lt;/code&gt;, the total RAM used, and the RAM used minus buffers.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;mysql-trunk&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;BUILDDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;mysql-5.6.3-m5-linux2.6-x86_64&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;TESTDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;HOME&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/mtr-test/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

stats&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
  &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TESTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/stats-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TESTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/running &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;df&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; /ramdisk | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/^\// {print $3}'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;mem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;free | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/^Mem/ {print $3}'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;mem1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;free | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/cache:/ {print $3}'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;rd&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mem&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mem1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TESTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/stats-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;i+1&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;1
  &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TMPDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TESTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/tmp&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TMPDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TMPDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TESTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/running
stats &amp;amp;

&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TESTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BUILDDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/mysql-test

  perl mysql-test-run.pl ... &lt;span class=&quot;nt&quot;&gt;--parallel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8 &lt;span class=&quot;nt&quot;&gt;--vardir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/ramdisk/mtr-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/...
  &lt;span class=&quot;nb&quot;&gt;mv&lt;/span&gt; /ramdisk/mtr-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TMPDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/
  ...
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;sync
rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TESTDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/running
&lt;span class=&quot;nb&quot;&gt;wait&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;First I graphed a straight run of the two branches, using the following gnuplot script:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-gnuplot&quot; data-lang=&quot;gnuplot&quot;&gt;set terminal png enhanced font &quot;Times,11&quot; size 640,768
set output &quot;mtr-ram.png&quot;
set title &quot;MTR memory usage (8-core Xeon, 24GB, 8GB RAM disk)&quot;
set xlabel &quot;Time (minutes)&quot;
set ylabel &quot;Memory usage (GB)&quot;
set yrange [0:16]
set xtics 10
set key top box
set grid
plot &quot;stats-mysql-trunk&quot; every 60 using (($1)/60):(($2)/1024/1024) \
        title 'mysql-trunk /ramdisk usage' with lines, \
     &quot;stats-mysql-trunk&quot; every 60 using (($1)/60):(($3)/1024/1024) \
        title 'mysql-trunk RAM (inc buf)' with lines, \
     &quot;stats-mysql-trunk&quot; every 60 using (($1)/60):(($4)/1024/1024) \
        title 'mysql-trunk RAM (exc buf)' with lines, \
     &quot;stats-mysql-cluster-7.1&quot; every 60 using (($1)/60):(($2)/1024/1024) \
        title 'cluster-7.1 /ramdisk usage' with lines, \
     &quot;stats-mysql-cluster-7.1&quot; every 60 using (($1)/60):(($3)/1024/1024) \
        title 'cluster-7.1 RAM (inc buf)' with lines, \
     &quot;stats-mysql-cluster-7.1&quot; every 60 using (($1)/60):(($4)/1024/1024) \
        title 'cluster-7.1 RAM (exc buf)' with lines&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;img src=&quot;/files/images/mtr-ram.png&quot; alt=&quot;MTR memory usage&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;I then performed a valgrind run on mysql-trunk using similar scripts.  As
valgrind takes considerably longer (and uses more RAM) I kept it separate as
the combined graph isn’t very clear:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;img src=&quot;/files/images/mtr-ram-valgrind.png&quot; alt=&quot;MTR+valgrind memory usage&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;So, based on these results, the host machine (16GB RAM + 8GB RAM disk) is
probably a sensible guide for now, and allows for some future growth.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Fix input box keybindings in Firefox</title>
      <link>//www.perkin.org.uk/posts/fix-input-box-keybindings-in-firefox.html</link>
      <pubDate>Wed, 29 Jun 2011 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/fix-input-box-keybindings-in-firefox.html</guid>
      <description>&lt;p&gt;Those of us used to command line editing will no doubt have been frustrated
many times in Firefox when editing text in an input box and subconciously
hitting &lt;code class=&quot;highlighter-rouge&quot;&gt;ctrl-w&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;delete-word&lt;/code&gt;, only to have the tab close and your work
deleted.&lt;/p&gt;

&lt;p&gt;Thankfully there is a workaround to this.  It used to be a case of adding the
following to &lt;code class=&quot;highlighter-rouge&quot;&gt;.gtkrc&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;gtk-key-theme-name = &quot;Emacs&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However these days it’s a gconf setting:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ gconftool-2 --set /desktop/gnome/interface/gtk_key_theme Emacs --type string&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This will bind &lt;code class=&quot;highlighter-rouge&quot;&gt;ctrl-w&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;delete-word&lt;/code&gt; when in an input box, but retain the
close tab binding elsewhere, a nice implementation of
&lt;a href=&quot;http://en.wikipedia.org/wiki/DWIM&quot;&gt;DWIM&lt;/a&gt;.  See &lt;a href=&quot;http://kb.mozillazine.org/Emacs_Keybindings_%28Firefox%29&quot;&gt;this
page&lt;/a&gt; for more
information.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to lose weight</title>
      <link>//www.perkin.org.uk/posts/how-to-lose-weight.html</link>
      <pubDate>Fri, 24 Jun 2011 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/how-to-lose-weight.html</guid>
      <description>&lt;p&gt;This year I set myself a target to get back to my pre-marital weight.  Back in
2001 I was 90kg, but over the past decade I’d steadily gone up and for quite a
few years had hovered around 100kg.&lt;/p&gt;

&lt;p&gt;I’m a bit of a perfectionist, and like shiny graphs, so from Jan 1st this year
I weighed myself every day on the Wii Fit, and kept a record of my progress.
This morning I was finally under 90kg.  Here’s how things have gone thus far:&lt;/p&gt;

&lt;div class=&quot;postimg&quot;&gt;
  &lt;img src=&quot;/files/images/weight-jun11.png&quot; alt=&quot;My weight loss between 1st January 2011 and 24th June 2011&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;And for the geeks, my gnuplot script, assuming an input file named &lt;code class=&quot;highlighter-rouge&quot;&gt;weight.txt&lt;/code&gt; containing lines of the format &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;%Y-%m-%d &amp;lt;weight&amp;gt;&quot;&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-gnuplot&quot; data-lang=&quot;gnuplot&quot;&gt;set terminal png size 640, 400
set output &quot;weight-jun11.png&quot;
set xdata time
set timefmt &quot;%Y-%m-%d&quot;
set format x &quot;%b&quot;
set xlabel 'Date'
set ytics 2
set ylabel 'Weight (kg)'
set multiplot
plot 'weight.txt' using 1:2 title 'Weight' with lines linecolor 2&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;my-three-step-plan-for-losing-weight&quot;&gt;My three step plan for losing weight&lt;/h2&gt;

&lt;p&gt;The interwebs are awash with a million different ways to lose weight, and there
are thousands of companies who will gladly accept large chunks of your cash in
order to provide you with their expert opinion on how to do it.  This is my
three-step plan, and you can have it for free:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Eat less.&lt;/li&gt;
  &lt;li&gt;Eat less!&lt;/li&gt;
  &lt;li&gt;Profit!!!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Really, that’s it.  It’s not rocket science, after all.  If you eat less stuff
(especially saturated fat and sugar), there is less excess for your body to
store as fat, and thus over time you weigh less as your body starts to use up
the excess you have stored.&lt;/p&gt;

&lt;p&gt;Here’s some things I did to achieve this.&lt;/p&gt;

&lt;h3 id=&quot;eat-less&quot;&gt;Eat less&lt;/h3&gt;

&lt;p&gt;The basic aim.  For me this was mainly about reducing my portion size.&lt;/p&gt;

&lt;p&gt;Previously, I’d eat a massive bowl of cereal in the morning. which I thought
was a good thing as everyone always says to ensure you have a good breakfast.
However I was eating more than my body needed and as a consequence it was
likely storing up the excess.&lt;/p&gt;

&lt;p&gt;Also at meal times I’d usually serve myself a full plate, and always feel that
I needed to finish it.  I liked feeling full.  However, again, this likely just
meant I was eating more than I needed, and I found that just by serving less
food I was still satisfying my hunger but with less excess.&lt;/p&gt;

&lt;p&gt;After a relatively short period of time I found that by avoiding these large
meals, I needed less to feel full – as if my stomach had shrunk and gotten used
to the reduced size.  This was a great positive feedback loop, as it massively
helped avoid the temptation to snack between meals.&lt;/p&gt;

&lt;h3 id=&quot;cut-down-on-sugarfat&quot;&gt;Cut down on sugar/fat&lt;/h3&gt;

&lt;p&gt;I realise this can be hard for some people, I found it relatively easy but as
you can see on the graph above there are some upward trends, which were mainly
when I went to visit my parents, who have a cupboard full of chocolates,
crisps, cakes, sweets, etc, and I find it really hard not to have at least one
or two fake Lidl snickers bars per day!&lt;/p&gt;

&lt;p&gt;However, also note that after an upward trend, I lost the weight again pretty
quickly, so don’t worry too much about a few days of eating junk, I actually
noticed how bad I felt afterwards after getting used to a reduced sugar/fat
intake, and that provided good incentive to cut down again.&lt;/p&gt;

&lt;p&gt;Some practical things I did:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Stopped putting sugar in tea/coffee.  I’ve since regressed, but it was
helpful to do this for a while, and definitely helped wean my body off
desiring sugar.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Avoided snacking on crisps, chocolate, biscuits, etc.  When you work from
home this can be difficult, but I found it helped to ensure they weren’t in
the house to begin with, and that we were stocked up on bananas, apples, and
other less sugary/fatty snacks.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Used a fine cheese grater when making sandwiches, beans on toast, etc.
Previously I’d put a good few slabs of cheese in, when I didn’t really need
that quantity.  The fine grater ensured I still got the taste, but with less
quantity.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Bought reduced fat mayonnaise, margarine, etc.  These actually taste pretty
good these days, and in a sandwich with lots of fresh cucumber, tomato, salad
etc you don’t notice the difference&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these things helped to lose weight and, in a similar manner to the ‘eating
less’ part, trained my body to not require them as much as it used to – and
actually, to noticeably feel worse if ever I regressed, which made getting back
on track very easy.&lt;/p&gt;

&lt;h3 id=&quot;weigh-myself-daily&quot;&gt;Weigh myself daily&lt;/h3&gt;

&lt;p&gt;It seems this is generally not recommended, and advice is that you should weigh
yourself weekly (at the same time each week).  Logically this doesn’t make
sense to me, as a geek it’s obvious that the more data points you have, the
better.  Your body weight can fluctuate quite a lot from day to day especially
with regards to how much liquid you have drunk, and if you are only weighing
yourself once per week you could get caught out by a daily spike.&lt;/p&gt;

&lt;p&gt;Aside from the geek factor of a better graph resolution, I also prefer daily
weighing as it provides me, as a perfectionist, with incentives both ways.  If
I weigh less compared to the previous day, I feel good that I am achieving my
aim, and am encouraged to continue.  If I weigh more, it’s a warning that I may
have eaten too much, and I am then motivated to be more careful that day.&lt;/p&gt;

&lt;p&gt;Weighing daily also helps to just keep your mind reminded of the task, plus if
you’re on the Wii Fit already you might be tempted to do some exercise :)&lt;/p&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;

&lt;p&gt;I’m not content to stay here, the next plan is to get closer to my ideal BMI
weight which is around 80kg.  This is likely to be much harder, as there is
less excess fat for me to get rid of now.  However, one thing I haven’t done so
far is increase the amount of exercise I do, and there is definitely room for
improvement there!&lt;/p&gt;

&lt;p&gt;Hopefully I can provide another update later this year and perhaps be around
85kg.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to fix stdio buffering</title>
      <link>//www.perkin.org.uk/posts/how-to-fix-stdio-buffering.html</link>
      <pubDate>Thu, 23 Jun 2011 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/how-to-fix-stdio-buffering.html</guid>
      <description>&lt;p&gt;It’s a common problem.  You write some shell command like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /var/log/foo | egrep &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'some|stuff'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and wonder why nothing is printed, even though you know some text has matched.
The problem is that stdio is being buffered, and there’s a very good write-up
of the problem &lt;a href=&quot;http://www.pixelbeat.org/programming/stdio_buffering/&quot;&gt;here&lt;/a&gt; so
I won’t repeat the technical background.&lt;/p&gt;

&lt;p&gt;What I will provide though is how to fix it for common cases.&lt;/p&gt;

&lt;h2 id=&quot;stdbuf&quot;&gt;stdbuf&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;stdbuf&lt;/code&gt; is part of GNU coreutils, and is essentially an &lt;code class=&quot;highlighter-rouge&quot;&gt;LD_PRELOAD&lt;/code&gt; hack which
calls &lt;code class=&quot;highlighter-rouge&quot;&gt;setvbuf()&lt;/code&gt; for an application.  Thus it is a generic solution to the
problem and can be used to fix most applications.  Usage looks like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /var/log/foo | &lt;span class=&quot;nb&quot;&gt;stdbuf&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o0&lt;/span&gt; app ...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;which will disable output buffering for app, assuming it does not do something
itself to reverse the &lt;code class=&quot;highlighter-rouge&quot;&gt;setvbuf()&lt;/code&gt; call.  An example of a misbehaving application
is &lt;code class=&quot;highlighter-rouge&quot;&gt;mawk&lt;/code&gt;, below.&lt;/p&gt;

&lt;h2 id=&quot;awk&quot;&gt;awk&lt;/h2&gt;

&lt;p&gt;GNU &lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt; needs no modifications, that is it does not buffer when there is no
controlling tty.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;mawk&lt;/code&gt; however (the default &lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt; in Debian/Ubuntu and possibly others) buffers
output, and also does not seem to work with &lt;code class=&quot;highlighter-rouge&quot;&gt;stdbuf&lt;/code&gt;.  It does however provide
a &lt;code class=&quot;highlighter-rouge&quot;&gt;-Winteractive&lt;/code&gt; option which will turn off buffering.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /var/log/foo | gawk&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /var/log/foo | mawk &lt;span class=&quot;nt&quot;&gt;-Winteractive&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;sed&quot;&gt;sed&lt;/h2&gt;

&lt;p&gt;GNU &lt;code class=&quot;highlighter-rouge&quot;&gt;sed&lt;/code&gt; provides the &lt;code class=&quot;highlighter-rouge&quot;&gt;-u&lt;/code&gt; option which calls &lt;code class=&quot;highlighter-rouge&quot;&gt;fflush()&lt;/code&gt;, thereby providing
unbuffered output.  You can also use &lt;code class=&quot;highlighter-rouge&quot;&gt;stdbuf&lt;/code&gt; as above.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /var/log/foo | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /var/log/foo | &lt;span class=&quot;nb&quot;&gt;stdbuf&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o0&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;grep&quot;&gt;grep&lt;/h2&gt;

&lt;p&gt;Similar to &lt;code class=&quot;highlighter-rouge&quot;&gt;sed&lt;/code&gt;, GNU &lt;code class=&quot;highlighter-rouge&quot;&gt;grep&lt;/code&gt; provides a specific option, &lt;code class=&quot;highlighter-rouge&quot;&gt;--line-buffered&lt;/code&gt;, to
disable buffering, or again you can use &lt;code class=&quot;highlighter-rouge&quot;&gt;stdbuf&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /var/log/foo | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--line-buffered&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tail&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /var/log/foo | &lt;span class=&quot;nb&quot;&gt;stdbuf&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o0&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
    </item>
    
    <item>
      <title>Serving multiple DNS search domains in IOS DHCP</title>
      <link>//www.perkin.org.uk/posts/serving-multiple-dns-search-domains-in-ios-dhcp.html</link>
      <pubDate>Mon, 13 Jun 2011 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/serving-multiple-dns-search-domains-in-ios-dhcp.html</guid>
      <description>&lt;p&gt;I have a Cisco router at home which I also use as a DHCP server, and it works
pretty well.  Today I wanted to fix a long-standing issue on my network, in
that I want multiple DNS search domains.&lt;/p&gt;

&lt;p&gt;First off, the domain-name DHCP option doesn’t support multiple entries so we
can’t use that.  So, off to try raw DHCP option codes.  You can find the list
of options
&lt;a href=&quot;http://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xml&quot;&gt;here&lt;/a&gt;,
thus 119 is the one I want.&lt;/p&gt;

&lt;p&gt;Trying a simple:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;ip dhcp pool host.net.example.com
   option 119 ascii net.example.com,example.com&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;didn’t work at all.  A quick prod of lazyweb (in this case Simon on IRC)
suggested using hex input instead.  In order to do that we need to convert the
ASCII string into Cisco’s hex sequence, which is as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Split domain name by dot&lt;/li&gt;
  &lt;li&gt;Prepend each string by its length (in hex)&lt;/li&gt;
  &lt;li&gt;NUL terminate each domain&lt;/li&gt;
  &lt;li&gt;Dot-seperate the final string in 16bit chunks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To do this I wrote a quick Python script:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/python&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;hexlist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;domain&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:]:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;domain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;hexlist&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%02&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;x&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;part&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;part&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;hexlist&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hex&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;hexlist&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;00&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; \
               &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hexlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)])&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;which can be used like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ./cisco.py net.example.com example.com
&lt;span class=&quot;go&quot;&gt;036e.6574.0765.7861.6d70.6c65.0363.6f6d.0007.6578.616d.706c.6503.636f.6d00&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then back to IOS and paste it in:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;ip dhcp pool host.net.example.com
   option 119 hex 036e.6574.0765.7861.6d70.6c65.0363.6f6d.0007.6578.616d.706c.6503.636f.6d00&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This seems to do what we want, though IOS appears to append a dot to each
domain when serving via DHCP.&lt;/p&gt;

&lt;p&gt;One last note, if you use this in addition to domain-name then the option 119
list will be appended to the domain-name name in the search list, so you’d
actually want something like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;ip dhcp pool host.net.example.com
   domain-name net.example.com
   option 119 hex 0765.7861.6d70.6c65.0363.6f6d.00&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;to generate a resolv.conf containing:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;domain net.example.com
search net.example.com example.com.&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
    </item>
    
    <item>
      <title>Fix Firefox URL double click behaviour</title>
      <link>//www.perkin.org.uk/posts/fix-firefox-url-double-click-behaviour.html</link>
      <pubDate>Mon, 13 Jun 2011 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/fix-firefox-url-double-click-behaviour.html</guid>
      <description>&lt;p&gt;One of the best things I find with OS X is the consistent and sane handling of
keyboard and mouse bindings.  Since having to move back to Linux for work I am
constantly frustrated that different applications all have their own idea of
what shortcuts to use.&lt;/p&gt;

&lt;p&gt;One of the biggest annoyances was the mouse click behaviour in the browser URL
bar.  OS X behaviour is one click to position cursor, two clicks to select a
word, three clicks to select all.  I rely on this behaviour a lot as I
frequently copy/paste parts of URLs.&lt;/p&gt;

&lt;p&gt;Thankfully that’s one that can be fixed easily. Simply navigate to&lt;/p&gt;
&lt;about:config&gt; and double click on the `browser.urlbar.doubleClickSelectsAll`
key to set it to false.

One annoyance down, lots more to go..
&lt;/about:config&gt;
</description>
    </item>
    
    <item>
      <title>SSH via HTTP proxy in OSX</title>
      <link>//www.perkin.org.uk/posts/ssh-via-http-proxy-in-osx.html</link>
      <pubDate>Wed, 20 Apr 2011 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/ssh-via-http-proxy-in-osx.html</guid>
      <description>&lt;p&gt;If you happen to be stuck behind a corporate firewall with only HTTP proxies
for external access, you might still be able to SSH out through them using the
built-in &lt;code class=&quot;highlighter-rouge&quot;&gt;nc&lt;/code&gt; on OSX.&lt;/p&gt;

&lt;p&gt;First, hope that the proxies haven’t disabled the &lt;code class=&quot;highlighter-rouge&quot;&gt;CONNECT&lt;/code&gt; method, then simply
add a section to your &lt;code class=&quot;highlighter-rouge&quot;&gt;.ssh/config&lt;/code&gt; like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Host foobar.example.com
    ProxyCommand          nc -X connect -x proxyhost:proxyport %h %p
    ServerAliveInterval   10&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This will tunnel the connection through the HTTP proxy to the remote server.
The &lt;code class=&quot;highlighter-rouge&quot;&gt;ServerAliveInterval&lt;/code&gt; setting is required as most proxies will drop the
connection after a period of inactivity.&lt;/p&gt;

&lt;p&gt;To avoid issues with trying to connect to the host when not behind the
corporate firewall, replace the above with a fake entry for the proxy method
like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Host foobar-proxy.example.com
    HostName              foobar.example.com
    ProxyCommand          nc -X connect -x proxyhost:proxyport %h %p
    ServerAliveInterval   10&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then use&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ssh foobar-proxy.example.com&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;when inside the firewall, and&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ssh foobar.example.com&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;when outside.&lt;/p&gt;

&lt;p&gt;Simples, no external software required.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to build MySQL releases</title>
      <link>//www.perkin.org.uk/posts/how-to-build-mysql-releases.html</link>
      <pubDate>Tue, 09 Nov 2010 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/how-to-build-mysql-releases.html</guid>
      <description>&lt;p&gt;One of the major benefits from the &lt;a href=&quot;http://forge.mysql.com/wiki/CMake&quot;&gt;CMake
work&lt;/a&gt; available in MySQL 5.5 is that in the
MySQL Release Engineering team we have been able to make it easy for users and
developers to build MySQL exactly as we do for the official releases.  For too
long there has been a disconnect between the binaries produced as part of a
regular “&lt;code class=&quot;highlighter-rouge&quot;&gt;./configure; make&lt;/code&gt;” build and what we ship to users and
customers.&lt;/p&gt;

&lt;p&gt;We’re still not exactly where we want to be, there are still some parts which
need to be integrated into the server tree, but for now it’s relatively
straightforward to build exactly as we do.&lt;/p&gt;

&lt;p&gt;Here are the instructions, using the &lt;code class=&quot;highlighter-rouge&quot;&gt;mysql-5.5.6-rc.tar.gz&lt;/code&gt; source tarball as an
example.&lt;/p&gt;

&lt;h2 id=&quot;targz&quot;&gt;tar.gz&lt;/h2&gt;

&lt;p&gt;These are the generic instructions to build a tarball release.  Note that we
make use of CMake’s out-of-srcdir support to&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ensure the source directory is kept pristine&lt;/li&gt;
  &lt;li&gt;allow us to easily build both debug and release binaries, and package them together&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-zxf&lt;/span&gt; mysql-5.5.6-rc.tar.gz

&lt;span class=&quot;c&quot;&gt;# Build debug binaries first, they are picked up in the final 'make package'&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;debug
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;debug
  cmake ../mysql-5.5.6-rc &lt;span class=&quot;nt&quot;&gt;-DBUILD_CONFIG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;mysql_release &lt;span class=&quot;nt&quot;&gt;-DCMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;Debug
  make &lt;span class=&quot;nv&quot;&gt;VERBOSE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Build release binaries and create final package&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;release
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;release
  cmake ../mysql-5.5.6-rc &lt;span class=&quot;nt&quot;&gt;-DBUILD_CONFIG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;mysql_release
  make &lt;span class=&quot;nv&quot;&gt;VERBOSE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 package
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Assuming everything goes ok, you should end up with a tarball in the &lt;code class=&quot;highlighter-rouge&quot;&gt;release/&lt;/code&gt;
directory.&lt;/p&gt;

&lt;p&gt;Some platforms require extra flags to be specified on the CMake command line to
ensure the correct compiler etc is used.  Here are some that we use.&lt;/p&gt;

&lt;h3 id=&quot;avoid-libstdc-dependancy&quot;&gt;Avoid libstdc++ dependancy&lt;/h3&gt;

&lt;p&gt;In order to create “generic” binaries, on GCC platforms we compile
using &lt;code class=&quot;highlighter-rouge&quot;&gt;CXX=gcc&lt;/code&gt;.  This avoids &lt;code class=&quot;highlighter-rouge&quot;&gt;libstdc++&lt;/code&gt; being pulled in, and means that the
server will run across a larger range of releases as you do not rely on having
the exact version of &lt;code class=&quot;highlighter-rouge&quot;&gt;libstdc++&lt;/code&gt; installed by your system package manager.&lt;/p&gt;

&lt;p&gt;Paste this before running cmake.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; CXXFLAGS is required to trick CMake into believing it is a C++ compiler
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;CXX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;gcc&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;CXXFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-fno-exceptions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;CXX CXXFLAGS&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;specify-target-architecture&quot;&gt;Specify target architecture&lt;/h3&gt;

&lt;p&gt;On systems which support multiple targets, you can specify exactly which one
you want, rather than relying on the OS default.  These strings are meant to be
added to the cmake command lines above.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;OSX&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DCMAKE_OSX_ARCHITECTURES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;i386&quot;&lt;/span&gt;    &lt;span class=&quot;c&quot;&gt;# 32bit&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DCMAKE_OSX_ARCHITECTURES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;x86_64&quot;&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# 64bit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;GCC/Sun Studio&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DCMAKE_C_FLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-m32&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DCMAKE_CXX_FLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-m32&quot;&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# 32bit&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DCMAKE_C_FLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-m64&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DCMAKE_CXX_FLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-m64&quot;&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# 64bit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;HP/UX&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DCMAKE_C_FLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;+DD64&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DCMAKE_CXX_FLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;+DD64&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;rpm&quot;&gt;RPM&lt;/h2&gt;

&lt;p&gt;We’ve spent a lot of time improving the RPM builds too.  Previously some of the
configuration was only available in the commercial RPM builds, but now we have
merged them into the community version.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; rpm/&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;BUILD,RPMS,SOURCES,SPECS,SRPMS&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; tmp

&lt;span class=&quot;c&quot;&gt;# Create spec file.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# XXX: We should probably just include this in the source tarball.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-zxf&lt;/span&gt; mysql-5.5.6-rc.tar.gz
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;bld&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;bld
  cmake ../mysql-5.5.6-rc
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;bld/support-files/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.spec rpm/SPECS
&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;mysql-5.5.6-rc.tar.gz rpm/SOURCES

rpmbuild &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--define&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;_topdir &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PWD&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/rpm&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--define&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;_tmppath &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PWD&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/tmp&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;-ba&lt;/span&gt; rpm/SPECS/mysql.5.5.6-rc.spec&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You should end up with nice shiny RPMs in &lt;code class=&quot;highlighter-rouge&quot;&gt;rpm/RPMS&lt;/code&gt;.  One thing to note is
that the RPM spec no longer runs the test suite as part of the build, so you
will need to run that separately.  On the plus side, you get your RPMs much
quicker.&lt;/p&gt;

&lt;p&gt;Another nice thing about the improved RPM spec is that you can now build
targetted distribution RPMs, as we do.  These have extra dependancy information
in them tailored to the target distribution.  Currently the spec file supports
the distributions we build on, but we will accept patches for others.&lt;/p&gt;

&lt;p&gt;To enable this, use:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; rpmbuild &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--define&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;distro_specific 1&quot;&lt;/span&gt; ...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;windows&quot;&gt;Windows&lt;/h2&gt;

&lt;p&gt;Our Windows builds have relied on CMake since MySQL 5.0, but the procedure has
still changed to ensure that you can build as we do.  These instructions use
&lt;code class=&quot;highlighter-rouge&quot;&gt;cmd.exe&lt;/code&gt; but you can use the Visual Studio front end if you prefer.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bat&quot; data-lang=&quot;bat&quot;&gt;unzip mysql-5.5.6-rc.zip

rem There is no separate 'debug' directory on Windows, as the CMake
rem infrastructure doesn't yet know to pull files in from there on Windows.
md release
cd release

rem Choose your target architecture, 32bit
set VSTARGET=Visual Studio 9 2008
rem or 64bit
set VSTARGET=Visual Studio 9 2008 Win64

cmake ..\mysql-5.5.6-rc -DBUILD_CONFIG=mysql_release \
 -DCMAKE_BUILD_TYPE=Debug -G &quot;%VSTARGET%&quot;

devenv MySql.sln /build Debug

cmake ..\mysql-5.5.6-rc -DBUILD_CONFIG=mysql_release \
 -DCMAKE_BUILD_TYPE=RelWithDebInfo -G &quot;%VSTARGET%&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can now choose which type of package to create.  5.5 includes new code to
create minimal MSI packages, these should work ok, and only differ from the
official MySQL MSI packages in that they do not include the instance config
wizard.&lt;/p&gt;

&lt;p&gt;To create the MSI packages you will need to install
&lt;a href=&quot;http://wix.codeplex.com/&quot;&gt;WiX&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bat&quot; data-lang=&quot;bat&quot;&gt;rem Standard zip package
devenv MySql.sln /build RelWithDebInfo /project package

rem Full MSI package
devenv MySql.sln /build RelWithDebInfo /project msi

rem 'Essentials' MSI package
devenv MySql.sln /build RelWithDebInfo /project msi_essentials&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Assuming everything goes ok, you should have some packages in the &lt;code class=&quot;highlighter-rouge&quot;&gt;release\&lt;/code&gt;
directory.&lt;/p&gt;

&lt;h2 id=&quot;work-still-to-be-done&quot;&gt;Work still to be done&lt;/h2&gt;

&lt;p&gt;We still have a number of scripts only available internally, for example those
we use to create SVR4, DMG and DEPOT packages.  However, we are looking to
integrate these into the MySQL Server source tree so that all users can benefit
from them.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>'apt-get' and 5,000 packages for Solaris10/x86</title>
      <link>//www.perkin.org.uk/posts/apt-get-and-5000-packages-for-solaris10x86.html</link>
      <pubDate>Thu, 29 Apr 2010 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/apt-get-and-5000-packages-for-solaris10x86.html</guid>
      <description>&lt;p&gt;Here’s how:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; Install pkg_&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; tools and the &lt;span class=&quot;s1&quot;&gt;'pkgin'&lt;/span&gt; package manager
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgadd &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; http://www.netbsd.org/~jperkin/TNFpkgsrc-x86.pkg all
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; Add tools to PATH
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/pkg/sbin:/opt/pkg/bin:&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; Update package repository &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;akin to &lt;span class=&quot;s1&quot;&gt;'apt-get update'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin up
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; Search &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;a particular package &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;you can use regexp&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin search ^ap.&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;python 
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; Install it
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;ap22-py25-python
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; Update all packages &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;akin to &lt;span class=&quot;s1&quot;&gt;'apt-get dist-upgrade'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin full-upgrade
&lt;span class=&quot;go&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; How many packages are available?
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgin avail | &lt;span class=&quot;nb&quot;&gt;wc&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;   4970&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ok, so the headline might be slightly mis-leading, this isn’t really apt-get
but a tool which is very similar. This is work which builds upon my &lt;a href=&quot;/posts/pkgsrc-on-solaris.html&quot;&gt;previous
post&lt;/a&gt; using pkgsrc to build binary packages on
Solaris.&lt;/p&gt;

&lt;p&gt;See &lt;a href=&quot;http://imil.net/pkgin/&quot;&gt;http://imil.net/pkgin/&lt;/a&gt; for more information on
pkgin.&lt;/p&gt;

&lt;p&gt;Hopefully this will prove really useful to people still using Solaris 10 and
unable to use the new pkg(5) stuff in OpenSolaris.&lt;/p&gt;

&lt;p&gt;Please try it out and provide any feedback to
&lt;a href=&quot;mailto:pkgsrc-users@netbsd.org&quot;&gt;pkgsrc-users@netbsd.org&lt;/a&gt;.  I’m hoping to keep
the packages updated for the 2009Q3 branch.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>ZFS and NFS vs OSX</title>
      <link>//www.perkin.org.uk/posts/zfs-and-nfs-vs-osx.html</link>
      <pubDate>Wed, 16 Sep 2009 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/zfs-and-nfs-vs-osx.html</guid>
      <description>&lt;p&gt;gromit is my Solaris 10 server, chorlton is my OSX desktop. Explain this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;root@gromit#&lt;/span&gt; zfs &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sharenfs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'anon=shared,sec=none'&lt;/span&gt; gromit/store&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;root@gromit#&lt;/span&gt; zfs get sharenfs gromit/store
&lt;span class=&quot;go&quot;&gt;NAME          PROPERTY  VALUE                 SOURCE
gromit/store  sharenfs  anon=shared,sec=none  local&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;user@chorlton$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /net/gromit/store
&lt;span class=&quot;go&quot;&gt;ls: cannot open directory /net/gromit/store/: Operation not permitted&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;root@gromit#&lt;/span&gt; zfs &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sharenfs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'anon=shared'&lt;/span&gt; gromit/store&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;user@chorlton$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /net/gromit/store
&lt;span class=&quot;go&quot;&gt;file1  file2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;user@chorlton$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /net/gromit/store/file3
&lt;span class=&quot;go&quot;&gt;touch: /net/gromit/store/file3: Permission denied&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;root@gromit#&lt;/span&gt; zfs &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sharenfs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'anon=shared,sec=none'&lt;/span&gt; gromit/store&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;user@chorlton$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt; /net/gromit/store/file3
&lt;span class=&quot;gp&quot;&gt;user@chorlton$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</description>
    </item>
    
    <item>
      <title>pkgsrc on Solaris</title>
      <link>//www.perkin.org.uk/posts/pkgsrc-on-solaris.html</link>
      <pubDate>Sat, 12 Sep 2009 00:00:00 +0100</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/pkgsrc-on-solaris.html</guid>
      <description>&lt;p&gt;For many years, building and installing third-party software on Solaris has
been a huge pain.  For people who do not use &lt;a href=&quot;http://www.pkgsrc.org/&quot;&gt;pkgsrc&lt;/a&gt;,
that is.&lt;/p&gt;

&lt;p&gt;Originating from the &lt;a href=&quot;http://www.netbsd.org/&quot;&gt;NetBSD&lt;/a&gt; project, pkgsrc is a
source-based cross-platform package manager.  If you’ve used FreeBSD ports,
then it is very similar as it derives from the same codebase, so the basic
premise is that you:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /usr/pkgsrc/www/apache22
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; make package&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and pkgsrc will download the source for Apache 2.2, compile it and all
dependancies, install it on the local system and create a package which can be
installed on other similar systems.&lt;/p&gt;

&lt;p&gt;However, we’ve taken ports further and applied the NetBSD philosophy of
portability, meaning that it not only works on NetBSD, but across all *BSD as
well as Linux, OSX, HP/UX, AIX, IRIX, QNX, Windows (via Interix), and of course
Solaris.&lt;/p&gt;

&lt;p&gt;So while apt-get might be awesome, it only really works on Linux.  FreeBSD
might have way more ports than us, but only runs on FreeBSD and OSX.  pkgsrc
provides a consistent interface across all the platforms listed above, and in
some cases provides a superior package manager than the system provides.&lt;/p&gt;

&lt;p&gt;Here’s how I use pkgsrc on Solaris, in this specific case Solaris 10/x86.
Paths are specific to my setup, you can of course change them.&lt;/p&gt;

&lt;h2 id=&quot;create-a-chrootzone-environment&quot;&gt;Create a chroot/zone environment&lt;/h2&gt;

&lt;p&gt;I use the zones feature of Solaris 10 to ensure that all packages are built in
a sandbox.  This has a number of benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The running system is unaffected by the builds, in that they are not writing
to the same file system.  This is good when you have misbehaving packages.&lt;/li&gt;
  &lt;li&gt;You can separate the build and install phases, so that you can verify all the
packages have been built and are correct before starting any install/upgrade
procedure&lt;/li&gt;
  &lt;li&gt;It’s easier to catch package mistakes, e.g. unpackaged files.&lt;/li&gt;
  &lt;li&gt;It avoids pollution from the host environment which may produce bad packages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For creating a zone, I wrote the following
&lt;a href=&quot;/files/solaris-pkgsrc/create-zone&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;create-zone&lt;/code&gt;&lt;/a&gt; script:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;DOMAIN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;adsl.perkin.org.uk&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;MASQDOMAIN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;perkin.org.uk&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;PHYSIF&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;e1000g0&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;RPOOL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;gromit&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$# &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-eq&lt;/span&gt; 1 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;shift
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;getent hosts &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{print $1}'&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ERROR: Could not determine IP address of &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Either add to hosts database or provide on command line&quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;echo
        echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;usage: &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &amp;lt;name&amp;gt; [ &amp;lt;ipaddr&amp;gt; ]&quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;2
    &lt;span class=&quot;k&quot;&gt;fi
elif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$# &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-eq&lt;/span&gt; 2 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;shift
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ipaddr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;shift
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;usage: &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &amp;lt;name&amp;gt; [ &amp;lt;ipaddr&amp;gt; ]&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;2
&lt;span class=&quot;k&quot;&gt;fi

&lt;/span&gt;zfs list &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;RPOOL&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-eq&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;RPOOL&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/zones/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; already exists, not continuing&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Inherited directories are read-only&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/tmp/zonecfg.&lt;span class=&quot;nv&quot;&gt;$$&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
    create
    set zonepath=/zones/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
    set autoboot=true
    add net
        set address=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ipaddr&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;/24
        set physical=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PHYSIF&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
    end
    verify
    commit
    exit
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF

&lt;/span&gt;zonecfg &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /tmp/zonecfg.&lt;span class=&quot;nv&quot;&gt;$$&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; /tmp/zonecfg.&lt;span class=&quot;nv&quot;&gt;$$&lt;/span&gt;

zoneadm &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Automatically configure new zone with most of the settings from the current&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# global, grabbing the encrypted root password directly.  Note that the&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# service_profile keyword doesn't seem to be used here, so we configure the&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# limited_net profile manually and optionally install a custom site.xml which&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# is parsed and activated during first boot.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt; &amp;gt;/zones/&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;/root/etc/sysidcfg
network_interface=PRIMARY
{
    hostname=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DOMAIN&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
}
name_service=DNS
{
    domain_name=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DOMAIN&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
    name_server=`awk '/^nameserver/ { print &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$NF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;; exit }' /etc/resolv.conf`
}
nfs4_domain=dynamic
root_password=`awk -F: '/^root/ {print &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$2&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;}' /etc/shadow`
security_policy=NONE
service_profile=limited_net
system_locale=C
terminal=xterm
timezone=Europe/London
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF

&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Use the limited_net profile and install custom site.xml if provided.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; /zones/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/root/var/svc/profile/generic.xml
&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; generic_limited_net.xml /zones/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/root/var/svc/profile/generic.xml
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /install/zones/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.xml &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; /install/zones/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.xml /zones/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/root/var/svc/profile/site.xml
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Disable nscd host cache&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
ex /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/etc/nscd.conf &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
/enable-cache/s/^#//
wq
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF

&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Configure sendmail to masquerade and route via smarthost.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
ex /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/etc/mail/cf/cf/submit.mc &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
/^dnl/
a
FEATURE(\`masquerade_envelope')dnl
MASQUERADE_AS(\`&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;MASQDOMAIN&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;')dnl
dnl
.
/^FEATURE.*msp/s/.127.0.0.1./mail.perkin.org.uk/
wq!
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/etc/mail/cf/cf
  /usr/ccs/bin/make submit.cf &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/etc/mail/cf/cf/submit.cf &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/etc/mail/submit.cf

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Use SHA512 crypted passwords, and change root's home directory.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
ex /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/etc/security/policy.conf &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
/^CRYPT_DEFAULT/s/__unix__/6/
wq
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; 0700 /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/root
ex /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/etc/passwd &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
/^root/s,:/:,:/root:,
/^root/s,:/sbin/sh,:/bin/bash,
wq
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF

&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; /root/.bash_profile /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/root/.bash_profile

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Allow root login over SSH (rest of network takes care of external access&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# so this isn't a problem) and enforce SSH key authentication.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
ex /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/etc/ssh/sshd_config &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
/^PermitRootLogin/s/no&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$/&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;yes/
/^PasswordAuthentication/s/yes&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$/&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;no/
wq
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF
&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; 0700 /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/root/.ssh
&lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; /home/jperkin/.ssh/id_rsa.pub /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/root/.ssh/authorized_keys

&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Automount shared directories from global zone using direct mounts&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
ex /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/etc/auto_master &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
a
/-        auto_direct
.
wq
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF
&lt;/span&gt;ex /zones/&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;/root/etc/auto_direct &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;
a
/content    gromit-lan:/content
/install    gromit-lan:/install
.
wq
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOF

&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# All done!  Fire it up...&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
zoneadm &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt; boot&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And the corresponding &lt;a href=&quot;/files/solaris-pkgsrc/delete-zone&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;delete-zone&lt;/code&gt;&lt;/a&gt; script
is:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;RPOOL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;gromit&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$# &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-ne&lt;/span&gt; 1 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;usage: &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &amp;lt;zone&amp;gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;2
&lt;span class=&quot;k&quot;&gt;fi

&lt;/span&gt;zoneadm &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt; halt
zonecfg &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt; delete &lt;span class=&quot;nt&quot;&gt;-F&lt;/span&gt;
zfs destroy &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;RPOOL&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/zones/&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you want to use them then there are some variables to set at the top, and
you may want to scan through them for additional bits to change, for example
&lt;a href=&quot;/files/solaris-pkgsrc/create-zone&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;create-zone&lt;/code&gt;&lt;/a&gt; copies my ssh public key
which will most likely be wrong for your setup :-)&lt;/p&gt;

&lt;p&gt;One additional piece of configuration for
&lt;a href=&quot;/files/solaris-pkgsrc/create-zone&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;create-zone&lt;/code&gt;&lt;/a&gt; is an optional SMF xml file.
I use this file to disable inetd inside the zone for additional security, like
so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version='1.0'?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;service_bundle&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'profile'&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'extract'&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;service&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'network/inetd'&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'service'&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'0'&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;instance&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'default'&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;enabled=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'false'&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/service&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/service_bundle&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The file should be named &amp;lt;yourzonename&amp;gt;.xml.  Mine is named
&lt;a href=&quot;/files/solaris-pkgsrc/vm-generic.xml&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;vm-generic.xml&lt;/code&gt;&lt;/a&gt; and I then create
symlinks to it for each VM I want with that default configuration.&lt;/p&gt;

&lt;h2 id=&quot;fetch-pkgsrc&quot;&gt;Fetch pkgsrc&lt;/h2&gt;

&lt;p&gt;pkgsrc is developed very rapidly.  Tracking nearly 9,000 pieces of third-party
software means there are always many updates.  Thankfully, we provide quarterly
branches for people who want more stability, and I recommend using the latest
quarterly release.  At time of writing, this is known as &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc-2009Q2&lt;/code&gt;.
Within the next month or so we will release &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgsrc-2009Q3&lt;/code&gt;, and you can figure
out the names of future releases yourself.&lt;/p&gt;

&lt;p&gt;The easiest way to get pkgsrc is using cvs.  I keep stuff like this under
&lt;code class=&quot;highlighter-rouge&quot;&gt;/content&lt;/code&gt; as opposed to the default of &lt;code class=&quot;highlighter-rouge&quot;&gt;/usr&lt;/code&gt;, you can use whatever you wish
but will need to change all my example scripts to match where you put it.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /content
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;pkgsrc-2009Q2&quot;&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; cvs &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; anoncvs@anoncvs.netbsd.org:/cvsroot co &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-P&lt;/span&gt; pkgsrc&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Alternatively, you can fetch either bzip2 or gzip archives of the current
branch.  I recommend the cvs method as, with the branch being updated for
security fixes and other important changes, you can easily track it using&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /content/pkgsrc-2009Q2
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; cvs update&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;pkgsrc-configuration&quot;&gt;pkgsrc configuration&lt;/h2&gt;

&lt;p&gt;pkgsrc is configured using a &lt;code class=&quot;highlighter-rouge&quot;&gt;mk.conf&lt;/code&gt; file,
&lt;a href=&quot;/files/solaris-pkgsrc/mk.conf&quot;&gt;this&lt;/a&gt; is mine:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;#
# Local settings
#
OS_HOST!= uname -n

#
# Per-host settings
#
#    vm0 builds local packages
#
.if !empty(OS_HOST:Mvm0.*) || !empty(OS_HOST:Mgromit.*)
PKGDIRSUFFIX=
PKG_DEFAULT_OPTIONS=    inet6 perl sasl ssl ncursesw
PKG_OPTIONS.mutt+=      mutt-hcache mutt-smtp
PKG_UID.cyrus=          2000
#PKG_GID.cyrus=         mail
PKG_SHELL.cyrus=        /usr/bin/false
PKG_UID.www=            2001
PKG_GID.www=            2001
PYTHON_VERSION_DEFAULT= 24
X11_TYPE=               modular
#
#    vm1 modular X11 bulk builds
#
.elif !empty(OS_HOST:Mvm1.*)
X11_TYPE=       modular
PKGDIRSUFFIX=   -${X11_TYPE}
#
#    vm2 native X11 bulk builds
#
.elif !empty(OS_HOST:Mvm2.*)
X11_TYPE=       native
PKGDIRSUFFIX=   -${X11_TYPE}
#
#    vm3 pkgsrc dev builds
#
.elif !empty(OS_HOST:Mvm3.*)
X11_TYPE=       modular
PKGDIRSUFFIX=   -${X11_TYPE}
.endif

.if exists(../../CVS/Tag)
PKG_BRANCH!=    ${TOOLS_PLATFORM.awk} -F- '{print $$2}' &amp;lt; ../../CVS/Tag
.else
PKG_BRANCH=     HEAD
.endif

ALLOW_VULNERABLE_PACKAGES=  YES

BULKFILESDIR=           ${WRKOBJDIR}
DISTDIR=                /install/pkgsrc/distfiles/
FAILOVER_FETCH=         YES
INSTALL_UNSTRIPPED=     YES
LINTPKGSRC_DB=          ${_PKGSRCDIR}/.lintpkgsrc.db
MASTER_SITE_OVERRIDE=   ftp://ftp.netbsd.org/pub/NetBSD/packages/distfiles/
PACKAGES=               /install/pkgsrc/packages/${PKG_BRANCH}${PKGDIRSUFFIX}
PKGCHK_CONF=            /install/pkgsrc/misc/pkgchk.conf
SKIP_LICENSE_CHECK=     YES
WRKOBJDIR=              /tmp/pkgsrc

#
# Parse pkgchk.conf and supply list of packages for the bulk build framework.
#
.if defined(SPECIFIC_PKGS)
PKGLIST!= ${TOOLS_PLATFORM.awk} '$$1 !~ /^(\#|$$)/ {print $$1}' ${PKGCHK_CONF}
.  for _pkg_ in ${PKGLIST}
HOST_SPECIFIC_PKGS+= ${_pkg_}
.  endfor
.endif&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This is the primary configuration file for pkgsrc.  Again, you may need to
tailor this to your environment, and may find it useful to read the pkgsrc
guide to understand what it all means.&lt;/p&gt;

&lt;p&gt;As I do a lot of pkgsrc development I have a number of virtual machines up and
running doing various bits and pieces.  Obviously I don’t want to copy that
&lt;a href=&quot;/files/solaris-pkgsrc/mk.conf&quot;&gt;mk.conf&lt;/a&gt; around, so I also have a small
&lt;a href=&quot;/files/solaris-pkgsrc/mk-include.conf&quot;&gt;fragment&lt;/a&gt; file which is appended to
each virtual machine’s &lt;code class=&quot;highlighter-rouge&quot;&gt;mk.conf&lt;/code&gt; (using the &lt;code class=&quot;highlighter-rouge&quot;&gt;--mk-fragment&lt;/code&gt; argument to
&lt;code class=&quot;highlighter-rouge&quot;&gt;bootstrap&lt;/code&gt;) and includes the global copy:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;.include &quot;/install/pkgsrc/misc/mk.conf&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The bulk build setup in pkgsrc requires its own configuration, and for this you
will need to edit a file inside pkgsrc.  There is an example file provided, so
what I usually do is symlink this to the real copy then I can easily keep it
up-to-date via cvs.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /content/pkgsrc-2009Q2/mk/bulk
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; build.conf-example build.conf
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi build.conf&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Again, you can find my personal build.conf here.&lt;/p&gt;

&lt;p&gt;Finally, there is a configuration file for &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_chk&lt;/code&gt; which is a package inside
pkgsrc which makes managing upgrades easier (ideally it should be a part of the
main pkgsrc tools but that’s for another day).  &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgchk.conf&lt;/code&gt; is a list of
package directories, relative to the pkgsrc top level, which are to be built
and installed for this setup.  If you have a large installation then &lt;code class=&quot;highlighter-rouge&quot;&gt;pkg_chk&lt;/code&gt;
has extra features to make it possible to share &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgchk.conf&lt;/code&gt; across a number of
machines and configure packages on a per-host, per-OS etc basis.&lt;/p&gt;

&lt;p&gt;Thus, a sample &lt;a href=&quot;/files/solaris-pkgsrc/pkgchk.conf&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgchk.conf&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;chat/irssi
chat/irssi-icb
converters/xlhtml
databases/lbdb
databases/rrdtool
devel/autoconf
devel/automake
devel/bzr
devel/bzrtools
devel/diffutils
devel/libtool-base
devel/scmcvs
editors/vim
mail/mutt-devel
misc/screen
net/p5-Net-SNMP
net/p5-Net-SNMP-Interfaces
net/rsync
net/samba
net/tnftp
pkgtools/digest
pkgtools/pkg_chk
pkgtools/rc.subr
print/mp
security/cy2-login
security/cy2-plain
security/sudo
sysutils/coreutils
textproc/antiword
textproc/grep
textproc/urlview
www/apache22
www/w3m&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It is highly likely you will want to change the &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgchk.conf&lt;/code&gt; file from what I
use :-)&lt;/p&gt;

&lt;h2 id=&quot;build-scripts&quot;&gt;Build scripts&lt;/h2&gt;

&lt;p&gt;Once everything is set up, I have two scripts to build then update my packages,
intuitively called &lt;a href=&quot;/files/solaris-pkgsrc/build-packages&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;build-packages&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/opt/pkg/sbin:/opt/pkg/bin:/sbin:/usr/sbin:/usr/bin:/usr/ccs/bin&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;PATH

&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2009Q2&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;BRANCH

&lt;span class=&quot;nv&quot;&gt;PDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/install/pkgsrc

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/bootstrap-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.tar &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /content/pkgsrc-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/bootstrap
    ./bootstrap &lt;span class=&quot;nt&quot;&gt;--workdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/pkgsrc &lt;span class=&quot;nt&quot;&gt;--prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/pkg &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;--varbase&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/var/opt/pkg &lt;span class=&quot;nt&quot;&gt;--sysconfdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/etc/opt/pkg &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;--mk-fragment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/misc/mk-include.conf &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;--binary-kit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/bootstrap-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.tar
    &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; /tmp/pkgsrc
&lt;span class=&quot;k&quot;&gt;fi

if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /opt/pkg/bin/bmake &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-xf&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/bootstrap-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.tar&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi

&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /content/pkgsrc-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

/bin/ksh mk/bulk/build &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt;  2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;tee&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/logs/build-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.log
/bin/ksh mk/bulk/upload &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;tee&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PDIR&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/logs/upload-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.log&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and &lt;a href=&quot;/files/solaris-pkgsrc/update-packages&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;update-packages&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/opt/pkg/sbin:/opt/pkg/bin:/sbin:/usr/sbin:/usr/bin:/usr/ccs/bin&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;PATH

&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;2009Q2
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;BRANCH

&lt;span class=&quot;nv&quot;&gt;PKGSRCDIR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/content/pkgsrc-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;PKGSRCDIR

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /opt/pkg/bin/bmake &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-xf&lt;/span&gt; /install/pkgsrc/bootstrap-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.tar&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Run this anyway in case there are updates to pkg_chk&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;env &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PKG_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/install/pkgsrc/packages/&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/All pkg_add &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; pkg_chk

&lt;span class=&quot;c&quot;&gt;# Dry run first&lt;/span&gt;
pkg_chk &lt;span class=&quot;nt&quot;&gt;-aurbn&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Do you wish to install? [y/N]: &quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;ans
&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ans&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;Yy]&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    pkg_chk &lt;span class=&quot;nt&quot;&gt;-aurb&lt;/span&gt; 2&amp;gt;&amp;amp;1 | &lt;span class=&quot;nb&quot;&gt;tee&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; /install/pkgsrc/logs/pkg_chk-&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;BRANCH&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;.log
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;esac&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;These are pretty simple as all the hard work has all been done.
&lt;a href=&quot;/files/solaris-pkgsrc/build-packages&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;build-packages&lt;/code&gt;&lt;/a&gt; is ran inside the
zone, then &lt;a href=&quot;/files/solaris-pkgsrc/update-packages&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;update-packages&lt;/code&gt;&lt;/a&gt; on the
main host.  These scripts hardcode the name of the branch currently used, so
you will need to update this when moving to newer releases.&lt;/p&gt;

&lt;h2 id=&quot;quick-recap&quot;&gt;Quick recap&lt;/h2&gt;

&lt;p&gt;Ok, so here is the stuff I have for my setup and where I keep them:&lt;/p&gt;

&lt;div class=&quot;posttable&quot;&gt;
 &lt;table&gt;
  &lt;thead&gt;
   &lt;tr&gt;&lt;th style=&quot;width: 40%&quot;&gt;Path&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/content/pkgsrc-2009Q2&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Checked out pkgsrc tree, &quot;2009Q2&quot; branch&lt;/td&gt;&lt;/tr&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/content/scripts/&lt;a href=&quot;/files/solaris-pkgsrc/create-zone&quot;&gt;create-zone&lt;/a&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Creates Solaris zone&lt;/td&gt;&lt;/tr&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/content/scripts/&lt;a href=&quot;/files/solaris-pkgsrc/delete-zone&quot;&gt;delete-zone&lt;/a&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Uninstalls and deletes zone&lt;/td&gt;&lt;/tr&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/content/scripts/&lt;a href=&quot;/files/solaris-pkgsrc/build-packages&quot;&gt;build-packages&lt;/a&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Bulk build packages inside the zone&lt;/td&gt;&lt;/tr&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/content/scripts/&lt;a href=&quot;/files/solaris-pkgsrc/update-packages&quot;&gt;update-packages&lt;/a&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Updates installed packages&lt;/td&gt;&lt;/tr&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/install/pkgsrc/misc/&lt;a href=&quot;/files/solaris-pkgsrc/mk.conf&quot;&gt;mk.conf&lt;/a&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Main pkgsrc configuration file&lt;/td&gt;&lt;/tr&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/install/pkgsrc/misc/&lt;a href=&quot;/files/solaris-pkgsrc/mk-include.conf&quot;&gt;mk-include.conf&lt;/a&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Fragment file included in each zone's &lt;code&gt;mk.conf&lt;/code&gt;, sources the global &lt;code&gt;mk.conf&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/install/pkgsrc/misc/&lt;a href=&quot;/files/solaris-pkgsrc/pkgchk.conf&quot;&gt;pkgchk.conf&lt;/a&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;pkg_chk&lt;/code&gt; configuration file&lt;/td&gt;&lt;/tr&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/install/zones/&lt;a href=&quot;/files/solaris-pkgsrc/vm-generic.xml&quot;&gt;vm-generic.xml&lt;/a&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Shared SMF configuration file, symlinked to from e.g. &quot;&lt;code&gt;vm0.xml&lt;/code&gt;&quot;&lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;
 &lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;And these are the paths where stuff will be created:&lt;/p&gt;

&lt;div class=&quot;posttable&quot;&gt;
 &lt;table&gt;
  &lt;thead&gt;
   &lt;tr&gt;&lt;th&gt;Path&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/install/pkgsrc/distfiles&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Source tarballs of packages&lt;/td&gt;&lt;/tr&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/install/pkgsrc/packages/2009Q2&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Resulting binary packages&lt;/td&gt;&lt;/tr&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/tmp/pkgsrc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Temporary build area for packages&lt;/td&gt;&lt;/tr&gt;
   &lt;tr&gt;&lt;td&gt;&lt;code&gt;/content/vwww/www.adsl.perkin.org.uk/pkgstat&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Bulk build results directory&lt;/td&gt;&lt;/tr&gt;
  &lt;/tbody&gt;
 &lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;It’s definitely harder than it should be to get this all setup, but the good
news is that once it’s done there’s very little maintenance.&lt;/p&gt;

&lt;h2 id=&quot;kicking-it-all-off&quot;&gt;Kicking it all off&lt;/h2&gt;

&lt;p&gt;Once everything is setup:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; /content/scripts/create-zone vm0
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; ssh vm0 /content/scripts/build-packages
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; /content/scripts/update-packages
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; /content/scripts/delete-zone vm0&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This should do the lot.  Once
&lt;a href=&quot;/files/solaris-pkgsrc/build-packages&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;build-packages&lt;/code&gt;&lt;/a&gt; has finished you
should, if you configured your email address in build.conf, get an email with
the bulk build results which looks similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://mail-index.netbsd.org/pkgsrc-bulk/2009/08/23/msg006883.html&quot;&gt;http://mail-index.netbsd.org/pkgsrc-bulk/2009/08/23/msg006883.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A fuller report is available if you configure a web server to serve the
&lt;code class=&quot;highlighter-rouge&quot;&gt;pkgstat&lt;/code&gt; directory created by the bulk build, and this can help debug problems
(again see the above URL for an example).&lt;/p&gt;

&lt;p&gt;You will need to add &lt;code class=&quot;highlighter-rouge&quot;&gt;/opt/pkg/sbin:/opt/pkg/bin&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;$PATH&lt;/code&gt;.  Configuration
files are in &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/opt/pkg&lt;/code&gt;, and log files and metadata are kept in
&lt;code class=&quot;highlighter-rouge&quot;&gt;/var/opt/pkg&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;this-stuff-should-be-obsolete&quot;&gt;This stuff should be obsolete&lt;/h2&gt;

&lt;p&gt;While this all works well for me, it’s pretty lame for users who just want to
install packages and have stuff work.  I’m working on providing regular updates
of binary packages, including a SVR4 package of the bootstrap kit, so that in
theory all a user needs to do is&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkgadd TNFpkgsrc.pkg
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_add apache22
&lt;span class=&quot;gp&quot;&gt;#&lt;/span&gt; Upgrade all installed packages to latest releases
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; pkg_chk &lt;span class=&quot;nt&quot;&gt;-aurb&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I’m almost there, just needs some tidying up and regular builds.  Please feel
free to help out!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Jumpstart from OSX</title>
      <link>//www.perkin.org.uk/posts/jumpstart-from-osx.html</link>
      <pubDate>Tue, 09 Dec 2008 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/jumpstart-from-osx.html</guid>
      <description>&lt;p&gt;I recently built a new file server on which I planned to install Solaris 10
10/08.  I’m not a fan of CD/DVD installs, so wanted to jumpstart via PXE,
though I only had OSX handy.&lt;/p&gt;

&lt;p&gt;Here’s how I installed my new machine (gromit.adsl.perkin.org.uk/192.168.1.10)
from my iMac (192.168.1.30) over the local network.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note that since writing this piece I’ve updated to Solaris 10 10/09, and have
changed the examples to use that instead.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;step-1-prepare-file-system&quot;&gt;Step 1, Prepare File System&lt;/h2&gt;

&lt;p&gt;First off, create a dedicated file system which we can export our jumpstart
configuration from. You can probably skip this and just use any existing file
system but this way everything is self-contained and we avoid NFS exporting
more than we need.&lt;/p&gt;

&lt;p&gt;We use HFSX to ensure that the file system is case sensitive, HFS+ can cause
problems with &lt;code class=&quot;highlighter-rouge&quot;&gt;pkgadd(1M)&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; hdiutil create &lt;span class=&quot;nt&quot;&gt;-size&lt;/span&gt; 1g &lt;span class=&quot;nt&quot;&gt;-type&lt;/span&gt; SPARSE &lt;span class=&quot;nt&quot;&gt;-fs&lt;/span&gt; HFSX &lt;span class=&quot;nt&quot;&gt;-volname&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;install&quot;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; hdiutil attach install.sparseimage &lt;span class=&quot;nt&quot;&gt;-mountpoint&lt;/span&gt; /install&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Next up, download and mount &lt;code class=&quot;highlighter-rouge&quot;&gt;sol-10-u8-ga-x86-dvd.iso&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; open sol-10-u8-ga-x86-dvd.iso&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;step-2-nfs&quot;&gt;Step 2, NFS&lt;/h2&gt;

&lt;p&gt;Share &lt;code class=&quot;highlighter-rouge&quot;&gt;/install&lt;/code&gt; and the DVD via NFS with the correct options. &lt;code class=&quot;highlighter-rouge&quot;&gt;-alldirs&lt;/code&gt;
allows clients to mount from any point within that file system (which jumpstart
requires), and &lt;code class=&quot;highlighter-rouge&quot;&gt;-maproot=root&lt;/code&gt; is also required by jumpstart. As this allows
root-owned files to be created, make sure you understand the security risks.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;vi /etc/exports&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;/install                  -alldirs -maproot=root
/Volumes/SOL_10_1009_X86  -alldirs -maproot=root&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;nfsd checkexports &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;nfsd &lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;step-3-dhcp&quot;&gt;Step 3, DHCP&lt;/h2&gt;

&lt;p&gt;For DHCP I happen to already use my Cisco router as a DHCP server on the local
network, so added the following configuration:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;ip dhcp pool gromit.adsl.perkin.org.uk
   host 192.168.1.10 255.255.255.0
   hardware-address xxxx.xxxx.xxxx
   bootfile /boot/grub/pxegrub
   next-server 192.168.1.30
   client-name gromit
   domain-name adsl.perkin.org.uk
   dns-server xxx.xxx.xxx.xxx
   default-router 192.168.1.1&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;however, given this is a guide for setting everything up under OSX I also tried
using ISC DHCP on OSX to prove it can be done that way too.&lt;/p&gt;

&lt;p&gt;I used &lt;a href=&quot;http://www.pkgsrc.org/&quot;&gt;pkgsrc&lt;/a&gt; to install it (I’ll add another blog
some time showing how to set up pkgsrc)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /usr/pkgsrc/net/isc-dhcpd
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;bmake package&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And here is my DHCP configuration file in full:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;option domain-name &quot;adsl.perkin.org.uk&quot;;
option domain-name-servers xxx.xxx.xxx.xxx;
ddns-update-style none;
authoritative;
log-facility local7;

subnet 192.168.1.0 netmask 255.255.255.0 {
    option routers 192.168.1.1;
}

group {
    filename &quot;/boot/grub/pxegrub&quot;;
    next-server 192.168.1.30;

    host gromit {
        hardware ethernet xx:xx:xx:xx:xx:xx;
        fixed-address 192.168.1.10;
        option host-name &quot;gromit.adsl.perkin.org.uk&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, start DHCP with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; /usr/pkg/sbin/dhcpd&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Most parts of these configurations should be self-explanatory. The
&lt;code class=&quot;highlighter-rouge&quot;&gt;/boot/grub/pxegrub&lt;/code&gt; entry is important for our next step, and I’d recommend
using that exact pathname for reasons explained later.&lt;/p&gt;

&lt;h2 id=&quot;step-4-tftp&quot;&gt;Step 4, TFTP&lt;/h2&gt;

&lt;p&gt;Now, enable the TFTP server which comes with OSX. I added the &lt;code class=&quot;highlighter-rouge&quot;&gt;-s&lt;/code&gt; option so
tftpd would chroot to the tftpboot directory, both for security reasons and
also to ensure that paths specified as &lt;code class=&quot;highlighter-rouge&quot;&gt;/path/to/file&lt;/code&gt; would work correctly
(relative to &lt;code class=&quot;highlighter-rouge&quot;&gt;/install/tftpboot&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;I also changed the location of the tftpboot directory so that everything was
self-contained within the UFS image. In previous attempts I didn’t do this and
ran into problems with GRUB which I think are again caused by case-insensitive
file systems.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;vi /System/Library/LaunchDaemons/tftp.plist&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;[...]
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;key&amp;gt;&lt;/span&gt;ProgramArguments&lt;span class=&quot;nt&quot;&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/usr/libexec/tftpd&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;-i&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;-s&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/install/tftpboot&lt;span class=&quot;nt&quot;&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
[...]&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; /install/tftpboot
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;launchctl load &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; /System/Library/LaunchDaemons/tftp.plist&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can then create a test file and check that it’s working as you expect, using:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;testing&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;/install/tftpboot/testfile
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;verbose&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;get testfile&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | tftp localhost
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; /install/tftpboot/testfile&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;step-5-grub&quot;&gt;Step 5, GRUB&lt;/h2&gt;

&lt;p&gt;Next up, configure PXE booting using GRUB. We need to copy the GRUB images and
configuration from the Solaris install DVD then modify it for our environment:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; rsync &lt;span class=&quot;nt&quot;&gt;-av&lt;/span&gt; /Volumes/SOL_10_1009_X86/boot/grub /install/tftpboot/boot/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; rsync &lt;span class=&quot;nt&quot;&gt;-av&lt;/span&gt; /Volumes/SOL_10_1009_X86/boot/multiboot /install/tftpboot/sol10u8x/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; rsync &lt;span class=&quot;nt&quot;&gt;-av&lt;/span&gt; /Volumes/SOL_10_1009_X86/boot/x86.miniroot /install/tftpboot/sol10u8x/&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As we are copying the boot files from the DVD, they come hardcoded with
particular pathnames to e.g. the &lt;code class=&quot;highlighter-rouge&quot;&gt;menu.lst&lt;/code&gt; file. While it may be possible to
pass extra parameters to pxegrub and load this from a different path, I simply
recommend doing as I do and replicating the &lt;code class=&quot;highlighter-rouge&quot;&gt;/boot/grub/&lt;/code&gt; path structure so
that everything Just Works.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;menu.lst&lt;/code&gt; file includes kernel arguments and allows you to choose which
type of install to perform at startup. My file listed below has 3 choices:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Unattended install using a graphical environment (if available). The
“install” keyword after the kernel instructs it to perform an
unattended install, so long as it can find the necessary settings from
sysidcfg etc.&lt;/li&gt;
  &lt;li&gt;As above, but force the use of the console and do not start a graphical
environment (using the “nowin” keyword)&lt;/li&gt;
  &lt;li&gt;A manual install, so you need to go through the steps of layout out disks,
selecting packages, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi /install/tftpboot/boot/grub/menu.lst&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;default=0
timeout=60

title Solaris PXE Unattended Install
    kernel /sol10u8x/multiboot kernel/unix - install -B \
      install_media=192.168.1.30:/Volumes/SOL_10_1009_X86,\
      sysid_config=192.168.1.30:/install/jumpstart,\
      install_config=192.168.1.30:/install/jumpstart
    module /sol10u8x/x86.miniroot

title Solaris PXE Unattended Install (console)
    kernel /sol10u8x/multiboot kernel/unix - install nowin -B \
      install_media=192.168.1.30:/Volumes/SOL_10_1009_X86,\
      sysid_config=192.168.1.30:/install/jumpstart,\
      install_config=192.168.1.30:/install/jumpstart
    module /sol10u8x/x86.miniroot

title Solaris PXE Manual Install
    kernel /sol10u8x/multiboot kernel/unix -B \
      install_media=192.168.1.30:/Volumes/SOL_10_1009_X86
    module /sol10u8x/x86.miniroot&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Anyone used to doing jumpstart but with RARP/bootparams will notice the
symmetry between &lt;code class=&quot;highlighter-rouge&quot;&gt;install_config&lt;/code&gt; etc in the GRUB configuration and similar
options in &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/bootparams&lt;/code&gt;. Make sure that the full kernel arguments are all
on one line, and that there are no spaces in between the
&lt;code class=&quot;highlighter-rouge&quot;&gt;install_media=..,sysid_config=..&lt;/code&gt; options.&lt;/p&gt;

&lt;h2 id=&quot;step-6-jumpstart&quot;&gt;Step 6, Jumpstart&lt;/h2&gt;

&lt;p&gt;Finally, set up your Jumpstart configuration. Here’s what I personally use, you
may want something different:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; /install/jumpstart
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /install/jumpstart
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi sysidcfg&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;name_service=DNS
{
    domain_name=adsl.perkin.org.uk
    name_server=xxx.xxx.xxx.xxx
}
network_interface=PRIMARY
{
    default_route=192.168.1.1
    netmask=255.255.255.0
    protocol_ipv6=yes
}
nfs4_domain=dynamic
root_password=xxxxxxxx
terminal=xterm
timeserver=localhost
timezone=Europe/London
security_policy=NONE
service_profile=limited_net
system_locale=C&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ordinarily this file is processed using a &lt;code class=&quot;highlighter-rouge&quot;&gt;check&lt;/code&gt; script available in the
&lt;code class=&quot;highlighter-rouge&quot;&gt;jumpstart_sample&lt;/code&gt; directory on the Solaris DVD, however this only works from a
Solaris host. To create the &lt;code class=&quot;highlighter-rouge&quot;&gt;rules.ok&lt;/code&gt; file, we need to strip out any comments
and put entries on one line, then create the checksum (although this isn’t
actually necessary).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi rules &lt;span class=&quot;c&quot;&gt;# emacs sucks :)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;hostname gromit.adsl.perkin.org.uk - profile -&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;rules rules.ok
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;# version=2 checksum=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cksum&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; 2 rules | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{print $1}'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; rules.ok&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Machine profile. This gives me a full Solaris install (minus OEM stuff) on
mirrored ZFS disks with additional dump/swap space (the defaults made dump a
bit too small I found).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; vi profile&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;install_type    initial_install
pool            store auto 4g 4g mirror c1t0d0s0 c1t1d0s0
bootenv         installbe bename sol10u8x
cluster         SUNWCall&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;step-7-make-a-cup-of-tea&quot;&gt;Step 7, Make A Cup Of Tea&lt;/h2&gt;

&lt;p&gt;With everything set up you should be able to enable PXE booting in your BIOS
and watch it automatically install. One small minor problem you may have if you
don’t have a BIOS which allows you to hit F12 or similar and choose PXE booting
for one boot only is that it will infinitely cycle through installing,
rebooting, installing, rebooting.. until you change your boot options.&lt;/p&gt;

&lt;p&gt;If this happens, I recommend making more cups of tea until you happen to return
in time to change the BIOS settings. If you aren’t able to do this for a while,
you may need to add the extra steps 8, 9 and 10 titled “Visit The
Bathroom”.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Set up local caching DNS server on OSX 10.4</title>
      <link>//www.perkin.org.uk/posts/set-up-local-caching-dns-server-on-osx-104.html</link>
      <pubDate>Mon, 31 Dec 2007 00:00:00 +0000</pubDate>
      <author>jonathan@perkin.org.uk (Jonathan Perkin)</author>
      <guid>//www.perkin.org.uk/posts/set-up-local-caching-dns-server-on-osx-104.html</guid>
      <description>&lt;p&gt;OSX 10.4 ships with ISC &lt;code class=&quot;highlighter-rouge&quot;&gt;named&lt;/code&gt;, but is not configured correctly out of the
box.  Follow the instructions below to run a local caching name server.&lt;/p&gt;

&lt;p&gt;First, we need to generate an rndc key.  The default &lt;code class=&quot;highlighter-rouge&quot;&gt;named.conf&lt;/code&gt; comes configured to use one, but if it does not exist will bail with an error.  Simply run &lt;code class=&quot;highlighter-rouge&quot;&gt;rndc-confgen(1)&lt;/code&gt; to create one.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;rndc-confgen &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Next, download the latest &lt;code class=&quot;highlighter-rouge&quot;&gt;named.root&lt;/code&gt; file, as the supplied &lt;code class=&quot;highlighter-rouge&quot;&gt;named.ca&lt;/code&gt; is
rather outdated (as you can see from the diff output).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /var/named
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; ftp://ftp.internic.net/domain/named.root
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; diff &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; named.ca named.root&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now edit &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/named.conf&lt;/code&gt;, we need to make three changes.  Firstly, the rndc
port is wrong in the default configuration, so make it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;        inet 127.0.0.1 port 953 allow {any;}&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Next, add a &lt;code class=&quot;highlighter-rouge&quot;&gt;listen-on&lt;/code&gt; directive in the options section to instruct named to
only listen on certain interfaces, ensuring that we keep as secure as possible.
I have added the internal 192.168/16 LAN to my configuration so that Parallels
VMs and other machines can use the server, but if you do not need this then
just keep the localhost entry:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;        directory &quot;/var/named&quot;;
        listen-on {
                127.0.0.1;
                192.168/16;
        };&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, change the root DNS server file from &lt;code class=&quot;highlighter-rouge&quot;&gt;named.ca&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;named.root&lt;/code&gt; as
downloaded above.  You could simply overwrite the &lt;code class=&quot;highlighter-rouge&quot;&gt;named.ca&lt;/code&gt; file instead with
&lt;code class=&quot;highlighter-rouge&quot;&gt;named.root&lt;/code&gt;, however I like to keep defaults around as much as possible - you
never know if an update will blat your changes or not:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;zone &quot;.&quot; IN {
        type hint;
        file &quot;named.root&quot;;
};&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;All done.  All that’s left to do is (re)start the service:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;service org.isc.named stop
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;service org.isc.named start&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;then run a quick test to ensure it is working correctly:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt; dig www.perkin.org.uk @localhost&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you get a reply, configure your DNS server to be 127.0.0.1 and you’re all
set.&lt;/p&gt;
</description>
    </item>
    

  </channel>
</rss>
