1// +build !windows
2
3/*
4   Copyright The containerd Authors.
5
6   Licensed under the Apache License, Version 2.0 (the "License");
7   you may not use this file except in compliance with the License.
8   You may obtain a copy of the License at
9
10       http://www.apache.org/licenses/LICENSE-2.0
11
12   Unless required by applicable law or agreed to in writing, software
13   distributed under the License is distributed on an "AS IS" BASIS,
14   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   See the License for the specific language governing permissions and
16   limitations under the License.
17*/
18
19package process
20
21import (
22	"context"
23
24	"github.com/containerd/console"
25	"github.com/pkg/errors"
26)
27
28type execState interface {
29	Resize(console.WinSize) error
30	Start(context.Context) error
31	Delete(context.Context) error
32	Kill(context.Context, uint32, bool) error
33	SetExited(int)
34	Status(context.Context) (string, error)
35}
36
37type execCreatedState struct {
38	p *execProcess
39}
40
41func (s *execCreatedState) transition(name string) error {
42	switch name {
43	case "running":
44		s.p.execState = &execRunningState{p: s.p}
45	case "stopped":
46		s.p.execState = &execStoppedState{p: s.p}
47	case "deleted":
48		s.p.execState = &deletedState{}
49	default:
50		return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
51	}
52	return nil
53}
54
55func (s *execCreatedState) Resize(ws console.WinSize) error {
56	return s.p.resize(ws)
57}
58
59func (s *execCreatedState) Start(ctx context.Context) error {
60	if err := s.p.start(ctx); err != nil {
61		return err
62	}
63	return s.transition("running")
64}
65
66func (s *execCreatedState) Delete(ctx context.Context) error {
67	if err := s.p.delete(ctx); err != nil {
68		return err
69	}
70
71	return s.transition("deleted")
72}
73
74func (s *execCreatedState) Kill(ctx context.Context, sig uint32, all bool) error {
75	return s.p.kill(ctx, sig, all)
76}
77
78func (s *execCreatedState) SetExited(status int) {
79	s.p.setExited(status)
80
81	if err := s.transition("stopped"); err != nil {
82		panic(err)
83	}
84}
85
86func (s *execCreatedState) Status(ctx context.Context) (string, error) {
87	return "created", nil
88}
89
90type execRunningState struct {
91	p *execProcess
92}
93
94func (s *execRunningState) transition(name string) error {
95	switch name {
96	case "stopped":
97		s.p.execState = &execStoppedState{p: s.p}
98	default:
99		return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
100	}
101	return nil
102}
103
104func (s *execRunningState) Resize(ws console.WinSize) error {
105	return s.p.resize(ws)
106}
107
108func (s *execRunningState) Start(ctx context.Context) error {
109	return errors.Errorf("cannot start a running process")
110}
111
112func (s *execRunningState) Delete(ctx context.Context) error {
113	return errors.Errorf("cannot delete a running process")
114}
115
116func (s *execRunningState) Kill(ctx context.Context, sig uint32, all bool) error {
117	return s.p.kill(ctx, sig, all)
118}
119
120func (s *execRunningState) SetExited(status int) {
121	s.p.setExited(status)
122
123	if err := s.transition("stopped"); err != nil {
124		panic(err)
125	}
126}
127
128func (s *execRunningState) Status(ctx context.Context) (string, error) {
129	return "running", nil
130}
131
132type execStoppedState struct {
133	p *execProcess
134}
135
136func (s *execStoppedState) transition(name string) error {
137	switch name {
138	case "deleted":
139		s.p.execState = &deletedState{}
140	default:
141		return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
142	}
143	return nil
144}
145
146func (s *execStoppedState) Resize(ws console.WinSize) error {
147	return errors.Errorf("cannot resize a stopped container")
148}
149
150func (s *execStoppedState) Start(ctx context.Context) error {
151	return errors.Errorf("cannot start a stopped process")
152}
153
154func (s *execStoppedState) Delete(ctx context.Context) error {
155	if err := s.p.delete(ctx); err != nil {
156		return err
157	}
158
159	return s.transition("deleted")
160}
161
162func (s *execStoppedState) Kill(ctx context.Context, sig uint32, all bool) error {
163	return s.p.kill(ctx, sig, all)
164}
165
166func (s *execStoppedState) SetExited(status int) {
167	// no op
168}
169
170func (s *execStoppedState) Status(ctx context.Context) (string, error) {
171	return "stopped", nil
172}
173