diff --git a/cmd/grumble/args.go b/cmd/grumble/args.go index 4b2331c..055f78b 100644 --- a/cmd/grumble/args.go +++ b/cmd/grumble/args.go @@ -85,16 +85,20 @@ func Usage() { } } -var Args args +func readCommandlineArguments() args { + var a args -func init() { flag.Usage = Usage - flag.BoolVar(&Args.ShowHelp, "help", false, "") - flag.StringVar(&Args.DataDir, "datadir", defaultDataDir(), "") - flag.StringVar(&Args.LogPath, "log", defaultLogPath(), "") - flag.BoolVar(&Args.RegenKeys, "regen-keys", false, "") + flag.BoolVar(&a.ShowHelp, "help", false, "") + flag.StringVar(&a.DataDir, "datadir", defaultDataDir(), "") + flag.StringVar(&a.LogPath, "log", defaultLogPath(), "") + flag.BoolVar(&a.RegenKeys, "regen-keys", false, "") - flag.StringVar(&Args.SQLiteDB, "import-murmurdb", "", "") - flag.BoolVar(&Args.CleanUp, "cleanup", false, "") + flag.StringVar(&a.SQLiteDB, "import-murmurdb", "", "") + flag.BoolVar(&a.CleanUp, "cleanup", false, "") + + flag.Parse() + + return a } diff --git a/cmd/grumble/freeze.go b/cmd/grumble/freeze.go index a8dbcfe..a2b2a5f 100644 --- a/cmd/grumble/freeze.go +++ b/cmd/grumble/freeze.go @@ -52,7 +52,7 @@ func (server *Server) openFreezeLog() error { server.freezelog = nil } - logfn := filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10), "log.fz") + logfn := filepath.Join(server.DataDir, "servers", strconv.FormatInt(server.Id, 10), "log.fz") err := os.Remove(logfn) if os.IsNotExist(err) { // fallthrough @@ -374,13 +374,13 @@ func FreezeGroup(group acl.Group) (*freezer.Group, error) { // Once both the full server and the log file has been merged together // in memory, a new full seralized server will be written and synced to // disk, and the existing log file will be removed. -func NewServerFromFrozen(name string) (s *Server, err error) { +func NewServerFromFrozen(name string, dataDir string) (s *Server, err error) { id, err := strconv.ParseInt(name, 10, 64) if err != nil { return nil, err } - path := filepath.Join(Args.DataDir, "servers", name) + path := filepath.Join(dataDir, "servers", name) mainFile := filepath.Join(path, "main.fz") backupFile := filepath.Join(path, "backup.fz") logFn := filepath.Join(path, "log.fz") @@ -424,6 +424,7 @@ func NewServerFromFrozen(name string) (s *Server, err error) { if err != nil { return nil, err } + s.DataDir = dataDir s.cfg = serverconf.New(cfgMap) // Unfreeze the server's frozen bans. diff --git a/cmd/grumble/freeze_unix.go b/cmd/grumble/freeze_unix.go index 5974539..087f300 100644 --- a/cmd/grumble/freeze_unix.go +++ b/cmd/grumble/freeze_unix.go @@ -30,7 +30,7 @@ func (server *Server) freezeToFile() (err error) { if err != nil { return err } - f, err := ioutil.TempFile(filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10)), ".main.fz_") + f, err := ioutil.TempFile(filepath.Join(server.DataDir, "servers", strconv.FormatInt(server.Id, 10)), ".main.fz_") if err != nil { return err } @@ -50,7 +50,7 @@ func (server *Server) freezeToFile() (err error) { if err != nil { return err } - err = os.Rename(f.Name(), filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10), "main.fz")) + err = os.Rename(f.Name(), filepath.Join(server.DataDir, "servers", strconv.FormatInt(server.Id, 10), "main.fz")) if err != nil { return err } diff --git a/cmd/grumble/freeze_windows.go b/cmd/grumble/freeze_windows.go index 8d967e7..d286164 100644 --- a/cmd/grumble/freeze_windows.go +++ b/cmd/grumble/freeze_windows.go @@ -29,7 +29,7 @@ func (server *Server) freezeToFile() (err error) { if err != nil { return err } - f, err := ioutil.TempFile(filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10)), ".main.fz_") + f, err := ioutil.TempFile(filepath.Join(server.DataDir, "servers", strconv.FormatInt(server.Id, 10)), ".main.fz_") if err != nil { return err } @@ -51,8 +51,8 @@ func (server *Server) freezeToFile() (err error) { } src := f.Name() - dst := filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10), "main.fz") - backup := filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10), "backup.fz") + dst := filepath.Join(server.DataDir, "servers", strconv.FormatInt(server.Id, 10), "main.fz") + backup := filepath.Join(server.DataDir, "servers", strconv.FormatInt(server.Id, 10), "backup.fz") err = replacefile.ReplaceFile(dst, src, backup, replacefile.Flag(0)) // If the dst file does not exist (as in, on first launch) diff --git a/cmd/grumble/gencert.go b/cmd/grumble/gencert.go index 4c2bb30..4f35b3e 100644 --- a/cmd/grumble/gencert.go +++ b/cmd/grumble/gencert.go @@ -20,7 +20,7 @@ import ( // Generate a 4096-bit RSA keypair and a Grumble auto-generated X509 // certificate. Output PEM-encoded DER representations of the resulting // certificate and private key to certpath and keypath. -func GenerateSelfSignedCert(certpath, keypath string) (err error) { +func GenerateSelfSignedCert(certpath, keypath string, dataDir string) (err error) { now := time.Now() tmpl := &x509.Certificate{ SerialNumber: big.NewInt(0), @@ -56,7 +56,7 @@ func GenerateSelfSignedCert(certpath, keypath string) (err error) { Bytes: keybuf, } - certfn := filepath.Join(Args.DataDir, "cert.pem") + certfn := filepath.Join(dataDir, "cert.pem") file, err := os.OpenFile(certfn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0700) if err != nil { return err @@ -67,7 +67,7 @@ func GenerateSelfSignedCert(certpath, keypath string) (err error) { return err } - keyfn := filepath.Join(Args.DataDir, "key.pem") + keyfn := filepath.Join(dataDir, "key.pem") file, err = os.OpenFile(keyfn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0700) if err != nil { return err diff --git a/cmd/grumble/grumble.go b/cmd/grumble/grumble.go index 56eaa9a..8cd1cf5 100644 --- a/cmd/grumble/grumble.go +++ b/cmd/grumble/grumble.go @@ -5,7 +5,6 @@ package main import ( - "flag" "fmt" "log" "os" @@ -22,31 +21,31 @@ var blobStore blobstore.BlobStore func main() { var err error - flag.Parse() - if Args.ShowHelp == true { + cmdArgs := readCommandlineArguments() + if cmdArgs.ShowHelp == true { Usage() return } // Open the data dir to check whether it exists. - dataDir, err := os.Open(Args.DataDir) + dataDir, err := os.Open(cmdArgs.DataDir) if err != nil { - log.Fatalf("Unable to open data directory (%v): %v", Args.DataDir, err) + log.Fatalf("Unable to open data directory (%v): %v", cmdArgs.DataDir, err) return } dataDir.Close() // Set up logging - err = logtarget.Target.OpenFile(Args.LogPath) + err = logtarget.Target.OpenFile(cmdArgs.LogPath) if err != nil { - fmt.Fprintf(os.Stderr, "Unable to open log file (%v): %v", Args.LogPath, err) + fmt.Fprintf(os.Stderr, "Unable to open log file (%v): %v", cmdArgs.LogPath, err) return } log.SetPrefix("[G] ") log.SetFlags(log.LstdFlags | log.Lmicroseconds) log.SetOutput(&logtarget.Target) log.Printf("Grumble") - log.Printf("Using data directory: %s", Args.DataDir) + log.Printf("Using data directory: %s", cmdArgs.DataDir) // Open the blobstore. If the directory doesn't // already exist, create the directory and open @@ -54,7 +53,7 @@ func main() { // The Open method of the blobstore performs simple // sanity checking of content of the blob directory, // and will return an error if something's amiss. - blobDir := filepath.Join(Args.DataDir, "blob") + blobDir := filepath.Join(cmdArgs.DataDir, "blob") err = os.Mkdir(blobDir, 0700) if err != nil && !os.IsExist(err) { log.Fatalf("Unable to create blob directory (%v): %v", blobDir, err) @@ -66,10 +65,10 @@ func main() { // These are used as the default certificate of all virtual servers // and the SSH admin console, but can be overridden using the "key" // and "cert" arguments to Grumble. - certFn := filepath.Join(Args.DataDir, "cert.pem") - keyFn := filepath.Join(Args.DataDir, "key.pem") + certFn := filepath.Join(cmdArgs.DataDir, "cert.pem") + keyFn := filepath.Join(cmdArgs.DataDir, "key.pem") shouldRegen := false - if Args.RegenKeys { + if cmdArgs.RegenKeys { shouldRegen = true } else { // OK. Here's the idea: We check for the existence of the cert.pem @@ -100,7 +99,7 @@ func main() { if shouldRegen { log.Printf("Generating 4096-bit RSA keypair for self-signed certificate...") - err := GenerateSelfSignedCert(certFn, keyFn) + err := GenerateSelfSignedCert(certFn, keyFn, cmdArgs.DataDir) if err != nil { log.Printf("Error: %v", err) return @@ -111,8 +110,8 @@ func main() { } // Should we import data from a Murmur SQLite file? - if SQLiteSupport && len(Args.SQLiteDB) > 0 { - f, err := os.Open(Args.DataDir) + if SQLiteSupport && len(cmdArgs.SQLiteDB) > 0 { + f, err := os.Open(cmdArgs.DataDir) if err != nil { log.Fatalf("Murmur import failed: %s", err.Error()) } @@ -123,20 +122,20 @@ func main() { log.Fatalf("Murmur import failed: %s", err.Error()) } - if !Args.CleanUp && len(names) > 0 { + if !cmdArgs.CleanUp && len(names) > 0 { log.Fatalf("Non-empty datadir. Refusing to import Murmur data.") } - if Args.CleanUp { + if cmdArgs.CleanUp { log.Print("Cleaning up existing data directory") for _, name := range names { - if err := os.RemoveAll(filepath.Join(Args.DataDir, name)); err != nil { + if err := os.RemoveAll(filepath.Join(cmdArgs.DataDir, name)); err != nil { log.Fatalf("Unable to cleanup file: %s", name) } } } - log.Printf("Importing Murmur data from '%s'", Args.SQLiteDB) - if err = MurmurImport(Args.SQLiteDB); err != nil { + log.Printf("Importing Murmur data from '%s'", cmdArgs.SQLiteDB) + if err = MurmurImport(cmdArgs.SQLiteDB, cmdArgs.DataDir); err != nil { log.Fatalf("Murmur import failed: %s", err.Error()) } @@ -148,7 +147,7 @@ func main() { // Create the servers directory if it doesn't already // exist. - serversDirPath := filepath.Join(Args.DataDir, "servers") + serversDirPath := filepath.Join(cmdArgs.DataDir, "servers") err = os.Mkdir(serversDirPath, 0700) if err != nil && !os.IsExist(err) { log.Fatalf("Unable to create servers directory: %v", err) @@ -177,7 +176,7 @@ func main() { for _, name := range names { if matched, _ := regexp.MatchString("^[0-9]+$", name); matched { log.Printf("Loading server %v", name) - s, err := NewServerFromFrozen(name) + s, err := NewServerFromFrozen(name, cmdArgs.DataDir) if err != nil { log.Fatalf("Unable to load server: %v", err.Error()) } @@ -192,6 +191,7 @@ func main() { // If no servers were found, create the default virtual server. if len(servers) == 0 { s, err := NewServer(1) + s.DataDir = cmdArgs.DataDir if err != nil { log.Fatalf("Couldn't start server: %s", err.Error()) } diff --git a/cmd/grumble/murmurdb.go b/cmd/grumble/murmurdb.go index 83cd2c9..e868eb7 100644 --- a/cmd/grumble/murmurdb.go +++ b/cmd/grumble/murmurdb.go @@ -39,7 +39,7 @@ const ( const SQLiteSupport = true // Import the structure of an existing Murmur SQLite database. -func MurmurImport(filename string) (err error) { +func MurmurImport(filename string, dataDir string) (err error) { db, err := sql.Open("sqlite", filename) if err != nil { panic(err.Error()) @@ -68,7 +68,7 @@ func MurmurImport(filename string) (err error) { return err } - err = os.Mkdir(filepath.Join(Args.DataDir, strconv.FormatInt(sid, 10)), 0750) + err = os.Mkdir(filepath.Join(dataDir, strconv.FormatInt(sid, 10)), 0750) if err != nil { return err } diff --git a/cmd/grumble/server.go b/cmd/grumble/server.go index 64b4dd8..c366f47 100644 --- a/cmd/grumble/server.go +++ b/cmd/grumble/server.go @@ -122,6 +122,9 @@ type Server struct { // Logging *log.Logger + + // Other configuration + DataDir string } type clientLogForwarder struct { @@ -1425,8 +1428,8 @@ func (server *Server) Start() (err error) { */ // Wrap a TLS listener around the TCP connection - certFn := filepath.Join(Args.DataDir, "cert.pem") - keyFn := filepath.Join(Args.DataDir, "key.pem") + certFn := filepath.Join(server.DataDir, "cert.pem") + keyFn := filepath.Join(server.DataDir, "key.pem") cert, err := tls.LoadX509KeyPair(certFn, keyFn) if err != nil { return err