Skip to content

Commit da560ea

Browse files
committed
Build on Windows
These changes allow go-systemd to build on Windows. Ideally, on platforms (like Windows) where systemd is not available, go-systemd should behave similarly to how it does on Linux, when a service is not started by systemd. Tipically this is default, no-op, behavior.
1 parent 87511f3 commit da560ea

File tree

5 files changed

+266
-179
lines changed

5 files changed

+266
-179
lines changed

activation/files.go activation/files_unix.go

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
// +build !windows
16+
1517
// Package activation implements primitives for systemd socket activation.
1618
package activation
1719

activation/files_windows.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2015 CoreOS, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package activation
16+
17+
import "os"
18+
19+
func Files(unsetEnv bool) []*os.File {
20+
return nil
21+
}

journal/journal.go

-179
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,7 @@
2323
package journal
2424

2525
import (
26-
"bytes"
27-
"encoding/binary"
28-
"errors"
2926
"fmt"
30-
"io"
31-
"io/ioutil"
32-
"net"
33-
"os"
34-
"strconv"
35-
"strings"
36-
"sync"
37-
"sync/atomic"
38-
"syscall"
39-
"unsafe"
4027
)
4128

4229
// Priority of a journal message
@@ -53,173 +40,7 @@ const (
5340
PriDebug
5441
)
5542

56-
var (
57-
// This can be overridden at build-time:
58-
// https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable
59-
journalSocket = "/run/systemd/journal/socket"
60-
61-
// unixConnPtr atomically holds the local unconnected Unix-domain socket.
62-
// Concrete safe pointer type: *net.UnixConn
63-
unixConnPtr unsafe.Pointer
64-
// onceConn ensures that unixConnPtr is initialized exactly once.
65-
onceConn sync.Once
66-
)
67-
68-
func init() {
69-
onceConn.Do(initConn)
70-
}
71-
72-
// Enabled checks whether the local systemd journal is available for logging.
73-
func Enabled() bool {
74-
onceConn.Do(initConn)
75-
76-
if (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) == nil {
77-
return false
78-
}
79-
80-
if _, err := net.Dial("unixgram", journalSocket); err != nil {
81-
return false
82-
}
83-
84-
return true
85-
}
86-
87-
// Send a message to the local systemd journal. vars is a map of journald
88-
// fields to values. Fields must be composed of uppercase letters, numbers,
89-
// and underscores, but must not start with an underscore. Within these
90-
// restrictions, any arbitrary field name may be used. Some names have special
91-
// significance: see the journalctl documentation
92-
// (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html)
93-
// for more details. vars may be nil.
94-
func Send(message string, priority Priority, vars map[string]string) error {
95-
conn := (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr))
96-
if conn == nil {
97-
return errors.New("could not initialize socket to journald")
98-
}
99-
100-
socketAddr := &net.UnixAddr{
101-
Name: journalSocket,
102-
Net: "unixgram",
103-
}
104-
105-
data := new(bytes.Buffer)
106-
appendVariable(data, "PRIORITY", strconv.Itoa(int(priority)))
107-
appendVariable(data, "MESSAGE", message)
108-
for k, v := range vars {
109-
appendVariable(data, k, v)
110-
}
111-
112-
_, _, err := conn.WriteMsgUnix(data.Bytes(), nil, socketAddr)
113-
if err == nil {
114-
return nil
115-
}
116-
if !isSocketSpaceError(err) {
117-
return err
118-
}
119-
120-
// Large log entry, send it via tempfile and ancillary-fd.
121-
file, err := tempFd()
122-
if err != nil {
123-
return err
124-
}
125-
defer file.Close()
126-
_, err = io.Copy(file, data)
127-
if err != nil {
128-
return err
129-
}
130-
rights := syscall.UnixRights(int(file.Fd()))
131-
_, _, err = conn.WriteMsgUnix([]byte{}, rights, socketAddr)
132-
if err != nil {
133-
return err
134-
}
135-
136-
return nil
137-
}
138-
13943
// Print prints a message to the local systemd journal using Send().
14044
func Print(priority Priority, format string, a ...interface{}) error {
14145
return Send(fmt.Sprintf(format, a...), priority, nil)
14246
}
143-
144-
func appendVariable(w io.Writer, name, value string) {
145-
if err := validVarName(name); err != nil {
146-
fmt.Fprintf(os.Stderr, "variable name %s contains invalid character, ignoring\n", name)
147-
}
148-
if strings.ContainsRune(value, '\n') {
149-
/* When the value contains a newline, we write:
150-
* - the variable name, followed by a newline
151-
* - the size (in 64bit little endian format)
152-
* - the data, followed by a newline
153-
*/
154-
fmt.Fprintln(w, name)
155-
binary.Write(w, binary.LittleEndian, uint64(len(value)))
156-
fmt.Fprintln(w, value)
157-
} else {
158-
/* just write the variable and value all on one line */
159-
fmt.Fprintf(w, "%s=%s\n", name, value)
160-
}
161-
}
162-
163-
// validVarName validates a variable name to make sure journald will accept it.
164-
// The variable name must be in uppercase and consist only of characters,
165-
// numbers and underscores, and may not begin with an underscore:
166-
// https://www.freedesktop.org/software/systemd/man/sd_journal_print.html
167-
func validVarName(name string) error {
168-
if name == "" {
169-
return errors.New("Empty variable name")
170-
} else if name[0] == '_' {
171-
return errors.New("Variable name begins with an underscore")
172-
}
173-
174-
for _, c := range name {
175-
if !(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') {
176-
return errors.New("Variable name contains invalid characters")
177-
}
178-
}
179-
return nil
180-
}
181-
182-
// isSocketSpaceError checks whether the error is signaling
183-
// an "overlarge message" condition.
184-
func isSocketSpaceError(err error) bool {
185-
opErr, ok := err.(*net.OpError)
186-
if !ok || opErr == nil {
187-
return false
188-
}
189-
190-
sysErr, ok := opErr.Err.(*os.SyscallError)
191-
if !ok || sysErr == nil {
192-
return false
193-
}
194-
195-
return sysErr.Err == syscall.EMSGSIZE || sysErr.Err == syscall.ENOBUFS
196-
}
197-
198-
// tempFd creates a temporary, unlinked file under `/dev/shm`.
199-
func tempFd() (*os.File, error) {
200-
file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX")
201-
if err != nil {
202-
return nil, err
203-
}
204-
err = syscall.Unlink(file.Name())
205-
if err != nil {
206-
return nil, err
207-
}
208-
return file, nil
209-
}
210-
211-
// initConn initializes the global `unixConnPtr` socket.
212-
// It is meant to be called exactly once, at program startup.
213-
func initConn() {
214-
autobind, err := net.ResolveUnixAddr("unixgram", "")
215-
if err != nil {
216-
return
217-
}
218-
219-
sock, err := net.ListenUnixgram("unixgram", autobind)
220-
if err != nil {
221-
return
222-
}
223-
224-
atomic.StorePointer(&unixConnPtr, unsafe.Pointer(sock))
225-
}

0 commit comments

Comments
 (0)