1
0
mirror of https://github.com/rancher/os.git synced 2025-09-03 15:54:24 +00:00

Add defered syslog hook

Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
This commit is contained in:
Sven Dowideit
2017-07-12 14:18:02 +10:00
parent 43c620c4d8
commit bb20e96a98
27 changed files with 777 additions and 254 deletions

View File

@@ -93,7 +93,7 @@ func sysInit(c *config.CloudConfig) (*config.CloudConfig, error) {
} }
func MainInit() { func MainInit() {
log.InitLogger() log.InitDeferedLogger()
log.Infof("MainInit() start") log.Infof("MainInit() start")
if err := RunInit(); err != nil { if err := RunInit(); err != nil {
log.Fatal(err) log.Fatal(err)
@@ -414,6 +414,8 @@ func RunInit() error {
return err return err
} }
log.SyslogReady(true)
return pidOne() return pidOne()
} }

View File

@@ -4,6 +4,8 @@ import (
"io" "io"
"os" "os"
"fmt"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
) )
@@ -110,7 +112,15 @@ func WithFields(fields Fields) *logrus.Entry {
return appLog.WithFields(logrus.Fields(fields)) return appLog.WithFields(logrus.Fields(fields))
} }
// InitLogger sets up Logging to log to /dev/kmsg and to Syslog
func InitLogger() { func InitLogger() {
InitDeferedLogger()
SyslogReady(false)
}
// InitDeferedLogger sets up logging to /dev/kmsg and to an internal buffer
// which is then written to Syslog when signaled by SyslogReady()
func InitDeferedLogger() {
if userHook != nil { if userHook != nil {
return // we've already initialised it return // we've already initialised it
} }
@@ -148,3 +158,17 @@ func InitLogger() {
thisLog.Debugf("START: %v in %s", os.Args, pwd) thisLog.Debugf("START: %v in %s", os.Args, pwd)
} }
// SyslogReady tells the storeing User hook to start writing to syslog
func SyslogReady(logHook bool) error {
if userHook != nil {
if logHook {
logrus.Infof("Starting Syslog Hook")
fmt.Fprintf(appLog.Out, "------------ Starting defered Syslog Hook (%s) ----------------\n", os.Args[0])
} else {
fmt.Fprintf(appLog.Out, "------------ Starting Syslog Hook (%s) ----------------\n", os.Args[0])
}
return userHook.LogSystemReady()
}
return nil
}

View File

@@ -2,32 +2,51 @@ package log
import ( import (
"fmt" "fmt"
"github.com/Sirupsen/logrus" "log/syslog"
"os" "os"
"github.com/Sirupsen/logrus"
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
) )
// ShowuserlogHook writes all levels of logrus entries to a file for later analysis // ShowuserlogHook stores all levels of logrus entries in memory until its told the RancherOS logging system is ready
// then it replays them to be logged
type ShowuserlogHook struct { type ShowuserlogHook struct {
Level logrus.Level Level logrus.Level
syslogHook *logrus_syslog.SyslogHook
storedEntries []*logrus.Entry
} }
// NewShowuserlogHook creates a new hook for use
func NewShowuserlogHook(l logrus.Level) (*ShowuserlogHook, error) { func NewShowuserlogHook(l logrus.Level) (*ShowuserlogHook, error) {
return &ShowuserlogHook{l}, nil return &ShowuserlogHook{l, nil, []*logrus.Entry{}}, nil
} }
// Fire is called by logrus when the Hook is active
func (hook *ShowuserlogHook) Fire(entry *logrus.Entry) error { func (hook *ShowuserlogHook) Fire(entry *logrus.Entry) error {
line, err := entry.String() line, err := entry.String()
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err) fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
return err return err
} }
if entry.Level <= hook.Level { if entry.Level <= hook.Level {
fmt.Printf("> %s", line) fmt.Printf("SVEN %s", line)
} }
if hook.syslogHook == nil {
hook.storedEntries = append(hook.storedEntries, entry)
} else {
err := hook.syslogHook.Fire(entry)
if err != nil {
fmt.Fprintf(os.Stderr, "LOGERR: Unable to write %s, %v", line, err)
return err
}
}
return nil return nil
} }
// Levels returns all log levels, so we can process them ourselves
func (hook *ShowuserlogHook) Levels() []logrus.Level { func (hook *ShowuserlogHook) Levels() []logrus.Level {
return []logrus.Level{ return []logrus.Level{
logrus.DebugLevel, logrus.DebugLevel,
@@ -38,3 +57,21 @@ func (hook *ShowuserlogHook) Levels() []logrus.Level {
logrus.PanicLevel, logrus.PanicLevel,
} }
} }
// Set up Syslog Hook, and replay any stored entries.
func (hook *ShowuserlogHook) LogSystemReady() error {
if hook.syslogHook == nil {
h, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
if err != nil {
logrus.Debugf("error creating SyslogHook: %s", err)
return err
}
hook.syslogHook = h
for _, entry := range hook.storedEntries {
hook.syslogHook.Fire(entry)
}
}
return nil
}

View File

@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
set -e set -ex
export ARCH=${ARCH:-"amd64"} export ARCH=${ARCH:-"amd64"}
BASE=images BASE=images

View File

@@ -1 +1 @@
APPEND rancher.autologin=tty1 rancher.autologin=ttyS0 rancher.autologin=ttyS1 console=tty0 console=ttyS0 console=ttyS1 printk.devkmsg=on ${APPEND} APPEND rancher.debug=true rancher.autologin=tty1 rancher.autologin=ttyS0 rancher.autologin=ttyS1 console=tty0 console=ttyS0 console=ttyS1 printk.devkmsg=on ${APPEND}

View File

@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
set -e set -ex
source $(dirname $0)/version source $(dirname $0)/version

View File

@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
set -e set -ex
cd $(dirname $0)/.. cd $(dirname $0)/..

View File

@@ -1,6 +1,6 @@
github.com/Microsoft/go-winio v0.1.0 github.com/Microsoft/go-winio v0.1.0
github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837 github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837
github.com/Sirupsen/logrus v0.11.0 github.com/Sirupsen/logrus v0.11.5
github.com/boltdb/bolt v1.2.0 github.com/boltdb/bolt v1.2.0
github.com/cloudfoundry-incubator/candiedyaml 01cbc92901719f599b11f3a7e3b1768d7002b0bb https://github.com/rancher/candiedyaml github.com/cloudfoundry-incubator/candiedyaml 01cbc92901719f599b11f3a7e3b1768d7002b0bb https://github.com/rancher/candiedyaml
github.com/cloudfoundry/gosigar 3ed7c74352dae6dc00bdc8c74045375352e3ec05 github.com/cloudfoundry/gosigar 3ed7c74352dae6dc00bdc8c74045375352e3ec05
@@ -53,7 +53,7 @@ github.com/vishvananda/netns 54f0e4339ce73702a0607f49922aaa1e749b418d
github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a github.com/xeipuuv/gojsonpointer e0fe6f68307607d540ed8eac07a342c33fa1b54a
github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45 github.com/xeipuuv/gojsonreference e02fc20de94c78484cd5ffb007f8af96be030a45
github.com/xeipuuv/gojsonschema ac452913faa25c08bb78810d3e6f88b8a39f8f25 github.com/xeipuuv/gojsonschema ac452913faa25c08bb78810d3e6f88b8a39f8f25
github.com/SvenDowideit/cpuid 399bf479aea1edfbfe0b686c514631b511f44641 github.com/SvenDowideit/cpuid dfdb6dba69f48dd44c5cd831950be648f71162ca
golang.org/x/crypto 2f3083f6163ef51179ad42ed523a18c9a1141467 golang.org/x/crypto 2f3083f6163ef51179ad42ed523a18c9a1141467
golang.org/x/net 991d3e32f76f19ee6d9caadb3a22eae8d23315f7 https://github.com/golang/net.git golang.org/x/net 991d3e32f76f19ee6d9caadb3a22eae8d23315f7 https://github.com/golang/net.git
golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git

View File

@@ -1,9 +1,7 @@
language: go language: go
go: go:
- 1.3
- 1.4
- 1.5
- 1.6 - 1.6
- 1.7
- tip - tip
install: install:
- go get -t ./... - go get -t ./...

View File

@@ -1,3 +1,31 @@
# 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 # 0.10.0
* feature: Add a test hook (#180) * feature: Add a test hook (#180)

View File

@@ -1,5 +1,11 @@
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](https://godoc.org/github.com/Sirupsen/logrus) # Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>&nbsp;[![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus)&nbsp;[![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](https://godoc.org/github.com/Sirupsen/logrus)
**Seeing weird case-sensitive problems?** See [this
issue](https://github.com/sirupsen/logrus/issues/451#issuecomment-264332021).
This change has been reverted. I apologize for causing this. I greatly
underestimated the impact this would have. Logrus strives for stability and
backwards compatibility and failed to provide that.
Logrus is a structured logger for Go (golang), completely API compatible with Logrus is a structured logger for Go (golang), completely API compatible with
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
yet stable (pre 1.0). Logrus itself is completely stable and has been used in yet stable (pre 1.0). Logrus itself is completely stable and has been used in
@@ -81,8 +87,9 @@ func init() {
// Log as JSON instead of the default ASCII formatter. // Log as JSON instead of the default ASCII formatter.
log.SetFormatter(&log.JSONFormatter{}) log.SetFormatter(&log.JSONFormatter{})
// Output to stderr instead of stdout, could also be a file. // Output to stdout instead of the default stderr
log.SetOutput(os.Stderr) // Can be any io.Writer, see below for File example
log.SetOutput(os.Stdout)
// Only log the warning severity or above. // Only log the warning severity or above.
log.SetLevel(log.WarnLevel) log.SetLevel(log.WarnLevel)
@@ -132,7 +139,15 @@ var log = logrus.New()
func main() { func main() {
// The API for setting attributes is a little different than the package level // The API for setting attributes is a little different than the package level
// exported logger. See Godoc. // exported logger. See Godoc.
log.Out = os.Stderr 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{ log.WithFields(logrus.Fields{
"animal": "walrus", "animal": "walrus",
@@ -165,6 +180,20 @@ 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 seen as a hint you should add a field, however, you can still use the
`printf`-family functions with Logrus. `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 #### Hooks
You can add hooks for logging levels. For example to send errors to an exception You can add hooks for logging levels. For example to send errors to an exception
@@ -200,40 +229,47 @@ Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/v
| Hook | Description | | Hook | Description |
| ----- | ----------- | | ----- | ----------- |
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. | | [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. | | [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. | | [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
| [Influxus] (http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB] (http://influxdata.com/) |
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) | | [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka | | [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) | | [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch| | [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)| | [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)| | [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) |
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) | | [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash | | [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
| [Influxus] (http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB] (http://influxdata.com/) |
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) | | [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) | | [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)|
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
#### Level logging #### Level logging
@@ -309,8 +345,11 @@ The built-in logging formatters are:
without colors. without colors.
* *Note:* to force colored output when there is no TTY, set the `ForceColors` * *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 field to `true`. To force no colored output even if there is a TTY set the
`DisableColors` field to `true` `DisableColors` field to `true`. For Windows, see
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
* `logrus.JSONFormatter`. Logs fields as JSON. * `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: Third party logging formatters:
@@ -359,6 +398,18 @@ srv := http.Server{
Each line written to that writer will be printed the usual way, using formatters Each line written to that writer will be printed the usual way, using formatters
and hooks. The level for those entries is `info`. 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 #### Rotation
Log rotation is not provided with Logrus. Log rotation should be done by an Log rotation is not provided with Logrus. Log rotation should be done by an
@@ -407,7 +458,7 @@ logrus.RegisterExitHandler(handler)
... ...
``` ```
#### Thread safty #### Thread safety
By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs. By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs.
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.

View File

@@ -0,0 +1,39 @@
# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
## Usage
```go
import (
"log/syslog"
"github.com/Sirupsen/logrus"
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
)
func main() {
log := logrus.New()
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
if err == nil {
log.Hooks.Add(hook)
}
}
```
If you want to connect to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). Just assign empty string to the first two parameters of `NewSyslogHook`. It should look like the following.
```go
import (
"log/syslog"
"github.com/Sirupsen/logrus"
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
)
func main() {
log := logrus.New()
hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
if err == nil {
log.Hooks.Add(hook)
}
}
```

View File

@@ -0,0 +1,54 @@
// +build !windows,!nacl,!plan9
package logrus_syslog
import (
"fmt"
"github.com/Sirupsen/logrus"
"log/syslog"
"os"
)
// SyslogHook to send logs via syslog.
type SyslogHook struct {
Writer *syslog.Writer
SyslogNetwork string
SyslogRaddr string
}
// Creates a hook to be added to an instance of logger. This is called with
// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
// `if err == nil { log.Hooks.Add(hook) }`
func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
w, err := syslog.Dial(network, raddr, priority, tag)
return &SyslogHook{w, network, raddr}, err
}
func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
line, err := entry.String()
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
return err
}
switch entry.Level {
case logrus.PanicLevel:
return hook.Writer.Crit(line)
case logrus.FatalLevel:
return hook.Writer.Crit(line)
case logrus.ErrorLevel:
return hook.Writer.Err(line)
case logrus.WarnLevel:
return hook.Writer.Warning(line)
case logrus.InfoLevel:
return hook.Writer.Info(line)
case logrus.DebugLevel:
return hook.Writer.Debug(line)
default:
return nil
}
}
func (hook *SyslogHook) Levels() []logrus.Level {
return logrus.AllLevels
}

View File

@@ -5,9 +5,40 @@ import (
"fmt" "fmt"
) )
type fieldKey string
type FieldMap map[fieldKey]string
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)
}
type JSONFormatter struct { type JSONFormatter struct {
// TimestampFormat sets the format used for marshaling timestamps. // TimestampFormat sets the format used for marshaling timestamps.
TimestampFormat string TimestampFormat string
// DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool
// FieldMap allows users to customize the names of keys for various fields.
// As an example:
// formatter := &JSONFormatter{
// FieldMap: FieldMap{
// FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level",
// FieldKeyLevel: "@message",
// },
// }
FieldMap FieldMap
} }
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
@@ -29,9 +60,11 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
timestampFormat = DefaultTimestampFormat timestampFormat = DefaultTimestampFormat
} }
data["time"] = entry.Time.Format(timestampFormat) if !f.DisableTimestamp {
data["msg"] = entry.Message data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
data["level"] = entry.Level.String() }
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
serialized, err := json.Marshal(data) serialized, err := json.Marshal(data)
if err != nil { if err != nil {

View File

@@ -2,7 +2,9 @@
package logrus package logrus
import "io"
// IsTerminal returns true if stderr's file descriptor is a terminal. // IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool { func IsTerminal(f io.Writer) bool {
return true return true
} }

View File

@@ -9,14 +9,20 @@
package logrus package logrus
import ( import (
"io"
"os"
"syscall" "syscall"
"unsafe" "unsafe"
) )
// IsTerminal returns true if stderr's file descriptor is a terminal. // IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool { func IsTerminal(f io.Writer) bool {
fd := syscall.Stderr
var termios Termios var termios Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) switch v := f.(type) {
return err == 0 case *os.File:
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
default:
return false
}
} }

