* Moved logger to separate source file.
directory index page (default "index.goph")
-c string
- configuration file (default "gogopherd.cfg")
+ configuration file
-d
allow access to dotfiles
-t int
connection read/write timeout in seconds (default 60)
+ -L string
+ write log to file; empty for stderr
+
-v
produce verbose output
```
"flag"
"fmt"
"io/ioutil"
+ "log"
"os"
"path"
"path/filepath"
showdot bool
indexes bool
timeout int
+ logfile string
verbose bool
}{
iface: "localhost",
showdot: false,
indexes: false,
timeout: 60,
+ logfile: "",
verbose: false,
}
func parseConfigFile(filename string) error {
- tracer.Print("reading config from ", filename)
file, err := ioutil.ReadFile(filename)
if err != nil {
- logger.Print("ReadFile: ", err.Error())
return err
}
+ tracer.Print("reading config from ", filename)
lines := strings.Split(string(file), "\n")
for _, line := range lines {
line = strings.TrimSpace(string(line))
cfg.indexes = strToBool(val)
case "timeout":
cfg.timeout, _ = strconv.Atoi(val)
+ case "logfile":
+ cfg.logfile = val
case "verbose":
cfg.verbose = strToBool(val)
default:
- logger.Print("ignoring unknown config item: ", name)
+ logger.Print("ignoring unknown config file option: ", name)
}
}
return nil
}
func initialize() {
+ var err error
help := false
- cfgfile := "gogopherd.cfg"
+ cfgfile := ""
flag.StringVar(&cfgfile, "c", cfgfile, "configuration file")
- flag.StringVar(&cfg.iface, "i", cfg.iface, "interface to bind to")
+ flag.StringVar(&cfg.iface, "i", cfg.iface, "interface to bind to; empty for any")
flag.StringVar(&cfg.port, "p", cfg.port, "TCP port to listen on")
flag.StringVar(&cfg.fqdn, "f", cfg.fqdn, "fully qualified domain name")
flag.StringVar(&cfg.docroot, "r", cfg.docroot, "document root directory")
flag.BoolVar(&cfg.showdot, "d", cfg.showdot, "allow access to dotfiles")
flag.BoolVar(&cfg.indexes, "l", cfg.indexes, "allow generated directory indexes")
flag.IntVar(&cfg.timeout, "t", cfg.timeout, "connection read/write timeout in seconds")
+ flag.StringVar(&cfg.logfile, "L", cfg.logfile, "write log to file; empty for stderr")
flag.BoolVar(&cfg.verbose, "v", cfg.verbose, "produce verbose output")
flag.Parse()
if help {
- fmt.Println("Version ", version)
+ fmt.Println("gogopherd version ", version)
flag.Usage()
os.Exit(1)
}
if 0 != len(flag.Args()) {
- fmt.Println("Version ", version)
- fmt.Println("unrecognized options: ", flag.Args())
+ log.Println("unrecognized arguments: ", flag.Args())
flag.Usage()
os.Exit(1)
}
- initUtil(cfg.verbose)
+ initLogger(cfg.verbose, cfg.logfile)
if len(cfgfile) > 0 {
- parseConfigFile(cfgfile)
+ err = parseConfigFile(cfgfile)
+ checkFatal(err, "parseConfigFile")
flag.Parse()
+ initLogger(cfg.verbose, cfg.logfile)
}
- var err error
cfg.docroot, err = canonicalizePath(cfg.docroot)
checkFatal(err, "canonicalizePath "+cfg.docroot)
if filepath.IsAbs(cfg.header) {
cfg.idxpage = ""
}
- tracer.Print("final config after evaluating command line:")
+ tracer.Print("final config:")
tracer.Print("fqdn: ", cfg.fqdn)
tracer.Print("iface: ", cfg.iface)
tracer.Print("port: ", cfg.port)
# Connection read and write timeout in seconds
timeout = 60
+# Log to file; leave empty for stderr
+logfile = ""
+
# Produce verbose output
verbose = false
--- /dev/null
+/*
+ * This file is part of the gogopherd project.
+ *
+ * Copyright 2019 Urban Wallasch <irrwahn35@freenet.de>
+ * See LICENSE file for more details.
+ *
+ */
+
+package main
+
+import (
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "runtime"
+)
+
+var (
+ logger *log.Logger
+ loggex *log.Logger
+ tracer *log.Logger
+ tracex *log.Logger
+)
+
+func initLogger(verbose bool, logfilename string) {
+ if len(logfilename) > 0 {
+ logfile, err := os.OpenFile(logfilename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
+ if err != nil {
+ log.Fatalln("Failed to open log file", logfilename, ":", err)
+ }
+ os.Stderr.Close()
+ os.Stderr = logfile
+ }
+ logger = log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lshortfile)
+ loggex = log.New(os.Stderr, "", log.Ldate|log.Ltime)
+ if verbose {
+ tracer = log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lshortfile)
+ tracex = log.New(os.Stderr, "", log.Ldate|log.Ltime)
+ } else {
+ tracer = log.New(ioutil.Discard, "", 0)
+ tracex = log.New(ioutil.Discard, "", 0)
+ }
+}
+
+func checkFatal(err error, msg string) {
+ if err != nil {
+ _, file, line, _ := runtime.Caller(1)
+ loggex.Fatalf("%s:%d: %s %v\n", filepath.Base(file), line, msg, err)
+ }
+}
+
+func check(err error, msg string) error {
+ if err != nil && cfg.verbose {
+ _, file, line, _ := runtime.Caller(1)
+ tracex.Printf("%s:%d: %s %v\n", filepath.Base(file), line, msg, err)
+ }
+ return err
+}
+
+/* EOF */
"errors"
"fmt"
"io"
- "io/ioutil"
- "log"
"net/http"
"os"
"path/filepath"
- "runtime"
"strings"
"time"
)
-var (
- logger *log.Logger
- loggex *log.Logger
- tracer *log.Logger
- tracex *log.Logger
-)
-
-func initUtil(verbose bool) {
- logger = log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lshortfile)
- loggex = log.New(os.Stderr, "", log.Ldate|log.Ltime)
- if verbose {
- tracer = log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lshortfile)
- tracex = log.New(os.Stderr, "", log.Ldate|log.Ltime)
- } else {
- tracer = log.New(ioutil.Discard, "", 0)
- tracex = log.New(ioutil.Discard, "", 0)
- }
-}
-
-func checkFatal(err error, msg string) {
- if err != nil {
- _, file, line, _ := runtime.Caller(1)
- loggex.Printf("%s:%d: %s %v\n", filepath.Base(file), line, msg, err)
- os.Exit(1)
- }
-}
-
-func check(err error, msg string) error {
- if err != nil && cfg.verbose {
- _, file, line, _ := runtime.Caller(1)
- tracex.Printf("%s:%d: %s %v\n", filepath.Base(file), line, msg, err)
- }
- return err
-}
-
func canonicalizePath(path string) (string, error) {
abs, err := filepath.Abs(path)
if check(err, "Abs "+path) != nil {