func cmdInfo(c *cli.Context) error { conf, err := config.Open(c.GlobalString("config")) if err != nil { Logger.Fatalf("Cannot load configuration: %v", err) return nil } fmt.Printf("Debug mode (client): %v\n", os.Getenv("ASSH_DEBUG") == "1") cliPath, _ := osext.Executable() fmt.Printf("CLI Path: %s\n", cliPath) fmt.Printf("Go version: %s\n", runtime.Version()) fmt.Printf("OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH) fmt.Println("") fmt.Printf("RC files:\n") homeDir := utils.GetHomeDir() for _, filename := range conf.IncludedFiles() { relativeFilename := strings.Replace(filename, homeDir, "~", -1) fmt.Printf("- %s\n", relativeFilename) } fmt.Println("") fmt.Println("Statistics:") fmt.Printf("- %d hosts\n", len(conf.Hosts)) fmt.Printf("- %d templates\n", len(conf.Templates)) fmt.Printf("- %d included files\n", len(conf.IncludedFiles())) // FIXME: print info about connections/running processes // FIXME: print info about current config file version return nil }
func GetThisPathParts() (dirPath, fileName, absPath string) { exeFile, err := osext.Executable() if err != nil { panic(err) } return GetPathParts(exeFile) }
func monitor(c *WrapConfig) (int, error) { // If we're the child process, absorb panics. if Wrapped(c) { panicCh := make(chan string) go trackPanic(os.Stdin, os.Stderr, c.DetectDuration, panicCh) // Wait on the panic data panicTxt := <-panicCh if panicTxt != "" { if !c.HidePanic { os.Stderr.Write([]byte(panicTxt)) } c.Handler(panicTxt) } os.Exit(0) } exePath, err := osext.Executable() if err != nil { return -1, err } cmd := exec.Command(exePath, os.Args[1:]...) read, write, err := os.Pipe() if err != nil { return -1, err } cmd.Stdin = read cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Env = append(os.Environ(), c.CookieKey+"="+c.CookieValue) if err != nil { return -1, err } err = cmd.Start() if err != nil { return -1, err } err = syscall.Dup2(int(write.Fd()), int(os.Stderr.Fd())) if err != nil { return -1, err } return -1, nil }
func TestPanicHandler(t *testing.T) { startTestServer() exePath, err := osext.Executable() if err != nil { t.Fatal(err) } // Use the same trick as panicwrap() to re-run ourselves. // In the init() block below, we will then panic. cmd := exec.Command(exePath, os.Args[1:]...) cmd.Env = append(os.Environ(), "BUGSNAG_API_KEY="+testAPIKey, "BUGSNAG_ENDPOINT="+testEndpoint, "please_panic=please_panic") if err = cmd.Start(); err != nil { t.Fatal(err) } if err = cmd.Wait(); err.Error() != "exit status 2" { t.Fatal(err) } json, err := simplejson.NewJson(<-postedJSON) if err != nil { t.Fatal(err) } event := json.Get("events").GetIndex(0) if event.Get("severity").MustString() != "error" { t.Errorf("severity should be error") } exception := event.Get("exceptions").GetIndex(0) if exception.Get("message").MustString() != "ruh roh" { t.Errorf("caught wrong panic") } if exception.Get("errorClass").MustString() != "panic" { t.Errorf("caught wrong panic") } frame := exception.Get("stacktrace").GetIndex(1) // Yeah, we just caught a panic from the init() function below and sent it to the server running above (mindblown) if frame.Get("inProject").MustBool() != true || frame.Get("file").MustString() != "panicwrap_test.go" || frame.Get("lineNumber").MustInt() == 0 { t.Errorf("stack trace seemed wrong: %v", frame) } }
func (u *Updater) update() error { path, err := osext.Executable() if err != nil { return err } old, err := os.Open(path) if err != nil { return err } defer old.Close() err = u.FetchInfo() if err != nil { return err } if u.Info.Version <= u.CurrentVersion { return nil } bin, err := u.fetchAndVerifyFullBin() if err != nil { if err == ErrHashMismatch { logrus.Warnln("update: hash mismatch from full binary") } else { logrus.Warnln("update: error fetching full binary,", err) } logrus.Warnln("update: please update your CLI manually by downloading the latest version for your OS here https://github.com/catalyzeio/cli/releases") return err } // close the old binary before installing because on windows // it can't be renamed if a handle to the file is still open old.Close() err, errRecover := up.FromStream(bytes.NewBuffer(bin)) if errRecover != nil { return fmt.Errorf("update and recovery errors: %q %q", err, errRecover) } if err != nil { return err } logrus.Println("update: your CLI has been successfully updated!") return nil }
func verifyExeDirWriteable() error { exe, err := osext.Executable() if err != nil { return exeGenericError() } exeDir := filepath.Dir(exe) f, err := os.Open(exeDir) if err != nil { return exeGenericError() } info, err := f.Stat() if err != nil { return exeGenericError() } usr, err := user.Current() if err != nil { return exeGenericError() } ownerID := strconv.FormatUint(uint64(info.Sys().(*syscall.Stat_t).Uid), 10) groupID := strconv.FormatUint(uint64(info.Sys().(*syscall.Stat_t).Gid), 10) // permissions are the 9 least significant bits mode := uint32(info.Mode()) & uint32((1<<9)-1) // Ex: 7 7 7 // 111 111 111 // ^ ^ groupWriteAble := uint32(1 << 4) globalWriteAble := uint32(1 << 1) // if user doesn't own the directory, and the directory isn't globally writeable, // and it is false that the directory is group writeable and the user is part of // the group, then we can't update. if ownerID != usr.Uid && (mode&globalWriteAble) != globalWriteAble && !((mode&groupWriteAble) == groupWriteAble && groupID == usr.Gid) { return fmt.Errorf("Your CLI cannot update, because your user cannot directly write to the directory it is in, \"%s\". Run the update command as the owner of the directory, or do the update manually.", exeDir) } return nil }
// runnerConfiguration creates a runnerConfiguration resolving all the // configurations from command line and provided configuration files. func (c *ConfigurationManager) runnerConfiguration(loadDockerVersion versionutil.Version) (runnerConfiguration, error) { // TODO: eliminate suites and just use arguments var conf string // Get first flag if flag.NArg() == 0 { cwd, err := os.Getwd() if err != nil { return runnerConfiguration{}, err } conf = filepath.Join(cwd, "golem.conf") logrus.Debugf("No configuration given, trying current directory %s", conf) } else { absPath, err := filepath.Abs(flag.Arg(0)) if err != nil { return runnerConfiguration{}, err } info, err := os.Stat(absPath) if err != nil { return runnerConfiguration{}, err } if info.IsDir() { absPath = filepath.Join(absPath, "golem.conf") if _, err := os.Stat(absPath); err != nil { return runnerConfiguration{}, err } } conf = absPath } suites, err := parseSuites(flag.Args()) if err != nil { return runnerConfiguration{}, err } // TODO: Support non-linux by downloading and replacing executable path executablePath, err := osext.Executable() if err != nil { return runnerConfiguration{}, fmt.Errorf("error getting path to executable: %s", err) } runnerConfig := runnerConfiguration{ ExecutableName: "golem_runner", ExecutablePath: executablePath, } for _, suite := range suites { resolver := newMultiResolver(c.flagResolver, suite, globalDefault) registrySuite := SuiteConfiguration{ Name: resolver.Name(), Path: resolver.Path(), DockerInDocker: resolver.Dind(), } baseConf := BaseImageConfiguration{ Base: resolver.BaseImage(), ExtraImages: resolver.Images(), DockerLoadVersion: loadDockerVersion, DockerVersion: versionutil.Version(c.dockerVersion), } instances := resolver.Instances() for idx, instance := range instances { name := registrySuite.Name if len(instances) > 1 { name = fmt.Sprintf("%s-%d", name, idx+1) } imageConf := baseConf imageConf.CustomImages = instance.CustomImages conf := InstanceConfiguration{ Name: name, BaseImage: imageConf, RunConfiguration: instance.RunConfiguration, } registrySuite.Instances = append(registrySuite.Instances, conf) } runnerConfig.Suites = append(runnerConfig.Suites, registrySuite) } return runnerConfig, nil }
func wrap(c *WrapConfig) (int, error) { // If we're already wrapped, exit out. if Wrapped(c) { return -1, nil } // Get the path to our current executable exePath, err := osext.Executable() if err != nil { return -1, err } // Pipe the stderr so we can read all the data as we look for panics stderr_r, stderr_w := io.Pipe() // doneCh is closed when we're done, signaling any other goroutines // to end immediately. doneCh := make(chan struct{}) // panicCh is the channel on which the panic text will actually be // sent. panicCh := make(chan string) // On close, make sure to finish off the copying of data to stderr defer func() { defer close(doneCh) stderr_w.Close() <-panicCh }() // Start the goroutine that will watch stderr for any panics go trackPanic(stderr_r, c.Writer, c.DetectDuration, panicCh) // Create the writer for stdout that we're going to use var stdout_w io.Writer = os.Stdout if c.Stdout != nil { stdout_w = c.Stdout } // Build a subcommand to re-execute ourselves. We make sure to // set the environmental variable to include our cookie. We also // set stdin/stdout to match the config. Finally, we pipe stderr // through ourselves in order to watch for panics. cmd := exec.Command(exePath, os.Args[1:]...) cmd.Env = append(os.Environ(), c.CookieKey+"="+c.CookieValue) cmd.Stdin = os.Stdin cmd.Stdout = stdout_w cmd.Stderr = stderr_w if err := cmd.Start(); err != nil { return 1, err } // Listen to signals and capture them forever. We allow the child // process to handle them in some way. sigCh := make(chan os.Signal) signal.Notify(sigCh, os.Interrupt) go func() { defer signal.Stop(sigCh) for { select { case <-doneCh: return case <-sigCh: } } }() if err := cmd.Wait(); err != nil { exitErr, ok := err.(*exec.ExitError) if !ok { // This is some other kind of subprocessing error. return 1, err } exitStatus := 1 if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { exitStatus = status.ExitStatus() } // Close the writer end so that the tracker goroutine ends at some point stderr_w.Close() // Wait on the panic data panicTxt := <-panicCh if panicTxt != "" { if !c.HidePanic { c.Writer.Write([]byte(panicTxt)) } c.Handler(panicTxt) } return exitStatus, nil } return 0, nil }
func (u *Updater) getExecRelativeDir(dir string) string { filename, _ := osext.Executable() path := filepath.Join(filepath.Dir(filename), dir) return path }