View File

@@ -3,13 +3,19 @@
package logrus package logrus
import ( import (
"io"
"os" "os"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
// IsTerminal returns true if the given file descriptor is a terminal. // IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal() bool { func IsTerminal(f io.Writer) bool {
_, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA) switch v := f.(type) {
return err == nil case *os.File:
_, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA)
return err == nil
default:
return false
}
} }

View File

@@ -8,6 +8,8 @@
package logrus package logrus
import ( import (
"io"
"os"
"syscall" "syscall"
"unsafe" "unsafe"
) )
@@ -19,9 +21,13 @@ var (
) )
// IsTerminal returns true if stderr's file descriptor is a terminal. // IsTerminal returns true if stderr's file descriptor is a terminal.
func IsTerminal() bool { func IsTerminal(f io.Writer) bool {
fd := syscall.Stderr switch v := f.(type) {
var st uint32 case *os.File:
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) var st uint32
return r != 0 && e == 0 r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
default:
return false
}
} }

View File

@@ -3,9 +3,9 @@ package logrus
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"runtime"
"sort" "sort"
"strings" "strings"
"sync"
"time" "time"
) )
@@ -20,16 +20,10 @@ const (
var ( var (
baseTimestamp time.Time baseTimestamp time.Time
isTerminal bool
) )
func init() { func init() {
baseTimestamp = time.Now() baseTimestamp = time.Now()
isTerminal = IsTerminal()
}
func miniTS() int {
return int(time.Since(baseTimestamp) / time.Second)
} }
type TextFormatter struct { type TextFormatter struct {
@@ -54,11 +48,32 @@ type TextFormatter struct {
// that log extremely frequently and don't use the JSON formatter this may not // that log extremely frequently and don't use the JSON formatter this may not
// be desired. // be desired.
DisableSorting bool DisableSorting bool
// QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool
// QuoteCharacter can be set to the override the default quoting character "
// with something else. For example: ', or `.
QuoteCharacter string
// Whether the logger's out is to a terminal
isTerminal bool
sync.Once
}
func (f *TextFormatter) init(entry *Entry) {
if len(f.QuoteCharacter) == 0 {
f.QuoteCharacter = "\""
}
if entry.Logger != nil {
f.isTerminal = IsTerminal(entry.Logger.Out)
}
} }
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var b *bytes.Buffer var b *bytes.Buffer
var keys []string = make([]string, 0, len(entry.Data)) keys := make([]string, 0, len(entry.Data))
for k := range entry.Data { for k := range entry.Data {
keys = append(keys, k) keys = append(keys, k)
} }
@@ -74,8 +89,9 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
prefixFieldClashes(entry.Data) prefixFieldClashes(entry.Data)
isColorTerminal := isTerminal && (runtime.GOOS != "windows") f.Do(func() { f.init(entry) })
isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
timestampFormat := f.TimestampFormat timestampFormat := f.TimestampFormat
if timestampFormat == "" { if timestampFormat == "" {
@@ -115,8 +131,10 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
levelText := strings.ToUpper(entry.Level.String())[0:4] levelText := strings.ToUpper(entry.Level.String())[0:4]
if !f.FullTimestamp { if f.DisableTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message) 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 { } else {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message) fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
} }
@@ -127,7 +145,10 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
} }
} }
func needsQuoting(text string) bool { func (f *TextFormatter) needsQuoting(text string) bool {
if f.QuoteEmptyFields && len(text) == 0 {
return true
}
for _, ch := range text { for _, ch := range text {
if !((ch >= 'a' && ch <= 'z') || if !((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') || (ch >= 'A' && ch <= 'Z') ||
@@ -150,17 +171,17 @@ func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interf
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
switch value := value.(type) { switch value := value.(type) {
case string: case string:
if !needsQuoting(value) { if !f.needsQuoting(value) {
b.WriteString(value) b.WriteString(value)
} else { } else {
fmt.Fprintf(b, "%q", value) fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter)
} }
case error: case error:
errmsg := value.Error() errmsg := value.Error()
if !needsQuoting(errmsg) { if !f.needsQuoting(errmsg) {
b.WriteString(errmsg) b.WriteString(errmsg)
} else { } else {
fmt.Fprintf(b, "%q", errmsg) fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
} }
default: default:
fmt.Fprint(b, value) fmt.Fprint(b, value)

View File

@@ -11,39 +11,48 @@ func (logger *Logger) Writer() *io.PipeWriter {
} }
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter { 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() reader, writer := io.Pipe()
var printFunc func(args ...interface{}) var printFunc func(args ...interface{})
switch level { switch level {
case DebugLevel: case DebugLevel:
printFunc = logger.Debug printFunc = entry.Debug
case InfoLevel: case InfoLevel:
printFunc = logger.Info printFunc = entry.Info
case WarnLevel: case WarnLevel:
printFunc = logger.Warn printFunc = entry.Warn
case ErrorLevel: case ErrorLevel:
printFunc = logger.Error printFunc = entry.Error
case FatalLevel: case FatalLevel:
printFunc = logger.Fatal printFunc = entry.Fatal
case PanicLevel: case PanicLevel:
printFunc = logger.Panic printFunc = entry.Panic
default: default:
printFunc = logger.Print printFunc = entry.Print
} }
go logger.writerScanner(reader, printFunc) go entry.writerScanner(reader, printFunc)
runtime.SetFinalizer(writer, writerFinalizer) runtime.SetFinalizer(writer, writerFinalizer)
return writer return writer
} }
func (logger *Logger) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) { func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
scanner := bufio.NewScanner(reader) scanner := bufio.NewScanner(reader)
for scanner.Scan() { for scanner.Scan() {
printFunc(scanner.Text()) printFunc(scanner.Text())
} }
if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
logger.Errorf("Error while reading from Writer: %s", err) entry.Errorf("Error while reading from Writer: %s", err)
} }
reader.Close() reader.Close()
} }

View File

@@ -12,7 +12,6 @@ package cpuid
import ( import (
"strings" "strings"
"unsafe"
) )
// Vendor is a representation of a CPU vendor. // Vendor is a representation of a CPU vendor.
@@ -565,9 +564,8 @@ func isHypervisorActive() bool {
} }
func getHypervisorCpuid(ax uint32) string { func getHypervisorCpuid(ax uint32) string {
a, b, c, d := cpuid(ax) _, b, c, d := cpuid(ax)
var info [4]uint32 = [4]uint32{a, b, c, d} name := strings.TrimRight(string(valAsString(b, c, d)), "\000")
name := strings.TrimRight(string((*[12]byte)(unsafe.Pointer(&info[1]))[:]), "\000")
return name return name
} }
@@ -584,10 +582,7 @@ func hypervisorName() string {
// return hv // return hv
//} //}
if hv := getHypervisorCpuid(0x40000000); hv != "" { return getHypervisorCpuid(0x40000000)
return hv
}
return ""
} }
// https://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID // https://en.wikipedia.org/wiki/CPUID#EAX.3D0:_Get_vendor_ID

