package main import ( "encoding/json" "errors" "io" "log" "os" "os/exec" "path" "time" ) func copy(src, dst string, stdlog *log.Logger) error { fi, err := os.Stat(src) if err != nil { return err } if fi.IsDir() { entries, _ := os.ReadDir(src) for _, ent := range entries { if err := copy(path.Join(src, ent.Name()), path.Join(dst, ent.Name()), stdlog); err != nil { return err } } return nil } inmode := fi.Mode() in, err := os.Open(src) if err != nil { return err } defer in.Close() out, err := os.Create(dst) if err != nil { return err } defer out.Close() copied, err := io.Copy(out, in) if err != nil { return err } if copied < fi.Size() { return errors.New("copy not completed") } if err := out.Sync(); err != nil { return err } if err := out.Chmod(inmode); err != nil { return err } stdlog.Println("file copied :", src, dst) return nil } func main() { logfile, _ := os.OpenFile("replacer.log", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) defer logfile.Close() stdlog := log.New(logfile, "", log.LstdFlags) args := os.Args // args[1] : 나를 시작한 pid. pid가 종료될 때 까지 기다림 // args[2] : target 폴더 // args[3:] : 다시 시작할 때 넘겨줄 arguments(프로세스 이름 포함) stdlog.Println(args) for { stdlog.Println("wait for terminating of", args[3]) cmd := exec.Command("ps", "-p", args[1]) if err := cmd.Run(); err != nil { break } time.Sleep(time.Second) } stdlog.Println("target is terminated") // replacer 제거. 내가 돌고 있으므로 복사는 안된다. // 내가 실행되기 전에 이미 복사가 되서 나는 최신 버전임 os.Remove(path.Join(args[2], os.Args[0])) if err := copy(args[2], "", stdlog); err != nil { stdlog.Fatal(err) } nextArgs := args[4:] if bt, _ := os.ReadFile("@args"); len(bt) > 0 { var tempArgs []string if json.Unmarshal(bt, &tempArgs) == nil { nextArgs = tempArgs } } os.Remove("@args") err := os.RemoveAll(args[2]) if err != nil { stdlog.Println("os.RemoveAll failed :", args[2], err) } err = os.Chmod(args[3], 0775) if err != nil { stdlog.Println("os.Chmod failed :", err) } stdlog.Println("exec.Command :", args) cmd := exec.Command(args[3], nextArgs...) cmd.Start() }