// KBFSServiceStatus returns service status for KBFS func KBFSServiceStatus(context Context, label string, wait time.Duration, log Log) (status keybase1.ServiceStatus) { if label == "" { status = keybase1.ServiceStatus{Status: keybase1.StatusFromCode(keybase1.StatusCode_SCServiceStatusError, "No service label")} return } kbfsService := launchd.NewService(label) status, err := serviceStatusFromLaunchd(kbfsService, context.GetKBFSInfoPath(), wait, log) if err != nil { return } bundleVersion, err := KBFSBundleVersion(context, "") if err != nil { status.Status = keybase1.StatusFromCode(keybase1.StatusCode_SCServiceStatusError, err.Error()) return } status.BundleVersion = bundleVersion if status.InstallStatus == keybase1.InstallStatus_NOT_INSTALLED { return } installStatus, installAction, kbStatus := ResolveInstallStatus(status.Version, status.BundleVersion, status.LastExitStatus, log) status.InstallStatus = installStatus status.InstallAction = installAction status.Status = kbStatus return }
func keybaseServiceStatus(g *libkb.GlobalContext, label string, bundleVersion string) keybase1.ServiceStatus { if label == "" { label = defaultServiceLabel(g.Env.GetRunMode()) } kbService := launchd.NewService(label) st, done := serviceStatusFromLaunchd(kbService, path.Join(g.Env.GetRuntimeDir(), "keybased.info")) st.BundleVersion = bundleVersion if done { return st } // Something must be wrong if this build doesn't match the package version. buildVersion := libkb.VersionString() if bundleVersion != "" && bundleVersion != buildVersion { st.InstallAction = keybase1.InstallAction_NONE st.InstallStatus = keybase1.InstallStatus_ERROR st.Status = errorStatus("INSTALL_ERROR", fmt.Sprintf("Version mismatch: %s != %s", bundleVersion, buildVersion)) return st } installStatus, installAction, status := installStatus(st.Version, st.BundleVersion, st.LastExitStatus) st.InstallStatus = installStatus st.InstallAction = installAction st.Status = status return st }
func autoInstall(g *libkb.GlobalContext, binPath string, force bool) (newProc bool, componentResults []keybase1.ComponentResult, err error) { g.Log.Debug("+ AutoInstall for launchd") defer func() { g.Log.Debug("- AutoInstall -> %v, %v", newProc, err) }() label := DefaultServiceLabel(g.Env.GetRunMode()) if label == "" { err = fmt.Errorf("No service label to install") return } resolvedBinPath, err := chooseBinPath(binPath) if err != nil { return } g.Log.Debug("Using binPath: %s", resolvedBinPath) service := launchd.NewService(label) plist := keybasePlist(g, resolvedBinPath, label) // Check if plist is valid. If so we're already installed and return. plistValid, err := service.CheckPlist(plist) if err != nil || plistValid { return } err = installService(g, binPath, true) componentResults = append(componentResults, componentResult(string(ComponentNameService), err)) if err != nil { return } newProc = true return }
func KBFSServiceStatus(g *libkb.GlobalContext, label string) (status keybase1.ServiceStatus) { if label == "" { label = DefaultKBFSLabel(g.Env.GetRunMode()) } kbfsService := launchd.NewService(label) status, err := serviceStatusFromLaunchd(g, kbfsService, path.Join(g.Env.GetRuntimeDir(), "kbfs.info")) if err != nil { return } bundleVersion, err := KBFSBundleVersion(g, "") if err != nil { status.Status = keybase1.StatusFromCode(keybase1.StatusCode_SCServiceStatusError, err.Error()) return } status.BundleVersion = bundleVersion if status.InstallStatus == keybase1.InstallStatus_NOT_INSTALLED { return } installStatus, installAction, kbStatus := ResolveInstallStatus(status.Version, status.BundleVersion, status.LastExitStatus) status.InstallStatus = installStatus status.InstallAction = installAction status.Status = kbStatus return }
// UpdaterServiceStatus returns service status for the Updater service func UpdaterServiceStatus(context Context, label string) keybase1.ServiceStatus { if label == "" { return keybase1.ServiceStatus{Status: keybase1.StatusFromCode(keybase1.StatusCode_SCServiceStatusError, "No service label")} } serviceStatus := keybase1.ServiceStatus{Label: label} updaterService := launchd.NewService(label) status, err := updaterService.WaitForStatus(defaultLaunchdWait, 500*time.Millisecond) if err != nil { serviceStatus.Status = keybase1.StatusFromCode(keybase1.StatusCode_SCServiceStatusError, err.Error()) return serviceStatus } if status != nil { serviceStatus.Pid = status.Pid() serviceStatus.LastExitStatus = status.LastExitStatus() } if serviceStatus.Pid != "" { serviceStatus.InstallStatus = keybase1.InstallStatus_INSTALLED serviceStatus.InstallAction = keybase1.InstallAction_NONE } else { serviceStatus.InstallStatus = keybase1.InstallStatus_NOT_INSTALLED serviceStatus.InstallAction = keybase1.InstallAction_INSTALL } serviceStatus.Status = keybase1.StatusOK("") return serviceStatus }
func installKBFSService(g *libkb.GlobalContext, binPath string) (*keybase1.ServiceStatus, error) { runMode := g.Env.GetRunMode() label := defaultKBFSLabel(runMode) kbfsBinPath, err := kbfsBinPath(runMode, binPath) if err != nil { return nil, err } mountPath := kbfsMountPath(g.Env.GetHome(), runMode) // Create mount dir if it doesn't exist if _, err := os.Stat(mountPath); os.IsNotExist(err) { // TODO Make dir hidden so it only shows when mounted? err := os.MkdirAll(mountPath, libkb.PermDir) if err != nil { return nil, err } } plistArgs := []string{mountPath} envVars := defaultLaunchdEnvVars(g, label) plist := launchd.NewPlist(label, kbfsBinPath, plistArgs, envVars) err = launchd.Install(plist, os.Stdout) if err != nil { return nil, err } kbfsService := launchd.NewService(label) st, _ := serviceStatusFromLaunchd(kbfsService, "") return &st, nil }
func installKBFSService(g *libkb.GlobalContext, binPath string) (*keybase1.ServiceStatus, error) { runMode := g.Env.GetRunMode() label := defaultKBFSLabel(runMode) kbfsBinPath, err := kbfsBinPath(runMode, binPath) if err != nil { return nil, err } mountPath := kbfsMountPath(runMode) _, err = os.Stat(mountPath) if err != nil { return nil, err } // TODO: Remove when doing real release plistArgs := []string{"-debug", mountPath} envVars := DefaultLaunchdEnvVars(g, label) plist := launchd.NewPlist(label, kbfsBinPath, plistArgs, envVars) err = launchd.Install(plist, g.Log) if err != nil { return nil, err } kbfsService := launchd.NewService(label) st, err := serviceStatusFromLaunchd(kbfsService, "") return &st, err }
func restartLaunchdService(g *libkb.GlobalContext, label string, serviceInfoPath string) error { launchService := launchd.NewService(label) launchService.SetLogger(g.Log) err := launchService.Restart(defaultLaunchdWait) if err != nil { return err } return WaitForService(g, launchService, serviceInfoPath) }
func installUpdater(context Context, keybaseBinPath string, force bool, log Log) error { if context.GetRunMode() != libkb.ProductionRunMode { return fmt.Errorf("Updater not supported in this run mode") } keybaseBinPath, err := chooseBinPath(keybaseBinPath) if err != nil { return err } updaterBinPath := filepath.Join(filepath.Dir(keybaseBinPath), "updater") if err != nil { return err } log.Debug("Using updater path: %s", updaterBinPath) label := DefaultUpdaterLabel(context.GetRunMode()) service := launchd.NewService(label) plist, err := updaterPlist(context, label, updaterBinPath, keybaseBinPath) if err != nil { return err } launchdStatus, err := service.LoadStatus() if err != nil { return err } needsInstall := false if launchdStatus == nil { log.Debug("No status, needs install") needsInstall = true } if !needsInstall { plistValid, err := service.CheckPlist(plist) if err != nil { return err } if !plistValid { log.Debug("Plist needs update: %s", service.PlistDestination()) needsInstall = true } } if needsInstall || force { uninstallUpdater(context.GetRunMode(), log) log.Debug("Installing updater service") _, err := installUpdaterService(service, plist, defaultLaunchdWait, log) if err != nil { log.Errorf("Error installing updater service: %s", err) return err } } return nil }
func (c *CtlHandler) stopLaunchd() { status := install.KeybaseServiceStatus(c.G(), c.G().Env.GetLabel()) if status.Pid == "" { c.G().Log.Debug("Service does not appear to be running via launchd (label = %q)", c.G().Env.GetLabel()) return } c.G().Log.Debug("Removing %s from launchd", status.Label) svc := launchd.NewService(status.Label) if err := svc.Stop(false); err != nil { c.G().Log.Warning("error stopping launchd service:", err) } }
func installKeybaseService(g *libkb.GlobalContext, binPath string) (*keybase1.ServiceStatus, error) { label := defaultServiceLabel(g.Env.GetRunMode()) plistArgs := []string{"service"} envVars := DefaultLaunchdEnvVars(g, label) plist := launchd.NewPlist(label, binPath, plistArgs, envVars) err := launchd.Install(plist, g.Log) if err != nil { return nil, err } kbService := launchd.NewService(label) st, err := serviceStatusFromLaunchd(kbService, serviceInfoPath(g)) return &st, err }
func installKeybaseService(g *libkb.GlobalContext, binPath string) (*keybase1.ServiceStatus, error) { label := DefaultServiceLabel(g.Env.GetRunMode()) // TODO: Remove -d when doing real release plistArgs := []string{"-d", "service"} envVars := DefaultLaunchdEnvVars(g, label) plist := launchd.NewPlist(label, binPath, plistArgs, envVars, libkb.ServiceLogFileName) err := launchd.Install(plist, g.Log) if err != nil { return nil, err } kbService := launchd.NewService(label) st, err := serviceStatusFromLaunchd(g, kbService, serviceInfoPath(g)) return &st, err }
func kbfsServiceStatus(g *libkb.GlobalContext, label string, bundleVersion string) keybase1.ServiceStatus { if label == "" { label = defaultKBFSLabel(g.Env.GetRunMode()) } kbfsService := launchd.NewService(label) st, done := serviceStatusFromLaunchd(kbfsService, path.Join(g.Env.GetRuntimeDir(), "kbfs.info")) st.BundleVersion = bundleVersion if done { return st } installStatus, installAction, status := installStatus(st.Version, st.BundleVersion, st.LastExitStatus) st.InstallStatus = installStatus st.InstallAction = installAction st.Status = status return st }
func KBFSServiceStatus(g *libkb.GlobalContext, bundleVersion string) keybase1.ServiceStatus { serviceLabel := libkb.DefaultServiceLabel(libkb.KBFSServiceID, libkb.DefaultRunMode) kbfsService := launchd.NewService(serviceLabel) kbfsLaunchdStatus, err := kbfsService.Status() if err != nil { return errorStatus(err) } if kbfsLaunchdStatus == nil { return keybase1.ServiceStatus{InstallStatus: keybase1.InstallStatus_NOT_INSTALLED} } var kbfsInfo *libkb.ServiceInfo if kbfsLaunchdStatus.Pid() != "" { runtimeDir := g.Env.GetRuntimeDir() kbfsInfo, err = libkb.WaitForServiceInfoFile(path.Join(runtimeDir, "kbfs.info"), kbfsLaunchdStatus.Pid(), 5, 500*time.Millisecond, "launchd status for kbfs") if err != nil { return errorStatus(err) } } // nil means not running or file wasn't found if kbfsInfo == nil { kbfsInfo = &libkb.ServiceInfo{} } version := kbfsInfo.Version st := keybase1.ServiceStatus{ Version: version, Label: kbfsLaunchdStatus.Label(), Pid: kbfsLaunchdStatus.Pid(), LastExitStatus: kbfsLaunchdStatus.LastExitStatus(), BundleVersion: bundleVersion, } installStatus, installAction, se := installStatus(version, bundleVersion, st.LastExitStatus) st.InstallStatus = installStatus st.InstallAction = installAction st.Error = se return st }
func installService(context Context, binPath string, force bool, log Log) error { resolvedBinPath, err := chooseBinPath(binPath) if err != nil { return err } log.Debug("Using binPath: %s", resolvedBinPath) label := DefaultServiceLabel(context.GetRunMode()) service := launchd.NewService(label) plist, err := keybasePlist(context, resolvedBinPath, label, log) if err != nil { return err } log.Debug("Checking service: %s", label) keybaseStatus := KeybaseServiceStatus(context, label, time.Second, log) log.Debug("Service: %s (Action: %s); %#v", keybaseStatus.InstallStatus.String(), keybaseStatus.InstallAction.String(), keybaseStatus) needsInstall := keybaseStatus.NeedsInstall() if !needsInstall { plistValid, err := service.CheckPlist(plist) if err != nil { return err } if !plistValid { log.Debug("Needs plist upgrade: %s", service.PlistDestination()) needsInstall = true } } if needsInstall || force { uninstallKeybaseServices(context.GetRunMode(), log) log.Debug("Installing Keybase service") _, err := installKeybaseService(context, service, plist, defaultLaunchdWait, log) if err != nil { log.Errorf("Error installing Keybase service: %s", err) return err } } return nil }
func KeybaseServiceStatus(g *libkb.GlobalContext, label string) (status keybase1.ServiceStatus) { if label == "" { label = DefaultServiceLabel(g.Env.GetRunMode()) } kbService := launchd.NewService(label) status, err := serviceStatusFromLaunchd(g, kbService, path.Join(g.Env.GetRuntimeDir(), "keybased.info")) status.BundleVersion = libkb.VersionString() if err != nil { return } if status.InstallStatus == keybase1.InstallStatus_NOT_INSTALLED { return } installStatus, installAction, kbStatus := ResolveInstallStatus(status.Version, status.BundleVersion, status.LastExitStatus) status.InstallStatus = installStatus status.InstallAction = installAction status.Status = kbStatus return }
// KBFS installs the KBFS service func KBFS(context Context, binPath string, force bool, log Log) error { runMode := context.GetRunMode() label := DefaultKBFSLabel(runMode) kbfsService := launchd.NewService(label) kbfsBinPath, err := KBFSBinPath(runMode, binPath) if err != nil { return err } plist, err := kbfsPlist(context, kbfsBinPath, label) if err != nil { return err } log.Debug("Checking KBFS") kbfsStatus := KBFSServiceStatus(context, label, time.Second, log) log.Debug("KBFS: %s (Action: %s); %#v", kbfsStatus.InstallStatus.String(), kbfsStatus.InstallAction.String(), kbfsStatus) needsInstall := kbfsStatus.NeedsInstall() if !needsInstall { plistValid, err := kbfsService.CheckPlist(plist) if err != nil { return err } if !plistValid { log.Debug("Needs plist upgrade: %s", kbfsService.PlistDestination()) needsInstall = true } } if needsInstall || force { uninstallKBFSServices(context.GetRunMode(), log) log.Debug("Installing KBFS") _, err := installKBFSService(context, kbfsService, plist, defaultLaunchdWait, log) if err != nil { log.Errorf("Error installing KBFS: %s", err) return err } } return nil }
func installKBFS(g *libkb.GlobalContext, binPath string, force bool) error { runMode := g.Env.GetRunMode() label := DefaultKBFSLabel(runMode) kbfsService := launchd.NewService(label) kbfsBinPath, err := kbfsBinPath(runMode, binPath) if err != nil { return err } plist, err := kbfsPlist(g, kbfsBinPath, label) if err != nil { return err } g.Log.Debug("Checking KBFS") kbfsStatus := KBFSServiceStatus(g, label) g.Log.Debug("KBFS: %s (Action: %s)", kbfsStatus.InstallStatus.String(), kbfsStatus.InstallAction.String()) needsInstall := kbfsStatus.NeedsInstall() if !needsInstall { plistValid, err := kbfsService.CheckPlist(plist) if err != nil { return err } if !plistValid { g.Log.Debug("Needs plist upgrade: %s", kbfsService.PlistDestination()) needsInstall = true } } if needsInstall || force { uninstallKBFSServices(g, g.Env.GetRunMode()) g.Log.Debug("Installing KBFS") _, err := installKBFSService(g, kbfsService, plist) if err != nil { g.Log.Errorf("Error installing KBFS: %s", err) return err } } return nil }
func BrewAutoInstall(g *libkb.GlobalContext) (newProc bool, err error) { g.Log.Debug("+ BrewAutoInstall for launchd") defer func() { g.Log.Debug("- BrewAutoInstall -> %v, %v", newProc, err) }() label := defaultBrewServiceLabel(g.Env.GetRunMode()) if label == "" { err = fmt.Errorf("No service label to install") return newProc, err } // Check if plist is installed. If so we're already installed and return. plistPath := launchd.PlistDestination(label) if _, err := os.Stat(plistPath); err == nil { g.Log.Debug("| already installed at %s", plistPath) return newProc, nil } // Get the full path to this executable using the brew opt bin directory. binName := filepath.Base(os.Args[0]) binPath := filepath.Join("/usr/local/opt", binName, "bin", binName) g.Log.Debug("| assembled binPath = %s", binPath) plistArgs := []string{"service"} envVars := defaultEnvVars(g, label) plist := launchd.NewPlist(label, binPath, plistArgs, envVars) err = launchd.Install(plist, ioutil.Discard) if err != nil { return newProc, err } // Get service install status. This causes us to pause (with timeout) until // the service is up. kbService := launchd.NewService(label) ServiceStatusFromLaunchd(kbService, path.Join(g.Env.GetRuntimeDir(), "keybased.info")) newProc = true return newProc, nil }
func installService(g *libkb.GlobalContext, binPath string, force bool) error { resolvedBinPath, err := chooseBinPath(binPath) if err != nil { return err } g.Log.Debug("Using binPath: %s", resolvedBinPath) label := DefaultServiceLabel(g.Env.GetRunMode()) service := launchd.NewService(label) plist := keybasePlist(g, resolvedBinPath, label) g.Log.Debug("Checking service") keybaseStatus := KeybaseServiceStatus(g, label) g.Log.Debug("Service: %s (Action: %s)", keybaseStatus.InstallStatus.String(), keybaseStatus.InstallAction.String()) needsInstall := keybaseStatus.NeedsInstall() if !needsInstall { plistValid, err := service.CheckPlist(plist) if err != nil { return err } if !plistValid { g.Log.Debug("Needs plist upgrade: %s", service.PlistDestination()) needsInstall = true } } if needsInstall || force { uninstallKeybaseServices(g, g.Env.GetRunMode()) g.Log.Debug("Installing Keybase service") _, err := installKeybaseService(g, service, plist) if err != nil { g.Log.Errorf("Error installing Keybase service: %s", err) return err } } return nil }
func KeybaseServiceStatus(g *libkb.GlobalContext, bundleVersion string) keybase1.ServiceStatus { serviceLabel := libkb.DefaultServiceLabel(libkb.KeybaseServiceID, libkb.DefaultRunMode) kbService := launchd.NewService(serviceLabel) kbLaunchdStatus, err := kbService.Status() if err != nil { return errorStatus(err) } if kbLaunchdStatus == nil { return keybase1.ServiceStatus{InstallStatus: keybase1.InstallStatus_NOT_INSTALLED} } var config keybase1.Config if kbLaunchdStatus.Pid() != "" { runtimeDir := g.Env.GetRuntimeDir() _, err := libkb.WaitForServiceInfoFile(path.Join(runtimeDir, "keybased.info"), kbLaunchdStatus.Pid(), 5, 500*time.Millisecond, "launchd status for service") if err != nil { return errorStatus(err) } configClient, err := GetConfigClient(g) if err != nil { return errorStatus(err) } config, err = configClient.GetConfig(context.TODO(), 0) if err != nil { return errorStatus(err) } if config.Label != kbLaunchdStatus.Label() { return errorStatus(fmt.Errorf("Service label mismatch: %s != %s", config.Label, kbLaunchdStatus.Label())) } } version := config.Version buildVersion := libkb.VersionString() st := keybase1.ServiceStatus{ Version: config.Version, Label: kbLaunchdStatus.Label(), Pid: kbLaunchdStatus.Pid(), LastExitStatus: kbLaunchdStatus.LastExitStatus(), BundleVersion: bundleVersion, } // Something must be wrong if this build doesn't match the package version. if bundleVersion != buildVersion { st.InstallStatus = keybase1.InstallStatus_ERROR st.InstallAction = keybase1.InstallAction_NONE st.Error = &keybase1.ServiceStatusError{Message: fmt.Sprintf("Version mismatch: %s != %s", bundleVersion, buildVersion)} return st } installStatus, installAction, se := installStatus(version, bundleVersion, st.LastExitStatus) st.InstallStatus = installStatus st.InstallAction = installAction st.Error = se return st }