1// +build !windows
2
3package proc
4
5import (
6	"context"
7
8	"github.com/containerd/console"
9	"github.com/pkg/errors"
10)
11
12type execCreatedState struct {
13	p *execProcess
14}
15
16func (s *execCreatedState) transition(name string) error {
17	switch name {
18	case "running":
19		s.p.State = &execRunningState{p: s.p}
20	case "stopped":
21		s.p.State = &execStoppedState{p: s.p}
22	case "deleted":
23		s.p.State = &deletedState{}
24	default:
25		return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
26	}
27	return nil
28}
29
30func (s *execCreatedState) Resize(ws console.WinSize) error {
31	s.p.mu.Lock()
32	defer s.p.mu.Unlock()
33
34	return s.p.resize(ws)
35}
36
37func (s *execCreatedState) Start(ctx context.Context) error {
38	s.p.mu.Lock()
39	defer s.p.mu.Unlock()
40	if err := s.p.start(ctx); err != nil {
41		return err
42	}
43	return s.transition("running")
44}
45
46func (s *execCreatedState) Delete(ctx context.Context) error {
47	s.p.mu.Lock()
48	defer s.p.mu.Unlock()
49	if err := s.p.delete(ctx); err != nil {
50		return err
51	}
52	return s.transition("deleted")
53}
54
55func (s *execCreatedState) Kill(ctx context.Context, sig uint32, all bool) error {
56	s.p.mu.Lock()
57	defer s.p.mu.Unlock()
58
59	return s.p.kill(ctx, sig, all)
60}
61
62func (s *execCreatedState) SetExited(status int) {
63	s.p.mu.Lock()
64	defer s.p.mu.Unlock()
65
66	s.p.setExited(status)
67
68	if err := s.transition("stopped"); err != nil {
69		panic(err)
70	}
71}
72
73type execRunningState struct {
74	p *execProcess
75}
76
77func (s *execRunningState) transition(name string) error {
78	switch name {
79	case "stopped":
80		s.p.State = &execStoppedState{p: s.p}
81	default:
82		return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
83	}
84	return nil
85}
86
87func (s *execRunningState) Resize(ws console.WinSize) error {
88	s.p.mu.Lock()
89	defer s.p.mu.Unlock()
90
91	return s.p.resize(ws)
92}
93
94func (s *execRunningState) Start(ctx context.Context) error {
95	s.p.mu.Lock()
96	defer s.p.mu.Unlock()
97
98	return errors.Errorf("cannot start a running process")
99}
100
101func (s *execRunningState) Delete(ctx context.Context) error {
102	s.p.mu.Lock()
103	defer s.p.mu.Unlock()
104
105	return errors.Errorf("cannot delete a running process")
106}
107
108func (s *execRunningState) Kill(ctx context.Context, sig uint32, all bool) error {
109	s.p.mu.Lock()
110	defer s.p.mu.Unlock()
111
112	return s.p.kill(ctx, sig, all)
113}
114
115func (s *execRunningState) SetExited(status int) {
116	s.p.mu.Lock()
117	defer s.p.mu.Unlock()
118
119	s.p.setExited(status)
120
121	if err := s.transition("stopped"); err != nil {
122		panic(err)
123	}
124}
125
126type execStoppedState struct {
127	p *execProcess
128}
129
130func (s *execStoppedState) transition(name string) error {
131	switch name {
132	case "deleted":
133		s.p.State = &deletedState{}
134	default:
135		return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
136	}
137	return nil
138}
139
140func (s *execStoppedState) Resize(ws console.WinSize) error {
141	s.p.mu.Lock()
142	defer s.p.mu.Unlock()
143
144	return errors.Errorf("cannot resize a stopped container")
145}
146
147func (s *execStoppedState) Start(ctx context.Context) error {
148	s.p.mu.Lock()
149	defer s.p.mu.Unlock()
150
151	return errors.Errorf("cannot start a stopped process")
152}
153
154func (s *execStoppedState) Delete(ctx context.Context) error {
155	s.p.mu.Lock()
156	defer s.p.mu.Unlock()
157	if err := s.p.delete(ctx); err != nil {
158		return err
159	}
160	return s.transition("deleted")
161}
162
163func (s *execStoppedState) Kill(ctx context.Context, sig uint32, all bool) error {
164	s.p.mu.Lock()
165	defer s.p.mu.Unlock()
166
167	return s.p.kill(ctx, sig, all)
168}
169
170func (s *execStoppedState) SetExited(status int) {
171	// no op
172}
173