Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / opencontainers / runc / notify_socket.go
1 // +build linux
2
3 package runc
4
5 import (
6         "bytes"
7         "fmt"
8         "net"
9         "path/filepath"
10
11         "github.com/Sirupsen/logrus"
12         "github.com/opencontainers/runtime-spec/specs-go"
13         "github.com/urfave/cli"
14 )
15
16 type notifySocket struct {
17         socket     *net.UnixConn
18         host       string
19         socketPath string
20 }
21
22 func newNotifySocket(context *cli.Context, notifySocketHost string, id string) *notifySocket {
23         if notifySocketHost == "" {
24                 return nil
25         }
26
27         root := filepath.Join(context.GlobalString("root"), id)
28         path := filepath.Join(root, "notify.sock")
29
30         notifySocket := &notifySocket{
31                 socket:     nil,
32                 host:       notifySocketHost,
33                 socketPath: path,
34         }
35
36         return notifySocket
37 }
38
39 func (ns *notifySocket) Close() error {
40         return ns.socket.Close()
41 }
42
43 // If systemd is supporting sd_notify protocol, this function will add support
44 // for sd_notify protocol from within the container.
45 func (s *notifySocket) setupSpec(context *cli.Context, spec *specs.Spec) {
46         mount := specs.Mount{Destination: s.host, Type: "bind", Source: s.socketPath, Options: []string{"bind"}}
47         spec.Mounts = append(spec.Mounts, mount)
48         spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", s.host))
49 }
50
51 func (s *notifySocket) setupSocket() error {
52         addr := net.UnixAddr{
53                 Name: s.socketPath,
54                 Net:  "unixgram",
55         }
56
57         socket, err := net.ListenUnixgram("unixgram", &addr)
58         if err != nil {
59                 return err
60         }
61
62         s.socket = socket
63         return nil
64 }
65
66 // pid1 must be set only with -d, as it is used to set the new process as the main process
67 // for the service in systemd
68 func (notifySocket *notifySocket) run(pid1 int) {
69         buf := make([]byte, 512)
70         notifySocketHostAddr := net.UnixAddr{Name: notifySocket.host, Net: "unixgram"}
71         client, err := net.DialUnix("unixgram", nil, &notifySocketHostAddr)
72         if err != nil {
73                 logrus.Error(err)
74                 return
75         }
76         for {
77                 r, err := notifySocket.socket.Read(buf)
78                 if err != nil {
79                         break
80                 }
81                 var out bytes.Buffer
82                 for _, line := range bytes.Split(buf[0:r], []byte{'\n'}) {
83                         if bytes.HasPrefix(line, []byte("READY=")) {
84                                 _, err = out.Write(line)
85                                 if err != nil {
86                                         return
87                                 }
88
89                                 _, err = out.Write([]byte{'\n'})
90                                 if err != nil {
91                                         return
92                                 }
93
94                                 _, err = client.Write(out.Bytes())
95                                 if err != nil {
96                                         return
97                                 }
98
99                                 // now we can inform systemd to use pid1 as the pid to monitor
100                                 if pid1 > 0 {
101                                         newPid := fmt.Sprintf("MAINPID=%d\n", pid1)
102                                         client.Write([]byte(newPid))
103                                 }
104                                 return
105                         }
106                 }
107         }
108 }