Merge pull request #3089 from thaJeztah/bump_golang_1.13.7
Update Golang 1.13.7, golang.org/x/crypto (CVE-2020-0601, CVE-2020-7919)master
						commit
						861aa2a621
					
				|  | @ -7,7 +7,7 @@ services: | |||
| language: go | ||||
| 
 | ||||
| go: | ||||
|   - "1.12.x" | ||||
|   - "1.13.x" | ||||
| 
 | ||||
| go_import_path: github.com/docker/distribution | ||||
| 
 | ||||
|  | @ -25,7 +25,7 @@ before_install: | |||
|   - sudo apt-get -q update | ||||
| 
 | ||||
| install: | ||||
|   - go get -u github.com/vbatts/git-validation | ||||
|   - cd /tmp && go get -u github.com/vbatts/git-validation | ||||
|     # TODO: Add enforcement of license | ||||
|     # - go get -u github.com/kunalkushwaha/ltag | ||||
|   - cd $TRAVIS_BUILD_DIR | ||||
|  |  | |||
|  | @ -1,4 +1,6 @@ | |||
| FROM golang:1.13.4-alpine AS build | ||||
| ARG GO_VERSION=1.13.7 | ||||
| 
 | ||||
| FROM golang:${GO_VERSION}-alpine3.11 AS build | ||||
| 
 | ||||
| ENV DISTRIBUTION_DIR /go/src/github.com/docker/distribution | ||||
| ENV BUILDTAGS include_oss include_gcs | ||||
|  | @ -16,7 +18,7 @@ WORKDIR $DISTRIBUTION_DIR | |||
| COPY . $DISTRIBUTION_DIR | ||||
| RUN CGO_ENABLED=0 make PREFIX=/go clean binaries && file ./bin/registry | grep "statically linked" | ||||
| 
 | ||||
| FROM alpine:3.10 | ||||
| FROM alpine:3.11 | ||||
| 
 | ||||
| RUN set -ex \ | ||||
|     && apk add --no-cache ca-certificates apache2-utils | ||||
|  |  | |||
							
								
								
									
										2
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										2
									
								
								go.mod
								
								
								
								
							|  | @ -45,7 +45,7 @@ require ( | |||
| 	github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 // indirect | ||||
| 	github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 | ||||
| 	github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f // indirect | ||||
| 	golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 | ||||
| 	golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d | ||||
| 	golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b // indirect | ||||
| 	golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 | ||||
| 	golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed // indirect | ||||
|  |  | |||
							
								
								
									
										4
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										4
									
								
								go.sum
								
								
								
								
							|  | @ -111,10 +111,13 @@ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1 | |||
| github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= | ||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= | ||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||
| golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d h1:9FCpayM9Egr1baVnV1SX0H87m+XB0B8S0hAMi99X/3U= | ||||
| golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= | ||||
| golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||
| golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||
| golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b h1:lkjdUzSyJ5P1+eal9fxXX9Xg2BTfswsonKUse48C0uE= | ||||
| golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= | ||||
|  | @ -122,6 +125,7 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr | |||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= | ||||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed h1:uPxWBzB3+mlnjy9W58qY1j/cjyFjutgw/Vhan2zLy/A= | ||||
| golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
|  |  | |||
|  | @ -5,5 +5,7 @@ | |||
| # | ||||
| set -eu -o pipefail | ||||
| 
 | ||||
| # prevent updating go.mod of the project | ||||
| cd /tmp | ||||
| go get -u github.com/golangci/golangci-lint/cmd/golangci-lint | ||||
| go get -u github.com/cpuguy83/go-md2man | ||||
|  |  | |||
|  | @ -4,7 +4,10 @@ | |||
| 
 | ||||
| // Package acme provides an implementation of the
 | ||||
| // Automatic Certificate Management Environment (ACME) spec.
 | ||||
| // See https://tools.ietf.org/html/draft-ietf-acme-acme-02 for details.
 | ||||
| // The intial implementation was based on ACME draft-02 and
 | ||||
| // is now being extended to comply with RFC 8555.
 | ||||
| // See https://tools.ietf.org/html/draft-ietf-acme-acme-02
 | ||||
| // and https://tools.ietf.org/html/rfc8555 for details.
 | ||||
| //
 | ||||
| // Most common scenarios will want to use autocert subdirectory instead,
 | ||||
| // which provides automatic access to certificates from Let's Encrypt
 | ||||
|  | @ -41,7 +44,7 @@ import ( | |||
| 
 | ||||
| const ( | ||||
| 	// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
 | ||||
| 	LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory" | ||||
| 	LetsEncryptURL = "https://acme-v02.api.letsencrypt.org/directory" | ||||
| 
 | ||||
| 	// ALPNProto is the ALPN protocol name used by a CA server when validating
 | ||||
| 	// tls-alpn-01 challenges.
 | ||||
|  | @ -57,7 +60,10 @@ var idPeACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1} | |||
| 
 | ||||
| const ( | ||||
| 	maxChainLen = 5       // max depth and breadth of a certificate chain
 | ||||
| 	maxCertSize = 1 << 20 // max size of a certificate, in bytes
 | ||||
| 	maxCertSize = 1 << 20 // max size of a certificate, in DER bytes
 | ||||
| 	// Used for decoding certs from application/pem-certificate-chain response,
 | ||||
| 	// the default when in RFC mode.
 | ||||
| 	maxCertChainSize = maxCertSize * maxChainLen | ||||
| 
 | ||||
| 	// Max number of collected nonces kept in memory.
 | ||||
| 	// Expect usual peak of 1 or 2.
 | ||||
|  | @ -109,21 +115,55 @@ type Client struct { | |||
| 	// The jitter is a random value up to 1 second.
 | ||||
| 	RetryBackoff func(n int, r *http.Request, resp *http.Response) time.Duration | ||||
| 
 | ||||
| 	dirMu sync.Mutex // guards writes to dir
 | ||||
| 	dir   *Directory // cached result of Client's Discover method
 | ||||
| 	// UserAgent is prepended to the User-Agent header sent to the ACME server,
 | ||||
| 	// which by default is this package's name and version.
 | ||||
| 	//
 | ||||
| 	// Reusable libraries and tools in particular should set this value to be
 | ||||
| 	// identifiable by the server, in case they are causing issues.
 | ||||
| 	UserAgent string | ||||
| 
 | ||||
| 	cacheMu sync.Mutex | ||||
| 	dir     *Directory // cached result of Client's Discover method
 | ||||
| 	kid     keyID      // cached Account.URI obtained from registerRFC or getAccountRFC
 | ||||
| 
 | ||||
| 	noncesMu sync.Mutex | ||||
| 	nonces   map[string]struct{} // nonces collected from previous responses
 | ||||
| } | ||||
| 
 | ||||
| // accountKID returns a key ID associated with c.Key, the account identity
 | ||||
| // provided by the CA during RFC based registration.
 | ||||
| // It assumes c.Discover has already been called.
 | ||||
| //
 | ||||
| // accountKID requires at most one network roundtrip.
 | ||||
| // It caches only successful result.
 | ||||
| //
 | ||||
| // When in pre-RFC mode or when c.getRegRFC responds with an error, accountKID
 | ||||
| // returns noKeyID.
 | ||||
| func (c *Client) accountKID(ctx context.Context) keyID { | ||||
| 	c.cacheMu.Lock() | ||||
| 	defer c.cacheMu.Unlock() | ||||
| 	if !c.dir.rfcCompliant() { | ||||
| 		return noKeyID | ||||
| 	} | ||||
| 	if c.kid != noKeyID { | ||||
| 		return c.kid | ||||
| 	} | ||||
| 	a, err := c.getRegRFC(ctx) | ||||
| 	if err != nil { | ||||
| 		return noKeyID | ||||
| 	} | ||||
| 	c.kid = keyID(a.URI) | ||||
| 	return c.kid | ||||
| } | ||||
| 
 | ||||
| // Discover performs ACME server discovery using c.DirectoryURL.
 | ||||
| //
 | ||||
| // It caches successful result. So, subsequent calls will not result in
 | ||||
| // a network round-trip. This also means mutating c.DirectoryURL after successful call
 | ||||
| // of this method will have no effect.
 | ||||
| func (c *Client) Discover(ctx context.Context) (Directory, error) { | ||||
| 	c.dirMu.Lock() | ||||
| 	defer c.dirMu.Unlock() | ||||
| 	c.cacheMu.Lock() | ||||
| 	defer c.cacheMu.Unlock() | ||||
| 	if c.dir != nil { | ||||
| 		return *c.dir, nil | ||||
| 	} | ||||
|  | @ -136,27 +176,53 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) { | |||
| 	c.addNonce(res.Header) | ||||
| 
 | ||||
| 	var v struct { | ||||
| 		Reg    string `json:"new-reg"` | ||||
| 		Authz  string `json:"new-authz"` | ||||
| 		Cert   string `json:"new-cert"` | ||||
| 		Revoke string `json:"revoke-cert"` | ||||
| 		Meta   struct { | ||||
| 			Terms   string   `json:"terms-of-service"` | ||||
| 			Website string   `json:"website"` | ||||
| 			CAA     []string `json:"caa-identities"` | ||||
| 		Reg          string `json:"new-reg"` | ||||
| 		RegRFC       string `json:"newAccount"` | ||||
| 		Authz        string `json:"new-authz"` | ||||
| 		AuthzRFC     string `json:"newAuthz"` | ||||
| 		OrderRFC     string `json:"newOrder"` | ||||
| 		Cert         string `json:"new-cert"` | ||||
| 		Revoke       string `json:"revoke-cert"` | ||||
| 		RevokeRFC    string `json:"revokeCert"` | ||||
| 		NonceRFC     string `json:"newNonce"` | ||||
| 		KeyChangeRFC string `json:"keyChange"` | ||||
| 		Meta         struct { | ||||
| 			Terms           string   `json:"terms-of-service"` | ||||
| 			TermsRFC        string   `json:"termsOfService"` | ||||
| 			WebsiteRFC      string   `json:"website"` | ||||
| 			CAA             []string `json:"caa-identities"` | ||||
| 			CAARFC          []string `json:"caaIdentities"` | ||||
| 			ExternalAcctRFC bool     `json:"externalAccountRequired"` | ||||
| 		} | ||||
| 	} | ||||
| 	if err := json.NewDecoder(res.Body).Decode(&v); err != nil { | ||||
| 		return Directory{}, err | ||||
| 	} | ||||
| 	if v.OrderRFC == "" { | ||||
| 		// Non-RFC compliant ACME CA.
 | ||||
| 		c.dir = &Directory{ | ||||
| 			RegURL:    v.Reg, | ||||
| 			AuthzURL:  v.Authz, | ||||
| 			CertURL:   v.Cert, | ||||
| 			RevokeURL: v.Revoke, | ||||
| 			Terms:     v.Meta.Terms, | ||||
| 			Website:   v.Meta.WebsiteRFC, | ||||
| 			CAA:       v.Meta.CAA, | ||||
| 		} | ||||
| 		return *c.dir, nil | ||||
| 	} | ||||
| 	// RFC compliant ACME CA.
 | ||||
| 	c.dir = &Directory{ | ||||
| 		RegURL:    v.Reg, | ||||
| 		AuthzURL:  v.Authz, | ||||
| 		CertURL:   v.Cert, | ||||
| 		RevokeURL: v.Revoke, | ||||
| 		Terms:     v.Meta.Terms, | ||||
| 		Website:   v.Meta.Website, | ||||
| 		CAA:       v.Meta.CAA, | ||||
| 		RegURL:                  v.RegRFC, | ||||
| 		AuthzURL:                v.AuthzRFC, | ||||
| 		OrderURL:                v.OrderRFC, | ||||
| 		RevokeURL:               v.RevokeRFC, | ||||
| 		NonceURL:                v.NonceRFC, | ||||
| 		KeyChangeURL:            v.KeyChangeRFC, | ||||
| 		Terms:                   v.Meta.TermsRFC, | ||||
| 		Website:                 v.Meta.WebsiteRFC, | ||||
| 		CAA:                     v.Meta.CAARFC, | ||||
| 		ExternalAccountRequired: v.Meta.ExternalAcctRFC, | ||||
| 	} | ||||
| 	return *c.dir, nil | ||||
| } | ||||
|  | @ -169,6 +235,9 @@ func (c *Client) directoryURL() string { | |||
| } | ||||
| 
 | ||||
| // CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format.
 | ||||
| // It is incompatible with RFC 8555. Callers should use CreateOrderCert when interfacing
 | ||||
| // with an RFC-compliant CA.
 | ||||
| //
 | ||||
| // The exp argument indicates the desired certificate validity duration. CA may issue a certificate
 | ||||
| // with a different duration.
 | ||||
| // If the bundle argument is true, the returned value will also contain the CA (issuer) certificate chain.
 | ||||
|  | @ -199,7 +268,7 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, | |||
| 		req.NotAfter = now.Add(exp).Format(time.RFC3339) | ||||
| 	} | ||||
| 
 | ||||
| 	res, err := c.post(ctx, c.Key, c.dir.CertURL, req, wantStatus(http.StatusCreated)) | ||||
| 	res, err := c.post(ctx, nil, c.dir.CertURL, req, wantStatus(http.StatusCreated)) | ||||
| 	if err != nil { | ||||
| 		return nil, "", err | ||||
| 	} | ||||
|  | @ -220,12 +289,22 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, | |||
| // It retries the request until the certificate is successfully retrieved,
 | ||||
| // context is cancelled by the caller or an error response is received.
 | ||||
| //
 | ||||
| // The returned value will also contain the CA (issuer) certificate if the bundle argument is true.
 | ||||
| // If the bundle argument is true, the returned value also contains the CA (issuer)
 | ||||
| // certificate chain.
 | ||||
| //
 | ||||
| // FetchCert returns an error if the CA's response or chain was unreasonably large.
 | ||||
| // Callers are encouraged to parse the returned value to ensure the certificate is valid
 | ||||
| // and has expected features.
 | ||||
| func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) { | ||||
| 	dir, err := c.Discover(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if dir.rfcCompliant() { | ||||
| 		return c.fetchCertRFC(ctx, url, bundle) | ||||
| 	} | ||||
| 
 | ||||
| 	// Legacy non-authenticated GET request.
 | ||||
| 	res, err := c.get(ctx, url, wantStatus(http.StatusOK)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|  | @ -240,10 +319,15 @@ func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]by | |||
| // For instance, the key pair of the certificate may be authorized.
 | ||||
| // If the key is nil, c.Key is used instead.
 | ||||
| func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error { | ||||
| 	if _, err := c.Discover(ctx); err != nil { | ||||
| 	dir, err := c.Discover(ctx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if dir.rfcCompliant() { | ||||
| 		return c.revokeCertRFC(ctx, key, cert, reason) | ||||
| 	} | ||||
| 
 | ||||
| 	// Legacy CA.
 | ||||
| 	body := &struct { | ||||
| 		Resource string `json:"resource"` | ||||
| 		Cert     string `json:"certificate"` | ||||
|  | @ -253,10 +337,7 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, | |||
| 		Cert:     base64.RawURLEncoding.EncodeToString(cert), | ||||
| 		Reason:   int(reason), | ||||
| 	} | ||||
| 	if key == nil { | ||||
| 		key = c.Key | ||||
| 	} | ||||
| 	res, err := c.post(ctx, key, c.dir.RevokeURL, body, wantStatus(http.StatusOK)) | ||||
| 	res, err := c.post(ctx, key, dir.RevokeURL, body, wantStatus(http.StatusOK)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | @ -268,20 +349,30 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, | |||
| // during account registration. See Register method of Client for more details.
 | ||||
| func AcceptTOS(tosURL string) bool { return true } | ||||
| 
 | ||||
| // Register creates a new account registration by following the "new-reg" flow.
 | ||||
| // It returns the registered account. The account is not modified.
 | ||||
| // Register creates a new account with the CA using c.Key.
 | ||||
| // It returns the registered account. The account acct is not modified.
 | ||||
| //
 | ||||
| // The registration may require the caller to agree to the CA's Terms of Service (TOS).
 | ||||
| // If so, and the account has not indicated the acceptance of the terms (see Account for details),
 | ||||
| // Register calls prompt with a TOS URL provided by the CA. Prompt should report
 | ||||
| // whether the caller agrees to the terms. To always accept the terms, the caller can use AcceptTOS.
 | ||||
| func (c *Client) Register(ctx context.Context, a *Account, prompt func(tosURL string) bool) (*Account, error) { | ||||
| 	if _, err := c.Discover(ctx); err != nil { | ||||
| //
 | ||||
| // When interfacing with an RFC-compliant CA, non-RFC 8555 fields of acct are ignored
 | ||||
| // and prompt is called if Directory's Terms field is non-zero.
 | ||||
| // Also see Error's Instance field for when a CA requires already registered accounts to agree
 | ||||
| // to an updated Terms of Service.
 | ||||
| func (c *Client) Register(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) { | ||||
| 	dir, err := c.Discover(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if dir.rfcCompliant() { | ||||
| 		return c.registerRFC(ctx, acct, prompt) | ||||
| 	} | ||||
| 
 | ||||
| 	var err error | ||||
| 	if a, err = c.doReg(ctx, c.dir.RegURL, "new-reg", a); err != nil { | ||||
| 	// Legacy ACME draft registration flow.
 | ||||
| 	a, err := c.doReg(ctx, dir.RegURL, "new-reg", acct) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var accept bool | ||||
|  | @ -295,9 +386,20 @@ func (c *Client) Register(ctx context.Context, a *Account, prompt func(tosURL st | |||
| 	return a, err | ||||
| } | ||||
| 
 | ||||
| // GetReg retrieves an existing registration.
 | ||||
| // The url argument is an Account URI.
 | ||||
| // GetReg retrieves an existing account associated with c.Key.
 | ||||
| //
 | ||||
| // The url argument is an Account URI used with pre-RFC 8555 CAs.
 | ||||
| // It is ignored when interfacing with an RFC-compliant CA.
 | ||||
| func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) { | ||||
| 	dir, err := c.Discover(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if dir.rfcCompliant() { | ||||
| 		return c.getRegRFC(ctx) | ||||
| 	} | ||||
| 
 | ||||
| 	// Legacy CA.
 | ||||
| 	a, err := c.doReg(ctx, url, "reg", nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|  | @ -308,9 +410,21 @@ func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) { | |||
| 
 | ||||
| // UpdateReg updates an existing registration.
 | ||||
| // It returns an updated account copy. The provided account is not modified.
 | ||||
| func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) { | ||||
| 	uri := a.URI | ||||
| 	a, err := c.doReg(ctx, uri, "reg", a) | ||||
| //
 | ||||
| // When interfacing with RFC-compliant CAs, a.URI is ignored and the account URL
 | ||||
| // associated with c.Key is used instead.
 | ||||
| func (c *Client) UpdateReg(ctx context.Context, acct *Account) (*Account, error) { | ||||
| 	dir, err := c.Discover(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if dir.rfcCompliant() { | ||||
| 		return c.updateRegRFC(ctx, acct) | ||||
| 	} | ||||
| 
 | ||||
| 	// Legacy CA.
 | ||||
| 	uri := acct.URI | ||||
| 	a, err := c.doReg(ctx, uri, "reg", acct) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | @ -318,13 +432,21 @@ func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) { | |||
| 	return a, nil | ||||
| } | ||||
| 
 | ||||
| // Authorize performs the initial step in an authorization flow.
 | ||||
| // Authorize performs the initial step in the pre-authorization flow,
 | ||||
| // as opposed to order-based flow.
 | ||||
| // The caller will then need to choose from and perform a set of returned
 | ||||
| // challenges using c.Accept in order to successfully complete authorization.
 | ||||
| //
 | ||||
| // Once complete, the caller can use AuthorizeOrder which the CA
 | ||||
| // should provision with the already satisfied authorization.
 | ||||
| // For pre-RFC CAs, the caller can proceed directly to requesting a certificate
 | ||||
| // using CreateCert method.
 | ||||
| //
 | ||||
| // If an authorization has been previously granted, the CA may return
 | ||||
| // a valid authorization (Authorization.Status is StatusValid). If so, the caller
 | ||||
| // need not fulfill any challenge and can proceed to requesting a certificate.
 | ||||
| // a valid authorization which has its Status field set to StatusValid.
 | ||||
| //
 | ||||
| // More about pre-authorization can be found at
 | ||||
| // https://tools.ietf.org/html/rfc8555#section-7.4.1.
 | ||||
| func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) { | ||||
| 	return c.authorize(ctx, "dns", domain) | ||||
| } | ||||
|  | @ -355,7 +477,7 @@ func (c *Client) authorize(ctx context.Context, typ, val string) (*Authorization | |||
| 		Resource:   "new-authz", | ||||
| 		Identifier: authzID{Type: typ, Value: val}, | ||||
| 	} | ||||
| 	res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated)) | ||||
| 	res, err := c.post(ctx, nil, c.dir.AuthzURL, req, wantStatus(http.StatusCreated)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | @ -376,7 +498,17 @@ func (c *Client) authorize(ctx context.Context, typ, val string) (*Authorization | |||
| // If a caller needs to poll an authorization until its status is final,
 | ||||
| // see the WaitAuthorization method.
 | ||||
| func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) { | ||||
| 	res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) | ||||
| 	dir, err := c.Discover(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var res *http.Response | ||||
| 	if dir.rfcCompliant() { | ||||
| 		res, err = c.postAsGet(ctx, url, wantStatus(http.StatusOK)) | ||||
| 	} else { | ||||
| 		res, err = c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | @ -393,11 +525,16 @@ func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorizati | |||
| // The url argument is an Authorization.URI value.
 | ||||
| //
 | ||||
| // If successful, the caller will be required to obtain a new authorization
 | ||||
| // using the Authorize method before being able to request a new certificate
 | ||||
| // for the domain associated with the authorization.
 | ||||
| // using the Authorize or AuthorizeOrder methods before being able to request
 | ||||
| // a new certificate for the domain associated with the authorization.
 | ||||
| //
 | ||||
| // It does not revoke existing certificates.
 | ||||
| func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { | ||||
| 	// Required for c.accountKID() when in RFC mode.
 | ||||
| 	if _, err := c.Discover(ctx); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	req := struct { | ||||
| 		Resource string `json:"resource"` | ||||
| 		Status   string `json:"status"` | ||||
|  | @ -407,7 +544,7 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { | |||
| 		Status:   "deactivated", | ||||
| 		Delete:   true, | ||||
| 	} | ||||
| 	res, err := c.post(ctx, c.Key, url, req, wantStatus(http.StatusOK)) | ||||
| 	res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | @ -423,8 +560,18 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { | |||
| // In all other cases WaitAuthorization returns an error.
 | ||||
| // If the Status is StatusInvalid, the returned error is of type *AuthorizationError.
 | ||||
| func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) { | ||||
| 	// Required for c.accountKID() when in RFC mode.
 | ||||
| 	dir, err := c.Discover(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	getfn := c.postAsGet | ||||
| 	if !dir.rfcCompliant() { | ||||
| 		getfn = c.get | ||||
| 	} | ||||
| 
 | ||||
| 	for { | ||||
| 		res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) | ||||
| 		res, err := getfn(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | @ -467,10 +614,21 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat | |||
| //
 | ||||
| // A client typically polls a challenge status using this method.
 | ||||
| func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) { | ||||
| 	res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) | ||||
| 	// Required for c.accountKID() when in RFC mode.
 | ||||
| 	dir, err := c.Discover(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	getfn := c.postAsGet | ||||
| 	if !dir.rfcCompliant() { | ||||
| 		getfn = c.get | ||||
| 	} | ||||
| 	res, err := getfn(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	defer res.Body.Close() | ||||
| 	v := wireChallenge{URI: url} | ||||
| 	if err := json.NewDecoder(res.Body).Decode(&v); err != nil { | ||||
|  | @ -484,21 +642,29 @@ func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, erro | |||
| //
 | ||||
| // The server will then perform the validation asynchronously.
 | ||||
| func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error) { | ||||
| 	auth, err := keyAuth(c.Key.Public(), chal.Token) | ||||
| 	// Required for c.accountKID() when in RFC mode.
 | ||||
| 	dir, err := c.Discover(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	req := struct { | ||||
| 		Resource string `json:"resource"` | ||||
| 		Type     string `json:"type"` | ||||
| 		Auth     string `json:"keyAuthorization"` | ||||
| 	}{ | ||||
| 		Resource: "challenge", | ||||
| 		Type:     chal.Type, | ||||
| 		Auth:     auth, | ||||
| 	var req interface{} = json.RawMessage("{}") // RFC-compliant CA
 | ||||
| 	if !dir.rfcCompliant() { | ||||
| 		auth, err := keyAuth(c.Key.Public(), chal.Token) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		req = struct { | ||||
| 			Resource string `json:"resource"` | ||||
| 			Type     string `json:"type"` | ||||
| 			Auth     string `json:"keyAuthorization"` | ||||
| 		}{ | ||||
| 			Resource: "challenge", | ||||
| 			Type:     chal.Type, | ||||
| 			Auth:     auth, | ||||
| 		} | ||||
| 	} | ||||
| 	res, err := c.post(ctx, c.Key, chal.URI, req, wantStatus( | ||||
| 	res, err := c.post(ctx, nil, chal.URI, req, wantStatus( | ||||
| 		http.StatusOK,       // according to the spec
 | ||||
| 		http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md)
 | ||||
| 	)) | ||||
|  | @ -548,21 +714,8 @@ func (c *Client) HTTP01ChallengePath(token string) string { | |||
| } | ||||
| 
 | ||||
| // TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response.
 | ||||
| // Servers can present the certificate to validate the challenge and prove control
 | ||||
| // over a domain name.
 | ||||
| //
 | ||||
| // The implementation is incomplete in that the returned value is a single certificate,
 | ||||
| // computed only for Z0 of the key authorization. ACME CAs are expected to update
 | ||||
| // their implementations to use the newer version, TLS-SNI-02.
 | ||||
| // For more details on TLS-SNI-01 see https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.3.
 | ||||
| //
 | ||||
| // The token argument is a Challenge.Token value.
 | ||||
| // If a WithKey option is provided, its private part signs the returned cert,
 | ||||
| // and the public part is used to specify the signee.
 | ||||
| // If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
 | ||||
| //
 | ||||
| // The returned certificate is valid for the next 24 hours and must be presented only when
 | ||||
| // the server name of the TLS ClientHello matches exactly the returned name value.
 | ||||
| // Deprecated: This challenge type is unused in both draft-02 and RFC versions of ACME spec.
 | ||||
| func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { | ||||
| 	ka, err := keyAuth(c.Key.Public(), token) | ||||
| 	if err != nil { | ||||
|  | @ -579,17 +732,8 @@ func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tl | |||
| } | ||||
| 
 | ||||
| // TLSSNI02ChallengeCert creates a certificate for TLS-SNI-02 challenge response.
 | ||||
| // Servers can present the certificate to validate the challenge and prove control
 | ||||
| // over a domain name. For more details on TLS-SNI-02 see
 | ||||
| // https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.3.
 | ||||
| //
 | ||||
| // The token argument is a Challenge.Token value.
 | ||||
| // If a WithKey option is provided, its private part signs the returned cert,
 | ||||
| // and the public part is used to specify the signee.
 | ||||
| // If no WithKey option is provided, a new ECDSA key is generated using P-256 curve.
 | ||||
| //
 | ||||
| // The returned certificate is valid for the next 24 hours and must be presented only when
 | ||||
| // the server name in the TLS ClientHello matches exactly the returned name value.
 | ||||
| // Deprecated: This challenge type is unused in both draft-02 and RFC versions of ACME spec.
 | ||||
| func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { | ||||
| 	b := sha256.Sum256([]byte(token)) | ||||
| 	h := hex.EncodeToString(b[:]) | ||||
|  | @ -656,7 +800,7 @@ func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption) | |||
| 	return tlsChallengeCert([]string{domain}, newOpt) | ||||
| } | ||||
| 
 | ||||
| // doReg sends all types of registration requests.
 | ||||
| // doReg sends all types of registration requests the old way (pre-RFC world).
 | ||||
| // The type of request is identified by typ argument, which is a "resource"
 | ||||
| // in the ACME spec terms.
 | ||||
| //
 | ||||
|  | @ -675,7 +819,7 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun | |||
| 		req.Contact = acct.Contact | ||||
| 		req.Agreement = acct.AgreedTerms | ||||
| 	} | ||||
| 	res, err := c.post(ctx, c.Key, url, req, wantStatus( | ||||
| 	res, err := c.post(ctx, nil, url, req, wantStatus( | ||||
| 		http.StatusOK,       // updates and deletes
 | ||||
| 		http.StatusCreated,  // new account creation
 | ||||
| 		http.StatusAccepted, // Let's Encrypt divergent implementation
 | ||||
|  | @ -714,12 +858,16 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun | |||
| } | ||||
| 
 | ||||
| // popNonce returns a nonce value previously stored with c.addNonce
 | ||||
| // or fetches a fresh one from a URL by issuing a HEAD request.
 | ||||
| // It first tries c.directoryURL() and then the provided url if the former fails.
 | ||||
| // or fetches a fresh one from c.dir.NonceURL.
 | ||||
| // If NonceURL is empty, it first tries c.directoryURL() and, failing that,
 | ||||
| // the provided url.
 | ||||
| func (c *Client) popNonce(ctx context.Context, url string) (string, error) { | ||||
| 	c.noncesMu.Lock() | ||||
| 	defer c.noncesMu.Unlock() | ||||
| 	if len(c.nonces) == 0 { | ||||
| 		if c.dir != nil && c.dir.NonceURL != "" { | ||||
| 			return c.fetchNonce(ctx, c.dir.NonceURL) | ||||
| 		} | ||||
| 		dirURL := c.directoryURL() | ||||
| 		v, err := c.fetchNonce(ctx, dirURL) | ||||
| 		if err != nil && url != dirURL { | ||||
|  |  | |||
|  | @ -32,8 +32,12 @@ import ( | |||
| 	"time" | ||||
| 
 | ||||
| 	"golang.org/x/crypto/acme" | ||||
| 	"golang.org/x/net/idna" | ||||
| ) | ||||
| 
 | ||||
| // DefaultACMEDirectory is the default ACME Directory URL used when the Manager's Client is nil.
 | ||||
| const DefaultACMEDirectory = "https://acme-v02.api.letsencrypt.org/directory" | ||||
| 
 | ||||
| // createCertRetryAfter is how much time to wait before removing a failed state
 | ||||
| // entry due to an unsuccessful createCert call.
 | ||||
| // This is a variable instead of a const for testing.
 | ||||
|  | @ -62,10 +66,16 @@ type HostPolicy func(ctx context.Context, host string) error | |||
| // HostWhitelist returns a policy where only the specified host names are allowed.
 | ||||
| // Only exact matches are currently supported. Subdomains, regexp or wildcard
 | ||||
| // will not match.
 | ||||
| //
 | ||||
| // Note that all hosts will be converted to Punycode via idna.Lookup.ToASCII so that
 | ||||
| // Manager.GetCertificate can handle the Unicode IDN and mixedcase hosts correctly.
 | ||||
| // Invalid hosts will be silently ignored.
 | ||||
| func HostWhitelist(hosts ...string) HostPolicy { | ||||
| 	whitelist := make(map[string]bool, len(hosts)) | ||||
| 	for _, h := range hosts { | ||||
| 		whitelist[h] = true | ||||
| 		if h, err := idna.Lookup.ToASCII(h); err == nil { | ||||
| 			whitelist[h] = true | ||||
| 		} | ||||
| 	} | ||||
| 	return func(_ context.Context, host string) error { | ||||
| 		if !whitelist[host] { | ||||
|  | @ -81,9 +91,9 @@ func defaultHostPolicy(context.Context, string) error { | |||
| } | ||||
| 
 | ||||
| // Manager is a stateful certificate manager built on top of acme.Client.
 | ||||
| // It obtains and refreshes certificates automatically using "tls-alpn-01",
 | ||||
| // "tls-sni-01", "tls-sni-02" and "http-01" challenge types,
 | ||||
| // as well as providing them to a TLS server via tls.Config.
 | ||||
| // It obtains and refreshes certificates automatically using "tls-alpn-01"
 | ||||
| // or "http-01" challenge types, as well as providing them to a TLS server
 | ||||
| // via tls.Config.
 | ||||
| //
 | ||||
| // You must specify a cache implementation, such as DirCache,
 | ||||
| // to reuse obtained certificates across program restarts.
 | ||||
|  | @ -128,9 +138,10 @@ type Manager struct { | |||
| 	// Client is used to perform low-level operations, such as account registration
 | ||||
| 	// and requesting new certificates.
 | ||||
| 	//
 | ||||
| 	// If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL
 | ||||
| 	// as directory endpoint. If the Client.Key is nil, a new ECDSA P-256 key is
 | ||||
| 	// generated and, if Cache is not nil, stored in cache.
 | ||||
| 	// If Client is nil, a zero-value acme.Client is used with DefaultACMEDirectory
 | ||||
| 	// as the directory endpoint.
 | ||||
| 	// If the Client.Key is nil, a new ECDSA P-256 key is generated and,
 | ||||
| 	// if Cache is not nil, stored in cache.
 | ||||
| 	//
 | ||||
| 	// Mutating the field after the first call of GetCertificate method will have no effect.
 | ||||
| 	Client *acme.Client | ||||
|  | @ -167,8 +178,8 @@ type Manager struct { | |||
| 	renewalMu sync.Mutex | ||||
| 	renewal   map[certKey]*domainRenewal | ||||
| 
 | ||||
| 	// tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens.
 | ||||
| 	tokensMu sync.RWMutex | ||||
| 	// challengeMu guards tryHTTP01, certTokens and httpTokens.
 | ||||
| 	challengeMu sync.RWMutex | ||||
| 	// tryHTTP01 indicates whether the Manager should try "http-01" challenge type
 | ||||
| 	// during the authorization flow.
 | ||||
| 	tryHTTP01 bool | ||||
|  | @ -177,12 +188,11 @@ type Manager struct { | |||
| 	// to be provisioned.
 | ||||
| 	// The entries are stored for the duration of the authorization flow.
 | ||||
| 	httpTokens map[string][]byte | ||||
| 	// certTokens contains temporary certificates for tls-sni and tls-alpn challenges
 | ||||
| 	// and is keyed by token domain name, which matches server name of ClientHello.
 | ||||
| 	// Keys always have ".acme.invalid" suffix for tls-sni. Otherwise, they are domain names
 | ||||
| 	// for tls-alpn.
 | ||||
| 	// certTokens contains temporary certificates for tls-alpn-01 challenges
 | ||||
| 	// and is keyed by the domain name which matches the ClientHello server name.
 | ||||
| 	// The entries are stored for the duration of the authorization flow.
 | ||||
| 	certTokens map[string]*tls.Certificate | ||||
| 
 | ||||
| 	// nowFunc, if not nil, returns the current time. This may be set for
 | ||||
| 	// testing purposes.
 | ||||
| 	nowFunc func() time.Time | ||||
|  | @ -219,7 +229,7 @@ func (m *Manager) TLSConfig() *tls.Config { | |||
| 
 | ||||
| // GetCertificate implements the tls.Config.GetCertificate hook.
 | ||||
| // It provides a TLS certificate for hello.ServerName host, including answering
 | ||||
| // tls-alpn-01 and *.acme.invalid (tls-sni-01 and tls-sni-02) challenges.
 | ||||
| // tls-alpn-01 challenges.
 | ||||
| // All other fields of hello are ignored.
 | ||||
| //
 | ||||
| // If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting
 | ||||
|  | @ -228,9 +238,7 @@ func (m *Manager) TLSConfig() *tls.Config { | |||
| // This does not affect cached certs. See HostPolicy field description for more details.
 | ||||
| //
 | ||||
| // If GetCertificate is used directly, instead of via Manager.TLSConfig, package users will
 | ||||
| // also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler
 | ||||
| // for http-01. (The tls-sni-* challenges have been deprecated by popular ACME providers
 | ||||
| // due to security issues in the ecosystem.)
 | ||||
| // also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler for http-01.
 | ||||
| func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { | ||||
| 	if m.Prompt == nil { | ||||
| 		return nil, errors.New("acme/autocert: Manager.Prompt not set") | ||||
|  | @ -243,7 +251,17 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, | |||
| 	if !strings.Contains(strings.Trim(name, "."), ".") { | ||||
| 		return nil, errors.New("acme/autocert: server name component count invalid") | ||||
| 	} | ||||
| 	if strings.ContainsAny(name, `+/\`) { | ||||
| 
 | ||||
| 	// Note that this conversion is necessary because some server names in the handshakes
 | ||||
| 	// started by some clients (such as cURL) are not converted to Punycode, which will
 | ||||
| 	// prevent us from obtaining certificates for them. In addition, we should also treat
 | ||||
| 	// example.com and EXAMPLE.COM as equivalent and return the same certificate for them.
 | ||||
| 	// Fortunately, this conversion also helped us deal with this kind of mixedcase problems.
 | ||||
| 	//
 | ||||
| 	// Due to the "σςΣ" problem (see https://unicode.org/faq/idn.html#22), we can't use
 | ||||
| 	// idna.Punycode.ToASCII (or just idna.ToASCII) here.
 | ||||
| 	name, err := idna.Lookup.ToASCII(name) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.New("acme/autocert: server name contains invalid character") | ||||
| 	} | ||||
| 
 | ||||
|  | @ -252,13 +270,10 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, | |||
| 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) | ||||
| 	defer cancel() | ||||
| 
 | ||||
| 	// Check whether this is a token cert requested for TLS-SNI or TLS-ALPN challenge.
 | ||||
| 	// Check whether this is a token cert requested for TLS-ALPN challenge.
 | ||||
| 	if wantsTokenCert(hello) { | ||||
| 		m.tokensMu.RLock() | ||||
| 		defer m.tokensMu.RUnlock() | ||||
| 		// It's ok to use the same token cert key for both tls-sni and tls-alpn
 | ||||
| 		// because there's always at most 1 token cert per on-going domain authorization.
 | ||||
| 		// See m.verify for details.
 | ||||
| 		m.challengeMu.RLock() | ||||
| 		defer m.challengeMu.RUnlock() | ||||
| 		if cert := m.certTokens[name]; cert != nil { | ||||
| 			return cert, nil | ||||
| 		} | ||||
|  | @ -301,8 +316,7 @@ func wantsTokenCert(hello *tls.ClientHelloInfo) bool { | |||
| 	if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto { | ||||
| 		return true | ||||
| 	} | ||||
| 	// tls-sni-xx
 | ||||
| 	return strings.HasSuffix(hello.ServerName, ".acme.invalid") | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func supportsECDSA(hello *tls.ClientHelloInfo) bool { | ||||
|  | @ -367,8 +381,8 @@ func supportsECDSA(hello *tls.ClientHelloInfo) bool { | |||
| // If HTTPHandler is never called, the Manager will only use the "tls-alpn-01"
 | ||||
| // challenge for domain verification.
 | ||||
| func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler { | ||||
| 	m.tokensMu.Lock() | ||||
| 	defer m.tokensMu.Unlock() | ||||
| 	m.challengeMu.Lock() | ||||
| 	defer m.challengeMu.Unlock() | ||||
| 	m.tryHTTP01 = true | ||||
| 
 | ||||
| 	if fallback == nil { | ||||
|  | @ -631,71 +645,64 @@ func (m *Manager) certState(ck certKey) (*certState, error) { | |||
| // authorizedCert starts the domain ownership verification process and requests a new cert upon success.
 | ||||
| // The key argument is the certificate private key.
 | ||||
| func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck certKey) (der [][]byte, leaf *x509.Certificate, err error) { | ||||
| 	client, err := m.acmeClient(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := m.verify(ctx, client, ck.domain); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	csr, err := certRequest(key, ck.domain, m.ExtraExtensions) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	der, _, err = client.CreateCert(ctx, csr, 0, true) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	leaf, err = validCert(ck, der, key, m.now()) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	return der, leaf, nil | ||||
| } | ||||
| 
 | ||||
| // revokePendingAuthz revokes all authorizations idenfied by the elements of uri slice.
 | ||||
| // It ignores revocation errors.
 | ||||
| func (m *Manager) revokePendingAuthz(ctx context.Context, uri []string) { | ||||
| 	client, err := m.acmeClient(ctx) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	for _, u := range uri { | ||||
| 		client.RevokeAuthorization(ctx, u) | ||||
| 	dir, err := client.Discover(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var chain [][]byte | ||||
| 	switch { | ||||
| 	// Pre-RFC legacy CA.
 | ||||
| 	case dir.OrderURL == "": | ||||
| 		if err := m.verify(ctx, client, ck.domain); err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| 		der, _, err := client.CreateCert(ctx, csr, 0, true) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| 		chain = der | ||||
| 	// RFC 8555 compliant CA.
 | ||||
| 	default: | ||||
| 		o, err := m.verifyRFC(ctx, client, ck.domain) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| 		der, _, err := client.CreateOrderCert(ctx, o.FinalizeURL, csr, true) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| 		chain = der | ||||
| 	} | ||||
| 	leaf, err = validCert(ck, chain, key, m.now()) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	return chain, leaf, nil | ||||
| } | ||||
| 
 | ||||
| // verify runs the identifier (domain) authorization flow
 | ||||
| // verify runs the identifier (domain) pre-authorization flow for legacy CAs
 | ||||
| // using each applicable ACME challenge type.
 | ||||
| func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error { | ||||
| 	// The list of challenge types we'll try to fulfill
 | ||||
| 	// in this specific order.
 | ||||
| 	challengeTypes := []string{"tls-alpn-01", "tls-sni-02", "tls-sni-01"} | ||||
| 	m.tokensMu.RLock() | ||||
| 	if m.tryHTTP01 { | ||||
| 		challengeTypes = append(challengeTypes, "http-01") | ||||
| 	} | ||||
| 	m.tokensMu.RUnlock() | ||||
| 
 | ||||
| 	// Keep track of pending authzs and revoke the ones that did not validate.
 | ||||
| 	pendingAuthzs := make(map[string]bool) | ||||
| 	// Remove all hanging authorizations to reduce rate limit quotas
 | ||||
| 	// after we're done.
 | ||||
| 	var authzURLs []string | ||||
| 	defer func() { | ||||
| 		var uri []string | ||||
| 		for k, pending := range pendingAuthzs { | ||||
| 			if pending { | ||||
| 				uri = append(uri, k) | ||||
| 			} | ||||
| 		} | ||||
| 		if len(uri) > 0 { | ||||
| 			// Use "detached" background context.
 | ||||
| 			// The revocations need not happen in the current verification flow.
 | ||||
| 			go m.revokePendingAuthz(context.Background(), uri) | ||||
| 		} | ||||
| 		go m.deactivatePendingAuthz(authzURLs) | ||||
| 	}() | ||||
| 
 | ||||
| 	// errs accumulates challenge failure errors, printed if all fail
 | ||||
| 	errs := make(map[*acme.Challenge]error) | ||||
| 	challengeTypes := m.supportedChallengeTypes() | ||||
| 	var nextTyp int // challengeType index of the next challenge type to try
 | ||||
| 	for { | ||||
| 		// Start domain authorization and get the challenge.
 | ||||
|  | @ -703,6 +710,7 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string | |||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		authzURLs = append(authzURLs, authz.URI) | ||||
| 		// No point in accepting challenges if the authorization status
 | ||||
| 		// is in a final state.
 | ||||
| 		switch authz.Status { | ||||
|  | @ -712,8 +720,6 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string | |||
| 			return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI) | ||||
| 		} | ||||
| 
 | ||||
| 		pendingAuthzs[authz.URI] = true | ||||
| 
 | ||||
| 		// Pick the next preferred challenge.
 | ||||
| 		var chal *acme.Challenge | ||||
| 		for chal == nil && nextTyp < len(challengeTypes) { | ||||
|  | @ -743,11 +749,126 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string | |||
| 			errs[chal] = err | ||||
| 			continue | ||||
| 		} | ||||
| 		delete(pendingAuthzs, authz.URI) | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // verifyRFC runs the identifier (domain) order-based authorization flow for RFC compliant CAs
 | ||||
| // using each applicable ACME challenge type.
 | ||||
| func (m *Manager) verifyRFC(ctx context.Context, client *acme.Client, domain string) (*acme.Order, error) { | ||||
| 	// Try each supported challenge type starting with a new order each time.
 | ||||
| 	// The nextTyp index of the next challenge type to try is shared across
 | ||||
| 	// all order authorizations: if we've tried a challenge type once and it didn't work,
 | ||||
| 	// it will most likely not work on another order's authorization either.
 | ||||
| 	challengeTypes := m.supportedChallengeTypes() | ||||
| 	nextTyp := 0 // challengeTypes index
 | ||||
| AuthorizeOrderLoop: | ||||
| 	for { | ||||
| 		o, err := client.AuthorizeOrder(ctx, acme.DomainIDs(domain)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		// Remove all hanging authorizations to reduce rate limit quotas
 | ||||
| 		// after we're done.
 | ||||
| 		defer func(urls []string) { | ||||
| 			go m.deactivatePendingAuthz(urls) | ||||
| 		}(o.AuthzURLs) | ||||
| 
 | ||||
| 		// Check if there's actually anything we need to do.
 | ||||
| 		switch o.Status { | ||||
| 		case acme.StatusReady: | ||||
| 			// Already authorized.
 | ||||
| 			return o, nil | ||||
| 		case acme.StatusPending: | ||||
| 			// Continue normal Order-based flow.
 | ||||
| 		default: | ||||
| 			return nil, fmt.Errorf("acme/autocert: invalid new order status %q; order URL: %q", o.Status, o.URI) | ||||
| 		} | ||||
| 
 | ||||
| 		// Satisfy all pending authorizations.
 | ||||
| 		for _, zurl := range o.AuthzURLs { | ||||
| 			z, err := client.GetAuthorization(ctx, zurl) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			if z.Status != acme.StatusPending { | ||||
| 				// We are interested only in pending authorizations.
 | ||||
| 				continue | ||||
| 			} | ||||
| 			// Pick the next preferred challenge.
 | ||||
| 			var chal *acme.Challenge | ||||
| 			for chal == nil && nextTyp < len(challengeTypes) { | ||||
| 				chal = pickChallenge(challengeTypes[nextTyp], z.Challenges) | ||||
| 				nextTyp++ | ||||
| 			} | ||||
| 			if chal == nil { | ||||
| 				return nil, fmt.Errorf("acme/autocert: unable to satisfy %q for domain %q: no viable challenge type found", z.URI, domain) | ||||
| 			} | ||||
| 			// Respond to the challenge and wait for validation result.
 | ||||
| 			cleanup, err := m.fulfill(ctx, client, chal, domain) | ||||
| 			if err != nil { | ||||
| 				continue AuthorizeOrderLoop | ||||
| 			} | ||||
| 			defer cleanup() | ||||
| 			if _, err := client.Accept(ctx, chal); err != nil { | ||||
| 				continue AuthorizeOrderLoop | ||||
| 			} | ||||
| 			if _, err := client.WaitAuthorization(ctx, z.URI); err != nil { | ||||
| 				continue AuthorizeOrderLoop | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// All authorizations are satisfied.
 | ||||
| 		// Wait for the CA to update the order status.
 | ||||
| 		o, err = client.WaitOrder(ctx, o.URI) | ||||
| 		if err != nil { | ||||
| 			continue AuthorizeOrderLoop | ||||
| 		} | ||||
| 		return o, nil | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge { | ||||
| 	for _, c := range chal { | ||||
| 		if c.Type == typ { | ||||
| 			return c | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (m *Manager) supportedChallengeTypes() []string { | ||||
| 	m.challengeMu.RLock() | ||||
| 	defer m.challengeMu.RUnlock() | ||||
| 	typ := []string{"tls-alpn-01"} | ||||
| 	if m.tryHTTP01 { | ||||
| 		typ = append(typ, "http-01") | ||||
| 	} | ||||
| 	return typ | ||||
| } | ||||
| 
 | ||||
| // deactivatePendingAuthz relinquishes all authorizations identified by the elements
 | ||||
| // of the provided uri slice which are in "pending" state.
 | ||||
| // It ignores revocation errors.
 | ||||
| //
 | ||||
| // deactivatePendingAuthz takes no context argument and instead runs with its own
 | ||||
| // "detached" context because deactivations are done in a goroutine separate from
 | ||||
| // that of the main issuance or renewal flow.
 | ||||
| func (m *Manager) deactivatePendingAuthz(uri []string) { | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) | ||||
| 	defer cancel() | ||||
| 	client, err := m.acmeClient(ctx) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	for _, u := range uri { | ||||
| 		z, err := client.GetAuthorization(ctx, u) | ||||
| 		if err == nil && z.Status == acme.StatusPending { | ||||
| 			client.RevokeAuthorization(ctx, u) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // fulfill provisions a response to the challenge chal.
 | ||||
| // The cleanup is non-nil only if provisioning succeeded.
 | ||||
| func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge, domain string) (cleanup func(), err error) { | ||||
|  | @ -759,20 +880,6 @@ func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.C | |||
| 		} | ||||
| 		m.putCertToken(ctx, domain, &cert) | ||||
| 		return func() { go m.deleteCertToken(domain) }, nil | ||||
| 	case "tls-sni-01": | ||||
| 		cert, name, err := client.TLSSNI01ChallengeCert(chal.Token) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		m.putCertToken(ctx, name, &cert) | ||||
| 		return func() { go m.deleteCertToken(name) }, nil | ||||
| 	case "tls-sni-02": | ||||
| 		cert, name, err := client.TLSSNI02ChallengeCert(chal.Token) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		m.putCertToken(ctx, name, &cert) | ||||
| 		return func() { go m.deleteCertToken(name) }, nil | ||||
| 	case "http-01": | ||||
| 		resp, err := client.HTTP01ChallengeResponse(chal.Token) | ||||
| 		if err != nil { | ||||
|  | @ -785,20 +892,11 @@ func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.C | |||
| 	return nil, fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type) | ||||
| } | ||||
| 
 | ||||
| func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge { | ||||
| 	for _, c := range chal { | ||||
| 		if c.Type == typ { | ||||
| 			return c | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // putCertToken stores the token certificate with the specified name
 | ||||
| // in both m.certTokens map and m.Cache.
 | ||||
| func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certificate) { | ||||
| 	m.tokensMu.Lock() | ||||
| 	defer m.tokensMu.Unlock() | ||||
| 	m.challengeMu.Lock() | ||||
| 	defer m.challengeMu.Unlock() | ||||
| 	if m.certTokens == nil { | ||||
| 		m.certTokens = make(map[string]*tls.Certificate) | ||||
| 	} | ||||
|  | @ -809,8 +907,8 @@ func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certi | |||
| // deleteCertToken removes the token certificate with the specified name
 | ||||
| // from both m.certTokens map and m.Cache.
 | ||||
| func (m *Manager) deleteCertToken(name string) { | ||||
| 	m.tokensMu.Lock() | ||||
| 	defer m.tokensMu.Unlock() | ||||
| 	m.challengeMu.Lock() | ||||
| 	defer m.challengeMu.Unlock() | ||||
| 	delete(m.certTokens, name) | ||||
| 	if m.Cache != nil { | ||||
| 		ck := certKey{domain: name, isToken: true} | ||||
|  | @ -821,8 +919,8 @@ func (m *Manager) deleteCertToken(name string) { | |||
| // httpToken retrieves an existing http-01 token value from an in-memory map
 | ||||
| // or the optional cache.
 | ||||
| func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, error) { | ||||
| 	m.tokensMu.RLock() | ||||
| 	defer m.tokensMu.RUnlock() | ||||
| 	m.challengeMu.RLock() | ||||
| 	defer m.challengeMu.RUnlock() | ||||
| 	if v, ok := m.httpTokens[tokenPath]; ok { | ||||
| 		return v, nil | ||||
| 	} | ||||
|  | @ -837,8 +935,8 @@ func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, erro | |||
| //
 | ||||
| // It ignores any error returned from Cache.Put.
 | ||||
| func (m *Manager) putHTTPToken(ctx context.Context, tokenPath, val string) { | ||||
| 	m.tokensMu.Lock() | ||||
| 	defer m.tokensMu.Unlock() | ||||
| 	m.challengeMu.Lock() | ||||
| 	defer m.challengeMu.Unlock() | ||||
| 	if m.httpTokens == nil { | ||||
| 		m.httpTokens = make(map[string][]byte) | ||||
| 	} | ||||
|  | @ -854,8 +952,8 @@ func (m *Manager) putHTTPToken(ctx context.Context, tokenPath, val string) { | |||
| //
 | ||||
| // If m.Cache is non-nil, it blocks until Cache.Delete returns without a timeout.
 | ||||
| func (m *Manager) deleteHTTPToken(tokenPath string) { | ||||
| 	m.tokensMu.Lock() | ||||
| 	defer m.tokensMu.Unlock() | ||||
| 	m.challengeMu.Lock() | ||||
| 	defer m.challengeMu.Unlock() | ||||
| 	delete(m.httpTokens, tokenPath) | ||||
| 	if m.Cache != nil { | ||||
| 		m.Cache.Delete(context.Background(), httpTokenCacheKey(tokenPath)) | ||||
|  | @ -954,7 +1052,7 @@ func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) { | |||
| 
 | ||||
| 	client := m.Client | ||||
| 	if client == nil { | ||||
| 		client = &acme.Client{DirectoryURL: acme.LetsEncryptURL} | ||||
| 		client = &acme.Client{DirectoryURL: DefaultACMEDirectory} | ||||
| 	} | ||||
| 	if client.Key == nil { | ||||
| 		var err error | ||||
|  | @ -963,20 +1061,32 @@ func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) { | |||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	if client.UserAgent == "" { | ||||
| 		client.UserAgent = "autocert" | ||||
| 	} | ||||
| 	var contact []string | ||||
| 	if m.Email != "" { | ||||
| 		contact = []string{"mailto:" + m.Email} | ||||
| 	} | ||||
| 	a := &acme.Account{Contact: contact} | ||||
| 	_, err := client.Register(ctx, a, m.Prompt) | ||||
| 	if ae, ok := err.(*acme.Error); err == nil || ok && ae.StatusCode == http.StatusConflict { | ||||
| 		// conflict indicates the key is already registered
 | ||||
| 	if err == nil || isAccountAlreadyExist(err) { | ||||
| 		m.client = client | ||||
| 		err = nil | ||||
| 	} | ||||
| 	return m.client, err | ||||
| } | ||||
| 
 | ||||
| // isAccountAlreadyExist reports whether the err, as returned from acme.Client.Register,
 | ||||
| // indicates the account has already been registered.
 | ||||
| func isAccountAlreadyExist(err error) bool { | ||||
| 	if err == acme.ErrAccountAlreadyExists { | ||||
| 		return true | ||||
| 	} | ||||
| 	ae, ok := err.(*acme.Error) | ||||
| 	return ok && ae.StatusCode == http.StatusConflict | ||||
| } | ||||
| 
 | ||||
| func (m *Manager) hostPolicy() HostPolicy { | ||||
| 	if m.HostPolicy != nil { | ||||
| 		return m.HostPolicy | ||||
|  |  | |||
|  | @ -77,6 +77,7 @@ func (d DirCache) Put(ctx context.Context, name string, data []byte) error { | |||
| 		if tmp, err = d.writeTempFile(name, data); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		defer os.Remove(tmp) | ||||
| 		select { | ||||
| 		case <-ctx.Done(): | ||||
| 			// Don't overwrite the file if the context was canceled.
 | ||||
|  | @ -116,12 +117,17 @@ func (d DirCache) Delete(ctx context.Context, name string) error { | |||
| } | ||||
| 
 | ||||
| // writeTempFile writes b to a temporary file, closes the file and returns its path.
 | ||||
| func (d DirCache) writeTempFile(prefix string, b []byte) (string, error) { | ||||
| func (d DirCache) writeTempFile(prefix string, b []byte) (name string, reterr error) { | ||||
| 	// TempFile uses 0600 permissions
 | ||||
| 	f, err := ioutil.TempFile(string(d), prefix) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	defer func() { | ||||
| 		if reterr != nil { | ||||
| 			os.Remove(f.Name()) | ||||
| 		} | ||||
| 	}() | ||||
| 	if _, err := f.Write(b); err != nil { | ||||
| 		f.Close() | ||||
| 		return "", err | ||||
|  |  | |||
|  | @ -155,8 +155,16 @@ func (c *Client) get(ctx context.Context, url string, ok resOkay) (*http.Respons | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // postAsGet is POST-as-GET, a replacement for GET in RFC8555
 | ||||
| // as described in https://tools.ietf.org/html/rfc8555#section-6.3.
 | ||||
| // It makes a POST request in KID form with zero JWS payload.
 | ||||
| // See nopayload doc comments in jws.go.
 | ||||
| func (c *Client) postAsGet(ctx context.Context, url string, ok resOkay) (*http.Response, error) { | ||||
| 	return c.post(ctx, nil, url, noPayload, ok) | ||||
| } | ||||
| 
 | ||||
| // post issues a signed POST request in JWS format using the provided key
 | ||||
| // to the specified URL.
 | ||||
| // to the specified URL. If key is nil, c.Key is used instead.
 | ||||
| // It returns a non-error value only when ok reports true.
 | ||||
| //
 | ||||
| // post retries unsuccessful attempts according to c.RetryBackoff
 | ||||
|  | @ -193,14 +201,28 @@ func (c *Client) post(ctx context.Context, key crypto.Signer, url string, body i | |||
| } | ||||
| 
 | ||||
| // postNoRetry signs the body with the given key and POSTs it to the provided url.
 | ||||
| // The body argument must be JSON-serializable.
 | ||||
| // It is used by c.post to retry unsuccessful attempts.
 | ||||
| // The body argument must be JSON-serializable.
 | ||||
| //
 | ||||
| // If key argument is nil, c.Key is used to sign the request.
 | ||||
| // If key argument is nil and c.accountKID returns a non-zero keyID,
 | ||||
| // the request is sent in KID form. Otherwise, JWK form is used.
 | ||||
| //
 | ||||
| // In practice, when interfacing with RFC-compliant CAs most requests are sent in KID form
 | ||||
| // and JWK is used only when KID is unavailable: new account endpoint and certificate
 | ||||
| // revocation requests authenticated by a cert key.
 | ||||
| // See jwsEncodeJSON for other details.
 | ||||
| func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, *http.Request, error) { | ||||
| 	kid := noKeyID | ||||
| 	if key == nil { | ||||
| 		key = c.Key | ||||
| 		kid = c.accountKID(ctx) | ||||
| 	} | ||||
| 	nonce, err := c.popNonce(ctx, url) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	b, err := jwsEncodeJSON(body, key, nonce) | ||||
| 	b, err := jwsEncodeJSON(body, key, kid, nonce, url) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | @ -219,6 +241,7 @@ func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, | |||
| 
 | ||||
| // doNoRetry issues a request req, replacing its context (if any) with ctx.
 | ||||
| func (c *Client) doNoRetry(ctx context.Context, req *http.Request) (*http.Response, error) { | ||||
| 	req.Header.Set("User-Agent", c.userAgent()) | ||||
| 	res, err := c.httpClient().Do(req.WithContext(ctx)) | ||||
| 	if err != nil { | ||||
| 		select { | ||||
|  | @ -243,6 +266,23 @@ func (c *Client) httpClient() *http.Client { | |||
| 	return http.DefaultClient | ||||
| } | ||||
| 
 | ||||
| // packageVersion is the version of the module that contains this package, for
 | ||||
| // sending as part of the User-Agent header. It's set in version_go112.go.
 | ||||
| var packageVersion string | ||||
| 
 | ||||
| // userAgent returns the User-Agent header value. It includes the package name,
 | ||||
| // the module version (if available), and the c.UserAgent value (if set).
 | ||||
| func (c *Client) userAgent() string { | ||||
| 	ua := "golang.org/x/crypto/acme" | ||||
| 	if packageVersion != "" { | ||||
| 		ua += "@" + packageVersion | ||||
| 	} | ||||
| 	if c.UserAgent != "" { | ||||
| 		ua = c.UserAgent + " " + ua | ||||
| 	} | ||||
| 	return ua | ||||
| } | ||||
| 
 | ||||
| // isBadNonce reports whether err is an ACME "badnonce" error.
 | ||||
| func isBadNonce(err error) bool { | ||||
| 	// According to the spec badNonce is urn:ietf:params:acme:error:badNonce.
 | ||||
|  |  | |||
|  | @ -11,31 +11,60 @@ import ( | |||
| 	"crypto/rsa" | ||||
| 	"crypto/sha256" | ||||
| 	_ "crypto/sha512" // need for EC keys
 | ||||
| 	"encoding/asn1" | ||||
| 	"encoding/base64" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"math/big" | ||||
| ) | ||||
| 
 | ||||
| // keyID is the account identity provided by a CA during registration.
 | ||||
| type keyID string | ||||
| 
 | ||||
| // noKeyID indicates that jwsEncodeJSON should compute and use JWK instead of a KID.
 | ||||
| // See jwsEncodeJSON for details.
 | ||||
| const noKeyID = keyID("") | ||||
| 
 | ||||
| // noPayload indicates jwsEncodeJSON will encode zero-length octet string
 | ||||
| // in a JWS request. This is called POST-as-GET in RFC 8555 and is used to make
 | ||||
| // authenticated GET requests via POSTing with an empty payload.
 | ||||
| // See https://tools.ietf.org/html/rfc8555#section-6.3 for more details.
 | ||||
| const noPayload = "" | ||||
| 
 | ||||
| // jwsEncodeJSON signs claimset using provided key and a nonce.
 | ||||
| // The result is serialized in JSON format.
 | ||||
| // The result is serialized in JSON format containing either kid or jwk
 | ||||
| // fields based on the provided keyID value.
 | ||||
| //
 | ||||
| // If kid is non-empty, its quoted value is inserted in the protected head
 | ||||
| // as "kid" field value. Otherwise, JWK is computed using jwkEncode and inserted
 | ||||
| // as "jwk" field value. The "jwk" and "kid" fields are mutually exclusive.
 | ||||
| //
 | ||||
| // See https://tools.ietf.org/html/rfc7515#section-7.
 | ||||
| func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) { | ||||
| 	jwk, err := jwkEncode(key.Public()) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid keyID, nonce, url string) ([]byte, error) { | ||||
| 	alg, sha := jwsHasher(key.Public()) | ||||
| 	if alg == "" || !sha.Available() { | ||||
| 		return nil, ErrUnsupportedKey | ||||
| 	} | ||||
| 	phead := fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q}`, alg, jwk, nonce) | ||||
| 	phead = base64.RawURLEncoding.EncodeToString([]byte(phead)) | ||||
| 	cs, err := json.Marshal(claimset) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	var phead string | ||||
| 	switch kid { | ||||
| 	case noKeyID: | ||||
| 		jwk, err := jwkEncode(key.Public()) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		phead = fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q,"url":%q}`, alg, jwk, nonce, url) | ||||
| 	default: | ||||
| 		phead = fmt.Sprintf(`{"alg":%q,"kid":%q,"nonce":%q,"url":%q}`, alg, kid, nonce, url) | ||||
| 	} | ||||
| 	phead = base64.RawURLEncoding.EncodeToString([]byte(phead)) | ||||
| 	var payload string | ||||
| 	if claimset != noPayload { | ||||
| 		cs, err := json.Marshal(claimset) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		payload = base64.RawURLEncoding.EncodeToString(cs) | ||||
| 	} | ||||
| 	payload := base64.RawURLEncoding.EncodeToString(cs) | ||||
| 	hash := sha.New() | ||||
| 	hash.Write([]byte(phead + "." + payload)) | ||||
| 	sig, err := jwsSign(key, sha, hash.Sum(nil)) | ||||
|  | @ -98,21 +127,23 @@ func jwkEncode(pub crypto.PublicKey) (string, error) { | |||
| 
 | ||||
| // jwsSign signs the digest using the given key.
 | ||||
| // The hash is unused for ECDSA keys.
 | ||||
| //
 | ||||
| // Note: non-stdlib crypto.Signer implementations are expected to return
 | ||||
| // the signature in the format as specified in RFC7518.
 | ||||
| // See https://tools.ietf.org/html/rfc7518 for more details.
 | ||||
| func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) { | ||||
| 	if key, ok := key.(*ecdsa.PrivateKey); ok { | ||||
| 		// The key.Sign method of ecdsa returns ASN1-encoded signature.
 | ||||
| 		// So, we use the package Sign function instead
 | ||||
| 		// to get R and S values directly and format the result accordingly.
 | ||||
| 		r, s, err := ecdsa.Sign(rand.Reader, key, digest) | ||||
| 	switch pub := key.Public().(type) { | ||||
| 	case *rsa.PublicKey: | ||||
| 		return key.Sign(rand.Reader, digest, hash) | ||||
| 	case *ecdsa.PublicKey: | ||||
| 		sigASN1, err := key.Sign(rand.Reader, digest, hash) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		rb, sb := r.Bytes(), s.Bytes() | ||||
| 		size := key.Params().BitSize / 8 | ||||
| 
 | ||||
| 		var rs struct{ R, S *big.Int } | ||||
| 		if _, err := asn1.Unmarshal(sigASN1, &rs); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 		rb, sb := rs.R.Bytes(), rs.S.Bytes() | ||||
| 		size := pub.Params().BitSize / 8 | ||||
| 		if size%8 > 0 { | ||||
| 			size++ | ||||
| 		} | ||||
|  | @ -121,7 +152,7 @@ func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) | |||
| 		copy(sig[size*2-len(sb):], sb) | ||||
| 		return sig, nil | ||||
| 	} | ||||
| 	return key.Sign(rand.Reader, digest, hash) | ||||
| 	return nil, ErrUnsupportedKey | ||||
| } | ||||
| 
 | ||||
| // jwsHasher indicates suitable JWS algorithm name and a hash function
 | ||||
|  |  | |||
|  | @ -0,0 +1,392 @@ | |||
| // Copyright 2019 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package acme | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto" | ||||
| 	"encoding/base64" | ||||
| 	"encoding/json" | ||||
| 	"encoding/pem" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| // DeactivateReg permanently disables an existing account associated with c.Key.
 | ||||
| // A deactivated account can no longer request certificate issuance or access
 | ||||
| // resources related to the account, such as orders or authorizations.
 | ||||
| //
 | ||||
| // It only works with CAs implementing RFC 8555.
 | ||||
| func (c *Client) DeactivateReg(ctx context.Context) error { | ||||
| 	url := string(c.accountKID(ctx)) | ||||
| 	if url == "" { | ||||
| 		return ErrNoAccount | ||||
| 	} | ||||
| 	req := json.RawMessage(`{"status": "deactivated"}`) | ||||
| 	res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	res.Body.Close() | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // registerRFC is quivalent to c.Register but for CAs implementing RFC 8555.
 | ||||
| // It expects c.Discover to have already been called.
 | ||||
| // TODO: Implement externalAccountBinding.
 | ||||
| func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) { | ||||
| 	c.cacheMu.Lock() // guard c.kid access
 | ||||
| 	defer c.cacheMu.Unlock() | ||||
| 
 | ||||
| 	req := struct { | ||||
| 		TermsAgreed bool     `json:"termsOfServiceAgreed,omitempty"` | ||||
| 		Contact     []string `json:"contact,omitempty"` | ||||
| 	}{ | ||||
| 		Contact: acct.Contact, | ||||
| 	} | ||||
| 	if c.dir.Terms != "" { | ||||
| 		req.TermsAgreed = prompt(c.dir.Terms) | ||||
| 	} | ||||
| 	res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus( | ||||
| 		http.StatusOK,      // account with this key already registered
 | ||||
| 		http.StatusCreated, // new account created
 | ||||
| 	)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	defer res.Body.Close() | ||||
| 	a, err := responseAccount(res) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	// Cache Account URL even if we return an error to the caller.
 | ||||
| 	// It is by all means a valid and usable "kid" value for future requests.
 | ||||
| 	c.kid = keyID(a.URI) | ||||
| 	if res.StatusCode == http.StatusOK { | ||||
| 		return nil, ErrAccountAlreadyExists | ||||
| 	} | ||||
| 	return a, nil | ||||
| } | ||||
| 
 | ||||
| // updateGegRFC is equivalent to c.UpdateReg but for CAs implementing RFC 8555.
 | ||||
| // It expects c.Discover to have already been called.
 | ||||
| func (c *Client) updateRegRFC(ctx context.Context, a *Account) (*Account, error) { | ||||
| 	url := string(c.accountKID(ctx)) | ||||
| 	if url == "" { | ||||
| 		return nil, ErrNoAccount | ||||
| 	} | ||||
| 	req := struct { | ||||
| 		Contact []string `json:"contact,omitempty"` | ||||
| 	}{ | ||||
| 		Contact: a.Contact, | ||||
| 	} | ||||
| 	res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer res.Body.Close() | ||||
| 	return responseAccount(res) | ||||
| } | ||||
| 
 | ||||
| // getGegRFC is equivalent to c.GetReg but for CAs implementing RFC 8555.
 | ||||
| // It expects c.Discover to have already been called.
 | ||||
| func (c *Client) getRegRFC(ctx context.Context) (*Account, error) { | ||||
| 	req := json.RawMessage(`{"onlyReturnExisting": true}`) | ||||
| 	res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(http.StatusOK)) | ||||
| 	if e, ok := err.(*Error); ok && e.ProblemType == "urn:ietf:params:acme:error:accountDoesNotExist" { | ||||
| 		return nil, ErrNoAccount | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	defer res.Body.Close() | ||||
| 	return responseAccount(res) | ||||
| } | ||||
| 
 | ||||
| func responseAccount(res *http.Response) (*Account, error) { | ||||
| 	var v struct { | ||||
| 		Status  string | ||||
| 		Contact []string | ||||
| 		Orders  string | ||||
| 	} | ||||
| 	if err := json.NewDecoder(res.Body).Decode(&v); err != nil { | ||||
| 		return nil, fmt.Errorf("acme: invalid account response: %v", err) | ||||
| 	} | ||||
| 	return &Account{ | ||||
| 		URI:       res.Header.Get("Location"), | ||||
| 		Status:    v.Status, | ||||
| 		Contact:   v.Contact, | ||||
| 		OrdersURL: v.Orders, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // AuthorizeOrder initiates the order-based application for certificate issuance,
 | ||||
| // as opposed to pre-authorization in Authorize.
 | ||||
| // It is only supported by CAs implementing RFC 8555.
 | ||||
| //
 | ||||
| // The caller then needs to fetch each authorization with GetAuthorization,
 | ||||
| // identify those with StatusPending status and fulfill a challenge using Accept.
 | ||||
| // Once all authorizations are satisfied, the caller will typically want to poll
 | ||||
| // order status using WaitOrder until it's in StatusReady state.
 | ||||
| // To finalize the order and obtain a certificate, the caller submits a CSR with CreateOrderCert.
 | ||||
| func (c *Client) AuthorizeOrder(ctx context.Context, id []AuthzID, opt ...OrderOption) (*Order, error) { | ||||
| 	dir, err := c.Discover(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	req := struct { | ||||
| 		Identifiers []wireAuthzID `json:"identifiers"` | ||||
| 		NotBefore   string        `json:"notBefore,omitempty"` | ||||
| 		NotAfter    string        `json:"notAfter,omitempty"` | ||||
| 	}{} | ||||
| 	for _, v := range id { | ||||
| 		req.Identifiers = append(req.Identifiers, wireAuthzID{ | ||||
| 			Type:  v.Type, | ||||
| 			Value: v.Value, | ||||
| 		}) | ||||
| 	} | ||||
| 	for _, o := range opt { | ||||
| 		switch o := o.(type) { | ||||
| 		case orderNotBeforeOpt: | ||||
| 			req.NotBefore = time.Time(o).Format(time.RFC3339) | ||||
| 		case orderNotAfterOpt: | ||||
| 			req.NotAfter = time.Time(o).Format(time.RFC3339) | ||||
| 		default: | ||||
| 			// Package's fault if we let this happen.
 | ||||
| 			panic(fmt.Sprintf("unsupported order option type %T", o)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	res, err := c.post(ctx, nil, dir.OrderURL, req, wantStatus(http.StatusCreated)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer res.Body.Close() | ||||
| 	return responseOrder(res) | ||||
| } | ||||
| 
 | ||||
| // GetOrder retrives an order identified by the given URL.
 | ||||
| // For orders created with AuthorizeOrder, the url value is Order.URI.
 | ||||
| //
 | ||||
| // If a caller needs to poll an order until its status is final,
 | ||||
| // see the WaitOrder method.
 | ||||
| func (c *Client) GetOrder(ctx context.Context, url string) (*Order, error) { | ||||
| 	if _, err := c.Discover(ctx); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer res.Body.Close() | ||||
| 	return responseOrder(res) | ||||
| } | ||||
| 
 | ||||
| // WaitOrder polls an order from the given URL until it is in one of the final states,
 | ||||
| // StatusReady, StatusValid or StatusInvalid, the CA responded with a non-retryable error
 | ||||
| // or the context is done.
 | ||||
| //
 | ||||
| // It returns a non-nil Order only if its Status is StatusReady or StatusValid.
 | ||||
| // In all other cases WaitOrder returns an error.
 | ||||
| // If the Status is StatusInvalid, the returned error is of type *OrderError.
 | ||||
| func (c *Client) WaitOrder(ctx context.Context, url string) (*Order, error) { | ||||
| 	if _, err := c.Discover(ctx); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for { | ||||
| 		res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		o, err := responseOrder(res) | ||||
| 		res.Body.Close() | ||||
| 		switch { | ||||
| 		case err != nil: | ||||
| 			// Skip and retry.
 | ||||
| 		case o.Status == StatusInvalid: | ||||
| 			return nil, &OrderError{OrderURL: o.URI, Status: o.Status} | ||||
| 		case o.Status == StatusReady || o.Status == StatusValid: | ||||
| 			return o, nil | ||||
| 		} | ||||
| 
 | ||||
| 		d := retryAfter(res.Header.Get("Retry-After")) | ||||
| 		if d == 0 { | ||||
| 			// Default retry-after.
 | ||||
| 			// Same reasoning as in WaitAuthorization.
 | ||||
| 			d = time.Second | ||||
| 		} | ||||
| 		t := time.NewTimer(d) | ||||
| 		select { | ||||
| 		case <-ctx.Done(): | ||||
| 			t.Stop() | ||||
| 			return nil, ctx.Err() | ||||
| 		case <-t.C: | ||||
| 			// Retry.
 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func responseOrder(res *http.Response) (*Order, error) { | ||||
| 	var v struct { | ||||
| 		Status         string | ||||
| 		Expires        time.Time | ||||
| 		Identifiers    []wireAuthzID | ||||
| 		NotBefore      time.Time | ||||
| 		NotAfter       time.Time | ||||
| 		Error          *wireError | ||||
| 		Authorizations []string | ||||
| 		Finalize       string | ||||
| 		Certificate    string | ||||
| 	} | ||||
| 	if err := json.NewDecoder(res.Body).Decode(&v); err != nil { | ||||
| 		return nil, fmt.Errorf("acme: error reading order: %v", err) | ||||
| 	} | ||||
| 	o := &Order{ | ||||
| 		URI:         res.Header.Get("Location"), | ||||
| 		Status:      v.Status, | ||||
| 		Expires:     v.Expires, | ||||
| 		NotBefore:   v.NotBefore, | ||||
| 		NotAfter:    v.NotAfter, | ||||
| 		AuthzURLs:   v.Authorizations, | ||||
| 		FinalizeURL: v.Finalize, | ||||
| 		CertURL:     v.Certificate, | ||||
| 	} | ||||
| 	for _, id := range v.Identifiers { | ||||
| 		o.Identifiers = append(o.Identifiers, AuthzID{Type: id.Type, Value: id.Value}) | ||||
| 	} | ||||
| 	if v.Error != nil { | ||||
| 		o.Error = v.Error.error(nil /* headers */) | ||||
| 	} | ||||
| 	return o, nil | ||||
| } | ||||
| 
 | ||||
| // CreateOrderCert submits the CSR (Certificate Signing Request) to a CA at the specified URL.
 | ||||
| // The URL is the FinalizeURL field of an Order created with AuthorizeOrder.
 | ||||
| //
 | ||||
| // If the bundle argument is true, the returned value also contain the CA (issuer)
 | ||||
| // certificate chain. Otherwise, only a leaf certificate is returned.
 | ||||
| // The returned URL can be used to re-fetch the certificate using FetchCert.
 | ||||
| //
 | ||||
| // This method is only supported by CAs implementing RFC 8555. See CreateCert for pre-RFC CAs.
 | ||||
| //
 | ||||
| // CreateOrderCert returns an error if the CA's response is unreasonably large.
 | ||||
| // Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features.
 | ||||
| func (c *Client) CreateOrderCert(ctx context.Context, url string, csr []byte, bundle bool) (der [][]byte, certURL string, err error) { | ||||
| 	if _, err := c.Discover(ctx); err != nil { // required by c.accountKID
 | ||||
| 		return nil, "", err | ||||
| 	} | ||||
| 
 | ||||
| 	// RFC describes this as "finalize order" request.
 | ||||
| 	req := struct { | ||||
| 		CSR string `json:"csr"` | ||||
| 	}{ | ||||
| 		CSR: base64.RawURLEncoding.EncodeToString(csr), | ||||
| 	} | ||||
| 	res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK)) | ||||
| 	if err != nil { | ||||
| 		return nil, "", err | ||||
| 	} | ||||
| 	defer res.Body.Close() | ||||
| 	o, err := responseOrder(res) | ||||
| 	if err != nil { | ||||
| 		return nil, "", err | ||||
| 	} | ||||
| 
 | ||||
| 	// Wait for CA to issue the cert if they haven't.
 | ||||
| 	if o.Status != StatusValid { | ||||
| 		o, err = c.WaitOrder(ctx, o.URI) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, "", err | ||||
| 	} | ||||
| 	// The only acceptable status post finalize and WaitOrder is "valid".
 | ||||
| 	if o.Status != StatusValid { | ||||
| 		return nil, "", &OrderError{OrderURL: o.URI, Status: o.Status} | ||||
| 	} | ||||
| 	crt, err := c.fetchCertRFC(ctx, o.CertURL, bundle) | ||||
| 	return crt, o.CertURL, err | ||||
| } | ||||
| 
 | ||||
| // fetchCertRFC downloads issued certificate from the given URL.
 | ||||
| // It expects the CA to respond with PEM-encoded certificate chain.
 | ||||
| //
 | ||||
| // The URL argument is the CertURL field of Order.
 | ||||
| func (c *Client) fetchCertRFC(ctx context.Context, url string, bundle bool) ([][]byte, error) { | ||||
| 	res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer res.Body.Close() | ||||
| 
 | ||||
| 	// Get all the bytes up to a sane maximum.
 | ||||
| 	// Account very roughly for base64 overhead.
 | ||||
| 	const max = maxCertChainSize + maxCertChainSize/33 | ||||
| 	b, err := ioutil.ReadAll(io.LimitReader(res.Body, max+1)) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("acme: fetch cert response stream: %v", err) | ||||
| 	} | ||||
| 	if len(b) > max { | ||||
| 		return nil, errors.New("acme: certificate chain is too big") | ||||
| 	} | ||||
| 
 | ||||
| 	// Decode PEM chain.
 | ||||
| 	var chain [][]byte | ||||
| 	for { | ||||
| 		var p *pem.Block | ||||
| 		p, b = pem.Decode(b) | ||||
| 		if p == nil { | ||||
| 			break | ||||
| 		} | ||||
| 		if p.Type != "CERTIFICATE" { | ||||
| 			return nil, fmt.Errorf("acme: invalid PEM cert type %q", p.Type) | ||||
| 		} | ||||
| 
 | ||||
| 		chain = append(chain, p.Bytes) | ||||
| 		if !bundle { | ||||
| 			return chain, nil | ||||
| 		} | ||||
| 		if len(chain) > maxChainLen { | ||||
| 			return nil, errors.New("acme: certificate chain is too long") | ||||
| 		} | ||||
| 	} | ||||
| 	if len(chain) == 0 { | ||||
| 		return nil, errors.New("acme: certificate chain is empty") | ||||
| 	} | ||||
| 	return chain, nil | ||||
| } | ||||
| 
 | ||||
| // sends a cert revocation request in either JWK form when key is non-nil or KID form otherwise.
 | ||||
| func (c *Client) revokeCertRFC(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error { | ||||
| 	req := &struct { | ||||
| 		Cert   string `json:"certificate"` | ||||
| 		Reason int    `json:"reason"` | ||||
| 	}{ | ||||
| 		Cert:   base64.RawURLEncoding.EncodeToString(cert), | ||||
| 		Reason: int(reason), | ||||
| 	} | ||||
| 	res, err := c.post(ctx, key, c.dir.RevokeURL, req, wantStatus(http.StatusOK)) | ||||
| 	if err != nil { | ||||
| 		if isAlreadyRevoked(err) { | ||||
| 			// Assume it is not an error to revoke an already revoked cert.
 | ||||
| 			return nil | ||||
| 		} | ||||
| 		return err | ||||
| 	} | ||||
| 	defer res.Body.Close() | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func isAlreadyRevoked(err error) bool { | ||||
| 	e, ok := err.(*Error) | ||||
| 	return ok && e.ProblemType == "urn:ietf:params:acme:error:alreadyRevoked" | ||||
| } | ||||
|  | @ -14,14 +14,18 @@ import ( | |||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| // ACME server response statuses used to describe Authorization and Challenge states.
 | ||||
| // ACME status values of Account, Order, Authorization and Challenge objects.
 | ||||
| // See https://tools.ietf.org/html/rfc8555#section-7.1.6 for details.
 | ||||
| const ( | ||||
| 	StatusUnknown    = "unknown" | ||||
| 	StatusPending    = "pending" | ||||
| 	StatusProcessing = "processing" | ||||
| 	StatusValid      = "valid" | ||||
| 	StatusInvalid    = "invalid" | ||||
| 	StatusRevoked    = "revoked" | ||||
| 	StatusDeactivated = "deactivated" | ||||
| 	StatusExpired     = "expired" | ||||
| 	StatusInvalid     = "invalid" | ||||
| 	StatusPending     = "pending" | ||||
| 	StatusProcessing  = "processing" | ||||
| 	StatusReady       = "ready" | ||||
| 	StatusRevoked     = "revoked" | ||||
| 	StatusUnknown     = "unknown" | ||||
| 	StatusValid       = "valid" | ||||
| ) | ||||
| 
 | ||||
| // CRLReasonCode identifies the reason for a certificate revocation.
 | ||||
|  | @ -41,8 +45,17 @@ const ( | |||
| 	CRLReasonAACompromise         CRLReasonCode = 10 | ||||
| ) | ||||
| 
 | ||||
| // ErrUnsupportedKey is returned when an unsupported key type is encountered.
 | ||||
| var ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported") | ||||
| var ( | ||||
| 	// ErrUnsupportedKey is returned when an unsupported key type is encountered.
 | ||||
| 	ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported") | ||||
| 
 | ||||
| 	// ErrAccountAlreadyExists indicates that the Client's key has already been registered
 | ||||
| 	// with the CA. It is returned by Register method.
 | ||||
| 	ErrAccountAlreadyExists = errors.New("acme: account already exists") | ||||
| 
 | ||||
| 	// ErrNoAccount indicates that the Client's key has not been registered with the CA.
 | ||||
| 	ErrNoAccount = errors.New("acme: account does not exist") | ||||
| ) | ||||
| 
 | ||||
| // Error is an ACME error, defined in Problem Details for HTTP APIs doc
 | ||||
| // http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
 | ||||
|  | @ -54,6 +67,12 @@ type Error struct { | |||
| 	ProblemType string | ||||
| 	// Detail is a human-readable explanation specific to this occurrence of the problem.
 | ||||
| 	Detail string | ||||
| 	// Instance indicates a URL that the client should direct a human user to visit
 | ||||
| 	// in order for instructions on how to agree to the updated Terms of Service.
 | ||||
| 	// In such an event CA sets StatusCode to 403, ProblemType to
 | ||||
| 	// "urn:ietf:params:acme:error:userActionRequired" and a Link header with relation
 | ||||
| 	// "terms-of-service" containing the latest TOS URL.
 | ||||
| 	Instance string | ||||
| 	// Header is the original server error response headers.
 | ||||
| 	// It may be nil.
 | ||||
| 	Header http.Header | ||||
|  | @ -86,6 +105,21 @@ func (a *AuthorizationError) Error() string { | |||
| 	return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; ")) | ||||
| } | ||||
| 
 | ||||
| // OrderError is returned from Client's order related methods.
 | ||||
| // It indicates the order is unusable and the clients should start over with
 | ||||
| // AuthorizeOrder.
 | ||||
| //
 | ||||
| // The clients can still fetch the order object from CA using GetOrder
 | ||||
| // to inspect its state.
 | ||||
| type OrderError struct { | ||||
| 	OrderURL string | ||||
| 	Status   string | ||||
| } | ||||
| 
 | ||||
| func (oe *OrderError) Error() string { | ||||
| 	return fmt.Sprintf("acme: order %s status: %s", oe.OrderURL, oe.Status) | ||||
| } | ||||
| 
 | ||||
| // RateLimit reports whether err represents a rate limit error and
 | ||||
| // any Retry-After duration returned by the server.
 | ||||
| //
 | ||||
|  | @ -108,49 +142,88 @@ func RateLimit(err error) (time.Duration, bool) { | |||
| } | ||||
| 
 | ||||
| // Account is a user account. It is associated with a private key.
 | ||||
| // Non-RFC 8555 fields are empty when interfacing with a compliant CA.
 | ||||
| type Account struct { | ||||
| 	// URI is the account unique ID, which is also a URL used to retrieve
 | ||||
| 	// account data from the CA.
 | ||||
| 	// When interfacing with RFC 8555-compliant CAs, URI is the "kid" field
 | ||||
| 	// value in JWS signed requests.
 | ||||
| 	URI string | ||||
| 
 | ||||
| 	// Contact is a slice of contact info used during registration.
 | ||||
| 	// See https://tools.ietf.org/html/rfc8555#section-7.3 for supported
 | ||||
| 	// formats.
 | ||||
| 	Contact []string | ||||
| 
 | ||||
| 	// Status indicates current account status as returned by the CA.
 | ||||
| 	// Possible values are StatusValid, StatusDeactivated, and StatusRevoked.
 | ||||
| 	Status string | ||||
| 
 | ||||
| 	// OrdersURL is a URL from which a list of orders submitted by this account
 | ||||
| 	// can be fetched.
 | ||||
| 	OrdersURL string | ||||
| 
 | ||||
| 	// The terms user has agreed to.
 | ||||
| 	// A value not matching CurrentTerms indicates that the user hasn't agreed
 | ||||
| 	// to the actual Terms of Service of the CA.
 | ||||
| 	//
 | ||||
| 	// It is non-RFC 8555 compliant. Package users can store the ToS they agree to
 | ||||
| 	// during Client's Register call in the prompt callback function.
 | ||||
| 	AgreedTerms string | ||||
| 
 | ||||
| 	// Actual terms of a CA.
 | ||||
| 	//
 | ||||
| 	// It is non-RFC 8555 compliant. Use Directory's Terms field.
 | ||||
| 	// When a CA updates their terms and requires an account agreement,
 | ||||
| 	// a URL at which instructions to do so is available in Error's Instance field.
 | ||||
| 	CurrentTerms string | ||||
| 
 | ||||
| 	// Authz is the authorization URL used to initiate a new authz flow.
 | ||||
| 	//
 | ||||
| 	// It is non-RFC 8555 compliant. Use Directory's AuthzURL or OrderURL.
 | ||||
| 	Authz string | ||||
| 
 | ||||
| 	// Authorizations is a URI from which a list of authorizations
 | ||||
| 	// granted to this account can be fetched via a GET request.
 | ||||
| 	//
 | ||||
| 	// It is non-RFC 8555 compliant and is obsoleted by OrdersURL.
 | ||||
| 	Authorizations string | ||||
| 
 | ||||
| 	// Certificates is a URI from which a list of certificates
 | ||||
| 	// issued for this account can be fetched via a GET request.
 | ||||
| 	//
 | ||||
| 	// It is non-RFC 8555 compliant and is obsoleted by OrdersURL.
 | ||||
| 	Certificates string | ||||
| } | ||||
| 
 | ||||
| // Directory is ACME server discovery data.
 | ||||
| // See https://tools.ietf.org/html/rfc8555#section-7.1.1 for more details.
 | ||||
| type Directory struct { | ||||
| 	// RegURL is an account endpoint URL, allowing for creating new
 | ||||
| 	// and modifying existing accounts.
 | ||||
| 	// NonceURL indicates an endpoint where to fetch fresh nonce values from.
 | ||||
| 	NonceURL string | ||||
| 
 | ||||
| 	// RegURL is an account endpoint URL, allowing for creating new accounts.
 | ||||
| 	// Pre-RFC 8555 CAs also allow modifying existing accounts at this URL.
 | ||||
| 	RegURL string | ||||
| 
 | ||||
| 	// AuthzURL is used to initiate Identifier Authorization flow.
 | ||||
| 	// OrderURL is used to initiate the certificate issuance flow
 | ||||
| 	// as described in RFC 8555.
 | ||||
| 	OrderURL string | ||||
| 
 | ||||
| 	// AuthzURL is used to initiate identifier pre-authorization flow.
 | ||||
| 	// Empty string indicates the flow is unsupported by the CA.
 | ||||
| 	AuthzURL string | ||||
| 
 | ||||
| 	// CertURL is a new certificate issuance endpoint URL.
 | ||||
| 	// It is non-RFC 8555 compliant and is obsoleted by OrderURL.
 | ||||
| 	CertURL string | ||||
| 
 | ||||
| 	// RevokeURL is used to initiate a certificate revocation flow.
 | ||||
| 	RevokeURL string | ||||
| 
 | ||||
| 	// KeyChangeURL allows to perform account key rollover flow.
 | ||||
| 	KeyChangeURL string | ||||
| 
 | ||||
| 	// Term is a URI identifying the current terms of service.
 | ||||
| 	Terms string | ||||
| 
 | ||||
|  | @ -162,44 +235,126 @@ type Directory struct { | |||
| 	// recognises as referring to itself for the purposes of CAA record validation
 | ||||
| 	// as defined in RFC6844.
 | ||||
| 	CAA []string | ||||
| 
 | ||||
| 	// ExternalAccountRequired indicates that the CA requires for all account-related
 | ||||
| 	// requests to include external account binding information.
 | ||||
| 	ExternalAccountRequired bool | ||||
| } | ||||
| 
 | ||||
| // Challenge encodes a returned CA challenge.
 | ||||
| // Its Error field may be non-nil if the challenge is part of an Authorization
 | ||||
| // with StatusInvalid.
 | ||||
| type Challenge struct { | ||||
| 	// Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01".
 | ||||
| 	Type string | ||||
| // rfcCompliant reports whether the ACME server implements RFC 8555.
 | ||||
| // Note that some servers may have incomplete RFC implementation
 | ||||
| // even if the returned value is true.
 | ||||
| // If rfcCompliant reports false, the server most likely implements draft-02.
 | ||||
| func (d *Directory) rfcCompliant() bool { | ||||
| 	return d.OrderURL != "" | ||||
| } | ||||
| 
 | ||||
| 	// URI is where a challenge response can be posted to.
 | ||||
| // Order represents a client's request for a certificate.
 | ||||
| // It tracks the request flow progress through to issuance.
 | ||||
| type Order struct { | ||||
| 	// URI uniquely identifies an order.
 | ||||
| 	URI string | ||||
| 
 | ||||
| 	// Token is a random value that uniquely identifies the challenge.
 | ||||
| 	Token string | ||||
| 
 | ||||
| 	// Status identifies the status of this challenge.
 | ||||
| 	// Status represents the current status of the order.
 | ||||
| 	// It indicates which action the client should take.
 | ||||
| 	//
 | ||||
| 	// Possible values are StatusPending, StatusReady, StatusProcessing, StatusValid and StatusInvalid.
 | ||||
| 	// Pending means the CA does not believe that the client has fulfilled the requirements.
 | ||||
| 	// Ready indicates that the client has fulfilled all the requirements and can submit a CSR
 | ||||
| 	// to obtain a certificate. This is done with Client's CreateOrderCert.
 | ||||
| 	// Processing means the certificate is being issued.
 | ||||
| 	// Valid indicates the CA has issued the certificate. It can be downloaded
 | ||||
| 	// from the Order's CertURL. This is done with Client's FetchCert.
 | ||||
| 	// Invalid means the certificate will not be issued. Users should consider this order
 | ||||
| 	// abandoned.
 | ||||
| 	Status string | ||||
| 
 | ||||
| 	// Error indicates the reason for an authorization failure
 | ||||
| 	// when this challenge was used.
 | ||||
| 	// The type of a non-nil value is *Error.
 | ||||
| 	Error error | ||||
| 	// Expires is the timestamp after which CA considers this order invalid.
 | ||||
| 	Expires time.Time | ||||
| 
 | ||||
| 	// Identifiers contains all identifier objects which the order pertains to.
 | ||||
| 	Identifiers []AuthzID | ||||
| 
 | ||||
| 	// NotBefore is the requested value of the notBefore field in the certificate.
 | ||||
| 	NotBefore time.Time | ||||
| 
 | ||||
| 	// NotAfter is the requested value of the notAfter field in the certificate.
 | ||||
| 	NotAfter time.Time | ||||
| 
 | ||||
| 	// AuthzURLs represents authorizations to complete before a certificate
 | ||||
| 	// for identifiers specified in the order can be issued.
 | ||||
| 	// It also contains unexpired authorizations that the client has completed
 | ||||
| 	// in the past.
 | ||||
| 	//
 | ||||
| 	// Authorization objects can be fetched using Client's GetAuthorization method.
 | ||||
| 	//
 | ||||
| 	// The required authorizations are dictated by CA policies.
 | ||||
| 	// There may not be a 1:1 relationship between the identifiers and required authorizations.
 | ||||
| 	// Required authorizations can be identified by their StatusPending status.
 | ||||
| 	//
 | ||||
| 	// For orders in the StatusValid or StatusInvalid state these are the authorizations
 | ||||
| 	// which were completed.
 | ||||
| 	AuthzURLs []string | ||||
| 
 | ||||
| 	// FinalizeURL is the endpoint at which a CSR is submitted to obtain a certificate
 | ||||
| 	// once all the authorizations are satisfied.
 | ||||
| 	FinalizeURL string | ||||
| 
 | ||||
| 	// CertURL points to the certificate that has been issued in response to this order.
 | ||||
| 	CertURL string | ||||
| 
 | ||||
| 	// The error that occurred while processing the order as received from a CA, if any.
 | ||||
| 	Error *Error | ||||
| } | ||||
| 
 | ||||
| // OrderOption allows customizing Client.AuthorizeOrder call.
 | ||||
| type OrderOption interface { | ||||
| 	privateOrderOpt() | ||||
| } | ||||
| 
 | ||||
| // WithOrderNotBefore sets order's NotBefore field.
 | ||||
| func WithOrderNotBefore(t time.Time) OrderOption { | ||||
| 	return orderNotBeforeOpt(t) | ||||
| } | ||||
| 
 | ||||
| // WithOrderNotAfter sets order's NotAfter field.
 | ||||
| func WithOrderNotAfter(t time.Time) OrderOption { | ||||
| 	return orderNotAfterOpt(t) | ||||
| } | ||||
| 
 | ||||
| type orderNotBeforeOpt time.Time | ||||
| 
 | ||||
| func (orderNotBeforeOpt) privateOrderOpt() {} | ||||
| 
 | ||||
| type orderNotAfterOpt time.Time | ||||
| 
 | ||||
| func (orderNotAfterOpt) privateOrderOpt() {} | ||||
| 
 | ||||
| // Authorization encodes an authorization response.
 | ||||
| type Authorization struct { | ||||
| 	// URI uniquely identifies a authorization.
 | ||||
| 	URI string | ||||
| 
 | ||||
| 	// Status identifies the status of an authorization.
 | ||||
| 	// Status is the current status of an authorization.
 | ||||
| 	// Possible values are StatusPending, StatusValid, StatusInvalid, StatusDeactivated,
 | ||||
| 	// StatusExpired and StatusRevoked.
 | ||||
| 	Status string | ||||
| 
 | ||||
| 	// Identifier is what the account is authorized to represent.
 | ||||
| 	Identifier AuthzID | ||||
| 
 | ||||
| 	// The timestamp after which the CA considers the authorization invalid.
 | ||||
| 	Expires time.Time | ||||
| 
 | ||||
| 	// Wildcard is true for authorizations of a wildcard domain name.
 | ||||
| 	Wildcard bool | ||||
| 
 | ||||
| 	// Challenges that the client needs to fulfill in order to prove possession
 | ||||
| 	// of the identifier (for pending authorizations).
 | ||||
| 	// For final authorizations, the challenges that were used.
 | ||||
| 	// For valid authorizations, the challenge that was validated.
 | ||||
| 	// For invalid authorizations, the challenge that was attempted and failed.
 | ||||
| 	//
 | ||||
| 	// RFC 8555 compatible CAs require users to fuflfill only one of the challenges.
 | ||||
| 	Challenges []*Challenge | ||||
| 
 | ||||
| 	// A collection of sets of challenges, each of which would be sufficient
 | ||||
|  | @ -207,24 +362,51 @@ type Authorization struct { | |||
| 	// Clients must complete a set of challenges that covers at least one set.
 | ||||
| 	// Challenges are identified by their indices in the challenges array.
 | ||||
| 	// If this field is empty, the client needs to complete all challenges.
 | ||||
| 	//
 | ||||
| 	// This field is unused in RFC 8555.
 | ||||
| 	Combinations [][]int | ||||
| } | ||||
| 
 | ||||
| // AuthzID is an identifier that an account is authorized to represent.
 | ||||
| type AuthzID struct { | ||||
| 	Type  string // The type of identifier, e.g. "dns".
 | ||||
| 	Type  string // The type of identifier, "dns" or "ip".
 | ||||
| 	Value string // The identifier itself, e.g. "example.org".
 | ||||
| } | ||||
| 
 | ||||
| // DomainIDs creates a slice of AuthzID with "dns" identifier type.
 | ||||
| func DomainIDs(names ...string) []AuthzID { | ||||
| 	a := make([]AuthzID, len(names)) | ||||
| 	for i, v := range names { | ||||
| 		a[i] = AuthzID{Type: "dns", Value: v} | ||||
| 	} | ||||
| 	return a | ||||
| } | ||||
| 
 | ||||
| // IPIDs creates a slice of AuthzID with "ip" identifier type.
 | ||||
| // Each element of addr is textual form of an address as defined
 | ||||
| // in RFC1123 Section 2.1 for IPv4 and in RFC5952 Section 4 for IPv6.
 | ||||
| func IPIDs(addr ...string) []AuthzID { | ||||
| 	a := make([]AuthzID, len(addr)) | ||||
| 	for i, v := range addr { | ||||
| 		a[i] = AuthzID{Type: "ip", Value: v} | ||||
| 	} | ||||
| 	return a | ||||
| } | ||||
| 
 | ||||
| // wireAuthzID is ACME JSON representation of authorization identifier objects.
 | ||||
| type wireAuthzID struct { | ||||
| 	Type  string `json:"type"` | ||||
| 	Value string `json:"value"` | ||||
| } | ||||
| 
 | ||||
| // wireAuthz is ACME JSON representation of Authorization objects.
 | ||||
| type wireAuthz struct { | ||||
| 	Identifier   wireAuthzID | ||||
| 	Status       string | ||||
| 	Expires      time.Time | ||||
| 	Wildcard     bool | ||||
| 	Challenges   []wireChallenge | ||||
| 	Combinations [][]int | ||||
| 	Identifier   struct { | ||||
| 		Type  string | ||||
| 		Value string | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (z *wireAuthz) authorization(uri string) *Authorization { | ||||
|  | @ -232,8 +414,10 @@ func (z *wireAuthz) authorization(uri string) *Authorization { | |||
| 		URI:          uri, | ||||
| 		Status:       z.Status, | ||||
| 		Identifier:   AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value}, | ||||
| 		Combinations: z.Combinations, // shallow copy
 | ||||
| 		Expires:      z.Expires, | ||||
| 		Wildcard:     z.Wildcard, | ||||
| 		Challenges:   make([]*Challenge, len(z.Challenges)), | ||||
| 		Combinations: z.Combinations, // shallow copy
 | ||||
| 	} | ||||
| 	for i, v := range z.Challenges { | ||||
| 		a.Challenges[i] = v.challenge() | ||||
|  | @ -254,22 +438,55 @@ func (z *wireAuthz) error(uri string) *AuthorizationError { | |||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // Challenge encodes a returned CA challenge.
 | ||||
| // Its Error field may be non-nil if the challenge is part of an Authorization
 | ||||
| // with StatusInvalid.
 | ||||
| type Challenge struct { | ||||
| 	// Type is the challenge type, e.g. "http-01", "tls-alpn-01", "dns-01".
 | ||||
| 	Type string | ||||
| 
 | ||||
| 	// URI is where a challenge response can be posted to.
 | ||||
| 	URI string | ||||
| 
 | ||||
| 	// Token is a random value that uniquely identifies the challenge.
 | ||||
| 	Token string | ||||
| 
 | ||||
| 	// Status identifies the status of this challenge.
 | ||||
| 	// In RFC 8555, possible values are StatusPending, StatusProcessing, StatusValid,
 | ||||
| 	// and StatusInvalid.
 | ||||
| 	Status string | ||||
| 
 | ||||
| 	// Validated is the time at which the CA validated this challenge.
 | ||||
| 	// Always zero value in pre-RFC 8555.
 | ||||
| 	Validated time.Time | ||||
| 
 | ||||
| 	// Error indicates the reason for an authorization failure
 | ||||
| 	// when this challenge was used.
 | ||||
| 	// The type of a non-nil value is *Error.
 | ||||
| 	Error error | ||||
| } | ||||
| 
 | ||||
| // wireChallenge is ACME JSON challenge representation.
 | ||||
| type wireChallenge struct { | ||||
| 	URI    string `json:"uri"` | ||||
| 	Type   string | ||||
| 	Token  string | ||||
| 	Status string | ||||
| 	Error  *wireError | ||||
| 	URL       string `json:"url"` // RFC
 | ||||
| 	URI       string `json:"uri"` // pre-RFC
 | ||||
| 	Type      string | ||||
| 	Token     string | ||||
| 	Status    string | ||||
| 	Validated time.Time | ||||
| 	Error     *wireError | ||||
| } | ||||
| 
 | ||||
| func (c *wireChallenge) challenge() *Challenge { | ||||
| 	v := &Challenge{ | ||||
| 		URI:    c.URI, | ||||
| 		URI:    c.URL, | ||||
| 		Type:   c.Type, | ||||
| 		Token:  c.Token, | ||||
| 		Status: c.Status, | ||||
| 	} | ||||
| 	if v.URI == "" { | ||||
| 		v.URI = c.URI // c.URL was empty; use legacy
 | ||||
| 	} | ||||
| 	if v.Status == "" { | ||||
| 		v.Status = StatusPending | ||||
| 	} | ||||
|  | @ -282,9 +499,10 @@ func (c *wireChallenge) challenge() *Challenge { | |||
| // wireError is a subset of fields of the Problem Details object
 | ||||
| // as described in https://tools.ietf.org/html/rfc7807#section-3.1.
 | ||||
| type wireError struct { | ||||
| 	Status int | ||||
| 	Type   string | ||||
| 	Detail string | ||||
| 	Status   int | ||||
| 	Type     string | ||||
| 	Detail   string | ||||
| 	Instance string | ||||
| } | ||||
| 
 | ||||
| func (e *wireError) error(h http.Header) *Error { | ||||
|  | @ -292,6 +510,7 @@ func (e *wireError) error(h http.Header) *Error { | |||
| 		StatusCode:  e.Status, | ||||
| 		ProblemType: e.Type, | ||||
| 		Detail:      e.Detail, | ||||
| 		Instance:    e.Instance, | ||||
| 		Header:      h, | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,27 @@ | |||
| // Copyright 2019 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build go1.12
 | ||||
| 
 | ||||
| package acme | ||||
| 
 | ||||
| import "runtime/debug" | ||||
| 
 | ||||
| func init() { | ||||
| 	// Set packageVersion if the binary was built in modules mode and x/crypto
 | ||||
| 	// was not replaced with a different module.
 | ||||
| 	info, ok := debug.ReadBuildInfo() | ||||
| 	if !ok { | ||||
| 		return | ||||
| 	} | ||||
| 	for _, m := range info.Deps { | ||||
| 		if m.Path != "golang.org/x/crypto" { | ||||
| 			continue | ||||
| 		} | ||||
| 		if m.Replace == nil { | ||||
| 			packageVersion = m.Version | ||||
| 		} | ||||
| 		break | ||||
| 	} | ||||
| } | ||||
|  | @ -1,61 +0,0 @@ | |||
| // Copyright 2018 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| // mkasm_darwin.go generates assembly trampolines to call libSystem routines from Go.
 | ||||
| //This program must be run after mksyscall.go.
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| 	in1, err := ioutil.ReadFile("syscall_darwin.go") | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("can't open syscall_darwin.go: %s", err) | ||||
| 	} | ||||
| 	arch := os.Args[1] | ||||
| 	in2, err := ioutil.ReadFile(fmt.Sprintf("syscall_darwin_%s.go", arch)) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("can't open syscall_darwin_%s.go: %s", arch, err) | ||||
| 	} | ||||
| 	in3, err := ioutil.ReadFile(fmt.Sprintf("zsyscall_darwin_%s.go", arch)) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("can't open zsyscall_darwin_%s.go: %s", arch, err) | ||||
| 	} | ||||
| 	in := string(in1) + string(in2) + string(in3) | ||||
| 
 | ||||
| 	trampolines := map[string]bool{} | ||||
| 
 | ||||
| 	var out bytes.Buffer | ||||
| 
 | ||||
| 	fmt.Fprintf(&out, "// go run mkasm_darwin.go %s\n", strings.Join(os.Args[1:], " ")) | ||||
| 	fmt.Fprintf(&out, "// Code generated by the command above; DO NOT EDIT.\n") | ||||
| 	fmt.Fprintf(&out, "\n") | ||||
| 	fmt.Fprintf(&out, "// +build go1.12\n") | ||||
| 	fmt.Fprintf(&out, "\n") | ||||
| 	fmt.Fprintf(&out, "#include \"textflag.h\"\n") | ||||
| 	for _, line := range strings.Split(in, "\n") { | ||||
| 		if !strings.HasPrefix(line, "func ") || !strings.HasSuffix(line, "_trampoline()") { | ||||
| 			continue | ||||
| 		} | ||||
| 		fn := line[5 : len(line)-13] | ||||
| 		if !trampolines[fn] { | ||||
| 			trampolines[fn] = true | ||||
| 			fmt.Fprintf(&out, "TEXT ·%s_trampoline(SB),NOSPLIT,$0-0\n", fn) | ||||
| 			fmt.Fprintf(&out, "\tJMP\t%s(SB)\n", fn) | ||||
| 		} | ||||
| 	} | ||||
| 	err = ioutil.WriteFile(fmt.Sprintf("zsyscall_darwin_%s.s", arch), out.Bytes(), 0644) | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("can't write zsyscall_darwin_%s.s: %s", arch, err) | ||||
| 	} | ||||
| } | ||||
|  | @ -1,122 +0,0 @@ | |||
| // Copyright 2016 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| // mkpost processes the output of cgo -godefs to
 | ||||
| // modify the generated types. It is used to clean up
 | ||||
| // the sys API in an architecture specific manner.
 | ||||
| //
 | ||||
| // mkpost is run after cgo -godefs; see README.md.
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"go/format" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"regexp" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| 	// Get the OS and architecture (using GOARCH_TARGET if it exists)
 | ||||
| 	goos := os.Getenv("GOOS") | ||||
| 	goarch := os.Getenv("GOARCH_TARGET") | ||||
| 	if goarch == "" { | ||||
| 		goarch = os.Getenv("GOARCH") | ||||
| 	} | ||||
| 	// Check that we are using the Docker-based build system if we should be.
 | ||||
| 	if goos == "linux" { | ||||
| 		if os.Getenv("GOLANG_SYS_BUILD") != "docker" { | ||||
| 			os.Stderr.WriteString("In the Docker-based build system, mkpost should not be called directly.\n") | ||||
| 			os.Stderr.WriteString("See README.md\n") | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	b, err := ioutil.ReadAll(os.Stdin) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if goos == "aix" { | ||||
| 		// Replace type of Atim, Mtim and Ctim by Timespec in Stat_t
 | ||||
| 		// to avoid having both StTimespec and Timespec.
 | ||||
| 		sttimespec := regexp.MustCompile(`_Ctype_struct_st_timespec`) | ||||
| 		b = sttimespec.ReplaceAll(b, []byte("Timespec")) | ||||
| 	} | ||||
| 
 | ||||
| 	// Intentionally export __val fields in Fsid and Sigset_t
 | ||||
| 	valRegex := regexp.MustCompile(`type (Fsid|Sigset_t) struct {(\s+)X__val(\s+\S+\s+)}`) | ||||
| 	b = valRegex.ReplaceAll(b, []byte("type $1 struct {${2}Val$3}")) | ||||
| 
 | ||||
| 	// Intentionally export __fds_bits field in FdSet
 | ||||
| 	fdSetRegex := regexp.MustCompile(`type (FdSet) struct {(\s+)X__fds_bits(\s+\S+\s+)}`) | ||||
| 	b = fdSetRegex.ReplaceAll(b, []byte("type $1 struct {${2}Bits$3}")) | ||||
| 
 | ||||
| 	// If we have empty Ptrace structs, we should delete them. Only s390x emits
 | ||||
| 	// nonempty Ptrace structs.
 | ||||
| 	ptraceRexexp := regexp.MustCompile(`type Ptrace((Psw|Fpregs|Per) struct {\s*})`) | ||||
| 	b = ptraceRexexp.ReplaceAll(b, nil) | ||||
| 
 | ||||
| 	// Replace the control_regs union with a blank identifier for now.
 | ||||
| 	controlRegsRegex := regexp.MustCompile(`(Control_regs)\s+\[0\]uint64`) | ||||
| 	b = controlRegsRegex.ReplaceAll(b, []byte("_ [0]uint64")) | ||||
| 
 | ||||
| 	// Remove fields that are added by glibc
 | ||||
| 	// Note that this is unstable as the identifers are private.
 | ||||
| 	removeFieldsRegex := regexp.MustCompile(`X__glibc\S*`) | ||||
| 	b = removeFieldsRegex.ReplaceAll(b, []byte("_")) | ||||
| 
 | ||||
| 	// Convert [65]int8 to [65]byte in Utsname members to simplify
 | ||||
| 	// conversion to string; see golang.org/issue/20753
 | ||||
| 	convertUtsnameRegex := regexp.MustCompile(`((Sys|Node|Domain)name|Release|Version|Machine)(\s+)\[(\d+)\]u?int8`) | ||||
| 	b = convertUtsnameRegex.ReplaceAll(b, []byte("$1$3[$4]byte")) | ||||
| 
 | ||||
| 	// Convert [1024]int8 to [1024]byte in Ptmget members
 | ||||
| 	convertPtmget := regexp.MustCompile(`([SC]n)(\s+)\[(\d+)\]u?int8`) | ||||
| 	b = convertPtmget.ReplaceAll(b, []byte("$1[$3]byte")) | ||||
| 
 | ||||
| 	// Remove spare fields (e.g. in Statx_t)
 | ||||
| 	spareFieldsRegex := regexp.MustCompile(`X__spare\S*`) | ||||
| 	b = spareFieldsRegex.ReplaceAll(b, []byte("_")) | ||||
| 
 | ||||
| 	// Remove cgo padding fields
 | ||||
| 	removePaddingFieldsRegex := regexp.MustCompile(`Pad_cgo_\d+`) | ||||
| 	b = removePaddingFieldsRegex.ReplaceAll(b, []byte("_")) | ||||
| 
 | ||||
| 	// Remove padding, hidden, or unused fields
 | ||||
| 	removeFieldsRegex = regexp.MustCompile(`\b(X_\S+|Padding)`) | ||||
| 	b = removeFieldsRegex.ReplaceAll(b, []byte("_")) | ||||
| 
 | ||||
| 	// Remove the first line of warning from cgo
 | ||||
| 	b = b[bytes.IndexByte(b, '\n')+1:] | ||||
| 	// Modify the command in the header to include:
 | ||||
| 	//  mkpost, our own warning, and a build tag.
 | ||||
| 	replacement := fmt.Sprintf(`$1 | go run mkpost.go | ||||
| // Code generated by the command above; see README.md. DO NOT EDIT.
 | ||||
| 
 | ||||
| // +build %s,%s`, goarch, goos)
 | ||||
| 	cgoCommandRegex := regexp.MustCompile(`(cgo -godefs .*)`) | ||||
| 	b = cgoCommandRegex.ReplaceAll(b, []byte(replacement)) | ||||
| 
 | ||||
| 	// Rename Stat_t time fields
 | ||||
| 	if goos == "freebsd" && goarch == "386" { | ||||
| 		// Hide Stat_t.[AMCB]tim_ext fields
 | ||||
| 		renameStatTimeExtFieldsRegex := regexp.MustCompile(`[AMCB]tim_ext`) | ||||
| 		b = renameStatTimeExtFieldsRegex.ReplaceAll(b, []byte("_")) | ||||
| 	} | ||||
| 	renameStatTimeFieldsRegex := regexp.MustCompile(`([AMCB])(?:irth)?time?(?:spec)?\s+(Timespec|StTimespec)`) | ||||
| 	b = renameStatTimeFieldsRegex.ReplaceAll(b, []byte("${1}tim ${2}")) | ||||
| 
 | ||||
| 	// gofmt
 | ||||
| 	b, err = format.Source(b) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	os.Stdout.Write(b) | ||||
| } | ||||
|  | @ -1,407 +0,0 @@ | |||
| // Copyright 2018 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| /* | ||||
| This program reads a file containing function prototypes | ||||
| (like syscall_darwin.go) and generates system call bodies. | ||||
| The prototypes are marked by lines beginning with "//sys" | ||||
| and read like func declarations if //sys is replaced by func, but:
 | ||||
| 	* The parameter lists must give a name for each argument. | ||||
| 	  This includes return parameters. | ||||
| 	* The parameter lists must give a type for each argument: | ||||
| 	  the (x, y, z int) shorthand is not allowed. | ||||
| 	* If the return parameter is an error number, it must be named errno. | ||||
| 
 | ||||
| A line beginning with //sysnb is like //sys, except that the
 | ||||
| goroutine will not be suspended during the execution of the system | ||||
| call.  This must only be used for system calls which can never | ||||
| block, as otherwise the system call could cause all goroutines to | ||||
| hang. | ||||
| */ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	b32       = flag.Bool("b32", false, "32bit big-endian") | ||||
| 	l32       = flag.Bool("l32", false, "32bit little-endian") | ||||
| 	plan9     = flag.Bool("plan9", false, "plan9") | ||||
| 	openbsd   = flag.Bool("openbsd", false, "openbsd") | ||||
| 	netbsd    = flag.Bool("netbsd", false, "netbsd") | ||||
| 	dragonfly = flag.Bool("dragonfly", false, "dragonfly") | ||||
| 	arm       = flag.Bool("arm", false, "arm") // 64-bit value should use (even, odd)-pair
 | ||||
| 	tags      = flag.String("tags", "", "build tags") | ||||
| 	filename  = flag.String("output", "", "output file name (standard output if omitted)") | ||||
| ) | ||||
| 
 | ||||
| // cmdLine returns this programs's commandline arguments
 | ||||
| func cmdLine() string { | ||||
| 	return "go run mksyscall.go " + strings.Join(os.Args[1:], " ") | ||||
| } | ||||
| 
 | ||||
| // buildTags returns build tags
 | ||||
| func buildTags() string { | ||||
| 	return *tags | ||||
| } | ||||
| 
 | ||||
| // Param is function parameter
 | ||||
| type Param struct { | ||||
| 	Name string | ||||
| 	Type string | ||||
| } | ||||
| 
 | ||||
| // usage prints the program usage
 | ||||
| func usage() { | ||||
| 	fmt.Fprintf(os.Stderr, "usage: go run mksyscall.go [-b32 | -l32] [-tags x,y] [file ...]\n") | ||||
| 	os.Exit(1) | ||||
| } | ||||
| 
 | ||||
| // parseParamList parses parameter list and returns a slice of parameters
 | ||||
| func parseParamList(list string) []string { | ||||
| 	list = strings.TrimSpace(list) | ||||
| 	if list == "" { | ||||
| 		return []string{} | ||||
| 	} | ||||
| 	return regexp.MustCompile(`\s*,\s*`).Split(list, -1) | ||||
| } | ||||
| 
 | ||||
| // parseParam splits a parameter into name and type
 | ||||
| func parseParam(p string) Param { | ||||
| 	ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p) | ||||
| 	if ps == nil { | ||||
| 		fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	return Param{ps[1], ps[2]} | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	// Get the OS and architecture (using GOARCH_TARGET if it exists)
 | ||||
| 	goos := os.Getenv("GOOS") | ||||
| 	if goos == "" { | ||||
| 		fmt.Fprintln(os.Stderr, "GOOS not defined in environment") | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	goarch := os.Getenv("GOARCH_TARGET") | ||||
| 	if goarch == "" { | ||||
| 		goarch = os.Getenv("GOARCH") | ||||
| 	} | ||||
| 
 | ||||
| 	// Check that we are using the Docker-based build system if we should
 | ||||
| 	if goos == "linux" { | ||||
| 		if os.Getenv("GOLANG_SYS_BUILD") != "docker" { | ||||
| 			fmt.Fprintf(os.Stderr, "In the Docker-based build system, mksyscall should not be called directly.\n") | ||||
| 			fmt.Fprintf(os.Stderr, "See README.md\n") | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	flag.Usage = usage | ||||
| 	flag.Parse() | ||||
| 	if len(flag.Args()) <= 0 { | ||||
| 		fmt.Fprintf(os.Stderr, "no files to parse provided\n") | ||||
| 		usage() | ||||
| 	} | ||||
| 
 | ||||
| 	endianness := "" | ||||
| 	if *b32 { | ||||
| 		endianness = "big-endian" | ||||
| 	} else if *l32 { | ||||
| 		endianness = "little-endian" | ||||
| 	} | ||||
| 
 | ||||
| 	libc := false | ||||
| 	if goos == "darwin" && strings.Contains(buildTags(), ",go1.12") { | ||||
| 		libc = true | ||||
| 	} | ||||
| 	trampolines := map[string]bool{} | ||||
| 
 | ||||
| 	text := "" | ||||
| 	for _, path := range flag.Args() { | ||||
| 		file, err := os.Open(path) | ||||
| 		if err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		s := bufio.NewScanner(file) | ||||
| 		for s.Scan() { | ||||
| 			t := s.Text() | ||||
| 			t = strings.TrimSpace(t) | ||||
| 			t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `) | ||||
| 			nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t) | ||||
| 			if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			// Line must be of the form
 | ||||
| 			//	func Open(path string, mode int, perm int) (fd int, errno error)
 | ||||
| 			// Split into name, in params, out params.
 | ||||
| 			f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$`).FindStringSubmatch(t) | ||||
| 			if f == nil { | ||||
| 				fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t) | ||||
| 				os.Exit(1) | ||||
| 			} | ||||
| 			funct, inps, outps, sysname := f[2], f[3], f[4], f[5] | ||||
| 
 | ||||
| 			// ClockGettime doesn't have a syscall number on Darwin, only generate libc wrappers.
 | ||||
| 			if goos == "darwin" && !libc && funct == "ClockGettime" { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			// Split argument lists on comma.
 | ||||
| 			in := parseParamList(inps) | ||||
| 			out := parseParamList(outps) | ||||
| 
 | ||||
| 			// Try in vain to keep people from editing this file.
 | ||||
| 			// The theory is that they jump into the middle of the file
 | ||||
| 			// without reading the header.
 | ||||
| 			text += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" | ||||
| 
 | ||||
| 			// Go function header.
 | ||||
| 			outDecl := "" | ||||
| 			if len(out) > 0 { | ||||
| 				outDecl = fmt.Sprintf(" (%s)", strings.Join(out, ", ")) | ||||
| 			} | ||||
| 			text += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outDecl) | ||||
| 
 | ||||
| 			// Check if err return available
 | ||||
| 			errvar := "" | ||||
| 			for _, param := range out { | ||||
| 				p := parseParam(param) | ||||
| 				if p.Type == "error" { | ||||
| 					errvar = p.Name | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Prepare arguments to Syscall.
 | ||||
| 			var args []string | ||||
| 			n := 0 | ||||
| 			for _, param := range in { | ||||
| 				p := parseParam(param) | ||||
| 				if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { | ||||
| 					args = append(args, "uintptr(unsafe.Pointer("+p.Name+"))") | ||||
| 				} else if p.Type == "string" && errvar != "" { | ||||
| 					text += fmt.Sprintf("\tvar _p%d *byte\n", n) | ||||
| 					text += fmt.Sprintf("\t_p%d, %s = BytePtrFromString(%s)\n", n, errvar, p.Name) | ||||
| 					text += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar) | ||||
| 					args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) | ||||
| 					n++ | ||||
| 				} else if p.Type == "string" { | ||||
| 					fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n") | ||||
| 					text += fmt.Sprintf("\tvar _p%d *byte\n", n) | ||||
| 					text += fmt.Sprintf("\t_p%d, _ = BytePtrFromString(%s)\n", n, p.Name) | ||||
| 					args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) | ||||
| 					n++ | ||||
| 				} else if regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type) != nil { | ||||
| 					// Convert slice into pointer, length.
 | ||||
| 					// Have to be careful not to take address of &a[0] if len == 0:
 | ||||
| 					// pass dummy pointer in that case.
 | ||||
| 					// Used to pass nil, but some OSes or simulators reject write(fd, nil, 0).
 | ||||
| 					text += fmt.Sprintf("\tvar _p%d unsafe.Pointer\n", n) | ||||
| 					text += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = unsafe.Pointer(&%s[0])\n\t}", p.Name, n, p.Name) | ||||
| 					text += fmt.Sprintf(" else {\n\t\t_p%d = unsafe.Pointer(&_zero)\n\t}\n", n) | ||||
| 					args = append(args, fmt.Sprintf("uintptr(_p%d)", n), fmt.Sprintf("uintptr(len(%s))", p.Name)) | ||||
| 					n++ | ||||
| 				} else if p.Type == "int64" && (*openbsd || *netbsd) { | ||||
| 					args = append(args, "0") | ||||
| 					if endianness == "big-endian" { | ||||
| 						args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					} else if endianness == "little-endian" { | ||||
| 						args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name)) | ||||
| 					} else { | ||||
| 						args = append(args, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					} | ||||
| 				} else if p.Type == "int64" && *dragonfly { | ||||
| 					if regexp.MustCompile(`^(?i)extp(read|write)`).FindStringSubmatch(funct) == nil { | ||||
| 						args = append(args, "0") | ||||
| 					} | ||||
| 					if endianness == "big-endian" { | ||||
| 						args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					} else if endianness == "little-endian" { | ||||
| 						args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name)) | ||||
| 					} else { | ||||
| 						args = append(args, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					} | ||||
| 				} else if (p.Type == "int64" || p.Type == "uint64") && endianness != "" { | ||||
| 					if len(args)%2 == 1 && *arm { | ||||
| 						// arm abi specifies 64-bit argument uses
 | ||||
| 						// (even, odd) pair
 | ||||
| 						args = append(args, "0") | ||||
| 					} | ||||
| 					if endianness == "big-endian" { | ||||
| 						args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					} else { | ||||
| 						args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name)) | ||||
| 					} | ||||
| 				} else { | ||||
| 					args = append(args, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Determine which form to use; pad args with zeros.
 | ||||
| 			asm := "Syscall" | ||||
| 			if nonblock != nil { | ||||
| 				if errvar == "" && goos == "linux" { | ||||
| 					asm = "RawSyscallNoError" | ||||
| 				} else { | ||||
| 					asm = "RawSyscall" | ||||
| 				} | ||||
| 			} else { | ||||
| 				if errvar == "" && goos == "linux" { | ||||
| 					asm = "SyscallNoError" | ||||
| 				} | ||||
| 			} | ||||
| 			if len(args) <= 3 { | ||||
| 				for len(args) < 3 { | ||||
| 					args = append(args, "0") | ||||
| 				} | ||||
| 			} else if len(args) <= 6 { | ||||
| 				asm += "6" | ||||
| 				for len(args) < 6 { | ||||
| 					args = append(args, "0") | ||||
| 				} | ||||
| 			} else if len(args) <= 9 { | ||||
| 				asm += "9" | ||||
| 				for len(args) < 9 { | ||||
| 					args = append(args, "0") | ||||
| 				} | ||||
| 			} else { | ||||
| 				fmt.Fprintf(os.Stderr, "%s:%s too many arguments to system call\n", path, funct) | ||||
| 			} | ||||
| 
 | ||||
| 			// System call number.
 | ||||
| 			if sysname == "" { | ||||
| 				sysname = "SYS_" + funct | ||||
| 				sysname = regexp.MustCompile(`([a-z])([A-Z])`).ReplaceAllString(sysname, `${1}_$2`) | ||||
| 				sysname = strings.ToUpper(sysname) | ||||
| 			} | ||||
| 
 | ||||
| 			var libcFn string | ||||
| 			if libc { | ||||
| 				asm = "syscall_" + strings.ToLower(asm[:1]) + asm[1:] // internal syscall call
 | ||||
| 				sysname = strings.TrimPrefix(sysname, "SYS_")         // remove SYS_
 | ||||
| 				sysname = strings.ToLower(sysname)                    // lowercase
 | ||||
| 				if sysname == "getdirentries64" { | ||||
| 					// Special case - libSystem name and
 | ||||
| 					// raw syscall name don't match.
 | ||||
| 					sysname = "__getdirentries64" | ||||
| 				} | ||||
| 				libcFn = sysname | ||||
| 				sysname = "funcPC(libc_" + sysname + "_trampoline)" | ||||
| 			} | ||||
| 
 | ||||
| 			// Actual call.
 | ||||
| 			arglist := strings.Join(args, ", ") | ||||
| 			call := fmt.Sprintf("%s(%s, %s)", asm, sysname, arglist) | ||||
| 
 | ||||
| 			// Assign return values.
 | ||||
| 			body := "" | ||||
| 			ret := []string{"_", "_", "_"} | ||||
| 			doErrno := false | ||||
| 			for i := 0; i < len(out); i++ { | ||||
| 				p := parseParam(out[i]) | ||||
| 				reg := "" | ||||
| 				if p.Name == "err" && !*plan9 { | ||||
| 					reg = "e1" | ||||
| 					ret[2] = reg | ||||
| 					doErrno = true | ||||
| 				} else if p.Name == "err" && *plan9 { | ||||
| 					ret[0] = "r0" | ||||
| 					ret[2] = "e1" | ||||
| 					break | ||||
| 				} else { | ||||
| 					reg = fmt.Sprintf("r%d", i) | ||||
| 					ret[i] = reg | ||||
| 				} | ||||
| 				if p.Type == "bool" { | ||||
| 					reg = fmt.Sprintf("%s != 0", reg) | ||||
| 				} | ||||
| 				if p.Type == "int64" && endianness != "" { | ||||
| 					// 64-bit number in r1:r0 or r0:r1.
 | ||||
| 					if i+2 > len(out) { | ||||
| 						fmt.Fprintf(os.Stderr, "%s:%s not enough registers for int64 return\n", path, funct) | ||||
| 					} | ||||
| 					if endianness == "big-endian" { | ||||
| 						reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i, i+1) | ||||
| 					} else { | ||||
| 						reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i+1, i) | ||||
| 					} | ||||
| 					ret[i] = fmt.Sprintf("r%d", i) | ||||
| 					ret[i+1] = fmt.Sprintf("r%d", i+1) | ||||
| 				} | ||||
| 				if reg != "e1" || *plan9 { | ||||
| 					body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg) | ||||
| 				} | ||||
| 			} | ||||
| 			if ret[0] == "_" && ret[1] == "_" && ret[2] == "_" { | ||||
| 				text += fmt.Sprintf("\t%s\n", call) | ||||
| 			} else { | ||||
| 				if errvar == "" && goos == "linux" { | ||||
| 					// raw syscall without error on Linux, see golang.org/issue/22924
 | ||||
| 					text += fmt.Sprintf("\t%s, %s := %s\n", ret[0], ret[1], call) | ||||
| 				} else { | ||||
| 					text += fmt.Sprintf("\t%s, %s, %s := %s\n", ret[0], ret[1], ret[2], call) | ||||
| 				} | ||||
| 			} | ||||
| 			text += body | ||||
| 
 | ||||
| 			if *plan9 && ret[2] == "e1" { | ||||
| 				text += "\tif int32(r0) == -1 {\n" | ||||
| 				text += "\t\terr = e1\n" | ||||
| 				text += "\t}\n" | ||||
| 			} else if doErrno { | ||||
| 				text += "\tif e1 != 0 {\n" | ||||
| 				text += "\t\terr = errnoErr(e1)\n" | ||||
| 				text += "\t}\n" | ||||
| 			} | ||||
| 			text += "\treturn\n" | ||||
| 			text += "}\n\n" | ||||
| 
 | ||||
| 			if libc && !trampolines[libcFn] { | ||||
| 				// some system calls share a trampoline, like read and readlen.
 | ||||
| 				trampolines[libcFn] = true | ||||
| 				// Declare assembly trampoline.
 | ||||
| 				text += fmt.Sprintf("func libc_%s_trampoline()\n", libcFn) | ||||
| 				// Assembly trampoline calls the libc_* function, which this magic
 | ||||
| 				// redirects to use the function from libSystem.
 | ||||
| 				text += fmt.Sprintf("//go:linkname libc_%s libc_%s\n", libcFn, libcFn) | ||||
| 				text += fmt.Sprintf("//go:cgo_import_dynamic libc_%s %s \"/usr/lib/libSystem.B.dylib\"\n", libcFn, libcFn) | ||||
| 				text += "\n" | ||||
| 			} | ||||
| 		} | ||||
| 		if err := s.Err(); err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		file.Close() | ||||
| 	} | ||||
| 	fmt.Printf(srcTemplate, cmdLine(), buildTags(), text) | ||||
| } | ||||
| 
 | ||||
| const srcTemplate = `// %s
 | ||||
| // Code generated by the command above; see README.md. DO NOT EDIT.
 | ||||
| 
 | ||||
| // +build %s
 | ||||
| 
 | ||||
| package unix | ||||
| 
 | ||||
| import ( | ||||
| 	"syscall" | ||||
| 	"unsafe" | ||||
| ) | ||||
| 
 | ||||
| var _ syscall.Errno | ||||
| 
 | ||||
| %s | ||||
| ` | ||||
|  | @ -1,415 +0,0 @@ | |||
| // Copyright 2019 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| /* | ||||
| This program reads a file containing function prototypes | ||||
| (like syscall_aix.go) and generates system call bodies. | ||||
| The prototypes are marked by lines beginning with "//sys" | ||||
| and read like func declarations if //sys is replaced by func, but:
 | ||||
| 	* The parameter lists must give a name for each argument. | ||||
| 	  This includes return parameters. | ||||
| 	* The parameter lists must give a type for each argument: | ||||
| 	  the (x, y, z int) shorthand is not allowed. | ||||
| 	* If the return parameter is an error number, it must be named err. | ||||
| 	* If go func name needs to be different than its libc name, | ||||
| 	* or the function is not in libc, name could be specified | ||||
| 	* at the end, after "=" sign, like | ||||
| 	  //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
 | ||||
| */ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	b32  = flag.Bool("b32", false, "32bit big-endian") | ||||
| 	l32  = flag.Bool("l32", false, "32bit little-endian") | ||||
| 	aix  = flag.Bool("aix", false, "aix") | ||||
| 	tags = flag.String("tags", "", "build tags") | ||||
| ) | ||||
| 
 | ||||
| // cmdLine returns this programs's commandline arguments
 | ||||
| func cmdLine() string { | ||||
| 	return "go run mksyscall_aix_ppc.go " + strings.Join(os.Args[1:], " ") | ||||
| } | ||||
| 
 | ||||
| // buildTags returns build tags
 | ||||
| func buildTags() string { | ||||
| 	return *tags | ||||
| } | ||||
| 
 | ||||
| // Param is function parameter
 | ||||
| type Param struct { | ||||
| 	Name string | ||||
| 	Type string | ||||
| } | ||||
| 
 | ||||
| // usage prints the program usage
 | ||||
| func usage() { | ||||
| 	fmt.Fprintf(os.Stderr, "usage: go run mksyscall_aix_ppc.go [-b32 | -l32] [-tags x,y] [file ...]\n") | ||||
| 	os.Exit(1) | ||||
| } | ||||
| 
 | ||||
| // parseParamList parses parameter list and returns a slice of parameters
 | ||||
| func parseParamList(list string) []string { | ||||
| 	list = strings.TrimSpace(list) | ||||
| 	if list == "" { | ||||
| 		return []string{} | ||||
| 	} | ||||
| 	return regexp.MustCompile(`\s*,\s*`).Split(list, -1) | ||||
| } | ||||
| 
 | ||||
| // parseParam splits a parameter into name and type
 | ||||
| func parseParam(p string) Param { | ||||
| 	ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p) | ||||
| 	if ps == nil { | ||||
| 		fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	return Param{ps[1], ps[2]} | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	flag.Usage = usage | ||||
| 	flag.Parse() | ||||
| 	if len(flag.Args()) <= 0 { | ||||
| 		fmt.Fprintf(os.Stderr, "no files to parse provided\n") | ||||
| 		usage() | ||||
| 	} | ||||
| 
 | ||||
| 	endianness := "" | ||||
| 	if *b32 { | ||||
| 		endianness = "big-endian" | ||||
| 	} else if *l32 { | ||||
| 		endianness = "little-endian" | ||||
| 	} | ||||
| 
 | ||||
| 	pack := "" | ||||
| 	text := "" | ||||
| 	cExtern := "/*\n#include <stdint.h>\n#include <stddef.h>\n" | ||||
| 	for _, path := range flag.Args() { | ||||
| 		file, err := os.Open(path) | ||||
| 		if err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		s := bufio.NewScanner(file) | ||||
| 		for s.Scan() { | ||||
| 			t := s.Text() | ||||
| 			t = strings.TrimSpace(t) | ||||
| 			t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `) | ||||
| 			if p := regexp.MustCompile(`^package (\S+)$`).FindStringSubmatch(t); p != nil && pack == "" { | ||||
| 				pack = p[1] | ||||
| 			} | ||||
| 			nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t) | ||||
| 			if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			// Line must be of the form
 | ||||
| 			//	func Open(path string, mode int, perm int) (fd int, err error)
 | ||||
| 			// Split into name, in params, out params.
 | ||||
| 			f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$`).FindStringSubmatch(t) | ||||
| 			if f == nil { | ||||
| 				fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t) | ||||
| 				os.Exit(1) | ||||
| 			} | ||||
| 			funct, inps, outps, modname, sysname := f[2], f[3], f[4], f[5], f[6] | ||||
| 
 | ||||
| 			// Split argument lists on comma.
 | ||||
| 			in := parseParamList(inps) | ||||
| 			out := parseParamList(outps) | ||||
| 
 | ||||
| 			inps = strings.Join(in, ", ") | ||||
| 			outps = strings.Join(out, ", ") | ||||
| 
 | ||||
| 			// Try in vain to keep people from editing this file.
 | ||||
| 			// The theory is that they jump into the middle of the file
 | ||||
| 			// without reading the header.
 | ||||
| 			text += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" | ||||
| 
 | ||||
| 			// Check if value return, err return available
 | ||||
| 			errvar := "" | ||||
| 			retvar := "" | ||||
| 			rettype := "" | ||||
| 			for _, param := range out { | ||||
| 				p := parseParam(param) | ||||
| 				if p.Type == "error" { | ||||
| 					errvar = p.Name | ||||
| 				} else { | ||||
| 					retvar = p.Name | ||||
| 					rettype = p.Type | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// System call name.
 | ||||
| 			if sysname == "" { | ||||
| 				sysname = funct | ||||
| 			} | ||||
| 			sysname = regexp.MustCompile(`([a-z])([A-Z])`).ReplaceAllString(sysname, `${1}_$2`) | ||||
| 			sysname = strings.ToLower(sysname) // All libc functions are lowercase.
 | ||||
| 
 | ||||
| 			cRettype := "" | ||||
| 			if rettype == "unsafe.Pointer" { | ||||
| 				cRettype = "uintptr_t" | ||||
| 			} else if rettype == "uintptr" { | ||||
| 				cRettype = "uintptr_t" | ||||
| 			} else if regexp.MustCompile(`^_`).FindStringSubmatch(rettype) != nil { | ||||
| 				cRettype = "uintptr_t" | ||||
| 			} else if rettype == "int" { | ||||
| 				cRettype = "int" | ||||
| 			} else if rettype == "int32" { | ||||
| 				cRettype = "int" | ||||
| 			} else if rettype == "int64" { | ||||
| 				cRettype = "long long" | ||||
| 			} else if rettype == "uint32" { | ||||
| 				cRettype = "unsigned int" | ||||
| 			} else if rettype == "uint64" { | ||||
| 				cRettype = "unsigned long long" | ||||
| 			} else { | ||||
| 				cRettype = "int" | ||||
| 			} | ||||
| 			if sysname == "exit" { | ||||
| 				cRettype = "void" | ||||
| 			} | ||||
| 
 | ||||
| 			// Change p.Types to c
 | ||||
| 			var cIn []string | ||||
| 			for _, param := range in { | ||||
| 				p := parseParam(param) | ||||
| 				if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { | ||||
| 					cIn = append(cIn, "uintptr_t") | ||||
| 				} else if p.Type == "string" { | ||||
| 					cIn = append(cIn, "uintptr_t") | ||||
| 				} else if regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type) != nil { | ||||
| 					cIn = append(cIn, "uintptr_t", "size_t") | ||||
| 				} else if p.Type == "unsafe.Pointer" { | ||||
| 					cIn = append(cIn, "uintptr_t") | ||||
| 				} else if p.Type == "uintptr" { | ||||
| 					cIn = append(cIn, "uintptr_t") | ||||
| 				} else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil { | ||||
| 					cIn = append(cIn, "uintptr_t") | ||||
| 				} else if p.Type == "int" { | ||||
| 					cIn = append(cIn, "int") | ||||
| 				} else if p.Type == "int32" { | ||||
| 					cIn = append(cIn, "int") | ||||
| 				} else if p.Type == "int64" { | ||||
| 					cIn = append(cIn, "long long") | ||||
| 				} else if p.Type == "uint32" { | ||||
| 					cIn = append(cIn, "unsigned int") | ||||
| 				} else if p.Type == "uint64" { | ||||
| 					cIn = append(cIn, "unsigned long long") | ||||
| 				} else { | ||||
| 					cIn = append(cIn, "int") | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if funct != "fcntl" && funct != "FcntlInt" && funct != "readlen" && funct != "writelen" { | ||||
| 				if sysname == "select" { | ||||
| 					// select is a keyword of Go. Its name is
 | ||||
| 					// changed to c_select.
 | ||||
| 					cExtern += "#define c_select select\n" | ||||
| 				} | ||||
| 				// Imports of system calls from libc
 | ||||
| 				cExtern += fmt.Sprintf("%s %s", cRettype, sysname) | ||||
| 				cIn := strings.Join(cIn, ", ") | ||||
| 				cExtern += fmt.Sprintf("(%s);\n", cIn) | ||||
| 			} | ||||
| 
 | ||||
| 			// So file name.
 | ||||
| 			if *aix { | ||||
| 				if modname == "" { | ||||
| 					modname = "libc.a/shr_64.o" | ||||
| 				} else { | ||||
| 					fmt.Fprintf(os.Stderr, "%s: only syscall using libc are available\n", funct) | ||||
| 					os.Exit(1) | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			strconvfunc := "C.CString" | ||||
| 
 | ||||
| 			// Go function header.
 | ||||
| 			if outps != "" { | ||||
| 				outps = fmt.Sprintf(" (%s)", outps) | ||||
| 			} | ||||
| 			if text != "" { | ||||
| 				text += "\n" | ||||
| 			} | ||||
| 
 | ||||
| 			text += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outps) | ||||
| 
 | ||||
| 			// Prepare arguments to Syscall.
 | ||||
| 			var args []string | ||||
| 			n := 0 | ||||
| 			argN := 0 | ||||
| 			for _, param := range in { | ||||
| 				p := parseParam(param) | ||||
| 				if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { | ||||
| 					args = append(args, "C.uintptr_t(uintptr(unsafe.Pointer("+p.Name+")))") | ||||
| 				} else if p.Type == "string" && errvar != "" { | ||||
| 					text += fmt.Sprintf("\t_p%d := uintptr(unsafe.Pointer(%s(%s)))\n", n, strconvfunc, p.Name) | ||||
| 					args = append(args, fmt.Sprintf("C.uintptr_t(_p%d)", n)) | ||||
| 					n++ | ||||
| 				} else if p.Type == "string" { | ||||
| 					fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n") | ||||
| 					text += fmt.Sprintf("\t_p%d := uintptr(unsafe.Pointer(%s(%s)))\n", n, strconvfunc, p.Name) | ||||
| 					args = append(args, fmt.Sprintf("C.uintptr_t(_p%d)", n)) | ||||
| 					n++ | ||||
| 				} else if m := regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type); m != nil { | ||||
| 					// Convert slice into pointer, length.
 | ||||
| 					// Have to be careful not to take address of &a[0] if len == 0:
 | ||||
| 					// pass nil in that case.
 | ||||
| 					text += fmt.Sprintf("\tvar _p%d *%s\n", n, m[1]) | ||||
| 					text += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = &%s[0]\n\t}\n", p.Name, n, p.Name) | ||||
| 					args = append(args, fmt.Sprintf("C.uintptr_t(uintptr(unsafe.Pointer(_p%d)))", n)) | ||||
| 					n++ | ||||
| 					text += fmt.Sprintf("\tvar _p%d int\n", n) | ||||
| 					text += fmt.Sprintf("\t_p%d = len(%s)\n", n, p.Name) | ||||
| 					args = append(args, fmt.Sprintf("C.size_t(_p%d)", n)) | ||||
| 					n++ | ||||
| 				} else if p.Type == "int64" && endianness != "" { | ||||
| 					if endianness == "big-endian" { | ||||
| 						args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					} else { | ||||
| 						args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name)) | ||||
| 					} | ||||
| 					n++ | ||||
| 				} else if p.Type == "bool" { | ||||
| 					text += fmt.Sprintf("\tvar _p%d uint32\n", n) | ||||
| 					text += fmt.Sprintf("\tif %s {\n\t\t_p%d = 1\n\t} else {\n\t\t_p%d = 0\n\t}\n", p.Name, n, n) | ||||
| 					args = append(args, fmt.Sprintf("_p%d", n)) | ||||
| 				} else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil { | ||||
| 					args = append(args, fmt.Sprintf("C.uintptr_t(uintptr(%s))", p.Name)) | ||||
| 				} else if p.Type == "unsafe.Pointer" { | ||||
| 					args = append(args, fmt.Sprintf("C.uintptr_t(uintptr(%s))", p.Name)) | ||||
| 				} else if p.Type == "int" { | ||||
| 					if (argN == 2) && ((funct == "readlen") || (funct == "writelen")) { | ||||
| 						args = append(args, fmt.Sprintf("C.size_t(%s)", p.Name)) | ||||
| 					} else if argN == 0 && funct == "fcntl" { | ||||
| 						args = append(args, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) | ||||
| 					} else if (argN == 2) && ((funct == "fcntl") || (funct == "FcntlInt")) { | ||||
| 						args = append(args, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) | ||||
| 					} else { | ||||
| 						args = append(args, fmt.Sprintf("C.int(%s)", p.Name)) | ||||
| 					} | ||||
| 				} else if p.Type == "int32" { | ||||
| 					args = append(args, fmt.Sprintf("C.int(%s)", p.Name)) | ||||
| 				} else if p.Type == "int64" { | ||||
| 					args = append(args, fmt.Sprintf("C.longlong(%s)", p.Name)) | ||||
| 				} else if p.Type == "uint32" { | ||||
| 					args = append(args, fmt.Sprintf("C.uint(%s)", p.Name)) | ||||
| 				} else if p.Type == "uint64" { | ||||
| 					args = append(args, fmt.Sprintf("C.ulonglong(%s)", p.Name)) | ||||
| 				} else if p.Type == "uintptr" { | ||||
| 					args = append(args, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) | ||||
| 				} else { | ||||
| 					args = append(args, fmt.Sprintf("C.int(%s)", p.Name)) | ||||
| 				} | ||||
| 				argN++ | ||||
| 			} | ||||
| 
 | ||||
| 			// Actual call.
 | ||||
| 			arglist := strings.Join(args, ", ") | ||||
| 			call := "" | ||||
| 			if sysname == "exit" { | ||||
| 				if errvar != "" { | ||||
| 					call += "er :=" | ||||
| 				} else { | ||||
| 					call += "" | ||||
| 				} | ||||
| 			} else if errvar != "" { | ||||
| 				call += "r0,er :=" | ||||
| 			} else if retvar != "" { | ||||
| 				call += "r0,_ :=" | ||||
| 			} else { | ||||
| 				call += "" | ||||
| 			} | ||||
| 			if sysname == "select" { | ||||
| 				// select is a keyword of Go. Its name is
 | ||||
| 				// changed to c_select.
 | ||||
| 				call += fmt.Sprintf("C.c_%s(%s)", sysname, arglist) | ||||
| 			} else { | ||||
| 				call += fmt.Sprintf("C.%s(%s)", sysname, arglist) | ||||
| 			} | ||||
| 
 | ||||
| 			// Assign return values.
 | ||||
| 			body := "" | ||||
| 			for i := 0; i < len(out); i++ { | ||||
| 				p := parseParam(out[i]) | ||||
| 				reg := "" | ||||
| 				if p.Name == "err" { | ||||
| 					reg = "e1" | ||||
| 				} else { | ||||
| 					reg = "r0" | ||||
| 				} | ||||
| 				if reg != "e1" { | ||||
| 					body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg) | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// verify return
 | ||||
| 			if sysname != "exit" && errvar != "" { | ||||
| 				if regexp.MustCompile(`^uintptr`).FindStringSubmatch(cRettype) != nil { | ||||
| 					body += "\tif (uintptr(r0) ==^uintptr(0) && er != nil) {\n" | ||||
| 					body += fmt.Sprintf("\t\t%s = er\n", errvar) | ||||
| 					body += "\t}\n" | ||||
| 				} else { | ||||
| 					body += "\tif (r0 ==-1 && er != nil) {\n" | ||||
| 					body += fmt.Sprintf("\t\t%s = er\n", errvar) | ||||
| 					body += "\t}\n" | ||||
| 				} | ||||
| 			} else if errvar != "" { | ||||
| 				body += "\tif (er != nil) {\n" | ||||
| 				body += fmt.Sprintf("\t\t%s = er\n", errvar) | ||||
| 				body += "\t}\n" | ||||
| 			} | ||||
| 
 | ||||
| 			text += fmt.Sprintf("\t%s\n", call) | ||||
| 			text += body | ||||
| 
 | ||||
| 			text += "\treturn\n" | ||||
| 			text += "}\n" | ||||
| 		} | ||||
| 		if err := s.Err(); err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		file.Close() | ||||
| 	} | ||||
| 	imp := "" | ||||
| 	if pack != "unix" { | ||||
| 		imp = "import \"golang.org/x/sys/unix\"\n" | ||||
| 
 | ||||
| 	} | ||||
| 	fmt.Printf(srcTemplate, cmdLine(), buildTags(), pack, cExtern, imp, text) | ||||
| } | ||||
| 
 | ||||
| const srcTemplate = `// %s
 | ||||
| // Code generated by the command above; see README.md. DO NOT EDIT.
 | ||||
| 
 | ||||
| // +build %s
 | ||||
| 
 | ||||
| package %s | ||||
| 
 | ||||
| 
 | ||||
| %s | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| %s | ||||
| 
 | ||||
| %s | ||||
| ` | ||||
|  | @ -1,614 +0,0 @@ | |||
| // Copyright 2019 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| /* | ||||
| This program reads a file containing function prototypes | ||||
| (like syscall_aix.go) and generates system call bodies. | ||||
| The prototypes are marked by lines beginning with "//sys" | ||||
| and read like func declarations if //sys is replaced by func, but:
 | ||||
| 	* The parameter lists must give a name for each argument. | ||||
| 	  This includes return parameters. | ||||
| 	* The parameter lists must give a type for each argument: | ||||
| 	  the (x, y, z int) shorthand is not allowed. | ||||
| 	* If the return parameter is an error number, it must be named err. | ||||
| 	* If go func name needs to be different than its libc name, | ||||
| 	* or the function is not in libc, name could be specified | ||||
| 	* at the end, after "=" sign, like | ||||
| 	  //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
 | ||||
| 
 | ||||
| 
 | ||||
| This program will generate three files and handle both gc and gccgo implementation: | ||||
|   - zsyscall_aix_ppc64.go: the common part of each implementation (error handler, pointer creation) | ||||
|   - zsyscall_aix_ppc64_gc.go: gc part with //go_cgo_import_dynamic and a call to syscall6
 | ||||
|   - zsyscall_aix_ppc64_gccgo.go: gccgo part with C function and conversion to C type. | ||||
| 
 | ||||
|  The generated code looks like this | ||||
| 
 | ||||
| zsyscall_aix_ppc64.go | ||||
| func asyscall(...) (n int, err error) { | ||||
| 	 // Pointer Creation
 | ||||
| 	 r1, e1 := callasyscall(...) | ||||
| 	 // Type Conversion
 | ||||
| 	 // Error Handler
 | ||||
| 	 return | ||||
| } | ||||
| 
 | ||||
| zsyscall_aix_ppc64_gc.go | ||||
| //go:cgo_import_dynamic libc_asyscall asyscall "libc.a/shr_64.o"
 | ||||
| //go:linkname libc_asyscall libc_asyscall
 | ||||
| var asyscall syscallFunc | ||||
| 
 | ||||
| func callasyscall(...) (r1 uintptr, e1 Errno) { | ||||
| 	 r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_asyscall)), "nb_args", ... ) | ||||
| 	 return | ||||
| } | ||||
| 
 | ||||
| zsyscall_aix_ppc64_ggcgo.go | ||||
| 
 | ||||
| // int asyscall(...)
 | ||||
| 
 | ||||
| import "C" | ||||
| 
 | ||||
| func callasyscall(...) (r1 uintptr, e1 Errno) { | ||||
| 	 r1 = uintptr(C.asyscall(...)) | ||||
| 	 e1 = syscall.GetErrno() | ||||
| 	 return | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	b32  = flag.Bool("b32", false, "32bit big-endian") | ||||
| 	l32  = flag.Bool("l32", false, "32bit little-endian") | ||||
| 	aix  = flag.Bool("aix", false, "aix") | ||||
| 	tags = flag.String("tags", "", "build tags") | ||||
| ) | ||||
| 
 | ||||
| // cmdLine returns this programs's commandline arguments
 | ||||
| func cmdLine() string { | ||||
| 	return "go run mksyscall_aix_ppc64.go " + strings.Join(os.Args[1:], " ") | ||||
| } | ||||
| 
 | ||||
| // buildTags returns build tags
 | ||||
| func buildTags() string { | ||||
| 	return *tags | ||||
| } | ||||
| 
 | ||||
| // Param is function parameter
 | ||||
| type Param struct { | ||||
| 	Name string | ||||
| 	Type string | ||||
| } | ||||
| 
 | ||||
| // usage prints the program usage
 | ||||
| func usage() { | ||||
| 	fmt.Fprintf(os.Stderr, "usage: go run mksyscall_aix_ppc64.go [-b32 | -l32] [-tags x,y] [file ...]\n") | ||||
| 	os.Exit(1) | ||||
| } | ||||
| 
 | ||||
| // parseParamList parses parameter list and returns a slice of parameters
 | ||||
| func parseParamList(list string) []string { | ||||
| 	list = strings.TrimSpace(list) | ||||
| 	if list == "" { | ||||
| 		return []string{} | ||||
| 	} | ||||
| 	return regexp.MustCompile(`\s*,\s*`).Split(list, -1) | ||||
| } | ||||
| 
 | ||||
| // parseParam splits a parameter into name and type
 | ||||
| func parseParam(p string) Param { | ||||
| 	ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p) | ||||
| 	if ps == nil { | ||||
| 		fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	return Param{ps[1], ps[2]} | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	flag.Usage = usage | ||||
| 	flag.Parse() | ||||
| 	if len(flag.Args()) <= 0 { | ||||
| 		fmt.Fprintf(os.Stderr, "no files to parse provided\n") | ||||
| 		usage() | ||||
| 	} | ||||
| 
 | ||||
| 	endianness := "" | ||||
| 	if *b32 { | ||||
| 		endianness = "big-endian" | ||||
| 	} else if *l32 { | ||||
| 		endianness = "little-endian" | ||||
| 	} | ||||
| 
 | ||||
| 	pack := "" | ||||
| 	// GCCGO
 | ||||
| 	textgccgo := "" | ||||
| 	cExtern := "/*\n#include <stdint.h>\n" | ||||
| 	// GC
 | ||||
| 	textgc := "" | ||||
| 	dynimports := "" | ||||
| 	linknames := "" | ||||
| 	var vars []string | ||||
| 	// COMMON
 | ||||
| 	textcommon := "" | ||||
| 	for _, path := range flag.Args() { | ||||
| 		file, err := os.Open(path) | ||||
| 		if err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		s := bufio.NewScanner(file) | ||||
| 		for s.Scan() { | ||||
| 			t := s.Text() | ||||
| 			t = strings.TrimSpace(t) | ||||
| 			t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `) | ||||
| 			if p := regexp.MustCompile(`^package (\S+)$`).FindStringSubmatch(t); p != nil && pack == "" { | ||||
| 				pack = p[1] | ||||
| 			} | ||||
| 			nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t) | ||||
| 			if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			// Line must be of the form
 | ||||
| 			//	func Open(path string, mode int, perm int) (fd int, err error)
 | ||||
| 			// Split into name, in params, out params.
 | ||||
| 			f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$`).FindStringSubmatch(t) | ||||
| 			if f == nil { | ||||
| 				fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t) | ||||
| 				os.Exit(1) | ||||
| 			} | ||||
| 			funct, inps, outps, modname, sysname := f[2], f[3], f[4], f[5], f[6] | ||||
| 
 | ||||
| 			// Split argument lists on comma.
 | ||||
| 			in := parseParamList(inps) | ||||
| 			out := parseParamList(outps) | ||||
| 
 | ||||
| 			inps = strings.Join(in, ", ") | ||||
| 			outps = strings.Join(out, ", ") | ||||
| 
 | ||||
| 			if sysname == "" { | ||||
| 				sysname = funct | ||||
| 			} | ||||
| 
 | ||||
| 			onlyCommon := false | ||||
| 			if funct == "readlen" || funct == "writelen" || funct == "FcntlInt" || funct == "FcntlFlock" { | ||||
| 				// This function call another syscall which is already implemented.
 | ||||
| 				// Therefore, the gc and gccgo part must not be generated.
 | ||||
| 				onlyCommon = true | ||||
| 			} | ||||
| 
 | ||||
| 			// Try in vain to keep people from editing this file.
 | ||||
| 			// The theory is that they jump into the middle of the file
 | ||||
| 			// without reading the header.
 | ||||
| 
 | ||||
| 			textcommon += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" | ||||
| 			if !onlyCommon { | ||||
| 				textgccgo += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" | ||||
| 				textgc += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" | ||||
| 			} | ||||
| 
 | ||||
| 			// Check if value return, err return available
 | ||||
| 			errvar := "" | ||||
| 			rettype := "" | ||||
| 			for _, param := range out { | ||||
| 				p := parseParam(param) | ||||
| 				if p.Type == "error" { | ||||
| 					errvar = p.Name | ||||
| 				} else { | ||||
| 					rettype = p.Type | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			sysname = regexp.MustCompile(`([a-z])([A-Z])`).ReplaceAllString(sysname, `${1}_$2`) | ||||
| 			sysname = strings.ToLower(sysname) // All libc functions are lowercase.
 | ||||
| 
 | ||||
| 			// GCCGO Prototype return type
 | ||||
| 			cRettype := "" | ||||
| 			if rettype == "unsafe.Pointer" { | ||||
| 				cRettype = "uintptr_t" | ||||
| 			} else if rettype == "uintptr" { | ||||
| 				cRettype = "uintptr_t" | ||||
| 			} else if regexp.MustCompile(`^_`).FindStringSubmatch(rettype) != nil { | ||||
| 				cRettype = "uintptr_t" | ||||
| 			} else if rettype == "int" { | ||||
| 				cRettype = "int" | ||||
| 			} else if rettype == "int32" { | ||||
| 				cRettype = "int" | ||||
| 			} else if rettype == "int64" { | ||||
| 				cRettype = "long long" | ||||
| 			} else if rettype == "uint32" { | ||||
| 				cRettype = "unsigned int" | ||||
| 			} else if rettype == "uint64" { | ||||
| 				cRettype = "unsigned long long" | ||||
| 			} else { | ||||
| 				cRettype = "int" | ||||
| 			} | ||||
| 			if sysname == "exit" { | ||||
| 				cRettype = "void" | ||||
| 			} | ||||
| 
 | ||||
| 			// GCCGO Prototype arguments type
 | ||||
| 			var cIn []string | ||||
| 			for i, param := range in { | ||||
| 				p := parseParam(param) | ||||
| 				if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { | ||||
| 					cIn = append(cIn, "uintptr_t") | ||||
| 				} else if p.Type == "string" { | ||||
| 					cIn = append(cIn, "uintptr_t") | ||||
| 				} else if regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type) != nil { | ||||
| 					cIn = append(cIn, "uintptr_t", "size_t") | ||||
| 				} else if p.Type == "unsafe.Pointer" { | ||||
| 					cIn = append(cIn, "uintptr_t") | ||||
| 				} else if p.Type == "uintptr" { | ||||
| 					cIn = append(cIn, "uintptr_t") | ||||
| 				} else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil { | ||||
| 					cIn = append(cIn, "uintptr_t") | ||||
| 				} else if p.Type == "int" { | ||||
| 					if (i == 0 || i == 2) && funct == "fcntl" { | ||||
| 						// These fcntl arguments needs to be uintptr to be able to call FcntlInt and FcntlFlock
 | ||||
| 						cIn = append(cIn, "uintptr_t") | ||||
| 					} else { | ||||
| 						cIn = append(cIn, "int") | ||||
| 					} | ||||
| 
 | ||||
| 				} else if p.Type == "int32" { | ||||
| 					cIn = append(cIn, "int") | ||||
| 				} else if p.Type == "int64" { | ||||
| 					cIn = append(cIn, "long long") | ||||
| 				} else if p.Type == "uint32" { | ||||
| 					cIn = append(cIn, "unsigned int") | ||||
| 				} else if p.Type == "uint64" { | ||||
| 					cIn = append(cIn, "unsigned long long") | ||||
| 				} else { | ||||
| 					cIn = append(cIn, "int") | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if !onlyCommon { | ||||
| 				// GCCGO Prototype Generation
 | ||||
| 				// Imports of system calls from libc
 | ||||
| 				if sysname == "select" { | ||||
| 					// select is a keyword of Go. Its name is
 | ||||
| 					// changed to c_select.
 | ||||
| 					cExtern += "#define c_select select\n" | ||||
| 				} | ||||
| 				cExtern += fmt.Sprintf("%s %s", cRettype, sysname) | ||||
| 				cIn := strings.Join(cIn, ", ") | ||||
| 				cExtern += fmt.Sprintf("(%s);\n", cIn) | ||||
| 			} | ||||
| 			// GC Library name
 | ||||
| 			if modname == "" { | ||||
| 				modname = "libc.a/shr_64.o" | ||||
| 			} else { | ||||
| 				fmt.Fprintf(os.Stderr, "%s: only syscall using libc are available\n", funct) | ||||
| 				os.Exit(1) | ||||
| 			} | ||||
| 			sysvarname := fmt.Sprintf("libc_%s", sysname) | ||||
| 
 | ||||
| 			if !onlyCommon { | ||||
| 				// GC Runtime import of function to allow cross-platform builds.
 | ||||
| 				dynimports += fmt.Sprintf("//go:cgo_import_dynamic %s %s \"%s\"\n", sysvarname, sysname, modname) | ||||
| 				// GC Link symbol to proc address variable.
 | ||||
| 				linknames += fmt.Sprintf("//go:linkname %s %s\n", sysvarname, sysvarname) | ||||
| 				// GC Library proc address variable.
 | ||||
| 				vars = append(vars, sysvarname) | ||||
| 			} | ||||
| 
 | ||||
| 			strconvfunc := "BytePtrFromString" | ||||
| 			strconvtype := "*byte" | ||||
| 
 | ||||
| 			// Go function header.
 | ||||
| 			if outps != "" { | ||||
| 				outps = fmt.Sprintf(" (%s)", outps) | ||||
| 			} | ||||
| 			if textcommon != "" { | ||||
| 				textcommon += "\n" | ||||
| 			} | ||||
| 
 | ||||
| 			textcommon += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outps) | ||||
| 
 | ||||
| 			// Prepare arguments tocall.
 | ||||
| 			var argscommon []string // Arguments in the common part
 | ||||
| 			var argscall []string   // Arguments for call prototype
 | ||||
| 			var argsgc []string     // Arguments for gc call (with syscall6)
 | ||||
| 			var argsgccgo []string  // Arguments for gccgo call (with C.name_of_syscall)
 | ||||
| 			n := 0 | ||||
| 			argN := 0 | ||||
| 			for _, param := range in { | ||||
| 				p := parseParam(param) | ||||
| 				if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { | ||||
| 					argscommon = append(argscommon, fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.Name)) | ||||
| 					argscall = append(argscall, fmt.Sprintf("%s uintptr", p.Name)) | ||||
| 					argsgc = append(argsgc, p.Name) | ||||
| 					argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) | ||||
| 				} else if p.Type == "string" && errvar != "" { | ||||
| 					textcommon += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype) | ||||
| 					textcommon += fmt.Sprintf("\t_p%d, %s = %s(%s)\n", n, errvar, strconvfunc, p.Name) | ||||
| 					textcommon += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar) | ||||
| 
 | ||||
| 					argscommon = append(argscommon, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) | ||||
| 					argscall = append(argscall, fmt.Sprintf("_p%d uintptr ", n)) | ||||
| 					argsgc = append(argsgc, fmt.Sprintf("_p%d", n)) | ||||
| 					argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(_p%d)", n)) | ||||
| 					n++ | ||||
| 				} else if p.Type == "string" { | ||||
| 					fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n") | ||||
| 					textcommon += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype) | ||||
| 					textcommon += fmt.Sprintf("\t_p%d, %s = %s(%s)\n", n, errvar, strconvfunc, p.Name) | ||||
| 					textcommon += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar) | ||||
| 
 | ||||
| 					argscommon = append(argscommon, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) | ||||
| 					argscall = append(argscall, fmt.Sprintf("_p%d uintptr", n)) | ||||
| 					argsgc = append(argsgc, fmt.Sprintf("_p%d", n)) | ||||
| 					argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(_p%d)", n)) | ||||
| 					n++ | ||||
| 				} else if m := regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type); m != nil { | ||||
| 					// Convert slice into pointer, length.
 | ||||
| 					// Have to be careful not to take address of &a[0] if len == 0:
 | ||||
| 					// pass nil in that case.
 | ||||
| 					textcommon += fmt.Sprintf("\tvar _p%d *%s\n", n, m[1]) | ||||
| 					textcommon += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = &%s[0]\n\t}\n", p.Name, n, p.Name) | ||||
| 					argscommon = append(argscommon, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n), fmt.Sprintf("len(%s)", p.Name)) | ||||
| 					argscall = append(argscall, fmt.Sprintf("_p%d uintptr", n), fmt.Sprintf("_lenp%d int", n)) | ||||
| 					argsgc = append(argsgc, fmt.Sprintf("_p%d", n), fmt.Sprintf("uintptr(_lenp%d)", n)) | ||||
| 					argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(_p%d)", n), fmt.Sprintf("C.size_t(_lenp%d)", n)) | ||||
| 					n++ | ||||
| 				} else if p.Type == "int64" && endianness != "" { | ||||
| 					fmt.Fprintf(os.Stderr, path+":"+funct+" uses int64 with 32 bits mode. Case not yet implemented\n") | ||||
| 				} else if p.Type == "bool" { | ||||
| 					fmt.Fprintf(os.Stderr, path+":"+funct+" uses bool. Case not yet implemented\n") | ||||
| 				} else if regexp.MustCompile(`^_`).FindStringSubmatch(p.Type) != nil || p.Type == "unsafe.Pointer" { | ||||
| 					argscommon = append(argscommon, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					argscall = append(argscall, fmt.Sprintf("%s uintptr", p.Name)) | ||||
| 					argsgc = append(argsgc, p.Name) | ||||
| 					argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) | ||||
| 				} else if p.Type == "int" { | ||||
| 					if (argN == 0 || argN == 2) && ((funct == "fcntl") || (funct == "FcntlInt") || (funct == "FcntlFlock")) { | ||||
| 						// These fcntl arguments need to be uintptr to be able to call FcntlInt and FcntlFlock
 | ||||
| 						argscommon = append(argscommon, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 						argscall = append(argscall, fmt.Sprintf("%s uintptr", p.Name)) | ||||
| 						argsgc = append(argsgc, p.Name) | ||||
| 						argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) | ||||
| 
 | ||||
| 					} else { | ||||
| 						argscommon = append(argscommon, p.Name) | ||||
| 						argscall = append(argscall, fmt.Sprintf("%s int", p.Name)) | ||||
| 						argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 						argsgccgo = append(argsgccgo, fmt.Sprintf("C.int(%s)", p.Name)) | ||||
| 					} | ||||
| 				} else if p.Type == "int32" { | ||||
| 					argscommon = append(argscommon, p.Name) | ||||
| 					argscall = append(argscall, fmt.Sprintf("%s int32", p.Name)) | ||||
| 					argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					argsgccgo = append(argsgccgo, fmt.Sprintf("C.int(%s)", p.Name)) | ||||
| 				} else if p.Type == "int64" { | ||||
| 					argscommon = append(argscommon, p.Name) | ||||
| 					argscall = append(argscall, fmt.Sprintf("%s int64", p.Name)) | ||||
| 					argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					argsgccgo = append(argsgccgo, fmt.Sprintf("C.longlong(%s)", p.Name)) | ||||
| 				} else if p.Type == "uint32" { | ||||
| 					argscommon = append(argscommon, p.Name) | ||||
| 					argscall = append(argscall, fmt.Sprintf("%s uint32", p.Name)) | ||||
| 					argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					argsgccgo = append(argsgccgo, fmt.Sprintf("C.uint(%s)", p.Name)) | ||||
| 				} else if p.Type == "uint64" { | ||||
| 					argscommon = append(argscommon, p.Name) | ||||
| 					argscall = append(argscall, fmt.Sprintf("%s uint64", p.Name)) | ||||
| 					argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					argsgccgo = append(argsgccgo, fmt.Sprintf("C.ulonglong(%s)", p.Name)) | ||||
| 				} else if p.Type == "uintptr" { | ||||
| 					argscommon = append(argscommon, p.Name) | ||||
| 					argscall = append(argscall, fmt.Sprintf("%s uintptr", p.Name)) | ||||
| 					argsgc = append(argsgc, p.Name) | ||||
| 					argsgccgo = append(argsgccgo, fmt.Sprintf("C.uintptr_t(%s)", p.Name)) | ||||
| 				} else { | ||||
| 					argscommon = append(argscommon, fmt.Sprintf("int(%s)", p.Name)) | ||||
| 					argscall = append(argscall, fmt.Sprintf("%s int", p.Name)) | ||||
| 					argsgc = append(argsgc, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					argsgccgo = append(argsgccgo, fmt.Sprintf("C.int(%s)", p.Name)) | ||||
| 				} | ||||
| 				argN++ | ||||
| 			} | ||||
| 			nargs := len(argsgc) | ||||
| 
 | ||||
| 			// COMMON function generation
 | ||||
| 			argscommonlist := strings.Join(argscommon, ", ") | ||||
| 			callcommon := fmt.Sprintf("call%s(%s)", sysname, argscommonlist) | ||||
| 			ret := []string{"_", "_"} | ||||
| 			body := "" | ||||
| 			doErrno := false | ||||
| 			for i := 0; i < len(out); i++ { | ||||
| 				p := parseParam(out[i]) | ||||
| 				reg := "" | ||||
| 				if p.Name == "err" { | ||||
| 					reg = "e1" | ||||
| 					ret[1] = reg | ||||
| 					doErrno = true | ||||
| 				} else { | ||||
| 					reg = "r0" | ||||
| 					ret[0] = reg | ||||
| 				} | ||||
| 				if p.Type == "bool" { | ||||
| 					reg = fmt.Sprintf("%s != 0", reg) | ||||
| 				} | ||||
| 				if reg != "e1" { | ||||
| 					body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg) | ||||
| 				} | ||||
| 			} | ||||
| 			if ret[0] == "_" && ret[1] == "_" { | ||||
| 				textcommon += fmt.Sprintf("\t%s\n", callcommon) | ||||
| 			} else { | ||||
| 				textcommon += fmt.Sprintf("\t%s, %s := %s\n", ret[0], ret[1], callcommon) | ||||
| 			} | ||||
| 			textcommon += body | ||||
| 
 | ||||
| 			if doErrno { | ||||
| 				textcommon += "\tif e1 != 0 {\n" | ||||
| 				textcommon += "\t\terr = errnoErr(e1)\n" | ||||
| 				textcommon += "\t}\n" | ||||
| 			} | ||||
| 			textcommon += "\treturn\n" | ||||
| 			textcommon += "}\n" | ||||
| 
 | ||||
| 			if onlyCommon { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			// CALL Prototype
 | ||||
| 			callProto := fmt.Sprintf("func call%s(%s) (r1 uintptr, e1 Errno) {\n", sysname, strings.Join(argscall, ", ")) | ||||
| 
 | ||||
| 			// GC function generation
 | ||||
| 			asm := "syscall6" | ||||
| 			if nonblock != nil { | ||||
| 				asm = "rawSyscall6" | ||||
| 			} | ||||
| 
 | ||||
| 			if len(argsgc) <= 6 { | ||||
| 				for len(argsgc) < 6 { | ||||
| 					argsgc = append(argsgc, "0") | ||||
| 				} | ||||
| 			} else { | ||||
| 				fmt.Fprintf(os.Stderr, "%s: too many arguments to system call", funct) | ||||
| 				os.Exit(1) | ||||
| 			} | ||||
| 			argsgclist := strings.Join(argsgc, ", ") | ||||
| 			callgc := fmt.Sprintf("%s(uintptr(unsafe.Pointer(&%s)), %d, %s)", asm, sysvarname, nargs, argsgclist) | ||||
| 
 | ||||
| 			textgc += callProto | ||||
| 			textgc += fmt.Sprintf("\tr1, _, e1 = %s\n", callgc) | ||||
| 			textgc += "\treturn\n}\n" | ||||
| 
 | ||||
| 			// GCCGO function generation
 | ||||
| 			argsgccgolist := strings.Join(argsgccgo, ", ") | ||||
| 			var callgccgo string | ||||
| 			if sysname == "select" { | ||||
| 				// select is a keyword of Go. Its name is
 | ||||
| 				// changed to c_select.
 | ||||
| 				callgccgo = fmt.Sprintf("C.c_%s(%s)", sysname, argsgccgolist) | ||||
| 			} else { | ||||
| 				callgccgo = fmt.Sprintf("C.%s(%s)", sysname, argsgccgolist) | ||||
| 			} | ||||
| 			textgccgo += callProto | ||||
| 			textgccgo += fmt.Sprintf("\tr1 = uintptr(%s)\n", callgccgo) | ||||
| 			textgccgo += "\te1 = syscall.GetErrno()\n" | ||||
| 			textgccgo += "\treturn\n}\n" | ||||
| 		} | ||||
| 		if err := s.Err(); err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		file.Close() | ||||
| 	} | ||||
| 	imp := "" | ||||
| 	if pack != "unix" { | ||||
| 		imp = "import \"golang.org/x/sys/unix\"\n" | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	// Print zsyscall_aix_ppc64.go
 | ||||
| 	err := ioutil.WriteFile("zsyscall_aix_ppc64.go", | ||||
| 		[]byte(fmt.Sprintf(srcTemplate1, cmdLine(), buildTags(), pack, imp, textcommon)), | ||||
| 		0644) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	// Print zsyscall_aix_ppc64_gc.go
 | ||||
| 	vardecls := "\t" + strings.Join(vars, ",\n\t") | ||||
| 	vardecls += " syscallFunc" | ||||
| 	err = ioutil.WriteFile("zsyscall_aix_ppc64_gc.go", | ||||
| 		[]byte(fmt.Sprintf(srcTemplate2, cmdLine(), buildTags(), pack, imp, dynimports, linknames, vardecls, textgc)), | ||||
| 		0644) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	// Print zsyscall_aix_ppc64_gccgo.go
 | ||||
| 	err = ioutil.WriteFile("zsyscall_aix_ppc64_gccgo.go", | ||||
| 		[]byte(fmt.Sprintf(srcTemplate3, cmdLine(), buildTags(), pack, cExtern, imp, textgccgo)), | ||||
| 		0644) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| const srcTemplate1 = `// %s
 | ||||
| // Code generated by the command above; see README.md. DO NOT EDIT.
 | ||||
| 
 | ||||
| // +build %s
 | ||||
| 
 | ||||
| package %s | ||||
| 
 | ||||
| import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| %s | ||||
| 
 | ||||
| %s | ||||
| ` | ||||
| const srcTemplate2 = `// %s
 | ||||
| // Code generated by the command above; see README.md. DO NOT EDIT.
 | ||||
| 
 | ||||
| // +build %s
 | ||||
| // +build !gccgo
 | ||||
| 
 | ||||
| package %s | ||||
| 
 | ||||
| import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
| %s | ||||
| %s | ||||
| %s | ||||
| type syscallFunc uintptr | ||||
| 
 | ||||
| var ( | ||||
| %s | ||||
| ) | ||||
| 
 | ||||
| // Implemented in runtime/syscall_aix.go.
 | ||||
| func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) | ||||
| func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) | ||||
| 
 | ||||
| %s | ||||
| ` | ||||
| const srcTemplate3 = `// %s
 | ||||
| // Code generated by the command above; see README.md. DO NOT EDIT.
 | ||||
| 
 | ||||
| // +build %s
 | ||||
| // +build gccgo
 | ||||
| 
 | ||||
| package %s | ||||
| 
 | ||||
| %s | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"syscall" | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| %s | ||||
| 
 | ||||
| %s | ||||
| ` | ||||
|  | @ -1,335 +0,0 @@ | |||
| // Copyright 2019 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| /* | ||||
|  This program reads a file containing function prototypes | ||||
|  (like syscall_solaris.go) and generates system call bodies. | ||||
|  The prototypes are marked by lines beginning with "//sys" | ||||
|  and read like func declarations if //sys is replaced by func, but:
 | ||||
| 	* The parameter lists must give a name for each argument. | ||||
| 	  This includes return parameters. | ||||
| 	* The parameter lists must give a type for each argument: | ||||
| 	  the (x, y, z int) shorthand is not allowed. | ||||
| 	* If the return parameter is an error number, it must be named err. | ||||
| 	* If go func name needs to be different than its libc name, | ||||
| 	* or the function is not in libc, name could be specified | ||||
| 	* at the end, after "=" sign, like | ||||
| 	  //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
 | ||||
| */ | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	b32  = flag.Bool("b32", false, "32bit big-endian") | ||||
| 	l32  = flag.Bool("l32", false, "32bit little-endian") | ||||
| 	tags = flag.String("tags", "", "build tags") | ||||
| ) | ||||
| 
 | ||||
| // cmdLine returns this programs's commandline arguments
 | ||||
| func cmdLine() string { | ||||
| 	return "go run mksyscall_solaris.go " + strings.Join(os.Args[1:], " ") | ||||
| } | ||||
| 
 | ||||
| // buildTags returns build tags
 | ||||
| func buildTags() string { | ||||
| 	return *tags | ||||
| } | ||||
| 
 | ||||
| // Param is function parameter
 | ||||
| type Param struct { | ||||
| 	Name string | ||||
| 	Type string | ||||
| } | ||||
| 
 | ||||
| // usage prints the program usage
 | ||||
| func usage() { | ||||
| 	fmt.Fprintf(os.Stderr, "usage: go run mksyscall_solaris.go [-b32 | -l32] [-tags x,y] [file ...]\n") | ||||
| 	os.Exit(1) | ||||
| } | ||||
| 
 | ||||
| // parseParamList parses parameter list and returns a slice of parameters
 | ||||
| func parseParamList(list string) []string { | ||||
| 	list = strings.TrimSpace(list) | ||||
| 	if list == "" { | ||||
| 		return []string{} | ||||
| 	} | ||||
| 	return regexp.MustCompile(`\s*,\s*`).Split(list, -1) | ||||
| } | ||||
| 
 | ||||
| // parseParam splits a parameter into name and type
 | ||||
| func parseParam(p string) Param { | ||||
| 	ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p) | ||||
| 	if ps == nil { | ||||
| 		fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	return Param{ps[1], ps[2]} | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	flag.Usage = usage | ||||
| 	flag.Parse() | ||||
| 	if len(flag.Args()) <= 0 { | ||||
| 		fmt.Fprintf(os.Stderr, "no files to parse provided\n") | ||||
| 		usage() | ||||
| 	} | ||||
| 
 | ||||
| 	endianness := "" | ||||
| 	if *b32 { | ||||
| 		endianness = "big-endian" | ||||
| 	} else if *l32 { | ||||
| 		endianness = "little-endian" | ||||
| 	} | ||||
| 
 | ||||
| 	pack := "" | ||||
| 	text := "" | ||||
| 	dynimports := "" | ||||
| 	linknames := "" | ||||
| 	var vars []string | ||||
| 	for _, path := range flag.Args() { | ||||
| 		file, err := os.Open(path) | ||||
| 		if err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		s := bufio.NewScanner(file) | ||||
| 		for s.Scan() { | ||||
| 			t := s.Text() | ||||
| 			t = strings.TrimSpace(t) | ||||
| 			t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `) | ||||
| 			if p := regexp.MustCompile(`^package (\S+)$`).FindStringSubmatch(t); p != nil && pack == "" { | ||||
| 				pack = p[1] | ||||
| 			} | ||||
| 			nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t) | ||||
| 			if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 
 | ||||
| 			// Line must be of the form
 | ||||
| 			//	func Open(path string, mode int, perm int) (fd int, err error)
 | ||||
| 			// Split into name, in params, out params.
 | ||||
| 			f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$`).FindStringSubmatch(t) | ||||
| 			if f == nil { | ||||
| 				fmt.Fprintf(os.Stderr, "%s:%s\nmalformed //sys declaration\n", path, t) | ||||
| 				os.Exit(1) | ||||
| 			} | ||||
| 			funct, inps, outps, modname, sysname := f[2], f[3], f[4], f[5], f[6] | ||||
| 
 | ||||
| 			// Split argument lists on comma.
 | ||||
| 			in := parseParamList(inps) | ||||
| 			out := parseParamList(outps) | ||||
| 
 | ||||
| 			inps = strings.Join(in, ", ") | ||||
| 			outps = strings.Join(out, ", ") | ||||
| 
 | ||||
| 			// Try in vain to keep people from editing this file.
 | ||||
| 			// The theory is that they jump into the middle of the file
 | ||||
| 			// without reading the header.
 | ||||
| 			text += "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" | ||||
| 
 | ||||
| 			// So file name.
 | ||||
| 			if modname == "" { | ||||
| 				modname = "libc" | ||||
| 			} | ||||
| 
 | ||||
| 			// System call name.
 | ||||
| 			if sysname == "" { | ||||
| 				sysname = funct | ||||
| 			} | ||||
| 
 | ||||
| 			// System call pointer variable name.
 | ||||
| 			sysvarname := fmt.Sprintf("proc%s", sysname) | ||||
| 
 | ||||
| 			strconvfunc := "BytePtrFromString" | ||||
| 			strconvtype := "*byte" | ||||
| 
 | ||||
| 			sysname = strings.ToLower(sysname) // All libc functions are lowercase.
 | ||||
| 
 | ||||
| 			// Runtime import of function to allow cross-platform builds.
 | ||||
| 			dynimports += fmt.Sprintf("//go:cgo_import_dynamic libc_%s %s \"%s.so\"\n", sysname, sysname, modname) | ||||
| 			// Link symbol to proc address variable.
 | ||||
| 			linknames += fmt.Sprintf("//go:linkname %s libc_%s\n", sysvarname, sysname) | ||||
| 			// Library proc address variable.
 | ||||
| 			vars = append(vars, sysvarname) | ||||
| 
 | ||||
| 			// Go function header.
 | ||||
| 			outlist := strings.Join(out, ", ") | ||||
| 			if outlist != "" { | ||||
| 				outlist = fmt.Sprintf(" (%s)", outlist) | ||||
| 			} | ||||
| 			if text != "" { | ||||
| 				text += "\n" | ||||
| 			} | ||||
| 			text += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outlist) | ||||
| 
 | ||||
| 			// Check if err return available
 | ||||
| 			errvar := "" | ||||
| 			for _, param := range out { | ||||
| 				p := parseParam(param) | ||||
| 				if p.Type == "error" { | ||||
| 					errvar = p.Name | ||||
| 					continue | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Prepare arguments to Syscall.
 | ||||
| 			var args []string | ||||
| 			n := 0 | ||||
| 			for _, param := range in { | ||||
| 				p := parseParam(param) | ||||
| 				if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil { | ||||
| 					args = append(args, "uintptr(unsafe.Pointer("+p.Name+"))") | ||||
| 				} else if p.Type == "string" && errvar != "" { | ||||
| 					text += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype) | ||||
| 					text += fmt.Sprintf("\t_p%d, %s = %s(%s)\n", n, errvar, strconvfunc, p.Name) | ||||
| 					text += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar) | ||||
| 					args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) | ||||
| 					n++ | ||||
| 				} else if p.Type == "string" { | ||||
| 					fmt.Fprintf(os.Stderr, path+":"+funct+" uses string arguments, but has no error return\n") | ||||
| 					text += fmt.Sprintf("\tvar _p%d %s\n", n, strconvtype) | ||||
| 					text += fmt.Sprintf("\t_p%d, _ = %s(%s)\n", n, strconvfunc, p.Name) | ||||
| 					args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n)) | ||||
| 					n++ | ||||
| 				} else if s := regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type); s != nil { | ||||
| 					// Convert slice into pointer, length.
 | ||||
| 					// Have to be careful not to take address of &a[0] if len == 0:
 | ||||
| 					// pass nil in that case.
 | ||||
| 					text += fmt.Sprintf("\tvar _p%d *%s\n", n, s[1]) | ||||
| 					text += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = &%s[0]\n\t}\n", p.Name, n, p.Name) | ||||
| 					args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n), fmt.Sprintf("uintptr(len(%s))", p.Name)) | ||||
| 					n++ | ||||
| 				} else if p.Type == "int64" && endianness != "" { | ||||
| 					if endianness == "big-endian" { | ||||
| 						args = append(args, fmt.Sprintf("uintptr(%s>>32)", p.Name), fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 					} else { | ||||
| 						args = append(args, fmt.Sprintf("uintptr(%s)", p.Name), fmt.Sprintf("uintptr(%s>>32)", p.Name)) | ||||
| 					} | ||||
| 				} else if p.Type == "bool" { | ||||
| 					text += fmt.Sprintf("\tvar _p%d uint32\n", n) | ||||
| 					text += fmt.Sprintf("\tif %s {\n\t\t_p%d = 1\n\t} else {\n\t\t_p%d = 0\n\t}\n", p.Name, n, n) | ||||
| 					args = append(args, fmt.Sprintf("uintptr(_p%d)", n)) | ||||
| 					n++ | ||||
| 				} else { | ||||
| 					args = append(args, fmt.Sprintf("uintptr(%s)", p.Name)) | ||||
| 				} | ||||
| 			} | ||||
| 			nargs := len(args) | ||||
| 
 | ||||
| 			// Determine which form to use; pad args with zeros.
 | ||||
| 			asm := "sysvicall6" | ||||
| 			if nonblock != nil { | ||||
| 				asm = "rawSysvicall6" | ||||
| 			} | ||||
| 			if len(args) <= 6 { | ||||
| 				for len(args) < 6 { | ||||
| 					args = append(args, "0") | ||||
| 				} | ||||
| 			} else { | ||||
| 				fmt.Fprintf(os.Stderr, "%s: too many arguments to system call\n", path) | ||||
| 				os.Exit(1) | ||||
| 			} | ||||
| 
 | ||||
| 			// Actual call.
 | ||||
| 			arglist := strings.Join(args, ", ") | ||||
| 			call := fmt.Sprintf("%s(uintptr(unsafe.Pointer(&%s)), %d, %s)", asm, sysvarname, nargs, arglist) | ||||
| 
 | ||||
| 			// Assign return values.
 | ||||
| 			body := "" | ||||
| 			ret := []string{"_", "_", "_"} | ||||
| 			doErrno := false | ||||
| 			for i := 0; i < len(out); i++ { | ||||
| 				p := parseParam(out[i]) | ||||
| 				reg := "" | ||||
| 				if p.Name == "err" { | ||||
| 					reg = "e1" | ||||
| 					ret[2] = reg | ||||
| 					doErrno = true | ||||
| 				} else { | ||||
| 					reg = fmt.Sprintf("r%d", i) | ||||
| 					ret[i] = reg | ||||
| 				} | ||||
| 				if p.Type == "bool" { | ||||
| 					reg = fmt.Sprintf("%d != 0", reg) | ||||
| 				} | ||||
| 				if p.Type == "int64" && endianness != "" { | ||||
| 					// 64-bit number in r1:r0 or r0:r1.
 | ||||
| 					if i+2 > len(out) { | ||||
| 						fmt.Fprintf(os.Stderr, "%s: not enough registers for int64 return\n", path) | ||||
| 						os.Exit(1) | ||||
| 					} | ||||
| 					if endianness == "big-endian" { | ||||
| 						reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i, i+1) | ||||
| 					} else { | ||||
| 						reg = fmt.Sprintf("int64(r%d)<<32 | int64(r%d)", i+1, i) | ||||
| 					} | ||||
| 					ret[i] = fmt.Sprintf("r%d", i) | ||||
| 					ret[i+1] = fmt.Sprintf("r%d", i+1) | ||||
| 				} | ||||
| 				if reg != "e1" { | ||||
| 					body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg) | ||||
| 				} | ||||
| 			} | ||||
| 			if ret[0] == "_" && ret[1] == "_" && ret[2] == "_" { | ||||
| 				text += fmt.Sprintf("\t%s\n", call) | ||||
| 			} else { | ||||
| 				text += fmt.Sprintf("\t%s, %s, %s := %s\n", ret[0], ret[1], ret[2], call) | ||||
| 			} | ||||
| 			text += body | ||||
| 
 | ||||
| 			if doErrno { | ||||
| 				text += "\tif e1 != 0 {\n" | ||||
| 				text += "\t\terr = e1\n" | ||||
| 				text += "\t}\n" | ||||
| 			} | ||||
| 			text += "\treturn\n" | ||||
| 			text += "}\n" | ||||
| 		} | ||||
| 		if err := s.Err(); err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		file.Close() | ||||
| 	} | ||||
| 	imp := "" | ||||
| 	if pack != "unix" { | ||||
| 		imp = "import \"golang.org/x/sys/unix\"\n" | ||||
| 
 | ||||
| 	} | ||||
| 	vardecls := "\t" + strings.Join(vars, ",\n\t") | ||||
| 	vardecls += " syscallFunc" | ||||
| 	fmt.Printf(srcTemplate, cmdLine(), buildTags(), pack, imp, dynimports, linknames, vardecls, text) | ||||
| } | ||||
| 
 | ||||
| const srcTemplate = `// %s
 | ||||
| // Code generated by the command above; see README.md. DO NOT EDIT.
 | ||||
| 
 | ||||
| // +build %s
 | ||||
| 
 | ||||
| package %s | ||||
| 
 | ||||
| import ( | ||||
| 	"syscall" | ||||
| 	"unsafe" | ||||
| ) | ||||
| %s | ||||
| %s | ||||
| %s | ||||
| var ( | ||||
| %s	 | ||||
| ) | ||||
| 
 | ||||
| %s | ||||
| ` | ||||
|  | @ -1,355 +0,0 @@ | |||
| // Copyright 2019 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| // Parse the header files for OpenBSD and generate a Go usable sysctl MIB.
 | ||||
| //
 | ||||
| // Build a MIB with each entry being an array containing the level, type and
 | ||||
| // a hash that will contain additional entries if the current entry is a node.
 | ||||
| // We then walk this MIB and create a flattened sysctl name to OID hash.
 | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	goos, goarch string | ||||
| ) | ||||
| 
 | ||||
| // cmdLine returns this programs's commandline arguments.
 | ||||
| func cmdLine() string { | ||||
| 	return "go run mksysctl_openbsd.go " + strings.Join(os.Args[1:], " ") | ||||
| } | ||||
| 
 | ||||
| // buildTags returns build tags.
 | ||||
| func buildTags() string { | ||||
| 	return fmt.Sprintf("%s,%s", goarch, goos) | ||||
| } | ||||
| 
 | ||||
| // reMatch performs regular expression match and stores the substring slice to value pointed by m.
 | ||||
| func reMatch(re *regexp.Regexp, str string, m *[]string) bool { | ||||
| 	*m = re.FindStringSubmatch(str) | ||||
| 	if *m != nil { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| type nodeElement struct { | ||||
| 	n  int | ||||
| 	t  string | ||||
| 	pE *map[string]nodeElement | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	debugEnabled bool | ||||
| 	mib          map[string]nodeElement | ||||
| 	node         *map[string]nodeElement | ||||
| 	nodeMap      map[string]string | ||||
| 	sysCtl       []string | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	ctlNames1RE = regexp.MustCompile(`^#define\s+(CTL_NAMES)\s+{`) | ||||
| 	ctlNames2RE = regexp.MustCompile(`^#define\s+(CTL_(.*)_NAMES)\s+{`) | ||||
| 	ctlNames3RE = regexp.MustCompile(`^#define\s+((.*)CTL_NAMES)\s+{`) | ||||
| 	netInetRE   = regexp.MustCompile(`^netinet/`) | ||||
| 	netInet6RE  = regexp.MustCompile(`^netinet6/`) | ||||
| 	netRE       = regexp.MustCompile(`^net/`) | ||||
| 	bracesRE    = regexp.MustCompile(`{.*}`) | ||||
| 	ctlTypeRE   = regexp.MustCompile(`{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}`) | ||||
| 	fsNetKernRE = regexp.MustCompile(`^(fs|net|kern)_`) | ||||
| ) | ||||
| 
 | ||||
| func debug(s string) { | ||||
| 	if debugEnabled { | ||||
| 		fmt.Fprintln(os.Stderr, s) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Walk the MIB and build a sysctl name to OID mapping.
 | ||||
| func buildSysctl(pNode *map[string]nodeElement, name string, oid []int) { | ||||
| 	lNode := pNode // local copy of pointer to node
 | ||||
| 	var keys []string | ||||
| 	for k := range *lNode { | ||||
| 		keys = append(keys, k) | ||||
| 	} | ||||
| 	sort.Strings(keys) | ||||
| 
 | ||||
| 	for _, key := range keys { | ||||
| 		nodename := name | ||||
| 		if name != "" { | ||||
| 			nodename += "." | ||||
| 		} | ||||
| 		nodename += key | ||||
| 
 | ||||
| 		nodeoid := append(oid, (*pNode)[key].n) | ||||
| 
 | ||||
| 		if (*pNode)[key].t == `CTLTYPE_NODE` { | ||||
| 			if _, ok := nodeMap[nodename]; ok { | ||||
| 				lNode = &mib | ||||
| 				ctlName := nodeMap[nodename] | ||||
| 				for _, part := range strings.Split(ctlName, ".") { | ||||
| 					lNode = ((*lNode)[part]).pE | ||||
| 				} | ||||
| 			} else { | ||||
| 				lNode = (*pNode)[key].pE | ||||
| 			} | ||||
| 			buildSysctl(lNode, nodename, nodeoid) | ||||
| 		} else if (*pNode)[key].t != "" { | ||||
| 			oidStr := []string{} | ||||
| 			for j := range nodeoid { | ||||
| 				oidStr = append(oidStr, fmt.Sprintf("%d", nodeoid[j])) | ||||
| 			} | ||||
| 			text := "\t{ \"" + nodename + "\", []_C_int{ " + strings.Join(oidStr, ", ") + " } }, \n" | ||||
| 			sysCtl = append(sysCtl, text) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	// Get the OS (using GOOS_TARGET if it exist)
 | ||||
| 	goos = os.Getenv("GOOS_TARGET") | ||||
| 	if goos == "" { | ||||
| 		goos = os.Getenv("GOOS") | ||||
| 	} | ||||
| 	// Get the architecture (using GOARCH_TARGET if it exists)
 | ||||
| 	goarch = os.Getenv("GOARCH_TARGET") | ||||
| 	if goarch == "" { | ||||
| 		goarch = os.Getenv("GOARCH") | ||||
| 	} | ||||
| 	// Check if GOOS and GOARCH environment variables are defined
 | ||||
| 	if goarch == "" || goos == "" { | ||||
| 		fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n") | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	mib = make(map[string]nodeElement) | ||||
| 	headers := [...]string{ | ||||
| 		`sys/sysctl.h`, | ||||
| 		`sys/socket.h`, | ||||
| 		`sys/tty.h`, | ||||
| 		`sys/malloc.h`, | ||||
| 		`sys/mount.h`, | ||||
| 		`sys/namei.h`, | ||||
| 		`sys/sem.h`, | ||||
| 		`sys/shm.h`, | ||||
| 		`sys/vmmeter.h`, | ||||
| 		`uvm/uvmexp.h`, | ||||
| 		`uvm/uvm_param.h`, | ||||
| 		`uvm/uvm_swap_encrypt.h`, | ||||
| 		`ddb/db_var.h`, | ||||
| 		`net/if.h`, | ||||
| 		`net/if_pfsync.h`, | ||||
| 		`net/pipex.h`, | ||||
| 		`netinet/in.h`, | ||||
| 		`netinet/icmp_var.h`, | ||||
| 		`netinet/igmp_var.h`, | ||||
| 		`netinet/ip_ah.h`, | ||||
| 		`netinet/ip_carp.h`, | ||||
| 		`netinet/ip_divert.h`, | ||||
| 		`netinet/ip_esp.h`, | ||||
| 		`netinet/ip_ether.h`, | ||||
| 		`netinet/ip_gre.h`, | ||||
| 		`netinet/ip_ipcomp.h`, | ||||
| 		`netinet/ip_ipip.h`, | ||||
| 		`netinet/pim_var.h`, | ||||
| 		`netinet/tcp_var.h`, | ||||
| 		`netinet/udp_var.h`, | ||||
| 		`netinet6/in6.h`, | ||||
| 		`netinet6/ip6_divert.h`, | ||||
| 		`netinet6/pim6_var.h`, | ||||
| 		`netinet/icmp6.h`, | ||||
| 		`netmpls/mpls.h`, | ||||
| 	} | ||||
| 
 | ||||
| 	ctls := [...]string{ | ||||
| 		`kern`, | ||||
| 		`vm`, | ||||
| 		`fs`, | ||||
| 		`net`, | ||||
| 		//debug			/* Special handling required */
 | ||||
| 		`hw`, | ||||
| 		//machdep		/* Arch specific */
 | ||||
| 		`user`, | ||||
| 		`ddb`, | ||||
| 		//vfs			/* Special handling required */
 | ||||
| 		`fs.posix`, | ||||
| 		`kern.forkstat`, | ||||
| 		`kern.intrcnt`, | ||||
| 		`kern.malloc`, | ||||
| 		`kern.nchstats`, | ||||
| 		`kern.seminfo`, | ||||
| 		`kern.shminfo`, | ||||
| 		`kern.timecounter`, | ||||
| 		`kern.tty`, | ||||
| 		`kern.watchdog`, | ||||
| 		`net.bpf`, | ||||
| 		`net.ifq`, | ||||
| 		`net.inet`, | ||||
| 		`net.inet.ah`, | ||||
| 		`net.inet.carp`, | ||||
| 		`net.inet.divert`, | ||||
| 		`net.inet.esp`, | ||||
| 		`net.inet.etherip`, | ||||
| 		`net.inet.gre`, | ||||
| 		`net.inet.icmp`, | ||||
| 		`net.inet.igmp`, | ||||
| 		`net.inet.ip`, | ||||
| 		`net.inet.ip.ifq`, | ||||
| 		`net.inet.ipcomp`, | ||||
| 		`net.inet.ipip`, | ||||
| 		`net.inet.mobileip`, | ||||
| 		`net.inet.pfsync`, | ||||
| 		`net.inet.pim`, | ||||
| 		`net.inet.tcp`, | ||||
| 		`net.inet.udp`, | ||||
| 		`net.inet6`, | ||||
| 		`net.inet6.divert`, | ||||
| 		`net.inet6.ip6`, | ||||
| 		`net.inet6.icmp6`, | ||||
| 		`net.inet6.pim6`, | ||||
| 		`net.inet6.tcp6`, | ||||
| 		`net.inet6.udp6`, | ||||
| 		`net.mpls`, | ||||
| 		`net.mpls.ifq`, | ||||
| 		`net.key`, | ||||
| 		`net.pflow`, | ||||
| 		`net.pfsync`, | ||||
| 		`net.pipex`, | ||||
| 		`net.rt`, | ||||
| 		`vm.swapencrypt`, | ||||
| 		//vfsgenctl		/* Special handling required */
 | ||||
| 	} | ||||
| 
 | ||||
| 	// Node name "fixups"
 | ||||
| 	ctlMap := map[string]string{ | ||||
| 		"ipproto":             "net.inet", | ||||
| 		"net.inet.ipproto":    "net.inet", | ||||
| 		"net.inet6.ipv6proto": "net.inet6", | ||||
| 		"net.inet6.ipv6":      "net.inet6.ip6", | ||||
| 		"net.inet.icmpv6":     "net.inet6.icmp6", | ||||
| 		"net.inet6.divert6":   "net.inet6.divert", | ||||
| 		"net.inet6.tcp6":      "net.inet.tcp", | ||||
| 		"net.inet6.udp6":      "net.inet.udp", | ||||
| 		"mpls":                "net.mpls", | ||||
| 		"swpenc":              "vm.swapencrypt", | ||||
| 	} | ||||
| 
 | ||||
| 	// Node mappings
 | ||||
| 	nodeMap = map[string]string{ | ||||
| 		"net.inet.ip.ifq": "net.ifq", | ||||
| 		"net.inet.pfsync": "net.pfsync", | ||||
| 		"net.mpls.ifq":    "net.ifq", | ||||
| 	} | ||||
| 
 | ||||
| 	mCtls := make(map[string]bool) | ||||
| 	for _, ctl := range ctls { | ||||
| 		mCtls[ctl] = true | ||||
| 	} | ||||
| 
 | ||||
| 	for _, header := range headers { | ||||
| 		debug("Processing " + header) | ||||
| 		file, err := os.Open(filepath.Join("/usr/include", header)) | ||||
| 		if err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, "%v\n", err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		s := bufio.NewScanner(file) | ||||
| 		for s.Scan() { | ||||
| 			var sub []string | ||||
| 			if reMatch(ctlNames1RE, s.Text(), &sub) || | ||||
| 				reMatch(ctlNames2RE, s.Text(), &sub) || | ||||
| 				reMatch(ctlNames3RE, s.Text(), &sub) { | ||||
| 				if sub[1] == `CTL_NAMES` { | ||||
| 					// Top level.
 | ||||
| 					node = &mib | ||||
| 				} else { | ||||
| 					// Node.
 | ||||
| 					nodename := strings.ToLower(sub[2]) | ||||
| 					ctlName := "" | ||||
| 					if reMatch(netInetRE, header, &sub) { | ||||
| 						ctlName = "net.inet." + nodename | ||||
| 					} else if reMatch(netInet6RE, header, &sub) { | ||||
| 						ctlName = "net.inet6." + nodename | ||||
| 					} else if reMatch(netRE, header, &sub) { | ||||
| 						ctlName = "net." + nodename | ||||
| 					} else { | ||||
| 						ctlName = nodename | ||||
| 						ctlName = fsNetKernRE.ReplaceAllString(ctlName, `$1.`) | ||||
| 					} | ||||
| 
 | ||||
| 					if val, ok := ctlMap[ctlName]; ok { | ||||
| 						ctlName = val | ||||
| 					} | ||||
| 					if _, ok := mCtls[ctlName]; !ok { | ||||
| 						debug("Ignoring " + ctlName + "...") | ||||
| 						continue | ||||
| 					} | ||||
| 
 | ||||
| 					// Walk down from the top of the MIB.
 | ||||
| 					node = &mib | ||||
| 					for _, part := range strings.Split(ctlName, ".") { | ||||
| 						if _, ok := (*node)[part]; !ok { | ||||
| 							debug("Missing node " + part) | ||||
| 							(*node)[part] = nodeElement{n: 0, t: "", pE: &map[string]nodeElement{}} | ||||
| 						} | ||||
| 						node = (*node)[part].pE | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				// Populate current node with entries.
 | ||||
| 				i := -1 | ||||
| 				for !strings.HasPrefix(s.Text(), "}") { | ||||
| 					s.Scan() | ||||
| 					if reMatch(bracesRE, s.Text(), &sub) { | ||||
| 						i++ | ||||
| 					} | ||||
| 					if !reMatch(ctlTypeRE, s.Text(), &sub) { | ||||
| 						continue | ||||
| 					} | ||||
| 					(*node)[sub[1]] = nodeElement{n: i, t: sub[2], pE: &map[string]nodeElement{}} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		err = s.Err() | ||||
| 		if err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, "%v\n", err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		file.Close() | ||||
| 	} | ||||
| 	buildSysctl(&mib, "", []int{}) | ||||
| 
 | ||||
| 	sort.Strings(sysCtl) | ||||
| 	text := strings.Join(sysCtl, "") | ||||
| 
 | ||||
| 	fmt.Printf(srcTemplate, cmdLine(), buildTags(), text) | ||||
| } | ||||
| 
 | ||||
| const srcTemplate = `// %s
 | ||||
| // Code generated by the command above; DO NOT EDIT.
 | ||||
| 
 | ||||
| // +build %s
 | ||||
| 
 | ||||
| package unix | ||||
| 
 | ||||
| type mibentry struct { | ||||
| 	ctlname string | ||||
| 	ctloid []_C_int | ||||
| } | ||||
| 
 | ||||
| var sysctlMib = []mibentry { | ||||
| %s | ||||
| } | ||||
| ` | ||||
|  | @ -1,190 +0,0 @@ | |||
| // Copyright 2018 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| // Generate system call table for DragonFly, NetBSD,
 | ||||
| // FreeBSD, OpenBSD or Darwin from master list
 | ||||
| // (for example, /usr/src/sys/kern/syscalls.master or
 | ||||
| // sys/syscall.h).
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	goos, goarch string | ||||
| ) | ||||
| 
 | ||||
| // cmdLine returns this programs's commandline arguments
 | ||||
| func cmdLine() string { | ||||
| 	return "go run mksysnum.go " + strings.Join(os.Args[1:], " ") | ||||
| } | ||||
| 
 | ||||
| // buildTags returns build tags
 | ||||
| func buildTags() string { | ||||
| 	return fmt.Sprintf("%s,%s", goarch, goos) | ||||
| } | ||||
| 
 | ||||
| func checkErr(err error) { | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "%v\n", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // source string and substring slice for regexp
 | ||||
| type re struct { | ||||
| 	str string   // source string
 | ||||
| 	sub []string // matched sub-string
 | ||||
| } | ||||
| 
 | ||||
| // Match performs regular expression match
 | ||||
| func (r *re) Match(exp string) bool { | ||||
| 	r.sub = regexp.MustCompile(exp).FindStringSubmatch(r.str) | ||||
| 	if r.sub != nil { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // fetchFile fetches a text file from URL
 | ||||
| func fetchFile(URL string) io.Reader { | ||||
| 	resp, err := http.Get(URL) | ||||
| 	checkErr(err) | ||||
| 	defer resp.Body.Close() | ||||
| 	body, err := ioutil.ReadAll(resp.Body) | ||||
| 	checkErr(err) | ||||
| 	return strings.NewReader(string(body)) | ||||
| } | ||||
| 
 | ||||
| // readFile reads a text file from path
 | ||||
| func readFile(path string) io.Reader { | ||||
| 	file, err := os.Open(os.Args[1]) | ||||
| 	checkErr(err) | ||||
| 	return file | ||||
| } | ||||
| 
 | ||||
| func format(name, num, proto string) string { | ||||
| 	name = strings.ToUpper(name) | ||||
| 	// There are multiple entries for enosys and nosys, so comment them out.
 | ||||
| 	nm := re{str: name} | ||||
| 	if nm.Match(`^SYS_E?NOSYS$`) { | ||||
| 		name = fmt.Sprintf("// %s", name) | ||||
| 	} | ||||
| 	if name == `SYS_SYS_EXIT` { | ||||
| 		name = `SYS_EXIT` | ||||
| 	} | ||||
| 	return fmt.Sprintf("	%s = %s;  // %s\n", name, num, proto) | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	// Get the OS (using GOOS_TARGET if it exist)
 | ||||
| 	goos = os.Getenv("GOOS_TARGET") | ||||
| 	if goos == "" { | ||||
| 		goos = os.Getenv("GOOS") | ||||
| 	} | ||||
| 	// Get the architecture (using GOARCH_TARGET if it exists)
 | ||||
| 	goarch = os.Getenv("GOARCH_TARGET") | ||||
| 	if goarch == "" { | ||||
| 		goarch = os.Getenv("GOARCH") | ||||
| 	} | ||||
| 	// Check if GOOS and GOARCH environment variables are defined
 | ||||
| 	if goarch == "" || goos == "" { | ||||
| 		fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n") | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	file := strings.TrimSpace(os.Args[1]) | ||||
| 	var syscalls io.Reader | ||||
| 	if strings.HasPrefix(file, "https://") || strings.HasPrefix(file, "http://") { | ||||
| 		// Download syscalls.master file
 | ||||
| 		syscalls = fetchFile(file) | ||||
| 	} else { | ||||
| 		syscalls = readFile(file) | ||||
| 	} | ||||
| 
 | ||||
| 	var text, line string | ||||
| 	s := bufio.NewScanner(syscalls) | ||||
| 	for s.Scan() { | ||||
| 		t := re{str: line} | ||||
| 		if t.Match(`^(.*)\\$`) { | ||||
| 			// Handle continuation
 | ||||
| 			line = t.sub[1] | ||||
| 			line += strings.TrimLeft(s.Text(), " \t") | ||||
| 		} else { | ||||
| 			// New line
 | ||||
| 			line = s.Text() | ||||
| 		} | ||||
| 		t = re{str: line} | ||||
| 		if t.Match(`\\$`) { | ||||
| 			continue | ||||
| 		} | ||||
| 		t = re{str: line} | ||||
| 
 | ||||
| 		switch goos { | ||||
| 		case "dragonfly": | ||||
| 			if t.Match(`^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$`) { | ||||
| 				num, proto := t.sub[1], t.sub[2] | ||||
| 				name := fmt.Sprintf("SYS_%s", t.sub[3]) | ||||
| 				text += format(name, num, proto) | ||||
| 			} | ||||
| 		case "freebsd": | ||||
| 			if t.Match(`^([0-9]+)\s+\S+\s+(?:NO)?STD\s+({ \S+\s+(\w+).*)$`) { | ||||
| 				num, proto := t.sub[1], t.sub[2] | ||||
| 				name := fmt.Sprintf("SYS_%s", t.sub[3]) | ||||
| 				text += format(name, num, proto) | ||||
| 			} | ||||
| 		case "openbsd": | ||||
| 			if t.Match(`^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$`) { | ||||
| 				num, proto, name := t.sub[1], t.sub[3], t.sub[4] | ||||
| 				text += format(name, num, proto) | ||||
| 			} | ||||
| 		case "netbsd": | ||||
| 			if t.Match(`^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$`) { | ||||
| 				num, proto, compat := t.sub[1], t.sub[6], t.sub[8] | ||||
| 				name := t.sub[7] + "_" + t.sub[9] | ||||
| 				if t.sub[11] != "" { | ||||
| 					name = t.sub[7] + "_" + t.sub[11] | ||||
| 				} | ||||
| 				name = strings.ToUpper(name) | ||||
| 				if compat == "" || compat == "13" || compat == "30" || compat == "50" { | ||||
| 					text += fmt.Sprintf("	%s = %s;  // %s\n", name, num, proto) | ||||
| 				} | ||||
| 			} | ||||
| 		case "darwin": | ||||
| 			if t.Match(`^#define\s+SYS_(\w+)\s+([0-9]+)`) { | ||||
| 				name, num := t.sub[1], t.sub[2] | ||||
| 				name = strings.ToUpper(name) | ||||
| 				text += fmt.Sprintf("	SYS_%s = %s;\n", name, num) | ||||
| 			} | ||||
| 		default: | ||||
| 			fmt.Fprintf(os.Stderr, "unrecognized GOOS=%s\n", goos) | ||||
| 			os.Exit(1) | ||||
| 
 | ||||
| 		} | ||||
| 	} | ||||
| 	err := s.Err() | ||||
| 	checkErr(err) | ||||
| 
 | ||||
| 	fmt.Printf(template, cmdLine(), buildTags(), text) | ||||
| } | ||||
| 
 | ||||
| const template = `// %s
 | ||||
| // Code generated by the command above; see README.md. DO NOT EDIT.
 | ||||
| 
 | ||||
| // +build %s
 | ||||
| 
 | ||||
| package unix | ||||
| 
 | ||||
| const( | ||||
| %s)` | ||||
|  | @ -1,237 +0,0 @@ | |||
| // Copyright 2018 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| // +build aix
 | ||||
| 
 | ||||
| /* | ||||
| Input to cgo -godefs.  See also mkerrors.sh and mkall.sh | ||||
| */ | ||||
| 
 | ||||
| // +godefs map struct_in_addr [4]byte /* in_addr */
 | ||||
| // +godefs map struct_in6_addr [16]byte /* in6_addr */
 | ||||
| 
 | ||||
| package unix | ||||
| 
 | ||||
| /* | ||||
| #include <sys/types.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/limits.h> | ||||
| #include <sys/un.h> | ||||
| #include <utime.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/poll.h> | ||||
| #include <sys/resource.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/statfs.h> | ||||
| #include <sys/termio.h> | ||||
| #include <sys/ioctl.h> | ||||
| 
 | ||||
| #include <termios.h> | ||||
| 
 | ||||
| #include <net/if.h> | ||||
| #include <net/if_dl.h> | ||||
| #include <netinet/in.h> | ||||
| #include <netinet/icmp6.h> | ||||
| 
 | ||||
| 
 | ||||
| #include <dirent.h> | ||||
| #include <fcntl.h> | ||||
| 
 | ||||
| enum { | ||||
| 	sizeofPtr = sizeof(void*), | ||||
| }; | ||||
| 
 | ||||
| union sockaddr_all { | ||||
| 	struct sockaddr s1;     // this one gets used for fields
 | ||||
| 	struct sockaddr_in s2;  // these pad it out
 | ||||
| 	struct sockaddr_in6 s3; | ||||
| 	struct sockaddr_un s4; | ||||
| 	struct sockaddr_dl s5; | ||||
| }; | ||||
| 
 | ||||
| struct sockaddr_any { | ||||
| 	struct sockaddr addr; | ||||
| 	char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; | ||||
| }; | ||||
| 
 | ||||
| */ | ||||
| import "C" | ||||
| 
 | ||||
| // Machine characteristics
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofPtr      = C.sizeofPtr | ||||
| 	SizeofShort    = C.sizeof_short | ||||
| 	SizeofInt      = C.sizeof_int | ||||
| 	SizeofLong     = C.sizeof_long | ||||
| 	SizeofLongLong = C.sizeof_longlong | ||||
| 	PathMax        = C.PATH_MAX | ||||
| ) | ||||
| 
 | ||||
| // Basic types
 | ||||
| 
 | ||||
| type ( | ||||
| 	_C_short     C.short | ||||
| 	_C_int       C.int | ||||
| 	_C_long      C.long | ||||
| 	_C_long_long C.longlong | ||||
| ) | ||||
| 
 | ||||
| type off64 C.off64_t | ||||
| type off C.off_t | ||||
| type Mode_t C.mode_t | ||||
| 
 | ||||
| // Time
 | ||||
| 
 | ||||
| type Timespec C.struct_timespec | ||||
| 
 | ||||
| type Timeval C.struct_timeval | ||||
| 
 | ||||
| type Timeval32 C.struct_timeval32 | ||||
| 
 | ||||
| type Timex C.struct_timex | ||||
| 
 | ||||
| type Time_t C.time_t | ||||
| 
 | ||||
| type Tms C.struct_tms | ||||
| 
 | ||||
| type Utimbuf C.struct_utimbuf | ||||
| 
 | ||||
| type Timezone C.struct_timezone | ||||
| 
 | ||||
| // Processes
 | ||||
| 
 | ||||
| type Rusage C.struct_rusage | ||||
| 
 | ||||
| type Rlimit C.struct_rlimit64 | ||||
| 
 | ||||
| type Pid_t C.pid_t | ||||
| 
 | ||||
| type _Gid_t C.gid_t | ||||
| 
 | ||||
| type dev_t C.dev_t | ||||
| 
 | ||||
| // Files
 | ||||
| 
 | ||||
| type Stat_t C.struct_stat | ||||
| 
 | ||||
| type StatxTimestamp C.struct_statx_timestamp | ||||
| 
 | ||||
| type Statx_t C.struct_statx | ||||
| 
 | ||||
| type Dirent C.struct_dirent | ||||
| 
 | ||||
| // Sockets
 | ||||
| 
 | ||||
| type RawSockaddrInet4 C.struct_sockaddr_in | ||||
| 
 | ||||
| type RawSockaddrInet6 C.struct_sockaddr_in6 | ||||
| 
 | ||||
| type RawSockaddrUnix C.struct_sockaddr_un | ||||
| 
 | ||||
| type RawSockaddrDatalink C.struct_sockaddr_dl | ||||
| 
 | ||||
| type RawSockaddr C.struct_sockaddr | ||||
| 
 | ||||
| type RawSockaddrAny C.struct_sockaddr_any | ||||
| 
 | ||||
| type _Socklen C.socklen_t | ||||
| 
 | ||||
| type Cmsghdr C.struct_cmsghdr | ||||
| 
 | ||||
| type ICMPv6Filter C.struct_icmp6_filter | ||||
| 
 | ||||
| type Iovec C.struct_iovec | ||||
| 
 | ||||
| type IPMreq C.struct_ip_mreq | ||||
| 
 | ||||
| type IPv6Mreq C.struct_ipv6_mreq | ||||
| 
 | ||||
| type IPv6MTUInfo C.struct_ip6_mtuinfo | ||||
| 
 | ||||
| type Linger C.struct_linger | ||||
| 
 | ||||
| type Msghdr C.struct_msghdr | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofSockaddrInet4    = C.sizeof_struct_sockaddr_in | ||||
| 	SizeofSockaddrInet6    = C.sizeof_struct_sockaddr_in6 | ||||
| 	SizeofSockaddrAny      = C.sizeof_struct_sockaddr_any | ||||
| 	SizeofSockaddrUnix     = C.sizeof_struct_sockaddr_un | ||||
| 	SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl | ||||
| 	SizeofLinger           = C.sizeof_struct_linger | ||||
| 	SizeofIPMreq           = C.sizeof_struct_ip_mreq | ||||
| 	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq | ||||
| 	SizeofIPv6MTUInfo      = C.sizeof_struct_ip6_mtuinfo | ||||
| 	SizeofMsghdr           = C.sizeof_struct_msghdr | ||||
| 	SizeofCmsghdr          = C.sizeof_struct_cmsghdr | ||||
| 	SizeofICMPv6Filter     = C.sizeof_struct_icmp6_filter | ||||
| ) | ||||
| 
 | ||||
| // Routing and interface messages
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofIfMsghdr = C.sizeof_struct_if_msghdr | ||||
| ) | ||||
| 
 | ||||
| type IfMsgHdr C.struct_if_msghdr | ||||
| 
 | ||||
| // Misc
 | ||||
| 
 | ||||
| type FdSet C.fd_set | ||||
| 
 | ||||
| type Utsname C.struct_utsname | ||||
| 
 | ||||
| type Ustat_t C.struct_ustat | ||||
| 
 | ||||
| type Sigset_t C.sigset_t | ||||
| 
 | ||||
| const ( | ||||
| 	AT_FDCWD            = C.AT_FDCWD | ||||
| 	AT_REMOVEDIR        = C.AT_REMOVEDIR | ||||
| 	AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW | ||||
| ) | ||||
| 
 | ||||
| // Terminal handling
 | ||||
| 
 | ||||
| type Termios C.struct_termios | ||||
| 
 | ||||
| type Termio C.struct_termio | ||||
| 
 | ||||
| type Winsize C.struct_winsize | ||||
| 
 | ||||
| //poll
 | ||||
| 
 | ||||
| type PollFd struct { | ||||
| 	Fd      int32 | ||||
| 	Events  uint16 | ||||
| 	Revents uint16 | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
| 	POLLERR    = C.POLLERR | ||||
| 	POLLHUP    = C.POLLHUP | ||||
| 	POLLIN     = C.POLLIN | ||||
| 	POLLNVAL   = C.POLLNVAL | ||||
| 	POLLOUT    = C.POLLOUT | ||||
| 	POLLPRI    = C.POLLPRI | ||||
| 	POLLRDBAND = C.POLLRDBAND | ||||
| 	POLLRDNORM = C.POLLRDNORM | ||||
| 	POLLWRBAND = C.POLLWRBAND | ||||
| 	POLLWRNORM = C.POLLWRNORM | ||||
| ) | ||||
| 
 | ||||
| //flock_t
 | ||||
| 
 | ||||
| type Flock_t C.struct_flock64 | ||||
| 
 | ||||
| // Statfs
 | ||||
| 
 | ||||
| type Fsid_t C.struct_fsid_t | ||||
| type Fsid64_t C.struct_fsid64_t | ||||
| 
 | ||||
| type Statfs_t C.struct_statfs | ||||
| 
 | ||||
| const RNDGETENTCNT = 0x80045200 | ||||
|  | @ -1,283 +0,0 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| /* | ||||
| Input to cgo -godefs.  See README.md | ||||
| */ | ||||
| 
 | ||||
| // +godefs map struct_in_addr [4]byte /* in_addr */
 | ||||
| // +godefs map struct_in6_addr [16]byte /* in6_addr */
 | ||||
| 
 | ||||
| package unix | ||||
| 
 | ||||
| /* | ||||
| #define __DARWIN_UNIX03 0 | ||||
| #define KERNEL | ||||
| #define _DARWIN_USE_64_BIT_INODE | ||||
| #include <dirent.h> | ||||
| #include <fcntl.h> | ||||
| #include <poll.h> | ||||
| #include <signal.h> | ||||
| #include <termios.h> | ||||
| #include <unistd.h> | ||||
| #include <mach/mach.h> | ||||
| #include <mach/message.h> | ||||
| #include <sys/event.h> | ||||
| #include <sys/mman.h> | ||||
| #include <sys/mount.h> | ||||
| #include <sys/param.h> | ||||
| #include <sys/ptrace.h> | ||||
| #include <sys/resource.h> | ||||
| #include <sys/select.h> | ||||
| #include <sys/signal.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/uio.h> | ||||
| #include <sys/un.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/wait.h> | ||||
| #include <net/bpf.h> | ||||
| #include <net/if.h> | ||||
| #include <net/if_dl.h> | ||||
| #include <net/if_var.h> | ||||
| #include <net/route.h> | ||||
| #include <netinet/in.h> | ||||
| #include <netinet/icmp6.h> | ||||
| #include <netinet/tcp.h> | ||||
| 
 | ||||
| enum { | ||||
| 	sizeofPtr = sizeof(void*), | ||||
| }; | ||||
| 
 | ||||
| union sockaddr_all { | ||||
| 	struct sockaddr s1;	// this one gets used for fields
 | ||||
| 	struct sockaddr_in s2;	// these pad it out
 | ||||
| 	struct sockaddr_in6 s3; | ||||
| 	struct sockaddr_un s4; | ||||
| 	struct sockaddr_dl s5; | ||||
| }; | ||||
| 
 | ||||
| struct sockaddr_any { | ||||
| 	struct sockaddr addr; | ||||
| 	char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; | ||||
| }; | ||||
| 
 | ||||
| */ | ||||
| import "C" | ||||
| 
 | ||||
| // Machine characteristics
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofPtr      = C.sizeofPtr | ||||
| 	SizeofShort    = C.sizeof_short | ||||
| 	SizeofInt      = C.sizeof_int | ||||
| 	SizeofLong     = C.sizeof_long | ||||
| 	SizeofLongLong = C.sizeof_longlong | ||||
| ) | ||||
| 
 | ||||
| // Basic types
 | ||||
| 
 | ||||
| type ( | ||||
| 	_C_short     C.short | ||||
| 	_C_int       C.int | ||||
| 	_C_long      C.long | ||||
| 	_C_long_long C.longlong | ||||
| ) | ||||
| 
 | ||||
| // Time
 | ||||
| 
 | ||||
| type Timespec C.struct_timespec | ||||
| 
 | ||||
| type Timeval C.struct_timeval | ||||
| 
 | ||||
| type Timeval32 C.struct_timeval32 | ||||
| 
 | ||||
| // Processes
 | ||||
| 
 | ||||
| type Rusage C.struct_rusage | ||||
| 
 | ||||
| type Rlimit C.struct_rlimit | ||||
| 
 | ||||
| type _Gid_t C.gid_t | ||||
| 
 | ||||
| // Files
 | ||||
| 
 | ||||
| type Stat_t C.struct_stat64 | ||||
| 
 | ||||
| type Statfs_t C.struct_statfs64 | ||||
| 
 | ||||
| type Flock_t C.struct_flock | ||||
| 
 | ||||
| type Fstore_t C.struct_fstore | ||||
| 
 | ||||
| type Radvisory_t C.struct_radvisory | ||||
| 
 | ||||
| type Fbootstraptransfer_t C.struct_fbootstraptransfer | ||||
| 
 | ||||
| type Log2phys_t C.struct_log2phys | ||||
| 
 | ||||
| type Fsid C.struct_fsid | ||||
| 
 | ||||
| type Dirent C.struct_dirent | ||||
| 
 | ||||
| // Sockets
 | ||||
| 
 | ||||
| type RawSockaddrInet4 C.struct_sockaddr_in | ||||
| 
 | ||||
| type RawSockaddrInet6 C.struct_sockaddr_in6 | ||||
| 
 | ||||
| type RawSockaddrUnix C.struct_sockaddr_un | ||||
| 
 | ||||
| type RawSockaddrDatalink C.struct_sockaddr_dl | ||||
| 
 | ||||
| type RawSockaddr C.struct_sockaddr | ||||
| 
 | ||||
| type RawSockaddrAny C.struct_sockaddr_any | ||||
| 
 | ||||
| type _Socklen C.socklen_t | ||||
| 
 | ||||
| type Linger C.struct_linger | ||||
| 
 | ||||
| type Iovec C.struct_iovec | ||||
| 
 | ||||
| type IPMreq C.struct_ip_mreq | ||||
| 
 | ||||
| type IPv6Mreq C.struct_ipv6_mreq | ||||
| 
 | ||||
| type Msghdr C.struct_msghdr | ||||
| 
 | ||||
| type Cmsghdr C.struct_cmsghdr | ||||
| 
 | ||||
| type Inet4Pktinfo C.struct_in_pktinfo | ||||
| 
 | ||||
| type Inet6Pktinfo C.struct_in6_pktinfo | ||||
| 
 | ||||
| type IPv6MTUInfo C.struct_ip6_mtuinfo | ||||
| 
 | ||||
| type ICMPv6Filter C.struct_icmp6_filter | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofSockaddrInet4    = C.sizeof_struct_sockaddr_in | ||||
| 	SizeofSockaddrInet6    = C.sizeof_struct_sockaddr_in6 | ||||
| 	SizeofSockaddrAny      = C.sizeof_struct_sockaddr_any | ||||
| 	SizeofSockaddrUnix     = C.sizeof_struct_sockaddr_un | ||||
| 	SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl | ||||
| 	SizeofLinger           = C.sizeof_struct_linger | ||||
| 	SizeofIPMreq           = C.sizeof_struct_ip_mreq | ||||
| 	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq | ||||
| 	SizeofMsghdr           = C.sizeof_struct_msghdr | ||||
| 	SizeofCmsghdr          = C.sizeof_struct_cmsghdr | ||||
| 	SizeofInet4Pktinfo     = C.sizeof_struct_in_pktinfo | ||||
| 	SizeofInet6Pktinfo     = C.sizeof_struct_in6_pktinfo | ||||
| 	SizeofIPv6MTUInfo      = C.sizeof_struct_ip6_mtuinfo | ||||
| 	SizeofICMPv6Filter     = C.sizeof_struct_icmp6_filter | ||||
| ) | ||||
| 
 | ||||
| // Ptrace requests
 | ||||
| 
 | ||||
| const ( | ||||
| 	PTRACE_TRACEME = C.PT_TRACE_ME | ||||
| 	PTRACE_CONT    = C.PT_CONTINUE | ||||
| 	PTRACE_KILL    = C.PT_KILL | ||||
| ) | ||||
| 
 | ||||
| // Events (kqueue, kevent)
 | ||||
| 
 | ||||
| type Kevent_t C.struct_kevent | ||||
| 
 | ||||
| // Select
 | ||||
| 
 | ||||
| type FdSet C.fd_set | ||||
| 
 | ||||
| // Routing and interface messages
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofIfMsghdr    = C.sizeof_struct_if_msghdr | ||||
| 	SizeofIfData      = C.sizeof_struct_if_data | ||||
| 	SizeofIfaMsghdr   = C.sizeof_struct_ifa_msghdr | ||||
| 	SizeofIfmaMsghdr  = C.sizeof_struct_ifma_msghdr | ||||
| 	SizeofIfmaMsghdr2 = C.sizeof_struct_ifma_msghdr2 | ||||
| 	SizeofRtMsghdr    = C.sizeof_struct_rt_msghdr | ||||
| 	SizeofRtMetrics   = C.sizeof_struct_rt_metrics | ||||
| ) | ||||
| 
 | ||||
| type IfMsghdr C.struct_if_msghdr | ||||
| 
 | ||||
| type IfData C.struct_if_data | ||||
| 
 | ||||
| type IfaMsghdr C.struct_ifa_msghdr | ||||
| 
 | ||||
| type IfmaMsghdr C.struct_ifma_msghdr | ||||
| 
 | ||||
| type IfmaMsghdr2 C.struct_ifma_msghdr2 | ||||
| 
 | ||||
| type RtMsghdr C.struct_rt_msghdr | ||||
| 
 | ||||
| type RtMetrics C.struct_rt_metrics | ||||
| 
 | ||||
| // Berkeley packet filter
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofBpfVersion = C.sizeof_struct_bpf_version | ||||
| 	SizeofBpfStat    = C.sizeof_struct_bpf_stat | ||||
| 	SizeofBpfProgram = C.sizeof_struct_bpf_program | ||||
| 	SizeofBpfInsn    = C.sizeof_struct_bpf_insn | ||||
| 	SizeofBpfHdr     = C.sizeof_struct_bpf_hdr | ||||
| ) | ||||
| 
 | ||||
| type BpfVersion C.struct_bpf_version | ||||
| 
 | ||||
| type BpfStat C.struct_bpf_stat | ||||
| 
 | ||||
| type BpfProgram C.struct_bpf_program | ||||
| 
 | ||||
| type BpfInsn C.struct_bpf_insn | ||||
| 
 | ||||
| type BpfHdr C.struct_bpf_hdr | ||||
| 
 | ||||
| // Terminal handling
 | ||||
| 
 | ||||
| type Termios C.struct_termios | ||||
| 
 | ||||
| type Winsize C.struct_winsize | ||||
| 
 | ||||
| // fchmodat-like syscalls.
 | ||||
| 
 | ||||
| const ( | ||||
| 	AT_FDCWD            = C.AT_FDCWD | ||||
| 	AT_REMOVEDIR        = C.AT_REMOVEDIR | ||||
| 	AT_SYMLINK_FOLLOW   = C.AT_SYMLINK_FOLLOW | ||||
| 	AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW | ||||
| ) | ||||
| 
 | ||||
| // poll
 | ||||
| 
 | ||||
| type PollFd C.struct_pollfd | ||||
| 
 | ||||
| const ( | ||||
| 	POLLERR    = C.POLLERR | ||||
| 	POLLHUP    = C.POLLHUP | ||||
| 	POLLIN     = C.POLLIN | ||||
| 	POLLNVAL   = C.POLLNVAL | ||||
| 	POLLOUT    = C.POLLOUT | ||||
| 	POLLPRI    = C.POLLPRI | ||||
| 	POLLRDBAND = C.POLLRDBAND | ||||
| 	POLLRDNORM = C.POLLRDNORM | ||||
| 	POLLWRBAND = C.POLLWRBAND | ||||
| 	POLLWRNORM = C.POLLWRNORM | ||||
| ) | ||||
| 
 | ||||
| // uname
 | ||||
| 
 | ||||
| type Utsname C.struct_utsname | ||||
| 
 | ||||
| // Clockinfo
 | ||||
| 
 | ||||
| const SizeofClockinfo = C.sizeof_struct_clockinfo | ||||
| 
 | ||||
| type Clockinfo C.struct_clockinfo | ||||
|  | @ -1,263 +0,0 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| /* | ||||
| Input to cgo -godefs.  See README.md | ||||
| */ | ||||
| 
 | ||||
| // +godefs map struct_in_addr [4]byte /* in_addr */
 | ||||
| // +godefs map struct_in6_addr [16]byte /* in6_addr */
 | ||||
| 
 | ||||
| package unix | ||||
| 
 | ||||
| /* | ||||
| #define KERNEL | ||||
| #include <dirent.h> | ||||
| #include <fcntl.h> | ||||
| #include <poll.h> | ||||
| #include <signal.h> | ||||
| #include <termios.h> | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/event.h> | ||||
| #include <sys/mman.h> | ||||
| #include <sys/mount.h> | ||||
| #include <sys/param.h> | ||||
| #include <sys/ptrace.h> | ||||
| #include <sys/resource.h> | ||||
| #include <sys/select.h> | ||||
| #include <sys/signal.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/un.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/wait.h> | ||||
| #include <net/bpf.h> | ||||
| #include <net/if.h> | ||||
| #include <net/if_dl.h> | ||||
| #include <net/route.h> | ||||
| #include <netinet/in.h> | ||||
| #include <netinet/icmp6.h> | ||||
| #include <netinet/tcp.h> | ||||
| 
 | ||||
| enum { | ||||
| 	sizeofPtr = sizeof(void*), | ||||
| }; | ||||
| 
 | ||||
| union sockaddr_all { | ||||
| 	struct sockaddr s1;	// this one gets used for fields
 | ||||
| 	struct sockaddr_in s2;	// these pad it out
 | ||||
| 	struct sockaddr_in6 s3; | ||||
| 	struct sockaddr_un s4; | ||||
| 	struct sockaddr_dl s5; | ||||
| }; | ||||
| 
 | ||||
| struct sockaddr_any { | ||||
| 	struct sockaddr addr; | ||||
| 	char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; | ||||
| }; | ||||
| 
 | ||||
| */ | ||||
| import "C" | ||||
| 
 | ||||
| // Machine characteristics
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofPtr      = C.sizeofPtr | ||||
| 	SizeofShort    = C.sizeof_short | ||||
| 	SizeofInt      = C.sizeof_int | ||||
| 	SizeofLong     = C.sizeof_long | ||||
| 	SizeofLongLong = C.sizeof_longlong | ||||
| ) | ||||
| 
 | ||||
| // Basic types
 | ||||
| 
 | ||||
| type ( | ||||
| 	_C_short     C.short | ||||
| 	_C_int       C.int | ||||
| 	_C_long      C.long | ||||
| 	_C_long_long C.longlong | ||||
| ) | ||||
| 
 | ||||
| // Time
 | ||||
| 
 | ||||
| type Timespec C.struct_timespec | ||||
| 
 | ||||
| type Timeval C.struct_timeval | ||||
| 
 | ||||
| // Processes
 | ||||
| 
 | ||||
| type Rusage C.struct_rusage | ||||
| 
 | ||||
| type Rlimit C.struct_rlimit | ||||
| 
 | ||||
| type _Gid_t C.gid_t | ||||
| 
 | ||||
| // Files
 | ||||
| 
 | ||||
| type Stat_t C.struct_stat | ||||
| 
 | ||||
| type Statfs_t C.struct_statfs | ||||
| 
 | ||||
| type Flock_t C.struct_flock | ||||
| 
 | ||||
| type Dirent C.struct_dirent | ||||
| 
 | ||||
| type Fsid C.struct_fsid | ||||
| 
 | ||||
| // File system limits
 | ||||
| 
 | ||||
| const ( | ||||
| 	PathMax = C.PATH_MAX | ||||
| ) | ||||
| 
 | ||||
| // Sockets
 | ||||
| 
 | ||||
| type RawSockaddrInet4 C.struct_sockaddr_in | ||||
| 
 | ||||
| type RawSockaddrInet6 C.struct_sockaddr_in6 | ||||
| 
 | ||||
| type RawSockaddrUnix C.struct_sockaddr_un | ||||
| 
 | ||||
| type RawSockaddrDatalink C.struct_sockaddr_dl | ||||
| 
 | ||||
| type RawSockaddr C.struct_sockaddr | ||||
| 
 | ||||
| type RawSockaddrAny C.struct_sockaddr_any | ||||
| 
 | ||||
| type _Socklen C.socklen_t | ||||
| 
 | ||||
| type Linger C.struct_linger | ||||
| 
 | ||||
| type Iovec C.struct_iovec | ||||
| 
 | ||||
| type IPMreq C.struct_ip_mreq | ||||
| 
 | ||||
| type IPv6Mreq C.struct_ipv6_mreq | ||||
| 
 | ||||
| type Msghdr C.struct_msghdr | ||||
| 
 | ||||
| type Cmsghdr C.struct_cmsghdr | ||||
| 
 | ||||
| type Inet6Pktinfo C.struct_in6_pktinfo | ||||
| 
 | ||||
| type IPv6MTUInfo C.struct_ip6_mtuinfo | ||||
| 
 | ||||
| type ICMPv6Filter C.struct_icmp6_filter | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofSockaddrInet4    = C.sizeof_struct_sockaddr_in | ||||
| 	SizeofSockaddrInet6    = C.sizeof_struct_sockaddr_in6 | ||||
| 	SizeofSockaddrAny      = C.sizeof_struct_sockaddr_any | ||||
| 	SizeofSockaddrUnix     = C.sizeof_struct_sockaddr_un | ||||
| 	SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl | ||||
| 	SizeofLinger           = C.sizeof_struct_linger | ||||
| 	SizeofIPMreq           = C.sizeof_struct_ip_mreq | ||||
| 	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq | ||||
| 	SizeofMsghdr           = C.sizeof_struct_msghdr | ||||
| 	SizeofCmsghdr          = C.sizeof_struct_cmsghdr | ||||
| 	SizeofInet6Pktinfo     = C.sizeof_struct_in6_pktinfo | ||||
| 	SizeofIPv6MTUInfo      = C.sizeof_struct_ip6_mtuinfo | ||||
| 	SizeofICMPv6Filter     = C.sizeof_struct_icmp6_filter | ||||
| ) | ||||
| 
 | ||||
| // Ptrace requests
 | ||||
| 
 | ||||
| const ( | ||||
| 	PTRACE_TRACEME = C.PT_TRACE_ME | ||||
| 	PTRACE_CONT    = C.PT_CONTINUE | ||||
| 	PTRACE_KILL    = C.PT_KILL | ||||
| ) | ||||
| 
 | ||||
| // Events (kqueue, kevent)
 | ||||
| 
 | ||||
| type Kevent_t C.struct_kevent | ||||
| 
 | ||||
| // Select
 | ||||
| 
 | ||||
| type FdSet C.fd_set | ||||
| 
 | ||||
| // Routing and interface messages
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofIfMsghdr         = C.sizeof_struct_if_msghdr | ||||
| 	SizeofIfData           = C.sizeof_struct_if_data | ||||
| 	SizeofIfaMsghdr        = C.sizeof_struct_ifa_msghdr | ||||
| 	SizeofIfmaMsghdr       = C.sizeof_struct_ifma_msghdr | ||||
| 	SizeofIfAnnounceMsghdr = C.sizeof_struct_if_announcemsghdr | ||||
| 	SizeofRtMsghdr         = C.sizeof_struct_rt_msghdr | ||||
| 	SizeofRtMetrics        = C.sizeof_struct_rt_metrics | ||||
| ) | ||||
| 
 | ||||
| type IfMsghdr C.struct_if_msghdr | ||||
| 
 | ||||
| type IfData C.struct_if_data | ||||
| 
 | ||||
| type IfaMsghdr C.struct_ifa_msghdr | ||||
| 
 | ||||
| type IfmaMsghdr C.struct_ifma_msghdr | ||||
| 
 | ||||
| type IfAnnounceMsghdr C.struct_if_announcemsghdr | ||||
| 
 | ||||
| type RtMsghdr C.struct_rt_msghdr | ||||
| 
 | ||||
| type RtMetrics C.struct_rt_metrics | ||||
| 
 | ||||
| // Berkeley packet filter
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofBpfVersion = C.sizeof_struct_bpf_version | ||||
| 	SizeofBpfStat    = C.sizeof_struct_bpf_stat | ||||
| 	SizeofBpfProgram = C.sizeof_struct_bpf_program | ||||
| 	SizeofBpfInsn    = C.sizeof_struct_bpf_insn | ||||
| 	SizeofBpfHdr     = C.sizeof_struct_bpf_hdr | ||||
| ) | ||||
| 
 | ||||
| type BpfVersion C.struct_bpf_version | ||||
| 
 | ||||
| type BpfStat C.struct_bpf_stat | ||||
| 
 | ||||
| type BpfProgram C.struct_bpf_program | ||||
| 
 | ||||
| type BpfInsn C.struct_bpf_insn | ||||
| 
 | ||||
| type BpfHdr C.struct_bpf_hdr | ||||
| 
 | ||||
| // Terminal handling
 | ||||
| 
 | ||||
| type Termios C.struct_termios | ||||
| 
 | ||||
| type Winsize C.struct_winsize | ||||
| 
 | ||||
| // fchmodat-like syscalls.
 | ||||
| 
 | ||||
| const ( | ||||
| 	AT_FDCWD            = C.AT_FDCWD | ||||
| 	AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW | ||||
| ) | ||||
| 
 | ||||
| // poll
 | ||||
| 
 | ||||
| type PollFd C.struct_pollfd | ||||
| 
 | ||||
| const ( | ||||
| 	POLLERR    = C.POLLERR | ||||
| 	POLLHUP    = C.POLLHUP | ||||
| 	POLLIN     = C.POLLIN | ||||
| 	POLLNVAL   = C.POLLNVAL | ||||
| 	POLLOUT    = C.POLLOUT | ||||
| 	POLLPRI    = C.POLLPRI | ||||
| 	POLLRDBAND = C.POLLRDBAND | ||||
| 	POLLRDNORM = C.POLLRDNORM | ||||
| 	POLLWRBAND = C.POLLWRBAND | ||||
| 	POLLWRNORM = C.POLLWRNORM | ||||
| ) | ||||
| 
 | ||||
| // Uname
 | ||||
| 
 | ||||
| type Utsname C.struct_utsname | ||||
|  | @ -1,356 +0,0 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| /* | ||||
| Input to cgo -godefs.  See README.md | ||||
| */ | ||||
| 
 | ||||
| // +godefs map struct_in_addr [4]byte /* in_addr */
 | ||||
| // +godefs map struct_in6_addr [16]byte /* in6_addr */
 | ||||
| 
 | ||||
| package unix | ||||
| 
 | ||||
| /* | ||||
| #define	_WANT_FREEBSD11_STAT	1 | ||||
| #define	_WANT_FREEBSD11_STATFS	1 | ||||
| #define	_WANT_FREEBSD11_DIRENT	1 | ||||
| #define	_WANT_FREEBSD11_KEVENT  1 | ||||
| 
 | ||||
| #include <dirent.h> | ||||
| #include <fcntl.h> | ||||
| #include <poll.h> | ||||
| #include <signal.h> | ||||
| #include <termios.h> | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/capsicum.h> | ||||
| #include <sys/event.h> | ||||
| #include <sys/mman.h> | ||||
| #include <sys/mount.h> | ||||
| #include <sys/param.h> | ||||
| #include <sys/ptrace.h> | ||||
| #include <sys/resource.h> | ||||
| #include <sys/select.h> | ||||
| #include <sys/signal.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/un.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/wait.h> | ||||
| #include <net/bpf.h> | ||||
| #include <net/if.h> | ||||
| #include <net/if_dl.h> | ||||
| #include <net/route.h> | ||||
| #include <netinet/in.h> | ||||
| #include <netinet/icmp6.h> | ||||
| #include <netinet/tcp.h> | ||||
| 
 | ||||
| enum { | ||||
| 	sizeofPtr = sizeof(void*), | ||||
| }; | ||||
| 
 | ||||
| union sockaddr_all { | ||||
| 	struct sockaddr s1;	// this one gets used for fields
 | ||||
| 	struct sockaddr_in s2;	// these pad it out
 | ||||
| 	struct sockaddr_in6 s3; | ||||
| 	struct sockaddr_un s4; | ||||
| 	struct sockaddr_dl s5; | ||||
| }; | ||||
| 
 | ||||
| struct sockaddr_any { | ||||
| 	struct sockaddr addr; | ||||
| 	char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; | ||||
| }; | ||||
| 
 | ||||
| // This structure is a duplicate of if_data on FreeBSD 8-STABLE.
 | ||||
| // See /usr/include/net/if.h.
 | ||||
| struct if_data8 { | ||||
| 	u_char  ifi_type; | ||||
| 	u_char  ifi_physical; | ||||
| 	u_char  ifi_addrlen; | ||||
| 	u_char  ifi_hdrlen; | ||||
| 	u_char  ifi_link_state; | ||||
| 	u_char  ifi_spare_char1; | ||||
| 	u_char  ifi_spare_char2; | ||||
| 	u_char  ifi_datalen; | ||||
| 	u_long  ifi_mtu; | ||||
| 	u_long  ifi_metric; | ||||
| 	u_long  ifi_baudrate; | ||||
| 	u_long  ifi_ipackets; | ||||
| 	u_long  ifi_ierrors; | ||||
| 	u_long  ifi_opackets; | ||||
| 	u_long  ifi_oerrors; | ||||
| 	u_long  ifi_collisions; | ||||
| 	u_long  ifi_ibytes; | ||||
| 	u_long  ifi_obytes; | ||||
| 	u_long  ifi_imcasts; | ||||
| 	u_long  ifi_omcasts; | ||||
| 	u_long  ifi_iqdrops; | ||||
| 	u_long  ifi_noproto; | ||||
| 	u_long  ifi_hwassist; | ||||
| // FIXME: these are now unions, so maybe need to change definitions?
 | ||||
| #undef ifi_epoch | ||||
| 	time_t  ifi_epoch; | ||||
| #undef ifi_lastchange | ||||
| 	struct  timeval ifi_lastchange; | ||||
| }; | ||||
| 
 | ||||
| // This structure is a duplicate of if_msghdr on FreeBSD 8-STABLE.
 | ||||
| // See /usr/include/net/if.h.
 | ||||
| struct if_msghdr8 { | ||||
| 	u_short ifm_msglen; | ||||
| 	u_char  ifm_version; | ||||
| 	u_char  ifm_type; | ||||
| 	int     ifm_addrs; | ||||
| 	int     ifm_flags; | ||||
| 	u_short ifm_index; | ||||
| 	struct  if_data8 ifm_data; | ||||
| }; | ||||
| */ | ||||
| import "C" | ||||
| 
 | ||||
| // Machine characteristics
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofPtr      = C.sizeofPtr | ||||
| 	SizeofShort    = C.sizeof_short | ||||
| 	SizeofInt      = C.sizeof_int | ||||
| 	SizeofLong     = C.sizeof_long | ||||
| 	SizeofLongLong = C.sizeof_longlong | ||||
| ) | ||||
| 
 | ||||
| // Basic types
 | ||||
| 
 | ||||
| type ( | ||||
| 	_C_short     C.short | ||||
| 	_C_int       C.int | ||||
| 	_C_long      C.long | ||||
| 	_C_long_long C.longlong | ||||
| ) | ||||
| 
 | ||||
| // Time
 | ||||
| 
 | ||||
| type Timespec C.struct_timespec | ||||
| 
 | ||||
| type Timeval C.struct_timeval | ||||
| 
 | ||||
| // Processes
 | ||||
| 
 | ||||
| type Rusage C.struct_rusage | ||||
| 
 | ||||
| type Rlimit C.struct_rlimit | ||||
| 
 | ||||
| type _Gid_t C.gid_t | ||||
| 
 | ||||
| // Files
 | ||||
| 
 | ||||
| const ( | ||||
| 	_statfsVersion = C.STATFS_VERSION | ||||
| 	_dirblksiz     = C.DIRBLKSIZ | ||||
| ) | ||||
| 
 | ||||
| type Stat_t C.struct_stat | ||||
| 
 | ||||
| type stat_freebsd11_t C.struct_freebsd11_stat | ||||
| 
 | ||||
| type Statfs_t C.struct_statfs | ||||
| 
 | ||||
| type statfs_freebsd11_t C.struct_freebsd11_statfs | ||||
| 
 | ||||
| type Flock_t C.struct_flock | ||||
| 
 | ||||
| type Dirent C.struct_dirent | ||||
| 
 | ||||
| type dirent_freebsd11 C.struct_freebsd11_dirent | ||||
| 
 | ||||
| type Fsid C.struct_fsid | ||||
| 
 | ||||
| // File system limits
 | ||||
| 
 | ||||
| const ( | ||||
| 	PathMax = C.PATH_MAX | ||||
| ) | ||||
| 
 | ||||
| // Advice to Fadvise
 | ||||
| 
 | ||||
| const ( | ||||
| 	FADV_NORMAL     = C.POSIX_FADV_NORMAL | ||||
| 	FADV_RANDOM     = C.POSIX_FADV_RANDOM | ||||
| 	FADV_SEQUENTIAL = C.POSIX_FADV_SEQUENTIAL | ||||
| 	FADV_WILLNEED   = C.POSIX_FADV_WILLNEED | ||||
| 	FADV_DONTNEED   = C.POSIX_FADV_DONTNEED | ||||
| 	FADV_NOREUSE    = C.POSIX_FADV_NOREUSE | ||||
| ) | ||||
| 
 | ||||
| // Sockets
 | ||||
| 
 | ||||
| type RawSockaddrInet4 C.struct_sockaddr_in | ||||
| 
 | ||||
| type RawSockaddrInet6 C.struct_sockaddr_in6 | ||||
| 
 | ||||
| type RawSockaddrUnix C.struct_sockaddr_un | ||||
| 
 | ||||
| type RawSockaddrDatalink C.struct_sockaddr_dl | ||||
| 
 | ||||
| type RawSockaddr C.struct_sockaddr | ||||
| 
 | ||||
| type RawSockaddrAny C.struct_sockaddr_any | ||||
| 
 | ||||
| type _Socklen C.socklen_t | ||||
| 
 | ||||
| type Linger C.struct_linger | ||||
| 
 | ||||
| type Iovec C.struct_iovec | ||||
| 
 | ||||
| type IPMreq C.struct_ip_mreq | ||||
| 
 | ||||
| type IPMreqn C.struct_ip_mreqn | ||||
| 
 | ||||
| type IPv6Mreq C.struct_ipv6_mreq | ||||
| 
 | ||||
| type Msghdr C.struct_msghdr | ||||
| 
 | ||||
| type Cmsghdr C.struct_cmsghdr | ||||
| 
 | ||||
| type Inet6Pktinfo C.struct_in6_pktinfo | ||||
| 
 | ||||
| type IPv6MTUInfo C.struct_ip6_mtuinfo | ||||
| 
 | ||||
| type ICMPv6Filter C.struct_icmp6_filter | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofSockaddrInet4    = C.sizeof_struct_sockaddr_in | ||||
| 	SizeofSockaddrInet6    = C.sizeof_struct_sockaddr_in6 | ||||
| 	SizeofSockaddrAny      = C.sizeof_struct_sockaddr_any | ||||
| 	SizeofSockaddrUnix     = C.sizeof_struct_sockaddr_un | ||||
| 	SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl | ||||
| 	SizeofLinger           = C.sizeof_struct_linger | ||||
| 	SizeofIPMreq           = C.sizeof_struct_ip_mreq | ||||
| 	SizeofIPMreqn          = C.sizeof_struct_ip_mreqn | ||||
| 	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq | ||||
| 	SizeofMsghdr           = C.sizeof_struct_msghdr | ||||
| 	SizeofCmsghdr          = C.sizeof_struct_cmsghdr | ||||
| 	SizeofInet6Pktinfo     = C.sizeof_struct_in6_pktinfo | ||||
| 	SizeofIPv6MTUInfo      = C.sizeof_struct_ip6_mtuinfo | ||||
| 	SizeofICMPv6Filter     = C.sizeof_struct_icmp6_filter | ||||
| ) | ||||
| 
 | ||||
| // Ptrace requests
 | ||||
| 
 | ||||
| const ( | ||||
| 	PTRACE_TRACEME = C.PT_TRACE_ME | ||||
| 	PTRACE_CONT    = C.PT_CONTINUE | ||||
| 	PTRACE_KILL    = C.PT_KILL | ||||
| ) | ||||
| 
 | ||||
| // Events (kqueue, kevent)
 | ||||
| 
 | ||||
| type Kevent_t C.struct_kevent_freebsd11 | ||||
| 
 | ||||
| // Select
 | ||||
| 
 | ||||
| type FdSet C.fd_set | ||||
| 
 | ||||
| // Routing and interface messages
 | ||||
| 
 | ||||
| const ( | ||||
| 	sizeofIfMsghdr         = C.sizeof_struct_if_msghdr | ||||
| 	SizeofIfMsghdr         = C.sizeof_struct_if_msghdr8 | ||||
| 	sizeofIfData           = C.sizeof_struct_if_data | ||||
| 	SizeofIfData           = C.sizeof_struct_if_data8 | ||||
| 	SizeofIfaMsghdr        = C.sizeof_struct_ifa_msghdr | ||||
| 	SizeofIfmaMsghdr       = C.sizeof_struct_ifma_msghdr | ||||
| 	SizeofIfAnnounceMsghdr = C.sizeof_struct_if_announcemsghdr | ||||
| 	SizeofRtMsghdr         = C.sizeof_struct_rt_msghdr | ||||
| 	SizeofRtMetrics        = C.sizeof_struct_rt_metrics | ||||
| ) | ||||
| 
 | ||||
| type ifMsghdr C.struct_if_msghdr | ||||
| 
 | ||||
| type IfMsghdr C.struct_if_msghdr8 | ||||
| 
 | ||||
| type ifData C.struct_if_data | ||||
| 
 | ||||
| type IfData C.struct_if_data8 | ||||
| 
 | ||||
| type IfaMsghdr C.struct_ifa_msghdr | ||||
| 
 | ||||
| type IfmaMsghdr C.struct_ifma_msghdr | ||||
| 
 | ||||
| type IfAnnounceMsghdr C.struct_if_announcemsghdr | ||||
| 
 | ||||
| type RtMsghdr C.struct_rt_msghdr | ||||
| 
 | ||||
| type RtMetrics C.struct_rt_metrics | ||||
| 
 | ||||
| // Berkeley packet filter
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofBpfVersion    = C.sizeof_struct_bpf_version | ||||
| 	SizeofBpfStat       = C.sizeof_struct_bpf_stat | ||||
| 	SizeofBpfZbuf       = C.sizeof_struct_bpf_zbuf | ||||
| 	SizeofBpfProgram    = C.sizeof_struct_bpf_program | ||||
| 	SizeofBpfInsn       = C.sizeof_struct_bpf_insn | ||||
| 	SizeofBpfHdr        = C.sizeof_struct_bpf_hdr | ||||
| 	SizeofBpfZbufHeader = C.sizeof_struct_bpf_zbuf_header | ||||
| ) | ||||
| 
 | ||||
| type BpfVersion C.struct_bpf_version | ||||
| 
 | ||||
| type BpfStat C.struct_bpf_stat | ||||
| 
 | ||||
| type BpfZbuf C.struct_bpf_zbuf | ||||
| 
 | ||||
| type BpfProgram C.struct_bpf_program | ||||
| 
 | ||||
| type BpfInsn C.struct_bpf_insn | ||||
| 
 | ||||
| type BpfHdr C.struct_bpf_hdr | ||||
| 
 | ||||
| type BpfZbufHeader C.struct_bpf_zbuf_header | ||||
| 
 | ||||
| // Terminal handling
 | ||||
| 
 | ||||
| type Termios C.struct_termios | ||||
| 
 | ||||
| type Winsize C.struct_winsize | ||||
| 
 | ||||
| // fchmodat-like syscalls.
 | ||||
| 
 | ||||
| const ( | ||||
| 	AT_FDCWD            = C.AT_FDCWD | ||||
| 	AT_REMOVEDIR        = C.AT_REMOVEDIR | ||||
| 	AT_SYMLINK_FOLLOW   = C.AT_SYMLINK_FOLLOW | ||||
| 	AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW | ||||
| ) | ||||
| 
 | ||||
| // poll
 | ||||
| 
 | ||||
| type PollFd C.struct_pollfd | ||||
| 
 | ||||
| const ( | ||||
| 	POLLERR      = C.POLLERR | ||||
| 	POLLHUP      = C.POLLHUP | ||||
| 	POLLIN       = C.POLLIN | ||||
| 	POLLINIGNEOF = C.POLLINIGNEOF | ||||
| 	POLLNVAL     = C.POLLNVAL | ||||
| 	POLLOUT      = C.POLLOUT | ||||
| 	POLLPRI      = C.POLLPRI | ||||
| 	POLLRDBAND   = C.POLLRDBAND | ||||
| 	POLLRDNORM   = C.POLLRDNORM | ||||
| 	POLLWRBAND   = C.POLLWRBAND | ||||
| 	POLLWRNORM   = C.POLLWRNORM | ||||
| ) | ||||
| 
 | ||||
| // Capabilities
 | ||||
| 
 | ||||
| type CapRights C.struct_cap_rights | ||||
| 
 | ||||
| // Uname
 | ||||
| 
 | ||||
| type Utsname C.struct_utsname | ||||
|  | @ -1,289 +0,0 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| /* | ||||
| Input to cgo -godefs.  See README.md | ||||
| */ | ||||
| 
 | ||||
| // +godefs map struct_in_addr [4]byte /* in_addr */
 | ||||
| // +godefs map struct_in6_addr [16]byte /* in6_addr */
 | ||||
| 
 | ||||
| package unix | ||||
| 
 | ||||
| /* | ||||
| #define KERNEL | ||||
| #include <dirent.h> | ||||
| #include <fcntl.h> | ||||
| #include <poll.h> | ||||
| #include <signal.h> | ||||
| #include <termios.h> | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/param.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/event.h> | ||||
| #include <sys/mman.h> | ||||
| #include <sys/mount.h> | ||||
| #include <sys/ptrace.h> | ||||
| #include <sys/resource.h> | ||||
| #include <sys/select.h> | ||||
| #include <sys/signal.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/sysctl.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/uio.h> | ||||
| #include <sys/un.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/wait.h> | ||||
| #include <net/bpf.h> | ||||
| #include <net/if.h> | ||||
| #include <net/if_dl.h> | ||||
| #include <net/route.h> | ||||
| #include <netinet/in.h> | ||||
| #include <netinet/icmp6.h> | ||||
| #include <netinet/tcp.h> | ||||
| 
 | ||||
| enum { | ||||
| 	sizeofPtr = sizeof(void*), | ||||
| }; | ||||
| 
 | ||||
| union sockaddr_all { | ||||
| 	struct sockaddr s1;	// this one gets used for fields
 | ||||
| 	struct sockaddr_in s2;	// these pad it out
 | ||||
| 	struct sockaddr_in6 s3; | ||||
| 	struct sockaddr_un s4; | ||||
| 	struct sockaddr_dl s5; | ||||
| }; | ||||
| 
 | ||||
| struct sockaddr_any { | ||||
| 	struct sockaddr addr; | ||||
| 	char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; | ||||
| }; | ||||
| 
 | ||||
| */ | ||||
| import "C" | ||||
| 
 | ||||
| // Machine characteristics
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofPtr      = C.sizeofPtr | ||||
| 	SizeofShort    = C.sizeof_short | ||||
| 	SizeofInt      = C.sizeof_int | ||||
| 	SizeofLong     = C.sizeof_long | ||||
| 	SizeofLongLong = C.sizeof_longlong | ||||
| ) | ||||
| 
 | ||||
| // Basic types
 | ||||
| 
 | ||||
| type ( | ||||
| 	_C_short     C.short | ||||
| 	_C_int       C.int | ||||
| 	_C_long      C.long | ||||
| 	_C_long_long C.longlong | ||||
| ) | ||||
| 
 | ||||
| // Time
 | ||||
| 
 | ||||
| type Timespec C.struct_timespec | ||||
| 
 | ||||
| type Timeval C.struct_timeval | ||||
| 
 | ||||
| // Processes
 | ||||
| 
 | ||||
| type Rusage C.struct_rusage | ||||
| 
 | ||||
| type Rlimit C.struct_rlimit | ||||
| 
 | ||||
| type _Gid_t C.gid_t | ||||
| 
 | ||||
| // Files
 | ||||
| 
 | ||||
| type Stat_t C.struct_stat | ||||
| 
 | ||||
| type Statfs_t C.struct_statfs | ||||
| 
 | ||||
| type Flock_t C.struct_flock | ||||
| 
 | ||||
| type Dirent C.struct_dirent | ||||
| 
 | ||||
| type Fsid C.fsid_t | ||||
| 
 | ||||
| // File system limits
 | ||||
| 
 | ||||
| const ( | ||||
| 	PathMax = C.PATH_MAX | ||||
| ) | ||||
| 
 | ||||
| // Advice to Fadvise
 | ||||
| 
 | ||||
| const ( | ||||
| 	FADV_NORMAL     = C.POSIX_FADV_NORMAL | ||||
| 	FADV_RANDOM     = C.POSIX_FADV_RANDOM | ||||
| 	FADV_SEQUENTIAL = C.POSIX_FADV_SEQUENTIAL | ||||
| 	FADV_WILLNEED   = C.POSIX_FADV_WILLNEED | ||||
| 	FADV_DONTNEED   = C.POSIX_FADV_DONTNEED | ||||
| 	FADV_NOREUSE    = C.POSIX_FADV_NOREUSE | ||||
| ) | ||||
| 
 | ||||
| // Sockets
 | ||||
| 
 | ||||
| type RawSockaddrInet4 C.struct_sockaddr_in | ||||
| 
 | ||||
| type RawSockaddrInet6 C.struct_sockaddr_in6 | ||||
| 
 | ||||
| type RawSockaddrUnix C.struct_sockaddr_un | ||||
| 
 | ||||
| type RawSockaddrDatalink C.struct_sockaddr_dl | ||||
| 
 | ||||
| type RawSockaddr C.struct_sockaddr | ||||
| 
 | ||||
| type RawSockaddrAny C.struct_sockaddr_any | ||||
| 
 | ||||
| type _Socklen C.socklen_t | ||||
| 
 | ||||
| type Linger C.struct_linger | ||||
| 
 | ||||
| type Iovec C.struct_iovec | ||||
| 
 | ||||
| type IPMreq C.struct_ip_mreq | ||||
| 
 | ||||
| type IPv6Mreq C.struct_ipv6_mreq | ||||
| 
 | ||||
| type Msghdr C.struct_msghdr | ||||
| 
 | ||||
| type Cmsghdr C.struct_cmsghdr | ||||
| 
 | ||||
| type Inet6Pktinfo C.struct_in6_pktinfo | ||||
| 
 | ||||
| type IPv6MTUInfo C.struct_ip6_mtuinfo | ||||
| 
 | ||||
| type ICMPv6Filter C.struct_icmp6_filter | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofSockaddrInet4    = C.sizeof_struct_sockaddr_in | ||||
| 	SizeofSockaddrInet6    = C.sizeof_struct_sockaddr_in6 | ||||
| 	SizeofSockaddrAny      = C.sizeof_struct_sockaddr_any | ||||
| 	SizeofSockaddrUnix     = C.sizeof_struct_sockaddr_un | ||||
| 	SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl | ||||
| 	SizeofLinger           = C.sizeof_struct_linger | ||||
| 	SizeofIPMreq           = C.sizeof_struct_ip_mreq | ||||
| 	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq | ||||
| 	SizeofMsghdr           = C.sizeof_struct_msghdr | ||||
| 	SizeofCmsghdr          = C.sizeof_struct_cmsghdr | ||||
| 	SizeofInet6Pktinfo     = C.sizeof_struct_in6_pktinfo | ||||
| 	SizeofIPv6MTUInfo      = C.sizeof_struct_ip6_mtuinfo | ||||
| 	SizeofICMPv6Filter     = C.sizeof_struct_icmp6_filter | ||||
| ) | ||||
| 
 | ||||
| // Ptrace requests
 | ||||
| 
 | ||||
| const ( | ||||
| 	PTRACE_TRACEME = C.PT_TRACE_ME | ||||
| 	PTRACE_CONT    = C.PT_CONTINUE | ||||
| 	PTRACE_KILL    = C.PT_KILL | ||||
| ) | ||||
| 
 | ||||
| // Events (kqueue, kevent)
 | ||||
| 
 | ||||
| type Kevent_t C.struct_kevent | ||||
| 
 | ||||
| // Select
 | ||||
| 
 | ||||
| type FdSet C.fd_set | ||||
| 
 | ||||
| // Routing and interface messages
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofIfMsghdr         = C.sizeof_struct_if_msghdr | ||||
| 	SizeofIfData           = C.sizeof_struct_if_data | ||||
| 	SizeofIfaMsghdr        = C.sizeof_struct_ifa_msghdr | ||||
| 	SizeofIfAnnounceMsghdr = C.sizeof_struct_if_announcemsghdr | ||||
| 	SizeofRtMsghdr         = C.sizeof_struct_rt_msghdr | ||||
| 	SizeofRtMetrics        = C.sizeof_struct_rt_metrics | ||||
| ) | ||||
| 
 | ||||
| type IfMsghdr C.struct_if_msghdr | ||||
| 
 | ||||
| type IfData C.struct_if_data | ||||
| 
 | ||||
| type IfaMsghdr C.struct_ifa_msghdr | ||||
| 
 | ||||
| type IfAnnounceMsghdr C.struct_if_announcemsghdr | ||||
| 
 | ||||
| type RtMsghdr C.struct_rt_msghdr | ||||
| 
 | ||||
| type RtMetrics C.struct_rt_metrics | ||||
| 
 | ||||
| type Mclpool C.struct_mclpool | ||||
| 
 | ||||
| // Berkeley packet filter
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofBpfVersion = C.sizeof_struct_bpf_version | ||||
| 	SizeofBpfStat    = C.sizeof_struct_bpf_stat | ||||
| 	SizeofBpfProgram = C.sizeof_struct_bpf_program | ||||
| 	SizeofBpfInsn    = C.sizeof_struct_bpf_insn | ||||
| 	SizeofBpfHdr     = C.sizeof_struct_bpf_hdr | ||||
| ) | ||||
| 
 | ||||
| type BpfVersion C.struct_bpf_version | ||||
| 
 | ||||
| type BpfStat C.struct_bpf_stat | ||||
| 
 | ||||
| type BpfProgram C.struct_bpf_program | ||||
| 
 | ||||
| type BpfInsn C.struct_bpf_insn | ||||
| 
 | ||||
| type BpfHdr C.struct_bpf_hdr | ||||
| 
 | ||||
| type BpfTimeval C.struct_bpf_timeval | ||||
| 
 | ||||
| // Terminal handling
 | ||||
| 
 | ||||
| type Termios C.struct_termios | ||||
| 
 | ||||
| type Winsize C.struct_winsize | ||||
| 
 | ||||
| type Ptmget C.struct_ptmget | ||||
| 
 | ||||
| // fchmodat-like syscalls.
 | ||||
| 
 | ||||
| const ( | ||||
| 	AT_FDCWD            = C.AT_FDCWD | ||||
| 	AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW | ||||
| ) | ||||
| 
 | ||||
| // poll
 | ||||
| 
 | ||||
| type PollFd C.struct_pollfd | ||||
| 
 | ||||
| const ( | ||||
| 	POLLERR    = C.POLLERR | ||||
| 	POLLHUP    = C.POLLHUP | ||||
| 	POLLIN     = C.POLLIN | ||||
| 	POLLNVAL   = C.POLLNVAL | ||||
| 	POLLOUT    = C.POLLOUT | ||||
| 	POLLPRI    = C.POLLPRI | ||||
| 	POLLRDBAND = C.POLLRDBAND | ||||
| 	POLLRDNORM = C.POLLRDNORM | ||||
| 	POLLWRBAND = C.POLLWRBAND | ||||
| 	POLLWRNORM = C.POLLWRNORM | ||||
| ) | ||||
| 
 | ||||
| // Sysctl
 | ||||
| 
 | ||||
| type Sysctlnode C.struct_sysctlnode | ||||
| 
 | ||||
| // Uname
 | ||||
| 
 | ||||
| type Utsname C.struct_utsname | ||||
| 
 | ||||
| // Clockinfo
 | ||||
| 
 | ||||
| const SizeofClockinfo = C.sizeof_struct_clockinfo | ||||
| 
 | ||||
| type Clockinfo C.struct_clockinfo | ||||
|  | @ -1,282 +0,0 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| /* | ||||
| Input to cgo -godefs.  See README.md | ||||
| */ | ||||
| 
 | ||||
| // +godefs map struct_in_addr [4]byte /* in_addr */
 | ||||
| // +godefs map struct_in6_addr [16]byte /* in6_addr */
 | ||||
| 
 | ||||
| package unix | ||||
| 
 | ||||
| /* | ||||
| #define KERNEL | ||||
| #include <dirent.h> | ||||
| #include <fcntl.h> | ||||
| #include <poll.h> | ||||
| #include <signal.h> | ||||
| #include <termios.h> | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/param.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/event.h> | ||||
| #include <sys/mman.h> | ||||
| #include <sys/mount.h> | ||||
| #include <sys/ptrace.h> | ||||
| #include <sys/resource.h> | ||||
| #include <sys/select.h> | ||||
| #include <sys/signal.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/uio.h> | ||||
| #include <sys/un.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/wait.h> | ||||
| #include <uvm/uvmexp.h> | ||||
| #include <net/bpf.h> | ||||
| #include <net/if.h> | ||||
| #include <net/if_dl.h> | ||||
| #include <net/route.h> | ||||
| #include <netinet/in.h> | ||||
| #include <netinet/icmp6.h> | ||||
| #include <netinet/tcp.h> | ||||
| 
 | ||||
| enum { | ||||
| 	sizeofPtr = sizeof(void*), | ||||
| }; | ||||
| 
 | ||||
| union sockaddr_all { | ||||
| 	struct sockaddr s1;	// this one gets used for fields
 | ||||
| 	struct sockaddr_in s2;	// these pad it out
 | ||||
| 	struct sockaddr_in6 s3; | ||||
| 	struct sockaddr_un s4; | ||||
| 	struct sockaddr_dl s5; | ||||
| }; | ||||
| 
 | ||||
| struct sockaddr_any { | ||||
| 	struct sockaddr addr; | ||||
| 	char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; | ||||
| }; | ||||
| 
 | ||||
| */ | ||||
| import "C" | ||||
| 
 | ||||
| // Machine characteristics
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofPtr      = C.sizeofPtr | ||||
| 	SizeofShort    = C.sizeof_short | ||||
| 	SizeofInt      = C.sizeof_int | ||||
| 	SizeofLong     = C.sizeof_long | ||||
| 	SizeofLongLong = C.sizeof_longlong | ||||
| ) | ||||
| 
 | ||||
| // Basic types
 | ||||
| 
 | ||||
| type ( | ||||
| 	_C_short     C.short | ||||
| 	_C_int       C.int | ||||
| 	_C_long      C.long | ||||
| 	_C_long_long C.longlong | ||||
| ) | ||||
| 
 | ||||
| // Time
 | ||||
| 
 | ||||
| type Timespec C.struct_timespec | ||||
| 
 | ||||
| type Timeval C.struct_timeval | ||||
| 
 | ||||
| // Processes
 | ||||
| 
 | ||||
| type Rusage C.struct_rusage | ||||
| 
 | ||||
| type Rlimit C.struct_rlimit | ||||
| 
 | ||||
| type _Gid_t C.gid_t | ||||
| 
 | ||||
| // Files
 | ||||
| 
 | ||||
| type Stat_t C.struct_stat | ||||
| 
 | ||||
| type Statfs_t C.struct_statfs | ||||
| 
 | ||||
| type Flock_t C.struct_flock | ||||
| 
 | ||||
| type Dirent C.struct_dirent | ||||
| 
 | ||||
| type Fsid C.fsid_t | ||||
| 
 | ||||
| // File system limits
 | ||||
| 
 | ||||
| const ( | ||||
| 	PathMax = C.PATH_MAX | ||||
| ) | ||||
| 
 | ||||
| // Sockets
 | ||||
| 
 | ||||
| type RawSockaddrInet4 C.struct_sockaddr_in | ||||
| 
 | ||||
| type RawSockaddrInet6 C.struct_sockaddr_in6 | ||||
| 
 | ||||
| type RawSockaddrUnix C.struct_sockaddr_un | ||||
| 
 | ||||
| type RawSockaddrDatalink C.struct_sockaddr_dl | ||||
| 
 | ||||
| type RawSockaddr C.struct_sockaddr | ||||
| 
 | ||||
| type RawSockaddrAny C.struct_sockaddr_any | ||||
| 
 | ||||
| type _Socklen C.socklen_t | ||||
| 
 | ||||
| type Linger C.struct_linger | ||||
| 
 | ||||
| type Iovec C.struct_iovec | ||||
| 
 | ||||
| type IPMreq C.struct_ip_mreq | ||||
| 
 | ||||
| type IPv6Mreq C.struct_ipv6_mreq | ||||
| 
 | ||||
| type Msghdr C.struct_msghdr | ||||
| 
 | ||||
| type Cmsghdr C.struct_cmsghdr | ||||
| 
 | ||||
| type Inet6Pktinfo C.struct_in6_pktinfo | ||||
| 
 | ||||
| type IPv6MTUInfo C.struct_ip6_mtuinfo | ||||
| 
 | ||||
| type ICMPv6Filter C.struct_icmp6_filter | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofSockaddrInet4    = C.sizeof_struct_sockaddr_in | ||||
| 	SizeofSockaddrInet6    = C.sizeof_struct_sockaddr_in6 | ||||
| 	SizeofSockaddrAny      = C.sizeof_struct_sockaddr_any | ||||
| 	SizeofSockaddrUnix     = C.sizeof_struct_sockaddr_un | ||||
| 	SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl | ||||
| 	SizeofLinger           = C.sizeof_struct_linger | ||||
| 	SizeofIPMreq           = C.sizeof_struct_ip_mreq | ||||
| 	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq | ||||
| 	SizeofMsghdr           = C.sizeof_struct_msghdr | ||||
| 	SizeofCmsghdr          = C.sizeof_struct_cmsghdr | ||||
| 	SizeofInet6Pktinfo     = C.sizeof_struct_in6_pktinfo | ||||
| 	SizeofIPv6MTUInfo      = C.sizeof_struct_ip6_mtuinfo | ||||
| 	SizeofICMPv6Filter     = C.sizeof_struct_icmp6_filter | ||||
| ) | ||||
| 
 | ||||
| // Ptrace requests
 | ||||
| 
 | ||||
| const ( | ||||
| 	PTRACE_TRACEME = C.PT_TRACE_ME | ||||
| 	PTRACE_CONT    = C.PT_CONTINUE | ||||
| 	PTRACE_KILL    = C.PT_KILL | ||||
| ) | ||||
| 
 | ||||
| // Events (kqueue, kevent)
 | ||||
| 
 | ||||
| type Kevent_t C.struct_kevent | ||||
| 
 | ||||
| // Select
 | ||||
| 
 | ||||
| type FdSet C.fd_set | ||||
| 
 | ||||
| // Routing and interface messages
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofIfMsghdr         = C.sizeof_struct_if_msghdr | ||||
| 	SizeofIfData           = C.sizeof_struct_if_data | ||||
| 	SizeofIfaMsghdr        = C.sizeof_struct_ifa_msghdr | ||||
| 	SizeofIfAnnounceMsghdr = C.sizeof_struct_if_announcemsghdr | ||||
| 	SizeofRtMsghdr         = C.sizeof_struct_rt_msghdr | ||||
| 	SizeofRtMetrics        = C.sizeof_struct_rt_metrics | ||||
| ) | ||||
| 
 | ||||
| type IfMsghdr C.struct_if_msghdr | ||||
| 
 | ||||
| type IfData C.struct_if_data | ||||
| 
 | ||||
| type IfaMsghdr C.struct_ifa_msghdr | ||||
| 
 | ||||
| type IfAnnounceMsghdr C.struct_if_announcemsghdr | ||||
| 
 | ||||
| type RtMsghdr C.struct_rt_msghdr | ||||
| 
 | ||||
| type RtMetrics C.struct_rt_metrics | ||||
| 
 | ||||
| type Mclpool C.struct_mclpool | ||||
| 
 | ||||
| // Berkeley packet filter
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofBpfVersion = C.sizeof_struct_bpf_version | ||||
| 	SizeofBpfStat    = C.sizeof_struct_bpf_stat | ||||
| 	SizeofBpfProgram = C.sizeof_struct_bpf_program | ||||
| 	SizeofBpfInsn    = C.sizeof_struct_bpf_insn | ||||
| 	SizeofBpfHdr     = C.sizeof_struct_bpf_hdr | ||||
| ) | ||||
| 
 | ||||
| type BpfVersion C.struct_bpf_version | ||||
| 
 | ||||
| type BpfStat C.struct_bpf_stat | ||||
| 
 | ||||
| type BpfProgram C.struct_bpf_program | ||||
| 
 | ||||
| type BpfInsn C.struct_bpf_insn | ||||
| 
 | ||||
| type BpfHdr C.struct_bpf_hdr | ||||
| 
 | ||||
| type BpfTimeval C.struct_bpf_timeval | ||||
| 
 | ||||
| // Terminal handling
 | ||||
| 
 | ||||
| type Termios C.struct_termios | ||||
| 
 | ||||
| type Winsize C.struct_winsize | ||||
| 
 | ||||
| // fchmodat-like syscalls.
 | ||||
| 
 | ||||
| const ( | ||||
| 	AT_FDCWD            = C.AT_FDCWD | ||||
| 	AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW | ||||
| ) | ||||
| 
 | ||||
| // poll
 | ||||
| 
 | ||||
| type PollFd C.struct_pollfd | ||||
| 
 | ||||
| const ( | ||||
| 	POLLERR    = C.POLLERR | ||||
| 	POLLHUP    = C.POLLHUP | ||||
| 	POLLIN     = C.POLLIN | ||||
| 	POLLNVAL   = C.POLLNVAL | ||||
| 	POLLOUT    = C.POLLOUT | ||||
| 	POLLPRI    = C.POLLPRI | ||||
| 	POLLRDBAND = C.POLLRDBAND | ||||
| 	POLLRDNORM = C.POLLRDNORM | ||||
| 	POLLWRBAND = C.POLLWRBAND | ||||
| 	POLLWRNORM = C.POLLWRNORM | ||||
| ) | ||||
| 
 | ||||
| // Signal Sets
 | ||||
| 
 | ||||
| type Sigset_t C.sigset_t | ||||
| 
 | ||||
| // Uname
 | ||||
| 
 | ||||
| type Utsname C.struct_utsname | ||||
| 
 | ||||
| // Uvmexp
 | ||||
| 
 | ||||
| const SizeofUvmexp = C.sizeof_struct_uvmexp | ||||
| 
 | ||||
| type Uvmexp C.struct_uvmexp | ||||
| 
 | ||||
| // Clockinfo
 | ||||
| 
 | ||||
| const SizeofClockinfo = C.sizeof_struct_clockinfo | ||||
| 
 | ||||
| type Clockinfo C.struct_clockinfo | ||||
|  | @ -1,266 +0,0 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| /* | ||||
| Input to cgo -godefs.  See README.md | ||||
| */ | ||||
| 
 | ||||
| // +godefs map struct_in_addr [4]byte /* in_addr */
 | ||||
| // +godefs map struct_in6_addr [16]byte /* in6_addr */
 | ||||
| 
 | ||||
| package unix | ||||
| 
 | ||||
| /* | ||||
| #define KERNEL | ||||
| // These defines ensure that builds done on newer versions of Solaris are
 | ||||
| // backwards-compatible with older versions of Solaris and
 | ||||
| // OpenSolaris-based derivatives.
 | ||||
| #define __USE_SUNOS_SOCKETS__          // msghdr
 | ||||
| #define __USE_LEGACY_PROTOTYPES__      // iovec
 | ||||
| #include <dirent.h> | ||||
| #include <fcntl.h> | ||||
| #include <netdb.h> | ||||
| #include <limits.h> | ||||
| #include <poll.h> | ||||
| #include <signal.h> | ||||
| #include <termios.h> | ||||
| #include <termio.h> | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/mman.h> | ||||
| #include <sys/mount.h> | ||||
| #include <sys/param.h> | ||||
| #include <sys/resource.h> | ||||
| #include <sys/select.h> | ||||
| #include <sys/signal.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/statvfs.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/times.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/utsname.h> | ||||
| #include <sys/un.h> | ||||
| #include <sys/wait.h> | ||||
| #include <net/bpf.h> | ||||
| #include <net/if.h> | ||||
| #include <net/if_dl.h> | ||||
| #include <net/route.h> | ||||
| #include <netinet/in.h> | ||||
| #include <netinet/icmp6.h> | ||||
| #include <netinet/tcp.h> | ||||
| #include <ustat.h> | ||||
| #include <utime.h> | ||||
| 
 | ||||
| enum { | ||||
| 	sizeofPtr = sizeof(void*), | ||||
| }; | ||||
| 
 | ||||
| union sockaddr_all { | ||||
| 	struct sockaddr s1;	// this one gets used for fields
 | ||||
| 	struct sockaddr_in s2;	// these pad it out
 | ||||
| 	struct sockaddr_in6 s3; | ||||
| 	struct sockaddr_un s4; | ||||
| 	struct sockaddr_dl s5; | ||||
| }; | ||||
| 
 | ||||
| struct sockaddr_any { | ||||
| 	struct sockaddr addr; | ||||
| 	char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; | ||||
| }; | ||||
| 
 | ||||
| */ | ||||
| import "C" | ||||
| 
 | ||||
| // Machine characteristics
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofPtr      = C.sizeofPtr | ||||
| 	SizeofShort    = C.sizeof_short | ||||
| 	SizeofInt      = C.sizeof_int | ||||
| 	SizeofLong     = C.sizeof_long | ||||
| 	SizeofLongLong = C.sizeof_longlong | ||||
| 	PathMax        = C.PATH_MAX | ||||
| 	MaxHostNameLen = C.MAXHOSTNAMELEN | ||||
| ) | ||||
| 
 | ||||
| // Basic types
 | ||||
| 
 | ||||
| type ( | ||||
| 	_C_short     C.short | ||||
| 	_C_int       C.int | ||||
| 	_C_long      C.long | ||||
| 	_C_long_long C.longlong | ||||
| ) | ||||
| 
 | ||||
| // Time
 | ||||
| 
 | ||||
| type Timespec C.struct_timespec | ||||
| 
 | ||||
| type Timeval C.struct_timeval | ||||
| 
 | ||||
| type Timeval32 C.struct_timeval32 | ||||
| 
 | ||||
| type Tms C.struct_tms | ||||
| 
 | ||||
| type Utimbuf C.struct_utimbuf | ||||
| 
 | ||||
| // Processes
 | ||||
| 
 | ||||
| type Rusage C.struct_rusage | ||||
| 
 | ||||
| type Rlimit C.struct_rlimit | ||||
| 
 | ||||
| type _Gid_t C.gid_t | ||||
| 
 | ||||
| // Files
 | ||||
| 
 | ||||
| type Stat_t C.struct_stat | ||||
| 
 | ||||
| type Flock_t C.struct_flock | ||||
| 
 | ||||
| type Dirent C.struct_dirent | ||||
| 
 | ||||
| // Filesystems
 | ||||
| 
 | ||||
| type _Fsblkcnt_t C.fsblkcnt_t | ||||
| 
 | ||||
| type Statvfs_t C.struct_statvfs | ||||
| 
 | ||||
| // Sockets
 | ||||
| 
 | ||||
| type RawSockaddrInet4 C.struct_sockaddr_in | ||||
| 
 | ||||
| type RawSockaddrInet6 C.struct_sockaddr_in6 | ||||
| 
 | ||||
| type RawSockaddrUnix C.struct_sockaddr_un | ||||
| 
 | ||||
| type RawSockaddrDatalink C.struct_sockaddr_dl | ||||
| 
 | ||||
| type RawSockaddr C.struct_sockaddr | ||||
| 
 | ||||
| type RawSockaddrAny C.struct_sockaddr_any | ||||
| 
 | ||||
| type _Socklen C.socklen_t | ||||
| 
 | ||||
| type Linger C.struct_linger | ||||
| 
 | ||||
| type Iovec C.struct_iovec | ||||
| 
 | ||||
| type IPMreq C.struct_ip_mreq | ||||
| 
 | ||||
| type IPv6Mreq C.struct_ipv6_mreq | ||||
| 
 | ||||
| type Msghdr C.struct_msghdr | ||||
| 
 | ||||
| type Cmsghdr C.struct_cmsghdr | ||||
| 
 | ||||
| type Inet6Pktinfo C.struct_in6_pktinfo | ||||
| 
 | ||||
| type IPv6MTUInfo C.struct_ip6_mtuinfo | ||||
| 
 | ||||
| type ICMPv6Filter C.struct_icmp6_filter | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofSockaddrInet4    = C.sizeof_struct_sockaddr_in | ||||
| 	SizeofSockaddrInet6    = C.sizeof_struct_sockaddr_in6 | ||||
| 	SizeofSockaddrAny      = C.sizeof_struct_sockaddr_any | ||||
| 	SizeofSockaddrUnix     = C.sizeof_struct_sockaddr_un | ||||
| 	SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl | ||||
| 	SizeofLinger           = C.sizeof_struct_linger | ||||
| 	SizeofIPMreq           = C.sizeof_struct_ip_mreq | ||||
| 	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq | ||||
| 	SizeofMsghdr           = C.sizeof_struct_msghdr | ||||
| 	SizeofCmsghdr          = C.sizeof_struct_cmsghdr | ||||
| 	SizeofInet6Pktinfo     = C.sizeof_struct_in6_pktinfo | ||||
| 	SizeofIPv6MTUInfo      = C.sizeof_struct_ip6_mtuinfo | ||||
| 	SizeofICMPv6Filter     = C.sizeof_struct_icmp6_filter | ||||
| ) | ||||
| 
 | ||||
| // Select
 | ||||
| 
 | ||||
| type FdSet C.fd_set | ||||
| 
 | ||||
| // Misc
 | ||||
| 
 | ||||
| type Utsname C.struct_utsname | ||||
| 
 | ||||
| type Ustat_t C.struct_ustat | ||||
| 
 | ||||
| const ( | ||||
| 	AT_FDCWD            = C.AT_FDCWD | ||||
| 	AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW | ||||
| 	AT_SYMLINK_FOLLOW   = C.AT_SYMLINK_FOLLOW | ||||
| 	AT_REMOVEDIR        = C.AT_REMOVEDIR | ||||
| 	AT_EACCESS          = C.AT_EACCESS | ||||
| ) | ||||
| 
 | ||||
| // Routing and interface messages
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofIfMsghdr  = C.sizeof_struct_if_msghdr | ||||
| 	SizeofIfData    = C.sizeof_struct_if_data | ||||
| 	SizeofIfaMsghdr = C.sizeof_struct_ifa_msghdr | ||||
| 	SizeofRtMsghdr  = C.sizeof_struct_rt_msghdr | ||||
| 	SizeofRtMetrics = C.sizeof_struct_rt_metrics | ||||
| ) | ||||
| 
 | ||||
| type IfMsghdr C.struct_if_msghdr | ||||
| 
 | ||||
| type IfData C.struct_if_data | ||||
| 
 | ||||
| type IfaMsghdr C.struct_ifa_msghdr | ||||
| 
 | ||||
| type RtMsghdr C.struct_rt_msghdr | ||||
| 
 | ||||
| type RtMetrics C.struct_rt_metrics | ||||
| 
 | ||||
| // Berkeley packet filter
 | ||||
| 
 | ||||
| const ( | ||||
| 	SizeofBpfVersion = C.sizeof_struct_bpf_version | ||||
| 	SizeofBpfStat    = C.sizeof_struct_bpf_stat | ||||
| 	SizeofBpfProgram = C.sizeof_struct_bpf_program | ||||
| 	SizeofBpfInsn    = C.sizeof_struct_bpf_insn | ||||
| 	SizeofBpfHdr     = C.sizeof_struct_bpf_hdr | ||||
| ) | ||||
| 
 | ||||
| type BpfVersion C.struct_bpf_version | ||||
| 
 | ||||
| type BpfStat C.struct_bpf_stat | ||||
| 
 | ||||
| type BpfProgram C.struct_bpf_program | ||||
| 
 | ||||
| type BpfInsn C.struct_bpf_insn | ||||
| 
 | ||||
| type BpfTimeval C.struct_bpf_timeval | ||||
| 
 | ||||
| type BpfHdr C.struct_bpf_hdr | ||||
| 
 | ||||
| // Terminal handling
 | ||||
| 
 | ||||
| type Termios C.struct_termios | ||||
| 
 | ||||
| type Termio C.struct_termio | ||||
| 
 | ||||
| type Winsize C.struct_winsize | ||||
| 
 | ||||
| // poll
 | ||||
| 
 | ||||
| type PollFd C.struct_pollfd | ||||
| 
 | ||||
| const ( | ||||
| 	POLLERR    = C.POLLERR | ||||
| 	POLLHUP    = C.POLLHUP | ||||
| 	POLLIN     = C.POLLIN | ||||
| 	POLLNVAL   = C.POLLNVAL | ||||
| 	POLLOUT    = C.POLLOUT | ||||
| 	POLLPRI    = C.POLLPRI | ||||
| 	POLLRDBAND = C.POLLRDBAND | ||||
| 	POLLRDNORM = C.POLLRDNORM | ||||
| 	POLLWRBAND = C.POLLWRBAND | ||||
| 	POLLWRNORM = C.POLLWRNORM | ||||
| ) | ||||
|  | @ -1,133 +0,0 @@ | |||
| // Copyright 2015 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"log" | ||||
| 
 | ||||
| 	"golang.org/x/text/internal/gen" | ||||
| 	"golang.org/x/text/internal/triegen" | ||||
| 	"golang.org/x/text/internal/ucd" | ||||
| ) | ||||
| 
 | ||||
| var outputFile = flag.String("out", "tables.go", "output file") | ||||
| 
 | ||||
| func main() { | ||||
| 	gen.Init() | ||||
| 	gen.Repackage("gen_trieval.go", "trieval.go", "bidi") | ||||
| 	gen.Repackage("gen_ranges.go", "ranges_test.go", "bidi") | ||||
| 
 | ||||
| 	genTables() | ||||
| } | ||||
| 
 | ||||
| // bidiClass names and codes taken from class "bc" in
 | ||||
| // http://www.unicode.org/Public/8.0.0/ucd/PropertyValueAliases.txt
 | ||||
| var bidiClass = map[string]Class{ | ||||
| 	"AL":  AL,  // ArabicLetter
 | ||||
| 	"AN":  AN,  // ArabicNumber
 | ||||
| 	"B":   B,   // ParagraphSeparator
 | ||||
| 	"BN":  BN,  // BoundaryNeutral
 | ||||
| 	"CS":  CS,  // CommonSeparator
 | ||||
| 	"EN":  EN,  // EuropeanNumber
 | ||||
| 	"ES":  ES,  // EuropeanSeparator
 | ||||
| 	"ET":  ET,  // EuropeanTerminator
 | ||||
| 	"L":   L,   // LeftToRight
 | ||||
| 	"NSM": NSM, // NonspacingMark
 | ||||
| 	"ON":  ON,  // OtherNeutral
 | ||||
| 	"R":   R,   // RightToLeft
 | ||||
| 	"S":   S,   // SegmentSeparator
 | ||||
| 	"WS":  WS,  // WhiteSpace
 | ||||
| 
 | ||||
| 	"FSI": Control, | ||||
| 	"PDF": Control, | ||||
| 	"PDI": Control, | ||||
| 	"LRE": Control, | ||||
| 	"LRI": Control, | ||||
| 	"LRO": Control, | ||||
| 	"RLE": Control, | ||||
| 	"RLI": Control, | ||||
| 	"RLO": Control, | ||||
| } | ||||
| 
 | ||||
| func genTables() { | ||||
| 	if numClass > 0x0F { | ||||
| 		log.Fatalf("Too many Class constants (%#x > 0x0F).", numClass) | ||||
| 	} | ||||
| 	w := gen.NewCodeWriter() | ||||
| 	defer w.WriteVersionedGoFile(*outputFile, "bidi") | ||||
| 
 | ||||
| 	gen.WriteUnicodeVersion(w) | ||||
| 
 | ||||
| 	t := triegen.NewTrie("bidi") | ||||
| 
 | ||||
| 	// Build data about bracket mapping. These bits need to be or-ed with
 | ||||
| 	// any other bits.
 | ||||
| 	orMask := map[rune]uint64{} | ||||
| 
 | ||||
| 	xorMap := map[rune]int{} | ||||
| 	xorMasks := []rune{0} // First value is no-op.
 | ||||
| 
 | ||||
| 	ucd.Parse(gen.OpenUCDFile("BidiBrackets.txt"), func(p *ucd.Parser) { | ||||
| 		r1 := p.Rune(0) | ||||
| 		r2 := p.Rune(1) | ||||
| 		xor := r1 ^ r2 | ||||
| 		if _, ok := xorMap[xor]; !ok { | ||||
| 			xorMap[xor] = len(xorMasks) | ||||
| 			xorMasks = append(xorMasks, xor) | ||||
| 		} | ||||
| 		entry := uint64(xorMap[xor]) << xorMaskShift | ||||
| 		switch p.String(2) { | ||||
| 		case "o": | ||||
| 			entry |= openMask | ||||
| 		case "c", "n": | ||||
| 		default: | ||||
| 			log.Fatalf("Unknown bracket class %q.", p.String(2)) | ||||
| 		} | ||||
| 		orMask[r1] = entry | ||||
| 	}) | ||||
| 
 | ||||
| 	w.WriteComment(` | ||||
| 	xorMasks contains masks to be xor-ed with brackets to get the reverse | ||||
| 	version.`) | ||||
| 	w.WriteVar("xorMasks", xorMasks) | ||||
| 
 | ||||
| 	done := map[rune]bool{} | ||||
| 
 | ||||
| 	insert := func(r rune, c Class) { | ||||
| 		if !done[r] { | ||||
| 			t.Insert(r, orMask[r]|uint64(c)) | ||||
| 			done[r] = true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Insert the derived BiDi properties.
 | ||||
| 	ucd.Parse(gen.OpenUCDFile("extracted/DerivedBidiClass.txt"), func(p *ucd.Parser) { | ||||
| 		r := p.Rune(0) | ||||
| 		class, ok := bidiClass[p.String(1)] | ||||
| 		if !ok { | ||||
| 			log.Fatalf("%U: Unknown BiDi class %q", r, p.String(1)) | ||||
| 		} | ||||
| 		insert(r, class) | ||||
| 	}) | ||||
| 	visitDefaults(insert) | ||||
| 
 | ||||
| 	// TODO: use sparse blocks. This would reduce table size considerably
 | ||||
| 	// from the looks of it.
 | ||||
| 
 | ||||
| 	sz, err := t.Gen(w) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	w.Size += sz | ||||
| } | ||||
| 
 | ||||
| // dummy values to make methods in gen_common compile. The real versions
 | ||||
| // will be generated by this file to tables.go.
 | ||||
| var ( | ||||
| 	xorMasks []rune | ||||
| ) | ||||
|  | @ -1,57 +0,0 @@ | |||
| // Copyright 2015 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"unicode" | ||||
| 
 | ||||
| 	"golang.org/x/text/internal/gen" | ||||
| 	"golang.org/x/text/internal/ucd" | ||||
| 	"golang.org/x/text/unicode/rangetable" | ||||
| ) | ||||
| 
 | ||||
| // These tables are hand-extracted from:
 | ||||
| // http://www.unicode.org/Public/8.0.0/ucd/extracted/DerivedBidiClass.txt
 | ||||
| func visitDefaults(fn func(r rune, c Class)) { | ||||
| 	// first write default values for ranges listed above.
 | ||||
| 	visitRunes(fn, AL, []rune{ | ||||
| 		0x0600, 0x07BF, // Arabic
 | ||||
| 		0x08A0, 0x08FF, // Arabic Extended-A
 | ||||
| 		0xFB50, 0xFDCF, // Arabic Presentation Forms
 | ||||
| 		0xFDF0, 0xFDFF, | ||||
| 		0xFE70, 0xFEFF, | ||||
| 		0x0001EE00, 0x0001EEFF, // Arabic Mathematical Alpha Symbols
 | ||||
| 	}) | ||||
| 	visitRunes(fn, R, []rune{ | ||||
| 		0x0590, 0x05FF, // Hebrew
 | ||||
| 		0x07C0, 0x089F, // Nko et al.
 | ||||
| 		0xFB1D, 0xFB4F, | ||||
| 		0x00010800, 0x00010FFF, // Cypriot Syllabary et. al.
 | ||||
| 		0x0001E800, 0x0001EDFF, | ||||
| 		0x0001EF00, 0x0001EFFF, | ||||
| 	}) | ||||
| 	visitRunes(fn, ET, []rune{ // European Terminator
 | ||||
| 		0x20A0, 0x20Cf, // Currency symbols
 | ||||
| 	}) | ||||
| 	rangetable.Visit(unicode.Noncharacter_Code_Point, func(r rune) { | ||||
| 		fn(r, BN) // Boundary Neutral
 | ||||
| 	}) | ||||
| 	ucd.Parse(gen.OpenUCDFile("DerivedCoreProperties.txt"), func(p *ucd.Parser) { | ||||
| 		if p.String(1) == "Default_Ignorable_Code_Point" { | ||||
| 			fn(p.Rune(0), BN) // Boundary Neutral
 | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func visitRunes(fn func(r rune, c Class), c Class, runes []rune) { | ||||
| 	for i := 0; i < len(runes); i += 2 { | ||||
| 		lo, hi := runes[i], runes[i+1] | ||||
| 		for j := lo; j <= hi; j++ { | ||||
| 			fn(j, c) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -1,64 +0,0 @@ | |||
| // Copyright 2015 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| // Class is the Unicode BiDi class. Each rune has a single class.
 | ||||
| type Class uint | ||||
| 
 | ||||
| const ( | ||||
| 	L       Class = iota // LeftToRight
 | ||||
| 	R                    // RightToLeft
 | ||||
| 	EN                   // EuropeanNumber
 | ||||
| 	ES                   // EuropeanSeparator
 | ||||
| 	ET                   // EuropeanTerminator
 | ||||
| 	AN                   // ArabicNumber
 | ||||
| 	CS                   // CommonSeparator
 | ||||
| 	B                    // ParagraphSeparator
 | ||||
| 	S                    // SegmentSeparator
 | ||||
| 	WS                   // WhiteSpace
 | ||||
| 	ON                   // OtherNeutral
 | ||||
| 	BN                   // BoundaryNeutral
 | ||||
| 	NSM                  // NonspacingMark
 | ||||
| 	AL                   // ArabicLetter
 | ||||
| 	Control              // Control LRO - PDI
 | ||||
| 
 | ||||
| 	numClass | ||||
| 
 | ||||
| 	LRO // LeftToRightOverride
 | ||||
| 	RLO // RightToLeftOverride
 | ||||
| 	LRE // LeftToRightEmbedding
 | ||||
| 	RLE // RightToLeftEmbedding
 | ||||
| 	PDF // PopDirectionalFormat
 | ||||
| 	LRI // LeftToRightIsolate
 | ||||
| 	RLI // RightToLeftIsolate
 | ||||
| 	FSI // FirstStrongIsolate
 | ||||
| 	PDI // PopDirectionalIsolate
 | ||||
| 
 | ||||
| 	unknownClass = ^Class(0) | ||||
| ) | ||||
| 
 | ||||
| var controlToClass = map[rune]Class{ | ||||
| 	0x202D: LRO, // LeftToRightOverride,
 | ||||
| 	0x202E: RLO, // RightToLeftOverride,
 | ||||
| 	0x202A: LRE, // LeftToRightEmbedding,
 | ||||
| 	0x202B: RLE, // RightToLeftEmbedding,
 | ||||
| 	0x202C: PDF, // PopDirectionalFormat,
 | ||||
| 	0x2066: LRI, // LeftToRightIsolate,
 | ||||
| 	0x2067: RLI, // RightToLeftIsolate,
 | ||||
| 	0x2068: FSI, // FirstStrongIsolate,
 | ||||
| 	0x2069: PDI, // PopDirectionalIsolate,
 | ||||
| } | ||||
| 
 | ||||
| // A trie entry has the following bits:
 | ||||
| // 7..5  XOR mask for brackets
 | ||||
| // 4     1: Bracket open, 0: Bracket close
 | ||||
| // 3..0  Class type
 | ||||
| 
 | ||||
| const ( | ||||
| 	openMask     = 0x10 | ||||
| 	xorMaskShift = 5 | ||||
| ) | ||||
|  | @ -1,976 +0,0 @@ | |||
| // Copyright 2011 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| // Normalization table generator.
 | ||||
| // Data read from the web.
 | ||||
| // See forminfo.go for a description of the trie values associated with each rune.
 | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"golang.org/x/text/internal/gen" | ||||
| 	"golang.org/x/text/internal/triegen" | ||||
| 	"golang.org/x/text/internal/ucd" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| 	gen.Init() | ||||
| 	loadUnicodeData() | ||||
| 	compactCCC() | ||||
| 	loadCompositionExclusions() | ||||
| 	completeCharFields(FCanonical) | ||||
| 	completeCharFields(FCompatibility) | ||||
| 	computeNonStarterCounts() | ||||
| 	verifyComputed() | ||||
| 	printChars() | ||||
| 	testDerived() | ||||
| 	printTestdata() | ||||
| 	makeTables() | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	tablelist = flag.String("tables", | ||||
| 		"all", | ||||
| 		"comma-separated list of which tables to generate; "+ | ||||
| 			"can be 'decomp', 'recomp', 'info' and 'all'") | ||||
| 	test = flag.Bool("test", | ||||
| 		false, | ||||
| 		"test existing tables against DerivedNormalizationProps and generate test data for regression testing") | ||||
| 	verbose = flag.Bool("verbose", | ||||
| 		false, | ||||
| 		"write data to stdout as it is parsed") | ||||
| ) | ||||
| 
 | ||||
| const MaxChar = 0x10FFFF // anything above this shouldn't exist
 | ||||
| 
 | ||||
| // Quick Check properties of runes allow us to quickly
 | ||||
| // determine whether a rune may occur in a normal form.
 | ||||
| // For a given normal form, a rune may be guaranteed to occur
 | ||||
| // verbatim (QC=Yes), may or may not combine with another
 | ||||
| // rune (QC=Maybe), or may not occur (QC=No).
 | ||||
| type QCResult int | ||||
| 
 | ||||
| const ( | ||||
| 	QCUnknown QCResult = iota | ||||
| 	QCYes | ||||
| 	QCNo | ||||
| 	QCMaybe | ||||
| ) | ||||
| 
 | ||||
| func (r QCResult) String() string { | ||||
| 	switch r { | ||||
| 	case QCYes: | ||||
| 		return "Yes" | ||||
| 	case QCNo: | ||||
| 		return "No" | ||||
| 	case QCMaybe: | ||||
| 		return "Maybe" | ||||
| 	} | ||||
| 	return "***UNKNOWN***" | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
| 	FCanonical     = iota // NFC or NFD
 | ||||
| 	FCompatibility        // NFKC or NFKD
 | ||||
| 	FNumberOfFormTypes | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	MComposed   = iota // NFC or NFKC
 | ||||
| 	MDecomposed        // NFD or NFKD
 | ||||
| 	MNumberOfModes | ||||
| ) | ||||
| 
 | ||||
| // This contains only the properties we're interested in.
 | ||||
| type Char struct { | ||||
| 	name          string | ||||
| 	codePoint     rune  // if zero, this index is not a valid code point.
 | ||||
| 	ccc           uint8 // canonical combining class
 | ||||
| 	origCCC       uint8 | ||||
| 	excludeInComp bool // from CompositionExclusions.txt
 | ||||
| 	compatDecomp  bool // it has a compatibility expansion
 | ||||
| 
 | ||||
| 	nTrailingNonStarters uint8 | ||||
| 	nLeadingNonStarters  uint8 // must be equal to trailing if non-zero
 | ||||
| 
 | ||||
| 	forms [FNumberOfFormTypes]FormInfo // For FCanonical and FCompatibility
 | ||||
| 
 | ||||
| 	state State | ||||
| } | ||||
| 
 | ||||
| var chars = make([]Char, MaxChar+1) | ||||
| var cccMap = make(map[uint8]uint8) | ||||
| 
 | ||||
| func (c Char) String() string { | ||||
| 	buf := new(bytes.Buffer) | ||||
| 
 | ||||
| 	fmt.Fprintf(buf, "%U [%s]:\n", c.codePoint, c.name) | ||||
| 	fmt.Fprintf(buf, "  ccc: %v\n", c.ccc) | ||||
| 	fmt.Fprintf(buf, "  excludeInComp: %v\n", c.excludeInComp) | ||||
| 	fmt.Fprintf(buf, "  compatDecomp: %v\n", c.compatDecomp) | ||||
| 	fmt.Fprintf(buf, "  state: %v\n", c.state) | ||||
| 	fmt.Fprintf(buf, "  NFC:\n") | ||||
| 	fmt.Fprint(buf, c.forms[FCanonical]) | ||||
| 	fmt.Fprintf(buf, "  NFKC:\n") | ||||
| 	fmt.Fprint(buf, c.forms[FCompatibility]) | ||||
| 
 | ||||
| 	return buf.String() | ||||
| } | ||||
| 
 | ||||
| // In UnicodeData.txt, some ranges are marked like this:
 | ||||
| //	3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
 | ||||
| //	4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
 | ||||
| // parseCharacter keeps a state variable indicating the weirdness.
 | ||||
| type State int | ||||
| 
 | ||||
| const ( | ||||
| 	SNormal State = iota // known to be zero for the type
 | ||||
| 	SFirst | ||||
| 	SLast | ||||
| 	SMissing | ||||
| ) | ||||
| 
 | ||||
| var lastChar = rune('\u0000') | ||||
| 
 | ||||
| func (c Char) isValid() bool { | ||||
| 	return c.codePoint != 0 && c.state != SMissing | ||||
| } | ||||
| 
 | ||||
| type FormInfo struct { | ||||
| 	quickCheck [MNumberOfModes]QCResult // index: MComposed or MDecomposed
 | ||||
| 	verified   [MNumberOfModes]bool     // index: MComposed or MDecomposed
 | ||||
| 
 | ||||
| 	combinesForward  bool // May combine with rune on the right
 | ||||
| 	combinesBackward bool // May combine with rune on the left
 | ||||
| 	isOneWay         bool // Never appears in result
 | ||||
| 	inDecomp         bool // Some decompositions result in this char.
 | ||||
| 	decomp           Decomposition | ||||
| 	expandedDecomp   Decomposition | ||||
| } | ||||
| 
 | ||||
| func (f FormInfo) String() string { | ||||
| 	buf := bytes.NewBuffer(make([]byte, 0)) | ||||
| 
 | ||||
| 	fmt.Fprintf(buf, "    quickCheck[C]: %v\n", f.quickCheck[MComposed]) | ||||
| 	fmt.Fprintf(buf, "    quickCheck[D]: %v\n", f.quickCheck[MDecomposed]) | ||||
| 	fmt.Fprintf(buf, "    cmbForward: %v\n", f.combinesForward) | ||||
| 	fmt.Fprintf(buf, "    cmbBackward: %v\n", f.combinesBackward) | ||||
| 	fmt.Fprintf(buf, "    isOneWay: %v\n", f.isOneWay) | ||||
| 	fmt.Fprintf(buf, "    inDecomp: %v\n", f.inDecomp) | ||||
| 	fmt.Fprintf(buf, "    decomposition: %X\n", f.decomp) | ||||
| 	fmt.Fprintf(buf, "    expandedDecomp: %X\n", f.expandedDecomp) | ||||
| 
 | ||||
| 	return buf.String() | ||||
| } | ||||
| 
 | ||||
| type Decomposition []rune | ||||
| 
 | ||||
| func parseDecomposition(s string, skipfirst bool) (a []rune, err error) { | ||||
| 	decomp := strings.Split(s, " ") | ||||
| 	if len(decomp) > 0 && skipfirst { | ||||
| 		decomp = decomp[1:] | ||||
| 	} | ||||
| 	for _, d := range decomp { | ||||
| 		point, err := strconv.ParseUint(d, 16, 64) | ||||
| 		if err != nil { | ||||
| 			return a, err | ||||
| 		} | ||||
| 		a = append(a, rune(point)) | ||||
| 	} | ||||
| 	return a, nil | ||||
| } | ||||
| 
 | ||||
| func loadUnicodeData() { | ||||
| 	f := gen.OpenUCDFile("UnicodeData.txt") | ||||
| 	defer f.Close() | ||||
| 	p := ucd.New(f) | ||||
| 	for p.Next() { | ||||
| 		r := p.Rune(ucd.CodePoint) | ||||
| 		char := &chars[r] | ||||
| 
 | ||||
| 		char.ccc = uint8(p.Uint(ucd.CanonicalCombiningClass)) | ||||
| 		decmap := p.String(ucd.DecompMapping) | ||||
| 
 | ||||
| 		exp, err := parseDecomposition(decmap, false) | ||||
| 		isCompat := false | ||||
| 		if err != nil { | ||||
| 			if len(decmap) > 0 { | ||||
| 				exp, err = parseDecomposition(decmap, true) | ||||
| 				if err != nil { | ||||
| 					log.Fatalf(`%U: bad decomp |%v|: "%s"`, r, decmap, err) | ||||
| 				} | ||||
| 				isCompat = true | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		char.name = p.String(ucd.Name) | ||||
| 		char.codePoint = r | ||||
| 		char.forms[FCompatibility].decomp = exp | ||||
| 		if !isCompat { | ||||
| 			char.forms[FCanonical].decomp = exp | ||||
| 		} else { | ||||
| 			char.compatDecomp = true | ||||
| 		} | ||||
| 		if len(decmap) > 0 { | ||||
| 			char.forms[FCompatibility].decomp = exp | ||||
| 		} | ||||
| 	} | ||||
| 	if err := p.Err(); err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // compactCCC converts the sparse set of CCC values to a continguous one,
 | ||||
| // reducing the number of bits needed from 8 to 6.
 | ||||
| func compactCCC() { | ||||
| 	m := make(map[uint8]uint8) | ||||
| 	for i := range chars { | ||||
| 		c := &chars[i] | ||||
| 		m[c.ccc] = 0 | ||||
| 	} | ||||
| 	cccs := []int{} | ||||
| 	for v, _ := range m { | ||||
| 		cccs = append(cccs, int(v)) | ||||
| 	} | ||||
| 	sort.Ints(cccs) | ||||
| 	for i, c := range cccs { | ||||
| 		cccMap[uint8(i)] = uint8(c) | ||||
| 		m[uint8(c)] = uint8(i) | ||||
| 	} | ||||
| 	for i := range chars { | ||||
| 		c := &chars[i] | ||||
| 		c.origCCC = c.ccc | ||||
| 		c.ccc = m[c.ccc] | ||||
| 	} | ||||
| 	if len(m) >= 1<<6 { | ||||
| 		log.Fatalf("too many difference CCC values: %d >= 64", len(m)) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // CompositionExclusions.txt has form:
 | ||||
| // 0958    # ...
 | ||||
| // See http://unicode.org/reports/tr44/ for full explanation
 | ||||
| func loadCompositionExclusions() { | ||||
| 	f := gen.OpenUCDFile("CompositionExclusions.txt") | ||||
| 	defer f.Close() | ||||
| 	p := ucd.New(f) | ||||
| 	for p.Next() { | ||||
| 		c := &chars[p.Rune(0)] | ||||
| 		if c.excludeInComp { | ||||
| 			log.Fatalf("%U: Duplicate entry in exclusions.", c.codePoint) | ||||
| 		} | ||||
| 		c.excludeInComp = true | ||||
| 	} | ||||
| 	if e := p.Err(); e != nil { | ||||
| 		log.Fatal(e) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // hasCompatDecomp returns true if any of the recursive
 | ||||
| // decompositions contains a compatibility expansion.
 | ||||
| // In this case, the character may not occur in NFK*.
 | ||||
| func hasCompatDecomp(r rune) bool { | ||||
| 	c := &chars[r] | ||||
| 	if c.compatDecomp { | ||||
| 		return true | ||||
| 	} | ||||
| 	for _, d := range c.forms[FCompatibility].decomp { | ||||
| 		if hasCompatDecomp(d) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // Hangul related constants.
 | ||||
| const ( | ||||
| 	HangulBase = 0xAC00 | ||||
| 	HangulEnd  = 0xD7A4 // hangulBase + Jamo combinations (19 * 21 * 28)
 | ||||
| 
 | ||||
| 	JamoLBase = 0x1100 | ||||
| 	JamoLEnd  = 0x1113 | ||||
| 	JamoVBase = 0x1161 | ||||
| 	JamoVEnd  = 0x1176 | ||||
| 	JamoTBase = 0x11A8 | ||||
| 	JamoTEnd  = 0x11C3 | ||||
| 
 | ||||
| 	JamoLVTCount = 19 * 21 * 28 | ||||
| 	JamoTCount   = 28 | ||||
| ) | ||||
| 
 | ||||
| func isHangul(r rune) bool { | ||||
| 	return HangulBase <= r && r < HangulEnd | ||||
| } | ||||
| 
 | ||||
| func isHangulWithoutJamoT(r rune) bool { | ||||
| 	if !isHangul(r) { | ||||
| 		return false | ||||
| 	} | ||||
| 	r -= HangulBase | ||||
| 	return r < JamoLVTCount && r%JamoTCount == 0 | ||||
| } | ||||
| 
 | ||||
| func ccc(r rune) uint8 { | ||||
| 	return chars[r].ccc | ||||
| } | ||||
| 
 | ||||
| // Insert a rune in a buffer, ordered by Canonical Combining Class.
 | ||||
| func insertOrdered(b Decomposition, r rune) Decomposition { | ||||
| 	n := len(b) | ||||
| 	b = append(b, 0) | ||||
| 	cc := ccc(r) | ||||
| 	if cc > 0 { | ||||
| 		// Use bubble sort.
 | ||||
| 		for ; n > 0; n-- { | ||||
| 			if ccc(b[n-1]) <= cc { | ||||
| 				break | ||||
| 			} | ||||
| 			b[n] = b[n-1] | ||||
| 		} | ||||
| 	} | ||||
| 	b[n] = r | ||||
| 	return b | ||||
| } | ||||
| 
 | ||||
| // Recursively decompose.
 | ||||
| func decomposeRecursive(form int, r rune, d Decomposition) Decomposition { | ||||
| 	dcomp := chars[r].forms[form].decomp | ||||
| 	if len(dcomp) == 0 { | ||||
| 		return insertOrdered(d, r) | ||||
| 	} | ||||
| 	for _, c := range dcomp { | ||||
| 		d = decomposeRecursive(form, c, d) | ||||
| 	} | ||||
| 	return d | ||||
| } | ||||
| 
 | ||||
| func completeCharFields(form int) { | ||||
| 	// Phase 0: pre-expand decomposition.
 | ||||
| 	for i := range chars { | ||||
| 		f := &chars[i].forms[form] | ||||
| 		if len(f.decomp) == 0 { | ||||
| 			continue | ||||
| 		} | ||||
| 		exp := make(Decomposition, 0) | ||||
| 		for _, c := range f.decomp { | ||||
| 			exp = decomposeRecursive(form, c, exp) | ||||
| 		} | ||||
| 		f.expandedDecomp = exp | ||||
| 	} | ||||
| 
 | ||||
| 	// Phase 1: composition exclusion, mark decomposition.
 | ||||
| 	for i := range chars { | ||||
| 		c := &chars[i] | ||||
| 		f := &c.forms[form] | ||||
| 
 | ||||
| 		// Marks script-specific exclusions and version restricted.
 | ||||
| 		f.isOneWay = c.excludeInComp | ||||
| 
 | ||||
| 		// Singletons
 | ||||
| 		f.isOneWay = f.isOneWay || len(f.decomp) == 1 | ||||
| 
 | ||||
| 		// Non-starter decompositions
 | ||||
| 		if len(f.decomp) > 1 { | ||||
| 			chk := c.ccc != 0 || chars[f.decomp[0]].ccc != 0 | ||||
| 			f.isOneWay = f.isOneWay || chk | ||||
| 		} | ||||
| 
 | ||||
| 		// Runes that decompose into more than two runes.
 | ||||
| 		f.isOneWay = f.isOneWay || len(f.decomp) > 2 | ||||
| 
 | ||||
| 		if form == FCompatibility { | ||||
| 			f.isOneWay = f.isOneWay || hasCompatDecomp(c.codePoint) | ||||
| 		} | ||||
| 
 | ||||
| 		for _, r := range f.decomp { | ||||
| 			chars[r].forms[form].inDecomp = true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Phase 2: forward and backward combining.
 | ||||
| 	for i := range chars { | ||||
| 		c := &chars[i] | ||||
| 		f := &c.forms[form] | ||||
| 
 | ||||
| 		if !f.isOneWay && len(f.decomp) == 2 { | ||||
| 			f0 := &chars[f.decomp[0]].forms[form] | ||||
| 			f1 := &chars[f.decomp[1]].forms[form] | ||||
| 			if !f0.isOneWay { | ||||
| 				f0.combinesForward = true | ||||
| 			} | ||||
| 			if !f1.isOneWay { | ||||
| 				f1.combinesBackward = true | ||||
| 			} | ||||
| 		} | ||||
| 		if isHangulWithoutJamoT(rune(i)) { | ||||
| 			f.combinesForward = true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Phase 3: quick check values.
 | ||||
| 	for i := range chars { | ||||
| 		c := &chars[i] | ||||
| 		f := &c.forms[form] | ||||
| 
 | ||||
| 		switch { | ||||
| 		case len(f.decomp) > 0: | ||||
| 			f.quickCheck[MDecomposed] = QCNo | ||||
| 		case isHangul(rune(i)): | ||||
| 			f.quickCheck[MDecomposed] = QCNo | ||||
| 		default: | ||||
| 			f.quickCheck[MDecomposed] = QCYes | ||||
| 		} | ||||
| 		switch { | ||||
| 		case f.isOneWay: | ||||
| 			f.quickCheck[MComposed] = QCNo | ||||
| 		case (i & 0xffff00) == JamoLBase: | ||||
| 			f.quickCheck[MComposed] = QCYes | ||||
| 			if JamoLBase <= i && i < JamoLEnd { | ||||
| 				f.combinesForward = true | ||||
| 			} | ||||
| 			if JamoVBase <= i && i < JamoVEnd { | ||||
| 				f.quickCheck[MComposed] = QCMaybe | ||||
| 				f.combinesBackward = true | ||||
| 				f.combinesForward = true | ||||
| 			} | ||||
| 			if JamoTBase <= i && i < JamoTEnd { | ||||
| 				f.quickCheck[MComposed] = QCMaybe | ||||
| 				f.combinesBackward = true | ||||
| 			} | ||||
| 		case !f.combinesBackward: | ||||
| 			f.quickCheck[MComposed] = QCYes | ||||
| 		default: | ||||
| 			f.quickCheck[MComposed] = QCMaybe | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func computeNonStarterCounts() { | ||||
| 	// Phase 4: leading and trailing non-starter count
 | ||||
| 	for i := range chars { | ||||
| 		c := &chars[i] | ||||
| 
 | ||||
| 		runes := []rune{rune(i)} | ||||
| 		// We always use FCompatibility so that the CGJ insertion points do not
 | ||||
| 		// change for repeated normalizations with different forms.
 | ||||
| 		if exp := c.forms[FCompatibility].expandedDecomp; len(exp) > 0 { | ||||
| 			runes = exp | ||||
| 		} | ||||
| 		// We consider runes that combine backwards to be non-starters for the
 | ||||
| 		// purpose of Stream-Safe Text Processing.
 | ||||
| 		for _, r := range runes { | ||||
| 			if cr := &chars[r]; cr.ccc == 0 && !cr.forms[FCompatibility].combinesBackward { | ||||
| 				break | ||||
| 			} | ||||
| 			c.nLeadingNonStarters++ | ||||
| 		} | ||||
| 		for i := len(runes) - 1; i >= 0; i-- { | ||||
| 			if cr := &chars[runes[i]]; cr.ccc == 0 && !cr.forms[FCompatibility].combinesBackward { | ||||
| 				break | ||||
| 			} | ||||
| 			c.nTrailingNonStarters++ | ||||
| 		} | ||||
| 		if c.nTrailingNonStarters > 3 { | ||||
| 			log.Fatalf("%U: Decomposition with more than 3 (%d) trailing modifiers (%U)", i, c.nTrailingNonStarters, runes) | ||||
| 		} | ||||
| 
 | ||||
| 		if isHangul(rune(i)) { | ||||
| 			c.nTrailingNonStarters = 2 | ||||
| 			if isHangulWithoutJamoT(rune(i)) { | ||||
| 				c.nTrailingNonStarters = 1 | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if l, t := c.nLeadingNonStarters, c.nTrailingNonStarters; l > 0 && l != t { | ||||
| 			log.Fatalf("%U: number of leading and trailing non-starters should be equal (%d vs %d)", i, l, t) | ||||
| 		} | ||||
| 		if t := c.nTrailingNonStarters; t > 3 { | ||||
| 			log.Fatalf("%U: number of trailing non-starters is %d > 3", t) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func printBytes(w io.Writer, b []byte, name string) { | ||||
| 	fmt.Fprintf(w, "// %s: %d bytes\n", name, len(b)) | ||||
| 	fmt.Fprintf(w, "var %s = [...]byte {", name) | ||||
| 	for i, c := range b { | ||||
| 		switch { | ||||
| 		case i%64 == 0: | ||||
| 			fmt.Fprintf(w, "\n// Bytes %x - %x\n", i, i+63) | ||||
| 		case i%8 == 0: | ||||
| 			fmt.Fprintf(w, "\n") | ||||
| 		} | ||||
| 		fmt.Fprintf(w, "0x%.2X, ", c) | ||||
| 	} | ||||
| 	fmt.Fprint(w, "\n}\n\n") | ||||
| } | ||||
| 
 | ||||
| // See forminfo.go for format.
 | ||||
| func makeEntry(f *FormInfo, c *Char) uint16 { | ||||
| 	e := uint16(0) | ||||
| 	if r := c.codePoint; HangulBase <= r && r < HangulEnd { | ||||
| 		e |= 0x40 | ||||
| 	} | ||||
| 	if f.combinesForward { | ||||
| 		e |= 0x20 | ||||
| 	} | ||||
| 	if f.quickCheck[MDecomposed] == QCNo { | ||||
| 		e |= 0x4 | ||||
| 	} | ||||
| 	switch f.quickCheck[MComposed] { | ||||
| 	case QCYes: | ||||
| 	case QCNo: | ||||
| 		e |= 0x10 | ||||
| 	case QCMaybe: | ||||
| 		e |= 0x18 | ||||
| 	default: | ||||
| 		log.Fatalf("Illegal quickcheck value %v.", f.quickCheck[MComposed]) | ||||
| 	} | ||||
| 	e |= uint16(c.nTrailingNonStarters) | ||||
| 	return e | ||||
| } | ||||
| 
 | ||||
| // decompSet keeps track of unique decompositions, grouped by whether
 | ||||
| // the decomposition is followed by a trailing and/or leading CCC.
 | ||||
| type decompSet [7]map[string]bool | ||||
| 
 | ||||
| const ( | ||||
| 	normalDecomp = iota | ||||
| 	firstMulti | ||||
| 	firstCCC | ||||
| 	endMulti | ||||
| 	firstLeadingCCC | ||||
| 	firstCCCZeroExcept | ||||
| 	firstStarterWithNLead | ||||
| 	lastDecomp | ||||
| ) | ||||
| 
 | ||||
| var cname = []string{"firstMulti", "firstCCC", "endMulti", "firstLeadingCCC", "firstCCCZeroExcept", "firstStarterWithNLead", "lastDecomp"} | ||||
| 
 | ||||
| func makeDecompSet() decompSet { | ||||
| 	m := decompSet{} | ||||
| 	for i := range m { | ||||
| 		m[i] = make(map[string]bool) | ||||
| 	} | ||||
| 	return m | ||||
| } | ||||
| func (m *decompSet) insert(key int, s string) { | ||||
| 	m[key][s] = true | ||||
| } | ||||
| 
 | ||||
| func printCharInfoTables(w io.Writer) int { | ||||
| 	mkstr := func(r rune, f *FormInfo) (int, string) { | ||||
| 		d := f.expandedDecomp | ||||
| 		s := string([]rune(d)) | ||||
| 		if max := 1 << 6; len(s) >= max { | ||||
| 			const msg = "%U: too many bytes in decomposition: %d >= %d" | ||||
| 			log.Fatalf(msg, r, len(s), max) | ||||
| 		} | ||||
| 		head := uint8(len(s)) | ||||
| 		if f.quickCheck[MComposed] != QCYes { | ||||
| 			head |= 0x40 | ||||
| 		} | ||||
| 		if f.combinesForward { | ||||
| 			head |= 0x80 | ||||
| 		} | ||||
| 		s = string([]byte{head}) + s | ||||
| 
 | ||||
| 		lccc := ccc(d[0]) | ||||
| 		tccc := ccc(d[len(d)-1]) | ||||
| 		cc := ccc(r) | ||||
| 		if cc != 0 && lccc == 0 && tccc == 0 { | ||||
| 			log.Fatalf("%U: trailing and leading ccc are 0 for non-zero ccc %d", r, cc) | ||||
| 		} | ||||
| 		if tccc < lccc && lccc != 0 { | ||||
| 			const msg = "%U: lccc (%d) must be <= tcc (%d)" | ||||
| 			log.Fatalf(msg, r, lccc, tccc) | ||||
| 		} | ||||
| 		index := normalDecomp | ||||
| 		nTrail := chars[r].nTrailingNonStarters | ||||
| 		nLead := chars[r].nLeadingNonStarters | ||||
| 		if tccc > 0 || lccc > 0 || nTrail > 0 { | ||||
| 			tccc <<= 2 | ||||
| 			tccc |= nTrail | ||||
| 			s += string([]byte{tccc}) | ||||
| 			index = endMulti | ||||
| 			for _, r := range d[1:] { | ||||
| 				if ccc(r) == 0 { | ||||
| 					index = firstCCC | ||||
| 				} | ||||
| 			} | ||||
| 			if lccc > 0 || nLead > 0 { | ||||
| 				s += string([]byte{lccc}) | ||||
| 				if index == firstCCC { | ||||
| 					log.Fatalf("%U: multi-segment decomposition not supported for decompositions with leading CCC != 0", r) | ||||
| 				} | ||||
| 				index = firstLeadingCCC | ||||
| 			} | ||||
| 			if cc != lccc { | ||||
| 				if cc != 0 { | ||||
| 					log.Fatalf("%U: for lccc != ccc, expected ccc to be 0; was %d", r, cc) | ||||
| 				} | ||||
| 				index = firstCCCZeroExcept | ||||
| 			} | ||||
| 		} else if len(d) > 1 { | ||||
| 			index = firstMulti | ||||
| 		} | ||||
| 		return index, s | ||||
| 	} | ||||
| 
 | ||||
| 	decompSet := makeDecompSet() | ||||
| 	const nLeadStr = "\x00\x01" // 0-byte length and tccc with nTrail.
 | ||||
| 	decompSet.insert(firstStarterWithNLead, nLeadStr) | ||||
| 
 | ||||
| 	// Store the uniqued decompositions in a byte buffer,
 | ||||
| 	// preceded by their byte length.
 | ||||
| 	for _, c := range chars { | ||||
| 		for _, f := range c.forms { | ||||
| 			if len(f.expandedDecomp) == 0 { | ||||
| 				continue | ||||
| 			} | ||||
| 			if f.combinesBackward { | ||||
| 				log.Fatalf("%U: combinesBackward and decompose", c.codePoint) | ||||
| 			} | ||||
| 			index, s := mkstr(c.codePoint, &f) | ||||
| 			decompSet.insert(index, s) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	decompositions := bytes.NewBuffer(make([]byte, 0, 10000)) | ||||
| 	size := 0 | ||||
| 	positionMap := make(map[string]uint16) | ||||
| 	decompositions.WriteString("\000") | ||||
| 	fmt.Fprintln(w, "const (") | ||||
| 	for i, m := range decompSet { | ||||
| 		sa := []string{} | ||||
| 		for s := range m { | ||||
| 			sa = append(sa, s) | ||||
| 		} | ||||
| 		sort.Strings(sa) | ||||
| 		for _, s := range sa { | ||||
| 			p := decompositions.Len() | ||||
| 			decompositions.WriteString(s) | ||||
| 			positionMap[s] = uint16(p) | ||||
| 		} | ||||
| 		if cname[i] != "" { | ||||
| 			fmt.Fprintf(w, "%s = 0x%X\n", cname[i], decompositions.Len()) | ||||
| 		} | ||||
| 	} | ||||
| 	fmt.Fprintln(w, "maxDecomp = 0x8000") | ||||
| 	fmt.Fprintln(w, ")") | ||||
| 	b := decompositions.Bytes() | ||||
| 	printBytes(w, b, "decomps") | ||||
| 	size += len(b) | ||||
| 
 | ||||
| 	varnames := []string{"nfc", "nfkc"} | ||||
| 	for i := 0; i < FNumberOfFormTypes; i++ { | ||||
| 		trie := triegen.NewTrie(varnames[i]) | ||||
| 
 | ||||
| 		for r, c := range chars { | ||||
| 			f := c.forms[i] | ||||
| 			d := f.expandedDecomp | ||||
| 			if len(d) != 0 { | ||||
| 				_, key := mkstr(c.codePoint, &f) | ||||
| 				trie.Insert(rune(r), uint64(positionMap[key])) | ||||
| 				if c.ccc != ccc(d[0]) { | ||||
| 					// We assume the lead ccc of a decomposition !=0 in this case.
 | ||||
| 					if ccc(d[0]) == 0 { | ||||
| 						log.Fatalf("Expected leading CCC to be non-zero; ccc is %d", c.ccc) | ||||
| 					} | ||||
| 				} | ||||
| 			} else if c.nLeadingNonStarters > 0 && len(f.expandedDecomp) == 0 && c.ccc == 0 && !f.combinesBackward { | ||||
| 				// Handle cases where it can't be detected that the nLead should be equal
 | ||||
| 				// to nTrail.
 | ||||
| 				trie.Insert(c.codePoint, uint64(positionMap[nLeadStr])) | ||||
| 			} else if v := makeEntry(&f, &c)<<8 | uint16(c.ccc); v != 0 { | ||||
| 				trie.Insert(c.codePoint, uint64(0x8000|v)) | ||||
| 			} | ||||
| 		} | ||||
| 		sz, err := trie.Gen(w, triegen.Compact(&normCompacter{name: varnames[i]})) | ||||
| 		if err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
| 		size += sz | ||||
| 	} | ||||
| 	return size | ||||
| } | ||||
| 
 | ||||
| func contains(sa []string, s string) bool { | ||||
| 	for _, a := range sa { | ||||
| 		if a == s { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func makeTables() { | ||||
| 	w := &bytes.Buffer{} | ||||
| 
 | ||||
| 	size := 0 | ||||
| 	if *tablelist == "" { | ||||
| 		return | ||||
| 	} | ||||
| 	list := strings.Split(*tablelist, ",") | ||||
| 	if *tablelist == "all" { | ||||
| 		list = []string{"recomp", "info"} | ||||
| 	} | ||||
| 
 | ||||
| 	// Compute maximum decomposition size.
 | ||||
| 	max := 0 | ||||
| 	for _, c := range chars { | ||||
| 		if n := len(string(c.forms[FCompatibility].expandedDecomp)); n > max { | ||||
| 			max = n | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Fprintln(w, "const (") | ||||
| 	fmt.Fprintln(w, "\t// Version is the Unicode edition from which the tables are derived.") | ||||
| 	fmt.Fprintf(w, "\tVersion = %q\n", gen.UnicodeVersion()) | ||||
| 	fmt.Fprintln(w) | ||||
| 	fmt.Fprintln(w, "\t// MaxTransformChunkSize indicates the maximum number of bytes that Transform") | ||||
| 	fmt.Fprintln(w, "\t// may need to write atomically for any Form. Making a destination buffer at") | ||||
| 	fmt.Fprintln(w, "\t// least this size ensures that Transform can always make progress and that") | ||||
| 	fmt.Fprintln(w, "\t// the user does not need to grow the buffer on an ErrShortDst.") | ||||
| 	fmt.Fprintf(w, "\tMaxTransformChunkSize = %d+maxNonStarters*4\n", len(string(0x034F))+max) | ||||
| 	fmt.Fprintln(w, ")\n") | ||||
| 
 | ||||
| 	// Print the CCC remap table.
 | ||||
| 	size += len(cccMap) | ||||
| 	fmt.Fprintf(w, "var ccc = [%d]uint8{", len(cccMap)) | ||||
| 	for i := 0; i < len(cccMap); i++ { | ||||
| 		if i%8 == 0 { | ||||
| 			fmt.Fprintln(w) | ||||
| 		} | ||||
| 		fmt.Fprintf(w, "%3d, ", cccMap[uint8(i)]) | ||||
| 	} | ||||
| 	fmt.Fprintln(w, "\n}\n") | ||||
| 
 | ||||
| 	if contains(list, "info") { | ||||
| 		size += printCharInfoTables(w) | ||||
| 	} | ||||
| 
 | ||||
| 	if contains(list, "recomp") { | ||||
| 		// Note that we use 32 bit keys, instead of 64 bit.
 | ||||
| 		// This clips the bits of three entries, but we know
 | ||||
| 		// this won't cause a collision. The compiler will catch
 | ||||
| 		// any changes made to UnicodeData.txt that introduces
 | ||||
| 		// a collision.
 | ||||
| 		// Note that the recomposition map for NFC and NFKC
 | ||||
| 		// are identical.
 | ||||
| 
 | ||||
| 		// Recomposition map
 | ||||
| 		nrentries := 0 | ||||
| 		for _, c := range chars { | ||||
| 			f := c.forms[FCanonical] | ||||
| 			if !f.isOneWay && len(f.decomp) > 0 { | ||||
| 				nrentries++ | ||||
| 			} | ||||
| 		} | ||||
| 		sz := nrentries * 8 | ||||
| 		size += sz | ||||
| 		fmt.Fprintf(w, "// recompMap: %d bytes (entries only)\n", sz) | ||||
| 		fmt.Fprintln(w, "var recompMap = map[uint32]rune{") | ||||
| 		for i, c := range chars { | ||||
| 			f := c.forms[FCanonical] | ||||
| 			d := f.decomp | ||||
| 			if !f.isOneWay && len(d) > 0 { | ||||
| 				key := uint32(uint16(d[0]))<<16 + uint32(uint16(d[1])) | ||||
| 				fmt.Fprintf(w, "0x%.8X: 0x%.4X,\n", key, i) | ||||
| 			} | ||||
| 		} | ||||
| 		fmt.Fprintf(w, "}\n\n") | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Fprintf(w, "// Total size of tables: %dKB (%d bytes)\n", (size+512)/1024, size) | ||||
| 	gen.WriteVersionedGoFile("tables.go", "norm", w.Bytes()) | ||||
| } | ||||
| 
 | ||||
| func printChars() { | ||||
| 	if *verbose { | ||||
| 		for _, c := range chars { | ||||
| 			if !c.isValid() || c.state == SMissing { | ||||
| 				continue | ||||
| 			} | ||||
| 			fmt.Println(c) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // verifyComputed does various consistency tests.
 | ||||
| func verifyComputed() { | ||||
| 	for i, c := range chars { | ||||
| 		for _, f := range c.forms { | ||||
| 			isNo := (f.quickCheck[MDecomposed] == QCNo) | ||||
| 			if (len(f.decomp) > 0) != isNo && !isHangul(rune(i)) { | ||||
| 				log.Fatalf("%U: NF*D QC must be No if rune decomposes", i) | ||||
| 			} | ||||
| 
 | ||||
| 			isMaybe := f.quickCheck[MComposed] == QCMaybe | ||||
| 			if f.combinesBackward != isMaybe { | ||||
| 				log.Fatalf("%U: NF*C QC must be Maybe if combinesBackward", i) | ||||
| 			} | ||||
| 			if len(f.decomp) > 0 && f.combinesForward && isMaybe { | ||||
| 				log.Fatalf("%U: NF*C QC must be Yes or No if combinesForward and decomposes", i) | ||||
| 			} | ||||
| 
 | ||||
| 			if len(f.expandedDecomp) != 0 { | ||||
| 				continue | ||||
| 			} | ||||
| 			if a, b := c.nLeadingNonStarters > 0, (c.ccc > 0 || f.combinesBackward); a != b { | ||||
| 				// We accept these runes to be treated differently (it only affects
 | ||||
| 				// segment breaking in iteration, most likely on improper use), but
 | ||||
| 				// reconsider if more characters are added.
 | ||||
| 				// U+FF9E HALFWIDTH KATAKANA VOICED SOUND MARK;Lm;0;L;<narrow> 3099;;;;N;;;;;
 | ||||
| 				// U+FF9F HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK;Lm;0;L;<narrow> 309A;;;;N;;;;;
 | ||||
| 				// U+3133 HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;;
 | ||||
| 				// U+318E HANGUL LETTER ARAEAE;Lo;0;L;<compat> 11A1;;;;N;HANGUL LETTER ALAE AE;;;;
 | ||||
| 				// U+FFA3 HALFWIDTH HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<narrow> 3133;;;;N;HALFWIDTH HANGUL LETTER GIYEOG SIOS;;;;
 | ||||
| 				// U+FFDC HALFWIDTH HANGUL LETTER I;Lo;0;L;<narrow> 3163;;;;N;;;;;
 | ||||
| 				if i != 0xFF9E && i != 0xFF9F && !(0x3133 <= i && i <= 0x318E) && !(0xFFA3 <= i && i <= 0xFFDC) { | ||||
| 					log.Fatalf("%U: nLead was %v; want %v", i, a, b) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		nfc := c.forms[FCanonical] | ||||
| 		nfkc := c.forms[FCompatibility] | ||||
| 		if nfc.combinesBackward != nfkc.combinesBackward { | ||||
| 			log.Fatalf("%U: Cannot combine combinesBackward\n", c.codePoint) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Use values in DerivedNormalizationProps.txt to compare against the
 | ||||
| // values we computed.
 | ||||
| // DerivedNormalizationProps.txt has form:
 | ||||
| // 00C0..00C5    ; NFD_QC; N # ...
 | ||||
| // 0374          ; NFD_QC; N # ...
 | ||||
| // See http://unicode.org/reports/tr44/ for full explanation
 | ||||
| func testDerived() { | ||||
| 	f := gen.OpenUCDFile("DerivedNormalizationProps.txt") | ||||
| 	defer f.Close() | ||||
| 	p := ucd.New(f) | ||||
| 	for p.Next() { | ||||
| 		r := p.Rune(0) | ||||
| 		c := &chars[r] | ||||
| 
 | ||||
| 		var ftype, mode int | ||||
| 		qt := p.String(1) | ||||
| 		switch qt { | ||||
| 		case "NFC_QC": | ||||
| 			ftype, mode = FCanonical, MComposed | ||||
| 		case "NFD_QC": | ||||
| 			ftype, mode = FCanonical, MDecomposed | ||||
| 		case "NFKC_QC": | ||||
| 			ftype, mode = FCompatibility, MComposed | ||||
| 		case "NFKD_QC": | ||||
| 			ftype, mode = FCompatibility, MDecomposed | ||||
| 		default: | ||||
| 			continue | ||||
| 		} | ||||
| 		var qr QCResult | ||||
| 		switch p.String(2) { | ||||
| 		case "Y": | ||||
| 			qr = QCYes | ||||
| 		case "N": | ||||
| 			qr = QCNo | ||||
| 		case "M": | ||||
| 			qr = QCMaybe | ||||
| 		default: | ||||
| 			log.Fatalf(`Unexpected quick check value "%s"`, p.String(2)) | ||||
| 		} | ||||
| 		if got := c.forms[ftype].quickCheck[mode]; got != qr { | ||||
| 			log.Printf("%U: FAILED %s (was %v need %v)\n", r, qt, got, qr) | ||||
| 		} | ||||
| 		c.forms[ftype].verified[mode] = true | ||||
| 	} | ||||
| 	if err := p.Err(); err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	// Any unspecified value must be QCYes. Verify this.
 | ||||
| 	for i, c := range chars { | ||||
| 		for j, fd := range c.forms { | ||||
| 			for k, qr := range fd.quickCheck { | ||||
| 				if !fd.verified[k] && qr != QCYes { | ||||
| 					m := "%U: FAIL F:%d M:%d (was %v need Yes) %s\n" | ||||
| 					log.Printf(m, i, j, k, qr, c.name) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| var testHeader = `const ( | ||||
| 	Yes = iota | ||||
| 	No | ||||
| 	Maybe | ||||
| ) | ||||
| 
 | ||||
| type formData struct { | ||||
| 	qc              uint8 | ||||
| 	combinesForward bool | ||||
| 	decomposition   string | ||||
| } | ||||
| 
 | ||||
| type runeData struct { | ||||
| 	r      rune | ||||
| 	ccc    uint8 | ||||
| 	nLead  uint8 | ||||
| 	nTrail uint8 | ||||
| 	f      [2]formData // 0: canonical; 1: compatibility
 | ||||
| } | ||||
| 
 | ||||
| func f(qc uint8, cf bool, dec string) [2]formData { | ||||
| 	return [2]formData{{qc, cf, dec}, {qc, cf, dec}} | ||||
| } | ||||
| 
 | ||||
| func g(qc, qck uint8, cf, cfk bool, d, dk string) [2]formData { | ||||
| 	return [2]formData{{qc, cf, d}, {qck, cfk, dk}} | ||||
| } | ||||
| 
 | ||||
| var testData = []runeData{ | ||||
| ` | ||||
| 
 | ||||
| func printTestdata() { | ||||
| 	type lastInfo struct { | ||||
| 		ccc    uint8 | ||||
| 		nLead  uint8 | ||||
| 		nTrail uint8 | ||||
| 		f      string | ||||
| 	} | ||||
| 
 | ||||
| 	last := lastInfo{} | ||||
| 	w := &bytes.Buffer{} | ||||
| 	fmt.Fprintf(w, testHeader) | ||||
| 	for r, c := range chars { | ||||
| 		f := c.forms[FCanonical] | ||||
| 		qc, cf, d := f.quickCheck[MComposed], f.combinesForward, string(f.expandedDecomp) | ||||
| 		f = c.forms[FCompatibility] | ||||
| 		qck, cfk, dk := f.quickCheck[MComposed], f.combinesForward, string(f.expandedDecomp) | ||||
| 		s := "" | ||||
| 		if d == dk && qc == qck && cf == cfk { | ||||
| 			s = fmt.Sprintf("f(%s, %v, %q)", qc, cf, d) | ||||
| 		} else { | ||||
| 			s = fmt.Sprintf("g(%s, %s, %v, %v, %q, %q)", qc, qck, cf, cfk, d, dk) | ||||
| 		} | ||||
| 		current := lastInfo{c.ccc, c.nLeadingNonStarters, c.nTrailingNonStarters, s} | ||||
| 		if last != current { | ||||
| 			fmt.Fprintf(w, "\t{0x%x, %d, %d, %d, %s},\n", r, c.origCCC, c.nLeadingNonStarters, c.nTrailingNonStarters, s) | ||||
| 			last = current | ||||
| 		} | ||||
| 	} | ||||
| 	fmt.Fprintln(w, "}") | ||||
| 	gen.WriteVersionedGoFile("data_test.go", "norm", w.Bytes()) | ||||
| } | ||||
|  | @ -1,117 +0,0 @@ | |||
| // Copyright 2011 The Go Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // +build ignore
 | ||||
| 
 | ||||
| // Trie table generator.
 | ||||
| // Used by make*tables tools to generate a go file with trie data structures
 | ||||
| // for mapping UTF-8 to a 16-bit value. All but the last byte in a UTF-8 byte
 | ||||
| // sequence are used to lookup offsets in the index table to be used for the
 | ||||
| // next byte. The last byte is used to index into a table with 16-bit values.
 | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| ) | ||||
| 
 | ||||
| const maxSparseEntries = 16 | ||||
| 
 | ||||
| type normCompacter struct { | ||||
| 	sparseBlocks [][]uint64 | ||||
| 	sparseOffset []uint16 | ||||
| 	sparseCount  int | ||||
| 	name         string | ||||
| } | ||||
| 
 | ||||
| func mostFrequentStride(a []uint64) int { | ||||
| 	counts := make(map[int]int) | ||||
| 	var v int | ||||
| 	for _, x := range a { | ||||
| 		if stride := int(x) - v; v != 0 && stride >= 0 { | ||||
| 			counts[stride]++ | ||||
| 		} | ||||
| 		v = int(x) | ||||
| 	} | ||||
| 	var maxs, maxc int | ||||
| 	for stride, cnt := range counts { | ||||
| 		if cnt > maxc || (cnt == maxc && stride < maxs) { | ||||
| 			maxs, maxc = stride, cnt | ||||
| 		} | ||||
| 	} | ||||
| 	return maxs | ||||
| } | ||||
| 
 | ||||
| func countSparseEntries(a []uint64) int { | ||||
| 	stride := mostFrequentStride(a) | ||||
| 	var v, count int | ||||
| 	for _, tv := range a { | ||||
| 		if int(tv)-v != stride { | ||||
| 			if tv != 0 { | ||||
| 				count++ | ||||
| 			} | ||||
| 		} | ||||
| 		v = int(tv) | ||||
| 	} | ||||
| 	return count | ||||
| } | ||||
| 
 | ||||
| func (c *normCompacter) Size(v []uint64) (sz int, ok bool) { | ||||
| 	if n := countSparseEntries(v); n <= maxSparseEntries { | ||||
| 		return (n+1)*4 + 2, true | ||||
| 	} | ||||
| 	return 0, false | ||||
| } | ||||
| 
 | ||||
| func (c *normCompacter) Store(v []uint64) uint32 { | ||||
| 	h := uint32(len(c.sparseOffset)) | ||||
| 	c.sparseBlocks = append(c.sparseBlocks, v) | ||||
| 	c.sparseOffset = append(c.sparseOffset, uint16(c.sparseCount)) | ||||
| 	c.sparseCount += countSparseEntries(v) + 1 | ||||
| 	return h | ||||
| } | ||||
| 
 | ||||
| func (c *normCompacter) Handler() string { | ||||
| 	return c.name + "Sparse.lookup" | ||||
| } | ||||
| 
 | ||||
| func (c *normCompacter) Print(w io.Writer) (retErr error) { | ||||
| 	p := func(f string, x ...interface{}) { | ||||
| 		if _, err := fmt.Fprintf(w, f, x...); retErr == nil && err != nil { | ||||
| 			retErr = err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ls := len(c.sparseBlocks) | ||||
| 	p("// %sSparseOffset: %d entries, %d bytes\n", c.name, ls, ls*2) | ||||
| 	p("var %sSparseOffset = %#v\n\n", c.name, c.sparseOffset) | ||||
| 
 | ||||
| 	ns := c.sparseCount | ||||
| 	p("// %sSparseValues: %d entries, %d bytes\n", c.name, ns, ns*4) | ||||
| 	p("var %sSparseValues = [%d]valueRange {", c.name, ns) | ||||
| 	for i, b := range c.sparseBlocks { | ||||
| 		p("\n// Block %#x, offset %#x", i, c.sparseOffset[i]) | ||||
| 		var v int | ||||
| 		stride := mostFrequentStride(b) | ||||
| 		n := countSparseEntries(b) | ||||
| 		p("\n{value:%#04x,lo:%#02x},", stride, uint8(n)) | ||||
| 		for i, nv := range b { | ||||
| 			if int(nv)-v != stride { | ||||
| 				if v != 0 { | ||||
| 					p(",hi:%#02x},", 0x80+i-1) | ||||
| 				} | ||||
| 				if nv != 0 { | ||||
| 					p("\n{value:%#04x,lo:%#02x", nv, 0x80+i) | ||||
| 				} | ||||
| 			} | ||||
| 			v = int(nv) | ||||
| 		} | ||||
| 		if v != 0 { | ||||
| 			p(",hi:%#02x},", 0x80+len(b)-1) | ||||
| 		} | ||||
| 	} | ||||
| 	p("\n}\n\n") | ||||
| 	return | ||||
| } | ||||
|  | @ -5,44 +5,44 @@ github.com/Azure/azure-sdk-for-go/storage | |||
| github.com/Azure/azure-sdk-for-go/version | ||||
| # github.com/Azure/go-autorest v10.8.1+incompatible | ||||
| github.com/Azure/go-autorest/autorest | ||||
| github.com/Azure/go-autorest/autorest/azure | ||||
| github.com/Azure/go-autorest/autorest/adal | ||||
| github.com/Azure/go-autorest/autorest/azure | ||||
| github.com/Azure/go-autorest/autorest/date | ||||
| # github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d | ||||
| github.com/Shopify/logrus-bugsnag | ||||
| # github.com/aws/aws-sdk-go v1.15.11 | ||||
| github.com/aws/aws-sdk-go/service/cloudfront/sign | ||||
| github.com/aws/aws-sdk-go/aws | ||||
| github.com/aws/aws-sdk-go/aws/awserr | ||||
| github.com/aws/aws-sdk-go/aws/awsutil | ||||
| github.com/aws/aws-sdk-go/aws/client | ||||
| github.com/aws/aws-sdk-go/aws/client/metadata | ||||
| github.com/aws/aws-sdk-go/aws/corehandlers | ||||
| github.com/aws/aws-sdk-go/aws/credentials | ||||
| github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds | ||||
| github.com/aws/aws-sdk-go/aws/credentials/endpointcreds | ||||
| github.com/aws/aws-sdk-go/aws/credentials/stscreds | ||||
| github.com/aws/aws-sdk-go/aws/csm | ||||
| github.com/aws/aws-sdk-go/aws/defaults | ||||
| github.com/aws/aws-sdk-go/aws/ec2metadata | ||||
| github.com/aws/aws-sdk-go/aws/endpoints | ||||
| github.com/aws/aws-sdk-go/aws/request | ||||
| github.com/aws/aws-sdk-go/aws/session | ||||
| github.com/aws/aws-sdk-go/service/s3 | ||||
| github.com/aws/aws-sdk-go/internal/sdkio | ||||
| github.com/aws/aws-sdk-go/internal/shareddefaults | ||||
| github.com/aws/aws-sdk-go/aws/client | ||||
| github.com/aws/aws-sdk-go/internal/sdkuri | ||||
| github.com/aws/aws-sdk-go/aws/client/metadata | ||||
| github.com/aws/aws-sdk-go/aws/awsutil | ||||
| github.com/aws/aws-sdk-go/aws/credentials/stscreds | ||||
| github.com/aws/aws-sdk-go/aws/csm | ||||
| github.com/aws/aws-sdk-go/aws/defaults | ||||
| github.com/aws/aws-sdk-go/aws/signer/v4 | ||||
| github.com/aws/aws-sdk-go/internal/sdkio | ||||
| github.com/aws/aws-sdk-go/internal/sdkrand | ||||
| github.com/aws/aws-sdk-go/internal/sdkuri | ||||
| github.com/aws/aws-sdk-go/internal/shareddefaults | ||||
| github.com/aws/aws-sdk-go/private/protocol | ||||
| github.com/aws/aws-sdk-go/private/protocol/eventstream | ||||
| github.com/aws/aws-sdk-go/private/protocol/eventstream/eventstreamapi | ||||
| github.com/aws/aws-sdk-go/private/protocol/query | ||||
| github.com/aws/aws-sdk-go/private/protocol/query/queryutil | ||||
| github.com/aws/aws-sdk-go/private/protocol/rest | ||||
| github.com/aws/aws-sdk-go/private/protocol/restxml | ||||
| github.com/aws/aws-sdk-go/internal/sdkrand | ||||
| github.com/aws/aws-sdk-go/service/sts | ||||
| github.com/aws/aws-sdk-go/aws/credentials/endpointcreds | ||||
| github.com/aws/aws-sdk-go/private/protocol/query | ||||
| github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil | ||||
| github.com/aws/aws-sdk-go/private/protocol/query/queryutil | ||||
| github.com/aws/aws-sdk-go/service/cloudfront/sign | ||||
| github.com/aws/aws-sdk-go/service/s3 | ||||
| github.com/aws/aws-sdk-go/service/sts | ||||
| # github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a | ||||
| github.com/beorn7/perks/quantile | ||||
| # github.com/bshuster-repo/logrus-logstash-hook v0.4.1 | ||||
|  | @ -56,8 +56,8 @@ github.com/bugsnag/osext | |||
| github.com/bugsnag/panicwrap | ||||
| # github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba | ||||
| github.com/denverdino/aliyungo/cdn/auth | ||||
| github.com/denverdino/aliyungo/oss | ||||
| github.com/denverdino/aliyungo/common | ||||
| github.com/denverdino/aliyungo/oss | ||||
| github.com/denverdino/aliyungo/util | ||||
| # github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c | ||||
| github.com/dgrijalva/jwt-go | ||||
|  | @ -66,8 +66,8 @@ github.com/docker/go-metrics | |||
| # github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 | ||||
| github.com/docker/libtrust | ||||
| # github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 | ||||
| github.com/garyburd/redigo/redis | ||||
| github.com/garyburd/redigo/internal | ||||
| github.com/garyburd/redigo/redis | ||||
| # github.com/go-ini/ini v1.25.4 | ||||
| github.com/go-ini/ini | ||||
| # github.com/golang/protobuf v1.2.0 | ||||
|  | @ -94,8 +94,8 @@ github.com/ncw/swift/swifttest | |||
| # github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420 | ||||
| github.com/opencontainers/go-digest | ||||
| # github.com/opencontainers/image-spec v1.0.0 | ||||
| github.com/opencontainers/image-spec/specs-go/v1 | ||||
| github.com/opencontainers/image-spec/specs-go | ||||
| github.com/opencontainers/image-spec/specs-go/v1 | ||||
| # github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06 | ||||
| github.com/prometheus/client_golang/prometheus | ||||
| github.com/prometheus/client_golang/prometheus/promhttp | ||||
|  | @ -103,13 +103,13 @@ github.com/prometheus/client_golang/prometheus/promhttp | |||
| github.com/prometheus/client_model/go | ||||
| # github.com/prometheus/common v0.0.0-20180110214958-89604d197083 | ||||
| github.com/prometheus/common/expfmt | ||||
| github.com/prometheus/common/model | ||||
| github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg | ||||
| github.com/prometheus/common/model | ||||
| # github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7 | ||||
| github.com/prometheus/procfs | ||||
| github.com/prometheus/procfs/internal/util | ||||
| github.com/prometheus/procfs/nfs | ||||
| github.com/prometheus/procfs/xfs | ||||
| github.com/prometheus/procfs/internal/util | ||||
| # github.com/satori/go.uuid v1.2.0 | ||||
| github.com/satori/go.uuid | ||||
| # github.com/sirupsen/logrus v1.4.2 | ||||
|  | @ -124,7 +124,7 @@ github.com/yvasiyarov/go-metrics | |||
| github.com/yvasiyarov/gorelic | ||||
| # github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f | ||||
| github.com/yvasiyarov/newrelic_platform_go | ||||
| # golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 | ||||
| # golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d | ||||
| golang.org/x/crypto/acme | ||||
| golang.org/x/crypto/acme/autocert | ||||
| golang.org/x/crypto/bcrypt | ||||
|  | @ -132,46 +132,46 @@ golang.org/x/crypto/blowfish | |||
| # golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b | ||||
| golang.org/x/net/context | ||||
| golang.org/x/net/context/ctxhttp | ||||
| golang.org/x/net/http2 | ||||
| golang.org/x/net/trace | ||||
| golang.org/x/net/http/httpguts | ||||
| golang.org/x/net/http2 | ||||
| golang.org/x/net/http2/hpack | ||||
| golang.org/x/net/idna | ||||
| golang.org/x/net/internal/timeseries | ||||
| golang.org/x/net/trace | ||||
| # golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 | ||||
| golang.org/x/oauth2 | ||||
| golang.org/x/oauth2/google | ||||
| golang.org/x/oauth2/jwt | ||||
| golang.org/x/oauth2/internal | ||||
| golang.org/x/oauth2/jws | ||||
| golang.org/x/oauth2/jwt | ||||
| # golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed | ||||
| golang.org/x/sys/unix | ||||
| # golang.org/x/text v0.3.0 | ||||
| golang.org/x/text/secure/bidirule | ||||
| golang.org/x/text/transform | ||||
| golang.org/x/text/unicode/bidi | ||||
| golang.org/x/text/unicode/norm | ||||
| golang.org/x/text/transform | ||||
| # google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff | ||||
| google.golang.org/api/gensupport | ||||
| google.golang.org/api/googleapi | ||||
| google.golang.org/api/googleapi/internal/uritemplates | ||||
| google.golang.org/api/storage/v1 | ||||
| google.golang.org/api/gensupport | ||||
| # google.golang.org/appengine v1.4.0 | ||||
| google.golang.org/appengine | ||||
| google.golang.org/appengine/urlfetch | ||||
| google.golang.org/appengine/internal | ||||
| google.golang.org/appengine/internal/app_identity | ||||
| google.golang.org/appengine/internal/modules | ||||
| google.golang.org/appengine/internal/urlfetch | ||||
| google.golang.org/appengine/internal/base | ||||
| google.golang.org/appengine/internal/datastore | ||||
| google.golang.org/appengine/internal/log | ||||
| google.golang.org/appengine/internal/modules | ||||
| google.golang.org/appengine/internal/remote_api | ||||
| google.golang.org/appengine/internal/urlfetch | ||||
| google.golang.org/appengine/urlfetch | ||||
| # google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8 | ||||
| google.golang.org/cloud | ||||
| google.golang.org/cloud/storage | ||||
| google.golang.org/cloud/internal | ||||
| google.golang.org/cloud/internal/opts | ||||
| google.golang.org/cloud/storage | ||||
| # google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a | ||||
| google.golang.org/grpc | ||||
| google.golang.org/grpc/codes | ||||
|  | @ -180,8 +180,8 @@ google.golang.org/grpc/grpclog | |||
| google.golang.org/grpc/internal | ||||
| google.golang.org/grpc/metadata | ||||
| google.golang.org/grpc/naming | ||||
| google.golang.org/grpc/transport | ||||
| google.golang.org/grpc/peer | ||||
| google.golang.org/grpc/transport | ||||
| # gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789 | ||||
| gopkg.in/check.v1 | ||||
| # gopkg.in/yaml.v2 v2.2.2 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue