diff --git a/cmd/cmd.go b/cmd/cmd.go index ad4be7f9..b9047529 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -1236,11 +1236,11 @@ func checkServerHeartbeat(cmd *cobra.Command, _ []string) error { return err } if err := client.Heartbeat(cmd.Context()); err != nil { - if !strings.Contains(err.Error(), " refused") { + if !(strings.Contains(err.Error(), " refused") || strings.Contains(err.Error(), "could not connect")) { return err } if err := startApp(cmd.Context(), client); err != nil { - return errors.New("could not connect to ollama app, is it running?") + return fmt.Errorf("ollama server not responding - %w", err) } } return nil diff --git a/cmd/start_windows.go b/cmd/start_windows.go index 5bca2433..bcc51057 100644 --- a/cmd/start_windows.go +++ b/cmd/start_windows.go @@ -4,17 +4,27 @@ import ( "context" "errors" "fmt" + "log/slog" "os" "os/exec" + "path" "path/filepath" "strings" "syscall" + "unsafe" "github.com/ollama/ollama/api" + "golang.org/x/sys/windows" +) + +const ( + Installer = "OllamaSetup.exe" ) func startApp(ctx context.Context, client *api.Client) error { - // log.Printf("XXX Attempting to find and start ollama app") + if len(isProcRunning(Installer)) > 0 { + return fmt.Errorf("upgrade in progress...") + } AppName := "ollama app.exe" exe, err := os.Executable() if err != nil { @@ -56,3 +66,41 @@ func startApp(ctx context.Context, client *api.Client) error { } return waitForServer(ctx, client) } + +func isProcRunning(procName string) []uint32 { + pids := make([]uint32, 2048) + var ret uint32 + if err := windows.EnumProcesses(pids, &ret); err != nil || ret == 0 { + slog.Debug("failed to check for running installers", "error", err) + return nil + } + pids = pids[:ret] + var matches []uint32 + for _, pid := range pids { + if pid == 0 { + continue + } + hProcess, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, pid) + if err != nil { + continue + } + defer windows.CloseHandle(hProcess) + var module windows.Handle + var cbNeeded uint32 + cb := (uint32)(unsafe.Sizeof(module)) + if err := windows.EnumProcessModules(hProcess, &module, cb, &cbNeeded); err != nil { + continue + } + var sz uint32 = 1024 * 8 + moduleName := make([]uint16, sz) + cb = uint32(len(moduleName)) * (uint32)(unsafe.Sizeof(uint16(0))) + if err := windows.GetModuleBaseName(hProcess, module, &moduleName[0], cb); err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER { + continue + } + exeFile := path.Base(strings.ToLower(syscall.UTF16ToString(moduleName))) + if strings.EqualFold(exeFile, procName) { + matches = append(matches, pid) + } + } + return matches +}