mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	Vendor github.com/godbus/dbus and github.com/coreos/go-systemd
We need this to do systemd API calls. We also add the static_build tag to make godbus not use os/user which is problematic for static builds. Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
This commit is contained in:
		
							parent
							
								
									9294d7f2af
								
							
						
					
					
						commit
						d4725801b3
					
				
					 74 changed files with 8313 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -89,7 +89,7 @@ LDFLAGS='
 | 
			
		|||
'
 | 
			
		||||
LDFLAGS_STATIC='-linkmode external'
 | 
			
		||||
EXTLDFLAGS_STATIC='-static'
 | 
			
		||||
BUILDFLAGS=( -a -tags "netgo $DOCKER_BUILDTAGS" )
 | 
			
		||||
BUILDFLAGS=( -a -tags "netgo static_build $DOCKER_BUILDTAGS" )
 | 
			
		||||
 | 
			
		||||
# A few more flags that are specific just to building a completely-static binary (see hack/make/binary)
 | 
			
		||||
# PLEASE do not use these anywhere else.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,3 +58,6 @@ mv src/code.google.com/p/go/src/pkg/archive/tar tmp-tar
 | 
			
		|||
rm -rf src/code.google.com/p/go
 | 
			
		||||
mkdir -p src/code.google.com/p/go/src/pkg/archive
 | 
			
		||||
mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
 | 
			
		||||
 | 
			
		||||
clone git github.com/godbus/dbus cb98efbb933d8389ab549a060e880ea3c375d213
 | 
			
		||||
clone git github.com/coreos/go-systemd 4c14ed39b8a643ac44b4f95b5a53c00e94261475
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										8
									
								
								vendor/src/github.com/coreos/go-systemd/.travis.yml
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/src/github.com/coreos/go-systemd/.travis.yml
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
language: go
 | 
			
		||||
go: 1.2
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
 - echo "Skip install"
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
 - ./test
 | 
			
		||||
							
								
								
									
										191
									
								
								vendor/src/github.com/coreos/go-systemd/LICENSE
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								vendor/src/github.com/coreos/go-systemd/LICENSE
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,191 @@
 | 
			
		|||
Apache License
 | 
			
		||||
Version 2.0, January 2004
 | 
			
		||||
http://www.apache.org/licenses/
 | 
			
		||||
 | 
			
		||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
			
		||||
 | 
			
		||||
1. Definitions.
 | 
			
		||||
 | 
			
		||||
"License" shall mean the terms and conditions for use, reproduction, and
 | 
			
		||||
distribution as defined by Sections 1 through 9 of this document.
 | 
			
		||||
 | 
			
		||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
 | 
			
		||||
owner that is granting the License.
 | 
			
		||||
 | 
			
		||||
"Legal Entity" shall mean the union of the acting entity and all other entities
 | 
			
		||||
that control, are controlled by, or are under common control with that entity.
 | 
			
		||||
For the purposes of this definition, "control" means (i) the power, direct or
 | 
			
		||||
indirect, to cause the direction or management of such entity, whether by
 | 
			
		||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
			
		||||
outstanding shares, or (iii) beneficial ownership of such entity.
 | 
			
		||||
 | 
			
		||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
 | 
			
		||||
permissions granted by this License.
 | 
			
		||||
 | 
			
		||||
"Source" form shall mean the preferred form for making modifications, including
 | 
			
		||||
but not limited to software source code, documentation source, and configuration
 | 
			
		||||
files.
 | 
			
		||||
 | 
			
		||||
"Object" form shall mean any form resulting from mechanical transformation or
 | 
			
		||||
translation of a Source form, including but not limited to compiled object code,
 | 
			
		||||
generated documentation, and conversions to other media types.
 | 
			
		||||
 | 
			
		||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
 | 
			
		||||
available under the License, as indicated by a copyright notice that is included
 | 
			
		||||
in or attached to the work (an example is provided in the Appendix below).
 | 
			
		||||
 | 
			
		||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
 | 
			
		||||
is based on (or derived from) the Work and for which the editorial revisions,
 | 
			
		||||
annotations, elaborations, or other modifications represent, as a whole, an
 | 
			
		||||
original work of authorship. For the purposes of this License, Derivative Works
 | 
			
		||||
shall not include works that remain separable from, or merely link (or bind by
 | 
			
		||||
name) to the interfaces of, the Work and Derivative Works thereof.
 | 
			
		||||
 | 
			
		||||
"Contribution" shall mean any work of authorship, including the original version
 | 
			
		||||
of the Work and any modifications or additions to that Work or Derivative Works
 | 
			
		||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
 | 
			
		||||
by the copyright owner or by an individual or Legal Entity authorized to submit
 | 
			
		||||
on behalf of the copyright owner. For the purposes of this definition,
 | 
			
		||||
"submitted" means any form of electronic, verbal, or written communication sent
 | 
			
		||||
to the Licensor or its representatives, including but not limited to
 | 
			
		||||
communication on electronic mailing lists, source code control systems, and
 | 
			
		||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
 | 
			
		||||
the purpose of discussing and improving the Work, but excluding communication
 | 
			
		||||
that is conspicuously marked or otherwise designated in writing by the copyright
 | 
			
		||||
owner as "Not a Contribution."
 | 
			
		||||
 | 
			
		||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
 | 
			
		||||
of whom a Contribution has been received by Licensor and subsequently
 | 
			
		||||
incorporated within the Work.
 | 
			
		||||
 | 
			
		||||
2. Grant of Copyright License.
 | 
			
		||||
 | 
			
		||||
Subject to the terms and conditions of this License, each Contributor hereby
 | 
			
		||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
 | 
			
		||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
 | 
			
		||||
publicly display, publicly perform, sublicense, and distribute the Work and such
 | 
			
		||||
Derivative Works in Source or Object form.
 | 
			
		||||
 | 
			
		||||
3. Grant of Patent License.
 | 
			
		||||
 | 
			
		||||
Subject to the terms and conditions of this License, each Contributor 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, and otherwise transfer the Work, where
 | 
			
		||||
such license applies only to those patent claims licensable by such Contributor
 | 
			
		||||
that are necessarily infringed by their Contribution(s) alone or by combination
 | 
			
		||||
of their Contribution(s) with the Work to which such Contribution(s) was
 | 
			
		||||
