Skip to content

Commit e75cd41

Browse files
author
Anthony Romano
committed
util: conditionally build CGO functions
Some projects don't need the CGO functions in the util package; split out the functions into a separate file so CGO_ENABLED=0 works if those functions are never used. Fixes coreos#171
1 parent fa8411d commit e75cd41

File tree

2 files changed

+201
-177
lines changed

2 files changed

+201
-177
lines changed

util/util.go

Lines changed: 0 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -18,190 +18,13 @@
1818
// than linking against them.
1919
package util
2020

21-
// #include <stdlib.h>
22-
// #include <sys/types.h>
23-
// #include <unistd.h>
24-
//
25-
// int
26-
// my_sd_pid_get_owner_uid(void *f, pid_t pid, uid_t *uid)
27-
// {
28-
// int (*sd_pid_get_owner_uid)(pid_t, uid_t *);
29-
//
30-
// sd_pid_get_owner_uid = (int (*)(pid_t, uid_t *))f;
31-
// return sd_pid_get_owner_uid(pid, uid);
32-
// }
33-
//
34-
// int
35-
// my_sd_pid_get_unit(void *f, pid_t pid, char **unit)
36-
// {
37-
// int (*sd_pid_get_unit)(pid_t, char **);
38-
//
39-
// sd_pid_get_unit = (int (*)(pid_t, char **))f;
40-
// return sd_pid_get_unit(pid, unit);
41-
// }
42-
//
43-
// int
44-
// my_sd_pid_get_slice(void *f, pid_t pid, char **slice)
45-
// {
46-
// int (*sd_pid_get_slice)(pid_t, char **);
47-
//
48-
// sd_pid_get_slice = (int (*)(pid_t, char **))f;
49-
// return sd_pid_get_slice(pid, slice);
50-
// }
51-
//
52-
// int
53-
// am_session_leader()
54-
// {
55-
// return (getsid(0) == getpid());
56-
// }
57-
import "C"
5821
import (
5922
"fmt"
6023
"io/ioutil"
6124
"os"
6225
"strings"
63-
"syscall"
64-
"unsafe"
65-
66-
"github.com/coreos/pkg/dlopen"
6726
)
6827

69-
var libsystemdNames = []string{
70-
// systemd < 209
71-
"libsystemd-login.so.0",
72-
"libsystemd-login.so",
73-
74-
// systemd >= 209 merged libsystemd-login into libsystemd proper
75-
"libsystemd.so.0",
76-
"libsystemd.so",
77-
}
78-
79-
// GetRunningSlice attempts to retrieve the name of the systemd slice in which
80-
// the current process is running.
81-
// This function is a wrapper around the libsystemd C library; if it cannot be
82-
// opened, an error is returned.
83-
func GetRunningSlice() (slice string, err error) {
84-
var h *dlopen.LibHandle
85-
h, err = dlopen.GetHandle(libsystemdNames)
86-
if err != nil {
87-
return
88-
}
89-
defer func() {
90-
if err1 := h.Close(); err1 != nil {
91-
err = err1
92-
}
93-
}()
94-
95-
sd_pid_get_slice, err := h.GetSymbolPointer("sd_pid_get_slice")
96-
if err != nil {
97-
return
98-
}
99-
100-
var s string
101-
sl := C.CString(s)
102-
defer C.free(unsafe.Pointer(sl))
103-
104-
ret := C.my_sd_pid_get_slice(sd_pid_get_slice, 0, &sl)
105-
if ret < 0 {
106-
err = fmt.Errorf("error calling sd_pid_get_slice: %v", syscall.Errno(-ret))
107-
return
108-
}
109-
110-
return C.GoString(sl), nil
111-
}
112-
113-
// RunningFromSystemService tries to detect whether the current process has
114-
// been invoked from a system service. The condition for this is whether the
115-
// process is _not_ a user process. User processes are those running in session
116-
// scopes or under per-user `systemd --user` instances.
117-
//
118-
// To avoid false positives on systems without `pam_systemd` (which is
119-
// responsible for creating user sessions), this function also uses a heuristic
120-
// to detect whether it's being invoked from a session leader process. This is
121-
// the case if the current process is executed directly from a service file
122-
// (e.g. with `ExecStart=/this/cmd`). Note that this heuristic will fail if the
123-
// command is instead launched in a subshell or similar so that it is not
124-
// session leader (e.g. `ExecStart=/bin/bash -c "/this/cmd"`)
125-
//
126-
// This function is a wrapper around the libsystemd C library; if this is
127-
// unable to successfully open a handle to the library for any reason (e.g. it
128-
// cannot be found), an errr will be returned
129-
func RunningFromSystemService() (ret bool, err error) {
130-
var h *dlopen.LibHandle
131-
h, err = dlopen.GetHandle(libsystemdNames)
132-
if err != nil {
133-
return
134-
}
135-
defer func() {
136-
if err1 := h.Close(); err1 != nil {
137-
err = err1
138-
}
139-
}()
140-
141-
sd_pid_get_owner_uid, err := h.GetSymbolPointer("sd_pid_get_owner_uid")
142-
if err != nil {
143-
return
144-
}
145-
146-
var uid C.uid_t
147-
errno := C.my_sd_pid_get_owner_uid(sd_pid_get_owner_uid, 0, &uid)
148-
serrno := syscall.Errno(-errno)
149-
// when we're running from a unit file, sd_pid_get_owner_uid returns
150-
// ENOENT (systemd <220) or ENXIO (systemd >=220)
151-
switch {
152-
case errno >= 0:
153-
ret = false
154-
case serrno == syscall.ENOENT, serrno == syscall.ENXIO:
155-
// Since the implementation of sessions in systemd relies on
156-
// the `pam_systemd` module, using the sd_pid_get_owner_uid
157-
// heuristic alone can result in false positives if that module
158-
// (or PAM itself) is not present or properly configured on the
159-
// system. As such, we also check if we're the session leader,
160-
// which should be the case if we're invoked from a unit file,
161-
// but not if e.g. we're invoked from the command line from a
162-
// user's login session
163-
ret = C.am_session_leader() == 1
164-
default:
165-
err = fmt.Errorf("error calling sd_pid_get_owner_uid: %v", syscall.Errno(-errno))
166-
}
167-
return
168-
}
169-
170-
// CurrentUnitName attempts to retrieve the name of the systemd system unit
171-
// from which the calling process has been invoked. It wraps the systemd
172-
// `sd_pid_get_unit` call, with the same caveat: for processes not part of a
173-
// systemd system unit, this function will return an error.
174-
func CurrentUnitName() (unit string, err error) {
175-
var h *dlopen.LibHandle
176-
h, err = dlopen.GetHandle(libsystemdNames)
177-
if err != nil {
178-
return
179-
}
180-
defer func() {
181-
if err1 := h.Close(); err1 != nil {
182-
err = err1
183-
}
184-
}()
185-
186-
sd_pid_get_unit, err := h.GetSymbolPointer("sd_pid_get_unit")
187-
if err != nil {
188-
return
189-
}
190-
191-
var s string
192-
u := C.CString(s)
193-
defer C.free(unsafe.Pointer(u))
194-
195-
ret := C.my_sd_pid_get_unit(sd_pid_get_unit, 0, &u)
196-
if ret < 0 {
197-
err = fmt.Errorf("error calling sd_pid_get_unit: %v", syscall.Errno(-ret))
198-
return
199-
}
200-
201-
unit = C.GoString(u)
202-
return
203-
}
204-
20528
// IsRunningSystemd checks whether the host was booted with systemd as its init
20629
// system. This functions similarly to systemd's `sd_booted(3)`: internally, it
20730
// checks whether /run/systemd/system/ exists and is a directory.

