diff --git a/cmd/serv.go b/cmd/serv.go index 9063a1c2c9..63befa88b4 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -24,6 +24,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/pprof" "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/services/lfs" @@ -247,7 +248,7 @@ func runServ(c *cli.Context) error { os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID)) os.Setenv(models.EnvAppURL, setting.AppURL) - //LFS token authentication + // LFS token authentication if verb == lfsAuthenticateVerb { url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName)) @@ -306,6 +307,7 @@ func runServ(c *cli.Context) error { } } + process.SetSysProcAttribute(gitcmd) gitcmd.Dir = setting.RepoRootPath gitcmd.Stdout = os.Stdout gitcmd.Stdin = os.Stdin diff --git a/modules/git/blame.go b/modules/git/blame.go index b30124594d..f887e4bf7d 100644 --- a/modules/git/blame.go +++ b/modules/git/blame.go @@ -130,6 +130,7 @@ func createBlameReader(ctx context.Context, dir string, command ...string) (*Bla cmd := exec.CommandContext(ctx, command[0], command[1:]...) cmd.Dir = dir cmd.Stderr = os.Stderr + process.SetSysProcAttribute(cmd) stdout, err := cmd.StdoutPipe() if err != nil { diff --git a/modules/git/command.go b/modules/git/command.go index ba4a8e3688..135e9755fd 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -188,6 +188,7 @@ func (c *Command) RunWithContext(rc *RunContext) error { if goVersionLessThan115 { cmd.Env = append(cmd.Env, "GODEBUG=asyncpreemptoff=1") } + process.SetSysProcAttribute(cmd) cmd.Dir = rc.Dir cmd.Stdout = rc.Stdout cmd.Stderr = rc.Stderr diff --git a/modules/markup/external/external.go b/modules/markup/external/external.go index 3acb601067..0f9d7935d3 100644 --- a/modules/markup/external/external.go +++ b/modules/markup/external/external.go @@ -119,6 +119,8 @@ func (p *Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io. cmd.Stdin = input } cmd.Stdout = output + process.SetSysProcAttribute(cmd) + if err := cmd.Run(); err != nil { return fmt.Errorf("%s render run command %s %v failed: %v", p.Name(), commands[0], args, err) } diff --git a/modules/process/manager.go b/modules/process/manager.go index 7cde9f9451..0522b2f5d9 100644 --- a/modules/process/manager.go +++ b/modules/process/manager.go @@ -254,13 +254,13 @@ func (pm *Manager) ExecDirEnvStdIn(timeout time.Duration, dir, desc string, env if stdIn != nil { cmd.Stdin = stdIn } + SetSysProcAttribute(cmd) if err := cmd.Start(); err != nil { return "", "", err } err := cmd.Wait() - if err != nil { err = &Error{ PID: GetPID(ctx), diff --git a/modules/process/manager_unix.go b/modules/process/manager_unix.go new file mode 100644 index 0000000000..2ed8009eec --- /dev/null +++ b/modules/process/manager_unix.go @@ -0,0 +1,19 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +//go:build !windows +// +build !windows + +package process + +import ( + "os/exec" + "syscall" +) + +// SetSysProcAttribute sets the common SysProcAttrs for commands +func SetSysProcAttribute(cmd *exec.Cmd) { + // When Gitea runs SubProcessA -> SubProcessB and SubProcessA gets killed by context timeout, use setpgid to make sure the sub processes can be reaped instead of leaving defunct(zombie) processes. + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} +} diff --git a/modules/process/manager_windows.go b/modules/process/manager_windows.go new file mode 100644 index 0000000000..892275382a --- /dev/null +++ b/modules/process/manager_windows.go @@ -0,0 +1,17 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +//go:build windows +// +build windows + +package process + +import ( + "os/exec" +) + +// SetSysProcAttribute sets the common SysProcAttrs for commands +func SetSysProcAttribute(cmd *exec.Cmd) { + // Do nothing +} diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index 5b09e0e37e..eb8d333d78 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -24,6 +24,7 @@ import ( asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -100,6 +101,8 @@ func sessionHandler(session ssh.Session) { } defer stdin.Close() + process.SetSysProcAttribute(cmd) + wg := &sync.WaitGroup{} wg.Add(2) @@ -330,7 +333,7 @@ func GenKeyPair(keyPath string) error { } privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)} - f, err := os.OpenFile(keyPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + f, err := os.OpenFile(keyPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600) if err != nil { return err } @@ -351,7 +354,7 @@ func GenKeyPair(keyPath string) error { } public := gossh.MarshalAuthorizedKey(pub) - p, err := os.OpenFile(keyPath+".pub", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + p, err := os.OpenFile(keyPath+".pub", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600) if err != nil { return err } diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go index e5e6272f10..dfb7bab998 100644 --- a/services/mailer/mailer.go +++ b/services/mailer/mailer.go @@ -284,6 +284,7 @@ func (s *sendmailSender) Send(from string, to []string, msg io.WriterTo) error { if err != nil { return err } + process.SetSysProcAttribute(cmd) if err = cmd.Start(); err != nil { _ = pipe.Close()