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