submitted. If You institute patent litigation against any entity (including a
 | 
			
		||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
 | 
			
		||||
Contribution incorporated within the Work constitutes direct or contributory
 | 
			
		||||
patent infringement, then any patent licenses granted to You under this License
 | 
			
		||||
for that Work shall terminate as of the date such litigation is filed.
 | 
			
		||||
 | 
			
		||||
4. Redistribution.
 | 
			
		||||
 | 
			
		||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
 | 
			
		||||
in any medium, with or without modifications, and in Source or Object form,
 | 
			
		||||
provided that You meet the following conditions:
 | 
			
		||||
 | 
			
		||||
You must give any other recipients of the Work or Derivative Works a copy of
 | 
			
		||||
this License; and
 | 
			
		||||
You must cause any modified files to carry prominent notices stating that You
 | 
			
		||||
changed the files; and
 | 
			
		||||
You must retain, in the Source form of any Derivative Works that You distribute,
 | 
			
		||||
all copyright, patent, trademark, and attribution notices from the Source form
 | 
			
		||||
of the Work, excluding those notices that do not pertain to any part of the
 | 
			
		||||
Derivative Works; and
 | 
			
		||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
 | 
			
		||||
Derivative Works that You distribute must include a readable copy of the
 | 
			
		||||
attribution notices contained within such NOTICE file, excluding those notices
 | 
			
		||||
that do not pertain to any part of the Derivative Works, in at least one of the
 | 
			
		||||
following places: within a NOTICE text file distributed as part of the
 | 
			
		||||
Derivative Works; within the Source form or documentation, if provided along
 | 
			
		||||
with the Derivative Works; or, within a display generated by the Derivative
 | 
			
		||||
Works, if and wherever such third-party notices normally appear. The contents of
 | 
			
		||||
the NOTICE file are for informational purposes only and do not modify the
 | 
			
		||||
License. You may add Your own attribution notices within Derivative Works that
 | 
			
		||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
 | 
			
		||||
provided that such additional attribution notices cannot be construed as
 | 
			
		||||
modifying the License.
 | 
			
		||||
You may add Your own copyright statement to Your modifications and may provide
 | 
			
		||||
additional or different license terms and conditions for use, reproduction, or
 | 
			
		||||
distribution of Your modifications, or for any such Derivative Works as a whole,
 | 
			
		||||
provided Your use, reproduction, and distribution of the Work otherwise complies
 | 
			
		||||
with the conditions stated in this License.
 | 
			
		||||
 | 
			
		||||
5. Submission of Contributions.
 | 
			
		||||
 | 
			
		||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
 | 
			
		||||
for inclusion in the Work by You to the Licensor shall be under the terms and
 | 
			
		||||
conditions of this License, without any additional terms or conditions.
 | 
			
		||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
 | 
			
		||||
any separate license agreement you may have executed with Licensor regarding
 | 
			
		||||
such Contributions.
 | 
			
		||||
 | 
			
		||||
6. Trademarks.
 | 
			
		||||
 | 
			
		||||
This License does not grant permission to use the trade names, trademarks,
 | 
			
		||||
service marks, or product names of the Licensor, except as required for
 | 
			
		||||
reasonable and customary use in describing the origin of the Work and
 | 
			
		||||
reproducing the content of the NOTICE file.
 | 
			
		||||
 | 
			
		||||
7. Disclaimer of Warranty.
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, Licensor provides the
 | 
			
		||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
 | 
			
		||||
including, without limitation, any warranties or conditions of TITLE,
 | 
			
		||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
 | 
			
		||||
solely responsible for determining the appropriateness of using or
 | 
			
		||||
redistributing the Work and assume any risks associated with Your exercise of
 | 
			
		||||
permissions under this License.
 | 
			
		||||
 | 
			
		||||
8. Limitation of Liability.
 | 
			
		||||
 | 
			
		||||
In no event and under no legal theory, whether in tort (including negligence),
 | 
			
		||||
contract, or otherwise, unless required by applicable law (such as deliberate
 | 
			
		||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
 | 
			
		||||
liable to You for damages, including any direct, indirect, special, incidental,
 | 
			
		||||
or consequential damages of any character arising as a result of this License or
 | 
			
		||||
out of the use or inability to use the Work (including but not limited to
 | 
			
		||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
 | 
			
		||||
any and all other commercial damages or losses), even if such Contributor has
 | 
			
		||||
been advised of the possibility of such damages.
 | 
			
		||||
 | 
			
		||||
9. Accepting Warranty or Additional Liability.
 | 
			
		||||
 | 
			
		||||
While redistributing the Work or Derivative Works thereof, You may choose to
 | 
			
		||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
 | 
			
		||||
other liability obligations and/or rights consistent with this License. However,
 | 
			
		||||
in accepting such obligations, You may act only on Your own behalf and on Your
 | 
			
		||||
sole responsibility, not on behalf of any other Contributor, and only if You
 | 
			
		||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
 | 
			
		||||
incurred by, or claims asserted against, such Contributor by reason of your
 | 
			
		||||
accepting any such warranty or additional liability.
 | 
			
		||||
 | 
			
		||||
END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
APPENDIX: How to apply the Apache License to your work
 | 
			
		||||
 | 
			
		||||
To apply the Apache License to your work, attach the following boilerplate
 | 
			
		||||
notice, with the fields enclosed by brackets "[]" replaced with your own
 | 
			
		||||
identifying information. (Don't include the brackets!) The text should be
 | 
			
		||||
enclosed in the appropriate comment syntax for the file format. We also
 | 
			
		||||
recommend that a file or class name and description of purpose be included on
 | 
			
		||||
the same "printed page" as the copyright notice for easier identification within
 | 
			
		||||
third-party archives.
 | 
			
		||||
 | 
			
		||||
   Copyright [yyyy] [name of copyright owner]
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
							
								
								
									
										44
									
								
								vendor/src/github.com/coreos/go-systemd/README.md
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								vendor/src/github.com/coreos/go-systemd/README.md
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
# go-systemd
 | 
			
		||||
 | 
			
		||||
Go bindings to systemd. The project has three packages:
 | 
			
		||||
 | 
			
		||||
- activation - for writing and using socket activation from Go
 | 
			
		||||
- journal - for writing to systemd's logging service, journal
 | 
			
		||||
- dbus - for starting/stopping/inspecting running services and units
 | 
			
		||||
 | 
			
		||||
Go docs for the entire project are here:
 | 
			
		||||
 | 
			
		||||
http://godoc.org/github.com/coreos/go-systemd
 | 
			
		||||
 | 
			
		||||
## Socket Activation
 | 
			
		||||
 | 
			
		||||
An example HTTP server using socket activation can be quickly setup by
 | 
			
		||||
following this README on a Linux machine running systemd:
 | 
			
		||||
 | 
			
		||||
https://github.com/coreos/go-systemd/tree/master/examples/activation/httpserver
 | 
			
		||||
 | 
			
		||||
## Journal
 | 
			
		||||
 | 
			
		||||
Using this package you can submit journal entries directly to systemd's journal taking advantage of features like indexed key/value pairs for each log entry.
 | 
			
		||||
 | 
			
		||||
## D-Bus
 | 
			
		||||
 | 
			
		||||
The D-Bus API lets you start, stop and introspect systemd units. The API docs are here:
 | 
			
		||||
 | 
			
		||||
http://godoc.org/github.com/coreos/go-systemd/dbus
 | 
			
		||||
 | 
			
		||||
### Debugging
 | 
			
		||||
 | 
			
		||||
Create `/etc/dbus-1/system-local.conf` that looks like this:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
<!DOCTYPE busconfig PUBLIC
 | 
			
		||||
"-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
 | 
			
		||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
 | 
			
		||||
<busconfig>
 | 
			
		||||
    <policy user="root">
 | 
			
		||||
        <allow eavesdrop="true"/>
 | 
			
		||||
        <allow eavesdrop="true" send_destination="*"/>
 | 
			
		||||
    </policy>
 | 
			
		||||
</busconfig>
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										56
									
								
								vendor/src/github.com/coreos/go-systemd/activation/files.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								vendor/src/github.com/coreos/go-systemd/activation/files.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,56 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2013 CoreOS Inc.
 | 
			
		||||
 | 
			
		||||
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 activation implements primitives for systemd socket activation.
 | 
			
		||||
package activation
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// based on: https://gist.github.com/alberts/4640792
 | 
			
		||||
const (
 | 
			
		||||
	listenFdsStart = 3
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Files(unsetEnv bool) []*os.File {
 | 
			
		||||
	if unsetEnv {
 | 
			
		||||
		// there is no way to unset env in golang os package for now
 | 
			
		||||
		// https://code.google.com/p/go/issues/detail?id=6423
 | 
			
		||||
		defer os.Setenv("LISTEN_PID", "")
 | 
			
		||||
		defer os.Setenv("LISTEN_FDS", "")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
 | 
			
		||||
	if err != nil || pid != os.Getpid() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS"))
 | 
			
		||||
	if err != nil || nfds == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var files []*os.File
 | 
			
		||||
	for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ {
 | 
			
		||||
		syscall.CloseOnExec(fd)
 | 
			
		||||
		files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd)))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return files
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										84
									
								
								vendor/src/github.com/coreos/go-systemd/activation/files_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								vendor/src/github.com/coreos/go-systemd/activation/files_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,84 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2013 CoreOS Inc.
 | 
			
		||||
 | 
			
		||||
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 activation
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// correctStringWritten fails the text if the correct string wasn't written
 | 
			
		||||
// to the other side of the pipe.
 | 
			
		||||
func correctStringWritten(t *testing.T, r *os.File, expected string) bool {
 | 
			
		||||
	bytes := make([]byte, len(expected))
 | 
			
		||||
	io.ReadAtLeast(r, bytes, len(expected))
 | 
			
		||||
 | 
			
		||||
	if string(bytes) != expected {
 | 
			
		||||
		t.Fatalf("Unexpected string %s", string(bytes))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestActivation forks out a copy of activation.go example and reads back two
 | 
			
		||||
// strings from the pipes that are passed in.
 | 
			
		||||
func TestActivation(t *testing.T) {
 | 
			
		||||
	cmd := exec.Command("go", "run", "../examples/activation/activation.go")
 | 
			
		||||
 | 
			
		||||
	r1, w1, _ := os.Pipe()
 | 
			
		||||
	r2, w2, _ := os.Pipe()
 | 
			
		||||
	cmd.ExtraFiles = []*os.File{
 | 
			
		||||
		w1,
 | 
			
		||||
		w2,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd.Env = os.Environ()
 | 
			
		||||
	cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "FIX_LISTEN_PID=1")
 | 
			
		||||
 | 
			
		||||
	err := cmd.Run()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	correctStringWritten(t, r1, "Hello world")
 | 
			
		||||
	correctStringWritten(t, r2, "Goodbye world")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestActivationNoFix(t *testing.T) {
 | 
			
		||||
	cmd := exec.Command("go", "run", "../examples/activation/activation.go")
 | 
			
		||||
	cmd.Env = os.Environ()
 | 
			
		||||
	cmd.Env = append(cmd.Env, "LISTEN_FDS=2")
 | 
			
		||||
 | 
			
		||||
	out, _ := cmd.CombinedOutput()
 | 
			
		||||
	if bytes.Contains(out, []byte("No files")) == false {
 | 
			
		||||
		t.Fatalf("Child didn't error out as expected")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestActivationNoFiles(t *testing.T) {
 | 
			
		||||
	cmd := exec.Command("go", "run", "../examples/activation/activation.go")
 | 
			
		||||
	cmd.Env = os.Environ()
 | 
			
		||||
	cmd.Env = append(cmd.Env, "LISTEN_FDS=0", "FIX_LISTEN_PID=1")
 | 
			
		||||
 | 
			
		||||
	out, _ := cmd.CombinedOutput()
 | 
			
		||||
	if bytes.Contains(out, []byte("No files")) == false {
 | 
			
		||||
		t.Fatalf("Child didn't error out as expected")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								vendor/src/github.com/coreos/go-systemd/activation/listeners.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								vendor/src/github.com/coreos/go-systemd/activation/listeners.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2014 CoreOS Inc.
 | 
			
		||||
 | 
			
		||||
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 activation
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Listeners returns net.Listeners for all socket activated fds passed to this process.
 | 
			
		||||
func Listeners(unsetEnv bool) ([]net.Listener, error) {
 | 
			
		||||
	files := Files(unsetEnv)
 | 
			
		||||
	listeners := make([]net.Listener, len(files))
 | 
			
		||||
 | 
			
		||||
	for i, f := range files {
 | 
			
		||||
		var err error
 | 
			
		||||
		listeners[i], err = net.FileListener(f)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("Error setting up FileListener for fd %d: %s", f.Fd(), err.Error())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return listeners, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										88
									
								
								vendor/src/github.com/coreos/go-systemd/activation/listeners_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								vendor/src/github.com/coreos/go-systemd/activation/listeners_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,88 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2014 CoreOS Inc.
 | 
			
		||||
 | 
			
		||||
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 activation
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// correctStringWritten fails the text if the correct string wasn't written
 | 
			
		||||
// to the other side of the pipe.
 | 
			
		||||
func correctStringWrittenNet(t *testing.T, r net.Conn, expected string) bool {
 | 
			
		||||
	bytes := make([]byte, len(expected))
 | 
			
		||||
	io.ReadAtLeast(r, bytes, len(expected))
 | 
			
		||||
 | 
			
		||||
	if string(bytes) != expected {
 | 
			
		||||
		t.Fatalf("Unexpected string %s", string(bytes))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestActivation forks out a copy of activation.go example and reads back two
 | 
			
		||||
// strings from the pipes that are passed in.
 | 
			
		||||
func TestListeners(t *testing.T) {
 | 
			
		||||
	cmd := exec.Command("go", "run", "../examples/activation/listen.go")
 | 
			
		||||
 | 
			
		||||
	l1, err := net.Listen("tcp", ":9999")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	l2, err := net.Listen("tcp", ":1234")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t1 := l1.(*net.TCPListener)
 | 
			
		||||
	t2 := l2.(*net.TCPListener)
 | 
			
		||||
 | 
			
		||||
	f1, _ := t1.File()
 | 
			
		||||
	f2, _  := t2.File()
 | 
			
		||||
 | 
			
		||||
	cmd.ExtraFiles = []*os.File{
 | 
			
		||||
		f1,
 | 
			
		||||
		f2,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r1, err := net.Dial("tcp", "127.0.0.1:9999")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	r1.Write([]byte("Hi"))
 | 
			
		||||
 | 
			
		||||
	r2, err := net.Dial("tcp", "127.0.0.1:1234")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	r2.Write([]byte("Hi"))
 | 
			
		||||
 | 
			
		||||
	cmd.Env = os.Environ()
 | 
			
		||||
	cmd.Env = append(cmd.Env, "LISTEN_FDS=2", "FIX_LISTEN_PID=1")
 | 
			
		||||
 | 
			
		||||
	out, err := cmd.Output()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		println(string(out))
 | 
			
		||||
		t.Fatalf(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	correctStringWrittenNet(t, r1, "Hello world")
 | 
			
		||||
	correctStringWrittenNet(t, r2, "Goodbye world")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										104
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/dbus.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/dbus.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,104 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2013 CoreOS Inc.
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// Integration with the systemd D-Bus API.  See http://www.freedesktop.org/wiki/Software/systemd/dbus/
 | 
			
		||||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const signalBuffer = 100
 | 
			
		||||
 | 
			
		||||
// ObjectPath creates a dbus.ObjectPath using the rules that systemd uses for
 | 
			
		||||
// serializing special characters.
 | 
			
		||||
func ObjectPath(path string) dbus.ObjectPath {
 | 
			
		||||
	path = strings.Replace(path, ".", "_2e", -1)
 | 
			
		||||
	path = strings.Replace(path, "-", "_2d", -1)
 | 
			
		||||
	path = strings.Replace(path, "@", "_40", -1)
 | 
			
		||||
 | 
			
		||||
	return dbus.ObjectPath(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Conn is a connection to systemds dbus endpoint.
 | 
			
		||||
type Conn struct {
 | 
			
		||||
	sysconn     *dbus.Conn
 | 
			
		||||
	sysobj      *dbus.Object
 | 
			
		||||
	jobListener struct {
 | 
			
		||||
		jobs map[dbus.ObjectPath]chan string
 | 
			
		||||
		sync.Mutex
 | 
			
		||||
	}
 | 
			
		||||
	subscriber struct {
 | 
			
		||||
		updateCh chan<- *SubStateUpdate
 | 
			
		||||
		errCh    chan<- error
 | 
			
		||||
		sync.Mutex
 | 
			
		||||
		ignore      map[dbus.ObjectPath]int64
 | 
			
		||||
		cleanIgnore int64
 | 
			
		||||
	}
 | 
			
		||||
	dispatch map[string]func(dbus.Signal)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New() establishes a connection to the system bus and authenticates.
 | 
			
		||||
func New() (*Conn, error) {
 | 
			
		||||
	c := new(Conn)
 | 
			
		||||
 | 
			
		||||
	if err := c.initConnection(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.initJobs()
 | 
			
		||||
	return c, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) initConnection() error {
 | 
			
		||||
	var err error
 | 
			
		||||
	c.sysconn, err = dbus.SystemBusPrivate()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Only use EXTERNAL method, and hardcode the uid (not username)
 | 
			
		||||
	// to avoid a username lookup (which requires a dynamically linked
 | 
			
		||||
	// libc)
 | 
			
		||||
	methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))}
 | 
			
		||||
 | 
			
		||||
	err = c.sysconn.Auth(methods)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.sysconn.Close()
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = c.sysconn.Hello()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.sysconn.Close()
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.sysobj = c.sysconn.Object("org.freedesktop.systemd1", dbus.ObjectPath("/org/freedesktop/systemd1"))
 | 
			
		||||
 | 
			
		||||
	// Setup the listeners on jobs so that we can get completions
 | 
			
		||||
	c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
 | 
			
		||||
		"type='signal', interface='org.freedesktop.systemd1.Manager', member='JobRemoved'")
 | 
			
		||||
	c.initSubscription()
 | 
			
		||||
	c.initDispatch()
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/dbus_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/dbus_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2013 CoreOS Inc.
 | 
			
		||||
 | 
			
		||||
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 dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TestObjectPath ensures path encoding of the systemd rules works.
 | 
			
		||||
func TestObjectPath(t *testing.T) {
 | 
			
		||||
	input := "/silly-path/to@a/unit..service"
 | 
			
		||||
	output := ObjectPath(input)
 | 
			
		||||
	expected := "/silly_2dpath/to_40a/unit_2e_2eservice"
 | 
			
		||||
 | 
			
		||||
	if string(output) != expected {
 | 
			
		||||
		t.Fatalf("Output '%s' did not match expected '%s'", output, expected)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestNew ensures that New() works without errors.
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	_, err := New()
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										354
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/methods.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/methods.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,354 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2013 CoreOS Inc.
 | 
			
		||||
 | 
			
		||||
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 dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (c *Conn) initJobs() {
 | 
			
		||||
	c.jobListener.jobs = make(map[dbus.ObjectPath]chan string)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) jobComplete(signal *dbus.Signal) {
 | 
			
		||||
	var id uint32
 | 
			
		||||
	var job dbus.ObjectPath
 | 
			
		||||
	var unit string
 | 
			
		||||
	var result string
 | 
			
		||||
	dbus.Store(signal.Body, &id, &job, &unit, &result)
 | 
			
		||||
	c.jobListener.Lock()
 | 
			
		||||
	out, ok := c.jobListener.jobs[job]
 | 
			
		||||
	if ok {
 | 
			
		||||
		out <- result
 | 
			
		||||
		delete(c.jobListener.jobs, job)
 | 
			
		||||
	}
 | 
			
		||||
	c.jobListener.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) startJob(job string, args ...interface{}) (<-chan string, error) {
 | 
			
		||||
	c.jobListener.Lock()
 | 
			
		||||
	defer c.jobListener.Unlock()
 | 
			
		||||
 | 
			
		||||
	ch := make(chan string, 1)
 | 
			
		||||
	var path dbus.ObjectPath
 | 
			
		||||
	err := c.sysobj.Call(job, 0, args...).Store(&path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	c.jobListener.jobs[path] = ch
 | 
			
		||||
	return ch, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) runJob(job string, args ...interface{}) (string, error) {
 | 
			
		||||
	respCh, err := c.startJob(job, args...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return <-respCh, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StartUnit enqeues a start job and depending jobs, if any (unless otherwise
 | 
			
		||||
// specified by the mode string).
 | 
			
		||||
//
 | 
			
		||||
// Takes the unit to activate, plus a mode string. The mode needs to be one of
 | 
			
		||||
// replace, fail, isolate, ignore-dependencies, ignore-requirements. If
 | 
			
		||||
// "replace" the call will start the unit and its dependencies, possibly
 | 
			
		||||
// replacing already queued jobs that conflict with this. If "fail" the call
 | 
			
		||||
// will start the unit and its dependencies, but will fail if this would change
 | 
			
		||||
// an already queued job. If "isolate" the call will start the unit in question
 | 
			
		||||
// and terminate all units that aren't dependencies of it. If
 | 
			
		||||
// "ignore-dependencies" it will start a unit but ignore all its dependencies.
 | 
			
		||||
// If "ignore-requirements" it will start a unit but only ignore the
 | 
			
		||||
// requirement dependencies. It is not recommended to make use of the latter
 | 
			
		||||
// two options.
 | 
			
		||||
//
 | 
			
		||||
// Result string: one of done, canceled, timeout, failed, dependency, skipped.
 | 
			
		||||
// done indicates successful execution of a job. canceled indicates that a job
 | 
			
		||||
// has been canceled  before it finished execution. timeout indicates that the
 | 
			
		||||
// job timeout was reached. failed indicates that the job failed. dependency
 | 
			
		||||
// indicates that a job this job has been depending on failed and the job hence
 | 
			
		||||
// has been removed too. skipped indicates that a job was skipped because it
 | 
			
		||||
// didn't apply to the units current state.
 | 
			
		||||
func (c *Conn) StartUnit(name string, mode string) (string, error) {
 | 
			
		||||
	return c.runJob("org.freedesktop.systemd1.Manager.StartUnit", name, mode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StopUnit is similar to StartUnit but stops the specified unit rather
 | 
			
		||||
// than starting it.
 | 
			
		||||
func (c *Conn) StopUnit(name string, mode string) (string, error) {
 | 
			
		||||
	return c.runJob("org.freedesktop.systemd1.Manager.StopUnit", name, mode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReloadUnit reloads a unit.  Reloading is done only if the unit is already running and fails otherwise.
 | 
			
		||||
func (c *Conn) ReloadUnit(name string, mode string) (string, error) {
 | 
			
		||||
	return c.runJob("org.freedesktop.systemd1.Manager.ReloadUnit", name, mode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RestartUnit restarts a service.  If a service is restarted that isn't
 | 
			
		||||
// running it will be started.
 | 
			
		||||
func (c *Conn) RestartUnit(name string, mode string) (string, error) {
 | 
			
		||||
	return c.runJob("org.freedesktop.systemd1.Manager.RestartUnit", name, mode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TryRestartUnit is like RestartUnit, except that a service that isn't running
 | 
			
		||||
// is not affected by the restart.
 | 
			
		||||
func (c *Conn) TryRestartUnit(name string, mode string) (string, error) {
 | 
			
		||||
	return c.runJob("org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReloadOrRestart attempts a reload if the unit supports it and use a restart
 | 
			
		||||
// otherwise.
 | 
			
		||||
func (c *Conn) ReloadOrRestartUnit(name string, mode string) (string, error) {
 | 
			
		||||
	return c.runJob("org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try"
 | 
			
		||||
// flavored restart otherwise.
 | 
			
		||||
func (c *Conn) ReloadOrTryRestartUnit(name string, mode string) (string, error) {
 | 
			
		||||
	return c.runJob("org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StartTransientUnit() may be used to create and start a transient unit, which
 | 
			
		||||
// will be released as soon as it is not running or referenced anymore or the
 | 
			
		||||
// system is rebooted. name is the unit name including suffix, and must be
 | 
			
		||||
// unique. mode is the same as in StartUnit(), properties contains properties
 | 
			
		||||
// of the unit.
 | 
			
		||||
func (c *Conn) StartTransientUnit(name string, mode string, properties ...Property) (string, error) {
 | 
			
		||||
	return c.runJob("org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// KillUnit takes the unit name and a UNIX signal number to send.  All of the unit's
 | 
			
		||||
// processes are killed.
 | 
			
		||||
func (c *Conn) KillUnit(name string, signal int32) {
 | 
			
		||||
	c.sysobj.Call("org.freedesktop.systemd1.Manager.KillUnit", 0, name, "all", signal).Store()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getProperties takes the unit name and returns all of its dbus object properties, for the given dbus interface
 | 
			
		||||
func (c *Conn) getProperties(unit string, dbusInterface string) (map[string]interface{}, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	var props map[string]dbus.Variant
 | 
			
		||||
 | 
			
		||||
	path := ObjectPath("/org/freedesktop/systemd1/unit/" + unit)
 | 
			
		||||
	if !path.IsValid() {
 | 
			
		||||
		return nil, errors.New("invalid unit name: " + unit)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	obj := c.sysconn.Object("org.freedesktop.systemd1", path)
 | 
			
		||||
	err = obj.Call("org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	out := make(map[string]interface{}, len(props))
 | 
			
		||||
	for k, v := range props {
 | 
			
		||||
		out[k] = v.Value()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return out, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUnitProperties takes the unit name and returns all of its dbus object properties.
 | 
			
		||||
func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) {
 | 
			
		||||
	return c.getProperties(unit, "org.freedesktop.systemd1.Unit")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) getProperty(unit string, dbusInterface string, propertyName string) (*Property, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	var prop dbus.Variant
 | 
			
		||||
 | 
			
		||||
	path := ObjectPath("/org/freedesktop/systemd1/unit/" + unit)
 | 
			
		||||
	if !path.IsValid() {
 | 
			
		||||
		return nil, errors.New("invalid unit name: " + unit)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	obj := c.sysconn.Object("org.freedesktop.systemd1", path)
 | 
			
		||||
	err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &Property{Name: propertyName, Value: prop}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) {
 | 
			
		||||
	return c.getProperty(unit, "org.freedesktop.systemd1.Unit", propertyName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUnitTypeProperties returns the extra properties for a unit, specific to the unit type.
 | 
			
		||||
// Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope
 | 
			
		||||
// return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit
 | 
			
		||||
func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) {
 | 
			
		||||
	return c.getProperties(unit, "org.freedesktop.systemd1."+unitType)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetUnitProperties() may be used to modify certain unit properties at runtime.
 | 
			
		||||
// Not all properties may be changed at runtime, but many resource management
 | 
			
		||||
// settings (primarily those in systemd.cgroup(5)) may. The changes are applied
 | 
			
		||||
// instantly, and stored on disk for future boots, unless runtime is true, in which
 | 
			
		||||
// case the settings only apply until the next reboot. name is the name of the unit
 | 
			
		||||
// to modify. properties are the settings to set, encoded as an array of property
 | 
			
		||||
// name and value pairs.
 | 
			
		||||
func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error {
 | 
			
		||||
	return c.sysobj.Call("SetUnitProperties", 0, name, runtime, properties).Store()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) {
 | 
			
		||||
	return c.getProperty(unit, "org.freedesktop.systemd1." + unitType, propertyName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListUnits returns an array with all currently loaded units. Note that
 | 
			
		||||
// units may be known by multiple names at the same time, and hence there might
 | 
			
		||||
// be more unit names loaded than actual units behind them.
 | 
			
		||||
func (c *Conn) ListUnits() ([]UnitStatus, error) {
 | 
			
		||||
	result := make([][]interface{}, 0)
 | 
			
		||||
	err := c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store(&result)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resultInterface := make([]interface{}, len(result))
 | 
			
		||||
	for i := range result {
 | 
			
		||||
		resultInterface[i] = result[i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	status := make([]UnitStatus, len(result))
 | 
			
		||||
	statusInterface := make([]interface{}, len(status))
 | 
			
		||||
	for i := range status {
 | 
			
		||||
		statusInterface[i] = &status[i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = dbus.Store(resultInterface, statusInterface...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return status, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UnitStatus struct {
 | 
			
		||||
	Name        string          // The primary unit name as string
 | 
			
		||||
	Description string          // The human readable description string
 | 
			
		||||
	LoadState   string          // The load state (i.e. whether the unit file has been loaded successfully)
 | 
			
		||||
	ActiveState string          // The active state (i.e. whether the unit is currently started or not)
 | 
			
		||||
	SubState    string          // The sub state (a more fine-grained version of the active state that is specific to the unit type, which the active state is not)
 | 
			
		||||
	Followed    string          // A unit that is being followed in its state by this unit, if there is any, otherwise the empty string.
 | 
			
		||||
	Path        dbus.ObjectPath // The unit object path
 | 
			
		||||
	JobId       uint32          // If there is a job queued for the job unit the numeric job id, 0 otherwise
 | 
			
		||||
	JobType     string          // The job type as string
 | 
			
		||||
	JobPath     dbus.ObjectPath // The job object path
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EnableUnitFiles() may be used to enable one or more units in the system (by
 | 
			
		||||
// creating symlinks to them in /etc or /run).
 | 
			
		||||
//
 | 
			
		||||
// It takes a list of unit files to enable (either just file names or full
 | 
			
		||||
// absolute paths if the unit files are residing outside the usual unit
 | 
			
		||||
// search paths), and two booleans: the first controls whether the unit shall
 | 
			
		||||
// be enabled for runtime only (true, /run), or persistently (false, /etc).
 | 
			
		||||
// The second one controls whether symlinks pointing to other units shall
 | 
			
		||||
// be replaced if necessary.
 | 
			
		||||
//
 | 
			
		||||
// This call returns one boolean and an array with the changes made. The
 | 
			
		||||
// boolean signals whether the unit files contained any enablement
 | 
			
		||||
// information (i.e. an [Install]) section. The changes list consists of
 | 
			
		||||
// structures with three strings: the type of the change (one of symlink
 | 
			
		||||
// or unlink), the file name of the symlink and the destination of the
 | 
			
		||||
// symlink.
 | 
			
		||||
func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) {
 | 
			
		||||
	var carries_install_info bool
 | 
			
		||||
 | 
			
		||||
	result := make([][]interface{}, 0)
 | 
			
		||||
	err := c.sysobj.Call("org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resultInterface := make([]interface{}, len(result))
 | 
			
		||||
	for i := range result {
 | 
			
		||||
		resultInterface[i] = result[i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	changes := make([]EnableUnitFileChange, len(result))
 | 
			
		||||
	changesInterface := make([]interface{}, len(changes))
 | 
			
		||||
	for i := range changes {
 | 
			
		||||
		changesInterface[i] = &changes[i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = dbus.Store(resultInterface, changesInterface...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return carries_install_info, changes, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type EnableUnitFileChange struct {
 | 
			
		||||
	Type        string // Type of the change (one of symlink or unlink)
 | 
			
		||||
	Filename    string // File name of the symlink
 | 
			
		||||
	Destination string // Destination of the symlink
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DisableUnitFiles() may be used to disable one or more units in the system (by
 | 
			
		||||
// removing symlinks to them from /etc or /run).
 | 
			
		||||
//
 | 
			
		||||
// It takes a list of unit files to disable (either just file names or full
 | 
			
		||||
// absolute paths if the unit files are residing outside the usual unit
 | 
			
		||||
// search paths), and one boolean: whether the unit was enabled for runtime
 | 
			
		||||
// only (true, /run), or persistently (false, /etc).
 | 
			
		||||
//
 | 
			
		||||
// This call returns an array with the changes made. The changes list
 | 
			
		||||
// consists of structures with three strings: the type of the change (one of
 | 
			
		||||
// symlink or unlink), the file name of the symlink and the destination of the
 | 
			
		||||
// symlink.
 | 
			
		||||
func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) {
 | 
			
		||||
	result := make([][]interface{}, 0)
 | 
			
		||||
	err := c.sysobj.Call("DisableUnitFiles", 0, files, runtime).Store(&result)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resultInterface := make([]interface{}, len(result))
 | 
			
		||||
	for i := range result {
 | 
			
		||||
		resultInterface[i] = result[i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	changes := make([]DisableUnitFileChange, len(result))
 | 
			
		||||
	changesInterface := make([]interface{}, len(changes))
 | 
			
		||||
	for i := range changes {
 | 
			
		||||
		changesInterface[i] = &changes[i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = dbus.Store(resultInterface, changesInterface...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return changes, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DisableUnitFileChange struct {
 | 
			
		||||
	Type        string // Type of the change (one of symlink or unlink)
 | 
			
		||||
	Filename    string // File name of the symlink
 | 
			
		||||
	Destination string // Destination of the symlink
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Reload instructs systemd to scan for and reload unit files. This is
 | 
			
		||||
// equivalent to a 'systemctl daemon-reload'.
 | 
			
		||||
func (c *Conn) Reload() error {
 | 
			
		||||
	return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										314
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/methods_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/methods_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,314 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2013 CoreOS Inc.
 | 
			
		||||
 | 
			
		||||
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 dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/guelfey/go.dbus"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func setupConn(t *testing.T) *Conn {
 | 
			
		||||
	conn, err := New()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return conn
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setupUnit(target string, conn *Conn, t *testing.T) {
 | 
			
		||||
	// Blindly stop the unit in case it is running
 | 
			
		||||
	conn.StopUnit(target, "replace")
 | 
			
		||||
 | 
			
		||||
	// Blindly remove the symlink in case it exists
 | 
			
		||||
	targetRun := filepath.Join("/run/systemd/system/", target)
 | 
			
		||||
	err := os.Remove(targetRun)
 | 
			
		||||
 | 
			
		||||
	// 1. Enable the unit
 | 
			
		||||
	abs, err := filepath.Abs("../fixtures/" + target)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fixture := []string{abs}
 | 
			
		||||
 | 
			
		||||
	install, changes, err := conn.EnableUnitFiles(fixture, true, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if install != false {
 | 
			
		||||
		t.Fatal("Install was true")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(changes) < 1 {
 | 
			
		||||
		t.Fatalf("Expected one change, got %v", changes)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if changes[0].Filename != targetRun {
 | 
			
		||||
		t.Fatal("Unexpected target filename")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Ensure that basic unit starting and stopping works.
 | 
			
		||||
func TestStartStopUnit(t *testing.T) {
 | 
			
		||||
	target := "start-stop.service"
 | 
			
		||||
	conn := setupConn(t)
 | 
			
		||||
 | 
			
		||||
	setupUnit(target, conn, t)
 | 
			
		||||
 | 
			
		||||
	// 2. Start the unit
 | 
			
		||||
	job, err := conn.StartUnit(target, "replace")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if job != "done" {
 | 
			
		||||
		t.Fatal("Job is not done, %v", job)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	units, err := conn.ListUnits()
 | 
			
		||||
 | 
			
		||||
	var unit *UnitStatus
 | 
			
		||||
	for _, u := range units {
 | 
			
		||||
		if u.Name == target {
 | 
			
		||||
			unit = &u
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if unit == nil {
 | 
			
		||||
		t.Fatalf("Test unit not found in list")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if unit.ActiveState != "active" {
 | 
			
		||||
		t.Fatalf("Test unit not active")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 3. Stop the unit
 | 
			
		||||
	job, err = conn.StopUnit(target, "replace")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	units, err = conn.ListUnits()
 | 
			
		||||
 | 
			
		||||
	unit = nil
 | 
			
		||||
	for _, u := range units {
 | 
			
		||||
		if u.Name == target {
 | 
			
		||||
			unit = &u
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if unit != nil {
 | 
			
		||||
		t.Fatalf("Test unit found in list, should be stopped")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Enables a unit and then immediately tears it down
 | 
			
		||||
func TestEnableDisableUnit(t *testing.T) {
 | 
			
		||||
	target := "enable-disable.service"
 | 
			
		||||
	conn := setupConn(t)
 | 
			
		||||
 | 
			
		||||
	setupUnit(target, conn, t)
 | 
			
		||||
 | 
			
		||||
	abs, err := filepath.Abs("../fixtures/" + target)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	path := filepath.Join("/run/systemd/system/", target)
 | 
			
		||||
 | 
			
		||||
	// 2. Disable the unit
 | 
			
		||||
	changes, err := conn.DisableUnitFiles([]string{abs}, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(changes) != 1 {
 | 
			
		||||
		t.Fatalf("Changes should include the path, %v", changes)
 | 
			
		||||
	}
 | 
			
		||||
	if changes[0].Filename != path {
 | 
			
		||||
		t.Fatalf("Change should include correct filename, %+v", changes[0])
 | 
			
		||||
	}
 | 
			
		||||
	if changes[0].Destination != "" {
 | 
			
		||||
		t.Fatalf("Change destination should be empty, %+v", changes[0])
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestGetUnitProperties reads the `-.mount` which should exist on all systemd
 | 
			
		||||
// systems and ensures that one of its properties is valid.
 | 
			
		||||
func TestGetUnitProperties(t *testing.T) {
 | 
			
		||||
	conn := setupConn(t)
 | 
			
		||||
 | 
			
		||||
	unit := "-.mount"
 | 
			
		||||
 | 
			
		||||
	info, err := conn.GetUnitProperties(unit)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	names := info["Wants"].([]string)
 | 
			
		||||
 | 
			
		||||
	if len(names) < 1 {
 | 
			
		||||
		t.Fatal("/ is unwanted")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if names[0] != "system.slice" {
 | 
			
		||||
		t.Fatal("unexpected wants for /")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	prop, err := conn.GetUnitProperty(unit, "Wants")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if prop.Name != "Wants" {
 | 
			
		||||
		t.Fatal("unexpected property name")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	val := prop.Value.Value().([]string)
 | 
			
		||||
	if !reflect.DeepEqual(val, names) {
 | 
			
		||||
		t.Fatal("unexpected property value")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestGetUnitPropertiesRejectsInvalidName attempts to get the properties for a
 | 
			
		||||
// unit with an invalid name. This test should be run with --test.timeout set,
 | 
			
		||||
// as a fail will manifest as GetUnitProperties hanging indefinitely.
 | 
			
		||||
func TestGetUnitPropertiesRejectsInvalidName(t *testing.T) {
 | 
			
		||||
	conn := setupConn(t)
 | 
			
		||||
 | 
			
		||||
	unit := "//invalid#$^/"
 | 
			
		||||
 | 
			
		||||
	_, err := conn.GetUnitProperties(unit)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("Expected an error, got nil")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = conn.GetUnitProperty(unit, "Wants")
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Fatal("Expected an error, got nil")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestSetUnitProperties changes a cgroup setting on the `tmp.mount`
 | 
			
		||||
// which should exist on all systemd systems and ensures that the
 | 
			
		||||
// property was set.
 | 
			
		||||
func TestSetUnitProperties(t *testing.T) {
 | 
			
		||||
	conn := setupConn(t)
 | 
			
		||||
 | 
			
		||||
	unit := "tmp.mount"
 | 
			
		||||
 | 
			
		||||
	if err := conn.SetUnitProperties(unit, true, Property{"CPUShares", dbus.MakeVariant(uint64(1023))}); err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info, err := conn.GetUnitTypeProperties(unit, "Mount")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	value := info["CPUShares"].(uint64)
 | 
			
		||||
	if value != 1023 {
 | 
			
		||||
		t.Fatal("CPUShares of unit is not 1023, %s", value)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Ensure that basic transient unit starting and stopping works.
 | 
			
		||||
func TestStartStopTransientUnit(t *testing.T) {
 | 
			
		||||
	conn := setupConn(t)
 | 
			
		||||
 | 
			
		||||
	props := []Property{
 | 
			
		||||
		PropExecStart([]string{"/bin/sleep", "400"}, false),
 | 
			
		||||
	}
 | 
			
		||||
	target := fmt.Sprintf("testing-transient-%d.service", rand.Int())
 | 
			
		||||
 | 
			
		||||
	// Start the unit
 | 
			
		||||
	job, err := conn.StartTransientUnit(target, "replace", props...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if job != "done" {
 | 
			
		||||
		t.Fatal("Job is not done, %v", job)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	units, err := conn.ListUnits()
 | 
			
		||||
 | 
			
		||||
	var unit *UnitStatus
 | 
			
		||||
	for _, u := range units {
 | 
			
		||||
		if u.Name == target {
 | 
			
		||||
			unit = &u
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if unit == nil {
 | 
			
		||||
		t.Fatalf("Test unit not found in list")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if unit.ActiveState != "active" {
 | 
			
		||||
		t.Fatalf("Test unit not active")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 3. Stop the unit
 | 
			
		||||
	job, err = conn.StopUnit(target, "replace")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	units, err = conn.ListUnits()
 | 
			
		||||
 | 
			
		||||
	unit = nil
 | 
			
		||||
	for _, u := range units {
 | 
			
		||||
		if u.Name == target {
 | 
			
		||||
			unit = &u
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if unit != nil {
 | 
			
		||||
		t.Fatalf("Test unit found in list, should be stopped")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestConnJobListener(t *testing.T) {
 | 
			
		||||
	target := "start-stop.service"
 | 
			
		||||
	conn := setupConn(t)
 | 
			
		||||
 | 
			
		||||
	setupUnit(target, conn, t)
 | 
			
		||||
 | 
			
		||||
	jobSize := len(conn.jobListener.jobs)
 | 
			
		||||
 | 
			
		||||
	_, err := conn.StartUnit(target, "replace")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = conn.StopUnit(target, "replace")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	currentJobSize := len(conn.jobListener.jobs)
 | 
			
		||||
	if jobSize != currentJobSize {
 | 
			
		||||
		t.Fatal("JobListener jobs leaked")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										220
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/properties.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/properties.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,220 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2013 CoreOS Inc.
 | 
			
		||||
 | 
			
		||||
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 dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// From the systemd docs:
 | 
			
		||||
//
 | 
			
		||||
// The properties array of StartTransientUnit() may take many of the settings
 | 
			
		||||
// that may also be configured in unit files. Not all parameters are currently
 | 
			
		||||
// accepted though, but we plan to cover more properties with future release.
 | 
			
		||||
// Currently you may set the Description, Slice and all dependency types of
 | 
			
		||||
// units, as well as RemainAfterExit, ExecStart for service units,
 | 
			
		||||
// TimeoutStopUSec and PIDs for scope units, and CPUAccounting, CPUShares,
 | 
			
		||||
// BlockIOAccounting, BlockIOWeight, BlockIOReadBandwidth,
 | 
			
		||||
// BlockIOWriteBandwidth, BlockIODeviceWeight, MemoryAccounting, MemoryLimit,
 | 
			
		||||
// DevicePolicy, DeviceAllow for services/scopes/slices. These fields map
 | 
			
		||||
// directly to their counterparts in unit files and as normal D-Bus object
 | 
			
		||||
// properties. The exception here is the PIDs field of scope units which is
 | 
			
		||||
// used for construction of the scope only and specifies the initial PIDs to
 | 
			
		||||
// add to the scope object.
 | 
			
		||||
 | 
			
		||||
type Property struct {
 | 
			
		||||
	Name  string
 | 
			
		||||
	Value dbus.Variant
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PropertyCollection struct {
 | 
			
		||||
	Name       string
 | 
			
		||||
	Properties []Property
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type execStart struct {
 | 
			
		||||
	Path             string   // the binary path to execute
 | 
			
		||||
	Args             []string // an array with all arguments to pass to the executed command, starting with argument 0
 | 
			
		||||
	UncleanIsFailure bool     // a boolean whether it should be considered a failure if the process exits uncleanly
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropExecStart sets the ExecStart service property.  The first argument is a
 | 
			
		||||
// slice with the binary path to execute followed by the arguments to pass to
 | 
			
		||||
// the executed command. See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=
 | 
			
		||||
func PropExecStart(command []string, uncleanIsFailure bool) Property {
 | 
			
		||||
	execStarts := []execStart{
 | 
			
		||||
		execStart{
 | 
			
		||||
			Path:             command[0],
 | 
			
		||||
			Args:             command,
 | 
			
		||||
			UncleanIsFailure: uncleanIsFailure,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Property{
 | 
			
		||||
		Name:  "ExecStart",
 | 
			
		||||
		Value: dbus.MakeVariant(execStarts),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropRemainAfterExit sets the RemainAfterExit service property. See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.service.html#RemainAfterExit=
 | 
			
		||||
func PropRemainAfterExit(b bool) Property {
 | 
			
		||||
	return Property{
 | 
			
		||||
		Name:  "RemainAfterExit",
 | 
			
		||||
		Value: dbus.MakeVariant(b),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropDescription sets the Description unit property. See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit#Description=
 | 
			
		||||
func PropDescription(desc string) Property {
 | 
			
		||||
	return Property{
 | 
			
		||||
		Name:  "Description",
 | 
			
		||||
		Value: dbus.MakeVariant(desc),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func propDependency(name string, units []string) Property {
 | 
			
		||||
	return Property{
 | 
			
		||||
		Name:  name,
 | 
			
		||||
		Value: dbus.MakeVariant(units),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropRequires sets the Requires unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requires=
 | 
			
		||||
func PropRequires(units ...string) Property {
 | 
			
		||||
	return propDependency("Requires", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropRequiresOverridable sets the RequiresOverridable unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresOverridable=
 | 
			
		||||
func PropRequiresOverridable(units ...string) Property {
 | 
			
		||||
	return propDependency("RequiresOverridable", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropRequisite sets the Requisite unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requisite=
 | 
			
		||||
func PropRequisite(units ...string) Property {
 | 
			
		||||
	return propDependency("Requisite", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropRequisiteOverridable sets the RequisiteOverridable unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequisiteOverridable=
 | 
			
		||||
func PropRequisiteOverridable(units ...string) Property {
 | 
			
		||||
	return propDependency("RequisiteOverridable", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropWants sets the Wants unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Wants=
 | 
			
		||||
func PropWants(units ...string) Property {
 | 
			
		||||
	return propDependency("Wants", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropBindsTo sets the BindsTo unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#BindsTo=
 | 
			
		||||
func PropBindsTo(units ...string) Property {
 | 
			
		||||
	return propDependency("BindsTo", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropRequiredBy sets the RequiredBy unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredBy=
 | 
			
		||||
func PropRequiredBy(units ...string) Property {
 | 
			
		||||
	return propDependency("RequiredBy", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropRequiredByOverridable sets the RequiredByOverridable unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiredByOverridable=
 | 
			
		||||
func PropRequiredByOverridable(units ...string) Property {
 | 
			
		||||
	return propDependency("RequiredByOverridable", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropWantedBy sets the WantedBy unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#WantedBy=
 | 
			
		||||
func PropWantedBy(units ...string) Property {
 | 
			
		||||
	return propDependency("WantedBy", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropBoundBy sets the BoundBy unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/main/systemd.unit.html#BoundBy=
 | 
			
		||||
func PropBoundBy(units ...string) Property {
 | 
			
		||||
	return propDependency("BoundBy", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropConflicts sets the Conflicts unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Conflicts=
 | 
			
		||||
func PropConflicts(units ...string) Property {
 | 
			
		||||
	return propDependency("Conflicts", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropConflictedBy sets the ConflictedBy unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#ConflictedBy=
 | 
			
		||||
func PropConflictedBy(units ...string) Property {
 | 
			
		||||
	return propDependency("ConflictedBy", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropBefore sets the Before unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Before=
 | 
			
		||||
func PropBefore(units ...string) Property {
 | 
			
		||||
	return propDependency("Before", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropAfter sets the After unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#After=
 | 
			
		||||
func PropAfter(units ...string) Property {
 | 
			
		||||
	return propDependency("After", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropOnFailure sets the OnFailure unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#OnFailure=
 | 
			
		||||
func PropOnFailure(units ...string) Property {
 | 
			
		||||
	return propDependency("OnFailure", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropTriggers sets the Triggers unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#Triggers=
 | 
			
		||||
func PropTriggers(units ...string) Property {
 | 
			
		||||
	return propDependency("Triggers", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropTriggeredBy sets the TriggeredBy unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#TriggeredBy=
 | 
			
		||||
func PropTriggeredBy(units ...string) Property {
 | 
			
		||||
	return propDependency("TriggeredBy", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropPropagatesReloadTo sets the PropagatesReloadTo unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#PropagatesReloadTo=
 | 
			
		||||
func PropPropagatesReloadTo(units ...string) Property {
 | 
			
		||||
	return propDependency("PropagatesReloadTo", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropRequiresMountsFor sets the RequiresMountsFor unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.unit.html#RequiresMountsFor=
 | 
			
		||||
func PropRequiresMountsFor(units ...string) Property {
 | 
			
		||||
	return propDependency("RequiresMountsFor", units)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PropSlice sets the Slice unit property.  See
 | 
			
		||||
// http://www.freedesktop.org/software/systemd/man/systemd.resource-control.html#Slice=
 | 
			
		||||
func PropSlice(slice string) Property {
 | 
			
		||||
	return Property{
 | 
			
		||||
		Name:  "Slice",
 | 
			
		||||
		Value: dbus.MakeVariant(slice),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/set.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/set.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
type set struct {
 | 
			
		||||
	data map[string]bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *set) Add(value string) {
 | 
			
		||||
	s.data[value] = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *set) Remove(value string) {
 | 
			
		||||
	delete(s.data, value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *set) Contains(value string) (exists bool) {
 | 
			
		||||
	_, exists = s.data[value]
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *set) Length() (int) {
 | 
			
		||||
	return len(s.data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newSet() (*set) {
 | 
			
		||||
	return &set{make(map[string] bool)}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/set_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/set_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TestBasicSetActions asserts that Add & Remove behavior is correct
 | 
			
		||||
func TestBasicSetActions(t *testing.T) {
 | 
			
		||||
	s := newSet()
 | 
			
		||||
 | 
			
		||||
	if s.Contains("foo") {
 | 
			
		||||
		t.Fatal("set should not contain 'foo'")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.Add("foo")
 | 
			
		||||
 | 
			
		||||
	if !s.Contains("foo") {
 | 
			
		||||
		t.Fatal("set should contain 'foo'")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.Remove("foo")
 | 
			
		||||
 | 
			
		||||
	if s.Contains("foo") {
 | 
			
		||||
		t.Fatal("set should not contain 'foo'")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										249
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/subscription.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/subscription.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,249 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2013 CoreOS Inc.
 | 
			
		||||
 | 
			
		||||
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 dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	cleanIgnoreInterval = int64(10 * time.Second)
 | 
			
		||||
	ignoreInterval      = int64(30 * time.Millisecond)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Subscribe sets up this connection to subscribe to all systemd dbus events.
 | 
			
		||||
// This is required before calling SubscribeUnits. When the connection closes
 | 
			
		||||
// systemd will automatically stop sending signals so there is no need to
 | 
			
		||||
// explicitly call Unsubscribe().
 | 
			
		||||
func (c *Conn) Subscribe() error {
 | 
			
		||||
	c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
 | 
			
		||||
		"type='signal',interface='org.freedesktop.systemd1.Manager',member='UnitNew'")
 | 
			
		||||
	c.sysconn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
 | 
			
		||||
		"type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'")
 | 
			
		||||
 | 
			
		||||
	err := c.sysobj.Call("org.freedesktop.systemd1.Manager.Subscribe", 0).Store()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.sysconn.Close()
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Unsubscribe this connection from systemd dbus events.
 | 
			
		||||
func (c *Conn) Unsubscribe() error {
 | 
			
		||||
	err := c.sysobj.Call("org.freedesktop.systemd1.Manager.Unsubscribe", 0).Store()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.sysconn.Close()
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) initSubscription() {
 | 
			
		||||
	c.subscriber.ignore = make(map[dbus.ObjectPath]int64)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) initDispatch() {
 | 
			
		||||
	ch := make(chan *dbus.Signal, signalBuffer)
 | 
			
		||||
 | 
			
		||||
	c.sysconn.Signal(ch)
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		for {
 | 
			
		||||
			signal := <-ch
 | 
			
		||||
			switch signal.Name {
 | 
			
		||||
			case "org.freedesktop.systemd1.Manager.JobRemoved":
 | 
			
		||||
				c.jobComplete(signal)
 | 
			
		||||
 | 
			
		||||
				unitName := signal.Body[2].(string)
 | 
			
		||||
				var unitPath dbus.ObjectPath
 | 
			
		||||
				c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnit", 0, unitName).Store(&unitPath)
 | 
			
		||||
				if unitPath != dbus.ObjectPath("") {
 | 
			
		||||
					c.sendSubStateUpdate(unitPath)
 | 
			
		||||
				}
 | 
			
		||||
			case "org.freedesktop.systemd1.Manager.UnitNew":
 | 
			
		||||
				c.sendSubStateUpdate(signal.Body[1].(dbus.ObjectPath))
 | 
			
		||||
			case "org.freedesktop.DBus.Properties.PropertiesChanged":
 | 
			
		||||
				if signal.Body[0].(string) == "org.freedesktop.systemd1.Unit" {
 | 
			
		||||
					// we only care about SubState updates, which are a Unit property
 | 
			
		||||
					c.sendSubStateUpdate(signal.Path)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns two unbuffered channels which will receive all changed units every
 | 
			
		||||
// interval.  Deleted units are sent as nil.
 | 
			
		||||
func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) {
 | 
			
		||||
	return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SubscribeUnitsCustom is like SubscribeUnits but lets you specify the buffer
 | 
			
		||||
// size of the channels, the comparison function for detecting changes and a filter
 | 
			
		||||
// function for cutting down on the noise that your channel receives.
 | 
			
		||||
func (c *Conn) SubscribeUnitsCustom(interval time.Duration, buffer int, isChanged func(*UnitStatus, *UnitStatus) bool, filterUnit func (string) bool) (<-chan map[string]*UnitStatus, <-chan error) {
 | 
			
		||||
	old := make(map[string]*UnitStatus)
 | 
			
		||||
	statusChan := make(chan map[string]*UnitStatus, buffer)
 | 
			
		||||
	errChan := make(chan error, buffer)
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		for {
 | 
			
		||||
			timerChan := time.After(interval)
 | 
			
		||||
 | 
			
		||||
			units, err := c.ListUnits()
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				cur := make(map[string]*UnitStatus)
 | 
			
		||||
				for i := range units {
 | 
			
		||||
					if filterUnit != nil && filterUnit(units[i].Name) {
 | 
			
		||||
						continue
 | 
			
		||||
					}
 | 
			
		||||
					cur[units[i].Name] = &units[i]
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// add all new or changed units
 | 
			
		||||
				changed := make(map[string]*UnitStatus)
 | 
			
		||||
				for n, u := range cur {
 | 
			
		||||
					if oldU, ok := old[n]; !ok || isChanged(oldU, u) {
 | 
			
		||||
						changed[n] = u
 | 
			
		||||
					}
 | 
			
		||||
					delete(old, n)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// add all deleted units
 | 
			
		||||
				for oldN := range old {
 | 
			
		||||
					changed[oldN] = nil
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				old = cur
 | 
			
		||||
 | 
			
		||||
				if len(changed) != 0 {
 | 
			
		||||
					statusChan <- changed
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				errChan <- err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			<-timerChan
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	return statusChan, errChan
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SubStateUpdate struct {
 | 
			
		||||
	UnitName string
 | 
			
		||||
	SubState string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetSubStateSubscriber writes to updateCh when any unit's substate changes.
 | 
			
		||||
// Although this writes to updateCh on every state change, the reported state
 | 
			
		||||
// may be more recent than the change that generated it (due to an unavoidable
 | 
			
		||||
// race in the systemd dbus interface).  That is, this method provides a good
 | 
			
		||||
// way to keep a current view of all units' states, but is not guaranteed to
 | 
			
		||||
// show every state transition they go through.  Furthermore, state changes
 | 
			
		||||
// will only be written to the channel with non-blocking writes.  If updateCh
 | 
			
		||||
// is full, it attempts to write an error to errCh; if errCh is full, the error
 | 
			
		||||
// passes silently.
 | 
			
		||||
func (c *Conn) SetSubStateSubscriber(updateCh chan<- *SubStateUpdate, errCh chan<- error) {
 | 
			
		||||
	c.subscriber.Lock()
 | 
			
		||||
	defer c.subscriber.Unlock()
 | 
			
		||||
	c.subscriber.updateCh = updateCh
 | 
			
		||||
	c.subscriber.errCh = errCh
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) sendSubStateUpdate(path dbus.ObjectPath) {
 | 
			
		||||
	c.subscriber.Lock()
 | 
			
		||||
	defer c.subscriber.Unlock()
 | 
			
		||||
	if c.subscriber.updateCh == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.shouldIgnore(path) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info, err := c.GetUnitProperties(string(path))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		select {
 | 
			
		||||
		case c.subscriber.errCh <- err:
 | 
			
		||||
		default:
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name := info["Id"].(string)
 | 
			
		||||
	substate := info["SubState"].(string)
 | 
			
		||||
 | 
			
		||||
	update := &SubStateUpdate{name, substate}
 | 
			
		||||
	select {
 | 
			
		||||
	case c.subscriber.updateCh <- update:
 | 
			
		||||
	default:
 | 
			
		||||
		select {
 | 
			
		||||
		case c.subscriber.errCh <- errors.New("update channel full!"):
 | 
			
		||||
		default:
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.updateIgnore(path, info)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The ignore functions work around a wart in the systemd dbus interface.
 | 
			
		||||
// Requesting the properties of an unloaded unit will cause systemd to send a
 | 
			
		||||
// pair of UnitNew/UnitRemoved signals.  Because we need to get a unit's
 | 
			
		||||
// properties on UnitNew (as that's the only indication of a new unit coming up
 | 
			
		||||
// for the first time), we would enter an infinite loop if we did not attempt
 | 
			
		||||
// to detect and ignore these spurious signals.  The signal themselves are
 | 
			
		||||
// indistinguishable from relevant ones, so we (somewhat hackishly) ignore an
 | 
			
		||||
// unloaded unit's signals for a short time after requesting its properties.
 | 
			
		||||
// This means that we will miss e.g. a transient unit being restarted
 | 
			
		||||
// *immediately* upon failure and also a transient unit being started
 | 
			
		||||
// immediately after requesting its status (with systemctl status, for example,
 | 
			
		||||
// because this causes a UnitNew signal to be sent which then causes us to fetch
 | 
			
		||||
// the properties).
 | 
			
		||||
 | 
			
		||||
func (c *Conn) shouldIgnore(path dbus.ObjectPath) bool {
 | 
			
		||||
	t, ok := c.subscriber.ignore[path]
 | 
			
		||||
	return ok && t >= time.Now().UnixNano()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) updateIgnore(path dbus.ObjectPath, info map[string]interface{}) {
 | 
			
		||||
	c.cleanIgnore()
 | 
			
		||||
 | 
			
		||||
	// unit is unloaded - it will trigger bad systemd dbus behavior
 | 
			
		||||
	if info["LoadState"].(string) == "not-found" {
 | 
			
		||||
		c.subscriber.ignore[path] = time.Now().UnixNano() + ignoreInterval
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// without this, ignore would grow unboundedly over time
 | 
			
		||||
func (c *Conn) cleanIgnore() {
 | 
			
		||||
	now := time.Now().UnixNano()
 | 
			
		||||
	if c.subscriber.cleanIgnore < now {
 | 
			
		||||
		c.subscriber.cleanIgnore = now + cleanIgnoreInterval
 | 
			
		||||
 | 
			
		||||
		for p, t := range c.subscriber.ignore {
 | 
			
		||||
			if t < now {
 | 
			
		||||
				delete(c.subscriber.ignore, p)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/subscription_set.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/subscription_set.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SubscriptionSet returns a subscription set which is like conn.Subscribe but
 | 
			
		||||
// can filter to only return events for a set of units.
 | 
			
		||||
type SubscriptionSet struct {
 | 
			
		||||
	*set
 | 
			
		||||
	conn *Conn
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func (s *SubscriptionSet) filter(unit string) bool {
 | 
			
		||||
	return !s.Contains(unit)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Subscribe starts listening for dbus events for all of the units in the set.
 | 
			
		||||
// Returns channels identical to conn.SubscribeUnits.
 | 
			
		||||
func (s *SubscriptionSet) Subscribe() (<-chan map[string]*UnitStatus, <-chan error) {
 | 
			
		||||
	// TODO: Make fully evented by using systemd 209 with properties changed values
 | 
			
		||||
	return s.conn.SubscribeUnitsCustom(time.Second, 0,
 | 
			
		||||
		func(u1, u2 *UnitStatus) bool { return *u1 != *u2 },
 | 
			
		||||
		func(unit string) bool { return s.filter(unit) },
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSubscriptionSet returns a new subscription set.
 | 
			
		||||
func (conn *Conn) NewSubscriptionSet() (*SubscriptionSet) {
 | 
			
		||||
	return &SubscriptionSet{newSet(), conn}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/subscription_set_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/subscription_set_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,67 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TestSubscribeUnit exercises the basics of subscription of a particular unit.
 | 
			
		||||
func TestSubscriptionSetUnit(t *testing.T) {
 | 
			
		||||
	target := "subscribe-events-set.service"
 | 
			
		||||
 | 
			
		||||
	conn, err := New()
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = conn.Subscribe()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	subSet := conn.NewSubscriptionSet()
 | 
			
		||||
	evChan, errChan := subSet.Subscribe()
 | 
			
		||||
 | 
			
		||||
	subSet.Add(target)
 | 
			
		||||
	setupUnit(target, conn, t)
 | 
			
		||||
 | 
			
		||||
	job, err := conn.StartUnit(target, "replace")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if job != "done" {
 | 
			
		||||
		t.Fatal("Couldn't start", target)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timeout := make(chan bool, 1)
 | 
			
		||||
	go func() {
 | 
			
		||||
		time.Sleep(3 * time.Second)
 | 
			
		||||
		close(timeout)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case changes := <-evChan:
 | 
			
		||||
			tCh, ok := changes[target]
 | 
			
		||||
 | 
			
		||||
			if !ok {
 | 
			
		||||
				t.Fatal("Unexpected event %v", changes)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if tCh.ActiveState == "active" && tCh.Name == target {
 | 
			
		||||
				goto success
 | 
			
		||||
			}
 | 
			
		||||
		case err = <-errChan:
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		case <-timeout:
 | 
			
		||||
			t.Fatal("Reached timeout")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
success:
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										90
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/subscription_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								vendor/src/github.com/coreos/go-systemd/dbus/subscription_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,90 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TestSubscribe exercises the basics of subscription
 | 
			
		||||
func TestSubscribe(t *testing.T) {
 | 
			
		||||
	conn, err := New()
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = conn.Subscribe()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = conn.Unsubscribe()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TestSubscribeUnit exercises the basics of subscription of a particular unit.
 | 
			
		||||
func TestSubscribeUnit(t *testing.T) {
 | 
			
		||||
	target := "subscribe-events.service"
 | 
			
		||||
 | 
			
		||||
	conn, err := New()
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = conn.Subscribe()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = conn.Unsubscribe()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	evChan, errChan := conn.SubscribeUnits(time.Second)
 | 
			
		||||
 | 
			
		||||
	setupUnit(target, conn, t)
 | 
			
		||||
 | 
			
		||||
	job, err := conn.StartUnit(target, "replace")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if job != "done" {
 | 
			
		||||
		t.Fatal("Couldn't start", target)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timeout := make(chan bool, 1)
 | 
			
		||||
	go func() {
 | 
			
		||||
		time.Sleep(3 * time.Second)
 | 
			
		||||
		close(timeout)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case changes := <-evChan:
 | 
			
		||||
			tCh, ok := changes[target]
 | 
			
		||||
 | 
			
		||||
			// Just continue until we see our event.
 | 
			
		||||
			if !ok {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if tCh.ActiveState == "active" && tCh.Name == target {
 | 
			
		||||
				goto success
 | 
			
		||||
			}
 | 
			
		||||
		case err = <-errChan:
 | 
			
		||||
			t.Fatal(err)
 | 
			
		||||
		case <-timeout:
 | 
			
		||||
			t.Fatal("Reached timeout")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
success:
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										44
									
								
								vendor/src/github.com/coreos/go-systemd/examples/activation/activation.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								vendor/src/github.com/coreos/go-systemd/examples/activation/activation.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
// Activation example used by the activation unit tests.
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/coreos/go-systemd/activation"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func fixListenPid() {
 | 
			
		||||
	if os.Getenv("FIX_LISTEN_PID") != "" {
 | 
			
		||||
		// HACK: real systemd would set LISTEN_PID before exec'ing but
 | 
			
		||||
		// this is too difficult in golang for the purpose of a test.
 | 
			
		||||
		// Do not do this in real code.
 | 
			
		||||
		os.Setenv("LISTEN_PID", fmt.Sprintf("%d", os.Getpid()))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	fixListenPid()
 | 
			
		||||
 | 
			
		||||
	files := activation.Files(false)
 | 
			
		||||
 | 
			
		||||
	if len(files) == 0 {
 | 
			
		||||
		panic("No files")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if os.Getenv("LISTEN_PID") == "" || os.Getenv("LISTEN_FDS") == "" {
 | 
			
		||||
		panic("Should not unset envs")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	files = activation.Files(true)
 | 
			
		||||
 | 
			
		||||
	if os.Getenv("LISTEN_PID") != "" || os.Getenv("LISTEN_FDS") != "" {
 | 
			
		||||
		panic("Can not unset envs")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Write out the expected strings to the two pipes
 | 
			
		||||
	files[0].Write([]byte("Hello world"))
 | 
			
		||||
	files[1].Write([]byte("Goodbye world"))
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								vendor/src/github.com/coreos/go-systemd/examples/activation/httpserver/README.md
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/src/github.com/coreos/go-systemd/examples/activation/httpserver/README.md
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
## socket activated http server
 | 
			
		||||
 | 
			
		||||
This is a simple example of using socket activation with systemd to serve a
 | 
			
		||||
simple HTTP server on http://127.0.0.1:8076
 | 
			
		||||
 | 
			
		||||
To try it out `go get` the httpserver and run it under the systemd-activate helper
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
export GOPATH=`pwd`
 | 
			
		||||
go get github.com/coreos/go-systemd/examples/activation/httpserver
 | 
			
		||||
sudo /usr/lib/systemd/systemd-activate -l 127.0.0.1:8076 ./bin/httpserver
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then curl the URL and you will notice that it starts up:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
curl 127.0.0.1:8076
 | 
			
		||||
hello socket activated world!
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										11
									
								
								vendor/src/github.com/coreos/go-systemd/examples/activation/httpserver/hello.service
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/src/github.com/coreos/go-systemd/examples/activation/httpserver/hello.service
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
[Unit]
 | 
			
		||||
Description=Hello World HTTP
 | 
			
		||||
Requires=network.target
 | 
			
		||||
After=multi-user.target
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
ExecStart=/usr/local/bin/httpserver
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/src/github.com/coreos/go-systemd/examples/activation/httpserver/hello.socket
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/src/github.com/coreos/go-systemd/examples/activation/httpserver/hello.socket
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
[Socket]
 | 
			
		||||
ListenStream=127.0.0.1:8076
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=sockets.target
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/src/github.com/coreos/go-systemd/examples/activation/httpserver/httpserver.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/src/github.com/coreos/go-systemd/examples/activation/httpserver/httpserver.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
 | 
			
		||||
	"github.com/coreos/go-systemd/activation"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func HelloServer(w http.ResponseWriter, req *http.Request) {
 | 
			
		||||
	io.WriteString(w, "hello socket activated world!\n")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	listeners, err := activation.Listeners(true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(listeners) != 1 {
 | 
			
		||||
		panic("Unexpected number of socket activation fds")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	http.HandleFunc("/", HelloServer)
 | 
			
		||||
	http.Serve(listeners[0], nil)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								vendor/src/github.com/coreos/go-systemd/examples/activation/listen.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								vendor/src/github.com/coreos/go-systemd/examples/activation/listen.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
// Activation example used by the activation unit tests.
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/coreos/go-systemd/activation"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func fixListenPid() {
 | 
			
		||||
	if os.Getenv("FIX_LISTEN_PID") != "" {
 | 
			
		||||
		// HACK: real systemd would set LISTEN_PID before exec'ing but
 | 
			
		||||
		// this is too difficult in golang for the purpose of a test.
 | 
			
		||||
		// Do not do this in real code.
 | 
			
		||||
		os.Setenv("LISTEN_PID", fmt.Sprintf("%d", os.Getpid()))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	fixListenPid()
 | 
			
		||||
 | 
			
		||||
	listeners, _ := activation.Listeners(false)
 | 
			
		||||
 | 
			
		||||
	if len(listeners) == 0 {
 | 
			
		||||
		panic("No listeners")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if os.Getenv("LISTEN_PID") == "" || os.Getenv("LISTEN_FDS") == "" {
 | 
			
		||||
		panic("Should not unset envs")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	listeners, err := activation.Listeners(true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if os.Getenv("LISTEN_PID") != "" || os.Getenv("LISTEN_FDS") != "" {
 | 
			
		||||
		panic("Can not unset envs")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c0, _ := listeners[0].Accept()
 | 
			
		||||
	c1, _ := listeners[1].Accept()
 | 
			
		||||
 | 
			
		||||
	// Write out the expected strings to the two pipes
 | 
			
		||||
	c0.Write([]byte("Hello world"))
 | 
			
		||||
	c1.Write([]byte("Goodbye world"))
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/src/github.com/coreos/go-systemd/fixtures/start-stop.service
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/src/github.com/coreos/go-systemd/fixtures/start-stop.service
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
[Unit]
 | 
			
		||||
Description=start stop test
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
ExecStart=/bin/sleep 400
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/src/github.com/coreos/go-systemd/fixtures/subscribe-events-set.service
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/src/github.com/coreos/go-systemd/fixtures/subscribe-events-set.service
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
[Unit]
 | 
			
		||||
Description=start stop test
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
ExecStart=/bin/sleep 400
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/src/github.com/coreos/go-systemd/fixtures/subscribe-events.service
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/src/github.com/coreos/go-systemd/fixtures/subscribe-events.service
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
[Unit]
 | 
			
		||||
Description=start stop test
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
ExecStart=/bin/sleep 400
 | 
			
		||||
							
								
								
									
										168
									
								
								vendor/src/github.com/coreos/go-systemd/journal/send.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								vendor/src/github.com/coreos/go-systemd/journal/send.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,168 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2013 CoreOS Inc.
 | 
			
		||||
 | 
			
		||||
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 journal provides write bindings to the systemd journal
 | 
			
		||||
package journal
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Priority of a journal message
 | 
			
		||||
type Priority int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	PriEmerg Priority = iota
 | 
			
		||||
	PriAlert
 | 
			
		||||
	PriCrit
 | 
			
		||||
	PriErr
 | 
			
		||||
	PriWarning
 | 
			
		||||
	PriNotice
 | 
			
		||||
	PriInfo
 | 
			
		||||
	PriDebug
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var conn net.Conn
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	var err error
 | 
			
		||||
	conn, err = net.Dial("unixgram", "/run/systemd/journal/socket")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		conn = nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Enabled returns true iff the systemd journal is available for logging
 | 
			
		||||
func Enabled() bool {
 | 
			
		||||
	return conn != nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send a message to the systemd journal. vars is a map of journald fields to
 | 
			
		||||
// values.  Fields must be composed of uppercase letters, numbers, and
 | 
			
		||||
// underscores, but must not start with an underscore. Within these
 | 
			
		||||
// restrictions, any arbitrary field name may be used.  Some names have special
 | 
			
		||||
// significance: see the journalctl documentation
 | 
			
		||||
// (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html)
 | 
			
		||||
// for more details.  vars may be nil.
 | 
			
		||||
func Send(message string, priority Priority, vars map[string]string) error {
 | 
			
		||||
	if conn == nil {
 | 
			
		||||
		return journalError("could not connect to journald socket")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data := new(bytes.Buffer)
 | 
			
		||||
	appendVariable(data, "PRIORITY", strconv.Itoa(int(priority)))
 | 
			
		||||
	appendVariable(data, "MESSAGE", message)
 | 
			
		||||
	for k, v := range vars {
 | 
			
		||||
		appendVariable(data, k, v)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err := io.Copy(conn, data)
 | 
			
		||||
	if err != nil && isSocketSpaceError(err) {
 | 
			
		||||
		file, err := tempFd()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return journalError(err.Error())
 | 
			
		||||
		}
 | 
			
		||||
		_, err = io.Copy(file, data)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return journalError(err.Error())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		rights := syscall.UnixRights(int(file.Fd()))
 | 
			
		||||
 | 
			
		||||
		/* this connection should always be a UnixConn, but better safe than sorry */
 | 
			
		||||
		unixConn, ok := conn.(*net.UnixConn)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return journalError("can't send file through non-Unix connection")
 | 
			
		||||
		}
 | 
			
		||||
		unixConn.WriteMsgUnix([]byte{}, rights, nil)
 | 
			
		||||
	} else if err != nil {
 | 
			
		||||
		return journalError(err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func appendVariable(w io.Writer, name, value string) {
 | 
			
		||||
	if !validVarName(name) {
 | 
			
		||||
		journalError("variable name contains invalid character, ignoring")
 | 
			
		||||
	}
 | 
			
		||||
	if strings.ContainsRune(value, '\n') {
 | 
			
		||||
		/* When the value contains a newline, we write:
 | 
			
		||||
		 * - the variable name, followed by a newline
 | 
			
		||||
		 * - the size (in 64bit little endian format)
 | 
			
		||||
		 * - the data, followed by a newline
 | 
			
		||||
		 */
 | 
			
		||||
		fmt.Fprintln(w, name)
 | 
			
		||||
		binary.Write(w, binary.LittleEndian, uint64(len(value)))
 | 
			
		||||
		fmt.Fprintln(w, value)
 | 
			
		||||
	} else {
 | 
			
		||||
		/* just write the variable and value all on one line */
 | 
			
		||||
		fmt.Fprintln(w, "%s=%s", name, value)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validVarName(name string) bool {
 | 
			
		||||
	/* The variable name must be in uppercase and consist only of characters,
 | 
			
		||||
	 * numbers and underscores, and may not begin with an underscore. (from the docs)
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	valid := name[0] != '_'
 | 
			
		||||
	for _, c := range name {
 | 
			
		||||
		valid = valid && ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_'
 | 
			
		||||
	}
 | 
			
		||||
	return valid
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isSocketSpaceError(err error) bool {
 | 
			
		||||
	opErr, ok := err.(*net.OpError)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sysErr, ok := opErr.Err.(syscall.Errno)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return sysErr == syscall.EMSGSIZE || sysErr == syscall.ENOBUFS
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func tempFd() (*os.File, error) {
 | 
			
		||||
	file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	syscall.Unlink(file.Name())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return file, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func journalError(s string) error {
 | 
			
		||||
	s = "journal error: " + s
 | 
			
		||||
	fmt.Fprintln(os.Stderr, s)
 | 
			
		||||
	return errors.New(s)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/src/github.com/coreos/go-systemd/test
									
										
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								vendor/src/github.com/coreos/go-systemd/test
									
										
									
									
										vendored
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
#!/bin/sh -e
 | 
			
		||||
 | 
			
		||||
go test -v ./...
 | 
			
		||||
							
								
								
									
										25
									
								
								vendor/src/github.com/godbus/dbus/LICENSE
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/src/github.com/godbus/dbus/LICENSE
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
Copyright (c) 2013, Georg Reinke (<guelfey at gmail dot com>)
 | 
			
		||||
All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions
 | 
			
		||||
are met:
 | 
			
		||||
 | 
			
		||||
1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
this list of conditions and the following disclaimer.
 | 
			
		||||
 | 
			
		||||
2. 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.
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
HOLDER 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.
 | 
			
		||||
							
								
								
									
										38
									
								
								vendor/src/github.com/godbus/dbus/README.markdown
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								vendor/src/github.com/godbus/dbus/README.markdown
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
dbus
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
dbus is a simple library that implements native Go client bindings for the
 | 
			
		||||
D-Bus message bus system.
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
* Complete native implementation of the D-Bus message protocol
 | 
			
		||||
* Go-like API (channels for signals / asynchronous method calls, Goroutine-safe connections)
 | 
			
		||||
* Subpackages that help with the introspection / property interfaces
 | 
			
		||||
 | 
			
		||||
### Installation
 | 
			
		||||
 | 
			
		||||
This packages requires Go 1.1. If you installed it and set up your GOPATH, just run:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
go get github.com/godbus/dbus
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If you want to use the subpackages, you can install them the same way.
 | 
			
		||||
 | 
			
		||||
### Usage
 | 
			
		||||
 | 
			
		||||
The complete package documentation and some simple examples are available at
 | 
			
		||||
[godoc.org](http://godoc.org/github.com/godbus/dbus). Also, the
 | 
			
		||||
[_examples](https://github.com/godbus/dbus/tree/master/_examples) directory
 | 
			
		||||
gives a short overview over the basic usage. 
 | 
			
		||||
 | 
			
		||||
Please note that the API is considered unstable for now and may change without
 | 
			
		||||
further notice.
 | 
			
		||||
 | 
			
		||||
### License
 | 
			
		||||
 | 
			
		||||
go.dbus is available under the Simplified BSD License; see LICENSE for the full
 | 
			
		||||
text.
 | 
			
		||||
 | 
			
		||||
Nearly all of the credit for this library goes to github.com/guelfey/go.dbus.
 | 
			
		||||
							
								
								
									
										30
									
								
								vendor/src/github.com/godbus/dbus/_examples/eavesdrop.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								vendor/src/github.com/godbus/dbus/_examples/eavesdrop.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	conn, err := dbus.SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, v := range []string{"method_call", "method_return", "error", "signal"} {
 | 
			
		||||
		call := conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
 | 
			
		||||
			"eavesdrop='true',type='"+v+"'")
 | 
			
		||||
		if call.Err != nil {
 | 
			
		||||
			fmt.Fprintln(os.Stderr, "Failed to add match:", call.Err)
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	c := make(chan *dbus.Message, 10)
 | 
			
		||||
	conn.Eavesdrop(c)
 | 
			
		||||
	fmt.Println("Listening for everything")
 | 
			
		||||
	for v := range c {
 | 
			
		||||
		fmt.Println(v)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/src/github.com/godbus/dbus/_examples/introspect.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/src/github.com/godbus/dbus/_examples/introspect.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
	"github.com/godbus/dbus/introspect"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	conn, err := dbus.SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	node, err := introspect.Call(conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	data, _ := json.MarshalIndent(node, "", "    ")
 | 
			
		||||
	os.Stdout.Write(data)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/src/github.com/godbus/dbus/_examples/list-names.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/src/github.com/godbus/dbus/_examples/list-names.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	conn, err := dbus.SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var s []string
 | 
			
		||||
	err = conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&s)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintln(os.Stderr, "Failed to get list of owned names:", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("Currently owned names on the session bus:")
 | 
			
		||||
	for _, v := range s {
 | 
			
		||||
		fmt.Println(v)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								vendor/src/github.com/godbus/dbus/_examples/notification.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/src/github.com/godbus/dbus/_examples/notification.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import "github.com/godbus/dbus"
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	conn, err := dbus.SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	obj := conn.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
 | 
			
		||||
	call := obj.Call("org.freedesktop.Notifications.Notify", 0, "", uint32(0),
 | 
			
		||||
		"", "Test", "This is a test of the DBus bindings for go.", []string{},
 | 
			
		||||
		map[string]dbus.Variant{}, int32(5000))
 | 
			
		||||
	if call.Err != nil {
 | 
			
		||||
		panic(call.Err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								vendor/src/github.com/godbus/dbus/_examples/prop.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								vendor/src/github.com/godbus/dbus/_examples/prop.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,68 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
	"github.com/godbus/dbus/introspect"
 | 
			
		||||
	"github.com/godbus/dbus/prop"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type foo string
 | 
			
		||||
 | 
			
		||||
func (f foo) Foo() (string, *dbus.Error) {
 | 
			
		||||
	fmt.Println(f)
 | 
			
		||||
	return string(f), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	conn, err := dbus.SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	reply, err := conn.RequestName("com.github.guelfey.Demo",
 | 
			
		||||
		dbus.NameFlagDoNotQueue)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	if reply != dbus.RequestNameReplyPrimaryOwner {
 | 
			
		||||
		fmt.Fprintln(os.Stderr, "name already taken")
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
	propsSpec := map[string]map[string]*prop.Prop{
 | 
			
		||||
		"com.github.guelfey.Demo": {
 | 
			
		||||
			"SomeInt": {
 | 
			
		||||
				int32(0),
 | 
			
		||||
				true,
 | 
			
		||||
				prop.EmitTrue,
 | 
			
		||||
				func(c *prop.Change) *dbus.Error {
 | 
			
		||||
					fmt.Println(c.Name, "changed to", c.Value)
 | 
			
		||||
					return nil
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	f := foo("Bar")
 | 
			
		||||
	conn.Export(f, "/com/github/guelfey/Demo", "com.github.guelfey.Demo")
 | 
			
		||||
	props := prop.New(conn, "/com/github/guelfey/Demo", propsSpec)
 | 
			
		||||
	n := &introspect.Node{
 | 
			
		||||
		Name: "/com/github/guelfey/Demo",
 | 
			
		||||
		Interfaces: []introspect.Interface{
 | 
			
		||||
			introspect.IntrospectData,
 | 
			
		||||
			prop.IntrospectData,
 | 
			
		||||
			{
 | 
			
		||||
				Name:       "com.github.guelfey.Demo",
 | 
			
		||||
				Methods:    introspect.Methods(f),
 | 
			
		||||
				Properties: props.Introspection("com.github.guelfey.Demo"),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	conn.Export(introspect.NewIntrospectable(n), "/com/github/guelfey/Demo",
 | 
			
		||||
		"org.freedesktop.DBus.Introspectable")
 | 
			
		||||
	fmt.Println("Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo ...")
 | 
			
		||||
 | 
			
		||||
	c := make(chan *dbus.Signal)
 | 
			
		||||
	conn.Signal(c)
 | 
			
		||||
	for _ = range c {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								vendor/src/github.com/godbus/dbus/_examples/server.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								vendor/src/github.com/godbus/dbus/_examples/server.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
	"github.com/godbus/dbus/introspect"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const intro = `
 | 
			
		||||
<node>
 | 
			
		||||
	<interface name="com.github.guelfey.Demo">
 | 
			
		||||
		<method name="Foo">
 | 
			
		||||
			<arg direction="out" type="s"/>
 | 
			
		||||
		</method>
 | 
			
		||||
	</interface>` + introspect.IntrospectDataString + `</node> `
 | 
			
		||||
 | 
			
		||||
type foo string
 | 
			
		||||
 | 
			
		||||
func (f foo) Foo() (string, *dbus.Error) {
 | 
			
		||||
	fmt.Println(f)
 | 
			
		||||
	return string(f), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	conn, err := dbus.SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	reply, err := conn.RequestName("com.github.guelfey.Demo",
 | 
			
		||||
		dbus.NameFlagDoNotQueue)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	if reply != dbus.RequestNameReplyPrimaryOwner {
 | 
			
		||||
		fmt.Fprintln(os.Stderr, "name already taken")
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
	f := foo("Bar!")
 | 
			
		||||
	conn.Export(f, "/com/github/guelfey/Demo", "com.github.guelfey.Demo")
 | 
			
		||||
	conn.Export(introspect.Introspectable(intro), "/com/github/guelfey/Demo",
 | 
			
		||||
		"org.freedesktop.DBus.Introspectable")
 | 
			
		||||
	fmt.Println("Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo ...")
 | 
			
		||||
	select {}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								vendor/src/github.com/godbus/dbus/_examples/signal.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								vendor/src/github.com/godbus/dbus/_examples/signal.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	conn, err := dbus.SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err)
 | 
			
		||||
		os.Exit(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
 | 
			
		||||
		"type='signal',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',sender='org.freedesktop.DBus'")
 | 
			
		||||
 | 
			
		||||
	c := make(chan *dbus.Signal, 10)
 | 
			
		||||
	conn.Signal(c)
 | 
			
		||||
	for v := range c {
 | 
			
		||||
		fmt.Println(v)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										253
									
								
								vendor/src/github.com/godbus/dbus/auth.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								vendor/src/github.com/godbus/dbus/auth.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,253 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AuthStatus represents the Status of an authentication mechanism.
 | 
			
		||||
type AuthStatus byte
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// AuthOk signals that authentication is finished; the next command
 | 
			
		||||
	// from the server should be an OK.
 | 
			
		||||
	AuthOk AuthStatus = iota
 | 
			
		||||
 | 
			
		||||
	// AuthContinue signals that additional data is needed; the next command
 | 
			
		||||
	// from the server should be a DATA.
 | 
			
		||||
	AuthContinue
 | 
			
		||||
 | 
			
		||||
	// AuthError signals an error; the server sent invalid data or some
 | 
			
		||||
	// other unexpected thing happened and the current authentication
 | 
			
		||||
	// process should be aborted.
 | 
			
		||||
	AuthError
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type authState byte
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	waitingForData authState = iota
 | 
			
		||||
	waitingForOk
 | 
			
		||||
	waitingForReject
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Auth defines the behaviour of an authentication mechanism.
 | 
			
		||||
type Auth interface {
 | 
			
		||||
	// Return the name of the mechnism, the argument to the first AUTH command
 | 
			
		||||
	// and the next status.
 | 
			
		||||
	FirstData() (name, resp []byte, status AuthStatus)
 | 
			
		||||
 | 
			
		||||
	// Process the given DATA command, and return the argument to the DATA
 | 
			
		||||
	// command and the next status. If len(resp) == 0, no DATA command is sent.
 | 
			
		||||
	HandleData(data []byte) (resp []byte, status AuthStatus)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Auth authenticates the connection, trying the given list of authentication
 | 
			
		||||
// mechanisms (in that order). If nil is passed, the EXTERNAL and
 | 
			
		||||
// DBUS_COOKIE_SHA1 mechanisms are tried for the current user. For private
 | 
			
		||||
// connections, this method must be called before sending any messages to the
 | 
			
		||||
// bus. Auth must not be called on shared connections.
 | 
			
		||||
func (conn *Conn) Auth(methods []Auth) error {
 | 
			
		||||
	if methods == nil {
 | 
			
		||||
		uid := strconv.Itoa(os.Getuid())
 | 
			
		||||
		methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())}
 | 
			
		||||
	}
 | 
			
		||||
	in := bufio.NewReader(conn.transport)
 | 
			
		||||
	err := conn.transport.SendNullByte()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	err = authWriteLine(conn.transport, []byte("AUTH"))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	s, err := authReadLine(in)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if len(s) < 2 || !bytes.Equal(s[0], []byte("REJECTED")) {
 | 
			
		||||
		return errors.New("dbus: authentication protocol error")
 | 
			
		||||
	}
 | 
			
		||||
	s = s[1:]
 | 
			
		||||
	for _, v := range s {
 | 
			
		||||
		for _, m := range methods {
 | 
			
		||||
			if name, data, status := m.FirstData(); bytes.Equal(v, name) {
 | 
			
		||||
				var ok bool
 | 
			
		||||
				err = authWriteLine(conn.transport, []byte("AUTH"), []byte(v), data)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				switch status {
 | 
			
		||||
				case AuthOk:
 | 
			
		||||
					err, ok = conn.tryAuth(m, waitingForOk, in)
 | 
			
		||||
				case AuthContinue:
 | 
			
		||||
					err, ok = conn.tryAuth(m, waitingForData, in)
 | 
			
		||||
				default:
 | 
			
		||||
					panic("dbus: invalid authentication status")
 | 
			
		||||
				}
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if ok {
 | 
			
		||||
					if conn.transport.SupportsUnixFDs() {
 | 
			
		||||
						err = authWriteLine(conn, []byte("NEGOTIATE_UNIX_FD"))
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							return err
 | 
			
		||||
						}
 | 
			
		||||
						line, err := authReadLine(in)
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							return err
 | 
			
		||||
						}
 | 
			
		||||
						switch {
 | 
			
		||||
						case bytes.Equal(line[0], []byte("AGREE_UNIX_FD")):
 | 
			
		||||
							conn.EnableUnixFDs()
 | 
			
		||||
							conn.unixFD = true
 | 
			
		||||
						case bytes.Equal(line[0], []byte("ERROR")):
 | 
			
		||||
						default:
 | 
			
		||||
							return errors.New("dbus: authentication protocol error")
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					err = authWriteLine(conn.transport, []byte("BEGIN"))
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
					go conn.inWorker()
 | 
			
		||||
					go conn.outWorker()
 | 
			
		||||
					return nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return errors.New("dbus: authentication failed")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tryAuth tries to authenticate with m as the mechanism, using state as the
 | 
			
		||||
// initial authState and in for reading input. It returns (nil, true) on
 | 
			
		||||
// success, (nil, false) on a REJECTED and (someErr, false) if some other
 | 
			
		||||
// error occured.
 | 
			
		||||
func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, bool) {
 | 
			
		||||
	for {
 | 
			
		||||
		s, err := authReadLine(in)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err, false
 | 
			
		||||
		}
 | 
			
		||||
		switch {
 | 
			
		||||
		case state == waitingForData && string(s[0]) == "DATA":
 | 
			
		||||
			if len(s) != 2 {
 | 
			
		||||
				err = authWriteLine(conn.transport, []byte("ERROR"))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err, false
 | 
			
		||||
				}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			data, status := m.HandleData(s[1])
 | 
			
		||||
			switch status {
 | 
			
		||||
			case AuthOk, AuthContinue:
 | 
			
		||||
				if len(data) != 0 {
 | 
			
		||||
					err = authWriteLine(conn.transport, []byte("DATA"), data)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err, false
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				if status == AuthOk {
 | 
			
		||||
					state = waitingForOk
 | 
			
		||||
				}
 | 
			
		||||
			case AuthError:
 | 
			
		||||
				err = authWriteLine(conn.transport, []byte("ERROR"))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err, false
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case state == waitingForData && string(s[0]) == "REJECTED":
 | 
			
		||||
			return nil, false
 | 
			
		||||
		case state == waitingForData && string(s[0]) == "ERROR":
 | 
			
		||||
			err = authWriteLine(conn.transport, []byte("CANCEL"))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err, false
 | 
			
		||||
			}
 | 
			
		||||
			state = waitingForReject
 | 
			
		||||
		case state == waitingForData && string(s[0]) == "OK":
 | 
			
		||||
			if len(s) != 2 {
 | 
			
		||||
				err = authWriteLine(conn.transport, []byte("CANCEL"))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err, false
 | 
			
		||||
				}
 | 
			
		||||
				state = waitingForReject
 | 
			
		||||
			}
 | 
			
		||||
			conn.uuid = string(s[1])
 | 
			
		||||
			return nil, true
 | 
			
		||||
		case state == waitingForData:
 | 
			
		||||
			err = authWriteLine(conn.transport, []byte("ERROR"))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err, false
 | 
			
		||||
			}
 | 
			
		||||
		case state == waitingForOk && string(s[0]) == "OK":
 | 
			
		||||
			if len(s) != 2 {
 | 
			
		||||
				err = authWriteLine(conn.transport, []byte("CANCEL"))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err, false
 | 
			
		||||
				}
 | 
			
		||||
				state = waitingForReject
 | 
			
		||||
			}
 | 
			
		||||
			conn.uuid = string(s[1])
 | 
			
		||||
			return nil, true
 | 
			
		||||
		case state == waitingForOk && string(s[0]) == "REJECTED":
 | 
			
		||||
			return nil, false
 | 
			
		||||
		case state == waitingForOk && (string(s[0]) == "DATA" ||
 | 
			
		||||
			string(s[0]) == "ERROR"):
 | 
			
		||||
 | 
			
		||||
			err = authWriteLine(conn.transport, []byte("CANCEL"))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err, false
 | 
			
		||||
			}
 | 
			
		||||
			state = waitingForReject
 | 
			
		||||
		case state == waitingForOk:
 | 
			
		||||
			err = authWriteLine(conn.transport, []byte("ERROR"))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err, false
 | 
			
		||||
			}
 | 
			
		||||
		case state == waitingForReject && string(s[0]) == "REJECTED":
 | 
			
		||||
			return nil, false
 | 
			
		||||
		case state == waitingForReject:
 | 
			
		||||
			return errors.New("dbus: authentication protocol error"), false
 | 
			
		||||
		default:
 | 
			
		||||
			panic("dbus: invalid auth state")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// authReadLine reads a line and separates it into its fields.
 | 
			
		||||
func authReadLine(in *bufio.Reader) ([][]byte, error) {
 | 
			
		||||
	data, err := in.ReadBytes('\n')
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	data = bytes.TrimSuffix(data, []byte("\r\n"))
 | 
			
		||||
	return bytes.Split(data, []byte{' '}), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// authWriteLine writes the given line in the authentication protocol format
 | 
			
		||||
// (elements of data separated by a " " and terminated by "\r\n").
 | 
			
		||||
func authWriteLine(out io.Writer, data ...[]byte) error {
 | 
			
		||||
	buf := make([]byte, 0)
 | 
			
		||||
	for i, v := range data {
 | 
			
		||||
		buf = append(buf, v...)
 | 
			
		||||
		if i != len(data)-1 {
 | 
			
		||||
			buf = append(buf, ' ')
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	buf = append(buf, '\r')
 | 
			
		||||
	buf = append(buf, '\n')
 | 
			
		||||
	n, err := out.Write(buf)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if n != len(buf) {
 | 
			
		||||
		return io.ErrUnexpectedEOF
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/src/github.com/godbus/dbus/auth_external.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/src/github.com/godbus/dbus/auth_external.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AuthExternal returns an Auth that authenticates as the given user with the
 | 
			
		||||
// EXTERNAL mechanism.
 | 
			
		||||
func AuthExternal(user string) Auth {
 | 
			
		||||
	return authExternal{user}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AuthExternal implements the EXTERNAL authentication mechanism.
 | 
			
		||||
type authExternal struct {
 | 
			
		||||
	user string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a authExternal) FirstData() ([]byte, []byte, AuthStatus) {
 | 
			
		||||
	b := make([]byte, 2*len(a.user))
 | 
			
		||||
	hex.Encode(b, []byte(a.user))
 | 
			
		||||
	return []byte("EXTERNAL"), b, AuthOk
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a authExternal) HandleData(b []byte) ([]byte, AuthStatus) {
 | 
			
		||||
	return nil, AuthError
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										102
									
								
								vendor/src/github.com/godbus/dbus/auth_sha1.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								vendor/src/github.com/godbus/dbus/auth_sha1.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,102 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AuthCookieSha1 returns an Auth that authenticates as the given user with the
 | 
			
		||||
// DBUS_COOKIE_SHA1 mechanism. The home parameter should specify the home
 | 
			
		||||
// directory of the user.
 | 
			
		||||
func AuthCookieSha1(user, home string) Auth {
 | 
			
		||||
	return authCookieSha1{user, home}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type authCookieSha1 struct {
 | 
			
		||||
	user, home string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a authCookieSha1) FirstData() ([]byte, []byte, AuthStatus) {
 | 
			
		||||
	b := make([]byte, 2*len(a.user))
 | 
			
		||||
	hex.Encode(b, []byte(a.user))
 | 
			
		||||
	return []byte("DBUS_COOKIE_SHA1"), b, AuthContinue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a authCookieSha1) HandleData(data []byte) ([]byte, AuthStatus) {
 | 
			
		||||
	challenge := make([]byte, len(data)/2)
 | 
			
		||||
	_, err := hex.Decode(challenge, data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, AuthError
 | 
			
		||||
	}
 | 
			
		||||
	b := bytes.Split(challenge, []byte{' '})
 | 
			
		||||
	if len(b) != 3 {
 | 
			
		||||
		return nil, AuthError
 | 
			
		||||
	}
 | 
			
		||||
	context := b[0]
 | 
			
		||||
	id := b[1]
 | 
			
		||||
	svchallenge := b[2]
 | 
			
		||||
	cookie := a.getCookie(context, id)
 | 
			
		||||
	if cookie == nil {
 | 
			
		||||
		return nil, AuthError
 | 
			
		||||
	}
 | 
			
		||||
	clchallenge := a.generateChallenge()
 | 
			
		||||
	if clchallenge == nil {
 | 
			
		||||
		return nil, AuthError
 | 
			
		||||
	}
 | 
			
		||||
	hash := sha1.New()
 | 
			
		||||
	hash.Write(bytes.Join([][]byte{svchallenge, clchallenge, cookie}, []byte{':'}))
 | 
			
		||||
	hexhash := make([]byte, 2*hash.Size())
 | 
			
		||||
	hex.Encode(hexhash, hash.Sum(nil))
 | 
			
		||||
	data = append(clchallenge, ' ')
 | 
			
		||||
	data = append(data, hexhash...)
 | 
			
		||||
	resp := make([]byte, 2*len(data))
 | 
			
		||||
	hex.Encode(resp, data)
 | 
			
		||||
	return resp, AuthOk
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getCookie searches for the cookie identified by id in context and returns
 | 
			
		||||
// the cookie content or nil. (Since HandleData can't return a specific error,
 | 
			
		||||
// but only whether an error occured, this function also doesn't bother to
 | 
			
		||||
// return an error.)
 | 
			
		||||
func (a authCookieSha1) getCookie(context, id []byte) []byte {
 | 
			
		||||
	file, err := os.Open(a.home + "/.dbus-keyrings/" + string(context))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	defer file.Close()
 | 
			
		||||
	rd := bufio.NewReader(file)
 | 
			
		||||
	for {
 | 
			
		||||
		line, err := rd.ReadBytes('\n')
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		line = line[:len(line)-1]
 | 
			
		||||
		b := bytes.Split(line, []byte{' '})
 | 
			
		||||
		if len(b) != 3 {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		if bytes.Equal(b[0], id) {
 | 
			
		||||
			return b[2]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generateChallenge returns a random, hex-encoded challenge, or nil on error
 | 
			
		||||
// (see above).
 | 
			
		||||
func (a authCookieSha1) generateChallenge() []byte {
 | 
			
		||||
	b := make([]byte, 16)
 | 
			
		||||
	n, err := rand.Read(b)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if n != 16 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	enc := make([]byte, 32)
 | 
			
		||||
	hex.Encode(enc, b)
 | 
			
		||||
	return enc
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										147
									
								
								vendor/src/github.com/godbus/dbus/call.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								vendor/src/github.com/godbus/dbus/call.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,147 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Call represents a pending or completed method call.
 | 
			
		||||
type Call struct {
 | 
			
		||||
	Destination string
 | 
			
		||||
	Path        ObjectPath
 | 
			
		||||
	Method      string
 | 
			
		||||
	Args        []interface{}
 | 
			
		||||
 | 
			
		||||
	// Strobes when the call is complete.
 | 
			
		||||
	Done chan *Call
 | 
			
		||||
 | 
			
		||||
	// After completion, the error status. If this is non-nil, it may be an
 | 
			
		||||
	// error message from the peer (with Error as its type) or some other error.
 | 
			
		||||
	Err error
 | 
			
		||||
 | 
			
		||||
	// Holds the response once the call is done.
 | 
			
		||||
	Body []interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var errSignature = errors.New("dbus: mismatched signature")
 | 
			
		||||
 | 
			
		||||
// Store stores the body of the reply into the provided pointers. It returns
 | 
			
		||||
// an error if the signatures of the body and retvalues don't match, or if
 | 
			
		||||
// the error status is not nil.
 | 
			
		||||
func (c *Call) Store(retvalues ...interface{}) error {
 | 
			
		||||
	if c.Err != nil {
 | 
			
		||||
		return c.Err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Store(c.Body, retvalues...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Object represents a remote object on which methods can be invoked.
 | 
			
		||||
type Object struct {
 | 
			
		||||
	conn *Conn
 | 
			
		||||
	dest string
 | 
			
		||||
	path ObjectPath
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Call calls a method with (*Object).Go and waits for its reply.
 | 
			
		||||
func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call {
 | 
			
		||||
	return <-o.Go(method, flags, make(chan *Call, 1), args...).Done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given
 | 
			
		||||
// object. The property name must be given in interface.member notation.
 | 
			
		||||
func (o *Object) GetProperty(p string) (Variant, error) {
 | 
			
		||||
	idx := strings.LastIndex(p, ".")
 | 
			
		||||
	if idx == -1 || idx+1 == len(p) {
 | 
			
		||||
		return Variant{}, errors.New("dbus: invalid property " + p)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iface := p[:idx]
 | 
			
		||||
	prop := p[idx+1:]
 | 
			
		||||
 | 
			
		||||
	result := Variant{}
 | 
			
		||||
	err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return Variant{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Go calls a method with the given arguments asynchronously. It returns a
 | 
			
		||||
// Call structure representing this method call. The passed channel will
 | 
			
		||||
// return the same value once the call is done. If ch is nil, a new channel
 | 
			
		||||
// will be allocated. Otherwise, ch has to be buffered or Go will panic.
 | 
			
		||||
//
 | 
			
		||||
// If the flags include FlagNoReplyExpected, ch is ignored and a Call structure
 | 
			
		||||
// is returned of which only the Err member is valid.
 | 
			
		||||
//
 | 
			
		||||
// If the method parameter contains a dot ('.'), the part before the last dot
 | 
			
		||||
// specifies the interface on which the method is called.
 | 
			
		||||
func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
 | 
			
		||||
	iface := ""
 | 
			
		||||
	i := strings.LastIndex(method, ".")
 | 
			
		||||
	if i != -1 {
 | 
			
		||||
		iface = method[:i]
 | 
			
		||||
	}
 | 
			
		||||
	method = method[i+1:]
 | 
			
		||||
	msg := new(Message)
 | 
			
		||||
	msg.Type = TypeMethodCall
 | 
			
		||||
	msg.serial = o.conn.getSerial()
 | 
			
		||||
	msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected)
 | 
			
		||||
	msg.Headers = make(map[HeaderField]Variant)
 | 
			
		||||
	msg.Headers[FieldPath] = MakeVariant(o.path)
 | 
			
		||||
	msg.Headers[FieldDestination] = MakeVariant(o.dest)
 | 
			
		||||
	msg.Headers[FieldMember] = MakeVariant(method)
 | 
			
		||||
	if iface != "" {
 | 
			
		||||
		msg.Headers[FieldInterface] = MakeVariant(iface)
 | 
			
		||||
	}
 | 
			
		||||
	msg.Body = args
 | 
			
		||||
	if len(args) > 0 {
 | 
			
		||||
		msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...))
 | 
			
		||||
	}
 | 
			
		||||
	if msg.Flags&FlagNoReplyExpected == 0 {
 | 
			
		||||
		if ch == nil {
 | 
			
		||||
			ch = make(chan *Call, 10)
 | 
			
		||||
		} else if cap(ch) == 0 {
 | 
			
		||||
			panic("dbus: unbuffered channel passed to (*Object).Go")
 | 
			
		||||
		}
 | 
			
		||||
		call := &Call{
 | 
			
		||||
			Destination: o.dest,
 | 
			
		||||
			Path:        o.path,
 | 
			
		||||
			Method:      method,
 | 
			
		||||
			Args:        args,
 | 
			
		||||
			Done:        ch,
 | 
			
		||||
		}
 | 
			
		||||
		o.conn.callsLck.Lock()
 | 
			
		||||
		o.conn.calls[msg.serial] = call
 | 
			
		||||
		o.conn.callsLck.Unlock()
 | 
			
		||||
		o.conn.outLck.RLock()
 | 
			
		||||
		if o.conn.closed {
 | 
			
		||||
			call.Err = ErrClosed
 | 
			
		||||
			call.Done <- call
 | 
			
		||||
		} else {
 | 
			
		||||
			o.conn.out <- msg
 | 
			
		||||
		}
 | 
			
		||||
		o.conn.outLck.RUnlock()
 | 
			
		||||
		return call
 | 
			
		||||
	}
 | 
			
		||||
	o.conn.outLck.RLock()
 | 
			
		||||
	defer o.conn.outLck.RUnlock()
 | 
			
		||||
	if o.conn.closed {
 | 
			
		||||
		return &Call{Err: ErrClosed}
 | 
			
		||||
	}
 | 
			
		||||
	o.conn.out <- msg
 | 
			
		||||
	return &Call{Err: nil}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Destination returns the destination that calls on o are sent to.
 | 
			
		||||
func (o *Object) Destination() string {
 | 
			
		||||
	return o.dest
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Path returns the path that calls on o are sent to.
 | 
			
		||||
func (o *Object) Path() ObjectPath {
 | 
			
		||||
	return o.path
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										601
									
								
								vendor/src/github.com/godbus/dbus/conn.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										601
									
								
								vendor/src/github.com/godbus/dbus/conn.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,601 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	systemBus     *Conn
 | 
			
		||||
	systemBusLck  sync.Mutex
 | 
			
		||||
	sessionBus    *Conn
 | 
			
		||||
	sessionBusLck sync.Mutex
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrClosed is the error returned by calls on a closed connection.
 | 
			
		||||
var ErrClosed = errors.New("dbus: connection closed by user")
 | 
			
		||||
 | 
			
		||||
// Conn represents a connection to a message bus (usually, the system or
 | 
			
		||||
// session bus).
 | 
			
		||||
//
 | 
			
		||||
// Connections are either shared or private. Shared connections
 | 
			
		||||
// are shared between calls to the functions that return them. As a result,
 | 
			
		||||
// the methods Close, Auth and Hello must not be called on them.
 | 
			
		||||
//
 | 
			
		||||
// Multiple goroutines may invoke methods on a connection simultaneously.
 | 
			
		||||
type Conn struct {
 | 
			
		||||
	transport
 | 
			
		||||
 | 
			
		||||
	busObj *Object
 | 
			
		||||
	unixFD bool
 | 
			
		||||
	uuid   string
 | 
			
		||||
 | 
			
		||||
	names    []string
 | 
			
		||||
	namesLck sync.RWMutex
 | 
			
		||||
 | 
			
		||||
	serialLck  sync.Mutex
 | 
			
		||||
	nextSerial uint32
 | 
			
		||||
	serialUsed map[uint32]bool
 | 
			
		||||
 | 
			
		||||
	calls    map[uint32]*Call
 | 
			
		||||
	callsLck sync.RWMutex
 | 
			
		||||
 | 
			
		||||
	handlers    map[ObjectPath]map[string]interface{}
 | 
			
		||||
	handlersLck sync.RWMutex
 | 
			
		||||
 | 
			
		||||
	out    chan *Message
 | 
			
		||||
	closed bool
 | 
			
		||||
	outLck sync.RWMutex
 | 
			
		||||
 | 
			
		||||
	signals    []chan<- *Signal
 | 
			
		||||
	signalsLck sync.Mutex
 | 
			
		||||
 | 
			
		||||
	eavesdropped    chan<- *Message
 | 
			
		||||
	eavesdroppedLck sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SessionBus returns a shared connection to the session bus, connecting to it
 | 
			
		||||
// if not already done.
 | 
			
		||||
func SessionBus() (conn *Conn, err error) {
 | 
			
		||||
	sessionBusLck.Lock()
 | 
			
		||||
	defer sessionBusLck.Unlock()
 | 
			
		||||
	if sessionBus != nil {
 | 
			
		||||
		return sessionBus, nil
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if conn != nil {
 | 
			
		||||
			sessionBus = conn
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	conn, err = SessionBusPrivate()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if err = conn.Auth(nil); err != nil {
 | 
			
		||||
		conn.Close()
 | 
			
		||||
		conn = nil
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if err = conn.Hello(); err != nil {
 | 
			
		||||
		conn.Close()
 | 
			
		||||
		conn = nil
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SessionBusPrivate returns a new private connection to the session bus.
 | 
			
		||||
func SessionBusPrivate() (*Conn, error) {
 | 
			
		||||
	address := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
 | 
			
		||||
	if address != "" && address != "autolaunch:" {
 | 
			
		||||
		return Dial(address)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return sessionBusPlatform()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SystemBus returns a shared connection to the system bus, connecting to it if
 | 
			
		||||
// not already done.
 | 
			
		||||
func SystemBus() (conn *Conn, err error) {
 | 
			
		||||
	systemBusLck.Lock()
 | 
			
		||||
	defer systemBusLck.Unlock()
 | 
			
		||||
	if systemBus != nil {
 | 
			
		||||
		return systemBus, nil
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if conn != nil {
 | 
			
		||||
			systemBus = conn
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	conn, err = SystemBusPrivate()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if err = conn.Auth(nil); err != nil {
 | 
			
		||||
		conn.Close()
 | 
			
		||||
		conn = nil
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if err = conn.Hello(); err != nil {
 | 
			
		||||
		conn.Close()
 | 
			
		||||
		conn = nil
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SystemBusPrivate returns a new private connection to the system bus.
 | 
			
		||||
func SystemBusPrivate() (*Conn, error) {
 | 
			
		||||
	address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
 | 
			
		||||
	if address != "" {
 | 
			
		||||
		return Dial(address)
 | 
			
		||||
	}
 | 
			
		||||
	return Dial(defaultSystemBusAddress)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dial establishes a new private connection to the message bus specified by address.
 | 
			
		||||
func Dial(address string) (*Conn, error) {
 | 
			
		||||
	tr, err := getTransport(address)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return newConn(tr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewConn creates a new private *Conn from an already established connection.
 | 
			
		||||
func NewConn(conn io.ReadWriteCloser) (*Conn, error) {
 | 
			
		||||
	return newConn(genericTransport{conn})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newConn creates a new *Conn from a transport.
 | 
			
		||||
func newConn(tr transport) (*Conn, error) {
 | 
			
		||||
	conn := new(Conn)
 | 
			
		||||
	conn.transport = tr
 | 
			
		||||
	conn.calls = make(map[uint32]*Call)
 | 
			
		||||
	conn.out = make(chan *Message, 10)
 | 
			
		||||
	conn.handlers = make(map[ObjectPath]map[string]interface{})
 | 
			
		||||
	conn.nextSerial = 1
 | 
			
		||||
	conn.serialUsed = map[uint32]bool{0: true}
 | 
			
		||||
	conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
 | 
			
		||||
	return conn, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BusObject returns the object owned by the bus daemon which handles
 | 
			
		||||
// administrative requests.
 | 
			
		||||
func (conn *Conn) BusObject() *Object {
 | 
			
		||||
	return conn.busObj
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close closes the connection. Any blocked operations will return with errors
 | 
			
		||||
// and the channels passed to Eavesdrop and Signal are closed. This method must
 | 
			
		||||
// not be called on shared connections.
 | 
			
		||||
func (conn *Conn) Close() error {
 | 
			
		||||
	conn.outLck.Lock()
 | 
			
		||||
	close(conn.out)
 | 
			
		||||
	conn.closed = true
 | 
			
		||||
	conn.outLck.Unlock()
 | 
			
		||||
	conn.signalsLck.Lock()
 | 
			
		||||
	for _, ch := range conn.signals {
 | 
			
		||||
		close(ch)
 | 
			
		||||
	}
 | 
			
		||||
	conn.signalsLck.Unlock()
 | 
			
		||||
	conn.eavesdroppedLck.Lock()
 | 
			
		||||
	if conn.eavesdropped != nil {
 | 
			
		||||
		close(conn.eavesdropped)
 | 
			
		||||
	}
 | 
			
		||||
	conn.eavesdroppedLck.Unlock()
 | 
			
		||||
	return conn.transport.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Eavesdrop causes conn to send all incoming messages to the given channel
 | 
			
		||||
// without further processing. Method replies, errors and signals will not be
 | 
			
		||||
// sent to the appropiate channels and method calls will not be handled. If nil
 | 
			
		||||
// is passed, the normal behaviour is restored.
 | 
			
		||||
//
 | 
			
		||||
// The caller has to make sure that ch is sufficiently buffered;
 | 
			
		||||
// if a message arrives when a write to ch is not possible, the message is
 | 
			
		||||
// discarded.
 | 
			
		||||
func (conn *Conn) Eavesdrop(ch chan<- *Message) {
 | 
			
		||||
	conn.eavesdroppedLck.Lock()
 | 
			
		||||
	conn.eavesdropped = ch
 | 
			
		||||
	conn.eavesdroppedLck.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getSerial returns an unused serial.
 | 
			
		||||
func (conn *Conn) getSerial() uint32 {
 | 
			
		||||
	conn.serialLck.Lock()
 | 
			
		||||
	defer conn.serialLck.Unlock()
 | 
			
		||||
	n := conn.nextSerial
 | 
			
		||||
	for conn.serialUsed[n] {
 | 
			
		||||
		n++
 | 
			
		||||
	}
 | 
			
		||||
	conn.serialUsed[n] = true
 | 
			
		||||
	conn.nextSerial = n + 1
 | 
			
		||||
	return n
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Hello sends the initial org.freedesktop.DBus.Hello call. This method must be
 | 
			
		||||
// called after authentication, but before sending any other messages to the
 | 
			
		||||
// bus. Hello must not be called for shared connections.
 | 
			
		||||
func (conn *Conn) Hello() error {
 | 
			
		||||
	var s string
 | 
			
		||||
	err := conn.busObj.Call("org.freedesktop.DBus.Hello", 0).Store(&s)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	conn.namesLck.Lock()
 | 
			
		||||
	conn.names = make([]string, 1)
 | 
			
		||||
	conn.names[0] = s
 | 
			
		||||
	conn.namesLck.Unlock()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// inWorker runs in an own goroutine, reading incoming messages from the
 | 
			
		||||
// transport and dispatching them appropiately.
 | 
			
		||||
func (conn *Conn) inWorker() {
 | 
			
		||||
	for {
 | 
			
		||||
		msg, err := conn.ReadMessage()
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			conn.eavesdroppedLck.Lock()
 | 
			
		||||
			if conn.eavesdropped != nil {
 | 
			
		||||
				select {
 | 
			
		||||
				case conn.eavesdropped <- msg:
 | 
			
		||||
				default:
 | 
			
		||||
				}
 | 
			
		||||
				conn.eavesdroppedLck.Unlock()
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			conn.eavesdroppedLck.Unlock()
 | 
			
		||||
			dest, _ := msg.Headers[FieldDestination].value.(string)
 | 
			
		||||
			found := false
 | 
			
		||||
			if dest == "" {
 | 
			
		||||
				found = true
 | 
			
		||||
			} else {
 | 
			
		||||
				conn.namesLck.RLock()
 | 
			
		||||
				if len(conn.names) == 0 {
 | 
			
		||||
					found = true
 | 
			
		||||
				}
 | 
			
		||||
				for _, v := range conn.names {
 | 
			
		||||
					if dest == v {
 | 
			
		||||
						found = true
 | 
			
		||||
						break
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				conn.namesLck.RUnlock()
 | 
			
		||||
			}
 | 
			
		||||
			if !found {
 | 
			
		||||
				// Eavesdropped a message, but no channel for it is registered.
 | 
			
		||||
				// Ignore it.
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			switch msg.Type {
 | 
			
		||||
			case TypeMethodReply, TypeError:
 | 
			
		||||
				serial := msg.Headers[FieldReplySerial].value.(uint32)
 | 
			
		||||
				conn.callsLck.Lock()
 | 
			
		||||
				if c, ok := conn.calls[serial]; ok {
 | 
			
		||||
					if msg.Type == TypeError {
 | 
			
		||||
						name, _ := msg.Headers[FieldErrorName].value.(string)
 | 
			
		||||
						c.Err = Error{name, msg.Body}
 | 
			
		||||
					} else {
 | 
			
		||||
						c.Body = msg.Body
 | 
			
		||||
					}
 | 
			
		||||
					c.Done <- c
 | 
			
		||||
					conn.serialLck.Lock()
 | 
			
		||||
					delete(conn.serialUsed, serial)
 | 
			
		||||
					conn.serialLck.Unlock()
 | 
			
		||||
					delete(conn.calls, serial)
 | 
			
		||||
				}
 | 
			
		||||
				conn.callsLck.Unlock()
 | 
			
		||||
			case TypeSignal:
 | 
			
		||||
				iface := msg.Headers[FieldInterface].value.(string)
 | 
			
		||||
				member := msg.Headers[FieldMember].value.(string)
 | 
			
		||||
				// as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
 | 
			
		||||
				// sender is optional for signals.
 | 
			
		||||
				sender, _ := msg.Headers[FieldSender].value.(string)
 | 
			
		||||
				if iface == "org.freedesktop.DBus" && member == "NameLost" &&
 | 
			
		||||
					sender == "org.freedesktop.DBus" {
 | 
			
		||||
 | 
			
		||||
					name, _ := msg.Body[0].(string)
 | 
			
		||||
					conn.namesLck.Lock()
 | 
			
		||||
					for i, v := range conn.names {
 | 
			
		||||
						if v == name {
 | 
			
		||||
							copy(conn.names[i:], conn.names[i+1:])
 | 
			
		||||
							conn.names = conn.names[:len(conn.names)-1]
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					conn.namesLck.Unlock()
 | 
			
		||||
				}
 | 
			
		||||
				signal := &Signal{
 | 
			
		||||
					Sender: sender,
 | 
			
		||||
					Path:   msg.Headers[FieldPath].value.(ObjectPath),
 | 
			
		||||
					Name:   iface + "." + member,
 | 
			
		||||
					Body:   msg.Body,
 | 
			
		||||
				}
 | 
			
		||||
				conn.signalsLck.Lock()
 | 
			
		||||
				for _, ch := range conn.signals {
 | 
			
		||||
					// don't block trying to send a signal
 | 
			
		||||
					select {
 | 
			
		||||
					case ch <- signal:
 | 
			
		||||
					default:
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				conn.signalsLck.Unlock()
 | 
			
		||||
			case TypeMethodCall:
 | 
			
		||||
				go conn.handleCall(msg)
 | 
			
		||||
			}
 | 
			
		||||
		} else if _, ok := err.(InvalidMessageError); !ok {
 | 
			
		||||
			// Some read error occured (usually EOF); we can't really do
 | 
			
		||||
			// anything but to shut down all stuff and returns errors to all
 | 
			
		||||
			// pending replies.
 | 
			
		||||
			conn.Close()
 | 
			
		||||
			conn.callsLck.RLock()
 | 
			
		||||
			for _, v := range conn.calls {
 | 
			
		||||
				v.Err = err
 | 
			
		||||
				v.Done <- v
 | 
			
		||||
			}
 | 
			
		||||
			conn.callsLck.RUnlock()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// invalid messages are ignored
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Names returns the list of all names that are currently owned by this
 | 
			
		||||
// connection. The slice is always at least one element long, the first element
 | 
			
		||||
// being the unique name of the connection.
 | 
			
		||||
func (conn *Conn) Names() []string {
 | 
			
		||||
	conn.namesLck.RLock()
 | 
			
		||||
	// copy the slice so it can't be modified
 | 
			
		||||
	s := make([]string, len(conn.names))
 | 
			
		||||
	copy(s, conn.names)
 | 
			
		||||
	conn.namesLck.RUnlock()
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Object returns the object identified by the given destination name and path.
 | 
			
		||||
func (conn *Conn) Object(dest string, path ObjectPath) *Object {
 | 
			
		||||
	return &Object{conn, dest, path}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// outWorker runs in an own goroutine, encoding and sending messages that are
 | 
			
		||||
// sent to conn.out.
 | 
			
		||||
func (conn *Conn) outWorker() {
 | 
			
		||||
	for msg := range conn.out {
 | 
			
		||||
		err := conn.SendMessage(msg)
 | 
			
		||||
		conn.callsLck.RLock()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if c := conn.calls[msg.serial]; c != nil {
 | 
			
		||||
				c.Err = err
 | 
			
		||||
				c.Done <- c
 | 
			
		||||
			}
 | 
			
		||||
			conn.serialLck.Lock()
 | 
			
		||||
			delete(conn.serialUsed, msg.serial)
 | 
			
		||||
			conn.serialLck.Unlock()
 | 
			
		||||
		} else if msg.Type != TypeMethodCall {
 | 
			
		||||
			conn.serialLck.Lock()
 | 
			
		||||
			delete(conn.serialUsed, msg.serial)
 | 
			
		||||
			conn.serialLck.Unlock()
 | 
			
		||||
		}
 | 
			
		||||
		conn.callsLck.RUnlock()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send sends the given message to the message bus. You usually don't need to
 | 
			
		||||
// use this; use the higher-level equivalents (Call / Go, Emit and Export)
 | 
			
		||||
// instead. If msg is a method call and NoReplyExpected is not set, a non-nil
 | 
			
		||||
// call is returned and the same value is sent to ch (which must be buffered)
 | 
			
		||||
// once the call is complete. Otherwise, ch is ignored and a Call structure is
 | 
			
		||||
// returned of which only the Err member is valid.
 | 
			
		||||
func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
 | 
			
		||||
	var call *Call
 | 
			
		||||
 | 
			
		||||
	msg.serial = conn.getSerial()
 | 
			
		||||
	if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 {
 | 
			
		||||
		if ch == nil {
 | 
			
		||||
			ch = make(chan *Call, 5)
 | 
			
		||||
		} else if cap(ch) == 0 {
 | 
			
		||||
			panic("dbus: unbuffered channel passed to (*Conn).Send")
 | 
			
		||||
		}
 | 
			
		||||
		call = new(Call)
 | 
			
		||||
		call.Destination, _ = msg.Headers[FieldDestination].value.(string)
 | 
			
		||||
		call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath)
 | 
			
		||||
		iface, _ := msg.Headers[FieldInterface].value.(string)
 | 
			
		||||
		member, _ := msg.Headers[FieldMember].value.(string)
 | 
			
		||||
		call.Method = iface + "." + member
 | 
			
		||||
		call.Args = msg.Body
 | 
			
		||||
		call.Done = ch
 | 
			
		||||
		conn.callsLck.Lock()
 | 
			
		||||
		conn.calls[msg.serial] = call
 | 
			
		||||
		conn.callsLck.Unlock()
 | 
			
		||||
		conn.outLck.RLock()
 | 
			
		||||
		if conn.closed {
 | 
			
		||||
			call.Err = ErrClosed
 | 
			
		||||
			call.Done <- call
 | 
			
		||||
		} else {
 | 
			
		||||
			conn.out <- msg
 | 
			
		||||
		}
 | 
			
		||||
		conn.outLck.RUnlock()
 | 
			
		||||
	} else {
 | 
			
		||||
		conn.outLck.RLock()
 | 
			
		||||
		if conn.closed {
 | 
			
		||||
			call = &Call{Err: ErrClosed}
 | 
			
		||||
		} else {
 | 
			
		||||
			conn.out <- msg
 | 
			
		||||
			call = &Call{Err: nil}
 | 
			
		||||
		}
 | 
			
		||||
		conn.outLck.RUnlock()
 | 
			
		||||
	}
 | 
			
		||||
	return call
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// sendError creates an error message corresponding to the parameters and sends
 | 
			
		||||
// it to conn.out.
 | 
			
		||||
func (conn *Conn) sendError(e Error, dest string, serial uint32) {
 | 
			
		||||
	msg := new(Message)
 | 
			
		||||
	msg.Type = TypeError
 | 
			
		||||
	msg.serial = conn.getSerial()
 | 
			
		||||
	msg.Headers = make(map[HeaderField]Variant)
 | 
			
		||||
	if dest != "" {
 | 
			
		||||
		msg.Headers[FieldDestination] = MakeVariant(dest)
 | 
			
		||||
	}
 | 
			
		||||
	msg.Headers[FieldErrorName] = MakeVariant(e.Name)
 | 
			
		||||
	msg.Headers[FieldReplySerial] = MakeVariant(serial)
 | 
			
		||||
	msg.Body = e.Body
 | 
			
		||||
	if len(e.Body) > 0 {
 | 
			
		||||
		msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...))
 | 
			
		||||
	}
 | 
			
		||||
	conn.outLck.RLock()
 | 
			
		||||
	if !conn.closed {
 | 
			
		||||
		conn.out <- msg
 | 
			
		||||
	}
 | 
			
		||||
	conn.outLck.RUnlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// sendReply creates a method reply message corresponding to the parameters and
 | 
			
		||||
// sends it to conn.out.
 | 
			
		||||
func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
 | 
			
		||||
	msg := new(Message)
 | 
			
		||||
	msg.Type = TypeMethodReply
 | 
			
		||||
	msg.serial = conn.getSerial()
 | 
			
		||||
	msg.Headers = make(map[HeaderField]Variant)
 | 
			
		||||
	if dest != "" {
 | 
			
		||||
		msg.Headers[FieldDestination] = MakeVariant(dest)
 | 
			
		||||
	}
 | 
			
		||||
	msg.Headers[FieldReplySerial] = MakeVariant(serial)
 | 
			
		||||
	msg.Body = values
 | 
			
		||||
	if len(values) > 0 {
 | 
			
		||||
		msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
 | 
			
		||||
	}
 | 
			
		||||
	conn.outLck.RLock()
 | 
			
		||||
	if !conn.closed {
 | 
			
		||||
		conn.out <- msg
 | 
			
		||||
	}
 | 
			
		||||
	conn.outLck.RUnlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Signal registers the given channel to be passed all received signal messages.
 | 
			
		||||
// The caller has to make sure that ch is sufficiently buffered; if a message
 | 
			
		||||
// arrives when a write to c is not possible, it is discarded.
 | 
			
		||||
//
 | 
			
		||||
// Multiple of these channels can be registered at the same time. Passing a
 | 
			
		||||
// channel that already is registered will remove it from the list of the
 | 
			
		||||
// registered channels.
 | 
			
		||||
//
 | 
			
		||||
// These channels are "overwritten" by Eavesdrop; i.e., if there currently is a
 | 
			
		||||
// channel for eavesdropped messages, this channel receives all signals, and
 | 
			
		||||
// none of the channels passed to Signal will receive any signals.
 | 
			
		||||
func (conn *Conn) Signal(ch chan<- *Signal) {
 | 
			
		||||
	conn.signalsLck.Lock()
 | 
			
		||||
	conn.signals = append(conn.signals, ch)
 | 
			
		||||
	conn.signalsLck.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SupportsUnixFDs returns whether the underlying transport supports passing of
 | 
			
		||||
// unix file descriptors. If this is false, method calls containing unix file
 | 
			
		||||
// descriptors will return an error and emitted signals containing them will
 | 
			
		||||
// not be sent.
 | 
			
		||||
func (conn *Conn) SupportsUnixFDs() bool {
 | 
			
		||||
	return conn.unixFD
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error represents a D-Bus message of type Error.
 | 
			
		||||
type Error struct {
 | 
			
		||||
	Name string
 | 
			
		||||
	Body []interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e Error) Error() string {
 | 
			
		||||
	if len(e.Body) >= 1 {
 | 
			
		||||
		s, ok := e.Body[0].(string)
 | 
			
		||||
		if ok {
 | 
			
		||||
			return s
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return e.Name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Signal represents a D-Bus message of type Signal. The name member is given in
 | 
			
		||||
// "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost.
 | 
			
		||||
type Signal struct {
 | 
			
		||||
	Sender string
 | 
			
		||||
	Path   ObjectPath
 | 
			
		||||
	Name   string
 | 
			
		||||
	Body   []interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// transport is a D-Bus transport.
 | 
			
		||||
type transport interface {
 | 
			
		||||
	// Read and Write raw data (for example, for the authentication protocol).
 | 
			
		||||
	io.ReadWriteCloser
 | 
			
		||||
 | 
			
		||||
	// Send the initial null byte used for the EXTERNAL mechanism.
 | 
			
		||||
	SendNullByte() error
 | 
			
		||||
 | 
			
		||||
	// Returns whether this transport supports passing Unix FDs.
 | 
			
		||||
	SupportsUnixFDs() bool
 | 
			
		||||
 | 
			
		||||
	// Signal the transport that Unix FD passing is enabled for this connection.
 | 
			
		||||
	EnableUnixFDs()
 | 
			
		||||
 | 
			
		||||
	// Read / send a message, handling things like Unix FDs.
 | 
			
		||||
	ReadMessage() (*Message, error)
 | 
			
		||||
	SendMessage(*Message) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getTransport(address string) (transport, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	var t transport
 | 
			
		||||
 | 
			
		||||
	m := map[string]func(string) (transport, error){
 | 
			
		||||
		"unix": newUnixTransport,
 | 
			
		||||
	}
 | 
			
		||||
	addresses := strings.Split(address, ";")
 | 
			
		||||
	for _, v := range addresses {
 | 
			
		||||
		i := strings.IndexRune(v, ':')
 | 
			
		||||
		if i == -1 {
 | 
			
		||||
			err = errors.New("dbus: invalid bus address (no transport)")
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		f := m[v[:i]]
 | 
			
		||||
		if f == nil {
 | 
			
		||||
			err = errors.New("dbus: invalid bus address (invalid or unsupported transport)")
 | 
			
		||||
		}
 | 
			
		||||
		t, err = f(v[i+1:])
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			return t, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// dereferenceAll returns a slice that, assuming that vs is a slice of pointers
 | 
			
		||||
// of arbitrary types, containes the values that are obtained from dereferencing
 | 
			
		||||
// all elements in vs.
 | 
			
		||||
func dereferenceAll(vs []interface{}) []interface{} {
 | 
			
		||||
	for i := range vs {
 | 
			
		||||
		v := reflect.ValueOf(vs[i])
 | 
			
		||||
		v = v.Elem()
 | 
			
		||||
		vs[i] = v.Interface()
 | 
			
		||||
	}
 | 
			
		||||
	return vs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getKey gets a key from a the list of keys. Returns "" on error / not found...
 | 
			
		||||
func getKey(s, key string) string {
 | 
			
		||||
	i := strings.Index(s, key)
 | 
			
		||||
	if i == -1 {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	if i+len(key)+1 >= len(s) || s[i+len(key)] != '=' {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	j := strings.Index(s, ",")
 | 
			
		||||
	if j == -1 {
 | 
			
		||||
		j = len(s)
 | 
			
		||||
	}
 | 
			
		||||
	return s[i+len(key)+1 : j]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/src/github.com/godbus/dbus/conn_darwin.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/src/github.com/godbus/dbus/conn_darwin.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func sessionBusPlatform() (*Conn, error) {
 | 
			
		||||
	cmd := exec.Command("launchctl", "getenv", "DBUS_LAUNCHD_SESSION_BUS_SOCKET")
 | 
			
		||||
	b, err := cmd.CombinedOutput()
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(b) == 0 {
 | 
			
		||||
		return nil, errors.New("dbus: couldn't determine address of session bus")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Dial("unix:path=" + string(b[:len(b)-1]))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/src/github.com/godbus/dbus/conn_other.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/src/github.com/godbus/dbus/conn_other.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
// +build !darwin
 | 
			
		||||
 | 
			
		||||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func sessionBusPlatform() (*Conn, error) {
 | 
			
		||||
	cmd := exec.Command("dbus-launch")
 | 
			
		||||
	b, err := cmd.CombinedOutput()
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i := bytes.IndexByte(b, '=')
 | 
			
		||||
	j := bytes.IndexByte(b, '\n')
 | 
			
		||||
 | 
			
		||||
	if i == -1 || j == -1 {
 | 
			
		||||
		return nil, errors.New("dbus: couldn't determine address of session bus")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Dial(string(b[i+1 : j]))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										199
									
								
								vendor/src/github.com/godbus/dbus/conn_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								vendor/src/github.com/godbus/dbus/conn_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,199 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import "testing"
 | 
			
		||||
 | 
			
		||||
func TestSessionBus(t *testing.T) {
 | 
			
		||||
	_, err := SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSystemBus(t *testing.T) {
 | 
			
		||||
	_, err := SystemBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSend(t *testing.T) {
 | 
			
		||||
	bus, err := SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
	ch := make(chan *Call, 1)
 | 
			
		||||
	msg := &Message{
 | 
			
		||||
		Type:  TypeMethodCall,
 | 
			
		||||
		Flags: 0,
 | 
			
		||||
		Headers: map[HeaderField]Variant{
 | 
			
		||||
			FieldDestination: MakeVariant(bus.Names()[0]),
 | 
			
		||||
			FieldPath:        MakeVariant(ObjectPath("/org/freedesktop/DBus")),
 | 
			
		||||
			FieldInterface:   MakeVariant("org.freedesktop.DBus.Peer"),
 | 
			
		||||
			FieldMember:      MakeVariant("Ping"),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	call := bus.Send(msg, ch)
 | 
			
		||||
	<-ch
 | 
			
		||||
	if call.Err != nil {
 | 
			
		||||
		t.Error(call.Err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type server struct{}
 | 
			
		||||
 | 
			
		||||
func (server) Double(i int64) (int64, *Error) {
 | 
			
		||||
	return 2 * i, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkCall(b *testing.B) {
 | 
			
		||||
	b.StopTimer()
 | 
			
		||||
	var s string
 | 
			
		||||
	bus, err := SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	name := bus.Names()[0]
 | 
			
		||||
	obj := bus.BusObject()
 | 
			
		||||
	b.StartTimer()
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		err := obj.Call("org.freedesktop.DBus.GetNameOwner", 0, name).Store(&s)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
		if s != name {
 | 
			
		||||
			b.Errorf("got %s, wanted %s", s, name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkCallAsync(b *testing.B) {
 | 
			
		||||
	b.StopTimer()
 | 
			
		||||
	bus, err := SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	name := bus.Names()[0]
 | 
			
		||||
	obj := bus.BusObject()
 | 
			
		||||
	c := make(chan *Call, 50)
 | 
			
		||||
	done := make(chan struct{})
 | 
			
		||||
	go func() {
 | 
			
		||||
		for i := 0; i < b.N; i++ {
 | 
			
		||||
			v := <-c
 | 
			
		||||
			if v.Err != nil {
 | 
			
		||||
				b.Error(v.Err)
 | 
			
		||||
			}
 | 
			
		||||
			s := v.Body[0].(string)
 | 
			
		||||
			if s != name {
 | 
			
		||||
				b.Errorf("got %s, wanted %s", s, name)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		close(done)
 | 
			
		||||
	}()
 | 
			
		||||
	b.StartTimer()
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		obj.Go("org.freedesktop.DBus.GetNameOwner", 0, c, name)
 | 
			
		||||
	}
 | 
			
		||||
	<-done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkServe(b *testing.B) {
 | 
			
		||||
	b.StopTimer()
 | 
			
		||||
	srv, err := SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	cli, err := SessionBusPrivate()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if err = cli.Auth(nil); err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if err = cli.Hello(); err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	benchmarkServe(b, srv, cli)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkServeAsync(b *testing.B) {
 | 
			
		||||
	b.StopTimer()
 | 
			
		||||
	srv, err := SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	cli, err := SessionBusPrivate()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if err = cli.Auth(nil); err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if err = cli.Hello(); err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	benchmarkServeAsync(b, srv, cli)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkServeSameConn(b *testing.B) {
 | 
			
		||||
	b.StopTimer()
 | 
			
		||||
	bus, err := SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	benchmarkServe(b, bus, bus)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkServeSameConnAsync(b *testing.B) {
 | 
			
		||||
	b.StopTimer()
 | 
			
		||||
	bus, err := SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	benchmarkServeAsync(b, bus, bus)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func benchmarkServe(b *testing.B, srv, cli *Conn) {
 | 
			
		||||
	var r int64
 | 
			
		||||
	var err error
 | 
			
		||||
	dest := srv.Names()[0]
 | 
			
		||||
	srv.Export(server{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
 | 
			
		||||
	obj := cli.Object(dest, "/org/guelfey/DBus/Test")
 | 
			
		||||
	b.StartTimer()
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		err = obj.Call("org.guelfey.DBus.Test.Double", 0, int64(i)).Store(&r)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
		if r != 2*int64(i) {
 | 
			
		||||
			b.Errorf("got %d, wanted %d", r, 2*int64(i))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func benchmarkServeAsync(b *testing.B, srv, cli *Conn) {
 | 
			
		||||
	dest := srv.Names()[0]
 | 
			
		||||
	srv.Export(server{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test")
 | 
			
		||||
	obj := cli.Object(dest, "/org/guelfey/DBus/Test")
 | 
			
		||||
	c := make(chan *Call, 50)
 | 
			
		||||
	done := make(chan struct{})
 | 
			
		||||
	go func() {
 | 
			
		||||
		for i := 0; i < b.N; i++ {
 | 
			
		||||
			v := <-c
 | 
			
		||||
			if v.Err != nil {
 | 
			
		||||
				b.Fatal(v.Err)
 | 
			
		||||
			}
 | 
			
		||||
			i, r := v.Args[0].(int64), v.Body[0].(int64)
 | 
			
		||||
			if 2*i != r {
 | 
			
		||||
				b.Errorf("got %d, wanted %d", r, 2*i)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		close(done)
 | 
			
		||||
	}()
 | 
			
		||||
	b.StartTimer()
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		obj.Go("org.guelfey.DBus.Test.Double", 0, c, int64(i))
 | 
			
		||||
	}
 | 
			
		||||
	<-done
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										258
									
								
								vendor/src/github.com/godbus/dbus/dbus.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								vendor/src/github.com/godbus/dbus/dbus.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,258 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	byteType        = reflect.TypeOf(byte(0))
 | 
			
		||||
	boolType        = reflect.TypeOf(false)
 | 
			
		||||
	uint8Type       = reflect.TypeOf(uint8(0))
 | 
			
		||||
	int16Type       = reflect.TypeOf(int16(0))
 | 
			
		||||
	uint16Type      = reflect.TypeOf(uint16(0))
 | 
			
		||||
	int32Type       = reflect.TypeOf(int32(0))
 | 
			
		||||
	uint32Type      = reflect.TypeOf(uint32(0))
 | 
			
		||||
	int64Type       = reflect.TypeOf(int64(0))
 | 
			
		||||
	uint64Type      = reflect.TypeOf(uint64(0))
 | 
			
		||||
	float64Type     = reflect.TypeOf(float64(0))
 | 
			
		||||
	stringType      = reflect.TypeOf("")
 | 
			
		||||
	signatureType   = reflect.TypeOf(Signature{""})
 | 
			
		||||
	objectPathType  = reflect.TypeOf(ObjectPath(""))
 | 
			
		||||
	variantType     = reflect.TypeOf(Variant{Signature{""}, nil})
 | 
			
		||||
	interfacesType  = reflect.TypeOf([]interface{}{})
 | 
			
		||||
	unixFDType      = reflect.TypeOf(UnixFD(0))
 | 
			
		||||
	unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// An InvalidTypeError signals that a value which cannot be represented in the
 | 
			
		||||
// D-Bus wire format was passed to a function.
 | 
			
		||||
type InvalidTypeError struct {
 | 
			
		||||
	Type reflect.Type
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e InvalidTypeError) Error() string {
 | 
			
		||||
	return "dbus: invalid type " + e.Type.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Store copies the values contained in src to dest, which must be a slice of
 | 
			
		||||
// pointers. It converts slices of interfaces from src to corresponding structs
 | 
			
		||||
// in dest. An error is returned if the lengths of src and dest or the types of
 | 
			
		||||
// their elements don't match.
 | 
			
		||||
func Store(src []interface{}, dest ...interface{}) error {
 | 
			
		||||
	if len(src) != len(dest) {
 | 
			
		||||
		return errors.New("dbus.Store: length mismatch")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := range src {
 | 
			
		||||
		if err := store(src[i], dest[i]); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func store(src, dest interface{}) error {
 | 
			
		||||
	if reflect.TypeOf(dest).Elem() == reflect.TypeOf(src) {
 | 
			
		||||
		reflect.ValueOf(dest).Elem().Set(reflect.ValueOf(src))
 | 
			
		||||
		return nil
 | 
			
		||||
	} else if hasStruct(dest) {
 | 
			
		||||
		rv := reflect.ValueOf(dest).Elem()
 | 
			
		||||
		switch rv.Kind() {
 | 
			
		||||
		case reflect.Struct:
 | 
			
		||||
			vs, ok := src.([]interface{})
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return errors.New("dbus.Store: type mismatch")
 | 
			
		||||
			}
 | 
			
		||||
			t := rv.Type()
 | 
			
		||||
			ndest := make([]interface{}, 0, rv.NumField())
 | 
			
		||||
			for i := 0; i < rv.NumField(); i++ {
 | 
			
		||||
				field := t.Field(i)
 | 
			
		||||
				if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
 | 
			
		||||
					ndest = append(ndest, rv.Field(i).Addr().Interface())
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if len(vs) != len(ndest) {
 | 
			
		||||
				return errors.New("dbus.Store: type mismatch")
 | 
			
		||||
			}
 | 
			
		||||
			err := Store(vs, ndest...)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.New("dbus.Store: type mismatch")
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Slice:
 | 
			
		||||
			sv := reflect.ValueOf(src)
 | 
			
		||||
			if sv.Kind() != reflect.Slice {
 | 
			
		||||
				return errors.New("dbus.Store: type mismatch")
 | 
			
		||||
			}
 | 
			
		||||
			rv.Set(reflect.MakeSlice(rv.Type(), sv.Len(), sv.Len()))
 | 
			
		||||
			for i := 0; i < sv.Len(); i++ {
 | 
			
		||||
				if err := store(sv.Index(i).Interface(), rv.Index(i).Addr().Interface()); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Map:
 | 
			
		||||
			sv := reflect.ValueOf(src)
 | 
			
		||||
			if sv.Kind() != reflect.Map {
 | 
			
		||||
				return errors.New("dbus.Store: type mismatch")
 | 
			
		||||
			}
 | 
			
		||||
			keys := sv.MapKeys()
 | 
			
		||||
			rv.Set(reflect.MakeMap(sv.Type()))
 | 
			
		||||
			for _, key := range keys {
 | 
			
		||||
				v := reflect.New(sv.Type().Elem())
 | 
			
		||||
				if err := store(v, sv.MapIndex(key).Interface()); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				rv.SetMapIndex(key, v.Elem())
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			return errors.New("dbus.Store: type mismatch")
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	} else {
 | 
			
		||||
		return errors.New("dbus.Store: type mismatch")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasStruct(v interface{}) bool {
 | 
			
		||||
	t := reflect.TypeOf(v)
 | 
			
		||||
	for {
 | 
			
		||||
		switch t.Kind() {
 | 
			
		||||
		case reflect.Struct:
 | 
			
		||||
			return true
 | 
			
		||||
		case reflect.Slice, reflect.Ptr, reflect.Map:
 | 
			
		||||
			t = t.Elem()
 | 
			
		||||
		default:
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An ObjectPath is an object path as defined by the D-Bus spec.
 | 
			
		||||
type ObjectPath string
 | 
			
		||||
 | 
			
		||||
// IsValid returns whether the object path is valid.
 | 
			
		||||
func (o ObjectPath) IsValid() bool {
 | 
			
		||||
	s := string(o)
 | 
			
		||||
	if len(s) == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if s[0] != '/' {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if s[len(s)-1] == '/' && len(s) != 1 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	// probably not used, but technically possible
 | 
			
		||||
	if s == "/" {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	split := strings.Split(s[1:], "/")
 | 
			
		||||
	for _, v := range split {
 | 
			
		||||
		if len(v) == 0 {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		for _, c := range v {
 | 
			
		||||
			if !isMemberChar(c) {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A UnixFD is a Unix file descriptor sent over the wire. See the package-level
 | 
			
		||||
// documentation for more information about Unix file descriptor passsing.
 | 
			
		||||
type UnixFD int32
 | 
			
		||||
 | 
			
		||||
// A UnixFDIndex is the representation of a Unix file descriptor in a message.
 | 
			
		||||
type UnixFDIndex uint32
 | 
			
		||||
 | 
			
		||||
// alignment returns the alignment of values of type t.
 | 
			
		||||
func alignment(t reflect.Type) int {
 | 
			
		||||
	switch t {
 | 
			
		||||
	case variantType:
 | 
			
		||||
		return 1
 | 
			
		||||
	case objectPathType:
 | 
			
		||||
		return 4
 | 
			
		||||
	case signatureType:
 | 
			
		||||
		return 1
 | 
			
		||||
	case interfacesType: // sometimes used for structs
 | 
			
		||||
		return 8
 | 
			
		||||
	}
 | 
			
		||||
	switch t.Kind() {
 | 
			
		||||
	case reflect.Uint8:
 | 
			
		||||
		return 1
 | 
			
		||||
	case reflect.Uint16, reflect.Int16:
 | 
			
		||||
		return 2
 | 
			
		||||
	case reflect.Uint32, reflect.Int32, reflect.String, reflect.Array, reflect.Slice, reflect.Map:
 | 
			
		||||
		return 4
 | 
			
		||||
	case reflect.Uint64, reflect.Int64, reflect.Float64, reflect.Struct:
 | 
			
		||||
		return 8
 | 
			
		||||
	case reflect.Ptr:
 | 
			
		||||
		return alignment(t.Elem())
 | 
			
		||||
	}
 | 
			
		||||
	return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isKeyType returns whether t is a valid type for a D-Bus dict.
 | 
			
		||||
func isKeyType(t reflect.Type) bool {
 | 
			
		||||
	switch t.Kind() {
 | 
			
		||||
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
 | 
			
		||||
		reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float64,
 | 
			
		||||
		reflect.String:
 | 
			
		||||
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isValidInterface returns whether s is a valid name for an interface.
 | 
			
		||||
func isValidInterface(s string) bool {
 | 
			
		||||
	if len(s) == 0 || len(s) > 255 || s[0] == '.' {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	elem := strings.Split(s, ".")
 | 
			
		||||
	if len(elem) < 2 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for _, v := range elem {
 | 
			
		||||
		if len(v) == 0 {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		if v[0] >= '0' && v[0] <= '9' {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		for _, c := range v {
 | 
			
		||||
			if !isMemberChar(c) {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isValidMember returns whether s is a valid name for a member.
 | 
			
		||||
func isValidMember(s string) bool {
 | 
			
		||||
	if len(s) == 0 || len(s) > 255 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	i := strings.Index(s, ".")
 | 
			
		||||
	if i != -1 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if s[0] >= '0' && s[0] <= '9' {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for _, c := range s {
 | 
			
		||||
		if !isMemberChar(c) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isMemberChar(c rune) bool {
 | 
			
		||||
	return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
 | 
			
		||||
		(c >= 'a' && c <= 'z') || c == '_'
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										228
									
								
								vendor/src/github.com/godbus/dbus/decoder.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								vendor/src/github.com/godbus/dbus/decoder.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,228 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"io"
 | 
			
		||||
	"reflect"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type decoder struct {
 | 
			
		||||
	in    io.Reader
 | 
			
		||||
	order binary.ByteOrder
 | 
			
		||||
	pos   int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newDecoder returns a new decoder that reads values from in. The input is
 | 
			
		||||
// expected to be in the given byte order.
 | 
			
		||||
func newDecoder(in io.Reader, order binary.ByteOrder) *decoder {
 | 
			
		||||
	dec := new(decoder)
 | 
			
		||||
	dec.in = in
 | 
			
		||||
	dec.order = order
 | 
			
		||||
	return dec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// align aligns the input to the given boundary and panics on error.
 | 
			
		||||
func (dec *decoder) align(n int) {
 | 
			
		||||
	if dec.pos%n != 0 {
 | 
			
		||||
		newpos := (dec.pos + n - 1) & ^(n - 1)
 | 
			
		||||
		empty := make([]byte, newpos-dec.pos)
 | 
			
		||||
		if _, err := io.ReadFull(dec.in, empty); err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		dec.pos = newpos
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Calls binary.Read(dec.in, dec.order, v) and panics on read errors.
 | 
			
		||||
func (dec *decoder) binread(v interface{}) {
 | 
			
		||||
	if err := binary.Read(dec.in, dec.order, v); err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		var ok bool
 | 
			
		||||
		v := recover()
 | 
			
		||||
		if err, ok = v.(error); ok {
 | 
			
		||||
			if err == io.EOF || err == io.ErrUnexpectedEOF {
 | 
			
		||||
				err = FormatError("unexpected EOF")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	vs = make([]interface{}, 0)
 | 
			
		||||
	s := sig.str
 | 
			
		||||
	for s != "" {
 | 
			
		||||
		err, rem := validSingle(s, 0)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		v := dec.decode(s[:len(s)-len(rem)], 0)
 | 
			
		||||
		vs = append(vs, v)
 | 
			
		||||
		s = rem
 | 
			
		||||
	}
 | 
			
		||||
	return vs, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (dec *decoder) decode(s string, depth int) interface{} {
 | 
			
		||||
	dec.align(alignment(typeFor(s)))
 | 
			
		||||
	switch s[0] {
 | 
			
		||||
	case 'y':
 | 
			
		||||
		var b [1]byte
 | 
			
		||||
		if _, err := dec.in.Read(b[:]); err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		dec.pos++
 | 
			
		||||
		return b[0]
 | 
			
		||||
	case 'b':
 | 
			
		||||
		i := dec.decode("u", depth).(uint32)
 | 
			
		||||
		switch {
 | 
			
		||||
		case i == 0:
 | 
			
		||||
			return false
 | 
			
		||||
		case i == 1:
 | 
			
		||||
			return true
 | 
			
		||||
		default:
 | 
			
		||||
			panic(FormatError("invalid value for boolean"))
 | 
			
		||||
		}
 | 
			
		||||
	case 'n':
 | 
			
		||||
		var i int16
 | 
			
		||||
		dec.binread(&i)
 | 
			
		||||
		dec.pos += 2
 | 
			
		||||
		return i
 | 
			
		||||
	case 'i':
 | 
			
		||||
		var i int32
 | 
			
		||||
		dec.binread(&i)
 | 
			
		||||
		dec.pos += 4
 | 
			
		||||
		return i
 | 
			
		||||
	case 'x':
 | 
			
		||||
		var i int64
 | 
			
		||||
		dec.binread(&i)
 | 
			
		||||
		dec.pos += 8
 | 
			
		||||
		return i
 | 
			
		||||
	case 'q':
 | 
			
		||||
		var i uint16
 | 
			
		||||
		dec.binread(&i)
 | 
			
		||||
		dec.pos += 2
 | 
			
		||||
		return i
 | 
			
		||||
	case 'u':
 | 
			
		||||
		var i uint32
 | 
			
		||||
		dec.binread(&i)
 | 
			
		||||
		dec.pos += 4
 | 
			
		||||
		return i
 | 
			
		||||
	case 't':
 | 
			
		||||
		var i uint64
 | 
			
		||||
		dec.binread(&i)
 | 
			
		||||
		dec.pos += 8
 | 
			
		||||
		return i
 | 
			
		||||
	case 'd':
 | 
			
		||||
		var f float64
 | 
			
		||||
		dec.binread(&f)
 | 
			
		||||
		dec.pos += 8
 | 
			
		||||
		return f
 | 
			
		||||
	case 's':
 | 
			
		||||
		length := dec.decode("u", depth).(uint32)
 | 
			
		||||
		b := make([]byte, int(length)+1)
 | 
			
		||||
		if _, err := io.ReadFull(dec.in, b); err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		dec.pos += int(length) + 1
 | 
			
		||||
		return string(b[:len(b)-1])
 | 
			
		||||
	case 'o':
 | 
			
		||||
		return ObjectPath(dec.decode("s", depth).(string))
 | 
			
		||||
	case 'g':
 | 
			
		||||
		length := dec.decode("y", depth).(byte)
 | 
			
		||||
		b := make([]byte, int(length)+1)
 | 
			
		||||
		if _, err := io.ReadFull(dec.in, b); err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		dec.pos += int(length) + 1
 | 
			
		||||
		sig, err := ParseSignature(string(b[:len(b)-1]))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		return sig
 | 
			
		||||
	case 'v':
 | 
			
		||||
		if depth >= 64 {
 | 
			
		||||
			panic(FormatError("input exceeds container depth limit"))
 | 
			
		||||
		}
 | 
			
		||||
		var variant Variant
 | 
			
		||||
		sig := dec.decode("g", depth).(Signature)
 | 
			
		||||
		if len(sig.str) == 0 {
 | 
			
		||||
			panic(FormatError("variant signature is empty"))
 | 
			
		||||
		}
 | 
			
		||||
		err, rem := validSingle(sig.str, 0)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		if rem != "" {
 | 
			
		||||
			panic(FormatError("variant signature has multiple types"))
 | 
			
		||||
		}
 | 
			
		||||
		variant.sig = sig
 | 
			
		||||
		variant.value = dec.decode(sig.str, depth+1)
 | 
			
		||||
		return variant
 | 
			
		||||
	case 'h':
 | 
			
		||||
		return UnixFDIndex(dec.decode("u", depth).(uint32))
 | 
			
		||||
	case 'a':
 | 
			
		||||
		if len(s) > 1 && s[1] == '{' {
 | 
			
		||||
			ksig := s[2:3]
 | 
			
		||||
			vsig := s[3 : len(s)-1]
 | 
			
		||||
			v := reflect.MakeMap(reflect.MapOf(typeFor(ksig), typeFor(vsig)))
 | 
			
		||||
			if depth >= 63 {
 | 
			
		||||
				panic(FormatError("input exceeds container depth limit"))
 | 
			
		||||
			}
 | 
			
		||||
			length := dec.decode("u", depth).(uint32)
 | 
			
		||||
			// Even for empty maps, the correct padding must be included
 | 
			
		||||
			dec.align(8)
 | 
			
		||||
			spos := dec.pos
 | 
			
		||||
			for dec.pos < spos+int(length) {
 | 
			
		||||
				dec.align(8)
 | 
			
		||||
				if !isKeyType(v.Type().Key()) {
 | 
			
		||||
					panic(InvalidTypeError{v.Type()})
 | 
			
		||||
				}
 | 
			
		||||
				kv := dec.decode(ksig, depth+2)
 | 
			
		||||
				vv := dec.decode(vsig, depth+2)
 | 
			
		||||
				v.SetMapIndex(reflect.ValueOf(kv), reflect.ValueOf(vv))
 | 
			
		||||
			}
 | 
			
		||||
			return v.Interface()
 | 
			
		||||
		}
 | 
			
		||||
		if depth >= 64 {
 | 
			
		||||
			panic(FormatError("input exceeds container depth limit"))
 | 
			
		||||
		}
 | 
			
		||||
		length := dec.decode("u", depth).(uint32)
 | 
			
		||||
		v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length))
 | 
			
		||||
		// Even for empty arrays, the correct padding must be included
 | 
			
		||||
		dec.align(alignment(typeFor(s[1:])))
 | 
			
		||||
		spos := dec.pos
 | 
			
		||||
		for dec.pos < spos+int(length) {
 | 
			
		||||
			ev := dec.decode(s[1:], depth+1)
 | 
			
		||||
			v = reflect.Append(v, reflect.ValueOf(ev))
 | 
			
		||||
		}
 | 
			
		||||
		return v.Interface()
 | 
			
		||||
	case '(':
 | 
			
		||||
		if depth >= 64 {
 | 
			
		||||
			panic(FormatError("input exceeds container depth limit"))
 | 
			
		||||
		}
 | 
			
		||||
		dec.align(8)
 | 
			
		||||
		v := make([]interface{}, 0)
 | 
			
		||||
		s = s[1 : len(s)-1]
 | 
			
		||||
		for s != "" {
 | 
			
		||||
			err, rem := validSingle(s, 0)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				panic(err)
 | 
			
		||||
			}
 | 
			
		||||
			ev := dec.decode(s[:len(s)-len(rem)], depth+1)
 | 
			
		||||
			v = append(v, ev)
 | 
			
		||||
			s = rem
 | 
			
		||||
		}
 | 
			
		||||
		return v
 | 
			
		||||
	default:
 | 
			
		||||
		panic(SignatureError{Sig: s})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A FormatError is an error in the wire format.
 | 
			
		||||
type FormatError string
 | 
			
		||||
 | 
			
		||||
func (e FormatError) Error() string {
 | 
			
		||||
	return "dbus: wire format error: " + string(e)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								vendor/src/github.com/godbus/dbus/doc.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								vendor/src/github.com/godbus/dbus/doc.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
/*
 | 
			
		||||
Package dbus implements bindings to the D-Bus message bus system.
 | 
			
		||||
 | 
			
		||||
To use the message bus API, you first need to connect to a bus (usually the
 | 
			
		||||
session or system bus). The acquired connection then can be used to call methods
 | 
			
		||||
on remote objects and emit or receive signals. Using the Export method, you can
 | 
			
		||||
arrange D-Bus methods calls to be directly translated to method calls on a Go
 | 
			
		||||
value.
 | 
			
		||||
 | 
			
		||||
Conversion Rules
 | 
			
		||||
 | 
			
		||||
For outgoing messages, Go types are automatically converted to the
 | 
			
		||||
corresponding D-Bus types. The following types are directly encoded as their
 | 
			
		||||
respective D-Bus equivalents:
 | 
			
		||||
 | 
			
		||||
     Go type     | D-Bus type
 | 
			
		||||
     ------------+-----------
 | 
			
		||||
     byte        | BYTE
 | 
			
		||||
     bool        | BOOLEAN
 | 
			
		||||
     int16       | INT16
 | 
			
		||||
     uint16      | UINT16
 | 
			
		||||
     int32       | INT32
 | 
			
		||||
     uint32      | UINT32
 | 
			
		||||
     int64       | INT64
 | 
			
		||||
     uint64      | UINT64
 | 
			
		||||
     float64     | DOUBLE
 | 
			
		||||
     string      | STRING
 | 
			
		||||
     ObjectPath  | OBJECT_PATH
 | 
			
		||||
     Signature   | SIGNATURE
 | 
			
		||||
     Variant     | VARIANT
 | 
			
		||||
     UnixFDIndex | UNIX_FD
 | 
			
		||||
 | 
			
		||||
Slices and arrays encode as ARRAYs of their element type.
 | 
			
		||||
 | 
			
		||||
Maps encode as DICTs, provided that their key type can be used as a key for
 | 
			
		||||
a DICT.
 | 
			
		||||
 | 
			
		||||
Structs other than Variant and Signature encode as a STRUCT containing their
 | 
			
		||||
exported fields. Fields whose tags contain `dbus:"-"` and unexported fields will
 | 
			
		||||
be skipped.
 | 
			
		||||
 | 
			
		||||
Pointers encode as the value they're pointed to.
 | 
			
		||||
 | 
			
		||||
Trying to encode any other type or a slice, map or struct containing an
 | 
			
		||||
unsupported type will result in an InvalidTypeError.
 | 
			
		||||
 | 
			
		||||
For incoming messages, the inverse of these rules are used, with the exception
 | 
			
		||||
of STRUCTs. Incoming STRUCTS are represented as a slice of empty interfaces
 | 
			
		||||
containing the struct fields in the correct order. The Store function can be
 | 
			
		||||
used to convert such values to Go structs.
 | 
			
		||||
 | 
			
		||||
Unix FD passing
 | 
			
		||||
 | 
			
		||||
Handling Unix file descriptors deserves special mention. To use them, you should
 | 
			
		||||
first check that they are supported on a connection by calling SupportsUnixFDs.
 | 
			
		||||
If it returns true, all method of Connection will translate messages containing
 | 
			
		||||
UnixFD's to messages that are accompanied by the given file descriptors with the
 | 
			
		||||
UnixFD values being substituted by the correct indices. Similarily, the indices
 | 
			
		||||
of incoming messages are automatically resolved. It shouldn't be necessary to use
 | 
			
		||||
UnixFDIndex.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
package dbus
 | 
			
		||||
							
								
								
									
										179
									
								
								vendor/src/github.com/godbus/dbus/encoder.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								vendor/src/github.com/godbus/dbus/encoder.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,179 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"io"
 | 
			
		||||
	"reflect"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// An encoder encodes values to the D-Bus wire format.
 | 
			
		||||
type encoder struct {
 | 
			
		||||
	out   io.Writer
 | 
			
		||||
	order binary.ByteOrder
 | 
			
		||||
	pos   int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewEncoder returns a new encoder that writes to out in the given byte order.
 | 
			
		||||
func newEncoder(out io.Writer, order binary.ByteOrder) *encoder {
 | 
			
		||||
	enc := new(encoder)
 | 
			
		||||
	enc.out = out
 | 
			
		||||
	enc.order = order
 | 
			
		||||
	return enc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Aligns the next output to be on a multiple of n. Panics on write errors.
 | 
			
		||||
func (enc *encoder) align(n int) {
 | 
			
		||||
	if enc.pos%n != 0 {
 | 
			
		||||
		newpos := (enc.pos + n - 1) & ^(n - 1)
 | 
			
		||||
		empty := make([]byte, newpos-enc.pos)
 | 
			
		||||
		if _, err := enc.out.Write(empty); err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		enc.pos = newpos
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Calls binary.Write(enc.out, enc.order, v) and panics on write errors.
 | 
			
		||||
func (enc *encoder) binwrite(v interface{}) {
 | 
			
		||||
	if err := binary.Write(enc.out, enc.order, v); err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Encode encodes the given values to the underyling reader. All written values
 | 
			
		||||
// are aligned properly as required by the D-Bus spec.
 | 
			
		||||
func (enc *encoder) Encode(vs ...interface{}) (err error) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		err, _ = recover().(error)
 | 
			
		||||
	}()
 | 
			
		||||
	for _, v := range vs {
 | 
			
		||||
		enc.encode(reflect.ValueOf(v), 0)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// encode encodes the given value to the writer and panics on error. depth holds
 | 
			
		||||
// the depth of the container nesting.
 | 
			
		||||
func (enc *encoder) encode(v reflect.Value, depth int) {
 | 
			
		||||
	enc.align(alignment(v.Type()))
 | 
			
		||||
	switch v.Kind() {
 | 
			
		||||
	case reflect.Uint8:
 | 
			
		||||
		var b [1]byte
 | 
			
		||||
		b[0] = byte(v.Uint())
 | 
			
		||||
		if _, err := enc.out.Write(b[:]); err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		enc.pos++
 | 
			
		||||
	case reflect.Bool:
 | 
			
		||||
		if v.Bool() {
 | 
			
		||||
			enc.encode(reflect.ValueOf(uint32(1)), depth)
 | 
			
		||||
		} else {
 | 
			
		||||
			enc.encode(reflect.ValueOf(uint32(0)), depth)
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Int16:
 | 
			
		||||
		enc.binwrite(int16(v.Int()))
 | 
			
		||||
		enc.pos += 2
 | 
			
		||||
	case reflect.Uint16:
 | 
			
		||||
		enc.binwrite(uint16(v.Uint()))
 | 
			
		||||
		enc.pos += 2
 | 
			
		||||
	case reflect.Int32:
 | 
			
		||||
		enc.binwrite(int32(v.Int()))
 | 
			
		||||
		enc.pos += 4
 | 
			
		||||
	case reflect.Uint32:
 | 
			
		||||
		enc.binwrite(uint32(v.Uint()))
 | 
			
		||||
		enc.pos += 4
 | 
			
		||||
	case reflect.Int64:
 | 
			
		||||
		enc.binwrite(v.Int())
 | 
			
		||||
		enc.pos += 8
 | 
			
		||||
	case reflect.Uint64:
 | 
			
		||||
		enc.binwrite(v.Uint())
 | 
			
		||||
		enc.pos += 8
 | 
			
		||||
	case reflect.Float64:
 | 
			
		||||
		enc.binwrite(v.Float())
 | 
			
		||||
		enc.pos += 8
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		enc.encode(reflect.ValueOf(uint32(len(v.String()))), depth)
 | 
			
		||||
		b := make([]byte, v.Len()+1)
 | 
			
		||||
		copy(b, v.String())
 | 
			
		||||
		b[len(b)-1] = 0
 | 
			
		||||
		n, err := enc.out.Write(b)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		enc.pos += n
 | 
			
		||||
	case reflect.Ptr:
 | 
			
		||||
		enc.encode(v.Elem(), depth)
 | 
			
		||||
	case reflect.Slice, reflect.Array:
 | 
			
		||||
		if depth >= 64 {
 | 
			
		||||
			panic(FormatError("input exceeds container depth limit"))
 | 
			
		||||
		}
 | 
			
		||||
		var buf bytes.Buffer
 | 
			
		||||
		bufenc := newEncoder(&buf, enc.order)
 | 
			
		||||
 | 
			
		||||
		for i := 0; i < v.Len(); i++ {
 | 
			
		||||
			bufenc.encode(v.Index(i), depth+1)
 | 
			
		||||
		}
 | 
			
		||||
		enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
 | 
			
		||||
		length := buf.Len()
 | 
			
		||||
		enc.align(alignment(v.Type().Elem()))
 | 
			
		||||
		if _, err := buf.WriteTo(enc.out); err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		enc.pos += length
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		if depth >= 64 && v.Type() != signatureType {
 | 
			
		||||
			panic(FormatError("input exceeds container depth limit"))
 | 
			
		||||
		}
 | 
			
		||||
		switch t := v.Type(); t {
 | 
			
		||||
		case signatureType:
 | 
			
		||||
			str := v.Field(0)
 | 
			
		||||
			enc.encode(reflect.ValueOf(byte(str.Len())), depth+1)
 | 
			
		||||
			b := make([]byte, str.Len()+1)
 | 
			
		||||
			copy(b, str.String())
 | 
			
		||||
			b[len(b)-1] = 0
 | 
			
		||||
			n, err := enc.out.Write(b)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				panic(err)
 | 
			
		||||
			}
 | 
			
		||||
			enc.pos += n
 | 
			
		||||
		case variantType:
 | 
			
		||||
			variant := v.Interface().(Variant)
 | 
			
		||||
			enc.encode(reflect.ValueOf(variant.sig), depth+1)
 | 
			
		||||
			enc.encode(reflect.ValueOf(variant.value), depth+1)
 | 
			
		||||
		default:
 | 
			
		||||
			for i := 0; i < v.Type().NumField(); i++ {
 | 
			
		||||
				field := t.Field(i)
 | 
			
		||||
				if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
 | 
			
		||||
					enc.encode(v.Field(i), depth+1)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Map:
 | 
			
		||||
		// Maps are arrays of structures, so they actually increase the depth by
 | 
			
		||||
		// 2.
 | 
			
		||||
		if depth >= 63 {
 | 
			
		||||
			panic(FormatError("input exceeds container depth limit"))
 | 
			
		||||
		}
 | 
			
		||||
		if !isKeyType(v.Type().Key()) {
 | 
			
		||||
			panic(InvalidTypeError{v.Type()})
 | 
			
		||||
		}
 | 
			
		||||
		keys := v.MapKeys()
 | 
			
		||||
		var buf bytes.Buffer
 | 
			
		||||
		bufenc := newEncoder(&buf, enc.order)
 | 
			
		||||
		for _, k := range keys {
 | 
			
		||||
			bufenc.align(8)
 | 
			
		||||
			bufenc.encode(k, depth+2)
 | 
			
		||||
			bufenc.encode(v.MapIndex(k), depth+2)
 | 
			
		||||
		}
 | 
			
		||||
		enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
 | 
			
		||||
		length := buf.Len()
 | 
			
		||||
		enc.align(8)
 | 
			
		||||
		if _, err := buf.WriteTo(enc.out); err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		enc.pos += length
 | 
			
		||||
	default:
 | 
			
		||||
		panic(InvalidTypeError{v.Type()})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								vendor/src/github.com/godbus/dbus/examples_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								vendor/src/github.com/godbus/dbus/examples_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import "fmt"
 | 
			
		||||
 | 
			
		||||
func ExampleConn_Emit() {
 | 
			
		||||
	conn, err := SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn.Emit("/foo/bar", "foo.bar.Baz", uint32(0xDAEDBEEF))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ExampleObject_Call() {
 | 
			
		||||
	var list []string
 | 
			
		||||
 | 
			
		||||
	conn, err := SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&list)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	for _, v := range list {
 | 
			
		||||
		fmt.Println(v)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ExampleObject_Go() {
 | 
			
		||||
	conn, err := SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ch := make(chan *Call, 10)
 | 
			
		||||
	conn.BusObject().Go("org.freedesktop.DBus.ListActivatableNames", 0, ch)
 | 
			
		||||
	select {
 | 
			
		||||
	case call := <-ch:
 | 
			
		||||
		if call.Err != nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		list := call.Body[0].([]string)
 | 
			
		||||
		for _, v := range list {
 | 
			
		||||
			fmt.Println(v)
 | 
			
		||||
		}
 | 
			
		||||
		// put some other cases here
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										302
									
								
								vendor/src/github.com/godbus/dbus/export.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								vendor/src/github.com/godbus/dbus/export.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,302 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	errmsgInvalidArg = Error{
 | 
			
		||||
		"org.freedesktop.DBus.Error.InvalidArgs",
 | 
			
		||||
		[]interface{}{"Invalid type / number of args"},
 | 
			
		||||
	}
 | 
			
		||||
	errmsgNoObject = Error{
 | 
			
		||||
		"org.freedesktop.DBus.Error.NoSuchObject",
 | 
			
		||||
		[]interface{}{"No such object"},
 | 
			
		||||
	}
 | 
			
		||||
	errmsgUnknownMethod = Error{
 | 
			
		||||
		"org.freedesktop.DBus.Error.UnknownMethod",
 | 
			
		||||
		[]interface{}{"Unknown / invalid method"},
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Sender is a type which can be used in exported methods to receive the message
 | 
			
		||||
// sender.
 | 
			
		||||
type Sender string
 | 
			
		||||
 | 
			
		||||
func exportedMethod(v interface{}, name string) reflect.Value {
 | 
			
		||||
	if v == nil {
 | 
			
		||||
		return reflect.Value{}
 | 
			
		||||
	}
 | 
			
		||||
	m := reflect.ValueOf(v).MethodByName(name)
 | 
			
		||||
	if !m.IsValid() {
 | 
			
		||||
		return reflect.Value{}
 | 
			
		||||
	}
 | 
			
		||||
	t := m.Type()
 | 
			
		||||
	if t.NumOut() == 0 ||
 | 
			
		||||
		t.Out(t.NumOut()-1) != reflect.TypeOf(&errmsgInvalidArg) {
 | 
			
		||||
 | 
			
		||||
		return reflect.Value{}
 | 
			
		||||
	}
 | 
			
		||||
	return m
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// handleCall handles the given method call (i.e. looks if it's one of the
 | 
			
		||||
// pre-implemented ones and searches for a corresponding handler if not).
 | 
			
		||||
func (conn *Conn) handleCall(msg *Message) {
 | 
			
		||||
	name := msg.Headers[FieldMember].value.(string)
 | 
			
		||||
	path := msg.Headers[FieldPath].value.(ObjectPath)
 | 
			
		||||
	ifaceName, hasIface := msg.Headers[FieldInterface].value.(string)
 | 
			
		||||
	sender, hasSender := msg.Headers[FieldSender].value.(string)
 | 
			
		||||
	serial := msg.serial
 | 
			
		||||
	if ifaceName == "org.freedesktop.DBus.Peer" {
 | 
			
		||||
		switch name {
 | 
			
		||||
		case "Ping":
 | 
			
		||||
			conn.sendReply(sender, serial)
 | 
			
		||||
		case "GetMachineId":
 | 
			
		||||
			conn.sendReply(sender, serial, conn.uuid)
 | 
			
		||||
		default:
 | 
			
		||||
			conn.sendError(errmsgUnknownMethod, sender, serial)
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if len(name) == 0 || unicode.IsLower([]rune(name)[0]) {
 | 
			
		||||
		conn.sendError(errmsgUnknownMethod, sender, serial)
 | 
			
		||||
	}
 | 
			
		||||
	var m reflect.Value
 | 
			
		||||
	if hasIface {
 | 
			
		||||
		conn.handlersLck.RLock()
 | 
			
		||||
		obj, ok := conn.handlers[path]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			conn.sendError(errmsgNoObject, sender, serial)
 | 
			
		||||
			conn.handlersLck.RUnlock()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		iface := obj[ifaceName]
 | 
			
		||||
		conn.handlersLck.RUnlock()
 | 
			
		||||
		m = exportedMethod(iface, name)
 | 
			
		||||
	} else {
 | 
			
		||||
		conn.handlersLck.RLock()
 | 
			
		||||
		if _, ok := conn.handlers[path]; !ok {
 | 
			
		||||
			conn.sendError(errmsgNoObject, sender, serial)
 | 
			
		||||
			conn.handlersLck.RUnlock()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		for _, v := range conn.handlers[path] {
 | 
			
		||||
			m = exportedMethod(v, name)
 | 
			
		||||
			if m.IsValid() {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		conn.handlersLck.RUnlock()
 | 
			
		||||
	}
 | 
			
		||||
	if !m.IsValid() {
 | 
			
		||||
		conn.sendError(errmsgUnknownMethod, sender, serial)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	t := m.Type()
 | 
			
		||||
	vs := msg.Body
 | 
			
		||||
	pointers := make([]interface{}, t.NumIn())
 | 
			
		||||
	decode := make([]interface{}, 0, len(vs))
 | 
			
		||||
	for i := 0; i < t.NumIn(); i++ {
 | 
			
		||||
		tp := t.In(i)
 | 
			
		||||
		val := reflect.New(tp)
 | 
			
		||||
		pointers[i] = val.Interface()
 | 
			
		||||
		if tp == reflect.TypeOf((*Sender)(nil)).Elem() {
 | 
			
		||||
			val.Elem().SetString(sender)
 | 
			
		||||
		} else {
 | 
			
		||||
			decode = append(decode, pointers[i])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(decode) != len(vs) {
 | 
			
		||||
		conn.sendError(errmsgInvalidArg, sender, serial)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if err := Store(vs, decode...); err != nil {
 | 
			
		||||
		conn.sendError(errmsgInvalidArg, sender, serial)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	params := make([]reflect.Value, len(pointers))
 | 
			
		||||
	for i := 0; i < len(pointers); i++ {
 | 
			
		||||
		params[i] = reflect.ValueOf(pointers[i]).Elem()
 | 
			
		||||
	}
 | 
			
		||||
	ret := m.Call(params)
 | 
			
		||||
	if em := ret[t.NumOut()-1].Interface().(*Error); em != nil {
 | 
			
		||||
		conn.sendError(*em, sender, serial)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if msg.Flags&FlagNoReplyExpected == 0 {
 | 
			
		||||
		reply := new(Message)
 | 
			
		||||
		reply.Type = TypeMethodReply
 | 
			
		||||
		reply.serial = conn.getSerial()
 | 
			
		||||
		reply.Headers = make(map[HeaderField]Variant)
 | 
			
		||||
		if hasSender {
 | 
			
		||||
			reply.Headers[FieldDestination] = msg.Headers[FieldSender]
 | 
			
		||||
		}
 | 
			
		||||
		reply.Headers[FieldReplySerial] = MakeVariant(msg.serial)
 | 
			
		||||
		reply.Body = make([]interface{}, len(ret)-1)
 | 
			
		||||
		for i := 0; i < len(ret)-1; i++ {
 | 
			
		||||
			reply.Body[i] = ret[i].Interface()
 | 
			
		||||
		}
 | 
			
		||||
		if len(ret) != 1 {
 | 
			
		||||
			reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...))
 | 
			
		||||
		}
 | 
			
		||||
		conn.outLck.RLock()
 | 
			
		||||
		if !conn.closed {
 | 
			
		||||
			conn.out <- reply
 | 
			
		||||
		}
 | 
			
		||||
		conn.outLck.RUnlock()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Emit emits the given signal on the message bus. The name parameter must be
 | 
			
		||||
// formatted as "interface.member", e.g., "org.freedesktop.DBus.NameLost".
 | 
			
		||||
func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) error {
 | 
			
		||||
	if !path.IsValid() {
 | 
			
		||||
		return errors.New("dbus: invalid object path")
 | 
			
		||||
	}
 | 
			
		||||
	i := strings.LastIndex(name, ".")
 | 
			
		||||
	if i == -1 {
 | 
			
		||||
		return errors.New("dbus: invalid method name")
 | 
			
		||||
	}
 | 
			
		||||
	iface := name[:i]
 | 
			
		||||
	member := name[i+1:]
 | 
			
		||||
	if !isValidMember(member) {
 | 
			
		||||
		return errors.New("dbus: invalid method name")
 | 
			
		||||
	}
 | 
			
		||||
	if !isValidInterface(iface) {
 | 
			
		||||
		return errors.New("dbus: invalid interface name")
 | 
			
		||||
	}
 | 
			
		||||
	msg := new(Message)
 | 
			
		||||
	msg.Type = TypeSignal
 | 
			
		||||
	msg.serial = conn.getSerial()
 | 
			
		||||
	msg.Headers = make(map[HeaderField]Variant)
 | 
			
		||||
	msg.Headers[FieldInterface] = MakeVariant(iface)
 | 
			
		||||
	msg.Headers[FieldMember] = MakeVariant(member)
 | 
			
		||||
	msg.Headers[FieldPath] = MakeVariant(path)
 | 
			
		||||
	msg.Body = values
 | 
			
		||||
	if len(values) > 0 {
 | 
			
		||||
		msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
 | 
			
		||||
	}
 | 
			
		||||
	conn.outLck.RLock()
 | 
			
		||||
	defer conn.outLck.RUnlock()
 | 
			
		||||
	if conn.closed {
 | 
			
		||||
		return ErrClosed
 | 
			
		||||
	}
 | 
			
		||||
	conn.out <- msg
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Export registers the given value to be exported as an object on the
 | 
			
		||||
// message bus.
 | 
			
		||||
//
 | 
			
		||||
// If a method call on the given path and interface is received, an exported
 | 
			
		||||
// method with the same name is called with v as the receiver if the
 | 
			
		||||
// parameters match and the last return value is of type *Error. If this
 | 
			
		||||
// *Error is not nil, it is sent back to the caller as an error.
 | 
			
		||||
// Otherwise, a method reply is sent with the other return values as its body.
 | 
			
		||||
//
 | 
			
		||||
// Any parameters with the special type Sender are set to the sender of the
 | 
			
		||||
// dbus message when the method is called. Parameters of this type do not
 | 
			
		||||
// contribute to the dbus signature of the method (i.e. the method is exposed
 | 
			
		||||
// as if the parameters of type Sender were not there).
 | 
			
		||||
//
 | 
			
		||||
// Every method call is executed in a new goroutine, so the method may be called
 | 
			
		||||
// in multiple goroutines at once.
 | 
			
		||||
//
 | 
			
		||||
// Method calls on the interface org.freedesktop.DBus.Peer will be automatically
 | 
			
		||||
// handled for every object.
 | 
			
		||||
//
 | 
			
		||||
// Passing nil as the first parameter will cause conn to cease handling calls on
 | 
			
		||||
// the given combination of path and interface.
 | 
			
		||||
//
 | 
			
		||||
// Export returns an error if path is not a valid path name.
 | 
			
		||||
func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
 | 
			
		||||
	if !path.IsValid() {
 | 
			
		||||
		return errors.New("dbus: invalid path name")
 | 
			
		||||
	}
 | 
			
		||||
	conn.handlersLck.Lock()
 | 
			
		||||
	if v == nil {
 | 
			
		||||
		if _, ok := conn.handlers[path]; ok {
 | 
			
		||||
			delete(conn.handlers[path], iface)
 | 
			
		||||
			if len(conn.handlers[path]) == 0 {
 | 
			
		||||
				delete(conn.handlers, path)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if _, ok := conn.handlers[path]; !ok {
 | 
			
		||||
		conn.handlers[path] = make(map[string]interface{})
 | 
			
		||||
	}
 | 
			
		||||
	conn.handlers[path][iface] = v
 | 
			
		||||
	conn.handlersLck.Unlock()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReleaseName calls org.freedesktop.DBus.ReleaseName. You should use only this
 | 
			
		||||
// method to release a name (see below).
 | 
			
		||||
func (conn *Conn) ReleaseName(name string) (ReleaseNameReply, error) {
 | 
			
		||||
	var r uint32
 | 
			
		||||
	err := conn.busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	if r == uint32(ReleaseNameReplyReleased) {
 | 
			
		||||
		conn.namesLck.Lock()
 | 
			
		||||
		for i, v := range conn.names {
 | 
			
		||||
			if v == name {
 | 
			
		||||
				copy(conn.names[i:], conn.names[i+1:])
 | 
			
		||||
				conn.names = conn.names[:len(conn.names)-1]
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		conn.namesLck.Unlock()
 | 
			
		||||
	}
 | 
			
		||||
	return ReleaseNameReply(r), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RequestName calls org.freedesktop.DBus.RequestName. You should use only this
 | 
			
		||||
// method to request a name because package dbus needs to keep track of all
 | 
			
		||||
// names that the connection has.
 | 
			
		||||
func (conn *Conn) RequestName(name string, flags RequestNameFlags) (RequestNameReply, error) {
 | 
			
		||||
	var r uint32
 | 
			
		||||
	err := conn.busObj.Call("org.freedesktop.DBus.RequestName", 0, name, flags).Store(&r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	if r == uint32(RequestNameReplyPrimaryOwner) {
 | 
			
		||||
		conn.namesLck.Lock()
 | 
			
		||||
		conn.names = append(conn.names, name)
 | 
			
		||||
		conn.namesLck.Unlock()
 | 
			
		||||
	}
 | 
			
		||||
	return RequestNameReply(r), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReleaseNameReply is the reply to a ReleaseName call.
 | 
			
		||||
type ReleaseNameReply uint32
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ReleaseNameReplyReleased ReleaseNameReply = 1 + iota
 | 
			
		||||
	ReleaseNameReplyNonExistent
 | 
			
		||||
	ReleaseNameReplyNotOwner
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RequestNameFlags represents the possible flags for a RequestName call.
 | 
			
		||||
type RequestNameFlags uint32
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	NameFlagAllowReplacement RequestNameFlags = 1 << iota
 | 
			
		||||
	NameFlagReplaceExisting
 | 
			
		||||
	NameFlagDoNotQueue
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RequestNameReply is the reply to a RequestName call.
 | 
			
		||||
type RequestNameReply uint32
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	RequestNameReplyPrimaryOwner RequestNameReply = 1 + iota
 | 
			
		||||
	RequestNameReplyInQueue
 | 
			
		||||
	RequestNameReplyExists
 | 
			
		||||
	RequestNameReplyAlreadyOwner
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/src/github.com/godbus/dbus/homedir.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/src/github.com/godbus/dbus/homedir.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	homeDir     string
 | 
			
		||||
	homeDirLock sync.Mutex
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func getHomeDir() string {
 | 
			
		||||
	homeDirLock.Lock()
 | 
			
		||||
	defer homeDirLock.Unlock()
 | 
			
		||||
 | 
			
		||||
	if homeDir != "" {
 | 
			
		||||
		return homeDir
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	homeDir = os.Getenv("HOME")
 | 
			
		||||
	if homeDir != "" {
 | 
			
		||||
		return homeDir
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	homeDir = lookupHomeDir()
 | 
			
		||||
	return homeDir
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								vendor/src/github.com/godbus/dbus/homedir_dynamic.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/src/github.com/godbus/dbus/homedir_dynamic.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
// +build !static_build
 | 
			
		||||
 | 
			
		||||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os/user"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func lookupHomeDir() string {
 | 
			
		||||
	u, err := user.Current()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "/"
 | 
			
		||||
	}
 | 
			
		||||
	return u.HomeDir
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								vendor/src/github.com/godbus/dbus/homedir_static.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								vendor/src/github.com/godbus/dbus/homedir_static.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
// +build static_build
 | 
			
		||||
 | 
			
		||||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func lookupHomeDir() string {
 | 
			
		||||
	myUid := os.Getuid()
 | 
			
		||||
 | 
			
		||||
	f, err := os.Open("/etc/passwd")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "/"
 | 
			
		||||
	}
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	s := bufio.NewScanner(f)
 | 
			
		||||
 | 
			
		||||
	for s.Scan() {
 | 
			
		||||
		if err := s.Err(); err != nil {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		line := strings.TrimSpace(s.Text())
 | 
			
		||||
		if line == "" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		parts := strings.Split(line, ":")
 | 
			
		||||
 | 
			
		||||
		if len(parts) >= 6 {
 | 
			
		||||
			uid, err := strconv.Atoi(parts[2])
 | 
			
		||||
			if err == nil && uid == myUid {
 | 
			
		||||
				return parts[5]
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Default to / if we can't get a better value
 | 
			
		||||
	return "/"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/src/github.com/godbus/dbus/introspect/call.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/src/github.com/godbus/dbus/introspect/call.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
package introspect
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/xml"
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Call calls org.freedesktop.Introspectable.Introspect on a remote object
 | 
			
		||||
// and returns the introspection data.
 | 
			
		||||
func Call(o *dbus.Object) (*Node, error) {
 | 
			
		||||
	var xmldata string
 | 
			
		||||
	var node Node
 | 
			
		||||
 | 
			
		||||
	err := o.Call("org.freedesktop.DBus.Introspectable.Introspect", 0).Store(&xmldata)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	err = xml.NewDecoder(strings.NewReader(xmldata)).Decode(&node)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if node.Name == "" {
 | 
			
		||||
		node.Name = string(o.Path())
 | 
			
		||||
	}
 | 
			
		||||
	return &node, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										80
									
								
								vendor/src/github.com/godbus/dbus/introspect/introspect.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								vendor/src/github.com/godbus/dbus/introspect/introspect.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,80 @@
 | 
			
		|||
// Package introspect provides some utilities for dealing with the DBus
 | 
			
		||||
// introspection format.
 | 
			
		||||
package introspect
 | 
			
		||||
 | 
			
		||||
import "encoding/xml"
 | 
			
		||||
 | 
			
		||||
// The introspection data for the org.freedesktop.DBus.Introspectable interface.
 | 
			
		||||
var IntrospectData = Interface{
 | 
			
		||||
	Name: "org.freedesktop.DBus.Introspectable",
 | 
			
		||||
	Methods: []Method{
 | 
			
		||||
		{
 | 
			
		||||
			Name: "Introspect",
 | 
			
		||||
			Args: []Arg{
 | 
			
		||||
				{"out", "s", "out"},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The introspection data for the org.freedesktop.DBus.Introspectable interface,
 | 
			
		||||
// as a string.
 | 
			
		||||
const IntrospectDataString = `
 | 
			
		||||
	<interface name="org.freedesktop.DBus.Introspectable">
 | 
			
		||||
		<method name="Introspect">
 | 
			
		||||
			<arg name="out" direction="out" type="s"/>
 | 
			
		||||
		</method>
 | 
			
		||||
	</interface>
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
// Node is the root element of an introspection.
 | 
			
		||||
type Node struct {
 | 
			
		||||
	XMLName    xml.Name    `xml:"node"`
 | 
			
		||||
	Name       string      `xml:"name,attr,omitempty"`
 | 
			
		||||
	Interfaces []Interface `xml:"interface"`
 | 
			
		||||
	Children   []Node      `xml:"node,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Interface describes a DBus interface that is available on the message bus.
 | 
			
		||||
type Interface struct {
 | 
			
		||||
	Name        string       `xml:"name,attr"`
 | 
			
		||||
	Methods     []Method     `xml:"method"`
 | 
			
		||||
	Signals     []Signal     `xml:"signal"`
 | 
			
		||||
	Properties  []Property   `xml:"property"`
 | 
			
		||||
	Annotations []Annotation `xml:"annotation"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Method describes a Method on an Interface as retured by an introspection.
 | 
			
		||||
type Method struct {
 | 
			
		||||
	Name        string       `xml:"name,attr"`
 | 
			
		||||
	Args        []Arg        `xml:"arg"`
 | 
			
		||||
	Annotations []Annotation `xml:"annotation"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Signal describes a Signal emitted on an Interface.
 | 
			
		||||
type Signal struct {
 | 
			
		||||
	Name        string       `xml:"name,attr"`
 | 
			
		||||
	Args        []Arg        `xml:"arg"`
 | 
			
		||||
	Annotations []Annotation `xml:"annotation"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Property describes a property of an Interface.
 | 
			
		||||
type Property struct {
 | 
			
		||||
	Name        string       `xml:"name,attr"`
 | 
			
		||||
	Type        string       `xml:"type,attr"`
 | 
			
		||||
	Access      string       `xml:"access,attr"`
 | 
			
		||||
	Annotations []Annotation `xml:"annotation"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Arg represents an argument of a method or a signal.
 | 
			
		||||
type Arg struct {
 | 
			
		||||
	Name      string `xml:"name,attr,omitempty"`
 | 
			
		||||
	Type      string `xml:"type,attr"`
 | 
			
		||||
	Direction string `xml:"direction,attr,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Annotation is an annotation in the introspection format.
 | 
			
		||||
type Annotation struct {
 | 
			
		||||
	Name  string `xml:"name,attr"`
 | 
			
		||||
	Value string `xml:"value,attr"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								vendor/src/github.com/godbus/dbus/introspect/introspectable.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								vendor/src/github.com/godbus/dbus/introspect/introspectable.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,74 @@
 | 
			
		|||
package introspect
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/xml"
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
	"reflect"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Introspectable implements org.freedesktop.Introspectable.
 | 
			
		||||
//
 | 
			
		||||
// You can create it by converting the XML-formatted introspection data from a
 | 
			
		||||
// string to an Introspectable or call NewIntrospectable with a Node. Then,
 | 
			
		||||
// export it as org.freedesktop.Introspectable on you object.
 | 
			
		||||
type Introspectable string
 | 
			
		||||
 | 
			
		||||
// NewIntrospectable returns an Introspectable that returns the introspection
 | 
			
		||||
// data that corresponds to the given Node. If n.Interfaces doesn't contain the
 | 
			
		||||
// data for org.freedesktop.DBus.Introspectable, it is added automatically.
 | 
			
		||||
func NewIntrospectable(n *Node) Introspectable {
 | 
			
		||||
	found := false
 | 
			
		||||
	for _, v := range n.Interfaces {
 | 
			
		||||
		if v.Name == "org.freedesktop.DBus.Introspectable" {
 | 
			
		||||
			found = true
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if !found {
 | 
			
		||||
		n.Interfaces = append(n.Interfaces, IntrospectData)
 | 
			
		||||
	}
 | 
			
		||||
	b, err := xml.Marshal(n)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	return Introspectable(b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Introspect implements org.freedesktop.Introspectable.Introspect.
 | 
			
		||||
func (i Introspectable) Introspect() (string, *dbus.Error) {
 | 
			
		||||
	return string(i), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Methods returns the description of the methods of v. This can be used to
 | 
			
		||||
// create a Node which can be passed to NewIntrospectable.
 | 
			
		||||
func Methods(v interface{}) []Method {
 | 
			
		||||
	t := reflect.TypeOf(v)
 | 
			
		||||
	ms := make([]Method, 0, t.NumMethod())
 | 
			
		||||
	for i := 0; i < t.NumMethod(); i++ {
 | 
			
		||||
		if t.Method(i).PkgPath != "" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		mt := t.Method(i).Type
 | 
			
		||||
		if mt.NumOut() == 0 ||
 | 
			
		||||
			mt.Out(mt.NumOut()-1) != reflect.TypeOf(&dbus.Error{"", nil}) {
 | 
			
		||||
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		var m Method
 | 
			
		||||
		m.Name = t.Method(i).Name
 | 
			
		||||
		m.Args = make([]Arg, 0, mt.NumIn()+mt.NumOut()-2)
 | 
			
		||||
		for j := 1; j < mt.NumIn(); j++ {
 | 
			
		||||
			if mt.In(j) != reflect.TypeOf((*dbus.Sender)(nil)).Elem() {
 | 
			
		||||
				arg := Arg{"", dbus.SignatureOfType(mt.In(j)).String(), "in"}
 | 
			
		||||
				m.Args = append(m.Args, arg)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for j := 0; j < mt.NumOut()-1; j++ {
 | 
			
		||||
			arg := Arg{"", dbus.SignatureOfType(mt.Out(j)).String(), "out"}
 | 
			
		||||
			m.Args = append(m.Args, arg)
 | 
			
		||||
		}
 | 
			
		||||
		m.Annotations = make([]Annotation, 0)
 | 
			
		||||
		ms = append(ms, m)
 | 
			
		||||
	}
 | 
			
		||||
	return ms
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										346
									
								
								vendor/src/github.com/godbus/dbus/message.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								vendor/src/github.com/godbus/dbus/message.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,346 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const protoVersion byte = 1
 | 
			
		||||
 | 
			
		||||
// Flags represents the possible flags of a D-Bus message.
 | 
			
		||||
type Flags byte
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// FlagNoReplyExpected signals that the message is not expected to generate
 | 
			
		||||
	// a reply. If this flag is set on outgoing messages, any possible reply
 | 
			
		||||
	// will be discarded.
 | 
			
		||||
	FlagNoReplyExpected Flags = 1 << iota
 | 
			
		||||
	// FlagNoAutoStart signals that the message bus should not automatically
 | 
			
		||||
	// start an application when handling this message.
 | 
			
		||||
	FlagNoAutoStart
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Type represents the possible types of a D-Bus message.
 | 
			
		||||
type Type byte
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	TypeMethodCall Type = 1 + iota
 | 
			
		||||
	TypeMethodReply
 | 
			
		||||
	TypeError
 | 
			
		||||
	TypeSignal
 | 
			
		||||
	typeMax
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (t Type) String() string {
 | 
			
		||||
	switch t {
 | 
			
		||||
	case TypeMethodCall:
 | 
			
		||||
		return "method call"
 | 
			
		||||
	case TypeMethodReply:
 | 
			
		||||
		return "reply"
 | 
			
		||||
	case TypeError:
 | 
			
		||||
		return "error"
 | 
			
		||||
	case TypeSignal:
 | 
			
		||||
		return "signal"
 | 
			
		||||
	}
 | 
			
		||||
	return "invalid"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HeaderField represents the possible byte codes for the headers
 | 
			
		||||
// of a D-Bus message.
 | 
			
		||||
type HeaderField byte
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	FieldPath HeaderField = 1 + iota
 | 
			
		||||
	FieldInterface
 | 
			
		||||
	FieldMember
 | 
			
		||||
	FieldErrorName
 | 
			
		||||
	FieldReplySerial
 | 
			
		||||
	FieldDestination
 | 
			
		||||
	FieldSender
 | 
			
		||||
	FieldSignature
 | 
			
		||||
	FieldUnixFDs
 | 
			
		||||
	fieldMax
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// An InvalidMessageError describes the reason why a D-Bus message is regarded as
 | 
			
		||||
// invalid.
 | 
			
		||||
type InvalidMessageError string
 | 
			
		||||
 | 
			
		||||
func (e InvalidMessageError) Error() string {
 | 
			
		||||
	return "dbus: invalid message: " + string(e)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// fieldType are the types of the various header fields.
 | 
			
		||||
var fieldTypes = [fieldMax]reflect.Type{
 | 
			
		||||
	FieldPath:        objectPathType,
 | 
			
		||||
	FieldInterface:   stringType,
 | 
			
		||||
	FieldMember:      stringType,
 | 
			
		||||
	FieldErrorName:   stringType,
 | 
			
		||||
	FieldReplySerial: uint32Type,
 | 
			
		||||
	FieldDestination: stringType,
 | 
			
		||||
	FieldSender:      stringType,
 | 
			
		||||
	FieldSignature:   signatureType,
 | 
			
		||||
	FieldUnixFDs:     uint32Type,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// requiredFields lists the header fields that are required by the different
 | 
			
		||||
// message types.
 | 
			
		||||
var requiredFields = [typeMax][]HeaderField{
 | 
			
		||||
	TypeMethodCall:  {FieldPath, FieldMember},
 | 
			
		||||
	TypeMethodReply: {FieldReplySerial},
 | 
			
		||||
	TypeError:       {FieldErrorName, FieldReplySerial},
 | 
			
		||||
	TypeSignal:      {FieldPath, FieldInterface, FieldMember},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Message represents a single D-Bus message.
 | 
			
		||||
type Message struct {
 | 
			
		||||
	Type
 | 
			
		||||
	Flags
 | 
			
		||||
	Headers map[HeaderField]Variant
 | 
			
		||||
	Body    []interface{}
 | 
			
		||||
 | 
			
		||||
	serial uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type header struct {
 | 
			
		||||
	Field byte
 | 
			
		||||
	Variant
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecodeMessage tries to decode a single message in the D-Bus wire format
 | 
			
		||||
// from the given reader. The byte order is figured out from the first byte.
 | 
			
		||||
// The possibly returned error can be an error of the underlying reader, an
 | 
			
		||||
// InvalidMessageError or a FormatError.
 | 
			
		||||
func DecodeMessage(rd io.Reader) (msg *Message, err error) {
 | 
			
		||||
	var order binary.ByteOrder
 | 
			
		||||
	var hlength, length uint32
 | 
			
		||||
	var typ, flags, proto byte
 | 
			
		||||
	var headers []header
 | 
			
		||||
 | 
			
		||||
	b := make([]byte, 1)
 | 
			
		||||
	_, err = rd.Read(b)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	switch b[0] {
 | 
			
		||||
	case 'l':
 | 
			
		||||
		order = binary.LittleEndian
 | 
			
		||||
	case 'B':
 | 
			
		||||
		order = binary.BigEndian
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, InvalidMessageError("invalid byte order")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dec := newDecoder(rd, order)
 | 
			
		||||
	dec.pos = 1
 | 
			
		||||
 | 
			
		||||
	msg = new(Message)
 | 
			
		||||
	vs, err := dec.Decode(Signature{"yyyuu"})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if err = Store(vs, &typ, &flags, &proto, &length, &msg.serial); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	msg.Type = Type(typ)
 | 
			
		||||
	msg.Flags = Flags(flags)
 | 
			
		||||
 | 
			
		||||
	// get the header length separately because we need it later
 | 
			
		||||
	b = make([]byte, 4)
 | 
			
		||||
	_, err = io.ReadFull(rd, b)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	binary.Read(bytes.NewBuffer(b), order, &hlength)
 | 
			
		||||
	if hlength+length+16 > 1<<27 {
 | 
			
		||||
		return nil, InvalidMessageError("message is too long")
 | 
			
		||||
	}
 | 
			
		||||
	dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order)
 | 
			
		||||
	dec.pos = 12
 | 
			
		||||
	vs, err = dec.Decode(Signature{"a(yv)"})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if err = Store(vs, &headers); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msg.Headers = make(map[HeaderField]Variant)
 | 
			
		||||
	for _, v := range headers {
 | 
			
		||||
		msg.Headers[HeaderField(v.Field)] = v.Variant
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dec.align(8)
 | 
			
		||||
	body := make([]byte, int(length))
 | 
			
		||||
	if length != 0 {
 | 
			
		||||
		_, err := io.ReadFull(rd, body)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = msg.IsValid(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	sig, _ := msg.Headers[FieldSignature].value.(Signature)
 | 
			
		||||
	if sig.str != "" {
 | 
			
		||||
		buf := bytes.NewBuffer(body)
 | 
			
		||||
		dec = newDecoder(buf, order)
 | 
			
		||||
		vs, err := dec.Decode(sig)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		msg.Body = vs
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncodeTo encodes and sends a message to the given writer. The byte order must
 | 
			
		||||
// be either binary.LittleEndian or binary.BigEndian. If the message is not
 | 
			
		||||
// valid or an error occurs when writing, an error is returned.
 | 
			
		||||
func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error {
 | 
			
		||||
	if err := msg.IsValid(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	var vs [7]interface{}
 | 
			
		||||
	switch order {
 | 
			
		||||
	case binary.LittleEndian:
 | 
			
		||||
		vs[0] = byte('l')
 | 
			
		||||
	case binary.BigEndian:
 | 
			
		||||
		vs[0] = byte('B')
 | 
			
		||||
	default:
 | 
			
		||||
		return errors.New("dbus: invalid byte order")
 | 
			
		||||
	}
 | 
			
		||||
	body := new(bytes.Buffer)
 | 
			
		||||
	enc := newEncoder(body, order)
 | 
			
		||||
	if len(msg.Body) != 0 {
 | 
			
		||||
		enc.Encode(msg.Body...)
 | 
			
		||||
	}
 | 
			
		||||
	vs[1] = msg.Type
 | 
			
		||||
	vs[2] = msg.Flags
 | 
			
		||||
	vs[3] = protoVersion
 | 
			
		||||
	vs[4] = uint32(len(body.Bytes()))
 | 
			
		||||
	vs[5] = msg.serial
 | 
			
		||||
	headers := make([]header, 0, len(msg.Headers))
 | 
			
		||||
	for k, v := range msg.Headers {
 | 
			
		||||
		headers = append(headers, header{byte(k), v})
 | 
			
		||||
	}
 | 
			
		||||
	vs[6] = headers
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	enc = newEncoder(&buf, order)
 | 
			
		||||
	enc.Encode(vs[:]...)
 | 
			
		||||
	enc.align(8)
 | 
			
		||||
	body.WriteTo(&buf)
 | 
			
		||||
	if buf.Len() > 1<<27 {
 | 
			
		||||
		return InvalidMessageError("message is too long")
 | 
			
		||||
	}
 | 
			
		||||
	if _, err := buf.WriteTo(out); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsValid checks whether msg is a valid message and returns an
 | 
			
		||||
// InvalidMessageError if it is not.
 | 
			
		||||
func (msg *Message) IsValid() error {
 | 
			
		||||
	if msg.Flags & ^(FlagNoAutoStart|FlagNoReplyExpected) != 0 {
 | 
			
		||||
		return InvalidMessageError("invalid flags")
 | 
			
		||||
	}
 | 
			
		||||
	if msg.Type == 0 || msg.Type >= typeMax {
 | 
			
		||||
		return InvalidMessageError("invalid message type")
 | 
			
		||||
	}
 | 
			
		||||
	for k, v := range msg.Headers {
 | 
			
		||||
		if k == 0 || k >= fieldMax {
 | 
			
		||||
			return InvalidMessageError("invalid header")
 | 
			
		||||
		}
 | 
			
		||||
		if reflect.TypeOf(v.value) != fieldTypes[k] {
 | 
			
		||||
			return InvalidMessageError("invalid type of header field")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for _, v := range requiredFields[msg.Type] {
 | 
			
		||||
		if _, ok := msg.Headers[v]; !ok {
 | 
			
		||||
			return InvalidMessageError("missing required header")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if path, ok := msg.Headers[FieldPath]; ok {
 | 
			
		||||
		if !path.value.(ObjectPath).IsValid() {
 | 
			
		||||
			return InvalidMessageError("invalid path name")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if iface, ok := msg.Headers[FieldInterface]; ok {
 | 
			
		||||
		if !isValidInterface(iface.value.(string)) {
 | 
			
		||||
			return InvalidMessageError("invalid interface name")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if member, ok := msg.Headers[FieldMember]; ok {
 | 
			
		||||
		if !isValidMember(member.value.(string)) {
 | 
			
		||||
			return InvalidMessageError("invalid member name")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if errname, ok := msg.Headers[FieldErrorName]; ok {
 | 
			
		||||
		if !isValidInterface(errname.value.(string)) {
 | 
			
		||||
			return InvalidMessageError("invalid error name")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(msg.Body) != 0 {
 | 
			
		||||
		if _, ok := msg.Headers[FieldSignature]; !ok {
 | 
			
		||||
			return InvalidMessageError("missing signature")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Serial returns the message's serial number. The returned value is only valid
 | 
			
		||||
// for messages received by eavesdropping.
 | 
			
		||||
func (msg *Message) Serial() uint32 {
 | 
			
		||||
	return msg.serial
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String returns a string representation of a message similar to the format of
 | 
			
		||||
// dbus-monitor.
 | 
			
		||||
func (msg *Message) String() string {
 | 
			
		||||
	if err := msg.IsValid(); err != nil {
 | 
			
		||||
		return "<invalid>"
 | 
			
		||||
	}
 | 
			
		||||
	s := msg.Type.String()
 | 
			
		||||
	if v, ok := msg.Headers[FieldSender]; ok {
 | 
			
		||||
		s += " from " + v.value.(string)
 | 
			
		||||
	}
 | 
			
		||||
	if v, ok := msg.Headers[FieldDestination]; ok {
 | 
			
		||||
		s += " to " + v.value.(string)
 | 
			
		||||
	}
 | 
			
		||||
	s += " serial " + strconv.FormatUint(uint64(msg.serial), 10)
 | 
			
		||||
	if v, ok := msg.Headers[FieldReplySerial]; ok {
 | 
			
		||||
		s += " reply_serial " + strconv.FormatUint(uint64(v.value.(uint32)), 10)
 | 
			
		||||
	}
 | 
			
		||||
	if v, ok := msg.Headers[FieldUnixFDs]; ok {
 | 
			
		||||
		s += " unixfds " + strconv.FormatUint(uint64(v.value.(uint32)), 10)
 | 
			
		||||
	}
 | 
			
		||||
	if v, ok := msg.Headers[FieldPath]; ok {
 | 
			
		||||
		s += " path " + string(v.value.(ObjectPath))
 | 
			
		||||
	}
 | 
			
		||||
	if v, ok := msg.Headers[FieldInterface]; ok {
 | 
			
		||||
		s += " interface " + v.value.(string)
 | 
			
		||||
	}
 | 
			
		||||
	if v, ok := msg.Headers[FieldErrorName]; ok {
 | 
			
		||||
		s += " error " + v.value.(string)
 | 
			
		||||
	}
 | 
			
		||||
	if v, ok := msg.Headers[FieldMember]; ok {
 | 
			
		||||
		s += " member " + v.value.(string)
 | 
			
		||||
	}
 | 
			
		||||
	if len(msg.Body) != 0 {
 | 
			
		||||
		s += "\n"
 | 
			
		||||
	}
 | 
			
		||||
	for i, v := range msg.Body {
 | 
			
		||||
		s += "  " + MakeVariant(v).String()
 | 
			
		||||
		if i != len(msg.Body)-1 {
 | 
			
		||||
			s += "\n"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										264
									
								
								vendor/src/github.com/godbus/dbus/prop/prop.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								vendor/src/github.com/godbus/dbus/prop/prop.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,264 @@
 | 
			
		|||
// Package prop provides the Properties struct which can be used to implement
 | 
			
		||||
// org.freedesktop.DBus.Properties.
 | 
			
		||||
package prop
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/godbus/dbus"
 | 
			
		||||
	"github.com/godbus/dbus/introspect"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// EmitType controls how org.freedesktop.DBus.Properties.PropertiesChanged is
 | 
			
		||||
// emitted for a property. If it is EmitTrue, the signal is emitted. If it is
 | 
			
		||||
// EmitInvalidates, the signal is also emitted, but the new value of the property
 | 
			
		||||
// is not disclosed.
 | 
			
		||||
type EmitType byte
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	EmitFalse EmitType = iota
 | 
			
		||||
	EmitTrue
 | 
			
		||||
	EmitInvalidates
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrIfaceNotFound is the error returned to peers who try to access properties
 | 
			
		||||
// on interfaces that aren't found.
 | 
			
		||||
var ErrIfaceNotFound = &dbus.Error{"org.freedesktop.DBus.Properties.Error.InterfaceNotFound", nil}
 | 
			
		||||
 | 
			
		||||
// ErrPropNotFound is the error returned to peers trying to access properties
 | 
			
		||||
// that aren't found.
 | 
			
		||||
var ErrPropNotFound = &dbus.Error{"org.freedesktop.DBus.Properties.Error.PropertyNotFound", nil}
 | 
			
		||||
 | 
			
		||||
// ErrReadOnly is the error returned to peers trying to set a read-only
 | 
			
		||||
// property.
 | 
			
		||||
var ErrReadOnly = &dbus.Error{"org.freedesktop.DBus.Properties.Error.ReadOnly", nil}
 | 
			
		||||
 | 
			
		||||
// ErrInvalidArg is returned to peers if the type of the property that is being
 | 
			
		||||
// changed and the argument don't match.
 | 
			
		||||
var ErrInvalidArg = &dbus.Error{"org.freedesktop.DBus.Properties.Error.InvalidArg", nil}
 | 
			
		||||
 | 
			
		||||
// The introspection data for the org.freedesktop.DBus.Properties interface.
 | 
			
		||||
var IntrospectData = introspect.Interface{
 | 
			
		||||
	Name: "org.freedesktop.DBus.Properties",
 | 
			
		||||
	Methods: []introspect.Method{
 | 
			
		||||
		{
 | 
			
		||||
			Name: "Get",
 | 
			
		||||
			Args: []introspect.Arg{
 | 
			
		||||
				{"interface", "s", "in"},
 | 
			
		||||
				{"property", "s", "in"},
 | 
			
		||||
				{"value", "v", "out"},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Name: "GetAll",
 | 
			
		||||
			Args: []introspect.Arg{
 | 
			
		||||
				{"interface", "s", "in"},
 | 
			
		||||
				{"props", "a{sv}", "out"},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Name: "Set",
 | 
			
		||||
			Args: []introspect.Arg{
 | 
			
		||||
				{"interface", "s", "in"},
 | 
			
		||||
				{"property", "s", "in"},
 | 
			
		||||
				{"value", "v", "in"},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	Signals: []introspect.Signal{
 | 
			
		||||
		{
 | 
			
		||||
			Name: "PropertiesChanged",
 | 
			
		||||
			Args: []introspect.Arg{
 | 
			
		||||
				{"interface", "s", "out"},
 | 
			
		||||
				{"changed_properties", "a{sv}", "out"},
 | 
			
		||||
				{"invalidates_properties", "as", "out"},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The introspection data for the org.freedesktop.DBus.Properties interface, as
 | 
			
		||||
// a string.
 | 
			
		||||
const IntrospectDataString = `
 | 
			
		||||
	<interface name="org.freedesktop.DBus.Introspectable">
 | 
			
		||||
		<method name="Get">
 | 
			
		||||
			<arg name="interface" direction="in" type="s"/>
 | 
			
		||||
			<arg name="property" direction="in" type="s"/>
 | 
			
		||||
			<arg name="value" direction="out" type="v"/>
 | 
			
		||||
		</method>
 | 
			
		||||
		<method name="GetAll">
 | 
			
		||||
			<arg name="interface" direction="in" type="s"/>
 | 
			
		||||
			<arg name="props" direction="out" type="a{sv}"/>
 | 
			
		||||
		</method>
 | 
			
		||||
		<method name="Set">
 | 
			
		||||
			<arg name="interface" direction="in" type="s"/>
 | 
			
		||||
			<arg name="property" direction="in" type="s"/>
 | 
			
		||||
			<arg name="value" direction="in" type="v"/>
 | 
			
		||||
		</method>
 | 
			
		||||
		<signal name="PropertiesChanged">
 | 
			
		||||
			<arg name="interface" type="s"/>
 | 
			
		||||
			<arg name="changed_properties" type="a{sv}"/>
 | 
			
		||||
			<arg name="invalidates_properties" type="as"/>
 | 
			
		||||
		</signal>
 | 
			
		||||
	</interface>
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
// Prop represents a single property. It is used for creating a Properties
 | 
			
		||||
// value.
 | 
			
		||||
type Prop struct {
 | 
			
		||||
	// Initial value. Must be a DBus-representable type.
 | 
			
		||||
	Value interface{}
 | 
			
		||||
 | 
			
		||||
	// If true, the value can be modified by calls to Set.
 | 
			
		||||
	Writable bool
 | 
			
		||||
 | 
			
		||||
	// Controls how org.freedesktop.DBus.Properties.PropertiesChanged is
 | 
			
		||||
	// emitted if this property changes.
 | 
			
		||||
	Emit EmitType
 | 
			
		||||
 | 
			
		||||
	// If not nil, anytime this property is changed by Set, this function is
 | 
			
		||||
	// called with an appropiate Change as its argument. If the returned error
 | 
			
		||||
	// is not nil, it is sent back to the caller of Set and the property is not
 | 
			
		||||
	// changed.
 | 
			
		||||
	Callback func(*Change) *dbus.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Change represents a change of a property by a call to Set.
 | 
			
		||||
type Change struct {
 | 
			
		||||
	Props *Properties
 | 
			
		||||
	Iface string
 | 
			
		||||
	Name  string
 | 
			
		||||
	Value interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Properties is a set of values that can be made available to the message bus
 | 
			
		||||
// using the org.freedesktop.DBus.Properties interface. It is safe for
 | 
			
		||||
// concurrent use by multiple goroutines.
 | 
			
		||||
type Properties struct {
 | 
			
		||||
	m    map[string]map[string]*Prop
 | 
			
		||||
	mut  sync.RWMutex
 | 
			
		||||
	conn *dbus.Conn
 | 
			
		||||
	path dbus.ObjectPath
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New returns a new Properties structure that manages the given properties.
 | 
			
		||||
// The key for the first-level map of props is the name of the interface; the
 | 
			
		||||
// second-level key is the name of the property. The returned structure will be
 | 
			
		||||
// exported as org.freedesktop.DBus.Properties on path.
 | 
			
		||||
func New(conn *dbus.Conn, path dbus.ObjectPath, props map[string]map[string]*Prop) *Properties {
 | 
			
		||||
	p := &Properties{m: props, conn: conn, path: path}
 | 
			
		||||
	conn.Export(p, path, "org.freedesktop.DBus.Properties")
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get implements org.freedesktop.DBus.Properties.Get.
 | 
			
		||||
func (p *Properties) Get(iface, property string) (dbus.Variant, *dbus.Error) {
 | 
			
		||||
	p.mut.RLock()
 | 
			
		||||
	defer p.mut.RUnlock()
 | 
			
		||||
	m, ok := p.m[iface]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return dbus.Variant{}, ErrIfaceNotFound
 | 
			
		||||
	}
 | 
			
		||||
	prop, ok := m[property]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return dbus.Variant{}, ErrPropNotFound
 | 
			
		||||
	}
 | 
			
		||||
	return dbus.MakeVariant(prop.Value), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetAll implements org.freedesktop.DBus.Properties.GetAll.
 | 
			
		||||
func (p *Properties) GetAll(iface string) (map[string]dbus.Variant, *dbus.Error) {
 | 
			
		||||
	p.mut.RLock()
 | 
			
		||||
	defer p.mut.RUnlock()
 | 
			
		||||
	m, ok := p.m[iface]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, ErrIfaceNotFound
 | 
			
		||||
	}
 | 
			
		||||
	rm := make(map[string]dbus.Variant, len(m))
 | 
			
		||||
	for k, v := range m {
 | 
			
		||||
		rm[k] = dbus.MakeVariant(v.Value)
 | 
			
		||||
	}
 | 
			
		||||
	return rm, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetMust returns the value of the given property and panics if either the
 | 
			
		||||
// interface or the property name are invalid.
 | 
			
		||||
func (p *Properties) GetMust(iface, property string) interface{} {
 | 
			
		||||
	p.mut.RLock()
 | 
			
		||||
	defer p.mut.RUnlock()
 | 
			
		||||
	return p.m[iface][property].Value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Introspection returns the introspection data that represents the properties
 | 
			
		||||
// of iface.
 | 
			
		||||
func (p *Properties) Introspection(iface string) []introspect.Property {
 | 
			
		||||
	p.mut.RLock()
 | 
			
		||||
	defer p.mut.RUnlock()
 | 
			
		||||
	m := p.m[iface]
 | 
			
		||||
	s := make([]introspect.Property, 0, len(m))
 | 
			
		||||
	for k, v := range m {
 | 
			
		||||
		p := introspect.Property{Name: k, Type: dbus.SignatureOf(v.Value).String()}
 | 
			
		||||
		if v.Writable {
 | 
			
		||||
			p.Access = "readwrite"
 | 
			
		||||
		} else {
 | 
			
		||||
			p.Access = "read"
 | 
			
		||||
		}
 | 
			
		||||
		s = append(s, p)
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// set sets the given property and emits PropertyChanged if appropiate. p.mut
 | 
			
		||||
// must already be locked.
 | 
			
		||||
func (p *Properties) set(iface, property string, v interface{}) {
 | 
			
		||||
	prop := p.m[iface][property]
 | 
			
		||||
	prop.Value = v
 | 
			
		||||
	switch prop.Emit {
 | 
			
		||||
	case EmitFalse:
 | 
			
		||||
		// do nothing
 | 
			
		||||
	case EmitInvalidates:
 | 
			
		||||
		p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
 | 
			
		||||
			iface, map[string]dbus.Variant{}, []string{property})
 | 
			
		||||
	case EmitTrue:
 | 
			
		||||
		p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
 | 
			
		||||
			iface, map[string]dbus.Variant{property: dbus.MakeVariant(v)},
 | 
			
		||||
			[]string{})
 | 
			
		||||
	default:
 | 
			
		||||
		panic("invalid value for EmitType")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set implements org.freedesktop.Properties.Set.
 | 
			
		||||
func (p *Properties) Set(iface, property string, newv dbus.Variant) *dbus.Error {
 | 
			
		||||
	p.mut.Lock()
 | 
			
		||||
	defer p.mut.Unlock()
 | 
			
		||||
	m, ok := p.m[iface]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return ErrIfaceNotFound
 | 
			
		||||
	}
 | 
			
		||||
	prop, ok := m[property]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return ErrPropNotFound
 | 
			
		||||
	}
 | 
			
		||||
	if !prop.Writable {
 | 
			
		||||
		return ErrReadOnly
 | 
			
		||||
	}
 | 
			
		||||
	if newv.Signature() != dbus.SignatureOf(prop.Value) {
 | 
			
		||||
		return ErrInvalidArg
 | 
			
		||||
	}
 | 
			
		||||
	if prop.Callback != nil {
 | 
			
		||||
		err := prop.Callback(&Change{p, iface, property, newv.Value()})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	p.set(iface, property, newv.Value())
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetMust sets the value of the given property and panics if the interface or
 | 
			
		||||
// the property name are invalid.
 | 
			
		||||
func (p *Properties) SetMust(iface, property string, v interface{}) {
 | 
			
		||||
	p.mut.Lock()
 | 
			
		||||
	p.set(iface, property, v)
 | 
			
		||||
	p.mut.Unlock()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										369
									
								
								vendor/src/github.com/godbus/dbus/proto_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										369
									
								
								vendor/src/github.com/godbus/dbus/proto_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,369 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"math"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var protoTests = []struct {
 | 
			
		||||
	vs           []interface{}
 | 
			
		||||
	bigEndian    []byte
 | 
			
		||||
	littleEndian []byte
 | 
			
		||||
}{
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{int32(0)},
 | 
			
		||||
		[]byte{0, 0, 0, 0},
 | 
			
		||||
		[]byte{0, 0, 0, 0},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{true, false},
 | 
			
		||||
		[]byte{0, 0, 0, 1, 0, 0, 0, 0},
 | 
			
		||||
		[]byte{1, 0, 0, 0, 0, 0, 0, 0},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{byte(0), uint16(12), int16(32), uint32(43)},
 | 
			
		||||
		[]byte{0, 0, 0, 12, 0, 32, 0, 0, 0, 0, 0, 43},
 | 
			
		||||
		[]byte{0, 0, 12, 0, 32, 0, 0, 0, 43, 0, 0, 0},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{int64(-1), uint64(1<<64 - 1)},
 | 
			
		||||
		bytes.Repeat([]byte{255}, 16),
 | 
			
		||||
		bytes.Repeat([]byte{255}, 16),
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{math.Inf(+1)},
 | 
			
		||||
		[]byte{0x7f, 0xf0, 0, 0, 0, 0, 0, 0},
 | 
			
		||||
		[]byte{0, 0, 0, 0, 0, 0, 0xf0, 0x7f},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{"foo"},
 | 
			
		||||
		[]byte{0, 0, 0, 3, 'f', 'o', 'o', 0},
 | 
			
		||||
		[]byte{3, 0, 0, 0, 'f', 'o', 'o', 0},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{Signature{"ai"}},
 | 
			
		||||
		[]byte{2, 'a', 'i', 0},
 | 
			
		||||
		[]byte{2, 'a', 'i', 0},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{[]int16{42, 256}},
 | 
			
		||||
		[]byte{0, 0, 0, 4, 0, 42, 1, 0},
 | 
			
		||||
		[]byte{4, 0, 0, 0, 42, 0, 0, 1},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{MakeVariant("foo")},
 | 
			
		||||
		[]byte{1, 's', 0, 0, 0, 0, 0, 3, 'f', 'o', 'o', 0},
 | 
			
		||||
		[]byte{1, 's', 0, 0, 3, 0, 0, 0, 'f', 'o', 'o', 0},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{MakeVariant(MakeVariant(Signature{"v"}))},
 | 
			
		||||
		[]byte{1, 'v', 0, 1, 'g', 0, 1, 'v', 0},
 | 
			
		||||
		[]byte{1, 'v', 0, 1, 'g', 0, 1, 'v', 0},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{map[int32]bool{42: true}},
 | 
			
		||||
		[]byte{0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 1},
 | 
			
		||||
		[]byte{8, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 1, 0, 0, 0},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{map[string]Variant{}, byte(42)},
 | 
			
		||||
		[]byte{0, 0, 0, 0, 0, 0, 0, 0, 42},
 | 
			
		||||
		[]byte{0, 0, 0, 0, 0, 0, 0, 0, 42},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{[]uint64{}, byte(42)},
 | 
			
		||||
		[]byte{0, 0, 0, 0, 0, 0, 0, 0, 42},
 | 
			
		||||
		[]byte{0, 0, 0, 0, 0, 0, 0, 0, 42},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestProto(t *testing.T) {
 | 
			
		||||
	for i, v := range protoTests {
 | 
			
		||||
		buf := new(bytes.Buffer)
 | 
			
		||||
		bigEnc := newEncoder(buf, binary.BigEndian)
 | 
			
		||||
		bigEnc.Encode(v.vs...)
 | 
			
		||||
		marshalled := buf.Bytes()
 | 
			
		||||
		if bytes.Compare(marshalled, v.bigEndian) != 0 {
 | 
			
		||||
			t.Errorf("test %d (marshal be): got '%v', but expected '%v'\n", i+1, marshalled,
 | 
			
		||||
				v.bigEndian)
 | 
			
		||||
		}
 | 
			
		||||
		buf.Reset()
 | 
			
		||||
		litEnc := newEncoder(buf, binary.LittleEndian)
 | 
			
		||||
		litEnc.Encode(v.vs...)
 | 
			
		||||
		marshalled = buf.Bytes()
 | 
			
		||||
		if bytes.Compare(marshalled, v.littleEndian) != 0 {
 | 
			
		||||
			t.Errorf("test %d (marshal le): got '%v', but expected '%v'\n", i+1, marshalled,
 | 
			
		||||
				v.littleEndian)
 | 
			
		||||
		}
 | 
			
		||||
		unmarshalled := reflect.MakeSlice(reflect.TypeOf(v.vs),
 | 
			
		||||
			0, 0)
 | 
			
		||||
		for i := range v.vs {
 | 
			
		||||
			unmarshalled = reflect.Append(unmarshalled,
 | 
			
		||||
				reflect.New(reflect.TypeOf(v.vs[i])))
 | 
			
		||||
		}
 | 
			
		||||
		bigDec := newDecoder(bytes.NewReader(v.bigEndian), binary.BigEndian)
 | 
			
		||||
		vs, err := bigDec.Decode(SignatureOf(v.vs...))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("test %d (unmarshal be): %s\n", i+1, err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !reflect.DeepEqual(vs, v.vs) {
 | 
			
		||||
			t.Errorf("test %d (unmarshal be): got %#v, but expected %#v\n", i+1, vs, v.vs)
 | 
			
		||||
		}
 | 
			
		||||
		litDec := newDecoder(bytes.NewReader(v.littleEndian), binary.LittleEndian)
 | 
			
		||||
		vs, err = litDec.Decode(SignatureOf(v.vs...))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("test %d (unmarshal le): %s\n", i+1, err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !reflect.DeepEqual(vs, v.vs) {
 | 
			
		||||
			t.Errorf("test %d (unmarshal le): got %#v, but expected %#v\n", i+1, vs, v.vs)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestProtoMap(t *testing.T) {
 | 
			
		||||
	m := map[string]uint8{
 | 
			
		||||
		"foo": 23,
 | 
			
		||||
		"bar": 2,
 | 
			
		||||
	}
 | 
			
		||||
	var n map[string]uint8
 | 
			
		||||
	buf := new(bytes.Buffer)
 | 
			
		||||
	enc := newEncoder(buf, binary.LittleEndian)
 | 
			
		||||
	enc.Encode(m)
 | 
			
		||||
	dec := newDecoder(buf, binary.LittleEndian)
 | 
			
		||||
	vs, err := dec.Decode(Signature{"a{sy}"})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if err = Store(vs, &n); err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if len(n) != 2 || n["foo"] != 23 || n["bar"] != 2 {
 | 
			
		||||
		t.Error("got", n)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestProtoVariantStruct(t *testing.T) {
 | 
			
		||||
	var variant Variant
 | 
			
		||||
	v := MakeVariant(struct {
 | 
			
		||||
		A int32
 | 
			
		||||
		B int16
 | 
			
		||||
	}{1, 2})
 | 
			
		||||
	buf := new(bytes.Buffer)
 | 
			
		||||
	enc := newEncoder(buf, binary.LittleEndian)
 | 
			
		||||
	enc.Encode(v)
 | 
			
		||||
	dec := newDecoder(buf, binary.LittleEndian)
 | 
			
		||||
	vs, err := dec.Decode(Signature{"v"})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if err = Store(vs, &variant); err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	sl := variant.Value().([]interface{})
 | 
			
		||||
	v1, v2 := sl[0].(int32), sl[1].(int16)
 | 
			
		||||
	if v1 != int32(1) {
 | 
			
		||||
		t.Error("got", v1, "as first int")
 | 
			
		||||
	}
 | 
			
		||||
	if v2 != int16(2) {
 | 
			
		||||
		t.Error("got", v2, "as second int")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestProtoStructTag(t *testing.T) {
 | 
			
		||||
	type Bar struct {
 | 
			
		||||
		A int32
 | 
			
		||||
		B chan interface{} `dbus:"-"`
 | 
			
		||||
		C int32
 | 
			
		||||
	}
 | 
			
		||||
	var bar1, bar2 Bar
 | 
			
		||||
	bar1.A = 234
 | 
			
		||||
	bar2.C = 345
 | 
			
		||||
	buf := new(bytes.Buffer)
 | 
			
		||||
	enc := newEncoder(buf, binary.LittleEndian)
 | 
			
		||||
	enc.Encode(bar1)
 | 
			
		||||
	dec := newDecoder(buf, binary.LittleEndian)
 | 
			
		||||
	vs, err := dec.Decode(Signature{"(ii)"})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if err = Store(vs, &bar2); err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if bar1 != bar2 {
 | 
			
		||||
		t.Error("struct tag test: got", bar2)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestProtoStoreStruct(t *testing.T) {
 | 
			
		||||
	var foo struct {
 | 
			
		||||
		A int32
 | 
			
		||||
		B string
 | 
			
		||||
		c chan interface{}
 | 
			
		||||
		D interface{} `dbus:"-"`
 | 
			
		||||
	}
 | 
			
		||||
	src := []interface{}{[]interface{}{int32(42), "foo"}}
 | 
			
		||||
	err := Store(src, &foo)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestProtoStoreNestedStruct(t *testing.T) {
 | 
			
		||||
	var foo struct {
 | 
			
		||||
		A int32
 | 
			
		||||
		B struct {
 | 
			
		||||
			C string
 | 
			
		||||
			D float64
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	src := []interface{}{
 | 
			
		||||
		[]interface{}{
 | 
			
		||||
			int32(42),
 | 
			
		||||
			[]interface{}{
 | 
			
		||||
				"foo",
 | 
			
		||||
				3.14,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	err := Store(src, &foo)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMessage(t *testing.T) {
 | 
			
		||||
	buf := new(bytes.Buffer)
 | 
			
		||||
	message := new(Message)
 | 
			
		||||
	message.Type = TypeMethodCall
 | 
			
		||||
	message.serial = 32
 | 
			
		||||
	message.Headers = map[HeaderField]Variant{
 | 
			
		||||
		FieldPath:   MakeVariant(ObjectPath("/org/foo/bar")),
 | 
			
		||||
		FieldMember: MakeVariant("baz"),
 | 
			
		||||
	}
 | 
			
		||||
	message.Body = make([]interface{}, 0)
 | 
			
		||||
	err := message.EncodeTo(buf, binary.LittleEndian)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
	_, err = DecodeMessage(buf)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestProtoStructInterfaces(t *testing.T) {
 | 
			
		||||
	b := []byte{42}
 | 
			
		||||
	vs, err := newDecoder(bytes.NewReader(b), binary.LittleEndian).Decode(Signature{"(y)"})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if vs[0].([]interface{})[0].(byte) != 42 {
 | 
			
		||||
		t.Errorf("wrongs results (got %v)", vs)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ordinary org.freedesktop.DBus.Hello call
 | 
			
		||||
var smallMessage = &Message{
 | 
			
		||||
	Type:   TypeMethodCall,
 | 
			
		||||
	serial: 1,
 | 
			
		||||
	Headers: map[HeaderField]Variant{
 | 
			
		||||
		FieldDestination: MakeVariant("org.freedesktop.DBus"),
 | 
			
		||||
		FieldPath:        MakeVariant(ObjectPath("/org/freedesktop/DBus")),
 | 
			
		||||
		FieldInterface:   MakeVariant("org.freedesktop.DBus"),
 | 
			
		||||
		FieldMember:      MakeVariant("Hello"),
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// org.freedesktop.Notifications.Notify
 | 
			
		||||
var bigMessage = &Message{
 | 
			
		||||
	Type:   TypeMethodCall,
 | 
			
		||||
	serial: 2,
 | 
			
		||||
	Headers: map[HeaderField]Variant{
 | 
			
		||||
		FieldDestination: MakeVariant("org.freedesktop.Notifications"),
 | 
			
		||||
		FieldPath:        MakeVariant(ObjectPath("/org/freedesktop/Notifications")),
 | 
			
		||||
		FieldInterface:   MakeVariant("org.freedesktop.Notifications"),
 | 
			
		||||
		FieldMember:      MakeVariant("Notify"),
 | 
			
		||||
		FieldSignature:   MakeVariant(Signature{"susssasa{sv}i"}),
 | 
			
		||||
	},
 | 
			
		||||
	Body: []interface{}{
 | 
			
		||||
		"app_name",
 | 
			
		||||
		uint32(0),
 | 
			
		||||
		"dialog-information",
 | 
			
		||||
		"Notification",
 | 
			
		||||
		"This is the body of a notification",
 | 
			
		||||
		[]string{"ok", "Ok"},
 | 
			
		||||
		map[string]Variant{
 | 
			
		||||
			"sound-name": MakeVariant("dialog-information"),
 | 
			
		||||
		},
 | 
			
		||||
		int32(-1),
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkDecodeMessageSmall(b *testing.B) {
 | 
			
		||||
	var err error
 | 
			
		||||
	var rd *bytes.Reader
 | 
			
		||||
 | 
			
		||||
	b.StopTimer()
 | 
			
		||||
	buf := new(bytes.Buffer)
 | 
			
		||||
	err = smallMessage.EncodeTo(buf, binary.LittleEndian)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	decoded := buf.Bytes()
 | 
			
		||||
	b.StartTimer()
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		rd = bytes.NewReader(decoded)
 | 
			
		||||
		_, err = DecodeMessage(rd)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkDecodeMessageBig(b *testing.B) {
 | 
			
		||||
	var err error
 | 
			
		||||
	var rd *bytes.Reader
 | 
			
		||||
 | 
			
		||||
	b.StopTimer()
 | 
			
		||||
	buf := new(bytes.Buffer)
 | 
			
		||||
	err = bigMessage.EncodeTo(buf, binary.LittleEndian)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		b.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	decoded := buf.Bytes()
 | 
			
		||||
	b.StartTimer()
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		rd = bytes.NewReader(decoded)
 | 
			
		||||
		_, err = DecodeMessage(rd)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkEncodeMessageSmall(b *testing.B) {
 | 
			
		||||
	var err error
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		err = smallMessage.EncodeTo(ioutil.Discard, binary.LittleEndian)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkEncodeMessageBig(b *testing.B) {
 | 
			
		||||
	var err error
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		err = bigMessage.EncodeTo(ioutil.Discard, binary.LittleEndian)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			b.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										257
									
								
								vendor/src/github.com/godbus/dbus/sig.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								vendor/src/github.com/godbus/dbus/sig.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,257 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var sigToType = map[byte]reflect.Type{
 | 
			
		||||
	'y': byteType,
 | 
			
		||||
	'b': boolType,
 | 
			
		||||
	'n': int16Type,
 | 
			
		||||
	'q': uint16Type,
 | 
			
		||||
	'i': int32Type,
 | 
			
		||||
	'u': uint32Type,
 | 
			
		||||
	'x': int64Type,
 | 
			
		||||
	't': uint64Type,
 | 
			
		||||
	'd': float64Type,
 | 
			
		||||
	's': stringType,
 | 
			
		||||
	'g': signatureType,
 | 
			
		||||
	'o': objectPathType,
 | 
			
		||||
	'v': variantType,
 | 
			
		||||
	'h': unixFDIndexType,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Signature represents a correct type signature as specified by the D-Bus
 | 
			
		||||
// specification. The zero value represents the empty signature, "".
 | 
			
		||||
type Signature struct {
 | 
			
		||||
	str string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SignatureOf returns the concatenation of all the signatures of the given
 | 
			
		||||
// values. It panics if one of them is not representable in D-Bus.
 | 
			
		||||
func SignatureOf(vs ...interface{}) Signature {
 | 
			
		||||
	var s string
 | 
			
		||||
	for _, v := range vs {
 | 
			
		||||
		s += getSignature(reflect.TypeOf(v))
 | 
			
		||||
	}
 | 
			
		||||
	return Signature{s}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SignatureOfType returns the signature of the given type. It panics if the
 | 
			
		||||
// type is not representable in D-Bus.
 | 
			
		||||
func SignatureOfType(t reflect.Type) Signature {
 | 
			
		||||
	return Signature{getSignature(t)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getSignature returns the signature of the given type and panics on unknown types.
 | 
			
		||||
func getSignature(t reflect.Type) string {
 | 
			
		||||
	// handle simple types first
 | 
			
		||||
	switch t.Kind() {
 | 
			
		||||
	case reflect.Uint8:
 | 
			
		||||
		return "y"
 | 
			
		||||
	case reflect.Bool:
 | 
			
		||||
		return "b"
 | 
			
		||||
	case reflect.Int16:
 | 
			
		||||
		return "n"
 | 
			
		||||
	case reflect.Uint16:
 | 
			
		||||
		return "q"
 | 
			
		||||
	case reflect.Int32:
 | 
			
		||||
		if t == unixFDType {
 | 
			
		||||
			return "h"
 | 
			
		||||
		}
 | 
			
		||||
		return "i"
 | 
			
		||||
	case reflect.Uint32:
 | 
			
		||||
		if t == unixFDIndexType {
 | 
			
		||||
			return "h"
 | 
			
		||||
		}
 | 
			
		||||
		return "u"
 | 
			
		||||
	case reflect.Int64:
 | 
			
		||||
		return "x"
 | 
			
		||||
	case reflect.Uint64:
 | 
			
		||||
		return "t"
 | 
			
		||||
	case reflect.Float64:
 | 
			
		||||
		return "d"
 | 
			
		||||
	case reflect.Ptr:
 | 
			
		||||
		return getSignature(t.Elem())
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		if t == objectPathType {
 | 
			
		||||
			return "o"
 | 
			
		||||
		}
 | 
			
		||||
		return "s"
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		if t == variantType {
 | 
			
		||||
			return "v"
 | 
			
		||||
		} else if t == signatureType {
 | 
			
		||||
			return "g"
 | 
			
		||||
		}
 | 
			
		||||
		var s string
 | 
			
		||||
		for i := 0; i < t.NumField(); i++ {
 | 
			
		||||
			field := t.Field(i)
 | 
			
		||||
			if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
 | 
			
		||||
				s += getSignature(t.Field(i).Type)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return "(" + s + ")"
 | 
			
		||||
	case reflect.Array, reflect.Slice:
 | 
			
		||||
		return "a" + getSignature(t.Elem())
 | 
			
		||||
	case reflect.Map:
 | 
			
		||||
		if !isKeyType(t.Key()) {
 | 
			
		||||
			panic(InvalidTypeError{t})
 | 
			
		||||
		}
 | 
			
		||||
		return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}"
 | 
			
		||||
	}
 | 
			
		||||
	panic(InvalidTypeError{t})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseSignature returns the signature represented by this string, or a
 | 
			
		||||
// SignatureError if the string is not a valid signature.
 | 
			
		||||
func ParseSignature(s string) (sig Signature, err error) {
 | 
			
		||||
	if len(s) == 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if len(s) > 255 {
 | 
			
		||||
		return Signature{""}, SignatureError{s, "too long"}
 | 
			
		||||
	}
 | 
			
		||||
	sig.str = s
 | 
			
		||||
	for err == nil && len(s) != 0 {
 | 
			
		||||
		err, s = validSingle(s, 0)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		sig = Signature{""}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseSignatureMust behaves like ParseSignature, except that it panics if s
 | 
			
		||||
// is not valid.
 | 
			
		||||
func ParseSignatureMust(s string) Signature {
 | 
			
		||||
	sig, err := ParseSignature(s)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	return sig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Empty retruns whether the signature is the empty signature.
 | 
			
		||||
func (s Signature) Empty() bool {
 | 
			
		||||
	return s.str == ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Single returns whether the signature represents a single, complete type.
 | 
			
		||||
func (s Signature) Single() bool {
 | 
			
		||||
	err, r := validSingle(s.str, 0)
 | 
			
		||||
	return err != nil && r == ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String returns the signature's string representation.
 | 
			
		||||
func (s Signature) String() string {
 | 
			
		||||
	return s.str
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A SignatureError indicates that a signature passed to a function or received
 | 
			
		||||
// on a connection is not a valid signature.
 | 
			
		||||
type SignatureError struct {
 | 
			
		||||
	Sig    string
 | 
			
		||||
	Reason string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e SignatureError) Error() string {
 | 
			
		||||
	return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Try to read a single type from this string. If it was successfull, err is nil
 | 
			
		||||
// and rem is the remaining unparsed part. Otherwise, err is a non-nil
 | 
			
		||||
// SignatureError and rem is "". depth is the current recursion depth which may
 | 
			
		||||
// not be greater than 64 and should be given as 0 on the first call.
 | 
			
		||||
func validSingle(s string, depth int) (err error, rem string) {
 | 
			
		||||
	if s == "" {
 | 
			
		||||
		return SignatureError{Sig: s, Reason: "empty signature"}, ""
 | 
			
		||||
	}
 | 
			
		||||
	if depth > 64 {
 | 
			
		||||
		return SignatureError{Sig: s, Reason: "container nesting too deep"}, ""
 | 
			
		||||
	}
 | 
			
		||||
	switch s[0] {
 | 
			
		||||
	case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'g', 'o', 'v', 'h':
 | 
			
		||||
		return nil, s[1:]
 | 
			
		||||
	case 'a':
 | 
			
		||||
		if len(s) > 1 && s[1] == '{' {
 | 
			
		||||
			i := findMatching(s[1:], '{', '}')
 | 
			
		||||
			if i == -1 {
 | 
			
		||||
				return SignatureError{Sig: s, Reason: "unmatched '{'"}, ""
 | 
			
		||||
			}
 | 
			
		||||
			i++
 | 
			
		||||
			rem = s[i+1:]
 | 
			
		||||
			s = s[2:i]
 | 
			
		||||
			if err, _ = validSingle(s[:1], depth+1); err != nil {
 | 
			
		||||
				return err, ""
 | 
			
		||||
			}
 | 
			
		||||
			err, nr := validSingle(s[1:], depth+1)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err, ""
 | 
			
		||||
			}
 | 
			
		||||
			if nr != "" {
 | 
			
		||||
				return SignatureError{Sig: s, Reason: "too many types in dict"}, ""
 | 
			
		||||
			}
 | 
			
		||||
			return nil, rem
 | 
			
		||||
		}
 | 
			
		||||
		return validSingle(s[1:], depth+1)
 | 
			
		||||
	case '(':
 | 
			
		||||
		i := findMatching(s, '(', ')')
 | 
			
		||||
		if i == -1 {
 | 
			
		||||
			return SignatureError{Sig: s, Reason: "unmatched ')'"}, ""
 | 
			
		||||
		}
 | 
			
		||||
		rem = s[i+1:]
 | 
			
		||||
		s = s[1:i]
 | 
			
		||||
		for err == nil && s != "" {
 | 
			
		||||
			err, s = validSingle(s, depth+1)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			rem = ""
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return SignatureError{Sig: s, Reason: "invalid type character"}, ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func findMatching(s string, left, right rune) int {
 | 
			
		||||
	n := 0
 | 
			
		||||
	for i, v := range s {
 | 
			
		||||
		if v == left {
 | 
			
		||||
			n++
 | 
			
		||||
		} else if v == right {
 | 
			
		||||
			n--
 | 
			
		||||
		}
 | 
			
		||||
		if n == 0 {
 | 
			
		||||
			return i
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return -1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// typeFor returns the type of the given signature. It ignores any left over
 | 
			
		||||
// characters and panics if s doesn't start with a valid type signature.
 | 
			
		||||
func typeFor(s string) (t reflect.Type) {
 | 
			
		||||
	err, _ := validSingle(s, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if t, ok := sigToType[s[0]]; ok {
 | 
			
		||||
		return t
 | 
			
		||||
	}
 | 
			
		||||
	switch s[0] {
 | 
			
		||||
	case 'a':
 | 
			
		||||
		if s[1] == '{' {
 | 
			
		||||
			i := strings.LastIndex(s, "}")
 | 
			
		||||
			t = reflect.MapOf(sigToType[s[2]], typeFor(s[3:i]))
 | 
			
		||||
		} else {
 | 
			
		||||
			t = reflect.SliceOf(typeFor(s[1:]))
 | 
			
		||||
		}
 | 
			
		||||
	case '(':
 | 
			
		||||
		t = interfacesType
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								vendor/src/github.com/godbus/dbus/sig_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								vendor/src/github.com/godbus/dbus/sig_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var sigTests = []struct {
 | 
			
		||||
	vs  []interface{}
 | 
			
		||||
	sig Signature
 | 
			
		||||
}{
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{new(int32)},
 | 
			
		||||
		Signature{"i"},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{new(string)},
 | 
			
		||||
		Signature{"s"},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{new(Signature)},
 | 
			
		||||
		Signature{"g"},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{new([]int16)},
 | 
			
		||||
		Signature{"an"},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{new(int16), new(uint32)},
 | 
			
		||||
		Signature{"nu"},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{new(map[byte]Variant)},
 | 
			
		||||
		Signature{"a{yv}"},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		[]interface{}{new(Variant), new([]map[int32]string)},
 | 
			
		||||
		Signature{"vaa{is}"},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSig(t *testing.T) {
 | 
			
		||||
	for i, v := range sigTests {
 | 
			
		||||
		sig := SignatureOf(v.vs...)
 | 
			
		||||
		if sig != v.sig {
 | 
			
		||||
			t.Errorf("test %d: got %q, expected %q", i+1, sig.str, v.sig.str)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var getSigTest = []interface{}{
 | 
			
		||||
	[]struct {
 | 
			
		||||
		b byte
 | 
			
		||||
		i int32
 | 
			
		||||
		t uint64
 | 
			
		||||
		s string
 | 
			
		||||
	}{},
 | 
			
		||||
	map[string]Variant{},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkGetSignatureSimple(b *testing.B) {
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		SignatureOf("", int32(0))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkGetSignatureLong(b *testing.B) {
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		SignatureOf(getSigTest...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/src/github.com/godbus/dbus/transport_darwin.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								vendor/src/github.com/godbus/dbus/transport_darwin.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
func (t *unixTransport) SendNullByte() error {
 | 
			
		||||
	_, err := t.Write([]byte{0})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								vendor/src/github.com/godbus/dbus/transport_generic.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								vendor/src/github.com/godbus/dbus/transport_generic.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type genericTransport struct {
 | 
			
		||||
	io.ReadWriteCloser
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t genericTransport) SendNullByte() error {
 | 
			
		||||
	_, err := t.Write([]byte{0})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t genericTransport) SupportsUnixFDs() bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t genericTransport) EnableUnixFDs() {}
 | 
			
		||||
 | 
			
		||||
func (t genericTransport) ReadMessage() (*Message, error) {
 | 
			
		||||
	return DecodeMessage(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t genericTransport) SendMessage(msg *Message) error {
 | 
			
		||||
	for _, v := range msg.Body {
 | 
			
		||||
		if _, ok := v.(UnixFD); ok {
 | 
			
		||||
			return errors.New("dbus: unix fd passing not enabled")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return msg.EncodeTo(t, binary.LittleEndian)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										190
									
								
								vendor/src/github.com/godbus/dbus/transport_unix.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								vendor/src/github.com/godbus/dbus/transport_unix.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,190 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type oobReader struct {
 | 
			
		||||
	conn *net.UnixConn
 | 
			
		||||
	oob  []byte
 | 
			
		||||
	buf  [4096]byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o *oobReader) Read(b []byte) (n int, err error) {
 | 
			
		||||
	n, oobn, flags, _, err := o.conn.ReadMsgUnix(b, o.buf[:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return n, err
 | 
			
		||||
	}
 | 
			
		||||
	if flags&syscall.MSG_CTRUNC != 0 {
 | 
			
		||||
		return n, errors.New("dbus: control data truncated (too many fds received)")
 | 
			
		||||
	}
 | 
			
		||||
	o.oob = append(o.oob, o.buf[:oobn]...)
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type unixTransport struct {
 | 
			
		||||
	*net.UnixConn
 | 
			
		||||
	hasUnixFDs bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newUnixTransport(keys string) (transport, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	t := new(unixTransport)
 | 
			
		||||
	abstract := getKey(keys, "abstract")
 | 
			
		||||
	path := getKey(keys, "path")
 | 
			
		||||
	switch {
 | 
			
		||||
	case abstract == "" && path == "":
 | 
			
		||||
		return nil, errors.New("dbus: invalid address (neither path nor abstract set)")
 | 
			
		||||
	case abstract != "" && path == "":
 | 
			
		||||
		t.UnixConn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: "@" + abstract, Net: "unix"})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return t, nil
 | 
			
		||||
	case abstract == "" && path != "":
 | 
			
		||||
		t.UnixConn, err = net.DialUnix("unix", nil, &net.UnixAddr{Name: path, Net: "unix"})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return t, nil
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, errors.New("dbus: invalid address (both path and abstract set)")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *unixTransport) EnableUnixFDs() {
 | 
			
		||||
	t.hasUnixFDs = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *unixTransport) ReadMessage() (*Message, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		blen, hlen uint32
 | 
			
		||||
		csheader   [16]byte
 | 
			
		||||
		headers    []header
 | 
			
		||||
		order      binary.ByteOrder
 | 
			
		||||
		unixfds    uint32
 | 
			
		||||
	)
 | 
			
		||||
	// To be sure that all bytes of out-of-band data are read, we use a special
 | 
			
		||||
	// reader that uses ReadUnix on the underlying connection instead of Read
 | 
			
		||||
	// and gathers the out-of-band data in a buffer.
 | 
			
		||||
	rd := &oobReader{conn: t.UnixConn}
 | 
			
		||||
	// read the first 16 bytes (the part of the header that has a constant size),
 | 
			
		||||
	// from which we can figure out the length of the rest of the message
 | 
			
		||||
	if _, err := io.ReadFull(rd, csheader[:]); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	switch csheader[0] {
 | 
			
		||||
	case 'l':
 | 
			
		||||
		order = binary.LittleEndian
 | 
			
		||||
	case 'B':
 | 
			
		||||
		order = binary.BigEndian
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, InvalidMessageError("invalid byte order")
 | 
			
		||||
	}
 | 
			
		||||
	// csheader[4:8] -> length of message body, csheader[12:16] -> length of
 | 
			
		||||
	// header fields (without alignment)
 | 
			
		||||
	binary.Read(bytes.NewBuffer(csheader[4:8]), order, &blen)
 | 
			
		||||
	binary.Read(bytes.NewBuffer(csheader[12:]), order, &hlen)
 | 
			
		||||
	if hlen%8 != 0 {
 | 
			
		||||
		hlen += 8 - (hlen % 8)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// decode headers and look for unix fds
 | 
			
		||||
	headerdata := make([]byte, hlen+4)
 | 
			
		||||
	copy(headerdata, csheader[12:])
 | 
			
		||||
	if _, err := io.ReadFull(t, headerdata[4:]); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	dec := newDecoder(bytes.NewBuffer(headerdata), order)
 | 
			
		||||
	dec.pos = 12
 | 
			
		||||
	vs, err := dec.Decode(Signature{"a(yv)"})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	Store(vs, &headers)
 | 
			
		||||
	for _, v := range headers {
 | 
			
		||||
		if v.Field == byte(FieldUnixFDs) {
 | 
			
		||||
			unixfds, _ = v.Variant.value.(uint32)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	all := make([]byte, 16+hlen+blen)
 | 
			
		||||
	copy(all, csheader[:])
 | 
			
		||||
	copy(all[16:], headerdata[4:])
 | 
			
		||||
	if _, err := io.ReadFull(rd, all[16+hlen:]); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if unixfds != 0 {
 | 
			
		||||
		if !t.hasUnixFDs {
 | 
			
		||||
			return nil, errors.New("dbus: got unix fds on unsupported transport")
 | 
			
		||||
		}
 | 
			
		||||
		// read the fds from the OOB data
 | 
			
		||||
		scms, err := syscall.ParseSocketControlMessage(rd.oob)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if len(scms) != 1 {
 | 
			
		||||
			return nil, errors.New("dbus: received more than one socket control message")
 | 
			
		||||
		}
 | 
			
		||||
		fds, err := syscall.ParseUnixRights(&scms[0])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		msg, err := DecodeMessage(bytes.NewBuffer(all))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		// substitute the values in the message body (which are indices for the
 | 
			
		||||
		// array receiver via OOB) with the actual values
 | 
			
		||||
		for i, v := range msg.Body {
 | 
			
		||||
			if j, ok := v.(UnixFDIndex); ok {
 | 
			
		||||
				if uint32(j) >= unixfds {
 | 
			
		||||
					return nil, InvalidMessageError("invalid index for unix fd")
 | 
			
		||||
				}
 | 
			
		||||
				msg.Body[i] = UnixFD(fds[j])
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return msg, nil
 | 
			
		||||
	}
 | 
			
		||||
	return DecodeMessage(bytes.NewBuffer(all))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *unixTransport) SendMessage(msg *Message) error {
 | 
			
		||||
	fds := make([]int, 0)
 | 
			
		||||
	for i, v := range msg.Body {
 | 
			
		||||
		if fd, ok := v.(UnixFD); ok {
 | 
			
		||||
			msg.Body[i] = UnixFDIndex(len(fds))
 | 
			
		||||
			fds = append(fds, int(fd))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(fds) != 0 {
 | 
			
		||||
		if !t.hasUnixFDs {
 | 
			
		||||
			return errors.New("dbus: unix fd passing not enabled")
 | 
			
		||||
		}
 | 
			
		||||
		msg.Headers[FieldUnixFDs] = MakeVariant(uint32(len(fds)))
 | 
			
		||||
		oob := syscall.UnixRights(fds...)
 | 
			
		||||
		buf := new(bytes.Buffer)
 | 
			
		||||
		msg.EncodeTo(buf, binary.LittleEndian)
 | 
			
		||||
		n, oobn, err := t.UnixConn.WriteMsgUnix(buf.Bytes(), oob, nil)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if n != buf.Len() || oobn != len(oob) {
 | 
			
		||||
			return io.ErrShortWrite
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if err := msg.EncodeTo(t, binary.LittleEndian); err != nil {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *unixTransport) SupportsUnixFDs() bool {
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								vendor/src/github.com/godbus/dbus/transport_unix_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								vendor/src/github.com/godbus/dbus/transport_unix_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,49 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const testString = `This is a test!
 | 
			
		||||
This text should be read from the file that is created by this test.`
 | 
			
		||||
 | 
			
		||||
type unixFDTest struct{}
 | 
			
		||||
 | 
			
		||||
func (t unixFDTest) Test(fd UnixFD) (string, *Error) {
 | 
			
		||||
	var b [4096]byte
 | 
			
		||||
	file := os.NewFile(uintptr(fd), "testfile")
 | 
			
		||||
	defer file.Close()
 | 
			
		||||
	n, err := file.Read(b[:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", &Error{"com.github.guelfey.test.Error", nil}
 | 
			
		||||
	}
 | 
			
		||||
	return string(b[:n]), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUnixFDs(t *testing.T) {
 | 
			
		||||
	conn, err := SessionBus()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	r, w, err := os.Pipe()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	defer w.Close()
 | 
			
		||||
	if _, err := w.Write([]byte(testString)); err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	name := conn.Names()[0]
 | 
			
		||||
	test := unixFDTest{}
 | 
			
		||||
	conn.Export(test, "/com/github/guelfey/test", "com.github.guelfey.test")
 | 
			
		||||
	var s string
 | 
			
		||||
	obj := conn.Object(name, "/com/github/guelfey/test")
 | 
			
		||||
	err = obj.Call("com.github.guelfey.test.Test", 0, UnixFD(r.Fd())).Store(&s)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if s != testString {
 | 
			
		||||
		t.Fatal("got", s, "wanted", testString)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/src/github.com/godbus/dbus/transport_unixcred.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/src/github.com/godbus/dbus/transport_unixcred.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
// +build !darwin
 | 
			
		||||
 | 
			
		||||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (t *unixTransport) SendNullByte() error {
 | 
			
		||||
	ucred := &syscall.Ucred{Pid: int32(os.Getpid()), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid())}
 | 
			
		||||
	b := syscall.UnixCredentials(ucred)
 | 
			
		||||
	_, oobn, err := t.UnixConn.WriteMsgUnix([]byte{0}, b, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if oobn != len(b) {
 | 
			
		||||
		return io.ErrShortWrite
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										129
									
								
								vendor/src/github.com/godbus/dbus/variant.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								vendor/src/github.com/godbus/dbus/variant.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,129 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Variant represents the D-Bus variant type.
 | 
			
		||||
type Variant struct {
 | 
			
		||||
	sig   Signature
 | 
			
		||||
	value interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MakeVariant converts the given value to a Variant. It panics if v cannot be
 | 
			
		||||
// represented as a D-Bus type.
 | 
			
		||||
func MakeVariant(v interface{}) Variant {
 | 
			
		||||
	return Variant{SignatureOf(v), v}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseVariant parses the given string as a variant as described at
 | 
			
		||||
// https://developer.gnome.org/glib/unstable/gvariant-text.html. If sig is not
 | 
			
		||||
// empty, it is taken to be the expected signature for the variant.
 | 
			
		||||
func ParseVariant(s string, sig Signature) (Variant, error) {
 | 
			
		||||
	tokens := varLex(s)
 | 
			
		||||
	p := &varParser{tokens: tokens}
 | 
			
		||||
	n, err := varMakeNode(p)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return Variant{}, err
 | 
			
		||||
	}
 | 
			
		||||
	if sig.str == "" {
 | 
			
		||||
		sig, err = varInfer(n)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return Variant{}, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	v, err := n.Value(sig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return Variant{}, err
 | 
			
		||||
	}
 | 
			
		||||
	return MakeVariant(v), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// format returns a formatted version of v and whether this string can be parsed
 | 
			
		||||
// unambigously.
 | 
			
		||||
func (v Variant) format() (string, bool) {
 | 
			
		||||
	switch v.sig.str[0] {
 | 
			
		||||
	case 'b', 'i':
 | 
			
		||||
		return fmt.Sprint(v.value), true
 | 
			
		||||
	case 'n', 'q', 'u', 'x', 't', 'd', 'h':
 | 
			
		||||
		return fmt.Sprint(v.value), false
 | 
			
		||||
	case 's':
 | 
			
		||||
		return strconv.Quote(v.value.(string)), true
 | 
			
		||||
	case 'o':
 | 
			
		||||
		return strconv.Quote(string(v.value.(ObjectPath))), false
 | 
			
		||||
	case 'g':
 | 
			
		||||
		return strconv.Quote(v.value.(Signature).str), false
 | 
			
		||||
	case 'v':
 | 
			
		||||
		s, unamb := v.value.(Variant).format()
 | 
			
		||||
		if !unamb {
 | 
			
		||||
			return "<@" + v.value.(Variant).sig.str + " " + s + ">", true
 | 
			
		||||
		}
 | 
			
		||||
		return "<" + s + ">", true
 | 
			
		||||
	case 'y':
 | 
			
		||||
		return fmt.Sprintf("%#x", v.value.(byte)), false
 | 
			
		||||
	}
 | 
			
		||||
	rv := reflect.ValueOf(v.value)
 | 
			
		||||
	switch rv.Kind() {
 | 
			
		||||
	case reflect.Slice:
 | 
			
		||||
		if rv.Len() == 0 {
 | 
			
		||||
			return "[]", false
 | 
			
		||||
		}
 | 
			
		||||
		unamb := true
 | 
			
		||||
		buf := bytes.NewBuffer([]byte("["))
 | 
			
		||||
		for i := 0; i < rv.Len(); i++ {
 | 
			
		||||
			// TODO: slooow
 | 
			
		||||
			s, b := MakeVariant(rv.Index(i).Interface()).format()
 | 
			
		||||
			unamb = unamb && b
 | 
			
		||||
			buf.WriteString(s)
 | 
			
		||||
			if i != rv.Len()-1 {
 | 
			
		||||
				buf.WriteString(", ")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		buf.WriteByte(']')
 | 
			
		||||
		return buf.String(), unamb
 | 
			
		||||
	case reflect.Map:
 | 
			
		||||
		if rv.Len() == 0 {
 | 
			
		||||
			return "{}", false
 | 
			
		||||
		}
 | 
			
		||||
		unamb := true
 | 
			
		||||
		buf := bytes.NewBuffer([]byte("{"))
 | 
			
		||||
		for i, k := range rv.MapKeys() {
 | 
			
		||||
			s, b := MakeVariant(k.Interface()).format()
 | 
			
		||||
			unamb = unamb && b
 | 
			
		||||
			buf.WriteString(s)
 | 
			
		||||
			buf.WriteString(": ")
 | 
			
		||||
			s, b = MakeVariant(rv.MapIndex(k).Interface()).format()
 | 
			
		||||
			unamb = unamb && b
 | 
			
		||||
			buf.WriteString(s)
 | 
			
		||||
			if i != rv.Len()-1 {
 | 
			
		||||
				buf.WriteString(", ")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		buf.WriteByte('}')
 | 
			
		||||
		return buf.String(), unamb
 | 
			
		||||
	}
 | 
			
		||||
	return `"INVALID"`, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Signature returns the D-Bus signature of the underlying value of v.
 | 
			
		||||
func (v Variant) Signature() Signature {
 | 
			
		||||
	return v.sig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// String returns the string representation of the underlying value of v as
 | 
			
		||||
// described at https://developer.gnome.org/glib/unstable/gvariant-text.html.
 | 
			
		||||
func (v Variant) String() string {
 | 
			
		||||
	s, unamb := v.format()
 | 
			
		||||
	if !unamb {
 | 
			
		||||
		return "@" + v.sig.str + " " + s
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Value returns the underlying value of v.
 | 
			
		||||
func (v Variant) Value() interface{} {
 | 
			
		||||
	return v.value
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										284
									
								
								vendor/src/github.com/godbus/dbus/variant_lexer.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								vendor/src/github.com/godbus/dbus/variant_lexer.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,284 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Heavily inspired by the lexer from text/template.
 | 
			
		||||
 | 
			
		||||
type varToken struct {
 | 
			
		||||
	typ varTokenType
 | 
			
		||||
	val string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type varTokenType byte
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	tokEOF varTokenType = iota
 | 
			
		||||
	tokError
 | 
			
		||||
	tokNumber
 | 
			
		||||
	tokString
 | 
			
		||||
	tokBool
 | 
			
		||||
	tokArrayStart
 | 
			
		||||
	tokArrayEnd
 | 
			
		||||
	tokDictStart
 | 
			
		||||
	tokDictEnd
 | 
			
		||||
	tokVariantStart
 | 
			
		||||
	tokVariantEnd
 | 
			
		||||
	tokComma
 | 
			
		||||
	tokColon
 | 
			
		||||
	tokType
 | 
			
		||||
	tokByteString
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type varLexer struct {
 | 
			
		||||
	input  string
 | 
			
		||||
	start  int
 | 
			
		||||
	pos    int
 | 
			
		||||
	width  int
 | 
			
		||||
	tokens []varToken
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type lexState func(*varLexer) lexState
 | 
			
		||||
 | 
			
		||||
func varLex(s string) []varToken {
 | 
			
		||||
	l := &varLexer{input: s}
 | 
			
		||||
	l.run()
 | 
			
		||||
	return l.tokens
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *varLexer) accept(valid string) bool {
 | 
			
		||||
	if strings.IndexRune(valid, l.next()) >= 0 {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	l.backup()
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *varLexer) backup() {
 | 
			
		||||
	l.pos -= l.width
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *varLexer) emit(t varTokenType) {
 | 
			
		||||
	l.tokens = append(l.tokens, varToken{t, l.input[l.start:l.pos]})
 | 
			
		||||
	l.start = l.pos
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *varLexer) errorf(format string, v ...interface{}) lexState {
 | 
			
		||||
	l.tokens = append(l.tokens, varToken{
 | 
			
		||||
		tokError,
 | 
			
		||||
		fmt.Sprintf(format, v...),
 | 
			
		||||
	})
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *varLexer) ignore() {
 | 
			
		||||
	l.start = l.pos
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *varLexer) next() rune {
 | 
			
		||||
	var r rune
 | 
			
		||||
 | 
			
		||||
	if l.pos >= len(l.input) {
 | 
			
		||||
		l.width = 0
 | 
			
		||||
		return -1
 | 
			
		||||
	}
 | 
			
		||||
	r, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
 | 
			
		||||
	l.pos += l.width
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *varLexer) run() {
 | 
			
		||||
	for state := varLexNormal; state != nil; {
 | 
			
		||||
		state = state(l)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *varLexer) peek() rune {
 | 
			
		||||
	r := l.next()
 | 
			
		||||
	l.backup()
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varLexNormal(l *varLexer) lexState {
 | 
			
		||||
	for {
 | 
			
		||||
		r := l.next()
 | 
			
		||||
		switch {
 | 
			
		||||
		case r == -1:
 | 
			
		||||
			l.emit(tokEOF)
 | 
			
		||||
			return nil
 | 
			
		||||
		case r == '[':
 | 
			
		||||
			l.emit(tokArrayStart)
 | 
			
		||||
		case r == ']':
 | 
			
		||||
			l.emit(tokArrayEnd)
 | 
			
		||||
		case r == '{':
 | 
			
		||||
			l.emit(tokDictStart)
 | 
			
		||||
		case r == '}':
 | 
			
		||||
			l.emit(tokDictEnd)
 | 
			
		||||
		case r == '<':
 | 
			
		||||
			l.emit(tokVariantStart)
 | 
			
		||||
		case r == '>':
 | 
			
		||||
			l.emit(tokVariantEnd)
 | 
			
		||||
		case r == ':':
 | 
			
		||||
			l.emit(tokColon)
 | 
			
		||||
		case r == ',':
 | 
			
		||||
			l.emit(tokComma)
 | 
			
		||||
		case r == '\'' || r == '"':
 | 
			
		||||
			l.backup()
 | 
			
		||||
			return varLexString
 | 
			
		||||
		case r == '@':
 | 
			
		||||
			l.backup()
 | 
			
		||||
			return varLexType
 | 
			
		||||
		case unicode.IsSpace(r):
 | 
			
		||||
			l.ignore()
 | 
			
		||||
		case unicode.IsNumber(r) || r == '+' || r == '-':
 | 
			
		||||
			l.backup()
 | 
			
		||||
			return varLexNumber
 | 
			
		||||
		case r == 'b':
 | 
			
		||||
			pos := l.start
 | 
			
		||||
			if n := l.peek(); n == '"' || n == '\'' {
 | 
			
		||||
				return varLexByteString
 | 
			
		||||
			}
 | 
			
		||||
			// not a byte string; try to parse it as a type or bool below
 | 
			
		||||
			l.pos = pos + 1
 | 
			
		||||
			l.width = 1
 | 
			
		||||
			fallthrough
 | 
			
		||||
		default:
 | 
			
		||||
			// either a bool or a type. Try bools first.
 | 
			
		||||
			l.backup()
 | 
			
		||||
			if l.pos+4 <= len(l.input) {
 | 
			
		||||
				if l.input[l.pos:l.pos+4] == "true" {
 | 
			
		||||
					l.pos += 4
 | 
			
		||||
					l.emit(tokBool)
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if l.pos+5 <= len(l.input) {
 | 
			
		||||
				if l.input[l.pos:l.pos+5] == "false" {
 | 
			
		||||
					l.pos += 5
 | 
			
		||||
					l.emit(tokBool)
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			// must be a type.
 | 
			
		||||
			return varLexType
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var varTypeMap = map[string]string{
 | 
			
		||||
	"boolean":    "b",
 | 
			
		||||
	"byte":       "y",
 | 
			
		||||
	"int16":      "n",
 | 
			
		||||
	"uint16":     "q",
 | 
			
		||||
	"int32":      "i",
 | 
			
		||||
	"uint32":     "u",
 | 
			
		||||
	"int64":      "x",
 | 
			
		||||
	"uint64":     "t",
 | 
			
		||||
	"double":     "f",
 | 
			
		||||
	"string":     "s",
 | 
			
		||||
	"objectpath": "o",
 | 
			
		||||
	"signature":  "g",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varLexByteString(l *varLexer) lexState {
 | 
			
		||||
	q := l.next()
 | 
			
		||||
Loop:
 | 
			
		||||
	for {
 | 
			
		||||
		switch l.next() {
 | 
			
		||||
		case '\\':
 | 
			
		||||
			if r := l.next(); r != -1 {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			fallthrough
 | 
			
		||||
		case -1:
 | 
			
		||||
			return l.errorf("unterminated bytestring")
 | 
			
		||||
		case q:
 | 
			
		||||
			break Loop
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	l.emit(tokByteString)
 | 
			
		||||
	return varLexNormal
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varLexNumber(l *varLexer) lexState {
 | 
			
		||||
	l.accept("+-")
 | 
			
		||||
	digits := "0123456789"
 | 
			
		||||
	if l.accept("0") {
 | 
			
		||||
		if l.accept("x") {
 | 
			
		||||
			digits = "0123456789abcdefABCDEF"
 | 
			
		||||
		} else {
 | 
			
		||||
			digits = "01234567"
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for strings.IndexRune(digits, l.next()) >= 0 {
 | 
			
		||||
	}
 | 
			
		||||
	l.backup()
 | 
			
		||||
	if l.accept(".") {
 | 
			
		||||
		for strings.IndexRune(digits, l.next()) >= 0 {
 | 
			
		||||
		}
 | 
			
		||||
		l.backup()
 | 
			
		||||
	}
 | 
			
		||||
	if l.accept("eE") {
 | 
			
		||||
		l.accept("+-")
 | 
			
		||||
		for strings.IndexRune("0123456789", l.next()) >= 0 {
 | 
			
		||||
		}
 | 
			
		||||
		l.backup()
 | 
			
		||||
	}
 | 
			
		||||
	if r := l.peek(); unicode.IsLetter(r) {
 | 
			
		||||
		l.next()
 | 
			
		||||
		return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
 | 
			
		||||
	}
 | 
			
		||||
	l.emit(tokNumber)
 | 
			
		||||
	return varLexNormal
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varLexString(l *varLexer) lexState {
 | 
			
		||||
	q := l.next()
 | 
			
		||||
Loop:
 | 
			
		||||
	for {
 | 
			
		||||
		switch l.next() {
 | 
			
		||||
		case '\\':
 | 
			
		||||
			if r := l.next(); r != -1 {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			fallthrough
 | 
			
		||||
		case -1:
 | 
			
		||||
			return l.errorf("unterminated string")
 | 
			
		||||
		case q:
 | 
			
		||||
			break Loop
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	l.emit(tokString)
 | 
			
		||||
	return varLexNormal
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varLexType(l *varLexer) lexState {
 | 
			
		||||
	at := l.accept("@")
 | 
			
		||||
	for {
 | 
			
		||||
		r := l.next()
 | 
			
		||||
		if r == -1 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		if unicode.IsSpace(r) {
 | 
			
		||||
			l.backup()
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if at {
 | 
			
		||||
		if _, err := ParseSignature(l.input[l.start+1 : l.pos]); err != nil {
 | 
			
		||||
			return l.errorf("%s", err)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if _, ok := varTypeMap[l.input[l.start:l.pos]]; ok {
 | 
			
		||||
			l.emit(tokType)
 | 
			
		||||
			return varLexNormal
 | 
			
		||||
		}
 | 
			
		||||
		return l.errorf("unrecognized type %q", l.input[l.start:l.pos])
 | 
			
		||||
	}
 | 
			
		||||
	l.emit(tokType)
 | 
			
		||||
	return varLexNormal
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										817
									
								
								vendor/src/github.com/godbus/dbus/variant_parser.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										817
									
								
								vendor/src/github.com/godbus/dbus/variant_parser.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,817 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type varParser struct {
 | 
			
		||||
	tokens []varToken
 | 
			
		||||
	i      int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *varParser) backup() {
 | 
			
		||||
	p.i--
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *varParser) next() varToken {
 | 
			
		||||
	if p.i < len(p.tokens) {
 | 
			
		||||
		t := p.tokens[p.i]
 | 
			
		||||
		p.i++
 | 
			
		||||
		return t
 | 
			
		||||
	}
 | 
			
		||||
	return varToken{typ: tokEOF}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type varNode interface {
 | 
			
		||||
	Infer() (Signature, error)
 | 
			
		||||
	String() string
 | 
			
		||||
	Sigs() sigSet
 | 
			
		||||
	Value(Signature) (interface{}, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varMakeNode(p *varParser) (varNode, error) {
 | 
			
		||||
	var sig Signature
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		t := p.next()
 | 
			
		||||
		switch t.typ {
 | 
			
		||||
		case tokEOF:
 | 
			
		||||
			return nil, io.ErrUnexpectedEOF
 | 
			
		||||
		case tokError:
 | 
			
		||||
			return nil, errors.New(t.val)
 | 
			
		||||
		case tokNumber:
 | 
			
		||||
			return varMakeNumNode(t, sig)
 | 
			
		||||
		case tokString:
 | 
			
		||||
			return varMakeStringNode(t, sig)
 | 
			
		||||
		case tokBool:
 | 
			
		||||
			if sig.str != "" && sig.str != "b" {
 | 
			
		||||
				return nil, varTypeError{t.val, sig}
 | 
			
		||||
			}
 | 
			
		||||
			b, err := strconv.ParseBool(t.val)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			return boolNode(b), nil
 | 
			
		||||
		case tokArrayStart:
 | 
			
		||||
			return varMakeArrayNode(p, sig)
 | 
			
		||||
		case tokVariantStart:
 | 
			
		||||
			return varMakeVariantNode(p, sig)
 | 
			
		||||
		case tokDictStart:
 | 
			
		||||
			return varMakeDictNode(p, sig)
 | 
			
		||||
		case tokType:
 | 
			
		||||
			if sig.str != "" {
 | 
			
		||||
				return nil, errors.New("unexpected type annotation")
 | 
			
		||||
			}
 | 
			
		||||
			if t.val[0] == '@' {
 | 
			
		||||
				sig.str = t.val[1:]
 | 
			
		||||
			} else {
 | 
			
		||||
				sig.str = varTypeMap[t.val]
 | 
			
		||||
			}
 | 
			
		||||
		case tokByteString:
 | 
			
		||||
			if sig.str != "" && sig.str != "ay" {
 | 
			
		||||
				return nil, varTypeError{t.val, sig}
 | 
			
		||||
			}
 | 
			
		||||
			b, err := varParseByteString(t.val)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			return byteStringNode(b), nil
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, fmt.Errorf("unexpected %q", t.val)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type varTypeError struct {
 | 
			
		||||
	val string
 | 
			
		||||
	sig Signature
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e varTypeError) Error() string {
 | 
			
		||||
	return fmt.Sprintf("dbus: can't parse %q as type %q", e.val, e.sig.str)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type sigSet map[Signature]bool
 | 
			
		||||
 | 
			
		||||
func (s sigSet) Empty() bool {
 | 
			
		||||
	return len(s) == 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s sigSet) Intersect(s2 sigSet) sigSet {
 | 
			
		||||
	r := make(sigSet)
 | 
			
		||||
	for k := range s {
 | 
			
		||||
		if s2[k] {
 | 
			
		||||
			r[k] = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s sigSet) Single() (Signature, bool) {
 | 
			
		||||
	if len(s) == 1 {
 | 
			
		||||
		for k := range s {
 | 
			
		||||
			return k, true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return Signature{}, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s sigSet) ToArray() sigSet {
 | 
			
		||||
	r := make(sigSet, len(s))
 | 
			
		||||
	for k := range s {
 | 
			
		||||
		r[Signature{"a" + k.str}] = true
 | 
			
		||||
	}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type numNode struct {
 | 
			
		||||
	sig Signature
 | 
			
		||||
	str string
 | 
			
		||||
	val interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var numSigSet = sigSet{
 | 
			
		||||
	Signature{"y"}: true,
 | 
			
		||||
	Signature{"n"}: true,
 | 
			
		||||
	Signature{"q"}: true,
 | 
			
		||||
	Signature{"i"}: true,
 | 
			
		||||
	Signature{"u"}: true,
 | 
			
		||||
	Signature{"x"}: true,
 | 
			
		||||
	Signature{"t"}: true,
 | 
			
		||||
	Signature{"d"}: true,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n numNode) Infer() (Signature, error) {
 | 
			
		||||
	if strings.ContainsAny(n.str, ".e") {
 | 
			
		||||
		return Signature{"d"}, nil
 | 
			
		||||
	}
 | 
			
		||||
	return Signature{"i"}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n numNode) String() string {
 | 
			
		||||
	return n.str
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n numNode) Sigs() sigSet {
 | 
			
		||||
	if n.sig.str != "" {
 | 
			
		||||
		return sigSet{n.sig: true}
 | 
			
		||||
	}
 | 
			
		||||
	if strings.ContainsAny(n.str, ".e") {
 | 
			
		||||
		return sigSet{Signature{"d"}: true}
 | 
			
		||||
	}
 | 
			
		||||
	return numSigSet
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n numNode) Value(sig Signature) (interface{}, error) {
 | 
			
		||||
	if n.sig.str != "" && n.sig != sig {
 | 
			
		||||
		return nil, varTypeError{n.str, sig}
 | 
			
		||||
	}
 | 
			
		||||
	if n.val != nil {
 | 
			
		||||
		return n.val, nil
 | 
			
		||||
	}
 | 
			
		||||
	return varNumAs(n.str, sig)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varMakeNumNode(tok varToken, sig Signature) (varNode, error) {
 | 
			
		||||
	if sig.str == "" {
 | 
			
		||||
		return numNode{str: tok.val}, nil
 | 
			
		||||
	}
 | 
			
		||||
	num, err := varNumAs(tok.val, sig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return numNode{sig: sig, val: num}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varNumAs(s string, sig Signature) (interface{}, error) {
 | 
			
		||||
	isUnsigned := false
 | 
			
		||||
	size := 32
 | 
			
		||||
	switch sig.str {
 | 
			
		||||
	case "n":
 | 
			
		||||
		size = 16
 | 
			
		||||
	case "i":
 | 
			
		||||
	case "x":
 | 
			
		||||
		size = 64
 | 
			
		||||
	case "y":
 | 
			
		||||
		size = 8
 | 
			
		||||
		isUnsigned = true
 | 
			
		||||
	case "q":
 | 
			
		||||
		size = 16
 | 
			
		||||
		isUnsigned = true
 | 
			
		||||
	case "u":
 | 
			
		||||
		isUnsigned = true
 | 
			
		||||
	case "t":
 | 
			
		||||
		size = 64
 | 
			
		||||
		isUnsigned = true
 | 
			
		||||
	case "d":
 | 
			
		||||
		d, err := strconv.ParseFloat(s, 64)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		return d, nil
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, varTypeError{s, sig}
 | 
			
		||||
	}
 | 
			
		||||
	base := 10
 | 
			
		||||
	if strings.HasPrefix(s, "0x") {
 | 
			
		||||
		base = 16
 | 
			
		||||
		s = s[2:]
 | 
			
		||||
	}
 | 
			
		||||
	if strings.HasPrefix(s, "0") && len(s) != 1 {
 | 
			
		||||
		base = 8
 | 
			
		||||
		s = s[1:]
 | 
			
		||||
	}
 | 
			
		||||
	if isUnsigned {
 | 
			
		||||
		i, err := strconv.ParseUint(s, base, size)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		var v interface{} = i
 | 
			
		||||
		switch sig.str {
 | 
			
		||||
		case "y":
 | 
			
		||||
			v = byte(i)
 | 
			
		||||
		case "q":
 | 
			
		||||
			v = uint16(i)
 | 
			
		||||
		case "u":
 | 
			
		||||
			v = uint32(i)
 | 
			
		||||
		}
 | 
			
		||||
		return v, nil
 | 
			
		||||
	}
 | 
			
		||||
	i, err := strconv.ParseInt(s, base, size)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	var v interface{} = i
 | 
			
		||||
	switch sig.str {
 | 
			
		||||
	case "n":
 | 
			
		||||
		v = int16(i)
 | 
			
		||||
	case "i":
 | 
			
		||||
		v = int32(i)
 | 
			
		||||
	}
 | 
			
		||||
	return v, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type stringNode struct {
 | 
			
		||||
	sig Signature
 | 
			
		||||
	str string      // parsed
 | 
			
		||||
	val interface{} // has correct type
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var stringSigSet = sigSet{
 | 
			
		||||
	Signature{"s"}: true,
 | 
			
		||||
	Signature{"g"}: true,
 | 
			
		||||
	Signature{"o"}: true,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n stringNode) Infer() (Signature, error) {
 | 
			
		||||
	return Signature{"s"}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n stringNode) String() string {
 | 
			
		||||
	return n.str
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n stringNode) Sigs() sigSet {
 | 
			
		||||
	if n.sig.str != "" {
 | 
			
		||||
		return sigSet{n.sig: true}
 | 
			
		||||
	}
 | 
			
		||||
	return stringSigSet
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n stringNode) Value(sig Signature) (interface{}, error) {
 | 
			
		||||
	if n.sig.str != "" && n.sig != sig {
 | 
			
		||||
		return nil, varTypeError{n.str, sig}
 | 
			
		||||
	}
 | 
			
		||||
	if n.val != nil {
 | 
			
		||||
		return n.val, nil
 | 
			
		||||
	}
 | 
			
		||||
	switch {
 | 
			
		||||
	case sig.str == "g":
 | 
			
		||||
		return Signature{n.str}, nil
 | 
			
		||||
	case sig.str == "o":
 | 
			
		||||
		return ObjectPath(n.str), nil
 | 
			
		||||
	case sig.str == "s":
 | 
			
		||||
		return n.str, nil
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, varTypeError{n.str, sig}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varMakeStringNode(tok varToken, sig Signature) (varNode, error) {
 | 
			
		||||
	if sig.str != "" && sig.str != "s" && sig.str != "g" && sig.str != "o" {
 | 
			
		||||
		return nil, fmt.Errorf("invalid type %q for string", sig.str)
 | 
			
		||||
	}
 | 
			
		||||
	s, err := varParseString(tok.val)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	n := stringNode{str: s}
 | 
			
		||||
	if sig.str == "" {
 | 
			
		||||
		return stringNode{str: s}, nil
 | 
			
		||||
	}
 | 
			
		||||
	n.sig = sig
 | 
			
		||||
	switch sig.str {
 | 
			
		||||
	case "o":
 | 
			
		||||
		n.val = ObjectPath(s)
 | 
			
		||||
	case "g":
 | 
			
		||||
		n.val = Signature{s}
 | 
			
		||||
	case "s":
 | 
			
		||||
		n.val = s
 | 
			
		||||
	}
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varParseString(s string) (string, error) {
 | 
			
		||||
	// quotes are guaranteed to be there
 | 
			
		||||
	s = s[1 : len(s)-1]
 | 
			
		||||
	buf := new(bytes.Buffer)
 | 
			
		||||
	for len(s) != 0 {
 | 
			
		||||
		r, size := utf8.DecodeRuneInString(s)
 | 
			
		||||
		if r == utf8.RuneError && size == 1 {
 | 
			
		||||
			return "", errors.New("invalid UTF-8")
 | 
			
		||||
		}
 | 
			
		||||
		s = s[size:]
 | 
			
		||||
		if r != '\\' {
 | 
			
		||||
			buf.WriteRune(r)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		r, size = utf8.DecodeRuneInString(s)
 | 
			
		||||
		if r == utf8.RuneError && size == 1 {
 | 
			
		||||
			return "", errors.New("invalid UTF-8")
 | 
			
		||||
		}
 | 
			
		||||
		s = s[size:]
 | 
			
		||||
		switch r {
 | 
			
		||||
		case 'a':
 | 
			
		||||
			buf.WriteRune(0x7)
 | 
			
		||||
		case 'b':
 | 
			
		||||
			buf.WriteRune(0x8)
 | 
			
		||||
		case 'f':
 | 
			
		||||
			buf.WriteRune(0xc)
 | 
			
		||||
		case 'n':
 | 
			
		||||
			buf.WriteRune('\n')
 | 
			
		||||
		case 'r':
 | 
			
		||||
			buf.WriteRune('\r')
 | 
			
		||||
		case 't':
 | 
			
		||||
			buf.WriteRune('\t')
 | 
			
		||||
		case '\n':
 | 
			
		||||
		case 'u':
 | 
			
		||||
			if len(s) < 4 {
 | 
			
		||||
				return "", errors.New("short unicode escape")
 | 
			
		||||
			}
 | 
			
		||||
			r, err := strconv.ParseUint(s[:4], 16, 32)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return "", err
 | 
			
		||||
			}
 | 
			
		||||
			buf.WriteRune(rune(r))
 | 
			
		||||
			s = s[4:]
 | 
			
		||||
		case 'U':
 | 
			
		||||
			if len(s) < 8 {
 | 
			
		||||
				return "", errors.New("short unicode escape")
 | 
			
		||||
			}
 | 
			
		||||
			r, err := strconv.ParseUint(s[:8], 16, 32)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return "", err
 | 
			
		||||
			}
 | 
			
		||||
			buf.WriteRune(rune(r))
 | 
			
		||||
			s = s[8:]
 | 
			
		||||
		default:
 | 
			
		||||
			buf.WriteRune(r)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return buf.String(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var boolSigSet = sigSet{Signature{"b"}: true}
 | 
			
		||||
 | 
			
		||||
type boolNode bool
 | 
			
		||||
 | 
			
		||||
func (boolNode) Infer() (Signature, error) {
 | 
			
		||||
	return Signature{"b"}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b boolNode) String() string {
 | 
			
		||||
	if b {
 | 
			
		||||
		return "true"
 | 
			
		||||
	}
 | 
			
		||||
	return "false"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (boolNode) Sigs() sigSet {
 | 
			
		||||
	return boolSigSet
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b boolNode) Value(sig Signature) (interface{}, error) {
 | 
			
		||||
	if sig.str != "b" {
 | 
			
		||||
		return nil, varTypeError{b.String(), sig}
 | 
			
		||||
	}
 | 
			
		||||
	return bool(b), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type arrayNode struct {
 | 
			
		||||
	set      sigSet
 | 
			
		||||
	children []varNode
 | 
			
		||||
	val      interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n arrayNode) Infer() (Signature, error) {
 | 
			
		||||
	for _, v := range n.children {
 | 
			
		||||
		csig, err := varInfer(v)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		return Signature{"a" + csig.str}, nil
 | 
			
		||||
	}
 | 
			
		||||
	return Signature{}, fmt.Errorf("can't infer type for %q", n.String())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n arrayNode) String() string {
 | 
			
		||||
	s := "["
 | 
			
		||||
	for i, v := range n.children {
 | 
			
		||||
		s += v.String()
 | 
			
		||||
		if i != len(n.children)-1 {
 | 
			
		||||
			s += ", "
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return s + "]"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n arrayNode) Sigs() sigSet {
 | 
			
		||||
	return n.set
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n arrayNode) Value(sig Signature) (interface{}, error) {
 | 
			
		||||
	if n.set.Empty() {
 | 
			
		||||
		// no type information whatsoever, so this must be an empty slice
 | 
			
		||||
		return reflect.MakeSlice(typeFor(sig.str), 0, 0).Interface(), nil
 | 
			
		||||
	}
 | 
			
		||||
	if !n.set[sig] {
 | 
			
		||||
		return nil, varTypeError{n.String(), sig}
 | 
			
		||||
	}
 | 
			
		||||
	s := reflect.MakeSlice(typeFor(sig.str), len(n.children), len(n.children))
 | 
			
		||||
	for i, v := range n.children {
 | 
			
		||||
		rv, err := v.Value(Signature{sig.str[1:]})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		s.Index(i).Set(reflect.ValueOf(rv))
 | 
			
		||||
	}
 | 
			
		||||
	return s.Interface(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varMakeArrayNode(p *varParser, sig Signature) (varNode, error) {
 | 
			
		||||
	var n arrayNode
 | 
			
		||||
	if sig.str != "" {
 | 
			
		||||
		n.set = sigSet{sig: true}
 | 
			
		||||
	}
 | 
			
		||||
	if t := p.next(); t.typ == tokArrayEnd {
 | 
			
		||||
		return n, nil
 | 
			
		||||
	} else {
 | 
			
		||||
		p.backup()
 | 
			
		||||
	}
 | 
			
		||||
Loop:
 | 
			
		||||
	for {
 | 
			
		||||
		t := p.next()
 | 
			
		||||
		switch t.typ {
 | 
			
		||||
		case tokEOF:
 | 
			
		||||
			return nil, io.ErrUnexpectedEOF
 | 
			
		||||
		case tokError:
 | 
			
		||||
			return nil, errors.New(t.val)
 | 
			
		||||
		}
 | 
			
		||||
		p.backup()
 | 
			
		||||
		cn, err := varMakeNode(p)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if cset := cn.Sigs(); !cset.Empty() {
 | 
			
		||||
			if n.set.Empty() {
 | 
			
		||||
				n.set = cset.ToArray()
 | 
			
		||||
			} else {
 | 
			
		||||
				nset := cset.ToArray().Intersect(n.set)
 | 
			
		||||
				if nset.Empty() {
 | 
			
		||||
					return nil, fmt.Errorf("can't parse %q with given type information", cn.String())
 | 
			
		||||
				}
 | 
			
		||||
				n.set = nset
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		n.children = append(n.children, cn)
 | 
			
		||||
		switch t := p.next(); t.typ {
 | 
			
		||||
		case tokEOF:
 | 
			
		||||
			return nil, io.ErrUnexpectedEOF
 | 
			
		||||
		case tokError:
 | 
			
		||||
			return nil, errors.New(t.val)
 | 
			
		||||
		case tokArrayEnd:
 | 
			
		||||
			break Loop
 | 
			
		||||
		case tokComma:
 | 
			
		||||
			continue
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, fmt.Errorf("unexpected %q", t.val)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type variantNode struct {
 | 
			
		||||
	n varNode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var variantSet = sigSet{
 | 
			
		||||
	Signature{"v"}: true,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (variantNode) Infer() (Signature, error) {
 | 
			
		||||
	return Signature{"v"}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n variantNode) String() string {
 | 
			
		||||
	return "<" + n.n.String() + ">"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (variantNode) Sigs() sigSet {
 | 
			
		||||
	return variantSet
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n variantNode) Value(sig Signature) (interface{}, error) {
 | 
			
		||||
	if sig.str != "v" {
 | 
			
		||||
		return nil, varTypeError{n.String(), sig}
 | 
			
		||||
	}
 | 
			
		||||
	sig, err := varInfer(n.n)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	v, err := n.n.Value(sig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return MakeVariant(v), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varMakeVariantNode(p *varParser, sig Signature) (varNode, error) {
 | 
			
		||||
	n, err := varMakeNode(p)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if t := p.next(); t.typ != tokVariantEnd {
 | 
			
		||||
		return nil, fmt.Errorf("unexpected %q", t.val)
 | 
			
		||||
	}
 | 
			
		||||
	vn := variantNode{n}
 | 
			
		||||
	if sig.str != "" && sig.str != "v" {
 | 
			
		||||
		return nil, varTypeError{vn.String(), sig}
 | 
			
		||||
	}
 | 
			
		||||
	return variantNode{n}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type dictEntry struct {
 | 
			
		||||
	key, val varNode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type dictNode struct {
 | 
			
		||||
	kset, vset sigSet
 | 
			
		||||
	children   []dictEntry
 | 
			
		||||
	val        interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n dictNode) Infer() (Signature, error) {
 | 
			
		||||
	for _, v := range n.children {
 | 
			
		||||
		ksig, err := varInfer(v.key)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		vsig, err := varInfer(v.val)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		return Signature{"a{" + ksig.str + vsig.str + "}"}, nil
 | 
			
		||||
	}
 | 
			
		||||
	return Signature{}, fmt.Errorf("can't infer type for %q", n.String())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n dictNode) String() string {
 | 
			
		||||
	s := "{"
 | 
			
		||||
	for i, v := range n.children {
 | 
			
		||||
		s += v.key.String() + ": " + v.val.String()
 | 
			
		||||
		if i != len(n.children)-1 {
 | 
			
		||||
			s += ", "
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return s + "}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n dictNode) Sigs() sigSet {
 | 
			
		||||
	r := sigSet{}
 | 
			
		||||
	for k := range n.kset {
 | 
			
		||||
		for v := range n.vset {
 | 
			
		||||
			sig := "a{" + k.str + v.str + "}"
 | 
			
		||||
			r[Signature{sig}] = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n dictNode) Value(sig Signature) (interface{}, error) {
 | 
			
		||||
	set := n.Sigs()
 | 
			
		||||
	if set.Empty() {
 | 
			
		||||
		// no type information -> empty dict
 | 
			
		||||
		return reflect.MakeMap(typeFor(sig.str)).Interface(), nil
 | 
			
		||||
	}
 | 
			
		||||
	if !set[sig] {
 | 
			
		||||
		return nil, varTypeError{n.String(), sig}
 | 
			
		||||
	}
 | 
			
		||||
	m := reflect.MakeMap(typeFor(sig.str))
 | 
			
		||||
	ksig := Signature{sig.str[2:3]}
 | 
			
		||||
	vsig := Signature{sig.str[3 : len(sig.str)-1]}
 | 
			
		||||
	for _, v := range n.children {
 | 
			
		||||
		kv, err := v.key.Value(ksig)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		vv, err := v.val.Value(vsig)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		m.SetMapIndex(reflect.ValueOf(kv), reflect.ValueOf(vv))
 | 
			
		||||
	}
 | 
			
		||||
	return m.Interface(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varMakeDictNode(p *varParser, sig Signature) (varNode, error) {
 | 
			
		||||
	var n dictNode
 | 
			
		||||
 | 
			
		||||
	if sig.str != "" {
 | 
			
		||||
		if len(sig.str) < 5 {
 | 
			
		||||
			return nil, fmt.Errorf("invalid signature %q for dict type", sig)
 | 
			
		||||
		}
 | 
			
		||||
		ksig := Signature{string(sig.str[2])}
 | 
			
		||||
		vsig := Signature{sig.str[3 : len(sig.str)-1]}
 | 
			
		||||
		n.kset = sigSet{ksig: true}
 | 
			
		||||
		n.vset = sigSet{vsig: true}
 | 
			
		||||
	}
 | 
			
		||||
	if t := p.next(); t.typ == tokDictEnd {
 | 
			
		||||
		return n, nil
 | 
			
		||||
	} else {
 | 
			
		||||
		p.backup()
 | 
			
		||||
	}
 | 
			
		||||
Loop:
 | 
			
		||||
	for {
 | 
			
		||||
		t := p.next()
 | 
			
		||||
		switch t.typ {
 | 
			
		||||
		case tokEOF:
 | 
			
		||||
			return nil, io.ErrUnexpectedEOF
 | 
			
		||||
		case tokError:
 | 
			
		||||
			return nil, errors.New(t.val)
 | 
			
		||||
		}
 | 
			
		||||
		p.backup()
 | 
			
		||||
		kn, err := varMakeNode(p)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if kset := kn.Sigs(); !kset.Empty() {
 | 
			
		||||
			if n.kset.Empty() {
 | 
			
		||||
				n.kset = kset
 | 
			
		||||
			} else {
 | 
			
		||||
				n.kset = kset.Intersect(n.kset)
 | 
			
		||||
				if n.kset.Empty() {
 | 
			
		||||
					return nil, fmt.Errorf("can't parse %q with given type information", kn.String())
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		t = p.next()
 | 
			
		||||
		switch t.typ {
 | 
			
		||||
		case tokEOF:
 | 
			
		||||
			return nil, io.ErrUnexpectedEOF
 | 
			
		||||
		case tokError:
 | 
			
		||||
			return nil, errors.New(t.val)
 | 
			
		||||
		case tokColon:
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, fmt.Errorf("unexpected %q", t.val)
 | 
			
		||||
		}
 | 
			
		||||
		t = p.next()
 | 
			
		||||
		switch t.typ {
 | 
			
		||||
		case tokEOF:
 | 
			
		||||
			return nil, io.ErrUnexpectedEOF
 | 
			
		||||
		case tokError:
 | 
			
		||||
			return nil, errors.New(t.val)
 | 
			
		||||
		}
 | 
			
		||||
		p.backup()
 | 
			
		||||
		vn, err := varMakeNode(p)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if vset := vn.Sigs(); !vset.Empty() {
 | 
			
		||||
			if n.vset.Empty() {
 | 
			
		||||
				n.vset = vset
 | 
			
		||||
			} else {
 | 
			
		||||
				n.vset = n.vset.Intersect(vset)
 | 
			
		||||
				if n.vset.Empty() {
 | 
			
		||||
					return nil, fmt.Errorf("can't parse %q with given type information", vn.String())
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		n.children = append(n.children, dictEntry{kn, vn})
 | 
			
		||||
		t = p.next()
 | 
			
		||||
		switch t.typ {
 | 
			
		||||
		case tokEOF:
 | 
			
		||||
			return nil, io.ErrUnexpectedEOF
 | 
			
		||||
		case tokError:
 | 
			
		||||
			return nil, errors.New(t.val)
 | 
			
		||||
		case tokDictEnd:
 | 
			
		||||
			break Loop
 | 
			
		||||
		case tokComma:
 | 
			
		||||
			continue
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, fmt.Errorf("unexpected %q", t.val)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type byteStringNode []byte
 | 
			
		||||
 | 
			
		||||
var byteStringSet = sigSet{
 | 
			
		||||
	Signature{"ay"}: true,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (byteStringNode) Infer() (Signature, error) {
 | 
			
		||||
	return Signature{"ay"}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b byteStringNode) String() string {
 | 
			
		||||
	return string(b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b byteStringNode) Sigs() sigSet {
 | 
			
		||||
	return byteStringSet
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b byteStringNode) Value(sig Signature) (interface{}, error) {
 | 
			
		||||
	if sig.str != "ay" {
 | 
			
		||||
		return nil, varTypeError{b.String(), sig}
 | 
			
		||||
	}
 | 
			
		||||
	return []byte(b), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varParseByteString(s string) ([]byte, error) {
 | 
			
		||||
	// quotes and b at start are guaranteed to be there
 | 
			
		||||
	b := make([]byte, 0, 1)
 | 
			
		||||
	s = s[2 : len(s)-1]
 | 
			
		||||
	for len(s) != 0 {
 | 
			
		||||
		c := s[0]
 | 
			
		||||
		s = s[1:]
 | 
			
		||||
		if c != '\\' {
 | 
			
		||||
			b = append(b, c)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		c = s[0]
 | 
			
		||||
		s = s[1:]
 | 
			
		||||
		switch c {
 | 
			
		||||
		case 'a':
 | 
			
		||||
			b = append(b, 0x7)
 | 
			
		||||
		case 'b':
 | 
			
		||||
			b = append(b, 0x8)
 | 
			
		||||
		case 'f':
 | 
			
		||||
			b = append(b, 0xc)
 | 
			
		||||
		case 'n':
 | 
			
		||||
			b = append(b, '\n')
 | 
			
		||||
		case 'r':
 | 
			
		||||
			b = append(b, '\r')
 | 
			
		||||
		case 't':
 | 
			
		||||
			b = append(b, '\t')
 | 
			
		||||
		case 'x':
 | 
			
		||||
			if len(s) < 2 {
 | 
			
		||||
				return nil, errors.New("short escape")
 | 
			
		||||
			}
 | 
			
		||||
			n, err := strconv.ParseUint(s[:2], 16, 8)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			b = append(b, byte(n))
 | 
			
		||||
			s = s[2:]
 | 
			
		||||
		case '0':
 | 
			
		||||
			if len(s) < 3 {
 | 
			
		||||
				return nil, errors.New("short escape")
 | 
			
		||||
			}
 | 
			
		||||
			n, err := strconv.ParseUint(s[:3], 8, 8)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			b = append(b, byte(n))
 | 
			
		||||
			s = s[3:]
 | 
			
		||||
		default:
 | 
			
		||||
			b = append(b, c)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return append(b, 0), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func varInfer(n varNode) (Signature, error) {
 | 
			
		||||
	if sig, ok := n.Sigs().Single(); ok {
 | 
			
		||||
		return sig, nil
 | 
			
		||||
	}
 | 
			
		||||
	return n.Infer()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										78
									
								
								vendor/src/github.com/godbus/dbus/variant_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								vendor/src/github.com/godbus/dbus/variant_test.go
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,78 @@
 | 
			
		|||
package dbus
 | 
			
		||||
 | 
			
		||||
import "reflect"
 | 
			
		||||
import "testing"
 | 
			
		||||
 | 
			
		||||
var variantFormatTests = []struct {
 | 
			
		||||
	v interface{}
 | 
			
		||||
	s string
 | 
			
		||||
}{
 | 
			
		||||
	{int32(1), `1`},
 | 
			
		||||
	{"foo", `"foo"`},
 | 
			
		||||
	{ObjectPath("/org/foo"), `@o "/org/foo"`},
 | 
			
		||||
	{Signature{"i"}, `@g "i"`},
 | 
			
		||||
	{[]byte{}, `@ay []`},
 | 
			
		||||
	{[]int32{1, 2}, `[1, 2]`},
 | 
			
		||||
	{[]int64{1, 2}, `@ax [1, 2]`},
 | 
			
		||||
	{[][]int32{{3, 4}, {5, 6}}, `[[3, 4], [5, 6]]`},
 | 
			
		||||
	{[]Variant{MakeVariant(int32(1)), MakeVariant(1.0)}, `[<1>, <@d 1>]`},
 | 
			
		||||
	{map[string]int32{"one": 1, "two": 2}, `{"one": 1, "two": 2}`},
 | 
			
		||||
	{map[int32]ObjectPath{1: "/org/foo"}, `@a{io} {1: "/org/foo"}`},
 | 
			
		||||
	{map[string]Variant{}, `@a{sv} {}`},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestFormatVariant(t *testing.T) {
 | 
			
		||||
	for i, v := range variantFormatTests {
 | 
			
		||||
		if s := MakeVariant(v.v).String(); s != v.s {
 | 
			
		||||
			t.Errorf("test %d: got %q, wanted %q", i+1, s, v.s)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var variantParseTests = []struct {
 | 
			
		||||
	s string
 | 
			
		||||
	v interface{}
 | 
			
		||||
}{
 | 
			
		||||
	{"1", int32(1)},
 | 
			
		||||
	{"true", true},
 | 
			
		||||
	{"false", false},
 | 
			
		||||
	{"1.0", float64(1.0)},
 | 
			
		||||
	{"0x10", int32(16)},
 | 
			
		||||
	{"1e1", float64(10)},
 | 
			
		||||
	{`"foo"`, "foo"},
 | 
			
		||||
	{`"\a\b\f\n\r\t"`, "\x07\x08\x0c\n\r\t"},
 | 
			
		||||
	{`"\u00e4\U0001f603"`, "\u00e4\U0001f603"},
 | 
			
		||||
	{"[1]", []int32{1}},
 | 
			
		||||
	{"[1, 2, 3]", []int32{1, 2, 3}},
 | 
			
		||||
	{"@ai []", []int32{}},
 | 
			
		||||
	{"[1, 5.0]", []float64{1, 5.0}},
 | 
			
		||||
	{"[[1, 2], [3, 4.0]]", [][]float64{{1, 2}, {3, 4}}},
 | 
			
		||||
	{`[@o "/org/foo", "/org/bar"]`, []ObjectPath{"/org/foo", "/org/bar"}},
 | 
			
		||||
	{"<1>", MakeVariant(int32(1))},
 | 
			
		||||
	{"[<1>, <2.0>]", []Variant{MakeVariant(int32(1)), MakeVariant(2.0)}},
 | 
			
		||||
	{`[[], [""]]`, [][]string{{}, {""}}},
 | 
			
		||||
	{`@a{ss} {}`, map[string]string{}},
 | 
			
		||||
	{`{"foo": 1}`, map[string]int32{"foo": 1}},
 | 
			
		||||
	{`[{}, {"foo": "bar"}]`, []map[string]string{{}, {"foo": "bar"}}},
 | 
			
		||||
	{`{"a": <1>, "b": <"foo">}`,
 | 
			
		||||
		map[string]Variant{"a": MakeVariant(int32(1)), "b": MakeVariant("foo")}},
 | 
			
		||||
	{`b''`, []byte{0}},
 | 
			
		||||
	{`b"abc"`, []byte{'a', 'b', 'c', 0}},
 | 
			
		||||
	{`b"\x01\0002\a\b\f\n\r\t"`, []byte{1, 2, 0x7, 0x8, 0xc, '\n', '\r', '\t', 0}},
 | 
			
		||||
	{`[[0], b""]`, [][]byte{{0}, {0}}},
 | 
			
		||||
	{"int16 0", int16(0)},
 | 
			
		||||
	{"byte 0", byte(0)},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseVariant(t *testing.T) {
 | 
			
		||||
	for i, v := range variantParseTests {
 | 
			
		||||
		nv, err := ParseVariant(v.s, Signature{})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Errorf("test %d: parsing failed: %s", i+1, err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !reflect.DeepEqual(nv.value, v.v) {
 | 
			
		||||
			t.Errorf("test %d: got %q, wanted %q", i+1, nv, v.v)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue