Bo-Yi Wu
7 years ago
271 changed files with 169964 additions and 6 deletions
@ -0,0 +1,123 @@ |
|||||
|
# 1.0.5 |
||||
|
|
||||
|
* Fix hooks race (#707) |
||||
|
* Fix panic deadlock (#695) |
||||
|
|
||||
|
# 1.0.4 |
||||
|
|
||||
|
* Fix race when adding hooks (#612) |
||||
|
* Fix terminal check in AppEngine (#635) |
||||
|
|
||||
|
# 1.0.3 |
||||
|
|
||||
|
* Replace example files with testable examples |
||||
|
|
||||
|
# 1.0.2 |
||||
|
|
||||
|
* bug: quote non-string values in text formatter (#583) |
||||
|
* Make (*Logger) SetLevel a public method |
||||
|
|
||||
|
# 1.0.1 |
||||
|
|
||||
|
* bug: fix escaping in text formatter (#575) |
||||
|
|
||||
|
# 1.0.0 |
||||
|
|
||||
|
* Officially changed name to lower-case |
||||
|
* bug: colors on Windows 10 (#541) |
||||
|
* bug: fix race in accessing level (#512) |
||||
|
|
||||
|
# 0.11.5 |
||||
|
|
||||
|
* feature: add writer and writerlevel to entry (#372) |
||||
|
|
||||
|
# 0.11.4 |
||||
|
|
||||
|
* bug: fix undefined variable on solaris (#493) |
||||
|
|
||||
|
# 0.11.3 |
||||
|
|
||||
|
* formatter: configure quoting of empty values (#484) |
||||
|
* formatter: configure quoting character (default is `"`) (#484) |
||||
|
* bug: fix not importing io correctly in non-linux environments (#481) |
||||
|
|
||||
|
# 0.11.2 |
||||
|
|
||||
|
* bug: fix windows terminal detection (#476) |
||||
|
|
||||
|
# 0.11.1 |
||||
|
|
||||
|
* bug: fix tty detection with custom out (#471) |
||||
|
|
||||
|
# 0.11.0 |
||||
|
|
||||
|
* performance: Use bufferpool to allocate (#370) |
||||
|
* terminal: terminal detection for app-engine (#343) |
||||
|
* feature: exit handler (#375) |
||||
|
|
||||
|
# 0.10.0 |
||||
|
|
||||
|
* feature: Add a test hook (#180) |
||||
|
* feature: `ParseLevel` is now case-insensitive (#326) |
||||
|
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308) |
||||
|
* performance: avoid re-allocations on `WithFields` (#335) |
||||
|
|
||||
|
# 0.9.0 |
||||
|
|
||||
|
* logrus/text_formatter: don't emit empty msg |
||||
|
* logrus/hooks/airbrake: move out of main repository |
||||
|
* logrus/hooks/sentry: move out of main repository |
||||
|
* logrus/hooks/papertrail: move out of main repository |
||||
|
* logrus/hooks/bugsnag: move out of main repository |
||||
|
* logrus/core: run tests with `-race` |
||||
|
* logrus/core: detect TTY based on `stderr` |
||||
|
* logrus/core: support `WithError` on logger |
||||
|
* logrus/core: Solaris support |
||||
|
|
||||
|
# 0.8.7 |
||||
|
|
||||
|
* logrus/core: fix possible race (#216) |
||||
|
* logrus/doc: small typo fixes and doc improvements |
||||
|
|
||||
|
|
||||
|
# 0.8.6 |
||||
|
|
||||
|
* hooks/raven: allow passing an initialized client |
||||
|
|
||||
|
# 0.8.5 |
||||
|
|
||||
|
* logrus/core: revert #208 |
||||
|
|
||||
|
# 0.8.4 |
||||
|
|
||||
|
* formatter/text: fix data race (#218) |
||||
|
|
||||
|
# 0.8.3 |
||||
|
|
||||
|
* logrus/core: fix entry log level (#208) |
||||
|
* logrus/core: improve performance of text formatter by 40% |
||||
|
* logrus/core: expose `LevelHooks` type |
||||
|
* logrus/core: add support for DragonflyBSD and NetBSD |
||||
|
* formatter/text: print structs more verbosely |
||||
|
|
||||
|
# 0.8.2 |
||||
|
|
||||
|
* logrus: fix more Fatal family functions |
||||
|
|
||||
|
# 0.8.1 |
||||
|
|
||||
|
* logrus: fix not exiting on `Fatalf` and `Fatalln` |
||||
|
|
||||
|
# 0.8.0 |
||||
|
|
||||
|
* logrus: defaults to stderr instead of stdout |
||||
|
* hooks/sentry: add special field for `*http.Request` |
||||
|
* formatter/text: ignore Windows for colors |
||||
|
|
||||
|
# 0.7.3 |
||||
|
|
||||
|
* formatter/\*: allow configuration of timestamp layout |
||||
|
|
||||
|
# 0.7.2 |
||||
|
|
||||
|
* formatter/text: Add configuration option for time format (#158) |
@ -0,0 +1,21 @@ |
|||||
|
The MIT License (MIT) |
||||
|
|
||||
|
Copyright (c) 2014 Simon Eskildsen |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), to deal |
||||
|
in the Software without restriction, including without limitation the rights |
||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
|
copies of the Software, and to permit persons to whom the Software is |
||||
|
furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in |
||||
|
all copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
|
THE SOFTWARE. |
@ -0,0 +1,461 @@ |
|||||
|
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus) |
||||
|
|
||||
|
Logrus is a structured logger for Go (golang), completely API compatible with |
||||
|
the standard library logger. |
||||
|
|
||||
|
**Seeing weird case-sensitive problems?** It's in the past been possible to |
||||
|
import Logrus as both upper- and lower-case. Due to the Go package environment, |
||||
|
this caused issues in the community and we needed a standard. Some environments |
||||
|
experienced problems with the upper-case variant, so the lower-case was decided. |
||||
|
Everything using `logrus` will need to use the lower-case: |
||||
|
`github.com/sirupsen/logrus`. Any package that isn't, should be changed. |
||||
|
|
||||
|
To fix Glide, see [these |
||||
|
comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437). |
||||
|
For an in-depth explanation of the casing issue, see [this |
||||
|
comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276). |
||||
|
|
||||
|
**Are you interested in assisting in maintaining Logrus?** Currently I have a |
||||
|
lot of obligations, and I am unable to provide Logrus with the maintainership it |
||||
|
needs. If you'd like to help, please reach out to me at `simon at author's |
||||
|
username dot com`. |
||||
|
|
||||
|
Nicely color-coded in development (when a TTY is attached, otherwise just |
||||
|
plain text): |
||||
|
|
||||
|
![Colored](http://i.imgur.com/PY7qMwd.png) |
||||
|
|
||||
|
With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash |
||||
|
or Splunk: |
||||
|
|
||||
|
```json |
||||
|
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the |
||||
|
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} |
||||
|
|
||||
|
{"level":"warning","msg":"The group's number increased tremendously!", |
||||
|
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} |
||||
|
|
||||
|
{"animal":"walrus","level":"info","msg":"A giant walrus appears!", |
||||
|
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} |
||||
|
|
||||
|
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", |
||||
|
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} |
||||
|
|
||||
|
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, |
||||
|
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"} |
||||
|
``` |
||||
|
|
||||
|
With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not |
||||
|
attached, the output is compatible with the |
||||
|
[logfmt](http://godoc.org/github.com/kr/logfmt) format: |
||||
|
|
||||
|
```text |
||||
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 |
||||
|
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 |
||||
|
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true |
||||
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 |
||||
|
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 |
||||
|
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true |
||||
|
exit status 1 |
||||
|
``` |
||||
|
|
||||
|
#### Case-sensitivity |
||||
|
|
||||
|
The organization's name was changed to lower-case--and this will not be changed |
||||
|
back. If you are getting import conflicts due to case sensitivity, please use |
||||
|
the lower-case import: `github.com/sirupsen/logrus`. |
||||
|
|
||||
|
#### Example |
||||
|
|
||||
|
The simplest way to use Logrus is simply the package-level exported logger: |
||||
|
|
||||
|
```go |
||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
log "github.com/sirupsen/logrus" |
||||
|
) |
||||
|
|
||||
|
func main() { |
||||
|
log.WithFields(log.Fields{ |
||||
|
"animal": "walrus", |
||||
|
}).Info("A walrus appears") |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
Note that it's completely api-compatible with the stdlib logger, so you can |
||||
|
replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"` |
||||
|
and you'll now have the flexibility of Logrus. You can customize it all you |
||||
|
want: |
||||
|
|
||||
|
```go |
||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"os" |
||||
|
log "github.com/sirupsen/logrus" |
||||
|
) |
||||
|
|
||||
|
func init() { |
||||
|
// Log as JSON instead of the default ASCII formatter. |
||||
|
log.SetFormatter(&log.JSONFormatter{}) |
||||
|
|
||||
|
// Output to stdout instead of the default stderr |
||||
|
// Can be any io.Writer, see below for File example |
||||
|
log.SetOutput(os.Stdout) |
||||
|
|
||||
|
// Only log the warning severity or above. |
||||
|
log.SetLevel(log.WarnLevel) |
||||
|
} |
||||
|
|
||||
|
func main() { |
||||
|
log.WithFields(log.Fields{ |
||||
|
"animal": "walrus", |
||||
|
"size": 10, |
||||
|
}).Info("A group of walrus emerges from the ocean") |
||||
|
|
||||
|
log.WithFields(log.Fields{ |
||||
|
"omg": true, |
||||
|
"number": 122, |
||||
|
}).Warn("The group's number increased tremendously!") |
||||
|
|
||||
|
log.WithFields(log.Fields{ |
||||
|
"omg": true, |
||||
|
"number": 100, |
||||
|
}).Fatal("The ice breaks!") |
||||
|
|
||||
|
// A common pattern is to re-use fields between logging statements by re-using |
||||
|
// the logrus.Entry returned from WithFields() |
||||
|
contextLogger := log.WithFields(log.Fields{ |
||||
|
"common": "this is a common field", |
||||
|
"other": "I also should be logged always", |
||||
|
}) |
||||
|
|
||||
|
contextLogger.Info("I'll be logged with common and other field") |
||||
|
contextLogger.Info("Me too") |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
For more advanced usage such as logging to multiple locations from the same |
||||
|
application, you can also create an instance of the `logrus` Logger: |
||||
|
|
||||
|
```go |
||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"os" |
||||
|
"github.com/sirupsen/logrus" |
||||
|
) |
||||
|
|
||||
|
// Create a new instance of the logger. You can have any number of instances. |
||||
|
var log = logrus.New() |
||||
|
|
||||
|
func main() { |
||||
|
// The API for setting attributes is a little different than the package level |
||||
|
// exported logger. See Godoc. |
||||
|
log.Out = os.Stdout |
||||
|
|
||||
|
// You could set this to any `io.Writer` such as a file |
||||
|
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY, 0666) |
||||
|
// if err == nil { |
||||
|
// log.Out = file |
||||
|
// } else { |
||||
|
// log.Info("Failed to log to file, using default stderr") |
||||
|
// } |
||||
|
|
||||
|
log.WithFields(logrus.Fields{ |
||||
|
"animal": "walrus", |
||||
|
"size": 10, |
||||
|
}).Info("A group of walrus emerges from the ocean") |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
#### Fields |
||||
|
|
||||
|
Logrus encourages careful, structured logging through logging fields instead of |
||||
|
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed |
||||
|
to send event %s to topic %s with key %d")`, you should log the much more |
||||
|
discoverable: |
||||
|
|
||||
|
```go |
||||
|
log.WithFields(log.Fields{ |
||||
|
"event": event, |
||||
|
"topic": topic, |
||||
|
"key": key, |
||||
|
}).Fatal("Failed to send event") |
||||
|
``` |
||||
|
|
||||
|
We've found this API forces you to think about logging in a way that produces |
||||
|
much more useful logging messages. We've been in countless situations where just |
||||
|
a single added field to a log statement that was already there would've saved us |
||||
|
hours. The `WithFields` call is optional. |
||||
|
|
||||
|
In general, with Logrus using any of the `printf`-family functions should be |
||||
|
seen as a hint you should add a field, however, you can still use the |
||||
|
`printf`-family functions with Logrus. |
||||
|
|
||||
|
#### Default Fields |
||||
|
|
||||
|
Often it's helpful to have fields _always_ attached to log statements in an |
||||
|
application or parts of one. For example, you may want to always log the |
||||
|
`request_id` and `user_ip` in the context of a request. Instead of writing |
||||
|
`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on |
||||
|
every line, you can create a `logrus.Entry` to pass around instead: |
||||
|
|
||||
|
```go |
||||
|
requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip}) |
||||
|
requestLogger.Info("something happened on that request") # will log request_id and user_ip |
||||
|
requestLogger.Warn("something not great happened") |
||||
|
``` |
||||
|
|
||||
|
#### Hooks |
||||
|
|
||||
|
You can add hooks for logging levels. For example to send errors to an exception |
||||
|
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to |
||||
|
multiple places simultaneously, e.g. syslog. |
||||
|
|
||||
|
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in |
||||
|
`init`: |
||||
|
|
||||
|
```go |
||||
|
import ( |
||||
|
log "github.com/sirupsen/logrus" |
||||
|
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake" |
||||
|
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog" |
||||
|
"log/syslog" |
||||
|
) |
||||
|
|
||||
|
func init() { |
||||
|
|
||||
|
// Use the Airbrake hook to report errors that have Error severity or above to |
||||
|
// an exception tracker. You can create custom hooks, see the Hooks section. |
||||
|
log.AddHook(airbrake.NewHook(123, "xyz", "production")) |
||||
|
|
||||
|
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") |
||||
|
if err != nil { |
||||
|
log.Error("Unable to connect to local syslog daemon") |
||||
|
} else { |
||||
|
log.AddHook(hook) |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). |
||||
|
|
||||
|
A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks) |
||||
|
|
||||
|
|
||||
|
#### Level logging |
||||
|
|
||||
|
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic. |
||||
|
|
||||
|
```go |
||||
|
log.Debug("Useful debugging information.") |
||||
|
log.Info("Something noteworthy happened!") |
||||
|
log.Warn("You should probably take a look at this.") |
||||
|
log.Error("Something failed but I'm not quitting.") |
||||
|
// Calls os.Exit(1) after logging |
||||
|
log.Fatal("Bye.") |
||||
|
// Calls panic() after logging |
||||
|
log.Panic("I'm bailing.") |
||||
|
``` |
||||
|
|
||||
|
You can set the logging level on a `Logger`, then it will only log entries with |
||||
|
that severity or anything above it: |
||||
|
|
||||
|
```go |
||||
|
// Will log anything that is info or above (warn, error, fatal, panic). Default. |
||||
|
log.SetLevel(log.InfoLevel) |
||||
|
``` |
||||
|
|
||||
|
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose |
||||
|
environment if your application has that. |
||||
|
|
||||
|
#### Entries |
||||
|
|
||||
|
Besides the fields added with `WithField` or `WithFields` some fields are |
||||
|
automatically added to all logging events: |
||||
|
|
||||
|
1. `time`. The timestamp when the entry was created. |
||||
|
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after |
||||
|
the `AddFields` call. E.g. `Failed to send event.` |
||||
|
3. `level`. The logging level. E.g. `info`. |
||||
|
|
||||
|
#### Environments |
||||
|
|
||||
|
Logrus has no notion of environment. |
||||
|
|
||||
|
If you wish for hooks and formatters to only be used in specific environments, |
||||
|
you should handle that yourself. For example, if your application has a global |
||||
|
variable `Environment`, which is a string representation of the environment you |
||||
|
could do: |
||||
|
|
||||
|
```go |
||||
|
import ( |
||||
|
log "github.com/sirupsen/logrus" |
||||
|
) |
||||
|
|
||||
|
init() { |
||||
|
// do something here to set environment depending on an environment variable |
||||
|
// or command-line flag |
||||
|
if Environment == "production" { |
||||
|
log.SetFormatter(&log.JSONFormatter{}) |
||||
|
} else { |
||||
|
// The TextFormatter is default, you don't actually have to do this. |
||||
|
log.SetFormatter(&log.TextFormatter{}) |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
This configuration is how `logrus` was intended to be used, but JSON in |
||||
|
production is mostly only useful if you do log aggregation with tools like |
||||
|
Splunk or Logstash. |
||||
|
|
||||
|
#### Formatters |
||||
|
|
||||
|
The built-in logging formatters are: |
||||
|
|
||||
|
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise |
||||
|
without colors. |
||||
|
* *Note:* to force colored output when there is no TTY, set the `ForceColors` |
||||
|
field to `true`. To force no colored output even if there is a TTY set the |
||||
|
`DisableColors` field to `true`. For Windows, see |
||||
|
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable). |
||||
|
* When colors are enabled, levels are truncated to 4 characters by default. To disable |
||||
|
truncation set the `DisableLevelTruncation` field to `true`. |
||||
|
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter). |
||||
|
* `logrus.JSONFormatter`. Logs fields as JSON. |
||||
|
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter). |
||||
|
|
||||
|
Third party logging formatters: |
||||
|
|
||||
|
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine. |
||||
|
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events. |
||||
|
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. |
||||
|
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. |
||||
|
|
||||
|
You can define your formatter by implementing the `Formatter` interface, |
||||
|
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a |
||||
|
`Fields` type (`map[string]interface{}`) with all your fields as well as the |
||||
|
default ones (see Entries section above): |
||||
|
|
||||
|
```go |
||||
|
type MyJSONFormatter struct { |
||||
|
} |
||||
|
|
||||
|
log.SetFormatter(new(MyJSONFormatter)) |
||||
|
|
||||
|
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { |
||||
|
// Note this doesn't include Time, Level and Message which are available on |
||||
|
// the Entry. Consult `godoc` on information about those fields or read the |
||||
|
// source of the official loggers. |
||||
|
serialized, err := json.Marshal(entry.Data) |
||||
|
if err != nil { |
||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) |
||||
|
} |
||||
|
return append(serialized, '\n'), nil |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
#### Logger as an `io.Writer` |
||||
|
|
||||
|
Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it. |
||||
|
|
||||
|
```go |
||||
|
w := logger.Writer() |
||||
|
defer w.Close() |
||||
|
|
||||
|
srv := http.Server{ |
||||
|
// create a stdlib log.Logger that writes to |
||||
|
// logrus.Logger. |
||||
|
ErrorLog: log.New(w, "", 0), |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
Each line written to that writer will be printed the usual way, using formatters |
||||
|
and hooks. The level for those entries is `info`. |
||||
|
|
||||
|
This means that we can override the standard library logger easily: |
||||
|
|
||||
|
```go |
||||
|
logger := logrus.New() |
||||
|
logger.Formatter = &logrus.JSONFormatter{} |
||||
|
|
||||
|
// Use logrus for standard log output |
||||
|
// Note that `log` here references stdlib's log |
||||
|
// Not logrus imported under the name `log`. |
||||
|
log.SetOutput(logger.Writer()) |
||||
|
``` |
||||
|
|
||||
|
#### Rotation |
||||
|
|
||||
|
Log rotation is not provided with Logrus. Log rotation should be done by an |
||||
|
external program (like `logrotate(8)`) that can compress and delete old log |
||||
|
entries. It should not be a feature of the application-level logger. |
||||
|
|
||||
|
#### Tools |
||||
|
|
||||
|
| Tool | Description | |
||||
|
| ---- | ----------- | |
||||
|
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.| |
||||
|
|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) | |
||||
|
|
||||
|
#### Testing |
||||
|
|
||||
|
Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: |
||||
|
|
||||
|
* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook |
||||
|
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): |
||||
|
|
||||
|
```go |
||||
|
import( |
||||
|
"github.com/sirupsen/logrus" |
||||
|
"github.com/sirupsen/logrus/hooks/test" |
||||
|
"github.com/stretchr/testify/assert" |
||||
|
"testing" |
||||
|
) |
||||
|
|
||||
|
func TestSomething(t*testing.T){ |
||||
|
logger, hook := test.NewNullLogger() |
||||
|
logger.Error("Helloerror") |
||||
|
|
||||
|
assert.Equal(t, 1, len(hook.Entries)) |
||||
|
assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level) |
||||
|
assert.Equal(t, "Helloerror", hook.LastEntry().Message) |
||||
|
|
||||
|
hook.Reset() |
||||
|
assert.Nil(t, hook.LastEntry()) |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
#### Fatal handlers |
||||
|
|
||||
|
Logrus can register one or more functions that will be called when any `fatal` |
||||
|
level message is logged. The registered handlers will be executed before |
||||
|
logrus performs a `os.Exit(1)`. This behavior may be helpful if callers need |
||||
|
to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted. |
||||
|
|
||||
|
``` |
||||
|
... |
||||
|
handler := func() { |
||||
|
// gracefully shutdown something... |
||||
|
} |
||||
|
logrus.RegisterExitHandler(handler) |
||||
|
... |
||||
|
``` |
||||
|
|
||||
|
#### Thread safety |
||||
|
|
||||
|
By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs. |
||||
|
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. |
||||
|
|
||||
|
Situation when locking is not needed includes: |
||||
|
|
||||
|
* You have no hooks registered, or hooks calling is already thread-safe. |
||||
|
|
||||
|
* Writing to logger.Out is already thread-safe, for example: |
||||
|
|
||||
|
1) logger.Out is protected by locks. |
||||
|
|
||||
|
2) logger.Out is a os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allow multi-thread/multi-process writing) |
||||
|
|
||||
|
(Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/) |
@ -0,0 +1,64 @@ |
|||||
|
package logrus |
||||
|
|
||||
|
// The following code was sourced and modified from the
|
||||
|
// https://github.com/tebeka/atexit package governed by the following license:
|
||||
|
//
|
||||
|
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
|
||||
|
//
|
||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
|
// this software and associated documentation files (the "Software"), to deal in
|
||||
|
// the Software without restriction, including without limitation the rights to
|
||||
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
|
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
|
// subject to the following conditions:
|
||||
|
//
|
||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||
|
// copies or substantial portions of the Software.
|
||||
|
//
|
||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
|
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
|
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"os" |
||||
|
) |
||||
|
|
||||
|
var handlers = []func(){} |
||||
|
|
||||
|
func runHandler(handler func()) { |
||||
|
defer func() { |
||||
|
if err := recover(); err != nil { |
||||
|
fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err) |
||||
|
} |
||||
|
}() |
||||
|
|
||||
|
handler() |
||||
|
} |
||||
|
|
||||
|
func runHandlers() { |
||||
|
for _, handler := range handlers { |
||||
|
runHandler(handler) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
|
||||
|
func Exit(code int) { |
||||
|
runHandlers() |
||||
|
os.Exit(code) |
||||
|
} |
||||
|
|
||||
|
// RegisterExitHandler adds a Logrus Exit handler, call logrus.Exit to invoke
|
||||
|
// all handlers. The handlers will also be invoked when any Fatal log entry is
|
||||
|
// made.
|
||||
|
//
|
||||
|
// This method is useful when a caller wishes to use logrus to log a fatal
|
||||
|
// message but also needs to gracefully shutdown. An example usecase could be
|
||||
|
// closing database connections, or sending a alert that the application is
|
||||
|
// closing.
|
||||
|
func RegisterExitHandler(handler func()) { |
||||
|
handlers = append(handlers, handler) |
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
version: "{build}" |
||||
|
platform: x64 |
||||
|
clone_folder: c:\gopath\src\github.com\sirupsen\logrus |
||||
|
environment: |
||||
|
GOPATH: c:\gopath |
||||
|
branches: |
||||
|
only: |
||||
|
- master |
||||
|
install: |
||||
|
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH% |
||||
|
- go version |
||||
|
build_script: |
||||
|
- go get -t |
||||
|
- go test |
@ -0,0 +1,26 @@ |
|||||
|
/* |
||||
|
Package logrus is a structured logger for Go, completely API compatible with the standard library logger. |
||||
|
|
||||
|
|
||||
|
The simplest way to use Logrus is simply the package-level exported logger: |
||||
|
|
||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
log "github.com/sirupsen/logrus" |
||||
|
) |
||||
|
|
||||
|
func main() { |
||||
|
log.WithFields(log.Fields{ |
||||
|
"animal": "walrus", |
||||
|
"number": 1, |
||||
|
"size": 10, |
||||
|
}).Info("A walrus appears") |
||||
|
} |
||||
|
|
||||
|
Output: |
||||
|
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 |
||||
|
|
||||
|
For a full guide visit https://github.com/sirupsen/logrus
|
||||
|
*/ |
||||
|
package logrus |
@ -0,0 +1,300 @@ |
|||||
|
package logrus |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"fmt" |
||||
|
"os" |
||||
|
"sync" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
var bufferPool *sync.Pool |
||||
|
|
||||
|
func init() { |
||||
|
bufferPool = &sync.Pool{ |
||||
|
New: func() interface{} { |
||||
|
return new(bytes.Buffer) |
||||
|
}, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Defines the key when adding errors using WithError.
|
||||
|
var ErrorKey = "error" |
||||
|
|
||||
|
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||
|
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
||||
|
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
||||
|
// passed around as much as you wish to avoid field duplication.
|
||||
|
type Entry struct { |
||||
|
Logger *Logger |
||||
|
|
||||
|
// Contains all the fields set by the user.
|
||||
|
Data Fields |
||||
|
|
||||
|
// Time at which the log entry was created
|
||||
|
Time time.Time |
||||
|
|
||||
|
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
||||
|
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
|
||||
|
Level Level |
||||
|
|
||||
|
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||
|
Message string |
||||
|
|
||||
|
// When formatter is called in entry.log(), an Buffer may be set to entry
|
||||
|
Buffer *bytes.Buffer |
||||
|
} |
||||
|
|
||||
|
func NewEntry(logger *Logger) *Entry { |
||||
|
return &Entry{ |
||||
|
Logger: logger, |
||||
|
// Default is five fields, give a little extra room
|
||||
|
Data: make(Fields, 5), |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Returns the string representation from the reader and ultimately the
|
||||
|
// formatter.
|
||||
|
func (entry *Entry) String() (string, error) { |
||||
|
serialized, err := entry.Logger.Formatter.Format(entry) |
||||
|
if err != nil { |
||||
|
return "", err |
||||
|
} |
||||
|
str := string(serialized) |
||||
|
return str, nil |
||||
|
} |
||||
|
|
||||
|
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
|
||||
|
func (entry *Entry) WithError(err error) *Entry { |
||||
|
return entry.WithField(ErrorKey, err) |
||||
|
} |
||||
|
|
||||
|
// Add a single field to the Entry.
|
||||
|
func (entry *Entry) WithField(key string, value interface{}) *Entry { |
||||
|
return entry.WithFields(Fields{key: value}) |
||||
|
} |
||||
|
|
||||
|
// Add a map of fields to the Entry.
|
||||
|
func (entry *Entry) WithFields(fields Fields) *Entry { |
||||
|
data := make(Fields, len(entry.Data)+len(fields)) |
||||
|
for k, v := range entry.Data { |
||||
|
data[k] = v |
||||
|
} |
||||
|
for k, v := range fields { |
||||
|
data[k] = v |
||||
|
} |
||||
|
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time} |
||||
|
} |
||||
|
|
||||
|
// Overrides the time of the Entry.
|
||||
|
func (entry *Entry) WithTime(t time.Time) *Entry { |
||||
|
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t} |
||||
|
} |
||||
|
|
||||
|
// This function is not declared with a pointer value because otherwise
|
||||
|
// race conditions will occur when using multiple goroutines
|
||||
|
func (entry Entry) log(level Level, msg string) { |
||||
|
var buffer *bytes.Buffer |
||||
|
|
||||
|
// Default to now, but allow users to override if they want.
|
||||
|
//
|
||||
|
// We don't have to worry about polluting future calls to Entry#log()
|
||||
|
// with this assignment because this function is declared with a
|
||||
|
// non-pointer receiver.
|
||||
|
if entry.Time.IsZero() { |
||||
|
entry.Time = time.Now() |
||||
|
} |
||||
|
|
||||
|
entry.Level = level |
||||
|
entry.Message = msg |
||||
|
|
||||
|
entry.fireHooks() |
||||
|
|
||||
|
buffer = bufferPool.Get().(*bytes.Buffer) |
||||
|
buffer.Reset() |
||||
|
defer bufferPool.Put(buffer) |
||||
|
entry.Buffer = buffer |
||||
|
|
||||
|
entry.write() |
||||
|
|
||||
|
entry.Buffer = nil |
||||
|
|
||||
|
// To avoid Entry#log() returning a value that only would make sense for
|
||||
|
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||
|
// directly here.
|
||||
|
if level <= PanicLevel { |
||||
|
panic(&entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) fireHooks() { |
||||
|
entry.Logger.mu.Lock() |
||||
|
defer entry.Logger.mu.Unlock() |
||||
|
err := entry.Logger.Hooks.Fire(entry.Level, entry) |
||||
|
if err != nil { |
||||
|
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) write() { |
||||
|
entry.Logger.mu.Lock() |
||||
|
defer entry.Logger.mu.Unlock() |
||||
|
serialized, err := entry.Logger.Formatter.Format(entry) |
||||
|
if err != nil { |
||||
|
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) |
||||
|
} else { |
||||
|
_, err = entry.Logger.Out.Write(serialized) |
||||
|
if err != nil { |
||||
|
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Debug(args ...interface{}) { |
||||
|
if entry.Logger.level() >= DebugLevel { |
||||
|
entry.log(DebugLevel, fmt.Sprint(args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Print(args ...interface{}) { |
||||
|
entry.Info(args...) |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Info(args ...interface{}) { |
||||
|
if entry.Logger.level() >= InfoLevel { |
||||
|
entry.log(InfoLevel, fmt.Sprint(args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Warn(args ...interface{}) { |
||||
|
if entry.Logger.level() >= WarnLevel { |
||||
|
entry.log(WarnLevel, fmt.Sprint(args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Warning(args ...interface{}) { |
||||
|
entry.Warn(args...) |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Error(args ...interface{}) { |
||||
|
if entry.Logger.level() >= ErrorLevel { |
||||
|
entry.log(ErrorLevel, fmt.Sprint(args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Fatal(args ...interface{}) { |
||||
|
if entry.Logger.level() >= FatalLevel { |
||||
|
entry.log(FatalLevel, fmt.Sprint(args...)) |
||||
|
} |
||||
|
Exit(1) |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Panic(args ...interface{}) { |
||||
|
if entry.Logger.level() >= PanicLevel { |
||||
|
entry.log(PanicLevel, fmt.Sprint(args...)) |
||||
|
} |
||||
|
panic(fmt.Sprint(args...)) |
||||
|
} |
||||
|
|
||||
|
// Entry Printf family functions
|
||||
|
|
||||
|
func (entry *Entry) Debugf(format string, args ...interface{}) { |
||||
|
if entry.Logger.level() >= DebugLevel { |
||||
|
entry.Debug(fmt.Sprintf(format, args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Infof(format string, args ...interface{}) { |
||||
|
if entry.Logger.level() >= InfoLevel { |
||||
|
entry.Info(fmt.Sprintf(format, args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Printf(format string, args ...interface{}) { |
||||
|
entry.Infof(format, args...) |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Warnf(format string, args ...interface{}) { |
||||
|
if entry.Logger.level() >= WarnLevel { |
||||
|
entry.Warn(fmt.Sprintf(format, args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Warningf(format string, args ...interface{}) { |
||||
|
entry.Warnf(format, args...) |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Errorf(format string, args ...interface{}) { |
||||
|
if entry.Logger.level() >= ErrorLevel { |
||||
|
entry.Error(fmt.Sprintf(format, args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Fatalf(format string, args ...interface{}) { |
||||
|
if entry.Logger.level() >= FatalLevel { |
||||
|
entry.Fatal(fmt.Sprintf(format, args...)) |
||||
|
} |
||||
|
Exit(1) |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Panicf(format string, args ...interface{}) { |
||||
|
if entry.Logger.level() >= PanicLevel { |
||||
|
entry.Panic(fmt.Sprintf(format, args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Entry Println family functions
|
||||
|
|
||||
|
func (entry *Entry) Debugln(args ...interface{}) { |
||||
|
if entry.Logger.level() >= DebugLevel { |
||||
|
entry.Debug(entry.sprintlnn(args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Infoln(args ...interface{}) { |
||||
|
if entry.Logger.level() >= InfoLevel { |
||||
|
entry.Info(entry.sprintlnn(args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Println(args ...interface{}) { |
||||
|
entry.Infoln(args...) |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Warnln(args ...interface{}) { |
||||
|
if entry.Logger.level() >= WarnLevel { |
||||
|
entry.Warn(entry.sprintlnn(args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Warningln(args ...interface{}) { |
||||
|
entry.Warnln(args...) |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Errorln(args ...interface{}) { |
||||
|
if entry.Logger.level() >= ErrorLevel { |
||||
|
entry.Error(entry.sprintlnn(args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Fatalln(args ...interface{}) { |
||||
|
if entry.Logger.level() >= FatalLevel { |
||||
|
entry.Fatal(entry.sprintlnn(args...)) |
||||
|
} |
||||
|
Exit(1) |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Panicln(args ...interface{}) { |
||||
|
if entry.Logger.level() >= PanicLevel { |
||||
|
entry.Panic(entry.sprintlnn(args...)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||
|
// fmt.Sprintln where spaces are always added between operands, regardless of
|
||||
|
// their type. Instead of vendoring the Sprintln implementation to spare a
|
||||
|
// string allocation, we do the simplest thing.
|
||||
|
func (entry *Entry) sprintlnn(args ...interface{}) string { |
||||
|
msg := fmt.Sprintln(args...) |
||||
|
return msg[:len(msg)-1] |
||||
|
} |
@ -0,0 +1,201 @@ |
|||||
|
package logrus |
||||
|
|
||||
|
import ( |
||||
|
"io" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
// std is the name of the standard logger in stdlib `log`
|
||||
|
std = New() |
||||
|
) |
||||
|
|
||||
|
func StandardLogger() *Logger { |
||||
|
return std |
||||
|
} |
||||
|
|
||||
|
// SetOutput sets the standard logger output.
|
||||
|
func SetOutput(out io.Writer) { |
||||
|
std.SetOutput(out) |
||||
|
} |
||||
|
|
||||
|
// SetFormatter sets the standard logger formatter.
|
||||
|
func SetFormatter(formatter Formatter) { |
||||
|
std.mu.Lock() |
||||
|
defer std.mu.Unlock() |
||||
|
std.Formatter = formatter |
||||
|
} |
||||
|
|
||||
|
// SetLevel sets the standard logger level.
|
||||
|
func SetLevel(level Level) { |
||||
|
std.mu.Lock() |
||||
|
defer std.mu.Unlock() |
||||
|
std.SetLevel(level) |
||||
|
} |
||||
|
|
||||
|
// GetLevel returns the standard logger level.
|
||||
|
func GetLevel() Level { |
||||
|
std.mu.Lock() |
||||
|
defer std.mu.Unlock() |
||||
|
return std.level() |
||||
|
} |
||||
|
|
||||
|
// AddHook adds a hook to the standard logger hooks.
|
||||
|
func AddHook(hook Hook) { |
||||
|
std.mu.Lock() |
||||
|
defer std.mu.Unlock() |
||||
|
std.Hooks.Add(hook) |
||||
|
} |
||||
|
|
||||
|
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||
|
func WithError(err error) *Entry { |
||||
|
return std.WithField(ErrorKey, err) |
||||
|
} |
||||
|
|
||||
|
// WithField creates an entry from the standard logger and adds a field to
|
||||
|
// it. If you want multiple fields, use `WithFields`.
|
||||
|
//
|
||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
|
// or Panic on the Entry it returns.
|
||||
|
func WithField(key string, value interface{}) *Entry { |
||||
|
return std.WithField(key, value) |
||||
|
} |
||||
|
|
||||
|
// WithFields creates an entry from the standard logger and adds multiple
|
||||
|
// fields to it. This is simply a helper for `WithField`, invoking it
|
||||
|
// once for each field.
|
||||
|
//
|
||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
|
// or Panic on the Entry it returns.
|
||||
|
func WithFields(fields Fields) *Entry { |
||||
|
return std.WithFields(fields) |
||||
|
} |
||||
|
|
||||
|
// WithTime creats an entry from the standard logger and overrides the time of
|
||||
|
// logs generated with it.
|
||||
|
//
|
||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||
|
// or Panic on the Entry it returns.
|
||||
|
func WithTime(t time.Time) *Entry { |
||||
|
return std.WithTime(t) |
||||
|
} |
||||
|
|
||||
|
// Debug logs a message at level Debug on the standard logger.
|
||||
|
func Debug(args ...interface{}) { |
||||
|
std.Debug(args...) |
||||
|
} |
||||
|
|
||||
|
// Print logs a message at level Info on the standard logger.
|
||||
|
func Print(args ...interface{}) { |
||||
|
std.Print(args...) |
||||
|
} |
||||
|
|
||||
|
// Info logs a message at level Info on the standard logger.
|
||||
|
func Info(args ...interface{}) { |
||||
|
std.Info(args...) |
||||
|
} |
||||
|
|
||||
|
// Warn logs a message at level Warn on the standard logger.
|
||||
|
func Warn(args ...interface{}) { |
||||
|
std.Warn(args...) |
||||
|
} |
||||
|
|
||||
|
// Warning logs a message at level Warn on the standard logger.
|
||||
|
func Warning(args ...interface{}) { |
||||
|
std.Warning(args...) |
||||
|
} |
||||
|
|
||||
|
// Error logs a message at level Error on the standard logger.
|
||||
|
func Error(args ...interface{}) { |
||||
|
std.Error(args...) |
||||
|
} |
||||
|
|
||||
|
// Panic logs a message at level Panic on the standard logger.
|
||||
|
func Panic(args ...interface{}) { |
||||
|
std.Panic(args...) |
||||
|
} |
||||
|
|
||||
|
// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
|
func Fatal(args ...interface{}) { |
||||
|
std.Fatal(args...) |
||||
|
} |
||||
|
|
||||
|
// Debugf logs a message at level Debug on the standard logger.
|
||||
|
func Debugf(format string, args ...interface{}) { |
||||
|
std.Debugf(format, args...) |
||||
|
} |
||||
|
|
||||
|
// Printf logs a message at level Info on the standard logger.
|
||||
|
func Printf(format string, args ...interface{}) { |
||||
|
std.Printf(format, args...) |
||||
|
} |
||||
|
|
||||
|
// Infof logs a message at level Info on the standard logger.
|
||||
|
func Infof(format string, args ...interface{}) { |
||||
|
std.Infof(format, args...) |
||||
|
} |
||||
|
|
||||
|
// Warnf logs a message at level Warn on the standard logger.
|
||||
|
func Warnf(format string, args ...interface{}) { |
||||
|
std.Warnf(format, args...) |
||||
|
} |
||||
|
|
||||
|
// Warningf logs a message at level Warn on the standard logger.
|
||||
|
func Warningf(format string, args ...interface{}) { |
||||
|
std.Warningf(format, args...) |
||||
|
} |
||||
|
|
||||
|
// Errorf logs a message at level Error on the standard logger.
|
||||
|
func Errorf(format string, args ...interface{}) { |
||||
|
std.Errorf(format, args...) |
||||
|
} |
||||
|
|
||||
|
// Panicf logs a message at level Panic on the standard logger.
|
||||
|
func Panicf(format string, args ...interface{}) { |
||||
|
std.Panicf(format, args...) |
||||
|
} |
||||
|
|
||||
|
// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
|
func Fatalf(format string, args ...interface{}) { |
||||
|
std.Fatalf(format, args...) |
||||
|
} |
||||
|
|
||||
|
// Debugln logs a message at level Debug on the standard logger.
|
||||
|
func Debugln(args ...interface{}) { |
||||
|
std.Debugln(args...) |
||||
|
} |
||||
|
|
||||
|
// Println logs a message at level Info on the standard logger.
|
||||
|
func Println(args ...interface{}) { |
||||
|
std.Println(args...) |
||||
|
} |
||||
|
|
||||
|
// Infoln logs a message at level Info on the standard logger.
|
||||
|
func Infoln(args ...interface{}) { |
||||
|
std.Infoln(args...) |
||||
|
} |
||||
|
|
||||
|
// Warnln logs a message at level Warn on the standard logger.
|
||||
|
func Warnln(args ...interface{}) { |
||||
|
std.Warnln(args...) |
||||
|
} |
||||
|
|
||||
|
// Warningln logs a message at level Warn on the standard logger.
|
||||
|
func Warningln(args ...interface{}) { |
||||
|
std.Warningln(args...) |
||||
|
} |
||||
|
|
||||
|
// Errorln logs a message at level Error on the standard logger.
|
||||
|
func Errorln(args ...interface{}) { |
||||
|
std.Errorln(args...) |
||||
|
} |
||||
|
|
||||
|
// Panicln logs a message at level Panic on the standard logger.
|
||||
|
func Panicln(args ...interface{}) { |
||||
|
std.Panicln(args...) |
||||
|
} |
||||
|
|
||||
|
// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
||||
|
func Fatalln(args ...interface{}) { |
||||
|
std.Fatalln(args...) |
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
package logrus |
||||
|
|
||||
|
import "time" |
||||
|
|
||||
|
const defaultTimestampFormat = time.RFC3339 |
||||
|
|
||||
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||
|
// `Entry`. It exposes all the fields, including the default ones:
|
||||
|
//
|
||||
|
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
||||
|
// * `entry.Data["time"]`. The timestamp.
|
||||
|
// * `entry.Data["level"]. The level the entry was logged at.
|
||||
|
//
|
||||
|
// Any additional fields added with `WithField` or `WithFields` are also in
|
||||
|
// `entry.Data`. Format is expected to return an array of bytes which are then
|
||||
|
// logged to `logger.Out`.
|
||||
|
type Formatter interface { |
||||
|
Format(*Entry) ([]byte, error) |
||||
|
} |
||||
|
|
||||
|
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
||||
|
// dumping it. If this code wasn't there doing:
|
||||
|
//
|
||||
|
// logrus.WithField("level", 1).Info("hello")
|
||||
|
//
|
||||
|
// Would just silently drop the user provided level. Instead with this code
|
||||
|
// it'll logged as:
|
||||
|
//
|
||||
|
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||
|
//
|
||||
|
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||
|
// avoid code duplication between the two default formatters.
|
||||
|
func prefixFieldClashes(data Fields, fieldMap FieldMap) { |
||||
|
timeKey := fieldMap.resolve(FieldKeyTime) |
||||
|
if t, ok := data[timeKey]; ok { |
||||
|
data["fields."+timeKey] = t |
||||
|
delete(data, timeKey) |
||||
|
} |
||||
|
|
||||
|
msgKey := fieldMap.resolve(FieldKeyMsg) |
||||
|
if m, ok := data[msgKey]; ok { |
||||
|
data["fields."+msgKey] = m |
||||
|
delete(data, msgKey) |
||||
|
} |
||||
|
|
||||
|
levelKey := fieldMap.resolve(FieldKeyLevel) |
||||
|
if l, ok := data[levelKey]; ok { |
||||
|
data["fields."+levelKey] = l |
||||
|
delete(data, levelKey) |
||||
|
} |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
package logrus |
||||
|
|
||||
|
// A hook to be fired when logging on the logging levels returned from
|
||||
|
// `Levels()` on your implementation of the interface. Note that this is not
|
||||
|
// fired in a goroutine or a channel with workers, you should handle such
|
||||
|
// functionality yourself if your call is non-blocking and you don't wish for
|
||||
|
// the logging calls for levels returned from `Levels()` to block.
|
||||
|
type Hook interface { |
||||
|
Levels() []Level |
||||
|
Fire(*Entry) error |
||||
|
} |
||||
|
|
||||
|
// Internal type for storing the hooks on a logger instance.
|
||||
|
type LevelHooks map[Level][]Hook |
||||
|
|
||||
|
// Add a hook to an instance of logger. This is called with
|
||||
|
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
||||
|
func (hooks LevelHooks) Add(hook Hook) { |
||||
|
for _, level := range hook.Levels() { |
||||
|
hooks[level] = append(hooks[level], hook) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
||||
|
// appropriate hooks for a log entry.
|
||||
|
func (hooks LevelHooks) Fire(level Level, entry *Entry) error { |
||||
|
for _, hook := range hooks[level] { |
||||
|
if err := hook.Fire(entry); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
@ -0,0 +1,89 @@ |
|||||
|
package logrus |
||||
|
|
||||
|
import ( |
||||
|
"encoding/json" |
||||
|
"fmt" |
||||
|
) |
||||
|
|
||||
|
type fieldKey string |
||||
|
|
||||
|
// FieldMap allows customization of the key names for default fields.
|
||||
|
type FieldMap map[fieldKey]string |
||||
|
|
||||
|
// Default key names for the default fields
|
||||
|
const ( |
||||
|
FieldKeyMsg = "msg" |
||||
|
FieldKeyLevel = "level" |
||||
|
FieldKeyTime = "time" |
||||
|
) |
||||
|
|
||||
|
func (f FieldMap) resolve(key fieldKey) string { |
||||
|
if k, ok := f[key]; ok { |
||||
|
return k |
||||
|
} |
||||
|
|
||||
|
return string(key) |
||||
|
} |
||||
|
|
||||
|
// JSONFormatter formats logs into parsable json
|
||||
|
type JSONFormatter struct { |
||||
|
// TimestampFormat sets the format used for marshaling timestamps.
|
||||
|
TimestampFormat string |
||||
|
|
||||
|
// DisableTimestamp allows disabling automatic timestamps in output
|
||||
|
DisableTimestamp bool |
||||
|
|
||||
|
// DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
|
||||
|
DataKey string |
||||
|
|
||||
|
// FieldMap allows users to customize the names of keys for default fields.
|
||||
|
// As an example:
|
||||
|
// formatter := &JSONFormatter{
|
||||
|
// FieldMap: FieldMap{
|
||||
|
// FieldKeyTime: "@timestamp",
|
||||
|
// FieldKeyLevel: "@level",
|
||||
|
// FieldKeyMsg: "@message",
|
||||
|
// },
|
||||
|
// }
|
||||
|
FieldMap FieldMap |
||||
|
} |
||||
|
|
||||
|
// Format renders a single log entry
|
||||
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { |
||||
|
data := make(Fields, len(entry.Data)+3) |
||||
|
for k, v := range entry.Data { |
||||
|
switch v := v.(type) { |
||||
|
case error: |
||||
|
// Otherwise errors are ignored by `encoding/json`
|
||||
|
// https://github.com/sirupsen/logrus/issues/137
|
||||
|
data[k] = v.Error() |
||||
|
default: |
||||
|
data[k] = v |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if f.DataKey != "" { |
||||
|
newData := make(Fields, 4) |
||||
|
newData[f.DataKey] = data |
||||
|
data = newData |
||||
|
} |
||||
|
|
||||
|
prefixFieldClashes(data, f.FieldMap) |
||||
|
|
||||
|
timestampFormat := f.TimestampFormat |
||||
|
if timestampFormat == "" { |
||||
|
timestampFormat = defaultTimestampFormat |
||||
|
} |
||||
|
|
||||
|
if !f.DisableTimestamp { |
||||
|
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat) |
||||
|
} |
||||
|
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message |
||||
|
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String() |
||||
|
|
||||
|
serialized, err := json.Marshal(data) |
||||
|
if err != nil { |
||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) |
||||
|
} |
||||
|
return append(serialized, '\n'), nil |
||||
|
} |
@ -0,0 +1,337 @@ |
|||||
|
package logrus |
||||
|
|
||||
|
import ( |
||||
|
"io" |
||||
|
"os" |
||||
|
"sync" |
||||
|
"sync/atomic" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
type Logger struct { |
||||
|
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||
|
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||
|
// something more adventorous, such as logging to Kafka.
|
||||
|
Out io.Writer |
||||
|
// Hooks for the logger instance. These allow firing events based on logging
|
||||
|
// levels and log entries. For example, to send errors to an error tracking
|
||||
|
// service, log to StatsD or dump the core on fatal errors.
|
||||
|
Hooks LevelHooks |
||||
|
// All log entries pass through the formatter before logged to Out. The
|
||||
|
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
||||
|
// TextFormatter is the default. In development (when a TTY is attached) it
|
||||
|
// logs with colors, but to a file it wouldn't. You can easily implement your
|
||||
|
// own that implements the `Formatter` interface, see the `README` or included
|
||||
|
// formatters for examples.
|
||||
|
Formatter Formatter |
||||
|
// The logging level the logger should log at. This is typically (and defaults
|
||||
|
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||
|
// logged.
|
||||
|
Level Level |
||||
|
// Used to sync writing to the log. Locking is enabled by Default
|
||||
|
mu MutexWrap |
||||
|
// Reusable empty entry
|
||||
|
entryPool sync.Pool |
||||
|
} |
||||
|
|
||||
|
type MutexWrap struct { |
||||
|
lock sync.Mutex |
||||
|
disabled bool |
||||
|
} |
||||
|
|
||||
|
func (mw *MutexWrap) Lock() { |
||||
|
if !mw.disabled { |
||||
|
mw.lock.Lock() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (mw *MutexWrap) Unlock() { |
||||
|
if !mw.disabled { |
||||
|
mw.lock.Unlock() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (mw *MutexWrap) Disable() { |
||||
|
mw.disabled = true |
||||
|
} |
||||
|
|
||||
|
// Creates a new logger. Configuration should be set by changing `Formatter`,
|
||||
|
// `Out` and `Hooks` directly on the default logger instance. You can also just
|
||||
|
// instantiate your own:
|
||||
|
//
|
||||
|
// var log = &Logger{
|
||||
|
// Out: os.Stderr,
|
||||
|
// Formatter: new(JSONFormatter),
|
||||
|
// Hooks: make(LevelHooks),
|
||||
|
// Level: logrus.DebugLevel,
|
||||
|
// }
|
||||
|
//
|
||||
|
// It's recommended to make this a global instance called `log`.
|
||||
|
func New() *Logger { |
||||
|
return &Logger{ |
||||
|
Out: os.Stderr, |
||||
|
Formatter: new(TextFormatter), |
||||
|
Hooks: make(LevelHooks), |
||||
|
Level: InfoLevel, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) newEntry() *Entry { |
||||
|
entry, ok := logger.entryPool.Get().(*Entry) |
||||
|
if ok { |
||||
|
return entry |
||||
|
} |
||||
|
return NewEntry(logger) |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) releaseEntry(entry *Entry) { |
||||
|
logger.entryPool.Put(entry) |
||||
|
} |
||||
|
|
||||
|
// Adds a field to the log entry, note that it doesn't log until you call
|
||||
|
// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry.
|
||||
|
// If you want multiple fields, use `WithFields`.
|
||||
|
func (logger *Logger) WithField(key string, value interface{}) *Entry { |
||||
|
entry := logger.newEntry() |
||||
|
defer logger.releaseEntry(entry) |
||||
|
return entry.WithField(key, value) |
||||
|
} |
||||
|
|
||||
|
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
||||
|
// each `Field`.
|
||||
|
func (logger *Logger) WithFields(fields Fields) *Entry { |
||||
|
entry := logger.newEntry() |
||||
|
defer logger.releaseEntry(entry) |
||||
|
return entry.WithFields(fields) |
||||
|
} |
||||
|
|
||||
|
// Add an error as single field to the log entry. All it does is call
|
||||
|
// `WithError` for the given `error`.
|
||||
|
func (logger *Logger) WithError(err error) *Entry { |
||||
|
entry := logger.newEntry() |
||||
|
defer logger.releaseEntry(entry) |
||||
|
return entry.WithError(err) |
||||
|
} |
||||
|
|
||||
|
// Overrides the time of the log entry.
|
||||
|
func (logger *Logger) WithTime(t time.Time) *Entry { |
||||
|
entry := logger.newEntry() |
||||
|
defer logger.releaseEntry(entry) |
||||
|
return entry.WithTime(t) |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Debugf(format string, args ...interface{}) { |
||||
|
if logger.level() >= DebugLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Debugf(format, args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Infof(format string, args ...interface{}) { |
||||
|
if logger.level() >= InfoLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Infof(format, args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Printf(format string, args ...interface{}) { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Printf(format, args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Warnf(format string, args ...interface{}) { |
||||
|
if logger.level() >= WarnLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Warnf(format, args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Warningf(format string, args ...interface{}) { |
||||
|
if logger.level() >= WarnLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Warnf(format, args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Errorf(format string, args ...interface{}) { |
||||
|
if logger.level() >= ErrorLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Errorf(format, args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Fatalf(format string, args ...interface{}) { |
||||
|
if logger.level() >= FatalLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Fatalf(format, args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
Exit(1) |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Panicf(format string, args ...interface{}) { |
||||
|
if logger.level() >= PanicLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Panicf(format, args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Debug(args ...interface{}) { |
||||
|
if logger.level() >= DebugLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Debug(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Info(args ...interface{}) { |
||||
|
if logger.level() >= InfoLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Info(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Print(args ...interface{}) { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Info(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Warn(args ...interface{}) { |
||||
|
if logger.level() >= WarnLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Warn(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Warning(args ...interface{}) { |
||||
|
if logger.level() >= WarnLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Warn(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Error(args ...interface{}) { |
||||
|
if logger.level() >= ErrorLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Error(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Fatal(args ...interface{}) { |
||||
|
if logger.level() >= FatalLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Fatal(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
Exit(1) |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Panic(args ...interface{}) { |
||||
|
if logger.level() >= PanicLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Panic(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Debugln(args ...interface{}) { |
||||
|
if logger.level() >= DebugLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Debugln(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Infoln(args ...interface{}) { |
||||
|
if logger.level() >= InfoLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Infoln(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Println(args ...interface{}) { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Println(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Warnln(args ...interface{}) { |
||||
|
if logger.level() >= WarnLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Warnln(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Warningln(args ...interface{}) { |
||||
|
if logger.level() >= WarnLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Warnln(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Errorln(args ...interface{}) { |
||||
|
if logger.level() >= ErrorLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Errorln(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Fatalln(args ...interface{}) { |
||||
|
if logger.level() >= FatalLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Fatalln(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
Exit(1) |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) Panicln(args ...interface{}) { |
||||
|
if logger.level() >= PanicLevel { |
||||
|
entry := logger.newEntry() |
||||
|
entry.Panicln(args...) |
||||
|
logger.releaseEntry(entry) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//When file is opened with appending mode, it's safe to
|
||||
|
//write concurrently to a file (within 4k message on Linux).
|
||||
|
//In these cases user can choose to disable the lock.
|
||||
|
func (logger *Logger) SetNoLock() { |
||||
|
logger.mu.Disable() |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) level() Level { |
||||
|
return Level(atomic.LoadUint32((*uint32)(&logger.Level))) |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) SetLevel(level Level) { |
||||
|
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) SetOutput(out io.Writer) { |
||||
|
logger.mu.Lock() |
||||
|
defer logger.mu.Unlock() |
||||
|
logger.Out = out |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) AddHook(hook Hook) { |
||||
|
logger.mu.Lock() |
||||
|
defer logger.mu.Unlock() |
||||
|
logger.Hooks.Add(hook) |
||||
|
} |
@ -0,0 +1,143 @@ |
|||||
|
package logrus |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"log" |
||||
|
"strings" |
||||
|
) |
||||
|
|
||||
|
// Fields type, used to pass to `WithFields`.
|
||||
|
type Fields map[string]interface{} |
||||
|
|
||||
|
// Level type
|
||||
|
type Level uint32 |
||||
|
|
||||
|
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||
|
func (level Level) String() string { |
||||
|
switch level { |
||||
|
case DebugLevel: |
||||
|
return "debug" |
||||
|
case InfoLevel: |
||||
|
return "info" |
||||
|
case WarnLevel: |
||||
|
return "warning" |
||||
|
case ErrorLevel: |
||||
|
return "error" |
||||
|
case FatalLevel: |
||||
|
return "fatal" |
||||
|
case PanicLevel: |
||||
|
return "panic" |
||||
|
} |
||||
|
|
||||
|
return "unknown" |
||||
|
} |
||||
|
|
||||
|
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||
|
func ParseLevel(lvl string) (Level, error) { |
||||
|
switch strings.ToLower(lvl) { |
||||
|
case "panic": |
||||
|
return PanicLevel, nil |
||||
|
case "fatal": |
||||
|
return FatalLevel, nil |
||||
|
case "error": |
||||
|
return ErrorLevel, nil |
||||
|
case "warn", "warning": |
||||
|
return WarnLevel, nil |
||||
|
case "info": |
||||
|
return InfoLevel, nil |
||||
|
case "debug": |
||||
|
return DebugLevel, nil |
||||
|
} |
||||
|
|
||||
|
var l Level |
||||
|
return l, fmt.Errorf("not a valid logrus Level: %q", lvl) |
||||
|
} |
||||
|
|
||||
|
// A constant exposing all logging levels
|
||||
|
var AllLevels = []Level{ |
||||
|
PanicLevel, |
||||
|
FatalLevel, |
||||
|
ErrorLevel, |
||||
|
WarnLevel, |
||||
|
InfoLevel, |
||||
|
DebugLevel, |
||||
|
} |
||||
|
|
||||
|
// These are the different logging levels. You can set the logging level to log
|
||||
|
// on your instance of logger, obtained with `logrus.New()`.
|
||||
|
const ( |
||||
|
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||
|
// message passed to Debug, Info, ...
|
||||
|
PanicLevel Level = iota |
||||
|
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
||||
|
// logging level is set to Panic.
|
||||
|
FatalLevel |
||||
|
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||
|
// Commonly used for hooks to send errors to an error tracking service.
|
||||
|
ErrorLevel |
||||
|
// WarnLevel level. Non-critical entries that deserve eyes.
|
||||
|
WarnLevel |
||||
|
// InfoLevel level. General operational entries about what's going on inside the
|
||||
|
// application.
|
||||
|
InfoLevel |
||||
|
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||
|
DebugLevel |
||||
|
) |
||||
|
|
||||
|
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||
|
var ( |
||||
|
_ StdLogger = &log.Logger{} |
||||
|
_ StdLogger = &Entry{} |
||||
|
_ StdLogger = &Logger{} |
||||
|
) |
||||
|
|
||||
|
// StdLogger is what your logrus-enabled library should take, that way
|
||||
|
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
||||
|
// interface, this is the closest we get, unfortunately.
|
||||
|
type StdLogger interface { |
||||
|
Print(...interface{}) |
||||
|
Printf(string, ...interface{}) |
||||
|
Println(...interface{}) |
||||
|
|
||||
|
Fatal(...interface{}) |
||||
|
Fatalf(string, ...interface{}) |
||||
|
Fatalln(...interface{}) |
||||
|
|
||||
|
Panic(...interface{}) |
||||
|
Panicf(string, ...interface{}) |
||||
|
Panicln(...interface{}) |
||||
|
} |
||||
|
|
||||
|
// The FieldLogger interface generalizes the Entry and Logger types
|
||||
|
type FieldLogger interface { |
||||
|
WithField(key string, value interface{}) *Entry |
||||
|
WithFields(fields Fields) *Entry |
||||
|
WithError(err error) *Entry |
||||
|
|
||||
|
Debugf(format string, args ...interface{}) |
||||
|
Infof(format string, args ...interface{}) |
||||
|
Printf(format string, args ...interface{}) |
||||
|
Warnf(format string, args ...interface{}) |
||||
|
Warningf(format string, args ...interface{}) |
||||
|
Errorf(format string, args ...interface{}) |
||||
|
Fatalf(format string, args ...interface{}) |
||||
|
Panicf(format string, args ...interface{}) |
||||
|
|
||||
|
Debug(args ...interface{}) |
||||
|
Info(args ...interface{}) |
||||
|
Print(args ...interface{}) |
||||
|
Warn(args ...interface{}) |
||||
|
Warning(args ...interface{}) |
||||
|
Error(args ...interface{}) |
||||
|
Fatal(args ...interface{}) |
||||
|
Panic(args ...interface{}) |
||||
|
|
||||
|
Debugln(args ...interface{}) |
||||
|
Infoln(args ...interface{}) |
||||
|
Println(args ...interface{}) |
||||
|
Warnln(args ...interface{}) |
||||
|
Warningln(args ...interface{}) |
||||
|
Errorln(args ...interface{}) |
||||
|
Fatalln(args ...interface{}) |
||||
|
Panicln(args ...interface{}) |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
// +build darwin freebsd openbsd netbsd dragonfly
|
||||
|
// +build !appengine,!gopherjs
|
||||
|
|
||||
|
package logrus |
||||
|
|
||||
|
import "golang.org/x/sys/unix" |
||||
|
|
||||
|
const ioctlReadTermios = unix.TIOCGETA |
||||
|
|
||||
|
type Termios unix.Termios |
@ -0,0 +1,11 @@ |
|||||
|
// +build appengine gopherjs
|
||||
|
|
||||
|
package logrus |
||||
|
|
||||
|
import ( |
||||
|
"io" |
||||
|
) |
||||
|
|
||||
|
func checkIfTerminal(w io.Writer) bool { |
||||
|
return true |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
// +build !appengine,!gopherjs
|
||||
|
|
||||
|
package logrus |
||||
|
|
||||
|
import ( |
||||
|
"io" |
||||
|
"os" |
||||
|
|
||||
|
"golang.org/x/crypto/ssh/terminal" |
||||
|
) |
||||
|
|
||||
|
func checkIfTerminal(w io.Writer) bool { |
||||
|
switch v := w.(type) { |
||||
|
case *os.File: |
||||
|
return terminal.IsTerminal(int(v.Fd())) |
||||
|
default: |
||||
|
return false |
||||
|
} |
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
// Based on ssh/terminal:
|
||||
|
// Copyright 2013 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 !appengine,!gopherjs
|
||||
|
|
||||
|
package logrus |
||||
|
|
||||
|
import "golang.org/x/sys/unix" |
||||
|
|
||||
|
const ioctlReadTermios = unix.TCGETS |
||||
|
|
||||
|
type Termios unix.Termios |
@ -0,0 +1,195 @@ |
|||||
|
package logrus |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"fmt" |
||||
|
"sort" |
||||
|
"strings" |
||||
|
"sync" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
nocolor = 0 |
||||
|
red = 31 |
||||
|
green = 32 |
||||
|
yellow = 33 |
||||
|
blue = 36 |
||||
|
gray = 37 |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
baseTimestamp time.Time |
||||
|
emptyFieldMap FieldMap |
||||
|
) |
||||
|
|
||||
|
func init() { |
||||
|
baseTimestamp = time.Now() |
||||
|
} |
||||
|
|
||||
|
// TextFormatter formats logs into text
|
||||
|
type TextFormatter struct { |
||||
|
// Set to true to bypass checking for a TTY before outputting colors.
|
||||
|
ForceColors bool |
||||
|
|
||||
|
// Force disabling colors.
|
||||
|
DisableColors bool |
||||
|
|
||||
|
// Disable timestamp logging. useful when output is redirected to logging
|
||||
|
// system that already adds timestamps.
|
||||
|
DisableTimestamp bool |
||||
|
|
||||
|
// Enable logging the full timestamp when a TTY is attached instead of just
|
||||
|
// the time passed since beginning of execution.
|
||||
|
FullTimestamp bool |
||||
|
|
||||
|
// TimestampFormat to use for display when a full timestamp is printed
|
||||
|
TimestampFormat string |
||||
|
|
||||
|
// The fields are sorted by default for a consistent output. For applications
|
||||
|
// that log extremely frequently and don't use the JSON formatter this may not
|
||||
|
// be desired.
|
||||
|
DisableSorting bool |
||||
|
|
||||
|
// Disables the truncation of the level text to 4 characters.
|
||||
|
DisableLevelTruncation bool |
||||
|
|
||||
|
// QuoteEmptyFields will wrap empty fields in quotes if true
|
||||
|
QuoteEmptyFields bool |
||||
|
|
||||
|
// Whether the logger's out is to a terminal
|
||||
|
isTerminal bool |
||||
|
|
||||
|
// FieldMap allows users to customize the names of keys for default fields.
|
||||
|
// As an example:
|
||||
|
// formatter := &TextFormatter{
|
||||
|
// FieldMap: FieldMap{
|
||||
|
// FieldKeyTime: "@timestamp",
|
||||
|
// FieldKeyLevel: "@level",
|
||||
|
// FieldKeyMsg: "@message"}}
|
||||
|
FieldMap FieldMap |
||||
|
|
||||
|
sync.Once |
||||
|
} |
||||
|
|
||||
|
func (f *TextFormatter) init(entry *Entry) { |
||||
|
if entry.Logger != nil { |
||||
|
f.isTerminal = checkIfTerminal(entry.Logger.Out) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Format renders a single log entry
|
||||
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { |
||||
|
prefixFieldClashes(entry.Data, f.FieldMap) |
||||
|
|
||||
|
keys := make([]string, 0, len(entry.Data)) |
||||
|
for k := range entry.Data { |
||||
|
keys = append(keys, k) |
||||
|
} |
||||
|
|
||||
|
if !f.DisableSorting { |
||||
|
sort.Strings(keys) |
||||
|
} |
||||
|
|
||||
|
var b *bytes.Buffer |
||||
|
if entry.Buffer != nil { |
||||
|
b = entry.Buffer |
||||
|
} else { |
||||
|
b = &bytes.Buffer{} |
||||
|
} |
||||
|
|
||||
|
f.Do(func() { f.init(entry) }) |
||||
|
|
||||
|
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors |
||||
|
|
||||
|
timestampFormat := f.TimestampFormat |
||||
|
if timestampFormat == "" { |
||||
|
timestampFormat = defaultTimestampFormat |
||||
|
} |
||||
|
if isColored { |
||||
|
f.printColored(b, entry, keys, timestampFormat) |
||||
|
} else { |
||||
|
if !f.DisableTimestamp { |
||||
|
f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyTime), entry.Time.Format(timestampFormat)) |
||||
|
} |
||||
|
f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyLevel), entry.Level.String()) |
||||
|
if entry.Message != "" { |
||||
|
f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyMsg), entry.Message) |
||||
|
} |
||||
|
for _, key := range keys { |
||||
|
f.appendKeyValue(b, key, entry.Data[key]) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
b.WriteByte('\n') |
||||
|
return b.Bytes(), nil |
||||
|
} |
||||
|
|
||||
|
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) { |
||||
|
var levelColor int |
||||
|
switch entry.Level { |
||||
|
case DebugLevel: |
||||
|
levelColor = gray |
||||
|
case WarnLevel: |
||||
|
levelColor = yellow |
||||
|
case ErrorLevel, FatalLevel, PanicLevel: |
||||
|
levelColor = red |
||||
|
default: |
||||
|
levelColor = blue |
||||
|
} |
||||
|
|
||||
|
levelText := strings.ToUpper(entry.Level.String()) |
||||
|
if !f.DisableLevelTruncation { |
||||
|
levelText = levelText[0:4] |
||||
|
} |
||||
|
|
||||
|
if f.DisableTimestamp { |
||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message) |
||||
|
} else if !f.FullTimestamp { |
||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), entry.Message) |
||||
|
} else { |
||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message) |
||||
|
} |
||||
|
for _, k := range keys { |
||||
|
v := entry.Data[k] |
||||
|
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k) |
||||
|
f.appendValue(b, v) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (f *TextFormatter) needsQuoting(text string) bool { |
||||
|
if f.QuoteEmptyFields && len(text) == 0 { |
||||
|
return true |
||||
|
} |
||||
|
for _, ch := range text { |
||||
|
if !((ch >= 'a' && ch <= 'z') || |
||||
|
(ch >= 'A' && ch <= 'Z') || |
||||
|
(ch >= '0' && ch <= '9') || |
||||
|
ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') { |
||||
|
return true |
||||
|
} |
||||
|
} |
||||
|
return false |
||||
|
} |
||||
|
|
||||
|
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { |
||||
|
if b.Len() > 0 { |
||||
|
b.WriteByte(' ') |
||||
|
} |
||||
|
b.WriteString(key) |
||||
|
b.WriteByte('=') |
||||
|
f.appendValue(b, value) |
||||
|
} |
||||
|
|
||||
|
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { |
||||
|
stringVal, ok := value.(string) |
||||
|
if !ok { |
||||
|
stringVal = fmt.Sprint(value) |
||||
|
} |
||||
|
|
||||
|
if !f.needsQuoting(stringVal) { |
||||
|
b.WriteString(stringVal) |
||||
|
} else { |
||||
|
b.WriteString(fmt.Sprintf("%q", stringVal)) |
||||
|
} |
||||
|
} |
@ -0,0 +1,62 @@ |
|||||
|
package logrus |
||||
|
|
||||
|
import ( |
||||
|
"bufio" |
||||
|
"io" |
||||
|
"runtime" |
||||
|
) |
||||
|
|
||||
|
func (logger *Logger) Writer() *io.PipeWriter { |
||||
|
return logger.WriterLevel(InfoLevel) |
||||
|
} |
||||
|
|
||||
|
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter { |
||||
|
return NewEntry(logger).WriterLevel(level) |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) Writer() *io.PipeWriter { |
||||
|
return entry.WriterLevel(InfoLevel) |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) WriterLevel(level Level) *io.PipeWriter { |
||||
|
reader, writer := io.Pipe() |
||||
|
|
||||
|
var printFunc func(args ...interface{}) |
||||
|
|
||||
|
switch level { |
||||
|
case DebugLevel: |
||||
|
printFunc = entry.Debug |
||||
|
case InfoLevel: |
||||
|
printFunc = entry.Info |
||||
|
case WarnLevel: |
||||
|
printFunc = entry.Warn |
||||
|
case ErrorLevel: |
||||
|
printFunc = entry.Error |
||||
|
case FatalLevel: |
||||
|
printFunc = entry.Fatal |
||||
|
case PanicLevel: |
||||
|
printFunc = entry.Panic |
||||
|
default: |
||||
|
printFunc = entry.Print |
||||
|
} |
||||
|
|
||||
|
go entry.writerScanner(reader, printFunc) |
||||
|
runtime.SetFinalizer(writer, writerFinalizer) |
||||
|
|
||||
|
return writer |
||||
|
} |
||||
|
|
||||
|
func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { |
||||
|
scanner := bufio.NewScanner(reader) |
||||
|
for scanner.Scan() { |
||||
|
printFunc(scanner.Text()) |
||||
|
} |
||||
|
if err := scanner.Err(); err != nil { |
||||
|
entry.Errorf("Error while reading from Writer: %s", err) |
||||
|
} |
||||
|
reader.Close() |
||||
|
} |
||||
|
|
||||
|
func writerFinalizer(writer *io.PipeWriter) { |
||||
|
writer.Close() |
||||
|
} |
@ -0,0 +1,27 @@ |
|||||
|
Copyright (c) 2009 The Go Authors. All rights reserved. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are |
||||
|
met: |
||||
|
|
||||
|
* Redistributions of source code must retain the above copyright |
||||
|
notice, this list of conditions and the following disclaimer. |
||||
|
* Redistributions in binary form must reproduce the above |
||||
|
copyright notice, this list of conditions and the following disclaimer |
||||
|
in the documentation and/or other materials provided with the |
||||
|
distribution. |
||||
|
* Neither the name of Google Inc. nor the names of its |
||||
|
contributors may be used to endorse or promote products derived from |
||||
|
this software without specific prior written permission. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,22 @@ |
|||||
|
Additional IP Rights Grant (Patents) |
||||
|
|
||||
|
"This implementation" means the copyrightable works distributed by |
||||
|
Google as part of the Go project. |
||||
|
|
||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive, |
||||
|
no-charge, royalty-free, irrevocable (except as stated in this section) |
||||
|
patent license to make, have made, use, offer to sell, sell, import, |
||||
|
transfer and otherwise run, modify and propagate the contents of this |
||||
|
implementation of Go, where such license applies only to those patent |
||||
|
claims, both currently owned or controlled by Google and acquired in |
||||
|
the future, licensable by Google that are necessarily infringed by this |
||||
|
implementation of Go. This grant does not include claims that would be |
||||
|
infringed only as a consequence of further modification of this |
||||
|
implementation. If you or your agent or exclusive licensee institute or |
||||
|
order or agree to the institution of patent litigation against any |
||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging |
||||
|
that this implementation of Go or any code incorporated within this |
||||
|
implementation of Go constitutes direct or contributory patent |
||||
|
infringement, or inducement of patent infringement, then any patent |
||||
|
rights granted to you under this License for this implementation of Go |
||||
|
shall terminate as of the date such litigation is filed. |
@ -0,0 +1,951 @@ |
|||||
|
// 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.
|
||||
|
|
||||
|
package terminal |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"io" |
||||
|
"sync" |
||||
|
"unicode/utf8" |
||||
|
) |
||||
|
|
||||
|
// EscapeCodes contains escape sequences that can be written to the terminal in
|
||||
|
// order to achieve different styles of text.
|
||||
|
type EscapeCodes struct { |
||||
|
// Foreground colors
|
||||
|
Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte |
||||
|
|
||||
|
// Reset all attributes
|
||||
|
Reset []byte |
||||
|
} |
||||
|
|
||||
|
var vt100EscapeCodes = EscapeCodes{ |
||||
|
Black: []byte{keyEscape, '[', '3', '0', 'm'}, |
||||
|
Red: []byte{keyEscape, '[', '3', '1', 'm'}, |
||||
|
Green: []byte{keyEscape, '[', '3', '2', 'm'}, |
||||
|
Yellow: []byte{keyEscape, '[', '3', '3', 'm'}, |
||||
|
Blue: []byte{keyEscape, '[', '3', '4', 'm'}, |
||||
|
Magenta: []byte{keyEscape, '[', '3', '5', 'm'}, |
||||
|
Cyan: []byte{keyEscape, '[', '3', '6', 'm'}, |
||||
|
White: []byte{keyEscape, '[', '3', '7', 'm'}, |
||||
|
|
||||
|
Reset: []byte{keyEscape, '[', '0', 'm'}, |
||||
|
} |
||||
|
|
||||
|
// Terminal contains the state for running a VT100 terminal that is capable of
|
||||
|
// reading lines of input.
|
||||
|
type Terminal struct { |
||||
|
// AutoCompleteCallback, if non-null, is called for each keypress with
|
||||
|
// the full input line and the current position of the cursor (in
|
||||
|
// bytes, as an index into |line|). If it returns ok=false, the key
|
||||
|
// press is processed normally. Otherwise it returns a replacement line
|
||||
|
// and the new cursor position.
|
||||
|
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool) |
||||
|
|
||||
|
// Escape contains a pointer to the escape codes for this terminal.
|
||||
|
// It's always a valid pointer, although the escape codes themselves
|
||||
|
// may be empty if the terminal doesn't support them.
|
||||
|
Escape *EscapeCodes |
||||
|
|
||||
|
// lock protects the terminal and the state in this object from
|
||||
|
// concurrent processing of a key press and a Write() call.
|
||||
|
lock sync.Mutex |
||||
|
|
||||
|
c io.ReadWriter |
||||
|
prompt []rune |
||||
|
|
||||
|
// line is the current line being entered.
|
||||
|
line []rune |
||||
|
// pos is the logical position of the cursor in line
|
||||
|
pos int |
||||
|
// echo is true if local echo is enabled
|
||||
|
echo bool |
||||
|
// pasteActive is true iff there is a bracketed paste operation in
|
||||
|
// progress.
|
||||
|
pasteActive bool |
||||
|
|
||||
|
// cursorX contains the current X value of the cursor where the left
|
||||
|
// edge is 0. cursorY contains the row number where the first row of
|
||||
|
// the current line is 0.
|
||||
|
cursorX, cursorY int |
||||
|
// maxLine is the greatest value of cursorY so far.
|
||||
|
maxLine int |
||||
|
|
||||
|
termWidth, termHeight int |
||||
|
|
||||
|
// outBuf contains the terminal data to be sent.
|
||||
|
outBuf []byte |
||||
|
// remainder contains the remainder of any partial key sequences after
|
||||
|
// a read. It aliases into inBuf.
|
||||
|
remainder []byte |
||||
|
inBuf [256]byte |
||||
|
|
||||
|
// history contains previously entered commands so that they can be
|
||||
|
// accessed with the up and down keys.
|
||||
|
history stRingBuffer |
||||
|
// historyIndex stores the currently accessed history entry, where zero
|
||||
|
// means the immediately previous entry.
|
||||
|
historyIndex int |
||||
|
// When navigating up and down the history it's possible to return to
|
||||
|
// the incomplete, initial line. That value is stored in
|
||||
|
// historyPending.
|
||||
|
historyPending string |
||||
|
} |
||||
|
|
||||
|
// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
|
||||
|
// a local terminal, that terminal must first have been put into raw mode.
|
||||
|
// prompt is a string that is written at the start of each input line (i.e.
|
||||
|
// "> ").
|
||||
|
func NewTerminal(c io.ReadWriter, prompt string) *Terminal { |
||||
|
return &Terminal{ |
||||
|
Escape: &vt100EscapeCodes, |
||||
|
c: c, |
||||
|
prompt: []rune(prompt), |
||||
|
termWidth: 80, |
||||
|
termHeight: 24, |
||||
|
echo: true, |
||||
|
historyIndex: -1, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const ( |
||||
|
keyCtrlD = 4 |
||||
|
keyCtrlU = 21 |
||||
|
keyEnter = '\r' |
||||
|
keyEscape = 27 |
||||
|
keyBackspace = 127 |
||||
|
keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota |
||||
|
keyUp |
||||
|
keyDown |
||||
|
keyLeft |
||||
|
keyRight |
||||
|
keyAltLeft |
||||
|
keyAltRight |
||||
|
keyHome |
||||
|
keyEnd |
||||
|
keyDeleteWord |
||||
|
keyDeleteLine |
||||
|
keyClearScreen |
||||
|
keyPasteStart |
||||
|
keyPasteEnd |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
crlf = []byte{'\r', '\n'} |
||||
|
pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'} |
||||
|
pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'} |
||||
|
) |
||||
|
|
||||
|
// bytesToKey tries to parse a key sequence from b. If successful, it returns
|
||||
|
// the key and the remainder of the input. Otherwise it returns utf8.RuneError.
|
||||
|
func bytesToKey(b []byte, pasteActive bool) (rune, []byte) { |
||||
|
if len(b) == 0 { |
||||
|
return utf8.RuneError, nil |
||||
|
} |
||||
|
|
||||
|
if !pasteActive { |
||||
|
switch b[0] { |
||||
|
case 1: // ^A
|
||||
|
return keyHome, b[1:] |
||||
|
case 5: // ^E
|
||||
|
return keyEnd, b[1:] |
||||
|
case 8: // ^H
|
||||
|
return keyBackspace, b[1:] |
||||
|
case 11: // ^K
|
||||
|
return keyDeleteLine, b[1:] |
||||
|
case 12: // ^L
|
||||
|
return keyClearScreen, b[1:] |
||||
|
case 23: // ^W
|
||||
|
return keyDeleteWord, b[1:] |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if b[0] != keyEscape { |
||||
|
if !utf8.FullRune(b) { |
||||
|
return utf8.RuneError, b |
||||
|
} |
||||
|
r, l := utf8.DecodeRune(b) |
||||
|
return r, b[l:] |
||||
|
} |
||||
|
|
||||
|
if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' { |
||||
|
switch b[2] { |
||||
|
case 'A': |
||||
|
return keyUp, b[3:] |
||||
|
case 'B': |
||||
|
return keyDown, b[3:] |
||||
|
case 'C': |
||||
|
return keyRight, b[3:] |
||||
|
case 'D': |
||||
|
return keyLeft, b[3:] |
||||
|
case 'H': |
||||
|
return keyHome, b[3:] |
||||
|
case 'F': |
||||
|
return keyEnd, b[3:] |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' { |
||||
|
switch b[5] { |
||||
|
case 'C': |
||||
|
return keyAltRight, b[6:] |
||||
|
case 'D': |
||||
|
return keyAltLeft, b[6:] |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) { |
||||
|
return keyPasteStart, b[6:] |
||||
|
} |
||||
|
|
||||
|
if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) { |
||||
|
return keyPasteEnd, b[6:] |
||||
|
} |
||||
|
|
||||
|
// If we get here then we have a key that we don't recognise, or a
|
||||
|
// partial sequence. It's not clear how one should find the end of a
|
||||
|
// sequence without knowing them all, but it seems that [a-zA-Z~] only
|
||||
|
// appears at the end of a sequence.
|
||||
|
for i, c := range b[0:] { |
||||
|
if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' { |
||||
|
return keyUnknown, b[i+1:] |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return utf8.RuneError, b |
||||
|
} |
||||
|
|
||||
|
// queue appends data to the end of t.outBuf
|
||||
|
func (t *Terminal) queue(data []rune) { |
||||
|
t.outBuf = append(t.outBuf, []byte(string(data))...) |
||||
|
} |
||||
|
|
||||
|
var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'} |
||||
|
var space = []rune{' '} |
||||
|
|
||||
|
func isPrintable(key rune) bool { |
||||
|
isInSurrogateArea := key >= 0xd800 && key <= 0xdbff |
||||
|
return key >= 32 && !isInSurrogateArea |
||||
|
} |
||||
|
|
||||
|
// moveCursorToPos appends data to t.outBuf which will move the cursor to the
|
||||
|
// given, logical position in the text.
|
||||
|
func (t *Terminal) moveCursorToPos(pos int) { |
||||
|
if !t.echo { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
x := visualLength(t.prompt) + pos |
||||
|
y := x / t.termWidth |
||||
|
x = x % t.termWidth |
||||
|
|
||||
|
up := 0 |
||||
|
if y < t.cursorY { |
||||
|
up = t.cursorY - y |
||||
|
} |
||||
|
|
||||
|
down := 0 |
||||
|
if y > t.cursorY { |
||||
|
down = y - t.cursorY |
||||
|
} |
||||
|
|
||||
|
left := 0 |
||||
|
if x < t.cursorX { |
||||
|
left = t.cursorX - x |
||||
|
} |
||||
|
|
||||
|
right := 0 |
||||
|
if x > t.cursorX { |
||||
|
right = x - t.cursorX |
||||
|
} |
||||
|
|
||||
|
t.cursorX = x |
||||
|
t.cursorY = y |
||||
|
t.move(up, down, left, right) |
||||
|
} |
||||
|
|
||||
|
func (t *Terminal) move(up, down, left, right int) { |
||||
|
movement := make([]rune, 3*(up+down+left+right)) |
||||
|
m := movement |
||||
|
for i := 0; i < up; i++ { |
||||
|
m[0] = keyEscape |
||||
|
m[1] = '[' |
||||
|
m[2] = 'A' |
||||
|
m = m[3:] |
||||
|
} |
||||
|
for i := 0; i < down; i++ { |
||||
|
m[0] = keyEscape |
||||
|
m[1] = '[' |
||||
|
m[2] = 'B' |
||||
|
m = m[3:] |
||||
|
} |
||||
|
for i := 0; i < left; i++ { |
||||
|
m[0] = keyEscape |
||||
|
m[1] = '[' |
||||
|
m[2] = 'D' |
||||
|
m = m[3:] |
||||
|
} |
||||
|
for i := 0; i < right; i++ { |
||||
|
m[0] = keyEscape |
||||
|
m[1] = '[' |
||||
|
m[2] = 'C' |
||||
|
m = m[3:] |
||||
|
} |
||||
|
|
||||
|
t.queue(movement) |
||||
|
} |
||||
|
|
||||
|
func (t *Terminal) clearLineToRight() { |
||||
|
op := []rune{keyEscape, '[', 'K'} |
||||
|
t.queue(op) |
||||
|
} |
||||
|
|
||||
|
const maxLineLength = 4096 |
||||
|
|
||||
|
func (t *Terminal) setLine(newLine []rune, newPos int) { |
||||
|
if t.echo { |
||||
|
t.moveCursorToPos(0) |
||||
|
t.writeLine(newLine) |
||||
|
for i := len(newLine); i < len(t.line); i++ { |
||||
|
t.writeLine(space) |
||||
|
} |
||||
|
t.moveCursorToPos(newPos) |
||||
|
} |
||||
|
t.line = newLine |
||||
|
t.pos = newPos |
||||
|
} |
||||
|
|
||||
|
func (t *Terminal) advanceCursor(places int) { |
||||
|
t.cursorX += places |
||||
|
t.cursorY += t.cursorX / t.termWidth |
||||
|
if t.cursorY > t.maxLine { |
||||
|
t.maxLine = t.cursorY |
||||
|
} |
||||
|
t.cursorX = t.cursorX % t.termWidth |
||||
|
|
||||
|
if places > 0 && t.cursorX == 0 { |
||||
|
// Normally terminals will advance the current position
|
||||
|
// when writing a character. But that doesn't happen
|
||||
|
// for the last character in a line. However, when
|
||||
|
// writing a character (except a new line) that causes
|
||||
|
// a line wrap, the position will be advanced two
|
||||
|
// places.
|
||||
|
//
|
||||
|
// So, if we are stopping at the end of a line, we
|
||||
|
// need to write a newline so that our cursor can be
|
||||
|
// advanced to the next line.
|
||||
|
t.outBuf = append(t.outBuf, '\r', '\n') |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (t *Terminal) eraseNPreviousChars(n int) { |
||||
|
if n == 0 { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
if t.pos < n { |
||||
|
n = t.pos |
||||
|
} |
||||
|
t.pos -= n |
||||
|
t.moveCursorToPos(t.pos) |
||||
|
|
||||
|
copy(t.line[t.pos:], t.line[n+t.pos:]) |
||||
|
t.line = t.line[:len(t.line)-n] |
||||
|
if t.echo { |
||||
|
t.writeLine(t.line[t.pos:]) |
||||
|
for i := 0; i < n; i++ { |
||||
|
t.queue(space) |
||||
|
} |
||||
|
t.advanceCursor(n) |
||||
|
t.moveCursorToPos(t.pos) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// countToLeftWord returns then number of characters from the cursor to the
|
||||
|
// start of the previous word.
|
||||
|
func (t *Terminal) countToLeftWord() int { |
||||
|
if t.pos == 0 { |
||||
|
return 0 |
||||
|
} |
||||
|
|
||||
|
pos := t.pos - 1 |
||||
|
for pos > 0 { |
||||
|
if t.line[pos] != ' ' { |
||||
|
break |
||||
|
} |
||||
|
pos-- |
||||
|
} |
||||
|
for pos > 0 { |
||||
|
if t.line[pos] == ' ' { |
||||
|
pos++ |
||||
|
break |
||||
|
} |
||||
|
pos-- |
||||
|
} |
||||
|
|
||||
|
return t.pos - pos |
||||
|
} |
||||
|
|
||||
|
// countToRightWord returns then number of characters from the cursor to the
|
||||
|
// start of the next word.
|
||||
|
func (t *Terminal) countToRightWord() int { |
||||
|
pos := t.pos |
||||
|
for pos < len(t.line) { |
||||
|
if t.line[pos] == ' ' { |
||||
|
break |
||||
|
} |
||||
|
pos++ |
||||
|
} |
||||
|
for pos < len(t.line) { |
||||
|
if t.line[pos] != ' ' { |
||||
|
break |
||||
|
} |
||||
|
pos++ |
||||
|
} |
||||
|
return pos - t.pos |
||||
|
} |
||||
|
|
||||
|
// visualLength returns the number of visible glyphs in s.
|
||||
|
func visualLength(runes []rune) int { |
||||
|
inEscapeSeq := false |
||||
|
length := 0 |
||||
|
|
||||
|
for _, r := range runes { |
||||
|
switch { |
||||
|
case inEscapeSeq: |
||||
|
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') { |
||||
|
inEscapeSeq = false |
||||
|
} |
||||
|
case r == '\x1b': |
||||
|
inEscapeSeq = true |
||||
|
default: |
||||
|
length++ |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return length |
||||
|
} |
||||
|
|
||||
|
// handleKey processes the given key and, optionally, returns a line of text
|
||||
|
// that the user has entered.
|
||||
|
func (t *Terminal) handleKey(key rune) (line string, ok bool) { |
||||
|
if t.pasteActive && key != keyEnter { |
||||
|
t.addKeyToLine(key) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
switch key { |
||||
|
case keyBackspace: |
||||
|
if t.pos == 0 { |
||||
|
return |
||||
|
} |
||||
|
t.eraseNPreviousChars(1) |
||||
|
case keyAltLeft: |
||||
|
// move left by a word.
|
||||
|
t.pos -= t.countToLeftWord() |
||||
|
t.moveCursorToPos(t.pos) |
||||
|
case keyAltRight: |
||||
|
// move right by a word.
|
||||
|
t.pos += t.countToRightWord() |
||||
|
t.moveCursorToPos(t.pos) |
||||
|
case keyLeft: |
||||
|
if t.pos == 0 { |
||||
|
return |
||||
|
} |
||||
|
t.pos-- |
||||
|
t.moveCursorToPos(t.pos) |
||||
|
case keyRight: |
||||
|
if t.pos == len(t.line) { |
||||
|
return |
||||
|
} |
||||
|
t.pos++ |
||||
|
t.moveCursorToPos(t.pos) |
||||
|
case keyHome: |
||||
|
if t.pos == 0 { |
||||
|
return |
||||
|
} |
||||
|
t.pos = 0 |
||||
|
t.moveCursorToPos(t.pos) |
||||
|
case keyEnd: |
||||
|
if t.pos == len(t.line) { |
||||
|
return |
||||
|
} |
||||
|
t.pos = len(t.line) |
||||
|
t.moveCursorToPos(t.pos) |
||||
|
case keyUp: |
||||
|
entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1) |
||||
|
if !ok { |
||||
|
return "", false |
||||
|
} |
||||
|
if t.historyIndex == -1 { |
||||
|
t.historyPending = string(t.line) |
||||
|
} |
||||
|
t.historyIndex++ |
||||
|
runes := []rune(entry) |
||||
|
t.setLine(runes, len(runes)) |
||||
|
case keyDown: |
||||
|
switch t.historyIndex { |
||||
|
case -1: |
||||
|
return |
||||
|
case 0: |
||||
|
runes := []rune(t.historyPending) |
||||
|
t.setLine(runes, len(runes)) |
||||
|
t.historyIndex-- |
||||
|
default: |
||||
|
entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1) |
||||
|
if ok { |
||||
|
t.historyIndex-- |
||||
|
runes := []rune(entry) |
||||
|
t.setLine(runes, len(runes)) |
||||
|
} |
||||
|
} |
||||
|
case keyEnter: |
||||
|
t.moveCursorToPos(len(t.line)) |
||||
|
t.queue([]rune("\r\n")) |
||||
|
line = string(t.line) |
||||
|
ok = true |
||||
|
t.line = t.line[:0] |
||||
|
t.pos = 0 |
||||
|
t.cursorX = 0 |
||||
|
t.cursorY = 0 |
||||
|
t.maxLine = 0 |
||||
|
case keyDeleteWord: |
||||
|
// Delete zero or more spaces and then one or more characters.
|
||||
|
t.eraseNPreviousChars(t.countToLeftWord()) |
||||
|
case keyDeleteLine: |
||||
|
// Delete everything from the current cursor position to the
|
||||
|
// end of line.
|
||||
|
for i := t.pos; i < len(t.line); i++ { |
||||
|
t.queue(space) |
||||
|
t.advanceCursor(1) |
||||
|
} |
||||
|
t.line = t.line[:t.pos] |
||||
|
t.moveCursorToPos(t.pos) |
||||
|
case keyCtrlD: |
||||
|
// Erase the character under the current position.
|
||||
|
// The EOF case when the line is empty is handled in
|
||||
|
// readLine().
|
||||
|
if t.pos < len(t.line) { |
||||
|
t.pos++ |
||||
|
t.eraseNPreviousChars(1) |
||||
|
} |
||||
|
case keyCtrlU: |
||||
|
t.eraseNPreviousChars(t.pos) |
||||
|
case keyClearScreen: |
||||
|
// Erases the screen and moves the cursor to the home position.
|
||||
|
t.queue([]rune("\x1b[2J\x1b[H")) |
||||
|
t.queue(t.prompt) |
||||
|
t.cursorX, t.cursorY = 0, 0 |
||||
|
t.advanceCursor(visualLength(t.prompt)) |
||||
|
t.setLine(t.line, t.pos) |
||||
|
default: |
||||
|
if t.AutoCompleteCallback != nil { |
||||
|
prefix := string(t.line[:t.pos]) |
||||
|
suffix := string(t.line[t.pos:]) |
||||
|
|
||||
|
t.lock.Unlock() |
||||
|
newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key) |
||||
|
t.lock.Lock() |
||||
|
|
||||
|
if completeOk { |
||||
|
t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos])) |
||||
|
return |
||||
|
} |
||||
|
} |
||||
|
if !isPrintable(key) { |
||||
|
return |
||||
|
} |
||||
|
if len(t.line) == maxLineLength { |
||||
|
return |
||||
|
} |
||||
|
t.addKeyToLine(key) |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// addKeyToLine inserts the given key at the current position in the current
|
||||
|
// line.
|
||||
|
func (t *Terminal) addKeyToLine(key rune) { |
||||
|
if len(t.line) == cap(t.line) { |
||||
|
newLine := make([]rune, len(t.line), 2*(1+len(t.line))) |
||||
|
copy(newLine, t.line) |
||||
|
t.line = newLine |
||||
|
} |
||||
|
t.line = t.line[:len(t.line)+1] |
||||
|
copy(t.line[t.pos+1:], t.line[t.pos:]) |
||||
|
t.line[t.pos] = key |
||||
|
if t.echo { |
||||
|
t.writeLine(t.line[t.pos:]) |
||||
|
} |
||||
|
t.pos++ |
||||
|
t.moveCursorToPos(t.pos) |
||||
|
} |
||||
|
|
||||
|
func (t *Terminal) writeLine(line []rune) { |
||||
|
for len(line) != 0 { |
||||
|
remainingOnLine := t.termWidth - t.cursorX |
||||
|
todo := len(line) |
||||
|
if todo > remainingOnLine { |
||||
|
todo = remainingOnLine |
||||
|
} |
||||
|
t.queue(line[:todo]) |
||||
|
t.advanceCursor(visualLength(line[:todo])) |
||||
|
line = line[todo:] |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n.
|
||||
|
func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) { |
||||
|
for len(buf) > 0 { |
||||
|
i := bytes.IndexByte(buf, '\n') |
||||
|
todo := len(buf) |
||||
|
if i >= 0 { |
||||
|
todo = i |
||||
|
} |
||||
|
|
||||
|
var nn int |
||||
|
nn, err = w.Write(buf[:todo]) |
||||
|
n += nn |
||||
|
if err != nil { |
||||
|
return n, err |
||||
|
} |
||||
|
buf = buf[todo:] |
||||
|
|
||||
|
if i >= 0 { |
||||
|
if _, err = w.Write(crlf); err != nil { |
||||
|
return n, err |
||||
|
} |
||||
|
n++ |
||||
|
buf = buf[1:] |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return n, nil |
||||
|
} |
||||
|
|
||||
|
func (t *Terminal) Write(buf []byte) (n int, err error) { |
||||
|
t.lock.Lock() |
||||
|
defer t.lock.Unlock() |
||||
|
|
||||
|
if t.cursorX == 0 && t.cursorY == 0 { |
||||
|
// This is the easy case: there's nothing on the screen that we
|
||||
|
// have to move out of the way.
|
||||
|
return writeWithCRLF(t.c, buf) |
||||
|
} |
||||
|
|
||||
|
// We have a prompt and possibly user input on the screen. We
|
||||
|
// have to clear it first.
|
||||
|
t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */) |
||||
|
t.cursorX = 0 |
||||
|
t.clearLineToRight() |
||||
|
|
||||
|
for t.cursorY > 0 { |
||||
|
t.move(1 /* up */, 0, 0, 0) |
||||
|
t.cursorY-- |
||||
|
t.clearLineToRight() |
||||
|
} |
||||
|
|
||||
|
if _, err = t.c.Write(t.outBuf); err != nil { |
||||
|
return |
||||
|
} |
||||
|
t.outBuf = t.outBuf[:0] |
||||
|
|
||||
|
if n, err = writeWithCRLF(t.c, buf); err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
t.writeLine(t.prompt) |
||||
|
if t.echo { |
||||
|
t.writeLine(t.line) |
||||
|
} |
||||
|
|
||||
|
t.moveCursorToPos(t.pos) |
||||
|
|
||||
|
if _, err = t.c.Write(t.outBuf); err != nil { |
||||
|
return |
||||
|
} |
||||
|
t.outBuf = t.outBuf[:0] |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// ReadPassword temporarily changes the prompt and reads a password, without
|
||||
|
// echo, from the terminal.
|
||||
|
func (t *Terminal) ReadPassword(prompt string) (line string, err error) { |
||||
|
t.lock.Lock() |
||||
|
defer t.lock.Unlock() |
||||
|
|
||||
|
oldPrompt := t.prompt |
||||
|
t.prompt = []rune(prompt) |
||||
|
t.echo = false |
||||
|
|
||||
|
line, err = t.readLine() |
||||
|
|
||||
|
t.prompt = oldPrompt |
||||
|
t.echo = true |
||||
|
|
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// ReadLine returns a line of input from the terminal.
|
||||
|
func (t *Terminal) ReadLine() (line string, err error) { |
||||
|
t.lock.Lock() |
||||
|
defer t.lock.Unlock() |
||||
|
|
||||
|
return t.readLine() |
||||
|
} |
||||
|
|
||||
|
func (t *Terminal) readLine() (line string, err error) { |
||||
|
// t.lock must be held at this point
|
||||
|
|
||||
|
if t.cursorX == 0 && t.cursorY == 0 { |
||||
|
t.writeLine(t.prompt) |
||||
|
t.c.Write(t.outBuf) |
||||
|
t.outBuf = t.outBuf[:0] |
||||
|
} |
||||
|
|
||||
|
lineIsPasted := t.pasteActive |
||||
|
|
||||
|
for { |
||||
|
rest := t.remainder |
||||
|
lineOk := false |
||||
|
for !lineOk { |
||||
|
var key rune |
||||
|
key, rest = bytesToKey(rest, t.pasteActive) |
||||
|
if key == utf8.RuneError { |
||||
|
break |
||||
|
} |
||||
|
if !t.pasteActive { |
||||
|
if key == keyCtrlD { |
||||
|
if len(t.line) == 0 { |
||||
|
return "", io.EOF |
||||
|
} |
||||
|
} |
||||
|
if key == keyPasteStart { |
||||
|
t.pasteActive = true |
||||
|
if len(t.line) == 0 { |
||||
|
lineIsPasted = true |
||||
|
} |
||||
|
continue |
||||
|
} |
||||
|
} else if key == keyPasteEnd { |
||||
|
t.pasteActive = false |
||||
|
continue |
||||
|
} |
||||
|
if !t.pasteActive { |
||||
|
lineIsPasted = false |
||||
|
} |
||||
|
line, lineOk = t.handleKey(key) |
||||
|
} |
||||
|
if len(rest) > 0 { |
||||
|
n := copy(t.inBuf[:], rest) |
||||
|
t.remainder = t.inBuf[:n] |
||||
|
} else { |
||||
|
t.remainder = nil |
||||
|
} |
||||
|
t.c.Write(t.outBuf) |
||||
|
t.outBuf = t.outBuf[:0] |
||||
|
if lineOk { |
||||
|
if t.echo { |
||||
|
t.historyIndex = -1 |
||||
|
t.history.Add(line) |
||||
|
} |
||||
|
if lineIsPasted { |
||||
|
err = ErrPasteIndicator |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// t.remainder is a slice at the beginning of t.inBuf
|
||||
|
// containing a partial key sequence
|
||||
|
readBuf := t.inBuf[len(t.remainder):] |
||||
|
var n int |
||||
|
|
||||
|
t.lock.Unlock() |
||||
|
n, err = t.c.Read(readBuf) |
||||
|
t.lock.Lock() |
||||
|
|
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
t.remainder = t.inBuf[:n+len(t.remainder)] |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// SetPrompt sets the prompt to be used when reading subsequent lines.
|
||||
|
func (t *Terminal) SetPrompt(prompt string) { |
||||
|
t.lock.Lock() |
||||
|
defer t.lock.Unlock() |
||||
|
|
||||
|
t.prompt = []rune(prompt) |
||||
|
} |
||||
|
|
||||
|
func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) { |
||||
|
// Move cursor to column zero at the start of the line.
|
||||
|
t.move(t.cursorY, 0, t.cursorX, 0) |
||||
|
t.cursorX, t.cursorY = 0, 0 |
||||
|
t.clearLineToRight() |
||||
|
for t.cursorY < numPrevLines { |
||||
|
// Move down a line
|
||||
|
t.move(0, 1, 0, 0) |
||||
|
t.cursorY++ |
||||
|
t.clearLineToRight() |
||||
|
} |
||||
|
// Move back to beginning.
|
||||
|
t.move(t.cursorY, 0, 0, 0) |
||||
|
t.cursorX, t.cursorY = 0, 0 |
||||
|
|
||||
|
t.queue(t.prompt) |
||||
|
t.advanceCursor(visualLength(t.prompt)) |
||||
|
t.writeLine(t.line) |
||||
|
t.moveCursorToPos(t.pos) |
||||
|
} |
||||
|
|
||||
|
func (t *Terminal) SetSize(width, height int) error { |
||||
|
t.lock.Lock() |
||||
|
defer t.lock.Unlock() |
||||
|
|
||||
|
if width == 0 { |
||||
|
width = 1 |
||||
|
} |
||||
|
|
||||
|
oldWidth := t.termWidth |
||||
|
t.termWidth, t.termHeight = width, height |
||||
|
|
||||
|
switch { |
||||
|
case width == oldWidth: |
||||
|
// If the width didn't change then nothing else needs to be
|
||||
|
// done.
|
||||
|
return nil |
||||
|
case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0: |
||||
|
// If there is nothing on current line and no prompt printed,
|
||||
|
// just do nothing
|
||||
|
return nil |
||||
|
case width < oldWidth: |
||||
|
// Some terminals (e.g. xterm) will truncate lines that were
|
||||
|
// too long when shinking. Others, (e.g. gnome-terminal) will
|
||||
|
// attempt to wrap them. For the former, repainting t.maxLine
|
||||
|
// works great, but that behaviour goes badly wrong in the case
|
||||
|
// of the latter because they have doubled every full line.
|
||||
|
|
||||
|
// We assume that we are working on a terminal that wraps lines
|
||||
|
// and adjust the cursor position based on every previous line
|
||||
|
// wrapping and turning into two. This causes the prompt on
|
||||
|
// xterms to move upwards, which isn't great, but it avoids a
|
||||
|
// huge mess with gnome-terminal.
|
||||
|
if t.cursorX >= t.termWidth { |
||||
|
t.cursorX = t.termWidth - 1 |
||||
|
} |
||||
|
t.cursorY *= 2 |
||||
|
t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2) |
||||
|
case width > oldWidth: |
||||
|
// If the terminal expands then our position calculations will
|
||||
|
// be wrong in the future because we think the cursor is
|
||||
|
// |t.pos| chars into the string, but there will be a gap at
|
||||
|
// the end of any wrapped line.
|
||||
|
//
|
||||
|
// But the position will actually be correct until we move, so
|
||||
|
// we can move back to the beginning and repaint everything.
|
||||
|
t.clearAndRepaintLinePlusNPrevious(t.maxLine) |
||||
|
} |
||||
|
|
||||
|
_, err := t.c.Write(t.outBuf) |
||||
|
t.outBuf = t.outBuf[:0] |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
type pasteIndicatorError struct{} |
||||
|
|
||||
|
func (pasteIndicatorError) Error() string { |
||||
|
return "terminal: ErrPasteIndicator not correctly handled" |
||||
|
} |
||||
|
|
||||
|
// ErrPasteIndicator may be returned from ReadLine as the error, in addition
|
||||
|
// to valid line data. It indicates that bracketed paste mode is enabled and
|
||||
|
// that the returned line consists only of pasted data. Programs may wish to
|
||||
|
// interpret pasted data more literally than typed data.
|
||||
|
var ErrPasteIndicator = pasteIndicatorError{} |
||||
|
|
||||
|
// SetBracketedPasteMode requests that the terminal bracket paste operations
|
||||
|
// with markers. Not all terminals support this but, if it is supported, then
|
||||
|
// enabling this mode will stop any autocomplete callback from running due to
|
||||
|
// pastes. Additionally, any lines that are completely pasted will be returned
|
||||
|
// from ReadLine with the error set to ErrPasteIndicator.
|
||||
|
func (t *Terminal) SetBracketedPasteMode(on bool) { |
||||
|
if on { |
||||
|
io.WriteString(t.c, "\x1b[?2004h") |
||||
|
} else { |
||||
|
io.WriteString(t.c, "\x1b[?2004l") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// stRingBuffer is a ring buffer of strings.
|
||||
|
type stRingBuffer struct { |
||||
|
// entries contains max elements.
|
||||
|
entries []string |
||||
|
max int |
||||
|
// head contains the index of the element most recently added to the ring.
|
||||
|
head int |
||||
|
// size contains the number of elements in the ring.
|
||||
|
size int |
||||
|
} |
||||
|
|
||||
|
func (s *stRingBuffer) Add(a string) { |
||||
|
if s.entries == nil { |
||||
|
const defaultNumEntries = 100 |
||||
|
s.entries = make([]string, defaultNumEntries) |
||||
|
s.max = defaultNumEntries |
||||
|
} |
||||
|
|
||||
|
s.head = (s.head + 1) % s.max |
||||
|
s.entries[s.head] = a |
||||
|
if s.size < s.max { |
||||
|
s.size++ |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// NthPreviousEntry returns the value passed to the nth previous call to Add.
|
||||
|
// If n is zero then the immediately prior value is returned, if one, then the
|
||||
|
// next most recent, and so on. If such an element doesn't exist then ok is
|
||||
|
// false.
|
||||
|
func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) { |
||||
|
if n >= s.size { |
||||
|
return "", false |
||||
|
} |
||||
|
index := s.head - n |
||||
|
if index < 0 { |
||||
|
index += s.max |
||||
|
} |
||||
|
return s.entries[index], true |
||||
|
} |
||||
|
|
||||
|
// readPasswordLine reads from reader until it finds \n or io.EOF.
|
||||
|
// The slice returned does not include the \n.
|
||||
|
// readPasswordLine also ignores any \r it finds.
|
||||
|
func readPasswordLine(reader io.Reader) ([]byte, error) { |
||||
|
var buf [1]byte |
||||
|
var ret []byte |
||||
|
|
||||
|
for { |
||||
|
n, err := reader.Read(buf[:]) |
||||
|
if n > 0 { |
||||
|
switch buf[0] { |
||||
|
case '\n': |
||||
|
return ret, nil |
||||
|
case '\r': |
||||
|
// remove \r from passwords on Windows
|
||||
|
default: |
||||
|
ret = append(ret, buf[0]) |
||||
|
} |
||||
|
continue |
||||
|
} |
||||
|
if err != nil { |
||||
|
if err == io.EOF && len(ret) > 0 { |
||||
|
return ret, nil |
||||
|
} |
||||
|
return ret, err |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,114 @@ |
|||||
|
// 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 darwin dragonfly freebsd linux,!appengine netbsd openbsd
|
||||
|
|
||||
|
// Package terminal provides support functions for dealing with terminals, as
|
||||
|
// commonly found on UNIX systems.
|
||||
|
//
|
||||
|
// Putting a terminal into raw mode is the most common requirement:
|
||||
|
//
|
||||
|
// oldState, err := terminal.MakeRaw(0)
|
||||
|
// if err != nil {
|
||||
|
// panic(err)
|
||||
|
// }
|
||||
|
// defer terminal.Restore(0, oldState)
|
||||
|
package terminal // import "golang.org/x/crypto/ssh/terminal"
|
||||
|
|
||||
|
import ( |
||||
|
"golang.org/x/sys/unix" |
||||
|
) |
||||
|
|
||||
|
// State contains the state of a terminal.
|
||||
|
type State struct { |
||||
|
termios unix.Termios |
||||
|
} |
||||
|
|
||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
|
func IsTerminal(fd int) bool { |
||||
|
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios) |
||||
|
return err == nil |
||||
|
} |
||||
|
|
||||
|
// MakeRaw put the terminal connected to the given file descriptor into raw
|
||||
|
// mode and returns the previous state of the terminal so that it can be
|
||||
|
// restored.
|
||||
|
func MakeRaw(fd int) (*State, error) { |
||||
|
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
oldState := State{termios: *termios} |
||||
|
|
||||
|
// This attempts to replicate the behaviour documented for cfmakeraw in
|
||||
|
// the termios(3) manpage.
|
||||
|
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON |
||||
|
termios.Oflag &^= unix.OPOST |
||||
|
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN |
||||
|
termios.Cflag &^= unix.CSIZE | unix.PARENB |
||||
|
termios.Cflag |= unix.CS8 |
||||
|
termios.Cc[unix.VMIN] = 1 |
||||
|
termios.Cc[unix.VTIME] = 0 |
||||
|
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return &oldState, nil |
||||
|
} |
||||
|
|
||||
|
// GetState returns the current state of a terminal which may be useful to
|
||||
|
// restore the terminal after a signal.
|
||||
|
func GetState(fd int) (*State, error) { |
||||
|
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return &State{termios: *termios}, nil |
||||
|
} |
||||
|
|
||||
|
// Restore restores the terminal connected to the given file descriptor to a
|
||||
|
// previous state.
|
||||
|
func Restore(fd int, state *State) error { |
||||
|
return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios) |
||||
|
} |
||||
|
|
||||
|
// GetSize returns the dimensions of the given terminal.
|
||||
|
func GetSize(fd int) (width, height int, err error) { |
||||
|
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) |
||||
|
if err != nil { |
||||
|
return -1, -1, err |
||||
|
} |
||||
|
return int(ws.Col), int(ws.Row), nil |
||||
|
} |
||||
|
|
||||
|
// passwordReader is an io.Reader that reads from a specific file descriptor.
|
||||
|
type passwordReader int |
||||
|
|
||||
|
func (r passwordReader) Read(buf []byte) (int, error) { |
||||
|
return unix.Read(int(r), buf) |
||||
|
} |
||||
|
|
||||
|
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||
|
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||
|
// returned does not include the \n.
|
||||
|
func ReadPassword(fd int) ([]byte, error) { |
||||
|
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
newState := *termios |
||||
|
newState.Lflag &^= unix.ECHO |
||||
|
newState.Lflag |= unix.ICANON | unix.ISIG |
||||
|
newState.Iflag |= unix.ICRNL |
||||
|
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios) |
||||
|
|
||||
|
return readPasswordLine(passwordReader(fd)) |
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
// Copyright 2013 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 darwin dragonfly freebsd netbsd openbsd
|
||||
|
|
||||
|
package terminal |
||||
|
|
||||
|
import "golang.org/x/sys/unix" |
||||
|
|
||||
|
const ioctlReadTermios = unix.TIOCGETA |
||||
|
const ioctlWriteTermios = unix.TIOCSETA |
@ -0,0 +1,10 @@ |
|||||
|
// Copyright 2013 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 terminal |
||||
|
|
||||
|
import "golang.org/x/sys/unix" |
||||
|
|
||||
|
const ioctlReadTermios = unix.TCGETS |
||||
|
const ioctlWriteTermios = unix.TCSETS |
@ -0,0 +1,58 @@ |
|||||
|
// 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.
|
||||
|
|
||||
|
// Package terminal provides support functions for dealing with terminals, as
|
||||
|
// commonly found on UNIX systems.
|
||||
|
//
|
||||
|
// Putting a terminal into raw mode is the most common requirement:
|
||||
|
//
|
||||
|
// oldState, err := terminal.MakeRaw(0)
|
||||
|
// if err != nil {
|
||||
|
// panic(err)
|
||||
|
// }
|
||||
|
// defer terminal.Restore(0, oldState)
|
||||
|
package terminal |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"runtime" |
||||
|
) |
||||
|
|
||||
|
type State struct{} |
||||
|
|
||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
|
func IsTerminal(fd int) bool { |
||||
|
return false |
||||
|
} |
||||
|
|
||||
|
// MakeRaw put the terminal connected to the given file descriptor into raw
|
||||
|
// mode and returns the previous state of the terminal so that it can be
|
||||
|
// restored.
|
||||
|
func MakeRaw(fd int) (*State, error) { |
||||
|
return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||
|
} |
||||
|
|
||||
|
// GetState returns the current state of a terminal which may be useful to
|
||||
|
// restore the terminal after a signal.
|
||||
|
func GetState(fd int) (*State, error) { |
||||
|
return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||
|
} |
||||
|
|
||||
|
// Restore restores the terminal connected to the given file descriptor to a
|
||||
|
// previous state.
|
||||
|
func Restore(fd int, state *State) error { |
||||
|
return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||
|
} |
||||
|
|
||||
|
// GetSize returns the dimensions of the given terminal.
|
||||
|
func GetSize(fd int) (width, height int, err error) { |
||||
|
return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||
|
} |
||||
|
|
||||
|
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||
|
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||
|
// returned does not include the \n.
|
||||
|
func ReadPassword(fd int) ([]byte, error) { |
||||
|
return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||
|
} |
@ -0,0 +1,124 @@ |
|||||
|
// 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 solaris
|
||||
|
|
||||
|
package terminal // import "golang.org/x/crypto/ssh/terminal"
|
||||
|
|
||||
|
import ( |
||||
|
"golang.org/x/sys/unix" |
||||
|
"io" |
||||
|
"syscall" |
||||
|
) |
||||
|
|
||||
|
// State contains the state of a terminal.
|
||||
|
type State struct { |
||||
|
termios unix.Termios |
||||
|
} |
||||
|
|
||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
|
func IsTerminal(fd int) bool { |
||||
|
_, err := unix.IoctlGetTermio(fd, unix.TCGETA) |
||||
|
return err == nil |
||||
|
} |
||||
|
|
||||
|
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||
|
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||
|
// returned does not include the \n.
|
||||
|
func ReadPassword(fd int) ([]byte, error) { |
||||
|
// see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c
|
||||
|
val, err := unix.IoctlGetTermios(fd, unix.TCGETS) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
oldState := *val |
||||
|
|
||||
|
newState := oldState |
||||
|
newState.Lflag &^= syscall.ECHO |
||||
|
newState.Lflag |= syscall.ICANON | syscall.ISIG |
||||
|
newState.Iflag |= syscall.ICRNL |
||||
|
err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState) |
||||
|
|
||||
|
var buf [16]byte |
||||
|
var ret []byte |
||||
|
for { |
||||
|
n, err := syscall.Read(fd, buf[:]) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if n == 0 { |
||||
|
if len(ret) == 0 { |
||||
|
return nil, io.EOF |
||||
|
} |
||||
|
break |
||||
|
} |
||||
|
if buf[n-1] == '\n' { |
||||
|
n-- |
||||
|
} |
||||
|
ret = append(ret, buf[:n]...) |
||||
|
if n < len(buf) { |
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return ret, nil |
||||
|
} |
||||
|
|
||||
|
// MakeRaw puts the terminal connected to the given file descriptor into raw
|
||||
|
// mode and returns the previous state of the terminal so that it can be
|
||||
|
// restored.
|
||||
|
// see http://cr.illumos.org/~webrev/andy_js/1060/
|
||||
|
func MakeRaw(fd int) (*State, error) { |
||||
|
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
oldState := State{termios: *termios} |
||||
|
|
||||
|
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON |
||||
|
termios.Oflag &^= unix.OPOST |
||||
|
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN |
||||
|
termios.Cflag &^= unix.CSIZE | unix.PARENB |
||||
|
termios.Cflag |= unix.CS8 |
||||
|
termios.Cc[unix.VMIN] = 1 |
||||
|
termios.Cc[unix.VTIME] = 0 |
||||
|
|
||||
|
if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return &oldState, nil |
||||
|
} |
||||
|
|
||||
|
// Restore restores the terminal connected to the given file descriptor to a
|
||||
|
// previous state.
|
||||
|
func Restore(fd int, oldState *State) error { |
||||
|
return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios) |
||||
|
} |
||||
|
|
||||
|
// GetState returns the current state of a terminal which may be useful to
|
||||
|
// restore the terminal after a signal.
|
||||
|
func GetState(fd int) (*State, error) { |
||||
|
termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
return &State{termios: *termios}, nil |
||||
|
} |
||||
|
|
||||
|
// GetSize returns the dimensions of the given terminal.
|
||||
|
func GetSize(fd int) (width, height int, err error) { |
||||
|
ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) |
||||
|
if err != nil { |
||||
|
return 0, 0, err |
||||
|
} |
||||
|
return int(ws.Col), int(ws.Row), nil |
||||
|
} |
@ -0,0 +1,103 @@ |
|||||
|
// 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 windows
|
||||
|
|
||||
|
// Package terminal provides support functions for dealing with terminals, as
|
||||
|
// commonly found on UNIX systems.
|
||||
|
//
|
||||
|
// Putting a terminal into raw mode is the most common requirement:
|
||||
|
//
|
||||
|
// oldState, err := terminal.MakeRaw(0)
|
||||
|
// if err != nil {
|
||||
|
// panic(err)
|
||||
|
// }
|
||||
|
// defer terminal.Restore(0, oldState)
|
||||
|
package terminal |
||||
|
|
||||
|
import ( |
||||
|
"os" |
||||
|
|
||||
|
"golang.org/x/sys/windows" |
||||
|
) |
||||
|
|
||||
|
type State struct { |
||||
|
mode uint32 |
||||
|
} |
||||
|
|
||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
|
func IsTerminal(fd int) bool { |
||||
|
var st uint32 |
||||
|
err := windows.GetConsoleMode(windows.Handle(fd), &st) |
||||
|
return err == nil |
||||
|
} |
||||
|
|
||||
|
// MakeRaw put the terminal connected to the given file descriptor into raw
|
||||
|
// mode and returns the previous state of the terminal so that it can be
|
||||
|
// restored.
|
||||
|
func MakeRaw(fd int) (*State, error) { |
||||
|
var st uint32 |
||||
|
if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) |
||||
|
if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
return &State{st}, nil |
||||
|
} |
||||
|
|
||||
|
// GetState returns the current state of a terminal which may be useful to
|
||||
|
// restore the terminal after a signal.
|
||||
|
func GetState(fd int) (*State, error) { |
||||
|
var st uint32 |
||||
|
if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
return &State{st}, nil |
||||
|
} |
||||
|
|
||||
|
// Restore restores the terminal connected to the given file descriptor to a
|
||||
|
// previous state.
|
||||
|
func Restore(fd int, state *State) error { |
||||
|
return windows.SetConsoleMode(windows.Handle(fd), state.mode) |
||||
|
} |
||||
|
|
||||
|
// GetSize returns the dimensions of the given terminal.
|
||||
|
func GetSize(fd int) (width, height int, err error) { |
||||
|
var info windows.ConsoleScreenBufferInfo |
||||
|
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil { |
||||
|
return 0, 0, err |
||||
|
} |
||||
|
return int(info.Size.X), int(info.Size.Y), nil |
||||
|
} |
||||
|
|
||||
|
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||
|
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||
|
// returned does not include the \n.
|
||||
|
func ReadPassword(fd int) ([]byte, error) { |
||||
|
var st uint32 |
||||
|
if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
old := st |
||||
|
|
||||
|
st &^= (windows.ENABLE_ECHO_INPUT) |
||||
|
st |= (windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) |
||||
|
if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
defer windows.SetConsoleMode(windows.Handle(fd), old) |
||||
|
|
||||
|
var h windows.Handle |
||||
|
p, _ := windows.GetCurrentProcess() |
||||
|
if err := windows.DuplicateHandle(p, windows.Handle(fd), p, &h, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
f := os.NewFile(uintptr(h), "stdin") |
||||
|
defer f.Close() |
||||
|
return readPasswordLine(f) |
||||
|
} |
@ -0,0 +1,27 @@ |
|||||
|
Copyright (c) 2009 The Go Authors. All rights reserved. |
||||
|
|
||||
|
Redistribution and use in source and binary forms, with or without |
||||
|
modification, are permitted provided that the following conditions are |
||||
|
met: |
||||
|
|
||||
|
* Redistributions of source code must retain the above copyright |
||||
|
notice, this list of conditions and the following disclaimer. |
||||
|
* Redistributions in binary form must reproduce the above |
||||
|
copyright notice, this list of conditions and the following disclaimer |
||||
|
in the documentation and/or other materials provided with the |
||||
|
distribution. |
||||
|
* Neither the name of Google Inc. nor the names of its |
||||
|
contributors may be used to endorse or promote products derived from |
||||
|
this software without specific prior written permission. |
||||
|
|
||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,22 @@ |
|||||
|
Additional IP Rights Grant (Patents) |
||||
|
|
||||
|
"This implementation" means the copyrightable works distributed by |
||||
|
Google as part of the Go project. |
||||
|
|
||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive, |
||||
|
no-charge, royalty-free, irrevocable (except as stated in this section) |
||||
|
patent license to make, have made, use, offer to sell, sell, import, |
||||
|
transfer and otherwise run, modify and propagate the contents of this |
||||
|
implementation of Go, where such license applies only to those patent |
||||
|
claims, both currently owned or controlled by Google and acquired in |
||||
|
the future, licensable by Google that are necessarily infringed by this |
||||
|
implementation of Go. This grant does not include claims that would be |
||||
|
infringed only as a consequence of further modification of this |
||||
|
implementation. If you or your agent or exclusive licensee institute or |
||||
|
order or agree to the institution of patent litigation against any |
||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging |
||||
|
that this implementation of Go or any code incorporated within this |
||||
|
implementation of Go constitutes direct or contributory patent |
||||
|
infringement, or inducement of patent infringement, then any patent |
||||
|
rights granted to you under this License for this implementation of Go |
||||
|
shall terminate as of the date such litigation is filed. |
@ -0,0 +1,173 @@ |
|||||
|
# Building `sys/unix` |
||||
|
|
||||
|
The sys/unix package provides access to the raw system call interface of the |
||||
|
underlying operating system. See: https://godoc.org/golang.org/x/sys/unix |
||||
|
|
||||
|
Porting Go to a new architecture/OS combination or adding syscalls, types, or |
||||
|
constants to an existing architecture/OS pair requires some manual effort; |
||||
|
however, there are tools that automate much of the process. |
||||
|
|
||||
|
## Build Systems |
||||
|
|
||||
|
There are currently two ways we generate the necessary files. We are currently |
||||
|
migrating the build system to use containers so the builds are reproducible. |
||||
|
This is being done on an OS-by-OS basis. Please update this documentation as |
||||
|
components of the build system change. |
||||
|
|
||||
|
### Old Build System (currently for `GOOS != "Linux" || GOARCH == "sparc64"`) |
||||
|
|
||||
|
The old build system generates the Go files based on the C header files |
||||
|
present on your system. This means that files |
||||
|
for a given GOOS/GOARCH pair must be generated on a system with that OS and |
||||
|
architecture. This also means that the generated code can differ from system |
||||
|
to system, based on differences in the header files. |
||||
|
|
||||
|
To avoid this, if you are using the old build system, only generate the Go |
||||
|
files on an installation with unmodified header files. It is also important to |
||||
|
keep track of which version of the OS the files were generated from (ex. |
||||
|
Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes |
||||
|
and have each OS upgrade correspond to a single change. |
||||
|
|
||||
|
To build the files for your current OS and architecture, make sure GOOS and |
||||
|
GOARCH are set correctly and run `mkall.sh`. This will generate the files for |
||||
|
your specific system. Running `mkall.sh -n` shows the commands that will be run. |
||||
|
|
||||
|
Requirements: bash, perl, go |
||||
|
|
||||
|
### New Build System (currently for `GOOS == "Linux" && GOARCH != "sparc64"`) |
||||
|
|
||||
|
The new build system uses a Docker container to generate the go files directly |
||||
|
from source checkouts of the kernel and various system libraries. This means |
||||
|
that on any platform that supports Docker, all the files using the new build |
||||
|
system can be generated at once, and generated files will not change based on |
||||
|
what the person running the scripts has installed on their computer. |
||||
|
|
||||
|
The OS specific files for the new build system are located in the `${GOOS}` |
||||
|
directory, and the build is coordinated by the `${GOOS}/mkall.go` program. When |
||||
|
the kernel or system library updates, modify the Dockerfile at |
||||
|
`${GOOS}/Dockerfile` to checkout the new release of the source. |
||||
|
|
||||
|
To build all the files under the new build system, you must be on an amd64/Linux |
||||
|
system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will |
||||
|
then generate all of the files for all of the GOOS/GOARCH pairs in the new build |
||||
|
system. Running `mkall.sh -n` shows the commands that will be run. |
||||
|
|
||||
|
Requirements: bash, perl, go, docker |
||||
|
|
||||
|
## Component files |
||||
|
|
||||
|
This section describes the various files used in the code generation process. |
||||
|
It also contains instructions on how to modify these files to add a new |
||||
|
architecture/OS or to add additional syscalls, types, or constants. Note that |
||||
|
if you are using the new build system, the scripts cannot be called normally. |
||||
|
They must be called from within the docker container. |
||||
|
|
||||
|
### asm files |
||||
|
|
||||
|
The hand-written assembly file at `asm_${GOOS}_${GOARCH}.s` implements system |
||||
|
call dispatch. There are three entry points: |
||||
|
``` |
||||
|
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) |
||||
|
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) |
||||
|
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) |
||||
|
``` |
||||
|
The first and second are the standard ones; they differ only in how many |
||||
|
arguments can be passed to the kernel. The third is for low-level use by the |
||||
|
ForkExec wrapper. Unlike the first two, it does not call into the scheduler to |
||||
|
let it know that a system call is running. |
||||
|
|
||||
|
When porting Go to an new architecture/OS, this file must be implemented for |
||||
|
each GOOS/GOARCH pair. |
||||
|
|
||||
|
### mksysnum |
||||
|
|
||||
|
Mksysnum is a script located at `${GOOS}/mksysnum.pl` (or `mksysnum_${GOOS}.pl` |
||||
|
for the old system). This script takes in a list of header files containing the |
||||
|
syscall number declarations and parses them to produce the corresponding list of |
||||
|
Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated |
||||
|
constants. |
||||
|
|
||||
|
Adding new syscall numbers is mostly done by running the build on a sufficiently |
||||
|
new installation of the target OS (or updating the source checkouts for the |
||||
|
new build system). However, depending on the OS, you make need to update the |
||||
|
parsing in mksysnum. |
||||
|
|
||||
|
### mksyscall.pl |
||||
|
|
||||
|
The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are |
||||
|
hand-written Go files which implement system calls (for unix, the specific OS, |
||||
|
or the specific OS/Architecture pair respectively) that need special handling |
||||
|
and list `//sys` comments giving prototypes for ones that can be generated. |
||||
|
|
||||
|
The mksyscall.pl script takes the `//sys` and `//sysnb` comments and converts |
||||
|
them into syscalls. This requires the name of the prototype in the comment to |
||||
|
match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function |
||||
|
prototype can be exported (capitalized) or not. |
||||
|
|
||||
|
Adding a new syscall often just requires adding a new `//sys` function prototype |
||||
|
with the desired arguments and a capitalized name so it is exported. However, if |
||||
|
you want the interface to the syscall to be different, often one will make an |
||||
|
unexported `//sys` prototype, an then write a custom wrapper in |
||||
|
`syscall_${GOOS}.go`. |
||||
|
|
||||
|
### types files |
||||
|
|
||||
|
For each OS, there is a hand-written Go file at `${GOOS}/types.go` (or |
||||
|
`types_${GOOS}.go` on the old system). This file includes standard C headers and |
||||
|
creates Go type aliases to the corresponding C types. The file is then fed |
||||
|
through godef to get the Go compatible definitions. Finally, the generated code |
||||
|
is fed though mkpost.go to format the code correctly and remove any hidden or |
||||
|
private identifiers. This cleaned-up code is written to |
||||
|
`ztypes_${GOOS}_${GOARCH}.go`. |
||||
|
|
||||
|
The hardest part about preparing this file is figuring out which headers to |
||||
|
include and which symbols need to be `#define`d to get the actual data |
||||
|
structures that pass through to the kernel system calls. Some C libraries |
||||
|
preset alternate versions for binary compatibility and translate them on the |
||||
|
way in and out of system calls, but there is almost always a `#define` that can |
||||
|
get the real ones. |
||||
|
See `types_darwin.go` and `linux/types.go` for examples. |
||||
|
|
||||
|
To add a new type, add in the necessary include statement at the top of the |
||||
|
file (if it is not already there) and add in a type alias line. Note that if |
||||
|
your type is significantly different on different architectures, you may need |
||||
|
some `#if/#elif` macros in your include statements. |
||||
|
|
||||
|
### mkerrors.sh |
||||
|
|
||||
|
This script is used to generate the system's various constants. This doesn't |
||||
|
just include the error numbers and error strings, but also the signal numbers |
||||
|
an a wide variety of miscellaneous constants. The constants come from the list |
||||
|
of include files in the `includes_${uname}` variable. A regex then picks out |
||||
|
the desired `#define` statements, and generates the corresponding Go constants. |
||||
|
The error numbers and strings are generated from `#include <errno.h>`, and the |
||||
|
signal numbers and strings are generated from `#include <signal.h>`. All of |
||||
|
these constants are written to `zerrors_${GOOS}_${GOARCH}.go` via a C program, |
||||
|
`_errors.c`, which prints out all the constants. |
||||
|
|
||||
|
To add a constant, add the header that includes it to the appropriate variable. |
||||
|
Then, edit the regex (if necessary) to match the desired constant. Avoid making |
||||
|
the regex too broad to avoid matching unintended constants. |
||||
|
|
||||
|
|
||||
|
## Generated files |
||||
|
|
||||
|
### `zerror_${GOOS}_${GOARCH}.go` |
||||
|
|
||||
|
A file containing all of the system's generated error numbers, error strings, |
||||
|
signal numbers, and constants. Generated by `mkerrors.sh` (see above). |
||||
|
|
||||
|
### `zsyscall_${GOOS}_${GOARCH}.go` |
||||
|
|
||||
|
A file containing all the generated syscalls for a specific GOOS and GOARCH. |
||||
|
Generated by `mksyscall.pl` (see above). |
||||
|
|
||||
|
### `zsysnum_${GOOS}_${GOARCH}.go` |
||||
|
|
||||
|
A list of numeric constants for all the syscall number of the specific GOOS |
||||
|
and GOARCH. Generated by mksysnum (see above). |
||||
|
|
||||
|
### `ztypes_${GOOS}_${GOARCH}.go` |
||||
|
|
||||
|
A file containing Go types for passing into (or returning from) syscalls. |
||||
|
Generated by godefs and the types file (see above). |
@ -0,0 +1,124 @@ |
|||||
|
// 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.
|
||||
|
|
||||
|
// CPU affinity functions
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import ( |
||||
|
"unsafe" |
||||
|
) |
||||
|
|
||||
|
const cpuSetSize = _CPU_SETSIZE / _NCPUBITS |
||||
|
|
||||
|
// CPUSet represents a CPU affinity mask.
|
||||
|
type CPUSet [cpuSetSize]cpuMask |
||||
|
|
||||
|
func schedAffinity(trap uintptr, pid int, set *CPUSet) error { |
||||
|
_, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set))) |
||||
|
if e != 0 { |
||||
|
return errnoErr(e) |
||||
|
} |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
|
||||
|
// If pid is 0 the calling thread is used.
|
||||
|
func SchedGetaffinity(pid int, set *CPUSet) error { |
||||
|
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set) |
||||
|
} |
||||
|
|
||||
|
// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
|
||||
|
// If pid is 0 the calling thread is used.
|
||||
|
func SchedSetaffinity(pid int, set *CPUSet) error { |
||||
|
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set) |
||||
|
} |
||||
|
|
||||
|
// Zero clears the set s, so that it contains no CPUs.
|
||||
|
func (s *CPUSet) Zero() { |
||||
|
for i := range s { |
||||
|
s[i] = 0 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func cpuBitsIndex(cpu int) int { |
||||
|
return cpu / _NCPUBITS |
||||
|
} |
||||
|
|
||||
|
func cpuBitsMask(cpu int) cpuMask { |
||||
|
return cpuMask(1 << (uint(cpu) % _NCPUBITS)) |
||||
|
} |
||||
|
|
||||
|
// Set adds cpu to the set s.
|
||||
|
func (s *CPUSet) Set(cpu int) { |
||||
|
i := cpuBitsIndex(cpu) |
||||
|
if i < len(s) { |
||||
|
s[i] |= cpuBitsMask(cpu) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Clear removes cpu from the set s.
|
||||
|
func (s *CPUSet) Clear(cpu int) { |
||||
|
i := cpuBitsIndex(cpu) |
||||
|
if i < len(s) { |
||||
|
s[i] &^= cpuBitsMask(cpu) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// IsSet reports whether cpu is in the set s.
|
||||
|
func (s *CPUSet) IsSet(cpu int) bool { |
||||
|
i := cpuBitsIndex(cpu) |
||||
|
if i < len(s) { |
||||
|
return s[i]&cpuBitsMask(cpu) != 0 |
||||
|
} |
||||
|
return false |
||||
|
} |
||||
|
|
||||
|
// Count returns the number of CPUs in the set s.
|
||||
|
func (s *CPUSet) Count() int { |
||||
|
c := 0 |
||||
|
for _, b := range s { |
||||
|
c += onesCount64(uint64(b)) |
||||
|
} |
||||
|
return c |
||||
|
} |
||||
|
|
||||
|
// onesCount64 is a copy of Go 1.9's math/bits.OnesCount64.
|
||||
|
// Once this package can require Go 1.9, we can delete this
|
||||
|
// and update the caller to use bits.OnesCount64.
|
||||
|
func onesCount64(x uint64) int { |
||||
|
const m0 = 0x5555555555555555 // 01010101 ...
|
||||
|
const m1 = 0x3333333333333333 // 00110011 ...
|
||||
|
const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
|
||||
|
const m3 = 0x00ff00ff00ff00ff // etc.
|
||||
|
const m4 = 0x0000ffff0000ffff |
||||
|
|
||||
|
// Implementation: Parallel summing of adjacent bits.
|
||||
|
// See "Hacker's Delight", Chap. 5: Counting Bits.
|
||||
|
// The following pattern shows the general approach:
|
||||
|
//
|
||||
|
// x = x>>1&(m0&m) + x&(m0&m)
|
||||
|
// x = x>>2&(m1&m) + x&(m1&m)
|
||||
|
// x = x>>4&(m2&m) + x&(m2&m)
|
||||
|
// x = x>>8&(m3&m) + x&(m3&m)
|
||||
|
// x = x>>16&(m4&m) + x&(m4&m)
|
||||
|
// x = x>>32&(m5&m) + x&(m5&m)
|
||||
|
// return int(x)
|
||||
|
//
|
||||
|
// Masking (& operations) can be left away when there's no
|
||||
|
// danger that a field's sum will carry over into the next
|
||||
|
// field: Since the result cannot be > 64, 8 bits is enough
|
||||
|
// and we can ignore the masks for the shifts by 8 and up.
|
||||
|
// Per "Hacker's Delight", the first line can be simplified
|
||||
|
// more, but it saves at best one instruction, so we leave
|
||||
|
// it alone for clarity.
|
||||
|
const m = 1<<64 - 1 |
||||
|
x = x>>1&(m0&m) + x&(m0&m) |
||||
|
x = x>>2&(m1&m) + x&(m1&m) |
||||
|
x = (x>>4 + x) & (m2 & m) |
||||
|
x += x >> 8 |
||||
|
x += x >> 16 |
||||
|
x += x >> 32 |
||||
|
return int(x) & (1<<7 - 1) |
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
// 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for 386, Darwin |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-52 |
||||
|
JMP syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||
|
JMP syscall·RawSyscall6(SB) |
@ -0,0 +1,29 @@ |
|||||
|
// 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for AMD64, Darwin |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-104 |
||||
|
JMP syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·RawSyscall6(SB) |
@ -0,0 +1,30 @@ |
|||||
|
// 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 !gccgo |
||||
|
// +build arm,darwin |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for ARM, Darwin |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-28 |
||||
|
B syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40 |
||||
|
B syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-52 |
||||
|
B syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||
|
B syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||
|
B syscall·RawSyscall6(SB) |
@ -0,0 +1,30 @@ |
|||||
|
// 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 !gccgo |
||||
|
// +build arm64,darwin |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for AMD64, Darwin |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
||||
|
B syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
||||
|
B syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-104 |
||||
|
B syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
||||
|
B syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
||||
|
B syscall·RawSyscall6(SB) |
@ -0,0 +1,29 @@ |
|||||
|
// 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for AMD64, DragonFly |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-104 |
||||
|
JMP syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·RawSyscall6(SB) |
@ -0,0 +1,29 @@ |
|||||
|
// 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for 386, FreeBSD |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-52 |
||||
|
JMP syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||
|
JMP syscall·RawSyscall6(SB) |
@ -0,0 +1,29 @@ |
|||||
|
// 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for AMD64, FreeBSD |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-104 |
||||
|
JMP syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·RawSyscall6(SB) |
@ -0,0 +1,29 @@ |
|||||
|
// Copyright 2012 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for ARM, FreeBSD |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-28 |
||||
|
B syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40 |
||||
|
B syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-52 |
||||
|
B syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||
|
B syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||
|
B syscall·RawSyscall6(SB) |
@ -0,0 +1,65 @@ |
|||||
|
// 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System calls for 386, Linux |
||||
|
// |
||||
|
|
||||
|
// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80 |
||||
|
// instead of the glibc-specific "CALL 0x10(GS)". |
||||
|
#define INVOKE_SYSCALL INT $0x80 |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24 |
||||
|
CALL runtime·entersyscall(SB) |
||||
|
MOVL trap+0(FP), AX // syscall entry |
||||
|
MOVL a1+4(FP), BX |
||||
|
MOVL a2+8(FP), CX |
||||
|
MOVL a3+12(FP), DX |
||||
|
MOVL $0, SI |
||||
|
MOVL $0, DI |
||||
|
INVOKE_SYSCALL |
||||
|
MOVL AX, r1+16(FP) |
||||
|
MOVL DX, r2+20(FP) |
||||
|
CALL runtime·exitsyscall(SB) |
||||
|
RET |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||
|
JMP syscall·RawSyscall6(SB) |
||||
|
|
||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24 |
||||
|
MOVL trap+0(FP), AX // syscall entry |
||||
|
MOVL a1+4(FP), BX |
||||
|
MOVL a2+8(FP), CX |
||||
|
MOVL a3+12(FP), DX |
||||
|
MOVL $0, SI |
||||
|
MOVL $0, DI |
||||
|
INVOKE_SYSCALL |
||||
|
MOVL AX, r1+16(FP) |
||||
|
MOVL DX, r2+20(FP) |
||||
|
RET |
||||
|
|
||||
|
TEXT ·socketcall(SB),NOSPLIT,$0-36 |
||||
|
JMP syscall·socketcall(SB) |
||||
|
|
||||
|
TEXT ·rawsocketcall(SB),NOSPLIT,$0-36 |
||||
|
JMP syscall·rawsocketcall(SB) |
||||
|
|
||||
|
TEXT ·seek(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·seek(SB) |
@ -0,0 +1,57 @@ |
|||||
|
// 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System calls for AMD64, Linux |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48 |
||||
|
CALL runtime·entersyscall(SB) |
||||
|
MOVQ a1+8(FP), DI |
||||
|
MOVQ a2+16(FP), SI |
||||
|
MOVQ a3+24(FP), DX |
||||
|
MOVQ $0, R10 |
||||
|
MOVQ $0, R8 |
||||
|
MOVQ $0, R9 |
||||
|
MOVQ trap+0(FP), AX // syscall entry |
||||
|
SYSCALL |
||||
|
MOVQ AX, r1+32(FP) |
||||
|
MOVQ DX, r2+40(FP) |
||||
|
CALL runtime·exitsyscall(SB) |
||||
|
RET |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·RawSyscall6(SB) |
||||
|
|
||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48 |
||||
|
MOVQ a1+8(FP), DI |
||||
|
MOVQ a2+16(FP), SI |
||||
|
MOVQ a3+24(FP), DX |
||||
|
MOVQ $0, R10 |
||||
|
MOVQ $0, R8 |
||||
|
MOVQ $0, R9 |
||||
|
MOVQ trap+0(FP), AX // syscall entry |
||||
|
SYSCALL |
||||
|
MOVQ AX, r1+32(FP) |
||||
|
MOVQ DX, r2+40(FP) |
||||
|
RET |
||||
|
|
||||
|
TEXT ·gettimeofday(SB),NOSPLIT,$0-16 |
||||
|
JMP syscall·gettimeofday(SB) |
@ -0,0 +1,56 @@ |
|||||
|
// 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System calls for arm, Linux |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-28 |
||||
|
B syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40 |
||||
|
B syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24 |
||||
|
BL runtime·entersyscall(SB) |
||||
|
MOVW trap+0(FP), R7 |
||||
|
MOVW a1+4(FP), R0 |
||||
|
MOVW a2+8(FP), R1 |
||||
|
MOVW a3+12(FP), R2 |
||||
|
MOVW $0, R3 |
||||
|
MOVW $0, R4 |
||||
|
MOVW $0, R5 |
||||
|
SWI $0 |
||||
|
MOVW R0, r1+16(FP) |
||||
|
MOVW $0, R0 |
||||
|
MOVW R0, r2+20(FP) |
||||
|
BL runtime·exitsyscall(SB) |
||||
|
RET |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||
|
B syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||
|
B syscall·RawSyscall6(SB) |
||||
|
|
||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24 |
||||
|
MOVW trap+0(FP), R7 // syscall entry |
||||
|
MOVW a1+4(FP), R0 |
||||
|
MOVW a2+8(FP), R1 |
||||
|
MOVW a3+12(FP), R2 |
||||
|
SWI $0 |
||||
|
MOVW R0, r1+16(FP) |
||||
|
MOVW $0, R0 |
||||
|
MOVW R0, r2+20(FP) |
||||
|
RET |
||||
|
|
||||
|
TEXT ·seek(SB),NOSPLIT,$0-28 |
||||
|
B syscall·seek(SB) |
@ -0,0 +1,52 @@ |
|||||
|
// 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 linux |
||||
|
// +build arm64 |
||||
|
// +build !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
||||
|
B syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
||||
|
B syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48 |
||||
|
BL runtime·entersyscall(SB) |
||||
|
MOVD a1+8(FP), R0 |
||||
|
MOVD a2+16(FP), R1 |
||||
|
MOVD a3+24(FP), R2 |
||||
|
MOVD $0, R3 |
||||
|
MOVD $0, R4 |
||||
|
MOVD $0, R5 |
||||
|
MOVD trap+0(FP), R8 // syscall entry |
||||
|
SVC |
||||
|
MOVD R0, r1+32(FP) // r1 |
||||
|
MOVD R1, r2+40(FP) // r2 |
||||
|
BL runtime·exitsyscall(SB) |
||||
|
RET |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
||||
|
B syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
||||
|
B syscall·RawSyscall6(SB) |
||||
|
|
||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48 |
||||
|
MOVD a1+8(FP), R0 |
||||
|
MOVD a2+16(FP), R1 |
||||
|
MOVD a3+24(FP), R2 |
||||
|
MOVD $0, R3 |
||||
|
MOVD $0, R4 |
||||
|
MOVD $0, R5 |
||||
|
MOVD trap+0(FP), R8 // syscall entry |
||||
|
SVC |
||||
|
MOVD R0, r1+32(FP) |
||||
|
MOVD R1, r2+40(FP) |
||||
|
RET |
@ -0,0 +1,56 @@ |
|||||
|
// 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 linux |
||||
|
// +build mips64 mips64le |
||||
|
// +build !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System calls for mips64, Linux |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48 |
||||
|
JAL runtime·entersyscall(SB) |
||||
|
MOVV a1+8(FP), R4 |
||||
|
MOVV a2+16(FP), R5 |
||||
|
MOVV a3+24(FP), R6 |
||||
|
MOVV R0, R7 |
||||
|
MOVV R0, R8 |
||||
|
MOVV R0, R9 |
||||
|
MOVV trap+0(FP), R2 // syscall entry |
||||
|
SYSCALL |
||||
|
MOVV R2, r1+32(FP) |
||||
|
MOVV R3, r2+40(FP) |
||||
|
JAL runtime·exitsyscall(SB) |
||||
|
RET |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·RawSyscall6(SB) |
||||
|
|
||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48 |
||||
|
MOVV a1+8(FP), R4 |
||||
|
MOVV a2+16(FP), R5 |
||||
|
MOVV a3+24(FP), R6 |
||||
|
MOVV R0, R7 |
||||
|
MOVV R0, R8 |
||||
|
MOVV R0, R9 |
||||
|
MOVV trap+0(FP), R2 // syscall entry |
||||
|
SYSCALL |
||||
|
MOVV R2, r1+32(FP) |
||||
|
MOVV R3, r2+40(FP) |
||||
|
RET |
@ -0,0 +1,54 @@ |
|||||
|
// 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 linux |
||||
|
// +build mips mipsle |
||||
|
// +build !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System calls for mips, Linux |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-52 |
||||
|
JMP syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24 |
||||
|
JAL runtime·entersyscall(SB) |
||||
|
MOVW a1+4(FP), R4 |
||||
|
MOVW a2+8(FP), R5 |
||||
|
MOVW a3+12(FP), R6 |
||||
|
MOVW R0, R7 |
||||
|
MOVW trap+0(FP), R2 // syscall entry |
||||
|
SYSCALL |
||||
|
MOVW R2, r1+16(FP) // r1 |
||||
|
MOVW R3, r2+20(FP) // r2 |
||||
|
JAL runtime·exitsyscall(SB) |
||||
|
RET |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||
|
JMP syscall·RawSyscall6(SB) |
||||
|
|
||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24 |
||||
|
MOVW a1+4(FP), R4 |
||||
|
MOVW a2+8(FP), R5 |
||||
|
MOVW a3+12(FP), R6 |
||||
|
MOVW trap+0(FP), R2 // syscall entry |
||||
|
SYSCALL |
||||
|
MOVW R2, r1+16(FP) |
||||
|
MOVW R3, r2+20(FP) |
||||
|
RET |
@ -0,0 +1,56 @@ |
|||||
|
// Copyright 2014 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 linux |
||||
|
// +build ppc64 ppc64le |
||||
|
// +build !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System calls for ppc64, Linux |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
||||
|
BR syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
||||
|
BR syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48 |
||||
|
BL runtime·entersyscall(SB) |
||||
|
MOVD a1+8(FP), R3 |
||||
|
MOVD a2+16(FP), R4 |
||||
|
MOVD a3+24(FP), R5 |
||||
|
MOVD R0, R6 |
||||
|
MOVD R0, R7 |
||||
|
MOVD R0, R8 |
||||
|
MOVD trap+0(FP), R9 // syscall entry |
||||
|
SYSCALL R9 |
||||
|
MOVD R3, r1+32(FP) |
||||
|
MOVD R4, r2+40(FP) |
||||
|
BL runtime·exitsyscall(SB) |
||||
|
RET |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
||||
|
BR syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
||||
|
BR syscall·RawSyscall6(SB) |
||||
|
|
||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48 |
||||
|
MOVD a1+8(FP), R3 |
||||
|
MOVD a2+16(FP), R4 |
||||
|
MOVD a3+24(FP), R5 |
||||
|
MOVD R0, R6 |
||||
|
MOVD R0, R7 |
||||
|
MOVD R0, R8 |
||||
|
MOVD trap+0(FP), R9 // syscall entry |
||||
|
SYSCALL R9 |
||||
|
MOVD R3, r1+32(FP) |
||||
|
MOVD R4, r2+40(FP) |
||||
|
RET |
@ -0,0 +1,56 @@ |
|||||
|
// 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 s390x |
||||
|
// +build linux |
||||
|
// +build !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System calls for s390x, Linux |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
||||
|
BR syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
||||
|
BR syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48 |
||||
|
BL runtime·entersyscall(SB) |
||||
|
MOVD a1+8(FP), R2 |
||||
|
MOVD a2+16(FP), R3 |
||||
|
MOVD a3+24(FP), R4 |
||||
|
MOVD $0, R5 |
||||
|
MOVD $0, R6 |
||||
|
MOVD $0, R7 |
||||
|
MOVD trap+0(FP), R1 // syscall entry |
||||
|
SYSCALL |
||||
|
MOVD R2, r1+32(FP) |
||||
|
MOVD R3, r2+40(FP) |
||||
|
BL runtime·exitsyscall(SB) |
||||
|
RET |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
||||
|
BR syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
||||
|
BR syscall·RawSyscall6(SB) |
||||
|
|
||||
|
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48 |
||||
|
MOVD a1+8(FP), R2 |
||||
|
MOVD a2+16(FP), R3 |
||||
|
MOVD a3+24(FP), R4 |
||||
|
MOVD $0, R5 |
||||
|
MOVD $0, R6 |
||||
|
MOVD $0, R7 |
||||
|
MOVD trap+0(FP), R1 // syscall entry |
||||
|
SYSCALL |
||||
|
MOVD R2, r1+32(FP) |
||||
|
MOVD R3, r2+40(FP) |
||||
|
RET |
@ -0,0 +1,29 @@ |
|||||
|
// 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for 386, NetBSD |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-52 |
||||
|
JMP syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||
|
JMP syscall·RawSyscall6(SB) |
@ -0,0 +1,29 @@ |
|||||
|
// 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for AMD64, NetBSD |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-104 |
||||
|
JMP syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·RawSyscall6(SB) |
@ -0,0 +1,29 @@ |
|||||
|
// Copyright 2013 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for ARM, NetBSD |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-28 |
||||
|
B syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40 |
||||
|
B syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-52 |
||||
|
B syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||
|
B syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||
|
B syscall·RawSyscall6(SB) |
@ -0,0 +1,29 @@ |
|||||
|
// 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for 386, OpenBSD |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-52 |
||||
|
JMP syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||
|
JMP syscall·RawSyscall6(SB) |
@ -0,0 +1,29 @@ |
|||||
|
// 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for AMD64, OpenBSD |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-104 |
||||
|
JMP syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
||||
|
JMP syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
||||
|
JMP syscall·RawSyscall6(SB) |
@ -0,0 +1,29 @@ |
|||||
|
// Copyright 2017 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System call support for ARM, OpenBSD |
||||
|
// |
||||
|
|
||||
|
// Just jump to package syscall's implementation for all these functions. |
||||
|
// The runtime may know about them. |
||||
|
|
||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-28 |
||||
|
B syscall·Syscall(SB) |
||||
|
|
||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-40 |
||||
|
B syscall·Syscall6(SB) |
||||
|
|
||||
|
TEXT ·Syscall9(SB),NOSPLIT,$0-52 |
||||
|
B syscall·Syscall9(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||
|
B syscall·RawSyscall(SB) |
||||
|
|
||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||
|
B syscall·RawSyscall6(SB) |
@ -0,0 +1,17 @@ |
|||||
|
// Copyright 2014 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 !gccgo |
||||
|
|
||||
|
#include "textflag.h" |
||||
|
|
||||
|
// |
||||
|
// System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go |
||||
|
// |
||||
|
|
||||
|
TEXT ·sysvicall6(SB),NOSPLIT,$0-88 |
||||
|
JMP syscall·sysvicall6(SB) |
||||
|
|
||||
|
TEXT ·rawSysvicall6(SB),NOSPLIT,$0-88 |
||||
|
JMP syscall·rawSysvicall6(SB) |
@ -0,0 +1,35 @@ |
|||||
|
// 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.
|
||||
|
|
||||
|
// Bluetooth sockets and messages
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
// Bluetooth Protocols
|
||||
|
const ( |
||||
|
BTPROTO_L2CAP = 0 |
||||
|
BTPROTO_HCI = 1 |
||||
|
BTPROTO_SCO = 2 |
||||
|
BTPROTO_RFCOMM = 3 |
||||
|
BTPROTO_BNEP = 4 |
||||
|
BTPROTO_CMTP = 5 |
||||
|
BTPROTO_HIDP = 6 |
||||
|
BTPROTO_AVDTP = 7 |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
HCI_CHANNEL_RAW = 0 |
||||
|
HCI_CHANNEL_USER = 1 |
||||
|
HCI_CHANNEL_MONITOR = 2 |
||||
|
HCI_CHANNEL_CONTROL = 3 |
||||
|
) |
||||
|
|
||||
|
// Socketoption Level
|
||||
|
const ( |
||||
|
SOL_BLUETOOTH = 0x112 |
||||
|
SOL_HCI = 0x0 |
||||
|
SOL_L2CAP = 0x6 |
||||
|
SOL_RFCOMM = 0x12 |
||||
|
SOL_SCO = 0x11 |
||||
|
) |
@ -0,0 +1,195 @@ |
|||||
|
// Copyright 2017 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 freebsd
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import ( |
||||
|
"errors" |
||||
|
"fmt" |
||||
|
) |
||||
|
|
||||
|
// Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c
|
||||
|
|
||||
|
const ( |
||||
|
// This is the version of CapRights this package understands. See C implementation for parallels.
|
||||
|
capRightsGoVersion = CAP_RIGHTS_VERSION_00 |
||||
|
capArSizeMin = CAP_RIGHTS_VERSION_00 + 2 |
||||
|
capArSizeMax = capRightsGoVersion + 2 |
||||
|
) |
||||
|
|
||||
|
var ( |
||||
|
bit2idx = []int{ |
||||
|
-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, |
||||
|
4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
func capidxbit(right uint64) int { |
||||
|
return int((right >> 57) & 0x1f) |
||||
|
} |
||||
|
|
||||
|
func rightToIndex(right uint64) (int, error) { |
||||
|
idx := capidxbit(right) |
||||
|
if idx < 0 || idx >= len(bit2idx) { |
||||
|
return -2, fmt.Errorf("index for right 0x%x out of range", right) |
||||
|
} |
||||
|
return bit2idx[idx], nil |
||||
|
} |
||||
|
|
||||
|
func caprver(right uint64) int { |
||||
|
return int(right >> 62) |
||||
|
} |
||||
|
|
||||
|
func capver(rights *CapRights) int { |
||||
|
return caprver(rights.Rights[0]) |
||||
|
} |
||||
|
|
||||
|
func caparsize(rights *CapRights) int { |
||||
|
return capver(rights) + 2 |
||||
|
} |
||||
|
|
||||
|
// CapRightsSet sets the permissions in setrights in rights.
|
||||
|
func CapRightsSet(rights *CapRights, setrights []uint64) error { |
||||
|
// This is essentially a copy of cap_rights_vset()
|
||||
|
if capver(rights) != CAP_RIGHTS_VERSION_00 { |
||||
|
return fmt.Errorf("bad rights version %d", capver(rights)) |
||||
|
} |
||||
|
|
||||
|
n := caparsize(rights) |
||||
|
if n < capArSizeMin || n > capArSizeMax { |
||||
|
return errors.New("bad rights size") |
||||
|
} |
||||
|
|
||||
|
for _, right := range setrights { |
||||
|
if caprver(right) != CAP_RIGHTS_VERSION_00 { |
||||
|
return errors.New("bad right version") |
||||
|
} |
||||
|
i, err := rightToIndex(right) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
if i >= n { |
||||
|
return errors.New("index overflow") |
||||
|
} |
||||
|
if capidxbit(rights.Rights[i]) != capidxbit(right) { |
||||
|
return errors.New("index mismatch") |
||||
|
} |
||||
|
rights.Rights[i] |= right |
||||
|
if capidxbit(rights.Rights[i]) != capidxbit(right) { |
||||
|
return errors.New("index mismatch (after assign)") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
// CapRightsClear clears the permissions in clearrights from rights.
|
||||
|
func CapRightsClear(rights *CapRights, clearrights []uint64) error { |
||||
|
// This is essentially a copy of cap_rights_vclear()
|
||||
|
if capver(rights) != CAP_RIGHTS_VERSION_00 { |
||||
|
return fmt.Errorf("bad rights version %d", capver(rights)) |
||||
|
} |
||||
|
|
||||
|
n := caparsize(rights) |
||||
|
if n < capArSizeMin || n > capArSizeMax { |
||||
|
return errors.New("bad rights size") |
||||
|
} |
||||
|
|
||||
|
for _, right := range clearrights { |
||||
|
if caprver(right) != CAP_RIGHTS_VERSION_00 { |
||||
|
return errors.New("bad right version") |
||||
|
} |
||||
|
i, err := rightToIndex(right) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
if i >= n { |
||||
|
return errors.New("index overflow") |
||||
|
} |
||||
|
if capidxbit(rights.Rights[i]) != capidxbit(right) { |
||||
|
return errors.New("index mismatch") |
||||
|
} |
||||
|
rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF) |
||||
|
if capidxbit(rights.Rights[i]) != capidxbit(right) { |
||||
|
return errors.New("index mismatch (after assign)") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
// CapRightsIsSet checks whether all the permissions in setrights are present in rights.
|
||||
|
func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) { |
||||
|
// This is essentially a copy of cap_rights_is_vset()
|
||||
|
if capver(rights) != CAP_RIGHTS_VERSION_00 { |
||||
|
return false, fmt.Errorf("bad rights version %d", capver(rights)) |
||||
|
} |
||||
|
|
||||
|
n := caparsize(rights) |
||||
|
if n < capArSizeMin || n > capArSizeMax { |
||||
|
return false, errors.New("bad rights size") |
||||
|
} |
||||
|
|
||||
|
for _, right := range setrights { |
||||
|
if caprver(right) != CAP_RIGHTS_VERSION_00 { |
||||
|
return false, errors.New("bad right version") |
||||
|
} |
||||
|
i, err := rightToIndex(right) |
||||
|
if err != nil { |
||||
|
return false, err |
||||
|
} |
||||
|
if i >= n { |
||||
|
return false, errors.New("index overflow") |
||||
|
} |
||||
|
if capidxbit(rights.Rights[i]) != capidxbit(right) { |
||||
|
return false, errors.New("index mismatch") |
||||
|
} |
||||
|
if (rights.Rights[i] & right) != right { |
||||
|
return false, nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return true, nil |
||||
|
} |
||||
|
|
||||
|
func capright(idx uint64, bit uint64) uint64 { |
||||
|
return ((1 << (57 + idx)) | bit) |
||||
|
} |
||||
|
|
||||
|
// CapRightsInit returns a pointer to an initialised CapRights structure filled with rights.
|
||||
|
// See man cap_rights_init(3) and rights(4).
|
||||
|
func CapRightsInit(rights []uint64) (*CapRights, error) { |
||||
|
var r CapRights |
||||
|
r.Rights[0] = (capRightsGoVersion << 62) | capright(0, 0) |
||||
|
r.Rights[1] = capright(1, 0) |
||||
|
|
||||
|
err := CapRightsSet(&r, rights) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
return &r, nil |
||||
|
} |
||||
|
|
||||
|
// CapRightsLimit reduces the operations permitted on fd to at most those contained in rights.
|
||||
|
// The capability rights on fd can never be increased by CapRightsLimit.
|
||||
|
// See man cap_rights_limit(2) and rights(4).
|
||||
|
func CapRightsLimit(fd uintptr, rights *CapRights) error { |
||||
|
return capRightsLimit(int(fd), rights) |
||||
|
} |
||||
|
|
||||
|
// CapRightsGet returns a CapRights structure containing the operations permitted on fd.
|
||||
|
// See man cap_rights_get(3) and rights(4).
|
||||
|
func CapRightsGet(fd uintptr) (*CapRights, error) { |
||||
|
r, err := CapRightsInit(nil) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
err = capRightsGet(capRightsGoVersion, int(fd), r) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
return r, nil |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
// 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 darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
const ( |
||||
|
R_OK = 0x4 |
||||
|
W_OK = 0x2 |
||||
|
X_OK = 0x1 |
||||
|
) |
@ -0,0 +1,24 @@ |
|||||
|
// Copyright 2017 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.
|
||||
|
|
||||
|
// Functions to access/create device major and minor numbers matching the
|
||||
|
// encoding used in Darwin's sys/types.h header.
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
// Major returns the major component of a Darwin device number.
|
||||
|
func Major(dev uint64) uint32 { |
||||
|
return uint32((dev >> 24) & 0xff) |
||||
|
} |
||||
|
|
||||
|
// Minor returns the minor component of a Darwin device number.
|
||||
|
func Minor(dev uint64) uint32 { |
||||
|
return uint32(dev & 0xffffff) |
||||
|
} |
||||
|
|
||||
|
// Mkdev returns a Darwin device number generated from the given major and minor
|
||||
|
// components.
|
||||
|
func Mkdev(major, minor uint32) uint64 { |
||||
|
return (uint64(major) << 24) | uint64(minor) |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
// Copyright 2017 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.
|
||||
|
|
||||
|
// Functions to access/create device major and minor numbers matching the
|
||||
|
// encoding used in Dragonfly's sys/types.h header.
|
||||
|
//
|
||||
|
// The information below is extracted and adapted from sys/types.h:
|
||||
|
//
|
||||
|
// Minor gives a cookie instead of an index since in order to avoid changing the
|
||||
|
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
|
||||
|
// devices that don't use them.
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
// Major returns the major component of a DragonFlyBSD device number.
|
||||
|
func Major(dev uint64) uint32 { |
||||
|
return uint32((dev >> 8) & 0xff) |
||||
|
} |
||||
|
|
||||
|
// Minor returns the minor component of a DragonFlyBSD device number.
|
||||
|
func Minor(dev uint64) uint32 { |
||||
|
return uint32(dev & 0xffff00ff) |
||||
|
} |
||||
|
|
||||
|
// Mkdev returns a DragonFlyBSD device number generated from the given major and
|
||||
|
// minor components.
|
||||
|
func Mkdev(major, minor uint32) uint64 { |
||||
|
return (uint64(major) << 8) | uint64(minor) |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
// Copyright 2017 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.
|
||||
|
|
||||
|
// Functions to access/create device major and minor numbers matching the
|
||||
|
// encoding used in FreeBSD's sys/types.h header.
|
||||
|
//
|
||||
|
// The information below is extracted and adapted from sys/types.h:
|
||||
|
//
|
||||
|
// Minor gives a cookie instead of an index since in order to avoid changing the
|
||||
|
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
|
||||
|
// devices that don't use them.
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
// Major returns the major component of a FreeBSD device number.
|
||||
|
func Major(dev uint64) uint32 { |
||||
|
return uint32((dev >> 8) & 0xff) |
||||
|
} |
||||
|
|
||||
|
// Minor returns the minor component of a FreeBSD device number.
|
||||
|
func Minor(dev uint64) uint32 { |
||||
|
return uint32(dev & 0xffff00ff) |
||||
|
} |
||||
|
|
||||
|
// Mkdev returns a FreeBSD device number generated from the given major and
|
||||
|
// minor components.
|
||||
|
func Mkdev(major, minor uint32) uint64 { |
||||
|
return (uint64(major) << 8) | uint64(minor) |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
// Copyright 2017 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.
|
||||
|
|
||||
|
// Functions to access/create device major and minor numbers matching the
|
||||
|
// encoding used by the Linux kernel and glibc.
|
||||
|
//
|
||||
|
// The information below is extracted and adapted from bits/sysmacros.h in the
|
||||
|
// glibc sources:
|
||||
|
//
|
||||
|
// dev_t in glibc is 64-bit, with 32-bit major and minor numbers. glibc's
|
||||
|
// default encoding is MMMM Mmmm mmmM MMmm, where M is a hex digit of the major
|
||||
|
// number and m is a hex digit of the minor number. This is backward compatible
|
||||
|
// with legacy systems where dev_t is 16 bits wide, encoded as MMmm. It is also
|
||||
|
// backward compatible with the Linux kernel, which for some architectures uses
|
||||
|
// 32-bit dev_t, encoded as mmmM MMmm.
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
// Major returns the major component of a Linux device number.
|
||||
|
func Major(dev uint64) uint32 { |
||||
|
major := uint32((dev & 0x00000000000fff00) >> 8) |
||||
|
major |= uint32((dev & 0xfffff00000000000) >> 32) |
||||
|
return major |
||||
|
} |
||||
|
|
||||
|
// Minor returns the minor component of a Linux device number.
|
||||
|
func Minor(dev uint64) uint32 { |
||||
|
minor := uint32((dev & 0x00000000000000ff) >> 0) |
||||
|
minor |= uint32((dev & 0x00000ffffff00000) >> 12) |
||||
|
return minor |
||||
|
} |
||||
|
|
||||
|
// Mkdev returns a Linux device number generated from the given major and minor
|
||||
|
// components.
|
||||
|
func Mkdev(major, minor uint32) uint64 { |
||||
|
dev := (uint64(major) & 0x00000fff) << 8 |
||||
|
dev |= (uint64(major) & 0xfffff000) << 32 |
||||
|
dev |= (uint64(minor) & 0x000000ff) << 0 |
||||
|
dev |= (uint64(minor) & 0xffffff00) << 12 |
||||
|
return dev |
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
// Copyright 2017 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.
|
||||
|
|
||||
|
// Functions to access/create device major and minor numbers matching the
|
||||
|
// encoding used in NetBSD's sys/types.h header.
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
// Major returns the major component of a NetBSD device number.
|
||||
|
func Major(dev uint64) uint32 { |
||||
|
return uint32((dev & 0x000fff00) >> 8) |
||||
|
} |
||||
|
|
||||
|
// Minor returns the minor component of a NetBSD device number.
|
||||
|
func Minor(dev uint64) uint32 { |
||||
|
minor := uint32((dev & 0x000000ff) >> 0) |
||||
|
minor |= uint32((dev & 0xfff00000) >> 12) |
||||
|
return minor |
||||
|
} |
||||
|
|
||||
|
// Mkdev returns a NetBSD device number generated from the given major and minor
|
||||
|
// components.
|
||||
|
func Mkdev(major, minor uint32) uint64 { |
||||
|
dev := (uint64(major) << 8) & 0x000fff00 |
||||
|
dev |= (uint64(minor) << 12) & 0xfff00000 |
||||
|
dev |= (uint64(minor) << 0) & 0x000000ff |
||||
|
return dev |
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
// Copyright 2017 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.
|
||||
|
|
||||
|
// Functions to access/create device major and minor numbers matching the
|
||||
|
// encoding used in OpenBSD's sys/types.h header.
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
// Major returns the major component of an OpenBSD device number.
|
||||
|
func Major(dev uint64) uint32 { |
||||
|
return uint32((dev & 0x0000ff00) >> 8) |
||||
|
} |
||||
|
|
||||
|
// Minor returns the minor component of an OpenBSD device number.
|
||||
|
func Minor(dev uint64) uint32 { |
||||
|
minor := uint32((dev & 0x000000ff) >> 0) |
||||
|
minor |= uint32((dev & 0xffff0000) >> 8) |
||||
|
return minor |
||||
|
} |
||||
|
|
||||
|
// Mkdev returns an OpenBSD device number generated from the given major and minor
|
||||
|
// components.
|
||||
|
func Mkdev(major, minor uint32) uint64 { |
||||
|
dev := (uint64(major) << 8) & 0x0000ff00 |
||||
|
dev |= (uint64(minor) << 8) & 0xffff0000 |
||||
|
dev |= (uint64(minor) << 0) & 0x000000ff |
||||
|
return dev |
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
// 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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import "syscall" |
||||
|
|
||||
|
// ParseDirent parses up to max directory entries in buf,
|
||||
|
// appending the names to names. It returns the number of
|
||||
|
// bytes consumed from buf, the number of entries added
|
||||
|
// to names, and the new names slice.
|
||||
|
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) { |
||||
|
return syscall.ParseDirent(buf, max, names) |
||||
|
} |
@ -0,0 +1,9 @@ |
|||||
|
// 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 ppc64 s390x mips mips64
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
const isBigEndian = true |
@ -0,0 +1,9 @@ |
|||||
|
// 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 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
const isBigEndian = false |
@ -0,0 +1,31 @@ |
|||||
|
// Copyright 2010 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 darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
|
||||
|
// Unix environment variables.
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import "syscall" |
||||
|
|
||||
|
func Getenv(key string) (value string, found bool) { |
||||
|
return syscall.Getenv(key) |
||||
|
} |
||||
|
|
||||
|
func Setenv(key, value string) error { |
||||
|
return syscall.Setenv(key, value) |
||||
|
} |
||||
|
|
||||
|
func Clearenv() { |
||||
|
syscall.Clearenv() |
||||
|
} |
||||
|
|
||||
|
func Environ() []string { |
||||
|
return syscall.Environ() |
||||
|
} |
||||
|
|
||||
|
func Unsetenv(key string) error { |
||||
|
return syscall.Unsetenv(key) |
||||
|
} |
@ -0,0 +1,227 @@ |
|||||
|
// Copyright 2017 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.
|
||||
|
|
||||
|
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
|
||||
|
// them here for backwards compatibility.
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
const ( |
||||
|
IFF_SMART = 0x20 |
||||
|
IFT_1822 = 0x2 |
||||
|
IFT_A12MPPSWITCH = 0x82 |
||||
|
IFT_AAL2 = 0xbb |
||||
|
IFT_AAL5 = 0x31 |
||||
|
IFT_ADSL = 0x5e |
||||
|
IFT_AFLANE8023 = 0x3b |
||||
|
IFT_AFLANE8025 = 0x3c |
||||
|
IFT_ARAP = 0x58 |
||||
|
IFT_ARCNET = 0x23 |
||||
|
IFT_ARCNETPLUS = 0x24 |
||||
|
IFT_ASYNC = 0x54 |
||||
|
IFT_ATM = 0x25 |
||||
|
IFT_ATMDXI = 0x69 |
||||
|
IFT_ATMFUNI = 0x6a |
||||
|
IFT_ATMIMA = 0x6b |
||||
|
IFT_ATMLOGICAL = 0x50 |
||||
|
IFT_ATMRADIO = 0xbd |
||||
|
IFT_ATMSUBINTERFACE = 0x86 |
||||
|
IFT_ATMVCIENDPT = 0xc2 |
||||
|
IFT_ATMVIRTUAL = 0x95 |
||||
|
IFT_BGPPOLICYACCOUNTING = 0xa2 |
||||
|
IFT_BSC = 0x53 |
||||
|
IFT_CCTEMUL = 0x3d |
||||
|
IFT_CEPT = 0x13 |
||||
|
IFT_CES = 0x85 |
||||
|
IFT_CHANNEL = 0x46 |
||||
|
IFT_CNR = 0x55 |
||||
|
IFT_COFFEE = 0x84 |
||||
|
IFT_COMPOSITELINK = 0x9b |
||||
|
IFT_DCN = 0x8d |
||||
|
IFT_DIGITALPOWERLINE = 0x8a |
||||
|
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba |
||||
|
IFT_DLSW = 0x4a |
||||
|
IFT_DOCSCABLEDOWNSTREAM = 0x80 |
||||
|
IFT_DOCSCABLEMACLAYER = 0x7f |
||||
|
IFT_DOCSCABLEUPSTREAM = 0x81 |
||||
|
IFT_DS0 = 0x51 |
||||
|
IFT_DS0BUNDLE = 0x52 |
||||
|
IFT_DS1FDL = 0xaa |
||||
|
IFT_DS3 = 0x1e |
||||
|
IFT_DTM = 0x8c |
||||
|
IFT_DVBASILN = 0xac |
||||
|
IFT_DVBASIOUT = 0xad |
||||
|
IFT_DVBRCCDOWNSTREAM = 0x93 |
||||
|
IFT_DVBRCCMACLAYER = 0x92 |
||||
|
IFT_DVBRCCUPSTREAM = 0x94 |
||||
|
IFT_ENC = 0xf4 |
||||
|
IFT_EON = 0x19 |
||||
|
IFT_EPLRS = 0x57 |
||||
|
IFT_ESCON = 0x49 |
||||
|
IFT_ETHER = 0x6 |
||||
|
IFT_FAITH = 0xf2 |
||||
|
IFT_FAST = 0x7d |
||||
|
IFT_FASTETHER = 0x3e |
||||
|
IFT_FASTETHERFX = 0x45 |
||||
|
IFT_FDDI = 0xf |
||||
|
IFT_FIBRECHANNEL = 0x38 |
||||
|
IFT_FRAMERELAYINTERCONNECT = 0x3a |
||||
|
IFT_FRAMERELAYMPI = 0x5c |
||||
|
IFT_FRDLCIENDPT = 0xc1 |
||||
|
IFT_FRELAY = 0x20 |
||||
|
IFT_FRELAYDCE = 0x2c |
||||
|
IFT_FRF16MFRBUNDLE = 0xa3 |
||||
|
IFT_FRFORWARD = 0x9e |
||||
|
IFT_G703AT2MB = 0x43 |
||||
|
IFT_G703AT64K = 0x42 |
||||
|
IFT_GIF = 0xf0 |
||||
|
IFT_GIGABITETHERNET = 0x75 |
||||
|
IFT_GR303IDT = 0xb2 |
||||
|
IFT_GR303RDT = 0xb1 |
||||
|
IFT_H323GATEKEEPER = 0xa4 |
||||
|
IFT_H323PROXY = 0xa5 |
||||
|
IFT_HDH1822 = 0x3 |
||||
|
IFT_HDLC = 0x76 |
||||
|
IFT_HDSL2 = 0xa8 |
||||
|
IFT_HIPERLAN2 = 0xb7 |
||||
|
IFT_HIPPI = 0x2f |
||||
|
IFT_HIPPIINTERFACE = 0x39 |
||||
|
IFT_HOSTPAD = 0x5a |
||||
|
IFT_HSSI = 0x2e |
||||
|
IFT_HY = 0xe |
||||
|
IFT_IBM370PARCHAN = 0x48 |
||||
|
IFT_IDSL = 0x9a |
||||
|
IFT_IEEE80211 = 0x47 |
||||
|
IFT_IEEE80212 = 0x37 |
||||
|
IFT_IEEE8023ADLAG = 0xa1 |
||||
|
IFT_IFGSN = 0x91 |
||||
|
IFT_IMT = 0xbe |
||||
|
IFT_INTERLEAVE = 0x7c |
||||
|
IFT_IP = 0x7e |
||||
|
IFT_IPFORWARD = 0x8e |
||||
|
IFT_IPOVERATM = 0x72 |
||||
|
IFT_IPOVERCDLC = 0x6d |
||||
|
IFT_IPOVERCLAW = 0x6e |
||||
|
IFT_IPSWITCH = 0x4e |
||||
|
IFT_IPXIP = 0xf9 |
||||
|
IFT_ISDN = 0x3f |
||||
|
IFT_ISDNBASIC = 0x14 |
||||
|
IFT_ISDNPRIMARY = 0x15 |
||||
|
IFT_ISDNS = 0x4b |
||||
|
IFT_ISDNU = 0x4c |
||||
|
IFT_ISO88022LLC = 0x29 |
||||
|
IFT_ISO88023 = 0x7 |
||||
|
IFT_ISO88024 = 0x8 |
||||
|
IFT_ISO88025 = 0x9 |
||||
|
IFT_ISO88025CRFPINT = 0x62 |
||||
|
IFT_ISO88025DTR = 0x56 |
||||
|
IFT_ISO88025FIBER = 0x73 |
||||
|
IFT_ISO88026 = 0xa |
||||
|
IFT_ISUP = 0xb3 |
||||
|
IFT_L3IPXVLAN = 0x89 |
||||
|
IFT_LAPB = 0x10 |
||||
|
IFT_LAPD = 0x4d |
||||
|
IFT_LAPF = 0x77 |
||||
|
IFT_LOCALTALK = 0x2a |
||||
|
IFT_LOOP = 0x18 |
||||
|
IFT_MEDIAMAILOVERIP = 0x8b |
||||
|
IFT_MFSIGLINK = 0xa7 |
||||
|
IFT_MIOX25 = 0x26 |
||||
|
IFT_MODEM = 0x30 |
||||
|
IFT_MPC = 0x71 |
||||
|
IFT_MPLS = 0xa6 |
||||
|
IFT_MPLSTUNNEL = 0x96 |
||||
|
IFT_MSDSL = 0x8f |
||||
|
IFT_MVL = 0xbf |
||||
|
IFT_MYRINET = 0x63 |
||||
|
IFT_NFAS = 0xaf |
||||
|
IFT_NSIP = 0x1b |
||||
|
IFT_OPTICALCHANNEL = 0xc3 |
||||
|
IFT_OPTICALTRANSPORT = 0xc4 |
||||
|
IFT_OTHER = 0x1 |
||||
|
IFT_P10 = 0xc |
||||
|
IFT_P80 = 0xd |
||||
|
IFT_PARA = 0x22 |
||||
|
IFT_PFLOG = 0xf6 |
||||
|
IFT_PFSYNC = 0xf7 |
||||
|
IFT_PLC = 0xae |
||||
|
IFT_POS = 0xab |
||||
|
IFT_PPPMULTILINKBUNDLE = 0x6c |
||||
|
IFT_PROPBWAP2MP = 0xb8 |
||||
|
IFT_PROPCNLS = 0x59 |
||||
|
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5 |
||||
|
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4 |
||||
|
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6 |
||||
|
IFT_PROPMUX = 0x36 |
||||
|
IFT_PROPWIRELESSP2P = 0x9d |
||||
|
IFT_PTPSERIAL = 0x16 |
||||
|
IFT_PVC = 0xf1 |
||||
|
IFT_QLLC = 0x44 |
||||
|
IFT_RADIOMAC = 0xbc |
||||
|
IFT_RADSL = 0x5f |
||||
|
IFT_REACHDSL = 0xc0 |
||||
|
IFT_RFC1483 = 0x9f |
||||
|
IFT_RS232 = 0x21 |
||||
|
IFT_RSRB = 0x4f |
||||
|
IFT_SDLC = 0x11 |
||||
|
IFT_SDSL = 0x60 |
||||
|
IFT_SHDSL = 0xa9 |
||||
|
IFT_SIP = 0x1f |
||||
|
IFT_SLIP = 0x1c |
||||
|
IFT_SMDSDXI = 0x2b |
||||
|
IFT_SMDSICIP = 0x34 |
||||
|
IFT_SONET = 0x27 |
||||
|
IFT_SONETOVERHEADCHANNEL = 0xb9 |
||||
|
IFT_SONETPATH = 0x32 |
||||
|
IFT_SONETVT = 0x33 |
||||
|
IFT_SRP = 0x97 |
||||
|
IFT_SS7SIGLINK = 0x9c |
||||
|
IFT_STACKTOSTACK = 0x6f |
||||
|
IFT_STARLAN = 0xb |
||||
|
IFT_STF = 0xd7 |
||||
|
IFT_T1 = 0x12 |
||||
|
IFT_TDLC = 0x74 |
||||
|
IFT_TERMPAD = 0x5b |
||||
|
IFT_TR008 = 0xb0 |
||||
|
IFT_TRANSPHDLC = 0x7b |
||||
|
IFT_TUNNEL = 0x83 |
||||
|
IFT_ULTRA = 0x1d |
||||
|
IFT_USB = 0xa0 |
||||
|
IFT_V11 = 0x40 |
||||
|
IFT_V35 = 0x2d |
||||
|
IFT_V36 = 0x41 |
||||
|
IFT_V37 = 0x78 |
||||
|
IFT_VDSL = 0x61 |
||||
|
IFT_VIRTUALIPADDRESS = 0x70 |
||||
|
IFT_VOICEEM = 0x64 |
||||
|
IFT_VOICEENCAP = 0x67 |
||||
|
IFT_VOICEFXO = 0x65 |
||||
|
IFT_VOICEFXS = 0x66 |
||||
|
IFT_VOICEOVERATM = 0x98 |
||||
|
IFT_VOICEOVERFRAMERELAY = 0x99 |
||||
|
IFT_VOICEOVERIP = 0x68 |
||||
|
IFT_X213 = 0x5d |
||||
|
IFT_X25 = 0x5 |
||||
|
IFT_X25DDN = 0x4 |
||||
|
IFT_X25HUNTGROUP = 0x7a |
||||
|
IFT_X25MLP = 0x79 |
||||
|
IFT_X25PLE = 0x28 |
||||
|
IFT_XETHER = 0x1a |
||||
|
IPPROTO_MAXID = 0x34 |
||||
|
IPV6_FAITH = 0x1d |
||||
|
IP_FAITH = 0x16 |
||||
|
MAP_NORESERVE = 0x40 |
||||
|
MAP_RENAME = 0x20 |
||||
|
NET_RT_MAXID = 0x6 |
||||
|
RTF_PRCLONING = 0x10000 |
||||
|
RTM_OLDADD = 0x9 |
||||
|
RTM_OLDDEL = 0xa |
||||
|
SIOCADDRT = 0x8030720a |
||||
|
SIOCALIFADDR = 0x8118691b |
||||
|
SIOCDELRT = 0x8030720b |
||||
|
SIOCDLIFADDR = 0x8118691d |
||||
|
SIOCGLIFADDR = 0xc118691c |
||||
|
SIOCGLIFPHYADDR = 0xc118694b |
||||
|
SIOCSLIFPHYADDR = 0x8118694a |
||||
|
) |
@ -0,0 +1,227 @@ |
|||||
|
// Copyright 2017 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.
|
||||
|
|
||||
|
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
|
||||
|
// them here for backwards compatibility.
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
const ( |
||||
|
IFF_SMART = 0x20 |
||||
|
IFT_1822 = 0x2 |
||||
|
IFT_A12MPPSWITCH = 0x82 |
||||
|
IFT_AAL2 = 0xbb |
||||
|
IFT_AAL5 = 0x31 |
||||
|
IFT_ADSL = 0x5e |
||||
|
IFT_AFLANE8023 = 0x3b |
||||
|
IFT_AFLANE8025 = 0x3c |
||||
|
IFT_ARAP = 0x58 |
||||
|
IFT_ARCNET = 0x23 |
||||
|
IFT_ARCNETPLUS = 0x24 |
||||
|
IFT_ASYNC = 0x54 |
||||
|
IFT_ATM = 0x25 |
||||
|
IFT_ATMDXI = 0x69 |
||||
|
IFT_ATMFUNI = 0x6a |
||||
|
IFT_ATMIMA = 0x6b |
||||
|
IFT_ATMLOGICAL = 0x50 |
||||
|
IFT_ATMRADIO = 0xbd |
||||
|
IFT_ATMSUBINTERFACE = 0x86 |
||||
|
IFT_ATMVCIENDPT = 0xc2 |
||||
|
IFT_ATMVIRTUAL = 0x95 |
||||
|
IFT_BGPPOLICYACCOUNTING = 0xa2 |
||||
|
IFT_BSC = 0x53 |
||||
|
IFT_CCTEMUL = 0x3d |
||||
|
IFT_CEPT = 0x13 |
||||
|
IFT_CES = 0x85 |
||||
|
IFT_CHANNEL = 0x46 |
||||
|
IFT_CNR = 0x55 |
||||
|
IFT_COFFEE = 0x84 |
||||
|
IFT_COMPOSITELINK = 0x9b |
||||
|
IFT_DCN = 0x8d |
||||
|
IFT_DIGITALPOWERLINE = 0x8a |
||||
|
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba |
||||
|
IFT_DLSW = 0x4a |
||||
|
IFT_DOCSCABLEDOWNSTREAM = 0x80 |
||||
|
IFT_DOCSCABLEMACLAYER = 0x7f |
||||
|
IFT_DOCSCABLEUPSTREAM = 0x81 |
||||
|
IFT_DS0 = 0x51 |
||||
|
IFT_DS0BUNDLE = 0x52 |
||||
|
IFT_DS1FDL = 0xaa |
||||
|
IFT_DS3 = 0x1e |
||||
|
IFT_DTM = 0x8c |
||||
|
IFT_DVBASILN = 0xac |
||||
|
IFT_DVBASIOUT = 0xad |
||||
|
IFT_DVBRCCDOWNSTREAM = 0x93 |
||||
|
IFT_DVBRCCMACLAYER = 0x92 |
||||
|
IFT_DVBRCCUPSTREAM = 0x94 |
||||
|
IFT_ENC = 0xf4 |
||||
|
IFT_EON = 0x19 |
||||
|
IFT_EPLRS = 0x57 |
||||
|
IFT_ESCON = 0x49 |
||||
|
IFT_ETHER = 0x6 |
||||
|
IFT_FAITH = 0xf2 |
||||
|
IFT_FAST = 0x7d |
||||
|
IFT_FASTETHER = 0x3e |
||||
|
IFT_FASTETHERFX = 0x45 |
||||
|
IFT_FDDI = 0xf |
||||
|
IFT_FIBRECHANNEL = 0x38 |
||||
|
IFT_FRAMERELAYINTERCONNECT = 0x3a |
||||
|
IFT_FRAMERELAYMPI = 0x5c |
||||
|
IFT_FRDLCIENDPT = 0xc1 |
||||
|
IFT_FRELAY = 0x20 |
||||
|
IFT_FRELAYDCE = 0x2c |
||||
|
IFT_FRF16MFRBUNDLE = 0xa3 |
||||
|
IFT_FRFORWARD = 0x9e |
||||
|
IFT_G703AT2MB = 0x43 |
||||
|
IFT_G703AT64K = 0x42 |
||||
|
IFT_GIF = 0xf0 |
||||
|
IFT_GIGABITETHERNET = 0x75 |
||||
|
IFT_GR303IDT = 0xb2 |
||||
|
IFT_GR303RDT = 0xb1 |
||||
|
IFT_H323GATEKEEPER = 0xa4 |
||||
|
IFT_H323PROXY = 0xa5 |
||||
|
IFT_HDH1822 = 0x3 |
||||
|
IFT_HDLC = 0x76 |
||||
|
IFT_HDSL2 = 0xa8 |
||||
|
IFT_HIPERLAN2 = 0xb7 |
||||
|
IFT_HIPPI = 0x2f |
||||
|
IFT_HIPPIINTERFACE = 0x39 |
||||
|
IFT_HOSTPAD = 0x5a |
||||
|
IFT_HSSI = 0x2e |
||||
|
IFT_HY = 0xe |
||||
|
IFT_IBM370PARCHAN = 0x48 |
||||
|
IFT_IDSL = 0x9a |
||||
|
IFT_IEEE80211 = 0x47 |
||||
|
IFT_IEEE80212 = 0x37 |
||||
|
IFT_IEEE8023ADLAG = 0xa1 |
||||
|
IFT_IFGSN = 0x91 |
||||
|
IFT_IMT = 0xbe |
||||
|
IFT_INTERLEAVE = 0x7c |
||||
|
IFT_IP = 0x7e |
||||
|
IFT_IPFORWARD = 0x8e |
||||
|
IFT_IPOVERATM = 0x72 |
||||
|
IFT_IPOVERCDLC = 0x6d |
||||
|
IFT_IPOVERCLAW = 0x6e |
||||
|
IFT_IPSWITCH = 0x4e |
||||
|
IFT_IPXIP = 0xf9 |
||||
|
IFT_ISDN = 0x3f |
||||
|
IFT_ISDNBASIC = 0x14 |
||||
|
IFT_ISDNPRIMARY = 0x15 |
||||
|
IFT_ISDNS = 0x4b |
||||
|
IFT_ISDNU = 0x4c |
||||
|
IFT_ISO88022LLC = 0x29 |
||||
|
IFT_ISO88023 = 0x7 |
||||
|
IFT_ISO88024 = 0x8 |
||||
|
IFT_ISO88025 = 0x9 |
||||
|
IFT_ISO88025CRFPINT = 0x62 |
||||
|
IFT_ISO88025DTR = 0x56 |
||||
|
IFT_ISO88025FIBER = 0x73 |
||||
|
IFT_ISO88026 = 0xa |
||||
|
IFT_ISUP = 0xb3 |
||||
|
IFT_L3IPXVLAN = 0x89 |
||||
|
IFT_LAPB = 0x10 |
||||
|
IFT_LAPD = 0x4d |
||||
|
IFT_LAPF = 0x77 |
||||
|
IFT_LOCALTALK = 0x2a |
||||
|
IFT_LOOP = 0x18 |
||||
|
IFT_MEDIAMAILOVERIP = 0x8b |
||||
|
IFT_MFSIGLINK = 0xa7 |
||||
|
IFT_MIOX25 = 0x26 |
||||
|
IFT_MODEM = 0x30 |
||||
|
IFT_MPC = 0x71 |
||||
|
IFT_MPLS = 0xa6 |
||||
|
IFT_MPLSTUNNEL = 0x96 |
||||
|
IFT_MSDSL = 0x8f |
||||
|
IFT_MVL = 0xbf |
||||
|
IFT_MYRINET = 0x63 |
||||
|
IFT_NFAS = 0xaf |
||||
|
IFT_NSIP = 0x1b |
||||
|
IFT_OPTICALCHANNEL = 0xc3 |
||||
|
IFT_OPTICALTRANSPORT = 0xc4 |
||||
|
IFT_OTHER = 0x1 |
||||
|
IFT_P10 = 0xc |
||||
|
IFT_P80 = 0xd |
||||
|
IFT_PARA = 0x22 |
||||
|
IFT_PFLOG = 0xf6 |
||||
|
IFT_PFSYNC = 0xf7 |
||||
|
IFT_PLC = 0xae |
||||
|
IFT_POS = 0xab |
||||
|
IFT_PPPMULTILINKBUNDLE = 0x6c |
||||
|
IFT_PROPBWAP2MP = 0xb8 |
||||
|
IFT_PROPCNLS = 0x59 |
||||
|
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5 |
||||
|
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4 |
||||
|
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6 |
||||
|
IFT_PROPMUX = 0x36 |
||||
|
IFT_PROPWIRELESSP2P = 0x9d |
||||
|
IFT_PTPSERIAL = 0x16 |
||||
|
IFT_PVC = 0xf1 |
||||
|
IFT_QLLC = 0x44 |
||||
|
IFT_RADIOMAC = 0xbc |
||||
|
IFT_RADSL = 0x5f |
||||
|
IFT_REACHDSL = 0xc0 |
||||
|
IFT_RFC1483 = 0x9f |
||||
|
IFT_RS232 = 0x21 |
||||
|
IFT_RSRB = 0x4f |
||||
|
IFT_SDLC = 0x11 |
||||
|
IFT_SDSL = 0x60 |
||||
|
IFT_SHDSL = 0xa9 |
||||
|
IFT_SIP = 0x1f |
||||
|
IFT_SLIP = 0x1c |
||||
|
IFT_SMDSDXI = 0x2b |
||||
|
IFT_SMDSICIP = 0x34 |
||||
|
IFT_SONET = 0x27 |
||||
|
IFT_SONETOVERHEADCHANNEL = 0xb9 |
||||
|
IFT_SONETPATH = 0x32 |
||||
|
IFT_SONETVT = 0x33 |
||||
|
IFT_SRP = 0x97 |
||||
|
IFT_SS7SIGLINK = 0x9c |
||||
|
IFT_STACKTOSTACK = 0x6f |
||||
|
IFT_STARLAN = 0xb |
||||
|
IFT_STF = 0xd7 |
||||
|
IFT_T1 = 0x12 |
||||
|
IFT_TDLC = 0x74 |
||||
|
IFT_TERMPAD = 0x5b |
||||
|
IFT_TR008 = 0xb0 |
||||
|
IFT_TRANSPHDLC = 0x7b |
||||
|
IFT_TUNNEL = 0x83 |
||||
|
IFT_ULTRA = 0x1d |
||||
|
IFT_USB = 0xa0 |
||||
|
IFT_V11 = 0x40 |
||||
|
IFT_V35 = 0x2d |
||||
|
IFT_V36 = 0x41 |
||||
|
IFT_V37 = 0x78 |
||||
|
IFT_VDSL = 0x61 |
||||
|
IFT_VIRTUALIPADDRESS = 0x70 |
||||
|
IFT_VOICEEM = 0x64 |
||||
|
IFT_VOICEENCAP = 0x67 |
||||
|
IFT_VOICEFXO = 0x65 |
||||
|
IFT_VOICEFXS = 0x66 |
||||
|
IFT_VOICEOVERATM = 0x98 |
||||
|
IFT_VOICEOVERFRAMERELAY = 0x99 |
||||
|
IFT_VOICEOVERIP = 0x68 |
||||
|
IFT_X213 = 0x5d |
||||
|
IFT_X25 = 0x5 |
||||
|
IFT_X25DDN = 0x4 |
||||
|
IFT_X25HUNTGROUP = 0x7a |
||||
|
IFT_X25MLP = 0x79 |
||||
|
IFT_X25PLE = 0x28 |
||||
|
IFT_XETHER = 0x1a |
||||
|
IPPROTO_MAXID = 0x34 |
||||
|
IPV6_FAITH = 0x1d |
||||
|
IP_FAITH = 0x16 |
||||
|
MAP_NORESERVE = 0x40 |
||||
|
MAP_RENAME = 0x20 |
||||
|
NET_RT_MAXID = 0x6 |
||||
|
RTF_PRCLONING = 0x10000 |
||||
|
RTM_OLDADD = 0x9 |
||||
|
RTM_OLDDEL = 0xa |
||||
|
SIOCADDRT = 0x8040720a |
||||
|
SIOCALIFADDR = 0x8118691b |
||||
|
SIOCDELRT = 0x8040720b |
||||
|
SIOCDLIFADDR = 0x8118691d |
||||
|
SIOCGLIFADDR = 0xc118691c |
||||
|
SIOCGLIFPHYADDR = 0xc118694b |
||||
|
SIOCSLIFPHYADDR = 0x8118694a |
||||
|
) |
@ -0,0 +1,226 @@ |
|||||
|
// Copyright 2017 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 unix |
||||
|
|
||||
|
const ( |
||||
|
IFT_1822 = 0x2 |
||||
|
IFT_A12MPPSWITCH = 0x82 |
||||
|
IFT_AAL2 = 0xbb |
||||
|
IFT_AAL5 = 0x31 |
||||
|
IFT_ADSL = 0x5e |
||||
|
IFT_AFLANE8023 = 0x3b |
||||
|
IFT_AFLANE8025 = 0x3c |
||||
|
IFT_ARAP = 0x58 |
||||
|
IFT_ARCNET = 0x23 |
||||
|
IFT_ARCNETPLUS = 0x24 |
||||
|
IFT_ASYNC = 0x54 |
||||
|
IFT_ATM = 0x25 |
||||
|
IFT_ATMDXI = 0x69 |
||||
|
IFT_ATMFUNI = 0x6a |
||||
|
IFT_ATMIMA = 0x6b |
||||
|
IFT_ATMLOGICAL = 0x50 |
||||
|
IFT_ATMRADIO = 0xbd |
||||
|
IFT_ATMSUBINTERFACE = 0x86 |
||||
|
IFT_ATMVCIENDPT = 0xc2 |
||||
|
IFT_ATMVIRTUAL = 0x95 |
||||
|
IFT_BGPPOLICYACCOUNTING = 0xa2 |
||||
|
IFT_BSC = 0x53 |
||||
|
IFT_CCTEMUL = 0x3d |
||||
|
IFT_CEPT = 0x13 |
||||
|
IFT_CES = 0x85 |
||||
|
IFT_CHANNEL = 0x46 |
||||
|
IFT_CNR = 0x55 |
||||
|
IFT_COFFEE = 0x84 |
||||
|
IFT_COMPOSITELINK = 0x9b |
||||
|
IFT_DCN = 0x8d |
||||
|
IFT_DIGITALPOWERLINE = 0x8a |
||||
|
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba |
||||
|
IFT_DLSW = 0x4a |
||||
|
IFT_DOCSCABLEDOWNSTREAM = 0x80 |
||||
|
IFT_DOCSCABLEMACLAYER = 0x7f |
||||
|
IFT_DOCSCABLEUPSTREAM = 0x81 |
||||
|
IFT_DS0 = 0x51 |
||||
|
IFT_DS0BUNDLE = 0x52 |
||||
|
IFT_DS1FDL = 0xaa |
||||
|
IFT_DS3 = 0x1e |
||||
|
IFT_DTM = 0x8c |
||||
|
IFT_DVBASILN = 0xac |
||||
|
IFT_DVBASIOUT = 0xad |
||||
|
IFT_DVBRCCDOWNSTREAM = 0x93 |
||||
|
IFT_DVBRCCMACLAYER = 0x92 |
||||
|
IFT_DVBRCCUPSTREAM = 0x94 |
||||
|
IFT_ENC = 0xf4 |
||||
|
IFT_EON = 0x19 |
||||
|
IFT_EPLRS = 0x57 |
||||
|
IFT_ESCON = 0x49 |
||||
|
IFT_ETHER = 0x6 |
||||
|
IFT_FAST = 0x7d |
||||
|
IFT_FASTETHER = 0x3e |
||||
|
IFT_FASTETHERFX = 0x45 |
||||
|
IFT_FDDI = 0xf |
||||
|
IFT_FIBRECHANNEL = 0x38 |
||||
|
IFT_FRAMERELAYINTERCONNECT = 0x3a |
||||
|
IFT_FRAMERELAYMPI = 0x5c |
||||
|
IFT_FRDLCIENDPT = 0xc1 |
||||
|
IFT_FRELAY = 0x20 |
||||
|
IFT_FRELAYDCE = 0x2c |
||||
|
IFT_FRF16MFRBUNDLE = 0xa3 |
||||
|
IFT_FRFORWARD = 0x9e |
||||
|
IFT_G703AT2MB = 0x43 |
||||
|
IFT_G703AT64K = 0x42 |
||||
|
IFT_GIF = 0xf0 |
||||
|
IFT_GIGABITETHERNET = 0x75 |
||||
|
IFT_GR303IDT = 0xb2 |
||||
|
IFT_GR303RDT = 0xb1 |
||||
|
IFT_H323GATEKEEPER = 0xa4 |
||||
|
IFT_H323PROXY = 0xa5 |
||||
|
IFT_HDH1822 = 0x3 |
||||
|
IFT_HDLC = 0x76 |
||||
|
IFT_HDSL2 = 0xa8 |
||||
|
IFT_HIPERLAN2 = 0xb7 |
||||
|
IFT_HIPPI = 0x2f |
||||
|
IFT_HIPPIINTERFACE = 0x39 |
||||
|
IFT_HOSTPAD = 0x5a |
||||
|
IFT_HSSI = 0x2e |
||||
|
IFT_HY = 0xe |
||||
|
IFT_IBM370PARCHAN = 0x48 |
||||
|
IFT_IDSL = 0x9a |
||||
|
IFT_IEEE80211 = 0x47 |
||||
|
IFT_IEEE80212 = 0x37 |
||||
|
IFT_IEEE8023ADLAG = 0xa1 |
||||
|
IFT_IFGSN = 0x91 |
||||
|
IFT_IMT = 0xbe |
||||
|
IFT_INTERLEAVE = 0x7c |
||||
|
IFT_IP = 0x7e |
||||
|
IFT_IPFORWARD = 0x8e |
||||
|
IFT_IPOVERATM = 0x72 |
||||
|
IFT_IPOVERCDLC = 0x6d |
||||
|
IFT_IPOVERCLAW = 0x6e |
||||
|
IFT_IPSWITCH = 0x4e |
||||
|
IFT_ISDN = 0x3f |
||||
|
IFT_ISDNBASIC = 0x14 |
||||
|
IFT_ISDNPRIMARY = 0x15 |
||||
|
IFT_ISDNS = 0x4b |
||||
|
IFT_ISDNU = 0x4c |
||||
|
IFT_ISO88022LLC = 0x29 |
||||
|
IFT_ISO88023 = 0x7 |
||||
|
IFT_ISO88024 = 0x8 |
||||
|
IFT_ISO88025 = 0x9 |
||||
|
IFT_ISO88025CRFPINT = 0x62 |
||||
|
IFT_ISO88025DTR = 0x56 |
||||
|
IFT_ISO88025FIBER = 0x73 |
||||
|
IFT_ISO88026 = 0xa |
||||
|
IFT_ISUP = 0xb3 |
||||
|
IFT_L3IPXVLAN = 0x89 |
||||
|
IFT_LAPB = 0x10 |
||||
|
IFT_LAPD = 0x4d |
||||
|
IFT_LAPF = 0x77 |
||||
|
IFT_LOCALTALK = 0x2a |
||||
|
IFT_LOOP = 0x18 |
||||
|
IFT_MEDIAMAILOVERIP = 0x8b |
||||
|
IFT_MFSIGLINK = 0xa7 |
||||
|
IFT_MIOX25 = 0x26 |
||||
|
IFT_MODEM = 0x30 |
||||
|
IFT_MPC = 0x71 |
||||
|
IFT_MPLS = 0xa6 |
||||
|
IFT_MPLSTUNNEL = 0x96 |
||||
|
IFT_MSDSL = 0x8f |
||||
|
IFT_MVL = 0xbf |
||||
|
IFT_MYRINET = 0x63 |
||||
|
IFT_NFAS = 0xaf |
||||
|
IFT_NSIP = 0x1b |
||||
|
IFT_OPTICALCHANNEL = 0xc3 |
||||
|
IFT_OPTICALTRANSPORT = 0xc4 |
||||
|
IFT_OTHER = 0x1 |
||||
|
IFT_P10 = 0xc |
||||
|
IFT_P80 = 0xd |
||||
|
IFT_PARA = 0x22 |
||||
|
IFT_PFLOG = 0xf6 |
||||
|
IFT_PFSYNC = 0xf7 |
||||
|
IFT_PLC = 0xae |
||||
|
IFT_POS = 0xab |
||||
|
IFT_PPPMULTILINKBUNDLE = 0x6c |
||||
|
IFT_PROPBWAP2MP = 0xb8 |
||||
|
IFT_PROPCNLS = 0x59 |
||||
|
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5 |
||||
|
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4 |
||||
|
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6 |
||||
|
IFT_PROPMUX = 0x36 |
||||
|
IFT_PROPWIRELESSP2P = 0x9d |
||||
|
IFT_PTPSERIAL = 0x16 |
||||
|
IFT_PVC = 0xf1 |
||||
|
IFT_QLLC = 0x44 |
||||
|
IFT_RADIOMAC = 0xbc |
||||
|
IFT_RADSL = 0x5f |
||||
|
IFT_REACHDSL = 0xc0 |
||||
|
IFT_RFC1483 = 0x9f |
||||
|
IFT_RS232 = 0x21 |
||||
|
IFT_RSRB = 0x4f |
||||
|
IFT_SDLC = 0x11 |
||||
|
IFT_SDSL = 0x60 |
||||
|
IFT_SHDSL = 0xa9 |
||||
|
IFT_SIP = 0x1f |
||||
|
IFT_SLIP = 0x1c |
||||
|
IFT_SMDSDXI = 0x2b |
||||
|
IFT_SMDSICIP = 0x34 |
||||
|
IFT_SONET = 0x27 |
||||
|
IFT_SONETOVERHEADCHANNEL = 0xb9 |
||||
|
IFT_SONETPATH = 0x32 |
||||
|
IFT_SONETVT = 0x33 |
||||
|
IFT_SRP = 0x97 |
||||
|
IFT_SS7SIGLINK = 0x9c |
||||
|
IFT_STACKTOSTACK = 0x6f |
||||
|
IFT_STARLAN = 0xb |
||||
|
IFT_STF = 0xd7 |
||||
|
IFT_T1 = 0x12 |
||||
|
IFT_TDLC = 0x74 |
||||
|
IFT_TERMPAD = 0x5b |
||||
|
IFT_TR008 = 0xb0 |
||||
|
IFT_TRANSPHDLC = 0x7b |
||||
|
IFT_TUNNEL = 0x83 |
||||
|
IFT_ULTRA = 0x1d |
||||
|
IFT_USB = 0xa0 |
||||
|
IFT_V11 = 0x40 |
||||
|
IFT_V35 = 0x2d |
||||
|
IFT_V36 = 0x41 |
||||
|
IFT_V37 = 0x78 |
||||
|
IFT_VDSL = 0x61 |
||||
|
IFT_VIRTUALIPADDRESS = 0x70 |
||||
|
IFT_VOICEEM = 0x64 |
||||
|
IFT_VOICEENCAP = 0x67 |
||||
|
IFT_VOICEFXO = 0x65 |
||||
|
IFT_VOICEFXS = 0x66 |
||||
|
IFT_VOICEOVERATM = 0x98 |
||||
|
IFT_VOICEOVERFRAMERELAY = 0x99 |
||||
|
IFT_VOICEOVERIP = 0x68 |
||||
|
IFT_X213 = 0x5d |
||||
|
IFT_X25 = 0x5 |
||||
|
IFT_X25DDN = 0x4 |
||||
|
IFT_X25HUNTGROUP = 0x7a |
||||
|
IFT_X25MLP = 0x79 |
||||
|
IFT_X25PLE = 0x28 |
||||
|
IFT_XETHER = 0x1a |
||||
|
|
||||
|
// missing constants on FreeBSD-11.1-RELEASE, copied from old values in ztypes_freebsd_arm.go
|
||||
|
IFF_SMART = 0x20 |
||||
|
IFT_FAITH = 0xf2 |
||||
|
IFT_IPXIP = 0xf9 |
||||
|
IPPROTO_MAXID = 0x34 |
||||
|
IPV6_FAITH = 0x1d |
||||
|
IP_FAITH = 0x16 |
||||
|
MAP_NORESERVE = 0x40 |
||||
|
MAP_RENAME = 0x20 |
||||
|
NET_RT_MAXID = 0x6 |
||||
|
RTF_PRCLONING = 0x10000 |
||||
|
RTM_OLDADD = 0x9 |
||||
|
RTM_OLDDEL = 0xa |
||||
|
SIOCADDRT = 0x8030720a |
||||
|
SIOCALIFADDR = 0x8118691b |
||||
|
SIOCDELRT = 0x8030720b |
||||
|
SIOCDLIFADDR = 0x8118691d |
||||
|
SIOCGLIFADDR = 0xc118691c |
||||
|
SIOCGLIFPHYADDR = 0xc118694b |
||||
|
SIOCSLIFPHYADDR = 0x8118694a |
||||
|
) |
@ -0,0 +1,32 @@ |
|||||
|
// Copyright 2014 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 darwin dragonfly freebsd linux netbsd openbsd
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import "unsafe" |
||||
|
|
||||
|
// fcntl64Syscall is usually SYS_FCNTL, but is overridden on 32-bit Linux
|
||||
|
// systems by flock_linux_32bit.go to be SYS_FCNTL64.
|
||||
|
var fcntl64Syscall uintptr = SYS_FCNTL |
||||
|
|
||||
|
// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
|
||||
|
func FcntlInt(fd uintptr, cmd, arg int) (int, error) { |
||||
|
valptr, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(arg)) |
||||
|
var err error |
||||
|
if errno != 0 { |
||||
|
err = errno |
||||
|
} |
||||
|
return int(valptr), err |
||||
|
} |
||||
|
|
||||
|
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
|
||||
|
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { |
||||
|
_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk))) |
||||
|
if errno == 0 { |
||||
|
return nil |
||||
|
} |
||||
|
return errno |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
// +build linux,386 linux,arm linux,mips linux,mipsle
|
||||
|
|
||||
|
// Copyright 2014 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 unix |
||||
|
|
||||
|
func init() { |
||||
|
// On 32-bit Linux systems, the fcntl syscall that matches Go's
|
||||
|
// Flock_t type is SYS_FCNTL64, not SYS_FCNTL.
|
||||
|
fcntl64Syscall = SYS_FCNTL64 |
||||
|
} |
@ -0,0 +1,61 @@ |
|||||
|
// 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 gccgo
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import "syscall" |
||||
|
|
||||
|
// We can't use the gc-syntax .s files for gccgo. On the plus side
|
||||
|
// much of the functionality can be written directly in Go.
|
||||
|
|
||||
|
//extern gccgoRealSyscallNoError
|
||||
|
func realSyscallNoError(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r uintptr) |
||||
|
|
||||
|
//extern gccgoRealSyscall
|
||||
|
func realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r, errno uintptr) |
||||
|
|
||||
|
func SyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) { |
||||
|
syscall.Entersyscall() |
||||
|
r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0) |
||||
|
syscall.Exitsyscall() |
||||
|
return r, 0 |
||||
|
} |
||||
|
|
||||
|
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { |
||||
|
syscall.Entersyscall() |
||||
|
r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0) |
||||
|
syscall.Exitsyscall() |
||||
|
return r, 0, syscall.Errno(errno) |
||||
|
} |
||||
|
|
||||
|
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) { |
||||
|
syscall.Entersyscall() |
||||
|
r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, 0, 0, 0) |
||||
|
syscall.Exitsyscall() |
||||
|
return r, 0, syscall.Errno(errno) |
||||
|
} |
||||
|
|
||||
|
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) { |
||||
|
syscall.Entersyscall() |
||||
|
r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9) |
||||
|
syscall.Exitsyscall() |
||||
|
return r, 0, syscall.Errno(errno) |
||||
|
} |
||||
|
|
||||
|
func RawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) { |
||||
|
r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0) |
||||
|
return r, 0 |
||||
|
} |
||||
|
|
||||
|
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { |
||||
|
r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0) |
||||
|
return r, 0, syscall.Errno(errno) |
||||
|
} |
||||
|
|
||||
|
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) { |
||||
|
r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, 0, 0, 0) |
||||
|
return r, 0, syscall.Errno(errno) |
||||
|
} |
@ -0,0 +1,38 @@ |
|||||
|
// 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 gccgo
|
||||
|
|
||||
|
#include <errno.h> |
||||
|
#include <stdint.h> |
||||
|
#include <unistd.h> |
||||
|
|
||||
|
#define _STRINGIFY2_(x) #x |
||||
|
#define _STRINGIFY_(x) _STRINGIFY2_(x) |
||||
|
#define GOSYM_PREFIX _STRINGIFY_(__USER_LABEL_PREFIX__) |
||||
|
|
||||
|
// Call syscall from C code because the gccgo support for calling from
|
||||
|
// Go to C does not support varargs functions.
|
||||
|
|
||||
|
struct ret { |
||||
|
uintptr_t r; |
||||
|
uintptr_t err; |
||||
|
}; |
||||
|
|
||||
|
struct ret |
||||
|
gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9) |
||||
|
{ |
||||
|
struct ret r; |
||||
|
|
||||
|
errno = 0; |
||||
|
r.r = syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9); |
||||
|
r.err = errno; |
||||
|
return r; |
||||
|
} |
||||
|
|
||||
|
uintptr_t |
||||
|
gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9) |
||||
|
{ |
||||
|
return syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9); |
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
// 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 gccgo,linux,amd64
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import "syscall" |
||||
|
|
||||
|
//extern gettimeofday
|
||||
|
func realGettimeofday(*Timeval, *byte) int32 |
||||
|
|
||||
|
func gettimeofday(tv *Timeval) (err syscall.Errno) { |
||||
|
r := realGettimeofday(tv, nil) |
||||
|
if r < 0 { |
||||
|
return syscall.GetErrno() |
||||
|
} |
||||
|
return 0 |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
// 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 darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import "runtime" |
||||
|
|
||||
|
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
|
||||
|
//
|
||||
|
// To change fd's window size, the req argument should be TIOCSWINSZ.
|
||||
|
func IoctlSetWinsize(fd int, req uint, value *Winsize) error { |
||||
|
// TODO: if we get the chance, remove the req parameter and
|
||||
|
// hardcode TIOCSWINSZ.
|
||||
|
err := ioctlSetWinsize(fd, req, value) |
||||
|
runtime.KeepAlive(value) |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
// IoctlSetTermios performs an ioctl on fd with a *Termios.
|
||||
|
//
|
||||
|
// The req value will usually be TCSETA or TIOCSETA.
|
||||
|
func IoctlSetTermios(fd int, req uint, value *Termios) error { |
||||
|
// TODO: if we get the chance, remove the req parameter.
|
||||
|
err := ioctlSetTermios(fd, req, value) |
||||
|
runtime.KeepAlive(value) |
||||
|
return err |
||||
|
} |
@ -0,0 +1,188 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
# 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. |
||||
|
|
||||
|
# This script runs or (given -n) prints suggested commands to generate files for |
||||
|
# the Architecture/OS specified by the GOARCH and GOOS environment variables. |
||||
|
# See README.md for more information about how the build system works. |
||||
|
|
||||
|
GOOSARCH="${GOOS}_${GOARCH}" |
||||
|
|
||||
|
# defaults |
||||
|
mksyscall="./mksyscall.pl" |
||||
|
mkerrors="./mkerrors.sh" |
||||
|
zerrors="zerrors_$GOOSARCH.go" |
||||
|
mksysctl="" |
||||
|
zsysctl="zsysctl_$GOOSARCH.go" |
||||
|
mksysnum= |
||||
|
mktypes= |
||||
|
run="sh" |
||||
|
cmd="" |
||||
|
|
||||
|
case "$1" in |
||||
|
-syscalls) |
||||
|
for i in zsyscall*go |
||||
|
do |
||||
|
# Run the command line that appears in the first line |
||||
|
# of the generated file to regenerate it. |
||||
|
sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i |
||||
|
rm _$i |
||||
|
done |
||||
|
exit 0 |
||||
|
;; |
||||
|
-n) |
||||
|
run="cat" |
||||
|
cmd="echo" |
||||
|
shift |
||||
|
esac |
||||
|
|
||||
|
case "$#" in |
||||
|
0) |
||||
|
;; |
||||
|
*) |
||||
|
echo 'usage: mkall.sh [-n]' 1>&2 |
||||
|
exit 2 |
||||
|
esac |
||||
|
|
||||
|
if [[ "$GOOS" = "linux" ]] && [[ "$GOARCH" != "sparc64" ]]; then |
||||
|
# Use then new build system |
||||
|
# Files generated through docker (use $cmd so you can Ctl-C the build or run) |
||||
|
$cmd docker build --tag generate:$GOOS $GOOS |
||||
|
$cmd docker run --interactive --tty --volume $(dirname "$(readlink -f "$0")"):/build generate:$GOOS |
||||
|
exit |
||||
|
fi |
||||
|
|
||||
|
GOOSARCH_in=syscall_$GOOSARCH.go |
||||
|
case "$GOOSARCH" in |
||||
|
_* | *_ | _) |
||||
|
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2 |
||||
|
exit 1 |
||||
|
;; |
||||
|
darwin_386) |
||||
|
mkerrors="$mkerrors -m32" |
||||
|
mksyscall="./mksyscall.pl -l32" |
||||
|
mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h" |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
darwin_amd64) |
||||
|
mkerrors="$mkerrors -m64" |
||||
|
mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h" |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
darwin_arm) |
||||
|
mkerrors="$mkerrors" |
||||
|
mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h" |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
darwin_arm64) |
||||
|
mkerrors="$mkerrors -m64" |
||||
|
mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h" |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
dragonfly_amd64) |
||||
|
mkerrors="$mkerrors -m64" |
||||
|
mksyscall="./mksyscall.pl -dragonfly" |
||||
|
mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl" |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
freebsd_386) |
||||
|
mkerrors="$mkerrors -m32" |
||||
|
mksyscall="./mksyscall.pl -l32" |
||||
|
mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl" |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
freebsd_amd64) |
||||
|
mkerrors="$mkerrors -m64" |
||||
|
mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl" |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
freebsd_arm) |
||||
|
mkerrors="$mkerrors" |
||||
|
mksyscall="./mksyscall.pl -l32 -arm" |
||||
|
mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl" |
||||
|
# Let the type of C char be signed for making the bare syscall |
||||
|
# API consistent across platforms. |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" |
||||
|
;; |
||||
|
linux_sparc64) |
||||
|
GOOSARCH_in=syscall_linux_sparc64.go |
||||
|
unistd_h=/usr/include/sparc64-linux-gnu/asm/unistd.h |
||||
|
mkerrors="$mkerrors -m64" |
||||
|
mksysnum="./mksysnum_linux.pl $unistd_h" |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
netbsd_386) |
||||
|
mkerrors="$mkerrors -m32" |
||||
|
mksyscall="./mksyscall.pl -l32 -netbsd" |
||||
|
mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl" |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
netbsd_amd64) |
||||
|
mkerrors="$mkerrors -m64" |
||||
|
mksyscall="./mksyscall.pl -netbsd" |
||||
|
mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl" |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
netbsd_arm) |
||||
|
mkerrors="$mkerrors" |
||||
|
mksyscall="./mksyscall.pl -l32 -netbsd -arm" |
||||
|
mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl" |
||||
|
# Let the type of C char be signed for making the bare syscall |
||||
|
# API consistent across platforms. |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" |
||||
|
;; |
||||
|
openbsd_386) |
||||
|
mkerrors="$mkerrors -m32" |
||||
|
mksyscall="./mksyscall.pl -l32 -openbsd" |
||||
|
mksysctl="./mksysctl_openbsd.pl" |
||||
|
mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl" |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
openbsd_amd64) |
||||
|
mkerrors="$mkerrors -m64" |
||||
|
mksyscall="./mksyscall.pl -openbsd" |
||||
|
mksysctl="./mksysctl_openbsd.pl" |
||||
|
mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl" |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
openbsd_arm) |
||||
|
mkerrors="$mkerrors" |
||||
|
mksyscall="./mksyscall.pl -l32 -openbsd -arm" |
||||
|
mksysctl="./mksysctl_openbsd.pl" |
||||
|
mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl" |
||||
|
# Let the type of C char be signed for making the bare syscall |
||||
|
# API consistent across platforms. |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char" |
||||
|
;; |
||||
|
solaris_amd64) |
||||
|
mksyscall="./mksyscall_solaris.pl" |
||||
|
mkerrors="$mkerrors -m64" |
||||
|
mksysnum= |
||||
|
mktypes="GOARCH=$GOARCH go tool cgo -godefs" |
||||
|
;; |
||||
|
*) |
||||
|
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2 |
||||
|
exit 1 |
||||
|
;; |
||||
|
esac |
||||
|
|
||||
|
( |
||||
|
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi |
||||
|
case "$GOOS" in |
||||
|
*) |
||||
|
syscall_goos="syscall_$GOOS.go" |
||||
|
case "$GOOS" in |
||||
|
darwin | dragonfly | freebsd | netbsd | openbsd) |
||||
|
syscall_goos="syscall_bsd.go $syscall_goos" |
||||
|
;; |
||||
|
esac |
||||
|
if [ -n "$mksyscall" ]; then echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; fi |
||||
|
;; |
||||
|
esac |
||||
|
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi |
||||
|
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi |
||||
|
if [ -n "$mktypes" ]; then |
||||
|
echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; |
||||
|
fi |
||||
|
) | $run |
@ -0,0 +1,604 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
# 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. |
||||
|
|
||||
|
# Generate Go code listing errors and other #defined constant |
||||
|
# values (ENAMETOOLONG etc.), by asking the preprocessor |
||||
|
# about the definitions. |
||||
|
|
||||
|
unset LANG |
||||
|
export LC_ALL=C |
||||
|
export LC_CTYPE=C |
||||
|
|
||||
|
if test -z "$GOARCH" -o -z "$GOOS"; then |
||||
|
echo 1>&2 "GOARCH or GOOS not defined in environment" |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
# Check that we are using the new build system if we should |
||||
|
if [[ "$GOOS" = "linux" ]] && [[ "$GOARCH" != "sparc64" ]]; then |
||||
|
if [[ "$GOLANG_SYS_BUILD" != "docker" ]]; then |
||||
|
echo 1>&2 "In the new build system, mkerrors should not be called directly." |
||||
|
echo 1>&2 "See README.md" |
||||
|
exit 1 |
||||
|
fi |
||||
|
fi |
||||
|
|
||||
|
CC=${CC:-cc} |
||||
|
|
||||
|
if [[ "$GOOS" = "solaris" ]]; then |
||||
|
# Assumes GNU versions of utilities in PATH. |
||||
|
export PATH=/usr/gnu/bin:$PATH |
||||
|
fi |
||||
|
|
||||
|
uname=$(uname) |
||||
|
|
||||
|
includes_Darwin=' |
||||
|
#define _DARWIN_C_SOURCE |
||||
|
#define KERNEL |
||||
|
#define _DARWIN_USE_64_BIT_INODE |
||||
|
#include <stdint.h> |
||||
|
#include <sys/attr.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/event.h> |
||||
|
#include <sys/ptrace.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <sys/sockio.h> |
||||
|
#include <sys/sysctl.h> |
||||
|
#include <sys/mman.h> |
||||
|
#include <sys/mount.h> |
||||
|
#include <sys/utsname.h> |
||||
|
#include <sys/wait.h> |
||||
|
#include <sys/xattr.h> |
||||
|
#include <net/bpf.h> |
||||
|
#include <net/if.h> |
||||
|
#include <net/if_types.h> |
||||
|
#include <net/route.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <netinet/ip.h> |
||||
|
#include <termios.h> |
||||
|
' |
||||
|
|
||||
|
includes_DragonFly=' |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/event.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <sys/sockio.h> |
||||
|
#include <sys/sysctl.h> |
||||
|
#include <sys/mman.h> |
||||
|
#include <sys/wait.h> |
||||
|
#include <sys/ioctl.h> |
||||
|
#include <net/bpf.h> |
||||
|
#include <net/if.h> |
||||
|
#include <net/if_types.h> |
||||
|
#include <net/route.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <termios.h> |
||||
|
#include <netinet/ip.h> |
||||
|
#include <net/ip_mroute/ip_mroute.h> |
||||
|
' |
||||
|
|
||||
|
includes_FreeBSD=' |
||||
|
#include <sys/capability.h> |
||||
|
#include <sys/param.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/event.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <sys/sockio.h> |
||||
|
#include <sys/sysctl.h> |
||||
|
#include <sys/mman.h> |
||||
|
#include <sys/mount.h> |
||||
|
#include <sys/wait.h> |
||||
|
#include <sys/ioctl.h> |
||||
|
#include <net/bpf.h> |
||||
|
#include <net/if.h> |
||||
|
#include <net/if_types.h> |
||||
|
#include <net/route.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <termios.h> |
||||
|
#include <netinet/ip.h> |
||||
|
#include <netinet/ip_mroute.h> |
||||
|
#include <sys/extattr.h> |
||||
|
|
||||
|
#if __FreeBSD__ >= 10 |
||||
|
#define IFT_CARP 0xf8 // IFT_CARP is deprecated in FreeBSD 10 |
||||
|
#undef SIOCAIFADDR |
||||
|
#define SIOCAIFADDR _IOW(105, 26, struct oifaliasreq) // ifaliasreq contains if_data |
||||
|
#undef SIOCSIFPHYADDR |
||||
|
#define SIOCSIFPHYADDR _IOW(105, 70, struct oifaliasreq) // ifaliasreq contains if_data |
||||
|
#endif |
||||
|
' |
||||
|
|
||||
|
includes_Linux=' |
||||
|
#define _LARGEFILE_SOURCE |
||||
|
#define _LARGEFILE64_SOURCE |
||||
|
#ifndef __LP64__ |
||||
|
#define _FILE_OFFSET_BITS 64 |
||||
|
#endif |
||||
|
#define _GNU_SOURCE |
||||
|
|
||||
|
// <sys/ioctl.h> is broken on powerpc64, as it fails to include definitions of |
||||
|
// these structures. We just include them copied from <bits/termios.h>. |
||||
|
#if defined(__powerpc__) |
||||
|
struct sgttyb { |
||||
|
char sg_ispeed; |
||||
|
char sg_ospeed; |
||||
|
char sg_erase; |
||||
|
char sg_kill; |
||||
|
short sg_flags; |
||||
|
}; |
||||
|
|
||||
|
struct tchars { |
||||
|
char t_intrc; |
||||
|
char t_quitc; |
||||
|
char t_startc; |
||||
|
char t_stopc; |
||||
|
char t_eofc; |
||||
|
char t_brkc; |
||||
|
}; |
||||
|
|
||||
|
struct ltchars { |
||||
|
char t_suspc; |
||||
|
char t_dsuspc; |
||||
|
char t_rprntc; |
||||
|
char t_flushc; |
||||
|
char t_werasc; |
||||
|
char t_lnextc; |
||||
|
}; |
||||
|
#endif |
||||
|
|
||||
|
#include <bits/sockaddr.h> |
||||
|
#include <sys/epoll.h> |
||||
|
#include <sys/eventfd.h> |
||||
|
#include <sys/inotify.h> |
||||
|
#include <sys/ioctl.h> |
||||
|
#include <sys/mman.h> |
||||
|
#include <sys/mount.h> |
||||
|
#include <sys/prctl.h> |
||||
|
#include <sys/stat.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/time.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <sys/xattr.h> |
||||
|
#include <linux/if.h> |
||||
|
#include <linux/if_alg.h> |
||||
|
#include <linux/if_arp.h> |
||||
|
#include <linux/if_ether.h> |
||||
|
#include <linux/if_tun.h> |
||||
|
#include <linux/if_packet.h> |
||||
|
#include <linux/if_addr.h> |
||||
|
#include <linux/falloc.h> |
||||
|
#include <linux/filter.h> |
||||
|
#include <linux/fs.h> |
||||
|
#include <linux/keyctl.h> |
||||
|
#include <linux/magic.h> |
||||
|
#include <linux/netfilter/nfnetlink.h> |
||||
|
#include <linux/netlink.h> |
||||
|
#include <linux/perf_event.h> |
||||
|
#include <linux/random.h> |
||||
|
#include <linux/reboot.h> |
||||
|
#include <linux/rtnetlink.h> |
||||
|
#include <linux/ptrace.h> |
||||
|
#include <linux/sched.h> |
||||
|
#include <linux/seccomp.h> |
||||
|
#include <linux/sockios.h> |
||||
|
#include <linux/wait.h> |
||||
|
#include <linux/icmpv6.h> |
||||
|
#include <linux/serial.h> |
||||
|
#include <linux/can.h> |
||||
|
#include <linux/vm_sockets.h> |
||||
|
#include <linux/taskstats.h> |
||||
|
#include <linux/genetlink.h> |
||||
|
#include <linux/stat.h> |
||||
|
#include <linux/watchdog.h> |
||||
|
#include <linux/hdreg.h> |
||||
|
#include <linux/rtc.h> |
||||
|
#include <net/route.h> |
||||
|
#include <asm/termbits.h> |
||||
|
|
||||
|
#ifndef MSG_FASTOPEN |
||||
|
#define MSG_FASTOPEN 0x20000000 |
||||
|
#endif |
||||
|
|
||||
|
#ifndef PTRACE_GETREGS |
||||
|
#define PTRACE_GETREGS 0xc |
||||
|
#endif |
||||
|
|
||||
|
#ifndef PTRACE_SETREGS |
||||
|
#define PTRACE_SETREGS 0xd |
||||
|
#endif |
||||
|
|
||||
|
#ifndef SOL_NETLINK |
||||
|
#define SOL_NETLINK 270 |
||||
|
#endif |
||||
|
|
||||
|
#ifdef SOL_BLUETOOTH |
||||
|
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h |
||||
|
// but it is already in bluetooth_linux.go |
||||
|
#undef SOL_BLUETOOTH |
||||
|
#endif |
||||
|
|
||||
|
// Certain constants are missing from the fs/crypto UAPI |
||||
|
#define FS_KEY_DESC_PREFIX "fscrypt:" |
||||
|
#define FS_KEY_DESC_PREFIX_SIZE 8 |
||||
|
#define FS_MAX_KEY_SIZE 64 |
||||
|
' |
||||
|
|
||||
|
includes_NetBSD=' |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/param.h> |
||||
|
#include <sys/event.h> |
||||
|
#include <sys/mman.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <sys/sockio.h> |
||||
|
#include <sys/sysctl.h> |
||||
|
#include <sys/termios.h> |
||||
|
#include <sys/ttycom.h> |
||||
|
#include <sys/wait.h> |
||||
|
#include <net/bpf.h> |
||||
|
#include <net/if.h> |
||||
|
#include <net/if_types.h> |
||||
|
#include <net/route.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <netinet/in_systm.h> |
||||
|
#include <netinet/ip.h> |
||||
|
#include <netinet/ip_mroute.h> |
||||
|
#include <netinet/if_ether.h> |
||||
|
|
||||
|
// Needed since <sys/param.h> refers to it... |
||||
|
#define schedppq 1 |
||||
|
' |
||||
|
|
||||
|
includes_OpenBSD=' |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/param.h> |
||||
|
#include <sys/event.h> |
||||
|
#include <sys/mman.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <sys/sockio.h> |
||||
|
#include <sys/sysctl.h> |
||||
|
#include <sys/termios.h> |
||||
|
#include <sys/ttycom.h> |
||||
|
#include <sys/wait.h> |
||||
|
#include <net/bpf.h> |
||||
|
#include <net/if.h> |
||||
|
#include <net/if_types.h> |
||||
|
#include <net/if_var.h> |
||||
|
#include <net/route.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <netinet/in_systm.h> |
||||
|
#include <netinet/ip.h> |
||||
|
#include <netinet/ip_mroute.h> |
||||
|
#include <netinet/if_ether.h> |
||||
|
#include <net/if_bridge.h> |
||||
|
|
||||
|
// We keep some constants not supported in OpenBSD 5.5 and beyond for |
||||
|
// the promise of compatibility. |
||||
|
#define EMUL_ENABLED 0x1 |
||||
|
#define EMUL_NATIVE 0x2 |
||||
|
#define IPV6_FAITH 0x1d |
||||
|
#define IPV6_OPTIONS 0x1 |
||||
|
#define IPV6_RTHDR_STRICT 0x1 |
||||
|
#define IPV6_SOCKOPT_RESERVED1 0x3 |
||||
|
#define SIOCGIFGENERIC 0xc020693a |
||||
|
#define SIOCSIFGENERIC 0x80206939 |
||||
|
#define WALTSIG 0x4 |
||||
|
' |
||||
|
|
||||
|
includes_SunOS=' |
||||
|
#include <limits.h> |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <sys/sockio.h> |
||||
|
#include <sys/mman.h> |
||||
|
#include <sys/wait.h> |
||||
|
#include <sys/ioctl.h> |
||||
|
#include <sys/mkdev.h> |
||||
|
#include <net/bpf.h> |
||||
|
#include <net/if.h> |
||||
|
#include <net/if_arp.h> |
||||
|
#include <net/if_types.h> |
||||
|
#include <net/route.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <termios.h> |
||||
|
#include <netinet/ip.h> |
||||
|
#include <netinet/ip_mroute.h> |
||||
|
' |
||||
|
|
||||
|
|
||||
|
includes=' |
||||
|
#include <sys/types.h> |
||||
|
#include <sys/file.h> |
||||
|
#include <fcntl.h> |
||||
|
#include <dirent.h> |
||||
|
#include <sys/socket.h> |
||||
|
#include <netinet/in.h> |
||||
|
#include <netinet/ip.h> |
||||
|
#include <netinet/ip6.h> |
||||
|
#include <netinet/tcp.h> |
||||
|
#include <errno.h> |
||||
|
#include <sys/signal.h> |
||||
|
#include <signal.h> |
||||
|
#include <sys/resource.h> |
||||
|
#include <time.h> |
||||
|
' |
||||
|
ccflags="$@" |
||||
|
|
||||
|
# Write go tool cgo -godefs input. |
||||
|
( |
||||
|
echo package unix |
||||
|
echo |
||||
|
echo '/*' |
||||
|
indirect="includes_$(uname)" |
||||
|
echo "${!indirect} $includes" |
||||
|
echo '*/' |
||||
|
echo 'import "C"' |
||||
|
echo 'import "syscall"' |
||||
|
echo |
||||
|
echo 'const (' |
||||
|
|
||||
|
# The gcc command line prints all the #defines |
||||
|
# it encounters while processing the input |
||||
|
echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags | |
||||
|
awk ' |
||||
|
$1 != "#define" || $2 ~ /\(/ || $3 == "" {next} |
||||
|
|
||||
|
$2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next} # 386 registers |
||||
|
$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next} |
||||
|
$2 ~ /^(SCM_SRCRT)$/ {next} |
||||
|
$2 ~ /^(MAP_FAILED)$/ {next} |
||||
|
$2 ~ /^ELF_.*$/ {next}# <asm/elf.h> contains ELF_ARCH, etc. |
||||
|
|
||||
|
$2 ~ /^EXTATTR_NAMESPACE_NAMES/ || |
||||
|
$2 ~ /^EXTATTR_NAMESPACE_[A-Z]+_STRING/ {next} |
||||
|
|
||||
|
$2 !~ /^ETH_/ && |
||||
|
$2 !~ /^EPROC_/ && |
||||
|
$2 !~ /^EQUIV_/ && |
||||
|
$2 !~ /^EXPR_/ && |
||||
|
$2 ~ /^E[A-Z0-9_]+$/ || |
||||
|
$2 ~ /^B[0-9_]+$/ || |
||||
|
$2 ~ /^(OLD|NEW)DEV$/ || |
||||
|
$2 == "BOTHER" || |
||||
|
$2 ~ /^CI?BAUD(EX)?$/ || |
||||
|
$2 == "IBSHIFT" || |
||||
|
$2 ~ /^V[A-Z0-9]+$/ || |
||||
|
$2 ~ /^CS[A-Z0-9]/ || |
||||
|
$2 ~ /^I(SIG|CANON|CRNL|UCLC|EXTEN|MAXBEL|STRIP|UTF8)$/ || |
||||
|
$2 ~ /^IGN/ || |
||||
|
$2 ~ /^IX(ON|ANY|OFF)$/ || |
||||
|
$2 ~ /^IN(LCR|PCK)$/ || |
||||
|
$2 !~ "X86_CR3_PCID_NOFLUSH" && |
||||
|
$2 ~ /(^FLU?SH)|(FLU?SH$)/ || |
||||
|
$2 ~ /^C(LOCAL|READ|MSPAR|RTSCTS)$/ || |
||||
|
$2 == "BRKINT" || |
||||
|
$2 == "HUPCL" || |
||||
|
$2 == "PENDIN" || |
||||
|
$2 == "TOSTOP" || |
||||
|
$2 == "XCASE" || |
||||
|
$2 == "ALTWERASE" || |
||||
|
$2 == "NOKERNINFO" || |
||||
|
$2 ~ /^PAR/ || |
||||
|
$2 ~ /^SIG[^_]/ || |
||||
|
$2 ~ /^O[CNPFPL][A-Z]+[^_][A-Z]+$/ || |
||||
|
$2 ~ /^(NL|CR|TAB|BS|VT|FF)DLY$/ || |
||||
|
$2 ~ /^(NL|CR|TAB|BS|VT|FF)[0-9]$/ || |
||||
|
$2 ~ /^O?XTABS$/ || |
||||
|
$2 ~ /^TC[IO](ON|OFF)$/ || |
||||
|
$2 ~ /^IN_/ || |
||||
|
$2 ~ /^LOCK_(SH|EX|NB|UN)$/ || |
||||
|
$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|T?PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ || |
||||
|
$2 ~ /^TP_STATUS_/ || |
||||
|
$2 ~ /^FALLOC_/ || |
||||
|
$2 == "ICMPV6_FILTER" || |
||||
|
$2 == "SOMAXCONN" || |
||||
|
$2 == "NAME_MAX" || |
||||
|
$2 == "IFNAMSIZ" || |
||||
|
$2 ~ /^CTL_(HW|KERN|MAXNAME|NET|QUERY)$/ || |
||||
|
$2 ~ /^KERN_(HOSTNAME|OS(RELEASE|TYPE)|VERSION)$/ || |
||||
|
$2 ~ /^HW_MACHINE$/ || |
||||
|
$2 ~ /^SYSCTL_VERS/ || |
||||
|
$2 ~ /^(MS|MNT|UMOUNT)_/ || |
||||
|
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ || |
||||
|
$2 ~ /^(O|F|E?FD|NAME|S|PTRACE|PT)_/ || |
||||
|
$2 ~ /^LINUX_REBOOT_CMD_/ || |
||||
|
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ || |
||||
|
$2 !~ "NLA_TYPE_MASK" && |
||||
|
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ || |
||||
|
$2 ~ /^SIOC/ || |
||||
|
$2 ~ /^TIOC/ || |
||||
|
$2 ~ /^TCGET/ || |
||||
|
$2 ~ /^TCSET/ || |
||||
|
$2 ~ /^TC(FLSH|SBRKP?|XONC)$/ || |
||||
|
$2 !~ "RTF_BITS" && |
||||
|
$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ || |
||||
|
$2 ~ /^BIOC/ || |
||||
|
$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ || |
||||
|
$2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|LOCKS|MEMLOCK|MSGQUEUE|NICE|NOFILE|NPROC|RSS|RTPRIO|RTTIME|SIGPENDING|STACK)|RLIM_INFINITY/ || |
||||
|
$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ || |
||||
|
$2 ~ /^CLONE_[A-Z_]+/ || |
||||
|
$2 !~ /^(BPF_TIMEVAL)$/ && |
||||
|
$2 ~ /^(BPF|DLT)_/ || |
||||
|
$2 ~ /^CLOCK_/ || |
||||
|
$2 ~ /^CAN_/ || |
||||
|
$2 ~ /^CAP_/ || |
||||
|
$2 ~ /^ALG_/ || |
||||
|
$2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE|IOC_(GET|SET)_ENCRYPTION)/ || |
||||
|
$2 ~ /^GRND_/ || |
||||
|
$2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ || |
||||
|
$2 ~ /^KEYCTL_/ || |
||||
|
$2 ~ /^PERF_EVENT_IOC_/ || |
||||
|
$2 ~ /^SECCOMP_MODE_/ || |
||||
|
$2 ~ /^SPLICE_/ || |
||||
|
$2 !~ /^AUDIT_RECORD_MAGIC/ && |
||||
|
$2 ~ /^[A-Z0-9_]+_MAGIC2?$/ || |
||||
|
$2 ~ /^(VM|VMADDR)_/ || |
||||
|
$2 ~ /^IOCTL_VM_SOCKETS_/ || |
||||
|
$2 ~ /^(TASKSTATS|TS)_/ || |
||||
|
$2 ~ /^CGROUPSTATS_/ || |
||||
|
$2 ~ /^GENL_/ || |
||||
|
$2 ~ /^STATX_/ || |
||||
|
$2 ~ /^UTIME_/ || |
||||
|
$2 ~ /^XATTR_(CREATE|REPLACE|NO(DEFAULT|FOLLOW|SECURITY)|SHOWCOMPRESSION)/ || |
||||
|
$2 ~ /^ATTR_(BIT_MAP_COUNT|(CMN|VOL|FILE)_)/ || |
||||
|
$2 ~ /^FSOPT_/ || |
||||
|
$2 ~ /^WDIOC_/ || |
||||
|
$2 ~ /^NFN/ || |
||||
|
$2 ~ /^(HDIO|WIN|SMART)_/ || |
||||
|
$2 !~ "WMESGLEN" && |
||||
|
$2 ~ /^W[A-Z0-9]+$/ || |
||||
|
$2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)} |
||||
|
$2 ~ /^__WCOREFLAG$/ {next} |
||||
|
$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)} |
||||
|
|
||||
|
{next} |
||||
|
' | sort |
||||
|
|
||||
|
echo ')' |
||||
|
) >_const.go |
||||
|
|
||||
|
# Pull out the error names for later. |
||||
|
errors=$( |
||||
|
echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags | |
||||
|
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' | |
||||
|
sort |
||||
|
) |
||||
|
|
||||
|
# Pull out the signal names for later. |
||||
|
signals=$( |
||||
|
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags | |
||||
|
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' | |
||||
|
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' | |
||||
|
sort |
||||
|
) |
||||
|
|
||||
|
# Again, writing regexps to a file. |
||||
|
echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags | |
||||
|
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' | |
||||
|
sort >_error.grep |
||||
|
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags | |
||||
|
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' | |
||||
|
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' | |
||||
|
sort >_signal.grep |
||||
|
|
||||
|
echo '// mkerrors.sh' "$@" |
||||
|
echo '// Code generated by the command above; see README.md. DO NOT EDIT.' |
||||
|
echo |
||||
|
echo "// +build ${GOARCH},${GOOS}" |
||||
|
echo |
||||
|
go tool cgo -godefs -- "$@" _const.go >_error.out |
||||
|
cat _error.out | grep -vf _error.grep | grep -vf _signal.grep |
||||
|
echo |
||||
|
echo '// Errors' |
||||
|
echo 'const (' |
||||
|
cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= syscall.Errno(\1)/' |
||||
|
echo ')' |
||||
|
|
||||
|
echo |
||||
|
echo '// Signals' |
||||
|
echo 'const (' |
||||
|
cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= syscall.Signal(\1)/' |
||||
|
echo ')' |
||||
|
|
||||
|
# Run C program to print error and syscall strings. |
||||
|
( |
||||
|
echo -E " |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <errno.h> |
||||
|
#include <ctype.h> |
||||
|
#include <string.h> |
||||
|
#include <signal.h> |
||||
|
|
||||
|
#define nelem(x) (sizeof(x)/sizeof((x)[0])) |
||||
|
|
||||
|
enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below |
||||
|
|
||||
|
struct tuple { |
||||
|
int num; |
||||
|
const char *name; |
||||
|
}; |
||||
|
|
||||
|
struct tuple errors[] = { |
||||
|
" |
||||
|
for i in $errors |
||||
|
do |
||||
|
echo -E ' {'$i', "'$i'" },' |
||||
|
done |
||||
|
|
||||
|
echo -E " |
||||
|
}; |
||||
|
|
||||
|
struct tuple signals[] = { |
||||
|
" |
||||
|
for i in $signals |
||||
|
do |
||||
|
echo -E ' {'$i', "'$i'" },' |
||||
|
done |
||||
|
|
||||
|
# Use -E because on some systems bash builtin interprets \n itself. |
||||
|
echo -E ' |
||||
|
}; |
||||
|
|
||||
|
static int |
||||
|
tuplecmp(const void *a, const void *b) |
||||
|
{ |
||||
|
return ((struct tuple *)a)->num - ((struct tuple *)b)->num; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
main(void) |
||||
|
{ |
||||
|
int i, e; |
||||
|
char buf[1024], *p; |
||||
|
|
||||
|
printf("\n\n// Error table\n"); |
||||
|
printf("var errorList = [...]struct {\n"); |
||||
|
printf("\tnum syscall.Errno\n"); |
||||
|
printf("\tname string\n"); |
||||
|
printf("\tdesc string\n"); |
||||
|
printf("} {\n"); |
||||
|
qsort(errors, nelem(errors), sizeof errors[0], tuplecmp); |
||||
|
for(i=0; i<nelem(errors); i++) { |
||||
|
e = errors[i].num; |
||||
|
if(i > 0 && errors[i-1].num == e) |
||||
|
continue; |
||||
|
strcpy(buf, strerror(e)); |
||||
|
// lowercase first letter: Bad -> bad, but STREAM -> STREAM. |
||||
|
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) |
||||
|
buf[0] += a - A; |
||||
|
printf("\t{ %d, \"%s\", \"%s\" },\n", e, errors[i].name, buf); |
||||
|
} |
||||
|
printf("}\n\n"); |
||||
|
|
||||
|
printf("\n\n// Signal table\n"); |
||||
|
printf("var signalList = [...]struct {\n"); |
||||
|
printf("\tnum syscall.Signal\n"); |
||||
|
printf("\tname string\n"); |
||||
|
printf("\tdesc string\n"); |
||||
|
printf("} {\n"); |
||||
|
qsort(signals, nelem(signals), sizeof signals[0], tuplecmp); |
||||
|
for(i=0; i<nelem(signals); i++) { |
||||
|
e = signals[i].num; |
||||
|
if(i > 0 && signals[i-1].num == e) |
||||
|
continue; |
||||
|
strcpy(buf, strsignal(e)); |
||||
|
// lowercase first letter: Bad -> bad, but STREAM -> STREAM. |
||||
|
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) |
||||
|
buf[0] += a - A; |
||||
|
// cut trailing : number. |
||||
|
p = strrchr(buf, ":"[0]); |
||||
|
if(p) |
||||
|
*p = '\0'; |
||||
|
printf("\t{ %d, \"%s\", \"%s\" },\n", e, signals[i].name, buf); |
||||
|
} |
||||
|
printf("}\n\n"); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
' |
||||
|
) >_errors.c |
||||
|
|
||||
|
$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out |
@ -0,0 +1,341 @@ |
|||||
|
#!/usr/bin/env perl |
||||
|
# 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. |
||||
|
|
||||
|
# 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. |
||||
|
|
||||
|
use strict; |
||||
|
|
||||
|
my $cmdline = "mksyscall.pl " . join(' ', @ARGV); |
||||
|
my $errors = 0; |
||||
|
my $_32bit = ""; |
||||
|
my $plan9 = 0; |
||||
|
my $openbsd = 0; |
||||
|
my $netbsd = 0; |
||||
|
my $dragonfly = 0; |
||||
|
my $arm = 0; # 64-bit value should use (even, odd)-pair |
||||
|
my $tags = ""; # build tags |
||||
|
|
||||
|
if($ARGV[0] eq "-b32") { |
||||
|
$_32bit = "big-endian"; |
||||
|
shift; |
||||
|
} elsif($ARGV[0] eq "-l32") { |
||||
|
$_32bit = "little-endian"; |
||||
|
shift; |
||||
|
} |
||||
|
if($ARGV[0] eq "-plan9") { |
||||
|
$plan9 = 1; |
||||
|
shift; |
||||
|
} |
||||
|
if($ARGV[0] eq "-openbsd") { |
||||
|
$openbsd = 1; |
||||
|
shift; |
||||
|
} |
||||
|
if($ARGV[0] eq "-netbsd") { |
||||
|
$netbsd = 1; |
||||
|
shift; |
||||
|
} |
||||
|
if($ARGV[0] eq "-dragonfly") { |
||||
|
$dragonfly = 1; |
||||
|
shift; |
||||
|
} |
||||
|
if($ARGV[0] eq "-arm") { |
||||
|
$arm = 1; |
||||
|
shift; |
||||
|
} |
||||
|
if($ARGV[0] eq "-tags") { |
||||
|
shift; |
||||
|
$tags = $ARGV[0]; |
||||
|
shift; |
||||
|
} |
||||
|
|
||||
|
if($ARGV[0] =~ /^-/) { |
||||
|
print STDERR "usage: mksyscall.pl [-b32 | -l32] [-tags x,y] [file ...]\n"; |
||||
|
exit 1; |
||||
|
} |
||||
|
|
||||
|
# Check that we are using the new build system if we should |
||||
|
if($ENV{'GOOS'} eq "linux" && $ENV{'GOARCH'} ne "sparc64") { |
||||
|
if($ENV{'GOLANG_SYS_BUILD'} ne "docker") { |
||||
|
print STDERR "In the new build system, mksyscall should not be called directly.\n"; |
||||
|
print STDERR "See README.md\n"; |
||||
|
exit 1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
sub parseparamlist($) { |
||||
|
my ($list) = @_; |
||||
|
$list =~ s/^\s*//; |
||||
|
$list =~ s/\s*$//; |
||||
|
if($list eq "") { |
||||
|
return (); |
||||
|
} |
||||
|
return split(/\s*,\s*/, $list); |
||||
|
} |
||||
|
|
||||
|
sub parseparam($) { |
||||
|
my ($p) = @_; |
||||
|
if($p !~ /^(\S*) (\S*)$/) { |
||||
|
print STDERR "$ARGV:$.: malformed parameter: $p\n"; |
||||
|
$errors = 1; |
||||
|
return ("xx", "int"); |
||||
|
} |
||||
|
return ($1, $2); |
||||
|
} |
||||
|
|
||||
|
my $text = ""; |
||||
|
while(<>) { |
||||
|
chomp; |
||||
|
s/\s+/ /g; |
||||
|
s/^\s+//; |
||||
|
s/\s+$//; |
||||
|
my $nonblock = /^\/\/sysnb /; |
||||
|
next if !/^\/\/sys / && !$nonblock; |
||||
|
|
||||
|
# 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. |
||||
|
if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) { |
||||
|
print STDERR "$ARGV:$.: malformed //sys declaration\n"; |
||||
|
$errors = 1; |
||||
|
next; |
||||
|
} |
||||
|
my ($func, $in, $out, $sysname) = ($2, $3, $4, $5); |
||||
|
|
||||
|
# Split argument lists on comma. |
||||
|
my @in = parseparamlist($in); |
||||
|
my @out = parseparamlist($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"; |
||||
|
|
||||
|
# Go function header. |
||||
|
my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : ""; |
||||
|
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl; |
||||
|
|
||||
|
# Check if err return available |
||||
|
my $errvar = ""; |
||||
|
foreach my $p (@out) { |
||||
|
my ($name, $type) = parseparam($p); |
||||
|
if($type eq "error") { |
||||
|
$errvar = $name; |
||||
|
last; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
# Prepare arguments to Syscall. |
||||
|
my @args = (); |
||||
|
my $n = 0; |
||||
|
foreach my $p (@in) { |
||||
|
my ($name, $type) = parseparam($p); |
||||
|
if($type =~ /^\*/) { |
||||
|
push @args, "uintptr(unsafe.Pointer($name))"; |
||||
|
} elsif($type eq "string" && $errvar ne "") { |
||||
|
$text .= "\tvar _p$n *byte\n"; |
||||
|
$text .= "\t_p$n, $errvar = BytePtrFromString($name)\n"; |
||||
|
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; |
||||
|
push @args, "uintptr(unsafe.Pointer(_p$n))"; |
||||
|
$n++; |
||||
|
} elsif($type eq "string") { |
||||
|
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; |
||||
|
$text .= "\tvar _p$n *byte\n"; |
||||
|
$text .= "\t_p$n, _ = BytePtrFromString($name)\n"; |
||||
|
push @args, "uintptr(unsafe.Pointer(_p$n))"; |
||||
|
$n++; |
||||
|
} elsif($type =~ /^\[\](.*)/) { |
||||
|
# 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 .= "\tvar _p$n unsafe.Pointer\n"; |
||||
|
$text .= "\tif len($name) > 0 {\n\t\t_p$n = unsafe.Pointer(\&${name}[0])\n\t}"; |
||||
|
$text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero)\n\t}"; |
||||
|
$text .= "\n"; |
||||
|
push @args, "uintptr(_p$n)", "uintptr(len($name))"; |
||||
|
$n++; |
||||
|
} elsif($type eq "int64" && ($openbsd || $netbsd)) { |
||||
|
push @args, "0"; |
||||
|
if($_32bit eq "big-endian") { |
||||
|
push @args, "uintptr($name>>32)", "uintptr($name)"; |
||||
|
} elsif($_32bit eq "little-endian") { |
||||
|
push @args, "uintptr($name)", "uintptr($name>>32)"; |
||||
|
} else { |
||||
|
push @args, "uintptr($name)"; |
||||
|
} |
||||
|
} elsif($type eq "int64" && $dragonfly) { |
||||
|
if ($func !~ /^extp(read|write)/i) { |
||||
|
push @args, "0"; |
||||
|
} |
||||
|
if($_32bit eq "big-endian") { |
||||
|
push @args, "uintptr($name>>32)", "uintptr($name)"; |
||||
|
} elsif($_32bit eq "little-endian") { |
||||
|
push @args, "uintptr($name)", "uintptr($name>>32)"; |
||||
|
} else { |
||||
|
push @args, "uintptr($name)"; |
||||
|
} |
||||
|
} elsif($type eq "int64" && $_32bit ne "") { |
||||
|
if(@args % 2 && $arm) { |
||||
|
# arm abi specifies 64-bit argument uses |
||||
|
# (even, odd) pair |
||||
|
push @args, "0" |
||||
|
} |
||||
|
if($_32bit eq "big-endian") { |
||||
|
push @args, "uintptr($name>>32)", "uintptr($name)"; |
||||
|
} else { |
||||
|
push @args, "uintptr($name)", "uintptr($name>>32)"; |
||||
|
} |
||||
|
} else { |
||||
|
push @args, "uintptr($name)"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
# Determine which form to use; pad args with zeros. |
||||
|
my $asm = "Syscall"; |
||||
|
if ($nonblock) { |
||||
|
if ($errvar eq "" && $ENV{'GOOS'} eq "linux") { |
||||
|
$asm = "RawSyscallNoError"; |
||||
|
} else { |
||||
|
$asm = "RawSyscall"; |
||||
|
} |
||||
|
} else { |
||||
|
if ($errvar eq "" && $ENV{'GOOS'} eq "linux") { |
||||
|
$asm = "SyscallNoError"; |
||||
|
} |
||||
|
} |
||||
|
if(@args <= 3) { |
||||
|
while(@args < 3) { |
||||
|
push @args, "0"; |
||||
|
} |
||||
|
} elsif(@args <= 6) { |
||||
|
$asm .= "6"; |
||||
|
while(@args < 6) { |
||||
|
push @args, "0"; |
||||
|
} |
||||
|
} elsif(@args <= 9) { |
||||
|
$asm .= "9"; |
||||
|
while(@args < 9) { |
||||
|
push @args, "0"; |
||||
|
} |
||||
|
} else { |
||||
|
print STDERR "$ARGV:$.: too many arguments to system call\n"; |
||||
|
} |
||||
|
|
||||
|
# System call number. |
||||
|
if($sysname eq "") { |
||||
|
$sysname = "SYS_$func"; |
||||
|
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar |
||||
|
$sysname =~ y/a-z/A-Z/; |
||||
|
} |
||||
|
|
||||
|
# Actual call. |
||||
|
my $args = join(', ', @args); |
||||
|
my $call = "$asm($sysname, $args)"; |
||||
|
|
||||
|
# Assign return values. |
||||
|
my $body = ""; |
||||
|
my @ret = ("_", "_", "_"); |
||||
|
my $do_errno = 0; |
||||
|
for(my $i=0; $i<@out; $i++) { |
||||
|
my $p = $out[$i]; |
||||
|
my ($name, $type) = parseparam($p); |
||||
|
my $reg = ""; |
||||
|
if($name eq "err" && !$plan9) { |
||||
|
$reg = "e1"; |
||||
|
$ret[2] = $reg; |
||||
|
$do_errno = 1; |
||||
|
} elsif($name eq "err" && $plan9) { |
||||
|
$ret[0] = "r0"; |
||||
|
$ret[2] = "e1"; |
||||
|
next; |
||||
|
} else { |
||||
|
$reg = sprintf("r%d", $i); |
||||
|
$ret[$i] = $reg; |
||||
|
} |
||||
|
if($type eq "bool") { |
||||
|
$reg = "$reg != 0"; |
||||
|
} |
||||
|
if($type eq "int64" && $_32bit ne "") { |
||||
|
# 64-bit number in r1:r0 or r0:r1. |
||||
|
if($i+2 > @out) { |
||||
|
print STDERR "$ARGV:$.: not enough registers for int64 return\n"; |
||||
|
} |
||||
|
if($_32bit eq "big-endian") { |
||||
|
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1); |
||||
|
} else { |
||||
|
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i); |
||||
|
} |
||||
|
$ret[$i] = sprintf("r%d", $i); |
||||
|
$ret[$i+1] = sprintf("r%d", $i+1); |
||||
|
} |
||||
|
if($reg ne "e1" || $plan9) { |
||||
|
$body .= "\t$name = $type($reg)\n"; |
||||
|
} |
||||
|
} |
||||
|
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") { |
||||
|
$text .= "\t$call\n"; |
||||
|
} else { |
||||
|
if ($errvar eq "" && $ENV{'GOOS'} eq "linux") { |
||||
|
# raw syscall without error on Linux, see golang.org/issue/22924 |
||||
|
$text .= "\t$ret[0], $ret[1] := $call\n"; |
||||
|
} else { |
||||
|
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; |
||||
|
} |
||||
|
} |
||||
|
$text .= $body; |
||||
|
|
||||
|
if ($plan9 && $ret[2] eq "e1") { |
||||
|
$text .= "\tif int32(r0) == -1 {\n"; |
||||
|
$text .= "\t\terr = e1\n"; |
||||
|
$text .= "\t}\n"; |
||||
|
} elsif ($do_errno) { |
||||
|
$text .= "\tif e1 != 0 {\n"; |
||||
|
$text .= "\t\terr = errnoErr(e1)\n"; |
||||
|
$text .= "\t}\n"; |
||||
|
} |
||||
|
$text .= "\treturn\n"; |
||||
|
$text .= "}\n\n"; |
||||
|
} |
||||
|
|
||||
|
chomp $text; |
||||
|
chomp $text; |
||||
|
|
||||
|
if($errors) { |
||||
|
exit 1; |
||||
|
} |
||||
|
|
||||
|
print <<EOF; |
||||
|
// $cmdline |
||||
|
// Code generated by the command above; see README.md. DO NOT EDIT. |
||||
|
|
||||
|
// +build $tags |
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import ( |
||||
|
"syscall" |
||||
|
"unsafe" |
||||
|
) |
||||
|
|
||||
|
var _ syscall.Errno |
||||
|
|
||||
|
$text |
||||
|
EOF |
||||
|
exit 0; |
@ -0,0 +1,289 @@ |
|||||
|
#!/usr/bin/env perl |
||||
|
# 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. |
||||
|
|
||||
|
# 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 |
||||
|
|
||||
|
use strict; |
||||
|
|
||||
|
my $cmdline = "mksyscall_solaris.pl " . join(' ', @ARGV); |
||||
|
my $errors = 0; |
||||
|
my $_32bit = ""; |
||||
|
my $tags = ""; # build tags |
||||
|
|
||||
|
binmode STDOUT; |
||||
|
|
||||
|
if($ARGV[0] eq "-b32") { |
||||
|
$_32bit = "big-endian"; |
||||
|
shift; |
||||
|
} elsif($ARGV[0] eq "-l32") { |
||||
|
$_32bit = "little-endian"; |
||||
|
shift; |
||||
|
} |
||||
|
if($ARGV[0] eq "-tags") { |
||||
|
shift; |
||||
|
$tags = $ARGV[0]; |
||||
|
shift; |
||||
|
} |
||||
|
|
||||
|
if($ARGV[0] =~ /^-/) { |
||||
|
print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [-tags x,y] [file ...]\n"; |
||||
|
exit 1; |
||||
|
} |
||||
|
|
||||
|
sub parseparamlist($) { |
||||
|
my ($list) = @_; |
||||
|
$list =~ s/^\s*//; |
||||
|
$list =~ s/\s*$//; |
||||
|
if($list eq "") { |
||||
|
return (); |
||||
|
} |
||||
|
return split(/\s*,\s*/, $list); |
||||
|
} |
||||
|
|
||||
|
sub parseparam($) { |
||||
|
my ($p) = @_; |
||||
|
if($p !~ /^(\S*) (\S*)$/) { |
||||
|
print STDERR "$ARGV:$.: malformed parameter: $p\n"; |
||||
|
$errors = 1; |
||||
|
return ("xx", "int"); |
||||
|
} |
||||
|
return ($1, $2); |
||||
|
} |
||||
|
|
||||
|
my $package = ""; |
||||
|
my $text = ""; |
||||
|
my $dynimports = ""; |
||||
|
my $linknames = ""; |
||||
|
my @vars = (); |
||||
|
while(<>) { |
||||
|
chomp; |
||||
|
s/\s+/ /g; |
||||
|
s/^\s+//; |
||||
|
s/\s+$//; |
||||
|
$package = $1 if !$package && /^package (\S+)$/; |
||||
|
my $nonblock = /^\/\/sysnb /; |
||||
|
next if !/^\/\/sys / && !$nonblock; |
||||
|
|
||||
|
# 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. |
||||
|
if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) { |
||||
|
print STDERR "$ARGV:$.: malformed //sys declaration\n"; |
||||
|
$errors = 1; |
||||
|
next; |
||||
|
} |
||||
|
my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6); |
||||
|
|
||||
|
# Split argument lists on comma. |
||||
|
my @in = parseparamlist($in); |
||||
|
my @out = parseparamlist($out); |
||||
|
|
||||
|
# So file name. |
||||
|
if($modname eq "") { |
||||
|
$modname = "libc"; |
||||
|
} |
||||
|
|
||||
|
# System call name. |
||||
|
if($sysname eq "") { |
||||
|
$sysname = "$func"; |
||||
|
} |
||||
|
|
||||
|
# System call pointer variable name. |
||||
|
my $sysvarname = "proc$sysname"; |
||||
|
|
||||
|
my $strconvfunc = "BytePtrFromString"; |
||||
|
my $strconvtype = "*byte"; |
||||
|
|
||||
|
$sysname =~ y/A-Z/a-z/; # All libc functions are lowercase. |
||||
|
|
||||
|
# Runtime import of function to allow cross-platform builds. |
||||
|
$dynimports .= "//go:cgo_import_dynamic libc_${sysname} ${sysname} \"$modname.so\"\n"; |
||||
|
# Link symbol to proc address variable. |
||||
|
$linknames .= "//go:linkname ${sysvarname} libc_${sysname}\n"; |
||||
|
# Library proc address variable. |
||||
|
push @vars, $sysvarname; |
||||
|
|
||||
|
# Go function header. |
||||
|
$out = join(', ', @out); |
||||
|
if($out ne "") { |
||||
|
$out = " ($out)"; |
||||
|
} |
||||
|
if($text ne "") { |
||||
|
$text .= "\n" |
||||
|
} |
||||
|
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out; |
||||
|
|
||||
|
# Check if err return available |
||||
|
my $errvar = ""; |
||||
|
foreach my $p (@out) { |
||||
|
my ($name, $type) = parseparam($p); |
||||
|
if($type eq "error") { |
||||
|
$errvar = $name; |
||||
|
last; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
# Prepare arguments to Syscall. |
||||
|
my @args = (); |
||||
|
my $n = 0; |
||||
|
foreach my $p (@in) { |
||||
|
my ($name, $type) = parseparam($p); |
||||
|
if($type =~ /^\*/) { |
||||
|
push @args, "uintptr(unsafe.Pointer($name))"; |
||||
|
} elsif($type eq "string" && $errvar ne "") { |
||||
|
$text .= "\tvar _p$n $strconvtype\n"; |
||||
|
$text .= "\t_p$n, $errvar = $strconvfunc($name)\n"; |
||||
|
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; |
||||
|
push @args, "uintptr(unsafe.Pointer(_p$n))"; |
||||
|
$n++; |
||||
|
} elsif($type eq "string") { |
||||
|
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; |
||||
|
$text .= "\tvar _p$n $strconvtype\n"; |
||||
|
$text .= "\t_p$n, _ = $strconvfunc($name)\n"; |
||||
|
push @args, "uintptr(unsafe.Pointer(_p$n))"; |
||||
|
$n++; |
||||
|
} elsif($type =~ /^\[\](.*)/) { |
||||
|
# 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 .= "\tvar _p$n *$1\n"; |
||||
|
$text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n"; |
||||
|
push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))"; |
||||
|
$n++; |
||||
|
} elsif($type eq "int64" && $_32bit ne "") { |
||||
|
if($_32bit eq "big-endian") { |
||||
|
push @args, "uintptr($name >> 32)", "uintptr($name)"; |
||||
|
} else { |
||||
|
push @args, "uintptr($name)", "uintptr($name >> 32)"; |
||||
|
} |
||||
|
} elsif($type eq "bool") { |
||||
|
$text .= "\tvar _p$n uint32\n"; |
||||
|
$text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n"; |
||||
|
push @args, "uintptr(_p$n)"; |
||||
|
$n++; |
||||
|
} else { |
||||
|
push @args, "uintptr($name)"; |
||||
|
} |
||||
|
} |
||||
|
my $nargs = @args; |
||||
|
|
||||
|
# Determine which form to use; pad args with zeros. |
||||
|
my $asm = "sysvicall6"; |
||||
|
if ($nonblock) { |
||||
|
$asm = "rawSysvicall6"; |
||||
|
} |
||||
|
if(@args <= 6) { |
||||
|
while(@args < 6) { |
||||
|
push @args, "0"; |
||||
|
} |
||||
|
} else { |
||||
|
print STDERR "$ARGV:$.: too many arguments to system call\n"; |
||||
|
} |
||||
|
|
||||
|
# Actual call. |
||||
|
my $args = join(', ', @args); |
||||
|
my $call = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $args)"; |
||||
|
|
||||
|
# Assign return values. |
||||
|
my $body = ""; |
||||
|
my $failexpr = ""; |
||||
|
my @ret = ("_", "_", "_"); |
||||
|
my @pout= (); |
||||
|
my $do_errno = 0; |
||||
|
for(my $i=0; $i<@out; $i++) { |
||||
|
my $p = $out[$i]; |
||||
|
my ($name, $type) = parseparam($p); |
||||
|
my $reg = ""; |
||||
|
if($name eq "err") { |
||||
|
$reg = "e1"; |
||||
|
$ret[2] = $reg; |
||||
|
$do_errno = 1; |
||||
|
} else { |
||||
|
$reg = sprintf("r%d", $i); |
||||
|
$ret[$i] = $reg; |
||||
|
} |
||||
|
if($type eq "bool") { |
||||
|
$reg = "$reg != 0"; |
||||
|
} |
||||
|
if($type eq "int64" && $_32bit ne "") { |
||||
|
# 64-bit number in r1:r0 or r0:r1. |
||||
|
if($i+2 > @out) { |
||||
|
print STDERR "$ARGV:$.: not enough registers for int64 return\n"; |
||||
|
} |
||||
|
if($_32bit eq "big-endian") { |
||||
|
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1); |
||||
|
} else { |
||||
|
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i); |
||||
|
} |
||||
|
$ret[$i] = sprintf("r%d", $i); |
||||
|
$ret[$i+1] = sprintf("r%d", $i+1); |
||||
|
} |
||||
|
if($reg ne "e1") { |
||||
|
$body .= "\t$name = $type($reg)\n"; |
||||
|
} |
||||
|
} |
||||
|
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") { |
||||
|
$text .= "\t$call\n"; |
||||
|
} else { |
||||
|
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; |
||||
|
} |
||||
|
$text .= $body; |
||||
|
|
||||
|
if ($do_errno) { |
||||
|
$text .= "\tif e1 != 0 {\n"; |
||||
|
$text .= "\t\terr = e1\n"; |
||||
|
$text .= "\t}\n"; |
||||
|
} |
||||
|
$text .= "\treturn\n"; |
||||
|
$text .= "}\n"; |
||||
|
} |
||||
|
|
||||
|
if($errors) { |
||||
|
exit 1; |
||||
|
} |
||||
|
|
||||
|
print <<EOF; |
||||
|
// $cmdline |
||||
|
// Code generated by the command above; see README.md. DO NOT EDIT. |
||||
|
|
||||
|
// +build $tags |
||||
|
|
||||
|
package $package |
||||
|
|
||||
|
import ( |
||||
|
"syscall" |
||||
|
"unsafe" |
||||
|
) |
||||
|
EOF |
||||
|
|
||||
|
print "import \"golang.org/x/sys/unix\"\n" if $package ne "unix"; |
||||
|
|
||||
|
my $vardecls = "\t" . join(",\n\t", @vars); |
||||
|
$vardecls .= " syscallFunc"; |
||||
|
|
||||
|
chomp($_=<<EOF); |
||||
|
|
||||
|
$dynimports |
||||
|
$linknames |
||||
|
var ( |
||||
|
$vardecls |
||||
|
) |
||||
|
|
||||
|
$text |
||||
|
EOF |
||||
|
print $_; |
||||
|
exit 0; |
@ -0,0 +1,264 @@ |
|||||
|
#!/usr/bin/env perl |
||||
|
|
||||
|
# 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. |
||||
|
|
||||
|
# |
||||
|
# 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. |
||||
|
# |
||||
|
|
||||
|
use strict; |
||||
|
|
||||
|
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
||||
|
print STDERR "GOARCH or GOOS not defined in environment\n"; |
||||
|
exit 1; |
||||
|
} |
||||
|
|
||||
|
my $debug = 0; |
||||
|
my %ctls = (); |
||||
|
|
||||
|
my @headers = qw ( |
||||
|
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/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 |
||||
|
); |
||||
|
|
||||
|
my @ctls = qw ( |
||||
|
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" |
||||
|
my %ctl_map = ( |
||||
|
"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 |
||||
|
my %node_map = ( |
||||
|
"net.inet.ip.ifq" => "net.ifq", |
||||
|
"net.inet.pfsync" => "net.pfsync", |
||||
|
"net.mpls.ifq" => "net.ifq" |
||||
|
); |
||||
|
|
||||
|
my $ctlname; |
||||
|
my %mib = (); |
||||
|
my %sysctl = (); |
||||
|
my $node; |
||||
|
|
||||
|
sub debug() { |
||||
|
print STDERR "$_[0]\n" if $debug; |
||||
|
} |
||||
|
|
||||
|
# Walk the MIB and build a sysctl name to OID mapping. |
||||
|
sub build_sysctl() { |
||||
|
my ($node, $name, $oid) = @_; |
||||
|
my %node = %{$node}; |
||||
|
my @oid = @{$oid}; |
||||
|
|
||||
|
foreach my $key (sort keys %node) { |
||||
|
my @node = @{$node{$key}}; |
||||
|
my $nodename = $name.($name ne '' ? '.' : '').$key; |
||||
|
my @nodeoid = (@oid, $node[0]); |
||||
|
if ($node[1] eq 'CTLTYPE_NODE') { |
||||
|
if (exists $node_map{$nodename}) { |
||||
|
$node = \%mib; |
||||
|
$ctlname = $node_map{$nodename}; |
||||
|
foreach my $part (split /\./, $ctlname) { |
||||
|
$node = \%{@{$$node{$part}}[2]}; |
||||
|
} |
||||
|
} else { |
||||
|
$node = $node[2]; |
||||
|
} |
||||
|
&build_sysctl($node, $nodename, \@nodeoid); |
||||
|
} elsif ($node[1] ne '') { |
||||
|
$sysctl{$nodename} = \@nodeoid; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
foreach my $ctl (@ctls) { |
||||
|
$ctls{$ctl} = $ctl; |
||||
|
} |
||||
|
|
||||
|
# Build MIB |
||||
|
foreach my $header (@headers) { |
||||
|
&debug("Processing $header..."); |
||||
|
open HEADER, "/usr/include/$header" || |
||||
|
print STDERR "Failed to open $header\n"; |
||||
|
while (<HEADER>) { |
||||
|
if ($_ =~ /^#define\s+(CTL_NAMES)\s+{/ || |
||||
|
$_ =~ /^#define\s+(CTL_(.*)_NAMES)\s+{/ || |
||||
|
$_ =~ /^#define\s+((.*)CTL_NAMES)\s+{/) { |
||||
|
if ($1 eq 'CTL_NAMES') { |
||||
|
# Top level. |
||||
|
$node = \%mib; |
||||
|
} else { |
||||
|
# Node. |
||||
|
my $nodename = lc($2); |
||||
|
if ($header =~ /^netinet\//) { |
||||
|
$ctlname = "net.inet.$nodename"; |
||||
|
} elsif ($header =~ /^netinet6\//) { |
||||
|
$ctlname = "net.inet6.$nodename"; |
||||
|
} elsif ($header =~ /^net\//) { |
||||
|
$ctlname = "net.$nodename"; |
||||
|
} else { |
||||
|
$ctlname = "$nodename"; |
||||
|
$ctlname =~ s/^(fs|net|kern)_/$1\./; |
||||
|
} |
||||
|
if (exists $ctl_map{$ctlname}) { |
||||
|
$ctlname = $ctl_map{$ctlname}; |
||||
|
} |
||||
|
if (not exists $ctls{$ctlname}) { |
||||
|
&debug("Ignoring $ctlname..."); |
||||
|
next; |
||||
|
} |
||||
|
|
||||
|
# Walk down from the top of the MIB. |
||||
|
$node = \%mib; |
||||
|
foreach my $part (split /\./, $ctlname) { |
||||
|
if (not exists $$node{$part}) { |
||||
|
&debug("Missing node $part"); |
||||
|
$$node{$part} = [ 0, '', {} ]; |
||||
|
} |
||||
|
$node = \%{@{$$node{$part}}[2]}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
# Populate current node with entries. |
||||
|
my $i = -1; |
||||
|
while (defined($_) && $_ !~ /^}/) { |
||||
|
$_ = <HEADER>; |
||||
|
$i++ if $_ =~ /{.*}/; |
||||
|
next if $_ !~ /{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}/; |
||||
|
$$node{$1} = [ $i, $2, {} ]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
close HEADER; |
||||
|
} |
||||
|
|
||||
|
&build_sysctl(\%mib, "", []); |
||||
|
|
||||
|
print <<EOF; |
||||
|
// mksysctl_openbsd.pl |
||||
|
// Code generated by the command above; DO NOT EDIT. |
||||
|
|
||||
|
// +build $ENV{'GOARCH'},$ENV{'GOOS'} |
||||
|
|
||||
|
package unix; |
||||
|
|
||||
|
type mibentry struct { |
||||
|
ctlname string |
||||
|
ctloid []_C_int |
||||
|
} |
||||
|
|
||||
|
var sysctlMib = []mibentry { |
||||
|
EOF |
||||
|
|
||||
|
foreach my $name (sort keys %sysctl) { |
||||
|
my @oid = @{$sysctl{$name}}; |
||||
|
print "\t{ \"$name\", []_C_int{ ", join(', ', @oid), " } }, \n"; |
||||
|
} |
||||
|
|
||||
|
print <<EOF; |
||||
|
} |
||||
|
EOF |
@ -0,0 +1,39 @@ |
|||||
|
#!/usr/bin/env perl |
||||
|
# 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. |
||||
|
# |
||||
|
# Generate system call table for Darwin from sys/syscall.h |
||||
|
|
||||
|
use strict; |
||||
|
|
||||
|
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
||||
|
print STDERR "GOARCH or GOOS not defined in environment\n"; |
||||
|
exit 1; |
||||
|
} |
||||
|
|
||||
|
my $command = "mksysnum_darwin.pl " . join(' ', @ARGV); |
||||
|
|
||||
|
print <<EOF; |
||||
|
// $command |
||||
|
// Code generated by the command above; see README.md. DO NOT EDIT. |
||||
|
|
||||
|
// +build $ENV{'GOARCH'},$ENV{'GOOS'} |
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
const ( |
||||
|
EOF |
||||
|
|
||||
|
while(<>){ |
||||
|
if(/^#define\s+SYS_(\w+)\s+([0-9]+)/){ |
||||
|
my $name = $1; |
||||
|
my $num = $2; |
||||
|
$name =~ y/a-z/A-Z/; |
||||
|
print " SYS_$name = $num;" |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
print <<EOF; |
||||
|
) |
||||
|
EOF |
@ -0,0 +1,50 @@ |
|||||
|
#!/usr/bin/env perl |
||||
|
# 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. |
||||
|
# |
||||
|
# Generate system call table for DragonFly from master list |
||||
|
# (for example, /usr/src/sys/kern/syscalls.master). |
||||
|
|
||||
|
use strict; |
||||
|
|
||||
|
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
||||
|
print STDERR "GOARCH or GOOS not defined in environment\n"; |
||||
|
exit 1; |
||||
|
} |
||||
|
|
||||
|
my $command = "mksysnum_dragonfly.pl " . join(' ', @ARGV); |
||||
|
|
||||
|
print <<EOF; |
||||
|
// $command |
||||
|
// Code generated by the command above; see README.md. DO NOT EDIT. |
||||
|
|
||||
|
// +build $ENV{'GOARCH'},$ENV{'GOOS'} |
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
const ( |
||||
|
EOF |
||||
|
|
||||
|
while(<>){ |
||||
|
if(/^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$/){ |
||||
|
my $num = $1; |
||||
|
my $proto = $2; |
||||
|
my $name = "SYS_$3"; |
||||
|
$name =~ y/a-z/A-Z/; |
||||
|
|
||||
|
# There are multiple entries for enosys and nosys, so comment them out. |
||||
|
if($name =~ /^SYS_E?NOSYS$/){ |
||||
|
$name = "// $name"; |
||||
|
} |
||||
|
if($name eq 'SYS_SYS_EXIT'){ |
||||
|
$name = 'SYS_EXIT'; |
||||
|
} |
||||
|
|
||||
|
print " $name = $num; // $proto\n"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
print <<EOF; |
||||
|
) |
||||
|
EOF |
@ -0,0 +1,50 @@ |
|||||
|
#!/usr/bin/env perl |
||||
|
# 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. |
||||
|
# |
||||
|
# Generate system call table for FreeBSD from master list |
||||
|
# (for example, /usr/src/sys/kern/syscalls.master). |
||||
|
|
||||
|
use strict; |
||||
|
|
||||
|
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
||||
|
print STDERR "GOARCH or GOOS not defined in environment\n"; |
||||
|
exit 1; |
||||
|
} |
||||
|
|
||||
|
my $command = "mksysnum_freebsd.pl " . join(' ', @ARGV); |
||||
|
|
||||
|
print <<EOF; |
||||
|
// $command |
||||
|
// Code generated by the command above; see README.md. DO NOT EDIT. |
||||
|
|
||||
|
// +build $ENV{'GOARCH'},$ENV{'GOOS'} |
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
const ( |
||||
|
EOF |
||||
|
|
||||
|
while(<>){ |
||||
|
if(/^([0-9]+)\s+\S+\s+STD\s+({ \S+\s+(\w+).*)$/){ |
||||
|
my $num = $1; |
||||
|
my $proto = $2; |
||||
|
my $name = "SYS_$3"; |
||||
|
$name =~ y/a-z/A-Z/; |
||||
|
|
||||
|
# There are multiple entries for enosys and nosys, so comment them out. |
||||
|
if($name =~ /^SYS_E?NOSYS$/){ |
||||
|
$name = "// $name"; |
||||
|
} |
||||
|
if($name eq 'SYS_SYS_EXIT'){ |
||||
|
$name = 'SYS_EXIT'; |
||||
|
} |
||||
|
|
||||
|
print " $name = $num; // $proto\n"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
print <<EOF; |
||||
|
) |
||||
|
EOF |
@ -0,0 +1,58 @@ |
|||||
|
#!/usr/bin/env perl |
||||
|
# 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. |
||||
|
# |
||||
|
# Generate system call table for OpenBSD from master list |
||||
|
# (for example, /usr/src/sys/kern/syscalls.master). |
||||
|
|
||||
|
use strict; |
||||
|
|
||||
|
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
||||
|
print STDERR "GOARCH or GOOS not defined in environment\n"; |
||||
|
exit 1; |
||||
|
} |
||||
|
|
||||
|
my $command = "mksysnum_netbsd.pl " . join(' ', @ARGV); |
||||
|
|
||||
|
print <<EOF; |
||||
|
// $command |
||||
|
// Code generated by the command above; see README.md. DO NOT EDIT. |
||||
|
|
||||
|
// +build $ENV{'GOARCH'},$ENV{'GOOS'} |
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
const ( |
||||
|
EOF |
||||
|
|
||||
|
my $line = ''; |
||||
|
while(<>){ |
||||
|
if($line =~ /^(.*)\\$/) { |
||||
|
# Handle continuation |
||||
|
$line = $1; |
||||
|
$_ =~ s/^\s+//; |
||||
|
$line .= $_; |
||||
|
} else { |
||||
|
# New line |
||||
|
$line = $_; |
||||
|
} |
||||
|
next if $line =~ /\\$/; |
||||
|
if($line =~ /^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$/) { |
||||
|
my $num = $1; |
||||
|
my $proto = $6; |
||||
|
my $compat = $8; |
||||
|
my $name = "$7_$9"; |
||||
|
|
||||
|
$name = "$7_$11" if $11 ne ''; |
||||
|
$name =~ y/a-z/A-Z/; |
||||
|
|
||||
|
if($compat eq '' || $compat eq '13' || $compat eq '30' || $compat eq '50') { |
||||
|
print " $name = $num; // $proto\n"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
print <<EOF; |
||||
|
) |
||||
|
EOF |
@ -0,0 +1,50 @@ |
|||||
|
#!/usr/bin/env perl |
||||
|
# 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. |
||||
|
# |
||||
|
# Generate system call table for OpenBSD from master list |
||||
|
# (for example, /usr/src/sys/kern/syscalls.master). |
||||
|
|
||||
|
use strict; |
||||
|
|
||||
|
if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
||||
|
print STDERR "GOARCH or GOOS not defined in environment\n"; |
||||
|
exit 1; |
||||
|
} |
||||
|
|
||||
|
my $command = "mksysnum_openbsd.pl " . join(' ', @ARGV); |
||||
|
|
||||
|
print <<EOF; |
||||
|
// $command |
||||
|
// Code generated by the command above; see README.md. DO NOT EDIT. |
||||
|
|
||||
|
// +build $ENV{'GOARCH'},$ENV{'GOOS'} |
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
const ( |
||||
|
EOF |
||||
|
|
||||
|
while(<>){ |
||||
|
if(/^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$/){ |
||||
|
my $num = $1; |
||||
|
my $proto = $3; |
||||
|
my $name = $4; |
||||
|
$name =~ y/a-z/A-Z/; |
||||
|
|
||||
|
# There are multiple entries for enosys and nosys, so comment them out. |
||||
|
if($name =~ /^SYS_E?NOSYS$/){ |
||||
|
$name = "// $name"; |
||||
|
} |
||||
|
if($name eq 'SYS_SYS_EXIT'){ |
||||
|
$name = 'SYS_EXIT'; |
||||
|
} |
||||
|
|
||||
|
print " $name = $num; // $proto\n"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
print <<EOF; |
||||
|
) |
||||
|
EOF |
@ -0,0 +1,38 @@ |
|||||
|
// 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 openbsd
|
||||
|
// +build 386 amd64 arm
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import ( |
||||
|
"syscall" |
||||
|
"unsafe" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
_SYS_PLEDGE = 108 |
||||
|
) |
||||
|
|
||||
|
// Pledge implements the pledge syscall. For more information see pledge(2).
|
||||
|
func Pledge(promises string, paths []string) error { |
||||
|
promisesPtr, err := syscall.BytePtrFromString(promises) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
promisesUnsafe, pathsUnsafe := unsafe.Pointer(promisesPtr), unsafe.Pointer(nil) |
||||
|
if paths != nil { |
||||
|
var pathsPtr []*byte |
||||
|
if pathsPtr, err = syscall.SlicePtrFromStrings(paths); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
pathsUnsafe = unsafe.Pointer(&pathsPtr[0]) |
||||
|
} |
||||
|
_, _, e := syscall.Syscall(_SYS_PLEDGE, uintptr(promisesUnsafe), uintptr(pathsUnsafe), 0) |
||||
|
if e != 0 { |
||||
|
return e |
||||
|
} |
||||
|
return nil |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
// Copyright 2017 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 darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
|
||||
|
// For Unix, get the pagesize from the runtime.
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import "syscall" |
||||
|
|
||||
|
func Getpagesize() int { |
||||
|
return syscall.Getpagesize() |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
// Copyright 2012 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 darwin,race linux,race freebsd,race
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import ( |
||||
|
"runtime" |
||||
|
"unsafe" |
||||
|
) |
||||
|
|
||||
|
const raceenabled = true |
||||
|
|
||||
|
func raceAcquire(addr unsafe.Pointer) { |
||||
|
runtime.RaceAcquire(addr) |
||||
|
} |
||||
|
|
||||
|
func raceReleaseMerge(addr unsafe.Pointer) { |
||||
|
runtime.RaceReleaseMerge(addr) |
||||
|
} |
||||
|
|
||||
|
func raceReadRange(addr unsafe.Pointer, len int) { |
||||
|
runtime.RaceReadRange(addr, len) |
||||
|
} |
||||
|
|
||||
|
func raceWriteRange(addr unsafe.Pointer, len int) { |
||||
|
runtime.RaceWriteRange(addr, len) |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
// Copyright 2012 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 darwin,!race linux,!race freebsd,!race netbsd openbsd solaris dragonfly
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import ( |
||||
|
"unsafe" |
||||
|
) |
||||
|
|
||||
|
const raceenabled = false |
||||
|
|
||||
|
func raceAcquire(addr unsafe.Pointer) { |
||||
|
} |
||||
|
|
||||
|
func raceReleaseMerge(addr unsafe.Pointer) { |
||||
|
} |
||||
|
|
||||
|
func raceReadRange(addr unsafe.Pointer, len int) { |
||||
|
} |
||||
|
|
||||
|
func raceWriteRange(addr unsafe.Pointer, len int) { |
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
// 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.
|
||||
|
|
||||
|
// Socket control messages
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import "unsafe" |
||||
|
|
||||
|
// UnixCredentials encodes credentials into a socket control message
|
||||
|
// for sending to another process. This can be used for
|
||||
|
// authentication.
|
||||
|
func UnixCredentials(ucred *Ucred) []byte { |
||||
|
b := make([]byte, CmsgSpace(SizeofUcred)) |
||||
|
h := (*Cmsghdr)(unsafe.Pointer(&b[0])) |
||||
|
h.Level = SOL_SOCKET |
||||
|
h.Type = SCM_CREDENTIALS |
||||
|
h.SetLen(CmsgLen(SizeofUcred)) |
||||
|
*((*Ucred)(cmsgData(h))) = *ucred |
||||
|
return b |
||||
|
} |
||||
|
|
||||
|
// ParseUnixCredentials decodes a socket control message that contains
|
||||
|
// credentials in a Ucred structure. To receive such a message, the
|
||||
|
// SO_PASSCRED option must be enabled on the socket.
|
||||
|
func ParseUnixCredentials(m *SocketControlMessage) (*Ucred, error) { |
||||
|
if m.Header.Level != SOL_SOCKET { |
||||
|
return nil, EINVAL |
||||
|
} |
||||
|
if m.Header.Type != SCM_CREDENTIALS { |
||||
|
return nil, EINVAL |
||||
|
} |
||||
|
ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0])) |
||||
|
return &ucred, nil |
||||
|
} |
@ -0,0 +1,104 @@ |
|||||
|
// 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 darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
|
||||
|
// Socket control messages
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import "unsafe" |
||||
|
|
||||
|
// Round the length of a raw sockaddr up to align it properly.
|
||||
|
func cmsgAlignOf(salen int) int { |
||||
|
salign := sizeofPtr |
||||
|
// NOTE: It seems like 64-bit Darwin, DragonFly BSD and
|
||||
|
// Solaris kernels still require 32-bit aligned access to
|
||||
|
// network subsystem.
|
||||
|
if darwin64Bit || dragonfly64Bit || solaris64Bit { |
||||
|
salign = 4 |
||||
|
} |
||||
|
return (salen + salign - 1) & ^(salign - 1) |
||||
|
} |
||||
|
|
||||
|
// CmsgLen returns the value to store in the Len field of the Cmsghdr
|
||||
|
// structure, taking into account any necessary alignment.
|
||||
|
func CmsgLen(datalen int) int { |
||||
|
return cmsgAlignOf(SizeofCmsghdr) + datalen |
||||
|
} |
||||
|
|
||||
|
// CmsgSpace returns the number of bytes an ancillary element with
|
||||
|
// payload of the passed data length occupies.
|
||||
|
func CmsgSpace(datalen int) int { |
||||
|
return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen) |
||||
|
} |
||||
|
|
||||
|
func cmsgData(h *Cmsghdr) unsafe.Pointer { |
||||
|
return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr))) |
||||
|
} |
||||
|
|
||||
|
// SocketControlMessage represents a socket control message.
|
||||
|
type SocketControlMessage struct { |
||||
|
Header Cmsghdr |
||||
|
Data []byte |
||||
|
} |
||||
|
|
||||
|
// ParseSocketControlMessage parses b as an array of socket control
|
||||
|
// messages.
|
||||
|
func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) { |
||||
|
var msgs []SocketControlMessage |
||||
|
i := 0 |
||||
|
for i+CmsgLen(0) <= len(b) { |
||||
|
h, dbuf, err := socketControlMessageHeaderAndData(b[i:]) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
m := SocketControlMessage{Header: *h, Data: dbuf} |
||||
|
msgs = append(msgs, m) |
||||
|
i += cmsgAlignOf(int(h.Len)) |
||||
|
} |
||||
|
return msgs, nil |
||||
|
} |
||||
|
|
||||
|
func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) { |
||||
|
h := (*Cmsghdr)(unsafe.Pointer(&b[0])) |
||||
|
if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) { |
||||
|
return nil, nil, EINVAL |
||||
|
} |
||||
|
return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil |
||||
|
} |
||||
|
|
||||
|
// UnixRights encodes a set of open file descriptors into a socket
|
||||
|
// control message for sending to another process.
|
||||
|
func UnixRights(fds ...int) []byte { |
||||
|
datalen := len(fds) * 4 |
||||
|
b := make([]byte, CmsgSpace(datalen)) |
||||
|
h := (*Cmsghdr)(unsafe.Pointer(&b[0])) |
||||
|
h.Level = SOL_SOCKET |
||||
|
h.Type = SCM_RIGHTS |
||||
|
h.SetLen(CmsgLen(datalen)) |
||||
|
data := cmsgData(h) |
||||
|
for _, fd := range fds { |
||||
|
*(*int32)(data) = int32(fd) |
||||
|
data = unsafe.Pointer(uintptr(data) + 4) |
||||
|
} |
||||
|
return b |
||||
|
} |
||||
|
|
||||
|
// ParseUnixRights decodes a socket control message that contains an
|
||||
|
// integer array of open file descriptors from another process.
|
||||
|
func ParseUnixRights(m *SocketControlMessage) ([]int, error) { |
||||
|
if m.Header.Level != SOL_SOCKET { |
||||
|
return nil, EINVAL |
||||
|
} |
||||
|
if m.Header.Type != SCM_RIGHTS { |
||||
|
return nil, EINVAL |
||||
|
} |
||||
|
fds := make([]int, len(m.Data)>>2) |
||||
|
for i, j := 0, 0; i < len(m.Data); i += 4 { |
||||
|
fds[j] = int(*(*int32)(unsafe.Pointer(&m.Data[i]))) |
||||
|
j++ |
||||
|
} |
||||
|
return fds, nil |
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
// 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 darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
|
||||
|
if val < 0 { |
||||
|
return "-" + uitoa(uint(-val)) |
||||
|
} |
||||
|
return uitoa(uint(val)) |
||||
|
} |
||||
|
|
||||
|
func uitoa(val uint) string { |
||||
|
var buf [32]byte // big enough for int64
|
||||
|
i := len(buf) - 1 |
||||
|
for val >= 10 { |
||||
|
buf[i] = byte(val%10 + '0') |
||||
|
i-- |
||||
|
val /= 10 |
||||
|
} |
||||
|
buf[i] = byte(val + '0') |
||||
|
return string(buf[i:]) |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
// 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 darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
|
||||
|
// Package unix contains an interface to the low-level operating system
|
||||
|
// primitives. OS details vary depending on the underlying system, and
|
||||
|
// by default, godoc will display OS-specific documentation for the current
|
||||
|
// system. If you want godoc to display OS documentation for another
|
||||
|
// system, set $GOOS and $GOARCH to the desired system. For example, if
|
||||
|
// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
|
||||
|
// to freebsd and $GOARCH to arm.
|
||||
|
//
|
||||
|
// The primary use of this package is inside other packages that provide a more
|
||||
|
// portable interface to the system, such as "os", "time" and "net". Use
|
||||
|
// those packages rather than this one if you can.
|
||||
|
//
|
||||
|
// For details of the functions and data types in this package consult
|
||||
|
// the manuals for the appropriate operating system.
|
||||
|
//
|
||||
|
// These calls return err == nil to indicate success; otherwise
|
||||
|
// err represents an operating system error describing the failure and
|
||||
|
// holds a value of type syscall.Errno.
|
||||
|
package unix // import "golang.org/x/sys/unix"
|
||||
|
|
||||
|
import "strings" |
||||
|
|
||||
|
// ByteSliceFromString returns a NUL-terminated slice of bytes
|
||||
|
// containing the text of s. If s contains a NUL byte at any
|
||||
|
// location, it returns (nil, EINVAL).
|
||||
|
func ByteSliceFromString(s string) ([]byte, error) { |
||||
|
if strings.IndexByte(s, 0) != -1 { |
||||
|
return nil, EINVAL |
||||
|
} |
||||
|
a := make([]byte, len(s)+1) |
||||
|
copy(a, s) |
||||
|
return a, nil |
||||
|
} |
||||
|
|
||||
|
// BytePtrFromString returns a pointer to a NUL-terminated array of
|
||||
|
// bytes containing the text of s. If s contains a NUL byte at any
|
||||
|
// location, it returns (nil, EINVAL).
|
||||
|
func BytePtrFromString(s string) (*byte, error) { |
||||
|
a, err := ByteSliceFromString(s) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
return &a[0], nil |
||||
|
} |
||||
|
|
||||
|
// Single-word zero for use when we need a valid pointer to 0 bytes.
|
||||
|
// See mkunix.pl.
|
||||
|
var _zero uintptr |
@ -0,0 +1,624 @@ |
|||||
|
// 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 darwin dragonfly freebsd netbsd openbsd
|
||||
|
|
||||
|
// BSD system call wrappers shared by *BSD based systems
|
||||
|
// including OS X (Darwin) and FreeBSD. Like the other
|
||||
|
// syscall_*.go files it is compiled as Go code but also
|
||||
|
// used as input to mksyscall which parses the //sys
|
||||
|
// lines and generates system call stubs.
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import ( |
||||
|
"runtime" |
||||
|
"syscall" |
||||
|
"unsafe" |
||||
|
) |
||||
|
|
||||
|
/* |
||||
|
* Wrapped |
||||
|
*/ |
||||
|
|
||||
|
//sysnb getgroups(ngid int, gid *_Gid_t) (n int, err error)
|
||||
|
//sysnb setgroups(ngid int, gid *_Gid_t) (err error)
|
||||
|
|
||||
|
func Getgroups() (gids []int, err error) { |
||||
|
n, err := getgroups(0, nil) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if n == 0 { |
||||
|
return nil, nil |
||||
|
} |
||||
|
|
||||
|
// Sanity check group count. Max is 16 on BSD.
|
||||
|
if n < 0 || n > 1000 { |
||||
|
return nil, EINVAL |
||||
|
} |
||||
|
|
||||
|
a := make([]_Gid_t, n) |
||||
|
n, err = getgroups(n, &a[0]) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
gids = make([]int, n) |
||||
|
for i, v := range a[0:n] { |
||||
|
gids[i] = int(v) |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func Setgroups(gids []int) (err error) { |
||||
|
if len(gids) == 0 { |
||||
|
return setgroups(0, nil) |
||||
|
} |
||||
|
|
||||
|
a := make([]_Gid_t, len(gids)) |
||||
|
for i, v := range gids { |
||||
|
a[i] = _Gid_t(v) |
||||
|
} |
||||
|
return setgroups(len(a), &a[0]) |
||||
|
} |
||||
|
|
||||
|
func ReadDirent(fd int, buf []byte) (n int, err error) { |
||||
|
// Final argument is (basep *uintptr) and the syscall doesn't take nil.
|
||||
|
// 64 bits should be enough. (32 bits isn't even on 386). Since the
|
||||
|
// actual system call is getdirentries64, 64 is a good guess.
|
||||
|
// TODO(rsc): Can we use a single global basep for all calls?
|
||||
|
var base = (*uintptr)(unsafe.Pointer(new(uint64))) |
||||
|
return Getdirentries(fd, buf, base) |
||||
|
} |
||||
|
|
||||
|
// Wait status is 7 bits at bottom, either 0 (exited),
|
||||
|
// 0x7F (stopped), or a signal number that caused an exit.
|
||||
|
// The 0x80 bit is whether there was a core dump.
|
||||
|
// An extra number (exit code, signal causing a stop)
|
||||
|
// is in the high bits.
|
||||
|
|
||||
|
type WaitStatus uint32 |
||||
|
|
||||
|
const ( |
||||
|
mask = 0x7F |
||||
|
core = 0x80 |
||||
|
shift = 8 |
||||
|
|
||||
|
exited = 0 |
||||
|
stopped = 0x7F |
||||
|
) |
||||
|
|
||||
|
func (w WaitStatus) Exited() bool { return w&mask == exited } |
||||
|
|
||||
|
func (w WaitStatus) ExitStatus() int { |
||||
|
if w&mask != exited { |
||||
|
return -1 |
||||
|
} |
||||
|
return int(w >> shift) |
||||
|
} |
||||
|
|
||||
|
func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != 0 } |
||||
|
|
||||
|
func (w WaitStatus) Signal() syscall.Signal { |
||||
|
sig := syscall.Signal(w & mask) |
||||
|
if sig == stopped || sig == 0 { |
||||
|
return -1 |
||||
|
} |
||||
|
return sig |
||||
|
} |
||||
|
|
||||
|
func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 } |
||||
|
|
||||
|
func (w WaitStatus) Stopped() bool { return w&mask == stopped && syscall.Signal(w>>shift) != SIGSTOP } |
||||
|
|
||||
|
func (w WaitStatus) Continued() bool { return w&mask == stopped && syscall.Signal(w>>shift) == SIGSTOP } |
||||
|
|
||||
|
func (w WaitStatus) StopSignal() syscall.Signal { |
||||
|
if !w.Stopped() { |
||||
|
return -1 |
||||
|
} |
||||
|
return syscall.Signal(w>>shift) & 0xFF |
||||
|
} |
||||
|
|
||||
|
func (w WaitStatus) TrapCause() int { return -1 } |
||||
|
|
||||
|
//sys wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error)
|
||||
|
|
||||
|
func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) { |
||||
|
var status _C_int |
||||
|
wpid, err = wait4(pid, &status, options, rusage) |
||||
|
if wstatus != nil { |
||||
|
*wstatus = WaitStatus(status) |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
|
||||
|
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
|
//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
|
//sysnb socket(domain int, typ int, proto int) (fd int, err error)
|
||||
|
//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
|
||||
|
//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
|
||||
|
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
|
||||
|
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
|
||||
|
//sys Shutdown(s int, how int) (err error)
|
||||
|
|
||||
|
func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { |
||||
|
if sa.Port < 0 || sa.Port > 0xFFFF { |
||||
|
return nil, 0, EINVAL |
||||
|
} |
||||
|
sa.raw.Len = SizeofSockaddrInet4 |
||||
|
sa.raw.Family = AF_INET |
||||
|
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) |
||||
|
p[0] = byte(sa.Port >> 8) |
||||
|
p[1] = byte(sa.Port) |
||||
|
for i := 0; i < len(sa.Addr); i++ { |
||||
|
sa.raw.Addr[i] = sa.Addr[i] |
||||
|
} |
||||
|
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil |
||||
|
} |
||||
|
|
||||
|
func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { |
||||
|
if sa.Port < 0 || sa.Port > 0xFFFF { |
||||
|
return nil, 0, EINVAL |
||||
|
} |
||||
|
sa.raw.Len = SizeofSockaddrInet6 |
||||
|
sa.raw.Family = AF_INET6 |
||||
|
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) |
||||
|
p[0] = byte(sa.Port >> 8) |
||||
|
p[1] = byte(sa.Port) |
||||
|
sa.raw.Scope_id = sa.ZoneId |
||||
|
for i := 0; i < len(sa.Addr); i++ { |
||||
|
sa.raw.Addr[i] = sa.Addr[i] |
||||
|
} |
||||
|
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil |
||||
|
} |
||||
|
|
||||
|
func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) { |
||||
|
name := sa.Name |
||||
|
n := len(name) |
||||
|
if n >= len(sa.raw.Path) || n == 0 { |
||||
|
return nil, 0, EINVAL |
||||
|
} |
||||
|
sa.raw.Len = byte(3 + n) // 2 for Family, Len; 1 for NUL
|
||||
|
sa.raw.Family = AF_UNIX |
||||
|
for i := 0; i < n; i++ { |
||||
|
sa.raw.Path[i] = int8(name[i]) |
||||
|
} |
||||
|
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil |
||||
|
} |
||||
|
|
||||
|
func (sa *SockaddrDatalink) sockaddr() (unsafe.Pointer, _Socklen, error) { |
||||
|
if sa.Index == 0 { |
||||
|
return nil, 0, EINVAL |
||||
|
} |
||||
|
sa.raw.Len = sa.Len |
||||
|
sa.raw.Family = AF_LINK |
||||
|
sa.raw.Index = sa.Index |
||||
|
sa.raw.Type = sa.Type |
||||
|
sa.raw.Nlen = sa.Nlen |
||||
|
sa.raw.Alen = sa.Alen |
||||
|
sa.raw.Slen = sa.Slen |
||||
|
for i := 0; i < len(sa.raw.Data); i++ { |
||||
|
sa.raw.Data[i] = sa.Data[i] |
||||
|
} |
||||
|
return unsafe.Pointer(&sa.raw), SizeofSockaddrDatalink, nil |
||||
|
} |
||||
|
|
||||
|
func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { |
||||
|
switch rsa.Addr.Family { |
||||
|
case AF_LINK: |
||||
|
pp := (*RawSockaddrDatalink)(unsafe.Pointer(rsa)) |
||||
|
sa := new(SockaddrDatalink) |
||||
|
sa.Len = pp.Len |
||||
|
sa.Family = pp.Family |
||||
|
sa.Index = pp.Index |
||||
|
sa.Type = pp.Type |
||||
|
sa.Nlen = pp.Nlen |
||||
|
sa.Alen = pp.Alen |
||||
|
sa.Slen = pp.Slen |
||||
|
for i := 0; i < len(sa.Data); i++ { |
||||
|
sa.Data[i] = pp.Data[i] |
||||
|
} |
||||
|
return sa, nil |
||||
|
|
||||
|
case AF_UNIX: |
||||
|
pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa)) |
||||
|
if pp.Len < 2 || pp.Len > SizeofSockaddrUnix { |
||||
|
return nil, EINVAL |
||||
|
} |
||||
|
sa := new(SockaddrUnix) |
||||
|
|
||||
|
// Some BSDs include the trailing NUL in the length, whereas
|
||||
|
// others do not. Work around this by subtracting the leading
|
||||
|
// family and len. The path is then scanned to see if a NUL
|
||||
|
// terminator still exists within the length.
|
||||
|
n := int(pp.Len) - 2 // subtract leading Family, Len
|
||||
|
for i := 0; i < n; i++ { |
||||
|
if pp.Path[i] == 0 { |
||||
|
// found early NUL; assume Len included the NUL
|
||||
|
// or was overestimating.
|
||||
|
n = i |
||||
|
break |
||||
|
} |
||||
|
} |
||||
|
bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n] |
||||
|
sa.Name = string(bytes) |
||||
|
return sa, nil |
||||
|
|
||||
|
case AF_INET: |
||||
|
pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)) |
||||
|
sa := new(SockaddrInet4) |
||||
|
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) |
||||
|
sa.Port = int(p[0])<<8 + int(p[1]) |
||||
|
for i := 0; i < len(sa.Addr); i++ { |
||||
|
sa.Addr[i] = pp.Addr[i] |
||||
|
} |
||||
|
return sa, nil |
||||
|
|
||||
|
case AF_INET6: |
||||
|
pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)) |
||||
|
sa := new(SockaddrInet6) |
||||
|
p := (*[2]byte)(unsafe.Pointer(&pp.Port)) |
||||
|
sa.Port = int(p[0])<<8 + int(p[1]) |
||||
|
sa.ZoneId = pp.Scope_id |
||||
|
for i := 0; i < len(sa.Addr); i++ { |
||||
|
sa.Addr[i] = pp.Addr[i] |
||||
|
} |
||||
|
return sa, nil |
||||
|
} |
||||
|
return nil, EAFNOSUPPORT |
||||
|
} |
||||
|
|
||||
|
func Accept(fd int) (nfd int, sa Sockaddr, err error) { |
||||
|
var rsa RawSockaddrAny |
||||
|
var len _Socklen = SizeofSockaddrAny |
||||
|
nfd, err = accept(fd, &rsa, &len) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
if runtime.GOOS == "darwin" && len == 0 { |
||||
|
// Accepted socket has no address.
|
||||
|
// This is likely due to a bug in xnu kernels,
|
||||
|
// where instead of ECONNABORTED error socket
|
||||
|
// is accepted, but has no address.
|
||||
|
Close(nfd) |
||||
|
return 0, nil, ECONNABORTED |
||||
|
} |
||||
|
sa, err = anyToSockaddr(fd, &rsa) |
||||
|
if err != nil { |
||||
|
Close(nfd) |
||||
|
nfd = 0 |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func Getsockname(fd int) (sa Sockaddr, err error) { |
||||
|
var rsa RawSockaddrAny |
||||
|
var len _Socklen = SizeofSockaddrAny |
||||
|
if err = getsockname(fd, &rsa, &len); err != nil { |
||||
|
return |
||||
|
} |
||||
|
// TODO(jsing): DragonFly has a "bug" (see issue 3349), which should be
|
||||
|
// reported upstream.
|
||||
|
if runtime.GOOS == "dragonfly" && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 { |
||||
|
rsa.Addr.Family = AF_UNIX |
||||
|
rsa.Addr.Len = SizeofSockaddrUnix |
||||
|
} |
||||
|
return anyToSockaddr(fd, &rsa) |
||||
|
} |
||||
|
|
||||
|
//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
|
||||
|
|
||||
|
// GetsockoptString returns the string value of the socket option opt for the
|
||||
|
// socket associated with fd at the given socket level.
|
||||
|
func GetsockoptString(fd, level, opt int) (string, error) { |
||||
|
buf := make([]byte, 256) |
||||
|
vallen := _Socklen(len(buf)) |
||||
|
err := getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen) |
||||
|
if err != nil { |
||||
|
return "", err |
||||
|
} |
||||
|
return string(buf[:vallen-1]), nil |
||||
|
} |
||||
|
|
||||
|
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
|
||||
|
//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
|
||||
|
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
|
||||
|
|
||||
|
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) { |
||||
|
var msg Msghdr |
||||
|
var rsa RawSockaddrAny |
||||
|
msg.Name = (*byte)(unsafe.Pointer(&rsa)) |
||||
|
msg.Namelen = uint32(SizeofSockaddrAny) |
||||
|
var iov Iovec |
||||
|
if len(p) > 0 { |
||||
|
iov.Base = (*byte)(unsafe.Pointer(&p[0])) |
||||
|
iov.SetLen(len(p)) |
||||
|
} |
||||
|
var dummy byte |
||||
|
if len(oob) > 0 { |
||||
|
// receive at least one normal byte
|
||||
|
if len(p) == 0 { |
||||
|
iov.Base = &dummy |
||||
|
iov.SetLen(1) |
||||
|
} |
||||
|
msg.Control = (*byte)(unsafe.Pointer(&oob[0])) |
||||
|
msg.SetControllen(len(oob)) |
||||
|
} |
||||
|
msg.Iov = &iov |
||||
|
msg.Iovlen = 1 |
||||
|
if n, err = recvmsg(fd, &msg, flags); err != nil { |
||||
|
return |
||||
|
} |
||||
|
oobn = int(msg.Controllen) |
||||
|
recvflags = int(msg.Flags) |
||||
|
// source address is only specified if the socket is unconnected
|
||||
|
if rsa.Addr.Family != AF_UNSPEC { |
||||
|
from, err = anyToSockaddr(fd, &rsa) |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
|
||||
|
|
||||
|
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) { |
||||
|
_, err = SendmsgN(fd, p, oob, to, flags) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) { |
||||
|
var ptr unsafe.Pointer |
||||
|
var salen _Socklen |
||||
|
if to != nil { |
||||
|
ptr, salen, err = to.sockaddr() |
||||
|
if err != nil { |
||||
|
return 0, err |
||||
|
} |
||||
|
} |
||||
|
var msg Msghdr |
||||
|
msg.Name = (*byte)(unsafe.Pointer(ptr)) |
||||
|
msg.Namelen = uint32(salen) |
||||
|
var iov Iovec |
||||
|
if len(p) > 0 { |
||||
|
iov.Base = (*byte)(unsafe.Pointer(&p[0])) |
||||
|
iov.SetLen(len(p)) |
||||
|
} |
||||
|
var dummy byte |
||||
|
if len(oob) > 0 { |
||||
|
// send at least one normal byte
|
||||
|
if len(p) == 0 { |
||||
|
iov.Base = &dummy |
||||
|
iov.SetLen(1) |
||||
|
} |
||||
|
msg.Control = (*byte)(unsafe.Pointer(&oob[0])) |
||||
|
msg.SetControllen(len(oob)) |
||||
|
} |
||||
|
msg.Iov = &iov |
||||
|
msg.Iovlen = 1 |
||||
|
if n, err = sendmsg(fd, &msg, flags); err != nil { |
||||
|
return 0, err |
||||
|
} |
||||
|
if len(oob) > 0 && len(p) == 0 { |
||||
|
n = 0 |
||||
|
} |
||||
|
return n, nil |
||||
|
} |
||||
|
|
||||
|
//sys kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error)
|
||||
|
|
||||
|
func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, err error) { |
||||
|
var change, event unsafe.Pointer |
||||
|
if len(changes) > 0 { |
||||
|
change = unsafe.Pointer(&changes[0]) |
||||
|
} |
||||
|
if len(events) > 0 { |
||||
|
event = unsafe.Pointer(&events[0]) |
||||
|
} |
||||
|
return kevent(kq, change, len(changes), event, len(events), timeout) |
||||
|
} |
||||
|
|
||||
|
//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
|
||||
|
|
||||
|
// sysctlmib translates name to mib number and appends any additional args.
|
||||
|
func sysctlmib(name string, args ...int) ([]_C_int, error) { |
||||
|
// Translate name to mib number.
|
||||
|
mib, err := nametomib(name) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
for _, a := range args { |
||||
|
mib = append(mib, _C_int(a)) |
||||
|
} |
||||
|
|
||||
|
return mib, nil |
||||
|
} |
||||
|
|
||||
|
func Sysctl(name string) (string, error) { |
||||
|
return SysctlArgs(name) |
||||
|
} |
||||
|
|
||||
|
func SysctlArgs(name string, args ...int) (string, error) { |
||||
|
buf, err := SysctlRaw(name, args...) |
||||
|
if err != nil { |
||||
|
return "", err |
||||
|
} |
||||
|
n := len(buf) |
||||
|
|
||||
|
// Throw away terminating NUL.
|
||||
|
if n > 0 && buf[n-1] == '\x00' { |
||||
|
n-- |
||||
|
} |
||||
|
return string(buf[0:n]), nil |
||||
|
} |
||||
|
|
||||
|
func SysctlUint32(name string) (uint32, error) { |
||||
|
return SysctlUint32Args(name) |
||||
|
} |
||||
|
|
||||
|
func SysctlUint32Args(name string, args ...int) (uint32, error) { |
||||
|
mib, err := sysctlmib(name, args...) |
||||
|
if err != nil { |
||||
|
return 0, err |
||||
|
} |
||||
|
|
||||
|
n := uintptr(4) |
||||
|
buf := make([]byte, 4) |
||||
|
if err := sysctl(mib, &buf[0], &n, nil, 0); err != nil { |
||||
|
return 0, err |
||||
|
} |
||||
|
if n != 4 { |
||||
|
return 0, EIO |
||||
|
} |
||||
|
return *(*uint32)(unsafe.Pointer(&buf[0])), nil |
||||
|
} |
||||
|
|
||||
|
func SysctlUint64(name string, args ...int) (uint64, error) { |
||||
|
mib, err := sysctlmib(name, args...) |
||||
|
if err != nil { |
||||
|
return 0, err |
||||
|
} |
||||
|
|
||||
|
n := uintptr(8) |
||||
|
buf := make([]byte, 8) |
||||
|
if err := sysctl(mib, &buf[0], &n, nil, 0); err != nil { |
||||
|
return 0, err |
||||
|
} |
||||
|
if n != 8 { |
||||
|
return 0, EIO |
||||
|
} |
||||
|
return *(*uint64)(unsafe.Pointer(&buf[0])), nil |
||||
|
} |
||||
|
|
||||
|
func SysctlRaw(name string, args ...int) ([]byte, error) { |
||||
|
mib, err := sysctlmib(name, args...) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
// Find size.
|
||||
|
n := uintptr(0) |
||||
|
if err := sysctl(mib, nil, &n, nil, 0); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
if n == 0 { |
||||
|
return nil, nil |
||||
|
} |
||||
|
|
||||
|
// Read into buffer of that size.
|
||||
|
buf := make([]byte, n) |
||||
|
if err := sysctl(mib, &buf[0], &n, nil, 0); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
// The actual call may return less than the original reported required
|
||||
|
// size so ensure we deal with that.
|
||||
|
return buf[:n], nil |
||||
|
} |
||||
|
|
||||
|
//sys utimes(path string, timeval *[2]Timeval) (err error)
|
||||
|
|
||||
|
func Utimes(path string, tv []Timeval) error { |
||||
|
if tv == nil { |
||||
|
return utimes(path, nil) |
||||
|
} |
||||
|
if len(tv) != 2 { |
||||
|
return EINVAL |
||||
|
} |
||||
|
return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) |
||||
|
} |
||||
|
|
||||
|
func UtimesNano(path string, ts []Timespec) error { |
||||
|
if ts == nil { |
||||
|
err := utimensat(AT_FDCWD, path, nil, 0) |
||||
|
if err != ENOSYS { |
||||
|
return err |
||||
|
} |
||||
|
return utimes(path, nil) |
||||
|
} |
||||
|
if len(ts) != 2 { |
||||
|
return EINVAL |
||||
|
} |
||||
|
// Darwin setattrlist can set nanosecond timestamps
|
||||
|
err := setattrlistTimes(path, ts, 0) |
||||
|
if err != ENOSYS { |
||||
|
return err |
||||
|
} |
||||
|
err = utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) |
||||
|
if err != ENOSYS { |
||||
|
return err |
||||
|
} |
||||
|
// Not as efficient as it could be because Timespec and
|
||||
|
// Timeval have different types in the different OSes
|
||||
|
tv := [2]Timeval{ |
||||
|
NsecToTimeval(TimespecToNsec(ts[0])), |
||||
|
NsecToTimeval(TimespecToNsec(ts[1])), |
||||
|
} |
||||
|
return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) |
||||
|
} |
||||
|
|
||||
|
func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error { |
||||
|
if ts == nil { |
||||
|
return utimensat(dirfd, path, nil, flags) |
||||
|
} |
||||
|
if len(ts) != 2 { |
||||
|
return EINVAL |
||||
|
} |
||||
|
err := setattrlistTimes(path, ts, flags) |
||||
|
if err != ENOSYS { |
||||
|
return err |
||||
|
} |
||||
|
return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags) |
||||
|
} |
||||
|
|
||||
|
//sys futimes(fd int, timeval *[2]Timeval) (err error)
|
||||
|
|
||||
|
func Futimes(fd int, tv []Timeval) error { |
||||
|
if tv == nil { |
||||
|
return futimes(fd, nil) |
||||
|
} |
||||
|
if len(tv) != 2 { |
||||
|
return EINVAL |
||||
|
} |
||||
|
return futimes(fd, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) |
||||
|
} |
||||
|
|
||||
|
//sys fcntl(fd int, cmd int, arg int) (val int, err error)
|
||||
|
|
||||
|
//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error)
|
||||
|
|
||||
|
func Poll(fds []PollFd, timeout int) (n int, err error) { |
||||
|
if len(fds) == 0 { |
||||
|
return poll(nil, 0, timeout) |
||||
|
} |
||||
|
return poll(&fds[0], len(fds), timeout) |
||||
|
} |
||||
|
|
||||
|
// TODO: wrap
|
||||
|
// Acct(name nil-string) (err error)
|
||||
|
// Gethostuuid(uuid *byte, timeout *Timespec) (err error)
|
||||
|
// Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, err error)
|
||||
|
|
||||
|
var mapper = &mmapper{ |
||||
|
active: make(map[*byte][]byte), |
||||
|
mmap: mmap, |
||||
|
munmap: munmap, |
||||
|
} |
||||
|
|
||||
|
func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { |
||||
|
return mapper.Mmap(fd, offset, length, prot, flags) |
||||
|
} |
||||
|
|
||||
|
func Munmap(b []byte) (err error) { |
||||
|
return mapper.Munmap(b) |
||||
|
} |
||||
|
|
||||
|
//sys Madvise(b []byte, behav int) (err error)
|
||||
|
//sys Mlock(b []byte) (err error)
|
||||
|
//sys Mlockall(flags int) (err error)
|
||||
|
//sys Mprotect(b []byte, prot int) (err error)
|
||||
|
//sys Msync(b []byte, flags int) (err error)
|
||||
|
//sys Munlock(b []byte) (err error)
|
||||
|
//sys Munlockall() (err error)
|
@ -0,0 +1,680 @@ |
|||||
|
// Copyright 2009,2010 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.
|
||||
|
|
||||
|
// Darwin system calls.
|
||||
|
// This file is compiled as ordinary Go code,
|
||||
|
// but it is also input to mksyscall,
|
||||
|
// which parses the //sys lines and generates system call stubs.
|
||||
|
// Note that sometimes we use a lowercase //sys name and wrap
|
||||
|
// it in our own nicer implementation, either here or in
|
||||
|
// syscall_bsd.go or syscall_unix.go.
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import ( |
||||
|
"errors" |
||||
|
"syscall" |
||||
|
"unsafe" |
||||
|
) |
||||
|
|
||||
|
const ImplementsGetwd = true |
||||
|
|
||||
|
func Getwd() (string, error) { |
||||
|
buf := make([]byte, 2048) |
||||
|
attrs, err := getAttrList(".", attrList{CommonAttr: attrCmnFullpath}, buf, 0) |
||||
|
if err == nil && len(attrs) == 1 && len(attrs[0]) >= 2 { |
||||
|
wd := string(attrs[0]) |
||||
|
// Sanity check that it's an absolute path and ends
|
||||
|
// in a null byte, which we then strip.
|
||||
|
if wd[0] == '/' && wd[len(wd)-1] == 0 { |
||||
|
return wd[:len(wd)-1], nil |
||||
|
} |
||||
|
} |
||||
|
// If pkg/os/getwd.go gets ENOTSUP, it will fall back to the
|
||||
|
// slow algorithm.
|
||||
|
return "", ENOTSUP |
||||
|
} |
||||
|
|
||||
|
// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets.
|
||||
|
type SockaddrDatalink struct { |
||||
|
Len uint8 |
||||
|
Family uint8 |
||||
|
Index uint16 |
||||
|
Type uint8 |
||||
|
Nlen uint8 |
||||
|
Alen uint8 |
||||
|
Slen uint8 |
||||
|
Data [12]int8 |
||||
|
raw RawSockaddrDatalink |
||||
|
} |
||||
|
|
||||
|
// Translate "kern.hostname" to []_C_int{0,1,2,3}.
|
||||
|
func nametomib(name string) (mib []_C_int, err error) { |
||||
|
const siz = unsafe.Sizeof(mib[0]) |
||||
|
|
||||
|
// NOTE(rsc): It seems strange to set the buffer to have
|
||||
|
// size CTL_MAXNAME+2 but use only CTL_MAXNAME
|
||||
|
// as the size. I don't know why the +2 is here, but the
|
||||
|
// kernel uses +2 for its own implementation of this function.
|
||||
|
// I am scared that if we don't include the +2 here, the kernel
|
||||
|
// will silently write 2 words farther than we specify
|
||||
|
// and we'll get memory corruption.
|
||||
|
var buf [CTL_MAXNAME + 2]_C_int |
||||
|
n := uintptr(CTL_MAXNAME) * siz |
||||
|
|
||||
|
p := (*byte)(unsafe.Pointer(&buf[0])) |
||||
|
bytes, err := ByteSliceFromString(name) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
// Magic sysctl: "setting" 0.3 to a string name
|
||||
|
// lets you read back the array of integers form.
|
||||
|
if err = sysctl([]_C_int{0, 3}, p, &n, &bytes[0], uintptr(len(name))); err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
return buf[0 : n/siz], nil |
||||
|
} |
||||
|
|
||||
|
//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
|
||||
|
func PtraceAttach(pid int) (err error) { return ptrace(PT_ATTACH, pid, 0, 0) } |
||||
|
func PtraceDetach(pid int) (err error) { return ptrace(PT_DETACH, pid, 0, 0) } |
||||
|
|
||||
|
const ( |
||||
|
attrBitMapCount = 5 |
||||
|
attrCmnFullpath = 0x08000000 |
||||
|
) |
||||
|
|
||||
|
type attrList struct { |
||||
|
bitmapCount uint16 |
||||
|
_ uint16 |
||||
|
CommonAttr uint32 |
||||
|
VolAttr uint32 |
||||
|
DirAttr uint32 |
||||
|
FileAttr uint32 |
||||
|
Forkattr uint32 |
||||
|
} |
||||
|
|
||||
|
func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) (attrs [][]byte, err error) { |
||||
|
if len(attrBuf) < 4 { |
||||
|
return nil, errors.New("attrBuf too small") |
||||
|
} |
||||
|
attrList.bitmapCount = attrBitMapCount |
||||
|
|
||||
|
var _p0 *byte |
||||
|
_p0, err = BytePtrFromString(path) |
||||
|
if err != nil { |
||||
|
return nil, err |
||||
|
} |
||||
|
|
||||
|
_, _, e1 := Syscall6( |
||||
|
SYS_GETATTRLIST, |
||||
|
uintptr(unsafe.Pointer(_p0)), |
||||
|
uintptr(unsafe.Pointer(&attrList)), |
||||
|
uintptr(unsafe.Pointer(&attrBuf[0])), |
||||
|
uintptr(len(attrBuf)), |
||||
|
uintptr(options), |
||||
|
0, |
||||
|
) |
||||
|
if e1 != 0 { |
||||
|
return nil, e1 |
||||
|
} |
||||
|
size := *(*uint32)(unsafe.Pointer(&attrBuf[0])) |
||||
|
|
||||
|
// dat is the section of attrBuf that contains valid data,
|
||||
|
// without the 4 byte length header. All attribute offsets
|
||||
|
// are relative to dat.
|
||||
|
dat := attrBuf |
||||
|
if int(size) < len(attrBuf) { |
||||
|
dat = dat[:size] |
||||
|
} |
||||
|
dat = dat[4:] // remove length prefix
|
||||
|
|
||||
|
for i := uint32(0); int(i) < len(dat); { |
||||
|
header := dat[i:] |
||||
|
if len(header) < 8 { |
||||
|
return attrs, errors.New("truncated attribute header") |
||||
|
} |
||||
|
datOff := *(*int32)(unsafe.Pointer(&header[0])) |
||||
|
attrLen := *(*uint32)(unsafe.Pointer(&header[4])) |
||||
|
if datOff < 0 || uint32(datOff)+attrLen > uint32(len(dat)) { |
||||
|
return attrs, errors.New("truncated results; attrBuf too small") |
||||
|
} |
||||
|
end := uint32(datOff) + attrLen |
||||
|
attrs = append(attrs, dat[datOff:end]) |
||||
|
i = end |
||||
|
if r := i % 4; r != 0 { |
||||
|
i += (4 - r) |
||||
|
} |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
//sysnb pipe() (r int, w int, err error)
|
||||
|
|
||||
|
func Pipe(p []int) (err error) { |
||||
|
if len(p) != 2 { |
||||
|
return EINVAL |
||||
|
} |
||||
|
p[0], p[1], err = pipe() |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { |
||||
|
var _p0 unsafe.Pointer |
||||
|
var bufsize uintptr |
||||
|
if len(buf) > 0 { |
||||
|
_p0 = unsafe.Pointer(&buf[0]) |
||||
|
bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf)) |
||||
|
} |
||||
|
r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags)) |
||||
|
n = int(r0) |
||||
|
if e1 != 0 { |
||||
|
err = e1 |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func xattrPointer(dest []byte) *byte { |
||||
|
// It's only when dest is set to NULL that the OS X implementations of
|
||||
|
// getxattr() and listxattr() return the current sizes of the named attributes.
|
||||
|
// An empty byte array is not sufficient. To maintain the same behaviour as the
|
||||
|
// linux implementation, we wrap around the system calls and pass in NULL when
|
||||
|
// dest is empty.
|
||||
|
var destp *byte |
||||
|
if len(dest) > 0 { |
||||
|
destp = &dest[0] |
||||
|
} |
||||
|
return destp |
||||
|
} |
||||
|
|
||||
|
//sys getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error)
|
||||
|
|
||||
|
func Getxattr(path string, attr string, dest []byte) (sz int, err error) { |
||||
|
return getxattr(path, attr, xattrPointer(dest), len(dest), 0, 0) |
||||
|
} |
||||
|
|
||||
|
func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) { |
||||
|
return getxattr(link, attr, xattrPointer(dest), len(dest), 0, XATTR_NOFOLLOW) |
||||
|
} |
||||
|
|
||||
|
//sys setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error)
|
||||
|
|
||||
|
func Setxattr(path string, attr string, data []byte, flags int) (err error) { |
||||
|
// The parameters for the OS X implementation vary slightly compared to the
|
||||
|
// linux system call, specifically the position parameter:
|
||||
|
//
|
||||
|
// linux:
|
||||
|
// int setxattr(
|
||||
|
// const char *path,
|
||||
|
// const char *name,
|
||||
|
// const void *value,
|
||||
|
// size_t size,
|
||||
|
// int flags
|
||||
|
// );
|
||||
|
//
|
||||
|
// darwin:
|
||||
|
// int setxattr(
|
||||
|
// const char *path,
|
||||
|
// const char *name,
|
||||
|
// void *value,
|
||||
|
// size_t size,
|
||||
|
// u_int32_t position,
|
||||
|
// int options
|
||||
|
// );
|
||||
|
//
|
||||
|
// position specifies the offset within the extended attribute. In the
|
||||
|
// current implementation, only the resource fork extended attribute makes
|
||||
|
// use of this argument. For all others, position is reserved. We simply
|
||||
|
// default to setting it to zero.
|
||||
|
return setxattr(path, attr, xattrPointer(data), len(data), 0, flags) |
||||
|
} |
||||
|
|
||||
|
func Lsetxattr(link string, attr string, data []byte, flags int) (err error) { |
||||
|
return setxattr(link, attr, xattrPointer(data), len(data), 0, flags|XATTR_NOFOLLOW) |
||||
|
} |
||||
|
|
||||
|
//sys removexattr(path string, attr string, options int) (err error)
|
||||
|
|
||||
|
func Removexattr(path string, attr string) (err error) { |
||||
|
// We wrap around and explicitly zero out the options provided to the OS X
|
||||
|
// implementation of removexattr, we do so for interoperability with the
|
||||
|
// linux variant.
|
||||
|
return removexattr(path, attr, 0) |
||||
|
} |
||||
|
|
||||
|
func Lremovexattr(link string, attr string) (err error) { |
||||
|
return removexattr(link, attr, XATTR_NOFOLLOW) |
||||
|
} |
||||
|
|
||||
|
//sys listxattr(path string, dest *byte, size int, options int) (sz int, err error)
|
||||
|
|
||||
|
func Listxattr(path string, dest []byte) (sz int, err error) { |
||||
|
return listxattr(path, xattrPointer(dest), len(dest), 0) |
||||
|
} |
||||
|
|
||||
|
func Llistxattr(link string, dest []byte) (sz int, err error) { |
||||
|
return listxattr(link, xattrPointer(dest), len(dest), XATTR_NOFOLLOW) |
||||
|
} |
||||
|
|
||||
|
func setattrlistTimes(path string, times []Timespec, flags int) error { |
||||
|
_p0, err := BytePtrFromString(path) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
var attrList attrList |
||||
|
attrList.bitmapCount = ATTR_BIT_MAP_COUNT |
||||
|
attrList.CommonAttr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME |
||||
|
|
||||
|
// order is mtime, atime: the opposite of Chtimes
|
||||
|
attributes := [2]Timespec{times[1], times[0]} |
||||
|
options := 0 |
||||
|
if flags&AT_SYMLINK_NOFOLLOW != 0 { |
||||
|
options |= FSOPT_NOFOLLOW |
||||
|
} |
||||
|
_, _, e1 := Syscall6( |
||||
|
SYS_SETATTRLIST, |
||||
|
uintptr(unsafe.Pointer(_p0)), |
||||
|
uintptr(unsafe.Pointer(&attrList)), |
||||
|
uintptr(unsafe.Pointer(&attributes)), |
||||
|
uintptr(unsafe.Sizeof(attributes)), |
||||
|
uintptr(options), |
||||
|
0, |
||||
|
) |
||||
|
if e1 != 0 { |
||||
|
return e1 |
||||
|
} |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func utimensat(dirfd int, path string, times *[2]Timespec, flags int) error { |
||||
|
// Darwin doesn't support SYS_UTIMENSAT
|
||||
|
return ENOSYS |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Wrapped |
||||
|
*/ |
||||
|
|
||||
|
//sys kill(pid int, signum int, posix int) (err error)
|
||||
|
|
||||
|
func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(signum), 1) } |
||||
|
|
||||
|
//sys ioctl(fd int, req uint, arg uintptr) (err error)
|
||||
|
|
||||
|
// ioctl itself should not be exposed directly, but additional get/set
|
||||
|
// functions for specific types are permissible.
|
||||
|
|
||||
|
// IoctlSetInt performs an ioctl operation which sets an integer value
|
||||
|
// on fd, using the specified request number.
|
||||
|
func IoctlSetInt(fd int, req uint, value int) error { |
||||
|
return ioctl(fd, req, uintptr(value)) |
||||
|
} |
||||
|
|
||||
|
func ioctlSetWinsize(fd int, req uint, value *Winsize) error { |
||||
|
return ioctl(fd, req, uintptr(unsafe.Pointer(value))) |
||||
|
} |
||||
|
|
||||
|
func ioctlSetTermios(fd int, req uint, value *Termios) error { |
||||
|
return ioctl(fd, req, uintptr(unsafe.Pointer(value))) |
||||
|
} |
||||
|
|
||||
|
// IoctlGetInt performs an ioctl operation which gets an integer value
|
||||
|
// from fd, using the specified request number.
|
||||
|
func IoctlGetInt(fd int, req uint) (int, error) { |
||||
|
var value int |
||||
|
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) |
||||
|
return value, err |
||||
|
} |
||||
|
|
||||
|
func IoctlGetWinsize(fd int, req uint) (*Winsize, error) { |
||||
|
var value Winsize |
||||
|
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) |
||||
|
return &value, err |
||||
|
} |
||||
|
|
||||
|
func IoctlGetTermios(fd int, req uint) (*Termios, error) { |
||||
|
var value Termios |
||||
|
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) |
||||
|
return &value, err |
||||
|
} |
||||
|
|
||||
|
func Uname(uname *Utsname) error { |
||||
|
mib := []_C_int{CTL_KERN, KERN_OSTYPE} |
||||
|
n := unsafe.Sizeof(uname.Sysname) |
||||
|
if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
mib = []_C_int{CTL_KERN, KERN_HOSTNAME} |
||||
|
n = unsafe.Sizeof(uname.Nodename) |
||||
|
if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
mib = []_C_int{CTL_KERN, KERN_OSRELEASE} |
||||
|
n = unsafe.Sizeof(uname.Release) |
||||
|
if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
mib = []_C_int{CTL_KERN, KERN_VERSION} |
||||
|
n = unsafe.Sizeof(uname.Version) |
||||
|
if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
// The version might have newlines or tabs in it, convert them to
|
||||
|
// spaces.
|
||||
|
for i, b := range uname.Version { |
||||
|
if b == '\n' || b == '\t' { |
||||
|
if i == len(uname.Version)-1 { |
||||
|
uname.Version[i] = 0 |
||||
|
} else { |
||||
|
uname.Version[i] = ' ' |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
mib = []_C_int{CTL_HW, HW_MACHINE} |
||||
|
n = unsafe.Sizeof(uname.Machine) |
||||
|
if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Exposed directly |
||||
|
*/ |
||||
|
//sys Access(path string, mode uint32) (err error)
|
||||
|
//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
|
||||
|
//sys Chdir(path string) (err error)
|
||||
|
//sys Chflags(path string, flags int) (err error)
|
||||
|
//sys Chmod(path string, mode uint32) (err error)
|
||||
|
//sys Chown(path string, uid int, gid int) (err error)
|
||||
|
//sys Chroot(path string) (err error)
|
||||
|
//sys Close(fd int) (err error)
|
||||
|
//sys Dup(fd int) (nfd int, err error)
|
||||
|
//sys Dup2(from int, to int) (err error)
|
||||
|
//sys Exchangedata(path1 string, path2 string, options int) (err error)
|
||||
|
//sys Exit(code int)
|
||||
|
//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
|
||||
|
//sys Fchdir(fd int) (err error)
|
||||
|
//sys Fchflags(fd int, flags int) (err error)
|
||||
|
//sys Fchmod(fd int, mode uint32) (err error)
|
||||
|
//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
|
||||
|
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
|
//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
|
||||
|
//sys Flock(fd int, how int) (err error)
|
||||
|
//sys Fpathconf(fd int, name int) (val int, err error)
|
||||
|
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
|
||||
|
//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
|
||||
|
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
|
||||
|
//sys Fsync(fd int) (err error)
|
||||
|
//sys Ftruncate(fd int, length int64) (err error)
|
||||
|
//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64
|
||||
|
//sys Getdtablesize() (size int)
|
||||
|
//sysnb Getegid() (egid int)
|
||||
|
//sysnb Geteuid() (uid int)
|
||||
|
//sysnb Getgid() (gid int)
|
||||
|
//sysnb Getpgid(pid int) (pgid int, err error)
|
||||
|
//sysnb Getpgrp() (pgrp int)
|
||||
|
//sysnb Getpid() (pid int)
|
||||
|
//sysnb Getppid() (ppid int)
|
||||
|
//sys Getpriority(which int, who int) (prio int, err error)
|
||||
|
//sysnb Getrlimit(which int, lim *Rlimit) (err error)
|
||||
|
//sysnb Getrusage(who int, rusage *Rusage) (err error)
|
||||
|
//sysnb Getsid(pid int) (sid int, err error)
|
||||
|
//sysnb Getuid() (uid int)
|
||||
|
//sysnb Issetugid() (tainted bool)
|
||||
|
//sys Kqueue() (fd int, err error)
|
||||
|
//sys Lchown(path string, uid int, gid int) (err error)
|
||||
|
//sys Link(path string, link string) (err error)
|
||||
|
//sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error)
|
||||
|
//sys Listen(s int, backlog int) (err error)
|
||||
|
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
|
||||
|
//sys Mkdir(path string, mode uint32) (err error)
|
||||
|
//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
|
||||
|
//sys Mkfifo(path string, mode uint32) (err error)
|
||||
|
//sys Mknod(path string, mode uint32, dev int) (err error)
|
||||
|
//sys Open(path string, mode int, perm uint32) (fd int, err error)
|
||||
|
//sys Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error)
|
||||
|
//sys Pathconf(path string, name int) (val int, err error)
|
||||
|
//sys Pread(fd int, p []byte, offset int64) (n int, err error)
|
||||
|
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
|
||||
|
//sys read(fd int, p []byte) (n int, err error)
|
||||
|
//sys Readlink(path string, buf []byte) (n int, err error)
|
||||
|
//sys Readlinkat(dirfd int, path string, buf []byte) (n int, err error)
|
||||
|
//sys Rename(from string, to string) (err error)
|
||||
|
//sys Renameat(fromfd int, from string, tofd int, to string) (err error)
|
||||
|
//sys Revoke(path string) (err error)
|
||||
|
//sys Rmdir(path string) (err error)
|
||||
|
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
|
||||
|
//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
|
||||
|
//sys Setegid(egid int) (err error)
|
||||
|
//sysnb Seteuid(euid int) (err error)
|
||||
|
//sysnb Setgid(gid int) (err error)
|
||||
|
//sys Setlogin(name string) (err error)
|
||||
|
//sysnb Setpgid(pid int, pgid int) (err error)
|
||||
|
//sys Setpriority(which int, who int, prio int) (err error)
|
||||
|
//sys Setprivexec(flag int) (err error)
|
||||
|
//sysnb Setregid(rgid int, egid int) (err error)
|
||||
|
//sysnb Setreuid(ruid int, euid int) (err error)
|
||||
|
//sysnb Setrlimit(which int, lim *Rlimit) (err error)
|
||||
|
//sysnb Setsid() (pid int, err error)
|
||||
|
//sysnb Settimeofday(tp *Timeval) (err error)
|
||||
|
//sysnb Setuid(uid int) (err error)
|
||||
|
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
||||
|
//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
|
||||
|
//sys Symlink(path string, link string) (err error)
|
||||
|
//sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error)
|
||||
|
//sys Sync() (err error)
|
||||
|
//sys Truncate(path string, length int64) (err error)
|
||||
|
//sys Umask(newmask int) (oldmask int)
|
||||
|
//sys Undelete(path string) (err error)
|
||||
|
//sys Unlink(path string) (err error)
|
||||
|
//sys Unlinkat(dirfd int, path string, flags int) (err error)
|
||||
|
//sys Unmount(path string, flags int) (err error)
|
||||
|
//sys write(fd int, p []byte) (n int, err error)
|
||||
|
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
|
||||
|
//sys munmap(addr uintptr, length uintptr) (err error)
|
||||
|
//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
|
||||
|
//sys writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE
|
||||
|
|
||||
|
/* |
||||
|
* Unimplemented |
||||
|
*/ |
||||
|
// Profil
|
||||
|
// Sigaction
|
||||
|
// Sigprocmask
|
||||
|
// Getlogin
|
||||
|
// Sigpending
|
||||
|
// Sigaltstack
|
||||
|
// Ioctl
|
||||
|
// Reboot
|
||||
|
// Execve
|
||||
|
// Vfork
|
||||
|
// Sbrk
|
||||
|
// Sstk
|
||||
|
// Ovadvise
|
||||
|
// Mincore
|
||||
|
// Setitimer
|
||||
|
// Swapon
|
||||
|
// Select
|
||||
|
// Sigsuspend
|
||||
|
// Readv
|
||||
|
// Writev
|
||||
|
// Nfssvc
|
||||
|
// Getfh
|
||||
|
// Quotactl
|
||||
|
// Mount
|
||||
|
// Csops
|
||||
|
// Waitid
|
||||
|
// Add_profil
|
||||
|
// Kdebug_trace
|
||||
|
// Sigreturn
|
||||
|
// Atsocket
|
||||
|
// Kqueue_from_portset_np
|
||||
|
// Kqueue_portset
|
||||
|
// Getattrlist
|
||||
|
// Setattrlist
|
||||
|
// Getdirentriesattr
|
||||
|
// Searchfs
|
||||
|
// Delete
|
||||
|
// Copyfile
|
||||
|
// Watchevent
|
||||
|
// Waitevent
|
||||
|
// Modwatch
|
||||
|
// Fgetxattr
|
||||
|
// Fsetxattr
|
||||
|
// Fremovexattr
|
||||
|
// Flistxattr
|
||||
|
// Fsctl
|
||||
|
// Initgroups
|
||||
|
// Posix_spawn
|
||||
|
// Nfsclnt
|
||||
|
// Fhopen
|
||||
|
// Minherit
|
||||
|
// Semsys
|
||||
|
// Msgsys
|
||||
|
// Shmsys
|
||||
|
// Semctl
|
||||
|
// Semget
|
||||
|
// Semop
|
||||
|
// Msgctl
|
||||
|
// Msgget
|
||||
|
// Msgsnd
|
||||
|
// Msgrcv
|
||||
|
// Shmat
|
||||
|
// Shmctl
|
||||
|
// Shmdt
|
||||
|
// Shmget
|
||||
|
// Shm_open
|
||||
|
// Shm_unlink
|
||||
|
// Sem_open
|
||||
|
// Sem_close
|
||||
|
// Sem_unlink
|
||||
|
// Sem_wait
|
||||
|
// Sem_trywait
|
||||
|
// Sem_post
|
||||
|
// Sem_getvalue
|
||||
|
// Sem_init
|
||||
|
// Sem_destroy
|
||||
|
// Open_extended
|
||||
|
// Umask_extended
|
||||
|
// Stat_extended
|
||||
|
// Lstat_extended
|
||||
|
// Fstat_extended
|
||||
|
// Chmod_extended
|
||||
|
// Fchmod_extended
|
||||
|
// Access_extended
|
||||
|
// Settid
|
||||
|
// Gettid
|
||||
|
// Setsgroups
|
||||
|
// Getsgroups
|
||||
|
// Setwgroups
|
||||
|
// Getwgroups
|
||||
|
// Mkfifo_extended
|
||||
|
// Mkdir_extended
|
||||
|
// Identitysvc
|
||||
|
// Shared_region_check_np
|
||||
|
// Shared_region_map_np
|
||||
|
// __pthread_mutex_destroy
|
||||
|
// __pthread_mutex_init
|
||||
|
// __pthread_mutex_lock
|
||||
|
// __pthread_mutex_trylock
|
||||
|
// __pthread_mutex_unlock
|
||||
|
// __pthread_cond_init
|
||||
|
// __pthread_cond_destroy
|
||||
|
// __pthread_cond_broadcast
|
||||
|
// __pthread_cond_signal
|
||||
|
// Setsid_with_pid
|
||||
|
// __pthread_cond_timedwait
|
||||
|
// Aio_fsync
|
||||
|
// Aio_return
|
||||
|
// Aio_suspend
|
||||
|
// Aio_cancel
|
||||
|
// Aio_error
|
||||
|
// Aio_read
|
||||
|
// Aio_write
|
||||
|
// Lio_listio
|
||||
|
// __pthread_cond_wait
|
||||
|
// Iopolicysys
|
||||
|
// __pthread_kill
|
||||
|
// __pthread_sigmask
|
||||
|
// __sigwait
|
||||
|
// __disable_threadsignal
|
||||
|
// __pthread_markcancel
|
||||
|
// __pthread_canceled
|
||||
|
// __semwait_signal
|
||||
|
// Proc_info
|
||||
|
// sendfile
|
||||
|
// Stat64_extended
|
||||
|
// Lstat64_extended
|
||||
|
// Fstat64_extended
|
||||
|
// __pthread_chdir
|
||||
|
// __pthread_fchdir
|
||||
|
// Audit
|
||||
|
// Auditon
|
||||
|
// Getauid
|
||||
|
// Setauid
|
||||
|
// Getaudit
|
||||
|
// Setaudit
|
||||
|
// Getaudit_addr
|
||||
|
// Setaudit_addr
|
||||
|
// Auditctl
|
||||
|
// Bsdthread_create
|
||||
|
// Bsdthread_terminate
|
||||
|
// Stack_snapshot
|
||||
|
// Bsdthread_register
|
||||
|
// Workq_open
|
||||
|
// Workq_ops
|
||||
|
// __mac_execve
|
||||
|
// __mac_syscall
|
||||
|
// __mac_get_file
|
||||
|
// __mac_set_file
|
||||
|
// __mac_get_link
|
||||
|
// __mac_set_link
|
||||
|
// __mac_get_proc
|
||||
|
// __mac_set_proc
|
||||
|
// __mac_get_fd
|
||||
|
// __mac_set_fd
|
||||
|
// __mac_get_pid
|
||||
|
// __mac_get_lcid
|
||||
|
// __mac_get_lctx
|
||||
|
// __mac_set_lctx
|
||||
|
// Setlcid
|
||||
|
// Read_nocancel
|
||||
|
// Write_nocancel
|
||||
|
// Open_nocancel
|
||||
|
// Close_nocancel
|
||||
|
// Wait4_nocancel
|
||||
|
// Recvmsg_nocancel
|
||||
|
// Sendmsg_nocancel
|
||||
|
// Recvfrom_nocancel
|
||||
|
// Accept_nocancel
|
||||
|
// Fcntl_nocancel
|
||||
|
// Select_nocancel
|
||||
|
// Fsync_nocancel
|
||||
|
// Connect_nocancel
|
||||
|
// Sigsuspend_nocancel
|
||||
|
// Readv_nocancel
|
||||
|
// Writev_nocancel
|
||||
|
// Sendto_nocancel
|
||||
|
// Pread_nocancel
|
||||
|
// Pwrite_nocancel
|
||||
|
// Waitid_nocancel
|
||||
|
// Poll_nocancel
|
||||
|
// Msgsnd_nocancel
|
||||
|
// Msgrcv_nocancel
|
||||
|
// Sem_wait_nocancel
|
||||
|
// Aio_suspend_nocancel
|
||||
|
// __sigwait_nocancel
|
||||
|
// __semwait_signal_nocancel
|
||||
|
// __mac_mount
|
||||
|
// __mac_get_mount
|
||||
|
// __mac_getfsstat
|
@ -0,0 +1,68 @@ |
|||||
|
// 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 386,darwin
|
||||
|
|
||||
|
package unix |
||||
|
|
||||
|
import ( |
||||
|
"syscall" |
||||
|
"unsafe" |
||||
|
) |
||||
|
|
||||
|
func setTimespec(sec, nsec int64) Timespec { |
||||
|
return Timespec{Sec: int32(sec), Nsec: int32(nsec)} |
||||
|
} |
||||
|
|
||||
|
func setTimeval(sec, usec int64) Timeval { |
||||
|
return Timeval{Sec: int32(sec), Usec: int32(usec)} |
||||
|
} |
||||
|
|
||||
|
//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
|
||||
|
func Gettimeofday(tv *Timeval) (err error) { |
||||
|
// The tv passed to gettimeofday must be non-nil
|
||||
|
// but is otherwise unused. The answers come back
|
||||
|
// in the two registers.
|
||||
|
sec, usec, err := gettimeofday(tv) |
||||
|
tv.Sec = int32(sec) |
||||
|
tv.Usec = int32(usec) |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
func SetKevent(k *Kevent_t, fd, mode, flags int) { |
||||
|
k.Ident = uint32(fd) |
||||
|
k.Filter = int16(mode) |
||||
|
k.Flags = uint16(flags) |
||||
|
} |
||||
|
|
||||
|
func (iov *Iovec) SetLen(length int) { |
||||
|
iov.Len = uint32(length) |
||||
|
} |
||||
|
|
||||
|
func (msghdr *Msghdr) SetControllen(length int) { |
||||
|
msghdr.Controllen = uint32(length) |
||||
|
} |
||||
|
|
||||
|
func (cmsg *Cmsghdr) SetLen(length int) { |
||||
|
cmsg.Len = uint32(length) |
||||
|
} |
||||
|
|
||||
|
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { |
||||
|
var length = uint64(count) |
||||
|
|
||||
|
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(*offset>>32), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0) |
||||
|
|
||||
|
written = int(length) |
||||
|
|
||||
|
if e1 != 0 { |
||||
|
err = e1 |
||||
|
} |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) |
||||
|
|
||||
|
// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
|
||||
|
// of darwin/386 the syscall is called sysctl instead of __sysctl.
|
||||
|
const SYS___SYSCTL = SYS_SYSCTL |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue