2016-08-13 12:49:04 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
2018-06-05 19:11:20 +00:00
|
|
|
"net"
|
2016-08-13 12:49:04 +00:00
|
|
|
"os"
|
2016-09-06 20:05:18 +00:00
|
|
|
"path/filepath"
|
2018-02-17 16:22:40 +00:00
|
|
|
"runtime"
|
2016-09-01 20:49:56 +00:00
|
|
|
"runtime/pprof"
|
2019-03-17 16:52:34 +00:00
|
|
|
"strconv"
|
2016-08-13 12:49:04 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2018-07-31 21:21:55 +00:00
|
|
|
envPath = os.Getenv("PATH")
|
2018-07-28 13:52:54 +00:00
|
|
|
envLevel = os.Getenv("LF_LEVEL")
|
2016-08-13 12:49:04 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2016-12-17 21:47:37 +00:00
|
|
|
gClientID int
|
2017-08-06 08:05:46 +00:00
|
|
|
gHostname string
|
2016-08-14 12:45:24 +00:00
|
|
|
gLastDirPath string
|
2016-08-13 12:49:04 +00:00
|
|
|
gSelectionPath string
|
2017-07-20 22:26:36 +00:00
|
|
|
gSocketProt string
|
2016-08-13 12:49:04 +00:00
|
|
|
gSocketPath string
|
|
|
|
gLogPath string
|
|
|
|
gServerLogPath string
|
2019-02-10 16:48:49 +00:00
|
|
|
gSelect string
|
|
|
|
gCommand string
|
2018-03-22 17:42:15 +00:00
|
|
|
gVersion string
|
2016-08-13 12:49:04 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
2017-11-19 18:55:13 +00:00
|
|
|
h, err := os.Hostname()
|
2017-08-06 08:05:46 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("hostname: %s", err)
|
2016-11-05 21:08:51 +00:00
|
|
|
}
|
2017-11-19 18:55:13 +00:00
|
|
|
gHostname = h
|
2018-07-28 13:52:54 +00:00
|
|
|
|
|
|
|
if envLevel == "" {
|
|
|
|
envLevel = "0"
|
|
|
|
}
|
2016-08-13 12:49:04 +00:00
|
|
|
}
|
|
|
|
|
2019-03-17 16:52:34 +00:00
|
|
|
func exportEnvVars() {
|
|
|
|
os.Setenv("id", strconv.Itoa(gClientID))
|
|
|
|
|
|
|
|
os.Setenv("OPENER", envOpener)
|
|
|
|
os.Setenv("EDITOR", envEditor)
|
|
|
|
os.Setenv("PAGER", envPager)
|
|
|
|
os.Setenv("SHELL", envShell)
|
|
|
|
|
|
|
|
level, err := strconv.Atoi(envLevel)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("reading lf level: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
level++
|
|
|
|
|
|
|
|
os.Setenv("LF_LEVEL", strconv.Itoa(level))
|
|
|
|
}
|
|
|
|
|
2016-08-13 12:49:04 +00:00
|
|
|
func startServer() {
|
2018-07-31 21:21:55 +00:00
|
|
|
cmd := detachedCommand(os.Args[0], "-server")
|
2016-08-17 20:28:42 +00:00
|
|
|
if err := cmd.Start(); err != nil {
|
2016-08-17 20:06:45 +00:00
|
|
|
log.Printf("starting server: %s", err)
|
2016-08-13 12:49:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-05 19:11:20 +00:00
|
|
|
func checkServer() {
|
|
|
|
if gSocketProt == "unix" {
|
|
|
|
if _, err := os.Stat(gSocketPath); os.IsNotExist(err) {
|
|
|
|
startServer()
|
|
|
|
} else if _, err := net.Dial(gSocketProt, gSocketPath); err != nil {
|
|
|
|
os.Remove(gSocketPath)
|
|
|
|
startServer()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if _, err := net.Dial(gSocketProt, gSocketPath); err != nil {
|
|
|
|
startServer()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-13 12:49:04 +00:00
|
|
|
func main() {
|
2017-11-19 18:55:13 +00:00
|
|
|
showDoc := flag.Bool(
|
|
|
|
"doc",
|
|
|
|
false,
|
|
|
|
"show documentation")
|
|
|
|
|
2018-03-22 17:42:15 +00:00
|
|
|
showVersion := flag.Bool(
|
|
|
|
"version",
|
|
|
|
false,
|
|
|
|
"show version")
|
|
|
|
|
2017-11-19 18:55:13 +00:00
|
|
|
remoteCmd := flag.String(
|
|
|
|
"remote",
|
|
|
|
"",
|
|
|
|
"send remote command to server")
|
|
|
|
|
|
|
|
serverMode := flag.Bool(
|
|
|
|
"server",
|
|
|
|
false,
|
|
|
|
"start server (automatic)")
|
|
|
|
|
|
|
|
cpuprofile := flag.String(
|
|
|
|
"cpuprofile",
|
|
|
|
"",
|
2018-02-17 16:22:40 +00:00
|
|
|
"path to the file to write the CPU profile")
|
|
|
|
|
|
|
|
memprofile := flag.String(
|
|
|
|
"memprofile",
|
|
|
|
"",
|
|
|
|
"path to the file to write the memory profile")
|
2017-11-19 18:55:13 +00:00
|
|
|
|
|
|
|
flag.StringVar(&gLastDirPath,
|
|
|
|
"last-dir-path",
|
|
|
|
"",
|
|
|
|
"path to the file to write the last dir on exit (to use for cd)")
|
|
|
|
|
|
|
|
flag.StringVar(&gSelectionPath,
|
|
|
|
"selection-path",
|
|
|
|
"",
|
|
|
|
"path to the file to write selected files on open (to use as open file dialog)")
|
2016-08-13 12:49:04 +00:00
|
|
|
|
2019-02-06 11:56:06 +00:00
|
|
|
flag.StringVar(&gCommand,
|
|
|
|
"command",
|
|
|
|
"",
|
|
|
|
"command to execute on client initialization")
|
|
|
|
|
2016-08-13 12:49:04 +00:00
|
|
|
flag.Parse()
|
|
|
|
|
2017-08-06 15:26:38 +00:00
|
|
|
gSocketProt = gDefaultSocketProt
|
|
|
|
gSocketPath = gDefaultSocketPath
|
|
|
|
|
2017-11-19 18:55:13 +00:00
|
|
|
if *cpuprofile != "" {
|
|
|
|
f, err := os.Create(*cpuprofile)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("could not create CPU profile: %s", err)
|
|
|
|
}
|
|
|
|
if err := pprof.StartCPUProfile(f); err != nil {
|
|
|
|
log.Fatalf("could not start CPU profile: %s", err)
|
|
|
|
}
|
|
|
|
defer pprof.StopCPUProfile()
|
|
|
|
}
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case *showDoc:
|
2016-09-15 14:08:05 +00:00
|
|
|
fmt.Print(genDocString)
|
2018-03-22 17:42:15 +00:00
|
|
|
case *showVersion:
|
|
|
|
fmt.Println(gVersion)
|
2017-11-19 18:55:13 +00:00
|
|
|
case *remoteCmd != "":
|
2019-02-26 18:27:04 +00:00
|
|
|
if err := remote(*remoteCmd); err != nil {
|
2016-12-19 18:28:57 +00:00
|
|
|
log.Fatalf("remote command: %s", err)
|
|
|
|
}
|
2017-11-19 18:55:13 +00:00
|
|
|
case *serverMode:
|
2017-08-06 08:05:46 +00:00
|
|
|
gServerLogPath = filepath.Join(os.TempDir(), fmt.Sprintf("lf.%s.server.log", gUser.Username))
|
2016-08-13 12:49:04 +00:00
|
|
|
serve()
|
2017-11-19 18:55:13 +00:00
|
|
|
default:
|
2018-06-05 19:11:20 +00:00
|
|
|
checkServer()
|
2016-08-13 12:49:04 +00:00
|
|
|
|
2017-08-06 08:05:46 +00:00
|
|
|
gClientID = 1000
|
|
|
|
gLogPath = filepath.Join(os.TempDir(), fmt.Sprintf("lf.%s.%d.log", gUser.Username, gClientID))
|
2017-11-19 18:55:13 +00:00
|
|
|
for _, err := os.Stat(gLogPath); !os.IsNotExist(err); _, err = os.Stat(gLogPath) {
|
2017-08-06 08:05:46 +00:00
|
|
|
gClientID++
|
|
|
|
gLogPath = filepath.Join(os.TempDir(), fmt.Sprintf("lf.%s.%d.log", gUser.Username, gClientID))
|
|
|
|
}
|
|
|
|
|
2018-07-30 17:56:57 +00:00
|
|
|
switch flag.NArg() {
|
|
|
|
case 0:
|
|
|
|
_, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "%s\n", err)
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
|
|
|
case 1:
|
2019-02-10 16:48:49 +00:00
|
|
|
gSelect = flag.Arg(0)
|
2018-07-30 17:56:57 +00:00
|
|
|
default:
|
2019-02-10 16:48:49 +00:00
|
|
|
fmt.Fprintf(os.Stderr, "only single file or directory is allowed\n")
|
2018-07-30 17:56:57 +00:00
|
|
|
os.Exit(2)
|
|
|
|
}
|
|
|
|
|
2017-11-19 18:55:13 +00:00
|
|
|
run()
|
2016-08-13 12:49:04 +00:00
|
|
|
}
|
2018-02-17 16:22:40 +00:00
|
|
|
|
|
|
|
if *memprofile != "" {
|
|
|
|
f, err := os.Create(*memprofile)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("could not create memory profile: ", err)
|
|
|
|
}
|
|
|
|
runtime.GC()
|
|
|
|
if err := pprof.WriteHeapProfile(f); err != nil {
|
|
|
|
log.Fatal("could not write memory profile: ", err)
|
|
|
|
}
|
|
|
|
f.Close()
|
|
|
|
}
|
2016-08-13 12:49:04 +00:00
|
|
|
}
|