View File

@@ -1,4 +1,4 @@
// Copyright 2016 VMware, Inc. All Rights Reserved. // Copyright 2016-2017 VMware, Inc. All Rights Reserved.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -15,7 +15,6 @@
package bdoor package bdoor
const ( const (
BackdoorMagic = uint64(0x564D5868)
BackdoorPort = uint16(0x5658) BackdoorPort = uint16(0x5658)
BackdoorHighBWPort = uint16(0x5659) BackdoorHighBWPort = uint16(0x5659)
@@ -26,109 +25,80 @@ const (
CommandFlagCookie = uint32(0x80000000) CommandFlagCookie = uint32(0x80000000)
) )
type BackdoorProto struct {
// typedef union {
// struct {
// DECLARE_REG_NAMED_STRUCT(ax);
// size_t size; /* Register bx. */
// DECLARE_REG_NAMED_STRUCT(cx);
// DECLARE_REG_NAMED_STRUCT(dx);
// DECLARE_REG_NAMED_STRUCT(si);
// DECLARE_REG_NAMED_STRUCT(di);
// } in;
// struct {
// DECLARE_REG_NAMED_STRUCT(ax);
// DECLARE_REG_NAMED_STRUCT(bx);
// DECLARE_REG_NAMED_STRUCT(cx);
// DECLARE_REG_NAMED_STRUCT(dx);
// DECLARE_REG_NAMED_STRUCT(si);
// DECLARE_REG_NAMED_STRUCT(di);
// } out;
// } proto;
AX, BX, CX, DX, SI, DI, BP UInt64
size uint32
}
func bdoor_inout(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func bdoor_hbout(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func bdoor_hbin(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func bdoor_inout_test(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func (p *BackdoorProto) InOut() *BackdoorProto { func (p *BackdoorProto) InOut() *BackdoorProto {
p.DX.Low.Low = BackdoorPort p.DX.AsUInt32().Low = BackdoorPort
p.AX.SetQuad(BackdoorMagic) p.AX.SetValue(BackdoorMagic)
retax, retbx, retcx, retdx, retsi, retdi, retbp := bdoor_inout( retax, retbx, retcx, retdx, retsi, retdi, retbp := bdoor_inout(
p.AX.Quad(), p.AX.Value(),
p.BX.Quad(), p.BX.Value(),
p.CX.Quad(), p.CX.Value(),
p.DX.Quad(), p.DX.Value(),
p.SI.Quad(), p.SI.Value(),
p.DI.Quad(), p.DI.Value(),
p.BP.Quad(), p.BP.Value(),
) )
ret := &BackdoorProto{} ret := &BackdoorProto{}
ret.AX.SetQuad(retax) ret.AX.SetValue(retax)
ret.BX.SetQuad(retbx) ret.BX.SetValue(retbx)
ret.CX.SetQuad(retcx) ret.CX.SetValue(retcx)
ret.DX.SetQuad(retdx) ret.DX.SetValue(retdx)
ret.SI.SetQuad(retsi) ret.SI.SetValue(retsi)
ret.DI.SetQuad(retdi) ret.DI.SetValue(retdi)
ret.BP.SetQuad(retbp) ret.BP.SetValue(retbp)
return ret return ret
} }
func (p *BackdoorProto) HighBandwidthOut() *BackdoorProto { func (p *BackdoorProto) HighBandwidthOut() *BackdoorProto {
p.DX.Low.Low = BackdoorHighBWPort p.DX.AsUInt32().Low = BackdoorHighBWPort
p.AX.SetQuad(BackdoorMagic) p.AX.SetValue(BackdoorMagic)
retax, retbx, retcx, retdx, retsi, retdi, retbp := bdoor_hbout( retax, retbx, retcx, retdx, retsi, retdi, retbp := bdoor_hbout(
p.AX.Quad(), p.AX.Value(),
p.BX.Quad(), p.BX.Value(),
p.CX.Quad(), p.CX.Value(),
p.DX.Quad(), p.DX.Value(),
p.SI.Quad(), p.SI.Value(),
p.DI.Quad(), p.DI.Value(),
p.BP.Quad(), p.BP.Value(),
) )
ret := &BackdoorProto{} ret := &BackdoorProto{}
ret.AX.SetQuad(retax) ret.AX.SetValue(retax)
ret.BX.SetQuad(retbx) ret.BX.SetValue(retbx)
ret.CX.SetQuad(retcx) ret.CX.SetValue(retcx)
ret.DX.SetQuad(retdx) ret.DX.SetValue(retdx)
ret.SI.SetQuad(retsi) ret.SI.SetValue(retsi)
ret.DI.SetQuad(retdi) ret.DI.SetValue(retdi)
ret.BP.SetQuad(retbp) ret.BP.SetValue(retbp)
return ret return ret
} }
func (p *BackdoorProto) HighBandwidthIn() *BackdoorProto { func (p *BackdoorProto) HighBandwidthIn() *BackdoorProto {
p.DX.Low.Low = BackdoorHighBWPort p.DX.AsUInt32().Low = BackdoorHighBWPort
p.AX.SetQuad(BackdoorMagic) p.AX.SetValue(BackdoorMagic)
retax, retbx, retcx, retdx, retsi, retdi, retbp := bdoor_hbin( retax, retbx, retcx, retdx, retsi, retdi, retbp := bdoor_hbin(
p.AX.Quad(), p.AX.Value(),
p.BX.Quad(), p.BX.Value(),
p.CX.Quad(), p.CX.Value(),
p.DX.Quad(), p.DX.Value(),
p.SI.Quad(), p.SI.Value(),
p.DI.Quad(), p.DI.Value(),
p.BP.Quad(), p.BP.Value(),
) )
ret := &BackdoorProto{} ret := &BackdoorProto{}
ret.AX.SetQuad(retax) ret.AX.SetValue(retax)
ret.BX.SetQuad(retbx) ret.BX.SetValue(retbx)
ret.CX.SetQuad(retcx) ret.CX.SetValue(retcx)
ret.DX.SetQuad(retdx) ret.DX.SetValue(retdx)
ret.SI.SetQuad(retsi) ret.SI.SetValue(retsi)
ret.DI.SetQuad(retdi) ret.DI.SetValue(retdi)
ret.BP.SetQuad(retbp) ret.BP.SetValue(retbp)
return ret return ret
} }

View File

@@ -0,0 +1,48 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bdoor
const (
BackdoorMagic = uint32(0x564D5868)
)
type BackdoorProto struct {
// typedef union {
// struct {
// DECLARE_REG_NAMED_STRUCT(ax);
// size_t size; /* Register bx. */
// DECLARE_REG_NAMED_STRUCT(cx);
// DECLARE_REG_NAMED_STRUCT(dx);
// DECLARE_REG_NAMED_STRUCT(si);
// DECLARE_REG_NAMED_STRUCT(di);
// } in;
// struct {
// DECLARE_REG_NAMED_STRUCT(ax);
// DECLARE_REG_NAMED_STRUCT(bx);
// DECLARE_REG_NAMED_STRUCT(cx);
// DECLARE_REG_NAMED_STRUCT(dx);
// DECLARE_REG_NAMED_STRUCT(si);
// DECLARE_REG_NAMED_STRUCT(di);
// } out;
// } proto;
AX, BX, CX, DX, SI, DI, BP UInt32
size uint32
}
func bdoor_inout(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
func bdoor_hbout(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
func bdoor_hbin(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
func bdoor_inout_test(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)

View File

@@ -0,0 +1,112 @@
#include "textflag.h"
// Doc of the golang plan9 assembler
// http://p9.nyx.link/labs/sys/doc/asm.html
//
// A good primer of how to write golang with some plan9 flavored assembly
// http://www.doxsey.net/blog/go-and-assembly
//
// Some x86 references
// http://www.eecg.toronto.edu/~amza/www.mindsec.com/files/x86regs.html
// https://cseweb.ucsd.edu/classes/sp10/cse141/pdf/02/S01_x86_64.key.pdf
// https://en.wikibooks.org/wiki/X86_Assembly/Other_Instructions
//
// (This one is invaluable. Has a working example of how a standard function
// call looks on the stack with the associated assembly.)
// https://www.recurse.com/blog/7-understanding-c-by-learning-assembly
//
// Reference with raw form of the Opcode
// http://x86.renejeschke.de/html/file_module_x86_id_139.html
//
// Massive x86_64 reference
// http://ref.x86asm.net/coder64.html#xED
//
// Adding instructions to the go assembler
// https://blog.klauspost.com/adding-unsupported-instructions-in-golang-assembler/
//
// Backdoor commands
// https://sites.google.com/site/chitchatvmback/backdoor
// func bdoor_inout(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
TEXT ·bdoor_inout(SB), NOSPLIT|WRAPPER, $0
MOVL ax+0(FP), AX
MOVL bx+4(FP), BX
MOVL cx+8(FP), CX
MOVL dx+12(FP), DX
MOVL si+16(FP), SI
MOVL di+20(FP), DI
MOVL bp+24(FP), BP
// IN to DX from EAX
INL
MOVL AX, retax+28(FP)
MOVL BX, retbx+32(FP)
MOVL CX, retcx+36(FP)
MOVL DX, retdx+40(FP)
MOVL SI, retsi+44(FP)
MOVL DI, retdi+48(FP)
MOVL BP, retbp+52(FP)
RET
// func bdoor_hbout(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
TEXT ·bdoor_hbout(SB), NOSPLIT|WRAPPER, $0
MOVL ax+0(FP), AX
MOVL bx+4(FP), BX
MOVL cx+8(FP), CX
MOVL dx+12(FP), DX
MOVL si+16(FP), SI
MOVL di+20(FP), DI
MOVL bp+24(FP), BP
CLD; REP; OUTSB
MOVL AX, retax+28(FP)
MOVL BX, retbx+32(FP)
MOVL CX, retcx+36(FP)
MOVL DX, retdx+40(FP)
MOVL SI, retsi+44(FP)
MOVL DI, retdi+48(FP)
MOVL BP, retbp+52(FP)
RET
// func bdoor_hbin(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
TEXT ·bdoor_hbin(SB), NOSPLIT|WRAPPER, $0
MOVL ax+0(FP), AX
MOVL bx+4(FP), BX
MOVL cx+8(FP), CX
MOVL dx+12(FP), DX
MOVL si+16(FP), SI
MOVL di+20(FP), DI
MOVL bp+24(FP), BP
CLD; REP; INSB
MOVL AX, retax+28(FP)
MOVL BX, retbx+32(FP)
MOVL CX, retcx+40(FP)
MOVL DX, retdx+44(FP)
MOVL SI, retsi+48(FP)
MOVL DI, retdi+52(FP)
MOVL BP, retbp+56(FP)
RET
// func bdoor_inout_test(ax, bx, cx, dx, si, di, bp uint32) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint32)
TEXT ·bdoor_inout_test(SB), NOSPLIT|WRAPPER, $0
MOVL ax+0(FP), AX
MOVL bx+4(FP), BX
MOVL cx+8(FP), CX
MOVL dx+12(FP), DX
MOVL si+16(FP), SI
MOVL di+20(FP), DI
MOVL bp+24(FP), BP
MOVL AX, retax+28(FP)
MOVL BX, retbx+32(FP)
MOVL CX, retcx+36(FP)
MOVL DX, retdx+40(FP)
MOVL SI, retsi+44(FP)
MOVL DI, retdi+48(FP)
MOVL BP, retbp+52(FP)
RET

View File

@@ -0,0 +1,48 @@
// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bdoor
const (
BackdoorMagic = uint64(0x564D5868)
)
type BackdoorProto struct {
// typedef union {
// struct {
// DECLARE_REG_NAMED_STRUCT(ax);
// size_t size; /* Register bx. */
// DECLARE_REG_NAMED_STRUCT(cx);
// DECLARE_REG_NAMED_STRUCT(dx);
// DECLARE_REG_NAMED_STRUCT(si);
// DECLARE_REG_NAMED_STRUCT(di);
// } in;
// struct {
// DECLARE_REG_NAMED_STRUCT(ax);
// DECLARE_REG_NAMED_STRUCT(bx);
// DECLARE_REG_NAMED_STRUCT(cx);
// DECLARE_REG_NAMED_STRUCT(dx);
// DECLARE_REG_NAMED_STRUCT(si);
// DECLARE_REG_NAMED_STRUCT(di);
// } out;
// } proto;
AX, BX, CX, DX, SI, DI, BP UInt64
size uint32
}
func bdoor_inout(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func bdoor_hbout(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func bdoor_hbin(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)
func bdoor_inout_test(ax, bx, cx, dx, si, di, bp uint64) (retax, retbx, retcx, retdx, retsi, retdi, retbp uint64)

View File

@@ -1,4 +1,4 @@
// Copyright 2016 VMware, Inc. All Rights Reserved. // Copyright 2016-2017 VMware, Inc. All Rights Reserved.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -14,6 +14,8 @@
package bdoor package bdoor
import "unsafe"
type UInt32 struct { type UInt32 struct {
High uint16 High uint16
Low uint16 Low uint16
@@ -28,6 +30,22 @@ func (u *UInt32) SetWord(w uint32) {
u.Low = uint16(w) u.Low = uint16(w)
} }
func (u *UInt32) AsUInt32() *UInt32 {
return u
}
func (u *UInt32) Value() uint32 {
return u.Word()
}
func (u *UInt32) SetValue(val uint32) {
u.SetWord(val)
}
func (u *UInt32) SetPointer(p unsafe.Pointer) {
u.SetWord(uint32(uintptr(p)))
}
type UInt64 struct { type UInt64 struct {
High UInt32 High UInt32
Low UInt32 Low UInt32
@@ -41,3 +59,19 @@ func (u *UInt64) SetQuad(w uint64) {
u.High.SetWord(uint32(w >> 32)) u.High.SetWord(uint32(w >> 32))
u.Low.SetWord(uint32(w)) u.Low.SetWord(uint32(w))
} }
func (u *UInt64) AsUInt32() *UInt32 {
return &u.Low
}
func (u *UInt64) Value() uint64 {
return u.Quad()
}
func (u *UInt64) SetValue(val uint64) {
u.SetQuad(val)
}
func (u *UInt64) SetPointer(p unsafe.Pointer) {
u.SetQuad(uint64(uintptr(p)))
}

View File

@@ -1,4 +1,4 @@
// Copyright 2016 VMware, Inc. All Rights Reserved. // Copyright 2016-2017 VMware, Inc. All Rights Reserved.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -66,12 +66,12 @@ func NewChannel(proto uint32) (*Channel, error) {
retry: retry:
bp := &bdoor.BackdoorProto{} bp := &bdoor.BackdoorProto{}
bp.BX.Low.SetWord(proto | flags) bp.BX.AsUInt32().SetWord(proto | flags)
bp.CX.Low.High = messageTypeOpen bp.CX.AsUInt32().High = messageTypeOpen
bp.CX.Low.Low = bdoor.CommandMessage bp.CX.AsUInt32().Low = bdoor.CommandMessage
out := bp.InOut() out := bp.InOut()
if (out.CX.Low.High & messageStatusSuccess) == 0 { if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
if flags != 0 { if flags != 0 {
flags = 0 flags = 0
goto retry goto retry
@@ -82,9 +82,9 @@ retry:
} }
ch := &Channel{} ch := &Channel{}
ch.id = out.DX.Low.High ch.id = out.DX.AsUInt32().High
ch.cookie.High.SetWord(out.SI.Low.Word()) ch.cookie.High.SetWord(out.SI.AsUInt32().Word())
ch.cookie.Low.SetWord(out.DI.Low.Word()) ch.cookie.Low.SetWord(out.DI.AsUInt32().Word())
Debugf("Opened channel %d", ch.id) Debugf("Opened channel %d", ch.id)
return ch, nil return ch, nil
@@ -93,15 +93,15 @@ retry:
func (c *Channel) Close() error { func (c *Channel) Close() error {
bp := &bdoor.BackdoorProto{} bp := &bdoor.BackdoorProto{}
bp.CX.Low.High = messageTypeClose bp.CX.AsUInt32().High = messageTypeClose
bp.CX.Low.Low = bdoor.CommandMessage bp.CX.AsUInt32().Low = bdoor.CommandMessage
bp.DX.Low.High = c.id bp.DX.AsUInt32().High = c.id
bp.SI.Low.SetWord(c.cookie.High.Word()) bp.SI.AsUInt32().SetWord(c.cookie.High.Word())
bp.DI.Low.SetWord(c.cookie.Low.Word()) bp.DI.AsUInt32().SetWord(c.cookie.Low.Word())
out := bp.InOut() out := bp.InOut()
if (out.CX.Low.High & messageStatusSuccess) == 0 { if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
Errorf("Message: Unable to close communication channel %d", c.id) Errorf("Message: Unable to close communication channel %d", c.id)
return ErrChannelClose return ErrChannelClose
} }
@@ -113,18 +113,18 @@ func (c *Channel) Close() error {
func (c *Channel) Send(buf []byte) error { func (c *Channel) Send(buf []byte) error {
retry: retry:
bp := &bdoor.BackdoorProto{} bp := &bdoor.BackdoorProto{}
bp.CX.Low.High = messageTypeSendSize bp.CX.AsUInt32().High = messageTypeSendSize
bp.CX.Low.Low = bdoor.CommandMessage bp.CX.AsUInt32().Low = bdoor.CommandMessage
bp.DX.Low.High = c.id bp.DX.AsUInt32().High = c.id
bp.SI.Low.SetWord(c.cookie.High.Word()) bp.SI.AsUInt32().SetWord(c.cookie.High.Word())
bp.DI.Low.SetWord(c.cookie.Low.Word()) bp.DI.AsUInt32().SetWord(c.cookie.Low.Word())
bp.BX.Low.SetWord(uint32(len(buf))) bp.BX.AsUInt32().SetWord(uint32(len(buf)))
// send the size // send the size
out := bp.InOut() out := bp.InOut()
if (out.CX.Low.High & messageStatusSuccess) == 0 { if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
Errorf("Message: Unable to send a message over the communication channel %d", c.id) Errorf("Message: Unable to send a message over the communication channel %d", c.id)
return ErrRpciSend return ErrRpciSend
} }
@@ -134,20 +134,20 @@ retry:
return nil return nil
} }
if !c.forceLowBW && (out.CX.Low.High&messageStatusHighBW) == messageStatusHighBW { if !c.forceLowBW && (out.CX.AsUInt32().High&messageStatusHighBW) == messageStatusHighBW {
hbbp := &bdoor.BackdoorProto{} hbbp := &bdoor.BackdoorProto{}
hbbp.BX.Low.Low = bdoor.CommandHighBWMessage hbbp.BX.AsUInt32().Low = bdoor.CommandHighBWMessage
hbbp.BX.Low.High = messageStatusSuccess hbbp.BX.AsUInt32().High = messageStatusSuccess
hbbp.DX.Low.High = c.id hbbp.DX.AsUInt32().High = c.id
hbbp.BP.Low.SetWord(c.cookie.High.Word()) hbbp.BP.AsUInt32().SetWord(c.cookie.High.Word())
hbbp.DI.Low.SetWord(c.cookie.Low.Word()) hbbp.DI.AsUInt32().SetWord(c.cookie.Low.Word())
hbbp.CX.Low.SetWord(uint32(len(buf))) hbbp.CX.AsUInt32().SetWord(uint32(len(buf)))
hbbp.SI.SetQuad(uint64(uintptr(unsafe.Pointer(&buf[0])))) hbbp.SI.SetPointer(unsafe.Pointer(&buf[0]))
out := hbbp.HighBandwidthOut() out := hbbp.HighBandwidthOut()
if (out.BX.Low.High & messageStatusSuccess) == 0 { if (out.BX.AsUInt32().High & messageStatusSuccess) == 0 {
if (out.BX.Low.High & messageStatusCheckPoint) != 0 { if (out.BX.AsUInt32().High & messageStatusCheckPoint) != 0 {
Debugf("A checkpoint occurred. Retrying the operation") Debugf("A checkpoint occurred. Retrying the operation")
goto retry goto retry
} }
@@ -156,7 +156,7 @@ retry:
return ErrRpciSend return ErrRpciSend
} }
} else { } else {
bp.CX.Low.High = messageTypeSendPayload bp.CX.AsUInt32().High = messageTypeSendPayload
bbuf := bytes.NewBuffer(buf) bbuf := bytes.NewBuffer(buf)
for { for {
@@ -169,17 +169,17 @@ retry:
Debugf("sending %q over %d", string(words), c.id) Debugf("sending %q over %d", string(words), c.id)
switch len(words) { switch len(words) {
case 3: case 3:
bp.BX.Low.SetWord(binary.LittleEndian.Uint32([]byte{0x0, words[2], words[1], words[0]})) bp.BX.AsUInt32().SetWord(binary.LittleEndian.Uint32([]byte{0x0, words[2], words[1], words[0]}))
case 2: case 2:
bp.BX.Low.SetWord(uint32(binary.LittleEndian.Uint16(words))) bp.BX.AsUInt32().SetWord(uint32(binary.LittleEndian.Uint16(words)))
case 1: case 1:
bp.BX.Low.SetWord(uint32(words[0])) bp.BX.AsUInt32().SetWord(uint32(words[0]))
default: default:
bp.BX.Low.SetWord(binary.LittleEndian.Uint32(words)) bp.BX.AsUInt32().SetWord(binary.LittleEndian.Uint32(words))
} }
out = bp.InOut() out = bp.InOut()
if (out.CX.Low.High & messageStatusSuccess) == 0 { if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
Errorf("Message: Unable to send a message over the communication channel %d", c.id) Errorf("Message: Unable to send a message over the communication channel %d", c.id)
return ErrRpciSend return ErrRpciSend
} }
@@ -193,50 +193,50 @@ func (c *Channel) Receive() ([]byte, error) {
retry: retry:
var err error var err error
bp := &bdoor.BackdoorProto{} bp := &bdoor.BackdoorProto{}
bp.CX.Low.High = messageTypeReceiveSize bp.CX.AsUInt32().High = messageTypeReceiveSize
bp.CX.Low.Low = bdoor.CommandMessage bp.CX.AsUInt32().Low = bdoor.CommandMessage
bp.DX.Low.High = c.id bp.DX.AsUInt32().High = c.id
bp.SI.Low.SetWord(c.cookie.High.Word()) bp.SI.AsUInt32().SetWord(c.cookie.High.Word())
bp.DI.Low.SetWord(c.cookie.Low.Word()) bp.DI.AsUInt32().SetWord(c.cookie.Low.Word())
out := bp.InOut() out := bp.InOut()
if (out.CX.Low.High & messageStatusSuccess) == 0 { if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
Errorf("Message: Unable to poll for messages over the communication channel %d", c.id) Errorf("Message: Unable to poll for messages over the communication channel %d", c.id)
return nil, ErrRpciReceive return nil, ErrRpciReceive
} }
if (out.CX.Low.High & messageStatusDoRecieve) == 0 { if (out.CX.AsUInt32().High & messageStatusDoRecieve) == 0 {
Debugf("No message to retrieve") Debugf("No message to retrieve")
return nil, nil return nil, nil
} }
// Receive the size. // Receive the size.
if out.DX.Low.High != messageTypeSendSize { if out.DX.AsUInt32().High != messageTypeSendSize {
Errorf("Message: Protocol error. Expected a MESSAGE_TYPE_SENDSIZE request from vmware") Errorf("Message: Protocol error. Expected a MESSAGE_TYPE_SENDSIZE request from vmware")
return nil, ErrRpciReceive return nil, ErrRpciReceive
} }
size := out.BX.Quad() size := out.BX.Value()
var buf []byte var buf []byte
if size != 0 { if size != 0 {
if !c.forceLowBW && (out.CX.Low.High&messageStatusHighBW == messageStatusHighBW) { if !c.forceLowBW && (out.CX.AsUInt32().High&messageStatusHighBW == messageStatusHighBW) {
buf = make([]byte, size) buf = make([]byte, size)
hbbp := &bdoor.BackdoorProto{} hbbp := &bdoor.BackdoorProto{}
hbbp.BX.Low.Low = bdoor.CommandHighBWMessage hbbp.BX.AsUInt32().Low = bdoor.CommandHighBWMessage
hbbp.BX.Low.High = messageStatusSuccess hbbp.BX.AsUInt32().High = messageStatusSuccess
hbbp.DX.Low.High = c.id hbbp.DX.AsUInt32().High = c.id
hbbp.SI.Low.SetWord(c.cookie.High.Word()) hbbp.SI.AsUInt32().SetWord(c.cookie.High.Word())
hbbp.BP.Low.SetWord(c.cookie.Low.Word()) hbbp.BP.AsUInt32().SetWord(c.cookie.Low.Word())
hbbp.CX.Low.SetWord(uint32(len(buf))) hbbp.CX.AsUInt32().SetWord(uint32(len(buf)))
hbbp.DI.SetQuad(uint64(uintptr(unsafe.Pointer(&buf[0])))) hbbp.DI.SetPointer(unsafe.Pointer(&buf[0]))
out := hbbp.HighBandwidthIn() out := hbbp.HighBandwidthIn()
if (out.BX.Low.High & messageStatusSuccess) == 0 { if (out.BX.AsUInt32().High & messageStatusSuccess) == 0 {
Errorf("Message: Unable to send a message over the communication channel %d", c.id) Errorf("Message: Unable to send a message over the communication channel %d", c.id)
c.reply(messageTypeReceivePayload, messageStatusFail) c.reply(messageTypeReceivePayload, messageStatusFail)
return nil, ErrRpciReceive return nil, ErrRpciReceive
@@ -249,12 +249,12 @@ retry:
break break
} }
bp.CX.Low.High = messageTypeReceivePayload bp.CX.AsUInt32().High = messageTypeReceivePayload
bp.BX.Low.Low = messageStatusSuccess bp.BX.AsUInt32().Low = messageStatusSuccess
out = bp.InOut() out = bp.InOut()
if (out.CX.Low.High & messageStatusSuccess) == 0 { if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
if (out.CX.Low.High & messageStatusCheckPoint) != 0 { if (out.CX.AsUInt32().High & messageStatusCheckPoint) != 0 {
Debugf("A checkpoint occurred. Retrying the operation") Debugf("A checkpoint occurred. Retrying the operation")
goto retry goto retry
} }
@@ -264,34 +264,34 @@ retry:
return nil, ErrRpciReceive return nil, ErrRpciReceive
} }
if out.DX.Low.High != messageTypeSendPayload { if out.DX.AsUInt32().High != messageTypeSendPayload {
Errorf("Message: Protocol error. Expected a MESSAGE_TYPE_SENDPAYLOAD from vmware") Errorf("Message: Protocol error. Expected a MESSAGE_TYPE_SENDPAYLOAD from vmware")
c.reply(messageTypeReceivePayload, messageStatusFail) c.reply(messageTypeReceivePayload, messageStatusFail)
return nil, ErrRpciReceive return nil, ErrRpciReceive
} }
Debugf("Received %#v", out.BX.Low.Word()) Debugf("Received %#v", out.BX.AsUInt32().Word())
switch size { switch size {
case 1: case 1:
err = binary.Write(b, binary.LittleEndian, uint8(out.BX.Low.Low)) err = binary.Write(b, binary.LittleEndian, uint8(out.BX.AsUInt32().Low))
size = size - 1 size = size - 1
case 2: case 2:
err = binary.Write(b, binary.LittleEndian, uint16(out.BX.Low.Low)) err = binary.Write(b, binary.LittleEndian, uint16(out.BX.AsUInt32().Low))
size = size - 2 size = size - 2
case 3: case 3:
err = binary.Write(b, binary.LittleEndian, uint16(out.BX.Low.Low)) err = binary.Write(b, binary.LittleEndian, uint16(out.BX.AsUInt32().Low))
if err != nil { if err != nil {
c.reply(messageTypeReceivePayload, messageStatusFail) c.reply(messageTypeReceivePayload, messageStatusFail)
return nil, ErrRpciReceive return nil, ErrRpciReceive
} }
err = binary.Write(b, binary.LittleEndian, uint8(out.BX.Low.High)) err = binary.Write(b, binary.LittleEndian, uint8(out.BX.AsUInt32().High))
size = size - 3 size = size - 3
default: default:
err = binary.Write(b, binary.LittleEndian, out.BX.Low.Word()) err = binary.Write(b, binary.LittleEndian, out.BX.AsUInt32().Word())
size = size - 4 size = size - 4
} }
@@ -314,17 +314,17 @@ retry:
func (c *Channel) reply(messageType, messageStatus uint16) { func (c *Channel) reply(messageType, messageStatus uint16) {
bp := &bdoor.BackdoorProto{} bp := &bdoor.BackdoorProto{}
bp.BX.Low.Low = messageStatus bp.BX.AsUInt32().Low = messageStatus
bp.CX.Low.High = messageType bp.CX.AsUInt32().High = messageType
bp.CX.Low.Low = bdoor.CommandMessage bp.CX.AsUInt32().Low = bdoor.CommandMessage
bp.DX.Low.High = c.id bp.DX.AsUInt32().High = c.id
bp.SI.Low.SetWord(c.cookie.High.Word()) bp.SI.AsUInt32().SetWord(c.cookie.High.Word())
bp.DI.Low.SetWord(c.cookie.Low.Word()) bp.DI.AsUInt32().SetWord(c.cookie.Low.Word())
out := bp.InOut() out := bp.InOut()
/* OUT: Status */ /* OUT: Status */
if (out.CX.Low.High & messageStatusSuccess) == 0 { if (out.CX.AsUInt32().High & messageStatusSuccess) == 0 {
if messageStatus == messageStatusSuccess { if messageStatus == messageStatusSuccess {
Errorf("reply Message: Unable to send a message over the communication channel %d", c.id) Errorf("reply Message: Unable to send a message over the communication channel %d", c.id)
} else { } else {