init.go 4.91 KB
Newer Older
1
package main
Matt Bell's avatar
Matt Bell committed
2 3

import (
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
4
	"errors"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
5
	"fmt"
6
	"io"
7 8
	"os"
	"path"
Matt Bell's avatar
Matt Bell committed
9

10 11 12 13 14 15
	assets "github.com/ipfs/go-ipfs/assets"
	cmds "github.com/ipfs/go-ipfs/commands"
	core "github.com/ipfs/go-ipfs/core"
	namesys "github.com/ipfs/go-ipfs/namesys"
	config "github.com/ipfs/go-ipfs/repo/config"
	fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
Jeromy's avatar
Jeromy committed
16
	context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
Matt Bell's avatar
Matt Bell committed
17 18
)

19 20 21
const (
	nBitsForKeypairDefault = 2048
)
22

Matt Bell's avatar
Matt Bell committed
23
var initCmd = &cmds.Command{
24
	Helptext: cmds.HelpText{
rht's avatar
rht committed
25
		Tagline: "Initializes IPFS config file.",
26 27 28 29 30 31 32 33
		ShortDescription: `
Initializes IPFS configuration files and generates a new keypair.

ipfs uses a repository in the local file system. By default, the repo is located
at ~/.ipfs. To change the repo location, set the $IPFS_PATH environment variable:

    export IPFS_PATH=/path/to/ipfsrepo
`,
34
	},
35

Matt Bell's avatar
Matt Bell committed
36
	Options: []cmds.Option{
37 38
		cmds.IntOption("bits", "b", "Number of bits to use in the generated RSA private key.").Default(nBitsForKeypairDefault),
		cmds.BoolOption("empty-repo", "e", "Don't add and pin help files to the local storage.").Default(false),
39 40 41 42

		// TODO need to decide whether to expose the override as a file or a
		// directory. That is: should we allow the user to also specify the
		// name of the file?
43
		// TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs."),
Matt Bell's avatar
Matt Bell committed
44
	},
45
	PreRun: func(req cmds.Request) error {
Jeromy's avatar
Jeromy committed
46
		daemonLocked, err := fsrepo.LockedByOtherProcess(req.InvocContext().ConfigRoot)
47 48 49
		if err != nil {
			return err
		}
50 51 52

		log.Info("checking if daemon is running...")
		if daemonLocked {
michael's avatar
michael committed
53
			log.Debug("Ipfs daemon is running.")
54 55 56 57 58 59
			e := "ipfs daemon is running. please stop it to run this command"
			return cmds.ClientError(e)
		}

		return nil
	},
60
	Run: func(req cmds.Request, res cmds.Response) {
Jeromy's avatar
Jeromy committed
61
		if req.InvocContext().Online {
62 63 64
			res.SetError(errors.New("init must be run offline only!"), cmds.ErrNormal)
			return
		}
65

66
		empty, _, err := req.Option("e").Bool()
67 68 69 70 71
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

72
		nBitsForKeypair, _, err := req.Option("b").Int()
73
		if err != nil {
74 75
			res.SetError(err, cmds.ErrNormal)
			return
76
		}
Henry's avatar
Henry committed
77

78
		if err := doInit(os.Stdout, req.InvocContext().ConfigRoot, empty, nBitsForKeypair); err != nil {
79 80 81
			res.SetError(err, cmds.ErrNormal)
			return
		}
82 83
	},
}
Matt Bell's avatar
Matt Bell committed
84

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
85
var errRepoExists = errors.New(`ipfs configuration file already exists!
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
86 87 88
Reinitializing would overwrite your keys.
`)

89
func initWithDefaults(out io.Writer, repoRoot string) error {
90
	return doInit(out, repoRoot, false, nBitsForKeypairDefault)
91 92
}