util/util_cgo.go

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
// Copyright 2016 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+
// +build cgo
16+
17+
package util
18+
19+
// #include <stdlib.h>
20+
// #include <sys/types.h>
21+
// #include <unistd.h>
22+
//
23+
// int
24+
// my_sd_pid_get_owner_uid(void *f, pid_t pid, uid_t *uid)
25+
// {
26+
// int (*sd_pid_get_owner_uid)(pid_t, uid_t *);
27+
//
28+
// sd_pid_get_owner_uid = (int (*)(pid_t, uid_t *))f;
29+
// return sd_pid_get_owner_uid(pid, uid);
30+
// }
31+
//
32+
// int
33+
// my_sd_pid_get_unit(void *f, pid_t pid, char **unit)
34+
// {
35+
// int (*sd_pid_get_unit)(pid_t, char **);
36+
//
37+
// sd_pid_get_unit = (int (*)(pid_t, char **))f;
38+
// return sd_pid_get_unit(pid, unit);
39+
// }
40+
//
41+
// int
42+
// my_sd_pid_get_slice(void *f, pid_t pid, char **slice)
43+
// {
44+
// int (*sd_pid_get_slice)(pid_t, char **);
45+
//
46+
// sd_pid_get_slice = (int (*)(pid_t, char **))f;
47+
// return sd_pid_get_slice(pid, slice);
48+
// }
49+
//
50+
// int
51+
// am_session_leader()
52+
// {
53+
// return (getsid(0) == getpid());
54+
// }
55+
import "C"
56+
import (
57+
"fmt"
58+
"io/ioutil"
59+
"os"
60+
"strings"
61+
"syscall"
62+
"unsafe"
63+
64+
"github.com/coreos/pkg/dlopen"
65+
)
66+
67+
var libsystemdNames = []string{
68+
// systemd < 209
69+
"libsystemd-login.so.0",
70+
"libsystemd-login.so",
71+
72+
// systemd >= 209 merged libsystemd-login into libsystemd proper
73+
"libsystemd.so.0",
74+
"libsystemd.so",
75+
}
76+
77+
// GetRunningSlice attempts to retrieve the name of the systemd slice in which
78+
// the current process is running.
79+
// This function is a wrapper around the libsystemd C library; if it cannot be
80+
// opened, an error is returned.
81+
func GetRunningSlice() (slice string, err error) {
82+
var h *dlopen.LibHandle
83+
h, err = dlopen.GetHandle(libsystemdNames)
84+
if err != nil {
85+
return
86+
}
87+
defer func() {
88+
if err1 := h.Close(); err1 != nil {
89+
err = err1
90+
}
91+
}()
92+
93+
sd_pid_get_slice, err := h.GetSymbolPointer("sd_pid_get_slice")
94+
if err != nil {
95+
return
96+
}
97+
98+
var s string
99+
sl := C.CString(s)
100+
defer C.free(unsafe.Pointer(sl))
101+
102+
ret := C.my_sd_pid_get_slice(sd_pid_get_slice, 0, &sl)
103+
if ret < 0 {
104+
err = fmt.Errorf("error calling sd_pid_get_slice: %v", syscall.Errno(-ret))
105+
return
106+
}
107+
108+
return C.GoString(sl), nil
109+
}
110+
111+
// RunningFromSystemService tries to detect whether the current process has
112+
// been invoked from a system service. The condition for this is whether the
113+
// process is _not_ a user process. User processes are those running in session
114+
// scopes or under per-user `systemd --user` instances.
115+
//
116+
// To avoid false positives on systems without `pam_systemd` (which is
117+
// responsible for creating user sessions), this function also uses a heuristic
118+
// to detect whether it's being invoked from a session leader process. This is
119+
// the case if the current process is executed directly from a service file
120+
// (e.g. with `ExecStart=/this/cmd`). Note that this heuristic will fail if the
121+
// command is instead launched in a subshell or similar so that it is not
122+
// session leader (e.g. `ExecStart=/bin/bash -c "/this/cmd"`)
123+
//
124+
// This function is a wrapper around the libsystemd C library; if this is
125+
// unable to successfully open a handle to the library for any reason (e.g. it
126+
// cannot be found), an errr will be returned
127+
func RunningFromSystemService() (ret bool, err error) {
128+
var h *dlopen.LibHandle
129+
h, err = dlopen.GetHandle(libsystemdNames)
130+
if err != nil {
131+
return
132+
}
133+
defer func() {
134+
if err1 := h.Close(); err1 != nil {
135+
err = err1
136+
}
137+
}()
138+
139+
sd_pid_get_owner_uid, err := h.GetSymbolPointer("sd_pid_get_owner_uid")
140+
if err != nil {
141+
return
142+
}
143+
144+
var uid C.uid_t
145+
errno := C.my_sd_pid_get_owner_uid(sd_pid_get_owner_uid, 0, &uid)
146+
serrno := syscall.Errno(-errno)
147+
// when we're running from a unit file, sd_pid_get_owner_uid returns
148+
// ENOENT (systemd <220) or ENXIO (systemd >=220)
149+
switch {
150+
case errno >= 0:
151+
ret = false
152+
case serrno == syscall.ENOENT, serrno == syscall.ENXIO:
153+
// Since the implementation of sessions in systemd relies on
154+
// the `pam_systemd` module, using the sd_pid_get_owner_uid
155+
// heuristic alone can result in false positives if that module
156+
// (or PAM itself) is not present or properly configured on the
157+
// system. As such, we also check if we're the session leader,
158+
// which should be the case if we're invoked from a unit file,
159+
// but not if e.g. we're invoked from the command line from a
160+
// user's login session
161+
ret = C.am_session_leader() == 1
162+
default:
163+
err = fmt.Errorf("error calling sd_pid_get_owner_uid: %v", syscall.Errno(-errno))
164+
}
165+
return
166+
}
167+
168+
// CurrentUnitName attempts to retrieve the name of the systemd system unit
169+
// from which the calling process has been invoked. It wraps the systemd
170+
// `sd_pid_get_unit` call, with the same caveat: for processes not part of a
171+
// systemd system unit, this function will return an error.
172+
func CurrentUnitName() (unit string, err error) {
173+
var h *dlopen.LibHandle
174+
h, err = dlopen.GetHandle(libsystemdNames)
175+
if err != nil {
176+
return
177+
}
178+
defer func() {
179+
if err1 := h.Close(); err1 != nil {
180+
err = err1
181+
}
182+
}()
183+
184+
sd_pid_get_unit, err := h.GetSymbolPointer("sd_pid_get_unit")
185+
if err != nil {
186+
return
187+
}
188+
189+
var s string
190+
u := C.CString(s)
191+
defer C.free(unsafe.Pointer(u))
192+
193+
ret := C.my_sd_pid_get_unit(sd_pid_get_unit, 0, &u)
194+
if ret < 0 {
195+
err = fmt.Errorf("error calling sd_pid_get_unit: %v", syscall.Errno(-ret))
196+
return
197+
}
198+
199+
unit = C.GoString(u)
200+
return
201+
}

0 commit comments

Comments
 (0)