// NewFS creates an FS func NewFS(config libkbfs.Config, conn *fuse.Conn, debug bool) *FS { log := logger.NewWithCallDepth("kbfsfuse", 1, os.Stderr) // We need extra depth for errors, so that we can report the line // number for the caller of reportErr, not reportErr itself. errLog := logger.NewWithCallDepth("kbfsfuse", 2, os.Stderr) if debug { // Turn on debugging. TODO: allow a proper log file and // style to be specified. log.Configure("", true, "") errLog.Configure("", true, "") } return &FS{config: config, conn: conn, log: log, errLog: errLog} }
// InitLog sets up logging switching to a log file if necessary. // Returns a valid logger even on error, which are non-fatal, thus // errors from this function may be ignored. // Possible errors are logged to the logger returned. func InitLog(params InitParams) (logger.Logger, error) { var err error log := logger.NewWithCallDepth("kbfs", 1) // Set log file to default if log-to-file was specified if params.LogToFile { if params.LogFileConfig.Path != "" { return nil, fmt.Errorf("log-to-file and log-file flags can't be specified together") } params.LogFileConfig.Path = defaultLogPath() } if params.LogFileConfig.Path != "" { err = logger.SetLogFileConfig(¶ms.LogFileConfig) } log.Configure("", params.Debug, "") log.Info("KBFS version %s", VersionString()) if err != nil { log.Warning("Failed to setup log file %q: %v", params.LogFileConfig.Path, err) } return log, err }
// Start the filesystem func Start(mounter Mounter, options StartOptions) *Error { c, err := mounter.Mount() if err != nil { return MountError(err.Error()) } defer c.Close() onInterruptFn := func() { select { case <-c.Ready: // Was mounted, so try to unmount if it was successful. if c.MountError == nil { err = mounter.Unmount() if err != nil { return } } default: // Was not mounted successfully yet, so do nothing. Note that the mount // could still happen, but that's a rare enough edge case. } } log := logger.NewWithCallDepth("", 1, os.Stderr) log.Info("KBFS version %s", libkbfs.VersionString()) config, err := libkbfs.Init(options.KbfsParams, onInterruptFn, log) if err != nil { return InitError(err.Error()) } defer libkbfs.Shutdown(options.KbfsParams.MemProfile) if options.RuntimeDir != "" { info := libkb.NewServiceInfo(libkbfs.Version, libkbfs.Build(), options.Label, os.Getpid()) err = info.WriteFile(path.Join(options.RuntimeDir, "kbfs.info")) if err != nil { return InitError(err.Error()) } } fs := NewFS(config, c, options.KbfsParams.Debug) ctx := context.WithValue(context.Background(), CtxAppIDKey, fs) logTags := make(logger.CtxLogTags) logTags[CtxIDKey] = CtxOpID ctx = logger.NewContextWithLogTags(ctx, logTags) fs.Serve(ctx) <-c.Ready err = c.MountError if err != nil { return MountError(err.Error()) } return nil }
// NewKeybaseDaemonRPC makes a new KeybaseDaemonRPC that makes RPC // calls using the socket of the given Keybase context. func NewKeybaseDaemonRPC(config Config, kbCtx *libkb.GlobalContext, log logger.Logger, debug bool) *KeybaseDaemonRPC { k := newKeybaseDaemonRPC(kbCtx, log) conn := NewSharedKeybaseConnection(kbCtx, config, k) k.fillClients(conn.GetClient()) k.shutdownFn = conn.Shutdown k.daemonLog = logger.NewWithCallDepth("daemon", 1, os.Stderr) if debug { k.daemonLog.Configure("", true, "") } return k }
// Define this so deferred functions get executed before exit. func realMain() (exitStatus int) { kbfsParams := libkbfs.AddFlags(flag.CommandLine) flag.Parse() if *version { fmt.Printf("%s\n", libkbfs.VersionString()) return 0 } if len(flag.Args()) < 1 { fmt.Print(getUsageStr()) return 1 } log := logger.NewWithCallDepth("", 1) config, err := libkbfs.Init(*kbfsParams, nil, log) if err != nil { printError("kbfs", err) return 1 } defer libkbfs.Shutdown() // TODO: Make the logging level WARNING instead of INFO, or // figure out some other way to log the full folder-branch // name for kbfsfuse but not for kbfs. cmd := flag.Arg(0) args := flag.Args()[1:] ctx := context.Background() switch cmd { case "stat": return stat(ctx, config, args) case "ls": return ls(ctx, config, args) case "mkdir": return mkdir(ctx, config, args) case "read": return read(ctx, config, args) case "write": return write(ctx, config, args) default: printError("kbfs", fmt.Errorf("unknown command '%s'", cmd)) return 1 } }
func start() *libfs.Error { kbfsParams := libkbfs.AddFlags(flag.CommandLine) platformParams := libfuse.AddPlatformFlags(flag.CommandLine) flag.Parse() if *version { fmt.Printf("%s\n", libkbfs.VersionString()) return nil } if len(flag.Args()) < 1 { fmt.Print(getUsageStr()) return libfs.InitError("no mount specified") } if len(flag.Args()) > 1 { fmt.Print(getUsageStr()) return libfs.InitError("extra arguments specified (flags go before the first argument)") } if kbfsParams.Debug { fuseLog := logger.NewWithCallDepth("FUSE", 1) fuseLog.Configure("", true, "") fuse.Debug = func(msg interface{}) { fuseLog.Debug("%s", msg) } } mountpoint := flag.Arg(0) var mounter libfuse.Mounter if *mountType == "force" { mounter = libfuse.NewForceMounter(mountpoint, *platformParams) } else { mounter = libfuse.NewDefaultMounter(mountpoint, *platformParams) } options := libfuse.StartOptions{ KbfsParams: *kbfsParams, RuntimeDir: *runtimeDir, Label: *label, } return libfuse.Start(mounter, options) }
// Init initializes a config and returns it. // // onInterruptFn is called whenever an interrupt signal is received // (e.g., if the user hits Ctrl-C). // // Init should be called at the beginning of main. Shutdown (see // below) should then be called at the end of main (usually via // defer). func Init(params InitParams, onInterruptFn func(), log logger.Logger) (Config, error) { initLibkb() localUser := libkb.NewNormalizedUsername(params.LocalUser) if params.CPUProfile != "" { // Let the GC/OS clean up the file handle. f, err := os.Create(params.CPUProfile) if err != nil { return nil, err } pprof.StartCPUProfile(f) } interruptChan := make(chan os.Signal, 1) signal.Notify(interruptChan, os.Interrupt) go func() { _ = <-interruptChan Shutdown(params.MemProfile) if onInterruptFn != nil { onInterruptFn() } os.Exit(1) }() config := NewConfigLocal() // 512K blocks by default, block changes embedded max == 8K. // Block size was chosen somewhat arbitrarily by trying to // minimize the overall size of the history written by a user when // appending 1KB writes to a file, up to a 1GB total file. Here // is the output of a simple script that approximates that // calculation: // // Total history size for 0065536-byte blocks: 1134341128192 bytes // Total history size for 0131072-byte blocks: 618945052672 bytes // Total history size for 0262144-byte blocks: 412786622464 bytes // Total history size for 0524288-byte blocks: 412786622464 bytes // Total history size for 1048576-byte blocks: 618945052672 bytes // Total history size for 2097152-byte blocks: 1134341128192 bytes // Total history size for 4194304-byte blocks: 2216672886784 bytes bsplitter, err := NewBlockSplitterSimple(512*1024, 8*1024, config.Codec()) if err != nil { return nil, err } config.SetBlockSplitter(bsplitter) if registry := config.MetricsRegistry(); registry != nil { keyCache := config.KeyCache() keyCache = NewKeyCacheMeasured(keyCache, registry) config.SetKeyCache(keyCache) } // Set logging config.SetLoggerMaker(func(module string) logger.Logger { mname := "kbfs" if module != "" { mname += fmt.Sprintf("(%s)", module) } // Add log depth so that context-based messages get the right // file printed out. lg := logger.NewWithCallDepth(mname, 1, os.Stderr) if params.Debug { // Turn on debugging. TODO: allow a proper log file and // style to be specified. lg.Configure("", true, "") } return lg }) kbfsOps := NewKBFSOpsStandard(config) config.SetKBFSOps(kbfsOps) config.SetNotifier(kbfsOps) config.SetKeyManager(NewKeyManagerStandard(config)) mdServer, err := makeMDServer( config, params.ServerInMemory, params.ServerRootDir, params.MDServerAddr) if err != nil { return nil, fmt.Errorf("problem creating MD server: %v", err) } config.SetMDServer(mdServer) // note: the mdserver is the keyserver at the moment. keyServer, err := makeKeyServer( config, params.ServerInMemory, params.ServerRootDir, params.MDServerAddr) if err != nil { return nil, fmt.Errorf("problem creating key server: %v", err) } if registry := config.MetricsRegistry(); registry != nil { keyServer = NewKeyServerMeasured(keyServer, registry) } config.SetKeyServer(keyServer) daemon, err := makeKeybaseDaemon(config, params.ServerInMemory, params.ServerRootDir, localUser, config.Codec(), config.MakeLogger(""), params.Debug) if err != nil { return nil, fmt.Errorf("problem creating daemon: %s", err) } if registry := config.MetricsRegistry(); registry != nil { daemon = NewKeybaseDaemonMeasured(daemon, registry) } config.SetKeybaseDaemon(daemon) k := NewKBPKIClient(config) config.SetKBPKI(k) config.SetReporter(NewReporterKBPKI(config, 10, 1000)) if localUser == "" { c := NewCryptoClient(config, libkb.G, config.MakeLogger("")) config.SetCrypto(c) } else { signingKey := MakeLocalUserSigningKeyOrBust(localUser) cryptPrivateKey := MakeLocalUserCryptPrivateKeyOrBust(localUser) config.SetCrypto(NewCryptoLocal(config, signingKey, cryptPrivateKey)) } bserv, err := makeBlockServer(config, params.ServerInMemory, params.ServerRootDir, params.BServerAddr, log) if err != nil { return nil, fmt.Errorf("cannot open block database: %v", err) } if registry := config.MetricsRegistry(); registry != nil { bserv = NewBlockServerMeasured(bserv, registry) } config.SetBlockServer(bserv) return config, nil }