93
func doInit(out io.Writer, repoRoot string, empty bool, nBitsForKeypair int) error {
Henry's avatar
Henry committed
94
	if _, err := fmt.Fprintf(out, "initializing ipfs node at %s\n", repoRoot); err != nil {
95 96
		return err
	}
97

98 99 100 101
	if err := checkWriteable(repoRoot); err != nil {
		return err
	}

Jeromy's avatar
Jeromy committed
102
	if fsrepo.IsInitialized(repoRoot) {
103
		return errRepoExists
104
	}
Henry's avatar
Henry committed
105

106 107 108
	conf, err := config.Init(out, nBitsForKeypair)
	if err != nil {
		return err
109
	}
Henry's avatar
Henry committed
110

111
	if err := fsrepo.Init(repoRoot, conf); err != nil {
112
		return err
113
	}
114

115 116 117 118
	if !empty {
		if err := addDefaultAssets(out, repoRoot); err != nil {
			return err
		}
Jeromy's avatar
Jeromy committed
119
	}
120 121

	return initializeIpnsKeyspace(repoRoot)
122 123
}

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
func checkWriteable(dir string) error {
	_, err := os.Stat(dir)
	if err == nil {
		// dir exists, make sure we can write to it
		testfile := path.Join(dir, "test")
		fi, err := os.Create(testfile)
		if err != nil {
			if os.IsPermission(err) {
				return fmt.Errorf("%s is not writeable by the current user", dir)
			}
			return fmt.Errorf("unexpected error while checking writeablility of repo root: %s", err)
		}
		fi.Close()
		return os.Remove(testfile)
	}

	if os.IsNotExist(err) {
		// dir doesnt exist, check that we can create it
		return os.Mkdir(dir, 0775)
	}

	if os.IsPermission(err) {
		return fmt.Errorf("cannot write to %s, incorrect permissions", err)
	}

	return err
}

152
func addDefaultAssets(out io.Writer, repoRoot string) error {
153
	ctx, cancel := context.WithCancel(context.Background())
154
	defer cancel()
Henry's avatar
Henry committed
155

156 157
	r, err := fsrepo.Open(repoRoot)
	if err != nil { // NB: repo is owned by the node
158 159
		return err
	}
Henry's avatar
Henry committed
160

161
	nd, err := core.NewNode(ctx, &core.BuildCfg{Repo: r})
162
	if err != nil {
163
		return err
164 165 166
	}
	defer nd.Close()

Henry's avatar
Henry committed
167
	dkey, err := assets.SeedInitDocs(nd)
168
	if err != nil {
Henry's avatar
Henry committed
169
		return fmt.Errorf("init: seeding init docs failed: %s", err)
170
	}
rht's avatar
rht committed
171
	log.Debugf("init: seeded init docs %s", dkey)
172

Henry's avatar
Henry committed
173 174 175 176 177 178
	if _, err = fmt.Fprintf(out, "to get started, enter:\n"); err != nil {
		return err
	}

	_, err = fmt.Fprintf(out, "\n\tipfs cat /ipfs/%s/readme\n\n", dkey)
	return err
Matt Bell's avatar
Matt Bell committed
179
}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
180

Jeromy's avatar
Jeromy committed
181 182 183 184
func initializeIpnsKeyspace(repoRoot string) error {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

185 186
	r, err := fsrepo.Open(repoRoot)
	if err != nil { // NB: repo is owned by the node
Jeromy's avatar
Jeromy committed
187 188 189
		return err
	}

190
	nd, err := core.NewNode(ctx, &core.BuildCfg{Repo: r})
Jeromy's avatar
Jeromy committed
191 192 193 194 195 196 197 198 199 200
	if err != nil {
		return err
	}
	defer nd.Close()

	err = nd.SetupOfflineRouting()
	if err != nil {
		return err
	}

201
	return namesys.InitializeKeyspace(ctx, nd.DAG, nd.Namesys, nd.Pinning, nd.PrivateKey)
Jeromy's avatar
Jeromy committed
202
}