go.net/ipv4: make use of go generate to create system adaptation files

LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/160800043
diff --git a/ipv4/gen.go b/ipv4/gen.go
index f2721a5..a1d65ef 100644
--- a/ipv4/gen.go
+++ b/ipv4/gen.go
@@ -6,8 +6,9 @@
 
 //go:generate go run gen.go
 
-// This program generates internet protocol constants and tables by
-// reading IANA protocol registries.
+// This program generates system adaptation constants and types,
+// internet protocol constants and tables by reading template files
+// and IANA protocol registries.
 package main
 
 import (
@@ -19,10 +20,55 @@
 	"io/ioutil"
 	"net/http"
 	"os"
+	"os/exec"
+	"runtime"
 	"strconv"
 	"strings"
 )
 
+func main() {
+	if err := genzsys(); err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(1)
+	}
+	if err := geniana(); err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(1)
+	}
+}
+
+func genzsys() error {
+	defs := "defs_" + runtime.GOOS + ".go"
+	f, err := os.Open(defs)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return nil
+		}
+		return err
+	}
+	f.Close()
+	cmd := exec.Command("go", "tool", "cgo", "-godefs", defs)
+	b, err := cmd.Output()
+	if err != nil {
+		return err
+	}
+	switch runtime.GOOS {
+	case "dragonfly", "solaris":
+		// The ipv4 pacakge still supports go1.2, and so we
+		// need to take care of additional platforms in go1.3
+		// and above for working with go1.2.
+		b = bytes.Replace(b, []byte("package ipv4\n"), []byte("// +build "+runtime.GOOS+"\n\npackage ipv4\n"), 1)
+	}
+	b, err = format.Source(b)
+	if err != nil {
+		return err
+	}
+	if err := ioutil.WriteFile("zsys_"+runtime.GOOS+".go", b, 0644); err != nil {
+		return err
+	}
+	return nil
+}
+
 var registries = []struct {
 	url   string
 	parse func(io.Writer, io.Reader) error
@@ -33,7 +79,7 @@
 	},
 }
 
-func main() {
+func geniana() error {
 	var bb bytes.Buffer
 	fmt.Fprintf(&bb, "// go generate gen.go\n")
 	fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
@@ -41,29 +87,25 @@
 	for _, r := range registries {
 		resp, err := http.Get(r.url)
 		if err != nil {
-			fmt.Fprintln(os.Stderr, err)
-			os.Exit(1)
+			return err
 		}
 		defer resp.Body.Close()
 		if resp.StatusCode != http.StatusOK {
-			fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url)
-			os.Exit(1)
+			return fmt.Errorf("got HTTP status code %v for %v\n", resp.StatusCode, r.url)
 		}
 		if err := r.parse(&bb, resp.Body); err != nil {
-			fmt.Fprintln(os.Stderr, err)
-			os.Exit(1)
+			return err
 		}
 		fmt.Fprintf(&bb, "\n")
 	}
 	b, err := format.Source(bb.Bytes())
 	if err != nil {
-		fmt.Fprintln(os.Stderr, err)
-		os.Exit(1)
+		return err
 	}
 	if err := ioutil.WriteFile("iana.go", b, 0644); err != nil {
-		fmt.Fprintln(os.Stderr, err)
-		os.Exit(1)
+		return err
 	}
+	return nil
 }
 
 func parseICMPv4Parameters(w io.Writer, r io.Reader) error {