├── run.sh
├── tools
├── jsstyle.conf
├── mk
│ ├── Makefile.node_deps.targ
│ ├── Makefile.smf.targ
│ ├── Makefile.smf.defs
│ ├── Makefile.deps
│ ├── Makefile.node.targ
│ ├── Makefile.node_deps.defs
│ ├── Makefile.defs
│ ├── Makefile.node_prebuilt.targ
│ ├── Makefile.node.defs
│ ├── Makefile.node_prebuilt.defs
│ └── Makefile.targ
├── bashstyle
├── mkrepo
├── runtests.in
├── jsl.web.conf
├── jsl.node.conf
└── service_bundle.dtd.1
├── .gitignore
├── .gitmodules
├── etc
├── template.json
└── example.json
├── bin
└── manta-nfs
├── svc
├── systemd
│ └── mantanfs.service
├── upstart
│ └── mantanfs.conf
├── launchd
│ └── com.joyent.mantanfs.plist
├── rc
│ └── mantanfs
└── smf
│ └── manta-nfs.xml
├── lib
├── nfs
│ ├── mknod.js
│ ├── link.js
│ ├── readlink.js
│ ├── symlink.js
│ ├── getattr.js
│ ├── commit.js
│ ├── fsstat.js
│ ├── pathconf.js
│ ├── access.js
│ ├── write.js
│ ├── fsinfo.js
│ ├── read.js
│ ├── setattr.js
│ ├── remove.js
│ ├── rmdir.js
│ ├── lookup.js
│ ├── common.js
│ ├── readdir.js
│ ├── rename.js
│ ├── mkdir.js
│ ├── index.js
│ ├── create.js
│ └── readdirplus.js
├── auth.js
├── portmap.js
├── index.js
└── mount.js
├── package.json
├── Makefile
├── server.js
├── LICENSE
└── README.md
/run.sh:
--------------------------------------------------------------------------------
1 | sudo rm -rf /var/tmp/mfsdb; sudo -E node server.js -d | bunyan
2 |
--------------------------------------------------------------------------------
/tools/jsstyle.conf:
--------------------------------------------------------------------------------
1 | indent=4
2 | doxygen
3 | unparenthesized-return=1
4 | blank-after-start-comment=0
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /tmp
3 | build
4 | docs/*.json
5 | docs/*.html
6 | cscope.in.out
7 | cscope.po.out
8 | cscope.out
9 | smf/manifests/*.xml
10 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "deps/jsstyle"]
2 | path = deps/jsstyle
3 | url = git://github.com/davepacheco/jsstyle.git
4 | [submodule "deps/javascriptlint"]
5 | path = deps/javascriptlint
6 | url = git://github.com/davepacheco/javascriptlint.git
7 |
--------------------------------------------------------------------------------
/etc/template.json:
--------------------------------------------------------------------------------
1 | {
2 | "manta": {
3 | "_comment": "the Manta environment variables can be used instead",
4 | "keyFile": "/Users/foo/.ssh/id_rsa",
5 | "keyId": "70:c0:50:d6:9e:1f:0c:74:04:8b:08:c9:12:a2:7c:9f",
6 | "url": "https://us-east.manta.joyent.com",
7 | "user": "foo.bar"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/bin/manta-nfs:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | dir=`dirname $0`
4 |
5 | if [ "$MANTA_USER"X == "X" ]; then
6 | echo "Error: the manta environment variables must be defined"
7 | exit 1
8 | fi
9 |
10 | euid=`id -u`
11 |
12 | if [ $euid != 0 ]; then
13 | echo "Error: manta-nfs must be started as root"
14 | exit 1
15 | fi
16 |
17 | node $dir/../server.js
18 |
--------------------------------------------------------------------------------
/svc/systemd/mantanfs.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Manta NFS service
3 | After=network.target
4 | ConditionFileIsExecutable=/usr/bin/node
5 | ConditionPathExists=/usr/local/bin/server.js
6 | ConditionPathExists=/usr/local/etc/manta-nfs.json
7 |
8 | [Service]
9 | Type=simple
10 | ExecStart=/usr/bin/node /usr/local/bin/server.js -f /usr/local/etc/manta-nfs.json
11 | Restart=on-failure
12 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.node_deps.targ:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.node_deps.targ: targets for Makefile.node_deps.defs.
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 |
13 | NPM_EXEC ?= $(error NPM_EXEC must be defined for Makefile.node_deps.targ)
14 |
15 | node_modules/%: src/node-% | $(NPM_EXEC)
16 | $(NPM) install $<
17 |
--------------------------------------------------------------------------------
/lib/nfs/mknod.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 |
9 | var common = require('./common');
10 |
11 |
12 |
13 | ///-- API
14 |
15 | function mknod(req, res, next) {
16 | req.log.debug('mknod: entered');
17 | res.error(nfs.NFS3ERR_NOTSUPP);
18 | next(false);
19 | }
20 |
21 |
22 | ///--- Exports
23 |
24 | module.exports = function chain() {
25 | return ([
26 | mknod
27 | ]);
28 | };
29 |
--------------------------------------------------------------------------------
/lib/nfs/link.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 |
9 | var common = require('./common');
10 |
11 |
12 |
13 | ///-- API
14 |
15 | function link(req, res, next) {
16 | req.log.debug('link(%s): entered', req.file);
17 | res.error(nfs.NFS3ERR_NOTSUPP);
18 | next(false);
19 | }
20 |
21 |
22 | ///--- Exports
23 |
24 | module.exports = function chain() {
25 | return ([
26 | link
27 | ]);
28 | };
29 |
--------------------------------------------------------------------------------
/lib/nfs/readlink.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 |
9 | var common = require('./common');
10 |
11 |
12 |
13 | ///-- API
14 |
15 | function readlink(req, res, next) {
16 | req.log.debug('readlink: entered');
17 | res.error(nfs.NFS3ERR_NOTSUPP);
18 | next(false);
19 | }
20 |
21 |
22 | ///--- Exports
23 |
24 | module.exports = function chain() {
25 | return ([
26 | readlink
27 | ]);
28 | };
29 |
--------------------------------------------------------------------------------
/lib/auth.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 |
8 |
9 | ///--- API
10 |
11 | function authorize(req, res, next) {
12 | // Let everything through
13 | // if (!req.is_user(0)) {
14 | // res.status = nfs.NFS3ERR_ACCES;
15 | // res.send();
16 | // next(false);
17 | // } else {
18 | // next();
19 | // }
20 | next();
21 | }
22 |
23 |
24 |
25 | ///--- Exports
26 |
27 | module.exports = {
28 | authorize: authorize
29 | };
30 |
--------------------------------------------------------------------------------
/lib/nfs/symlink.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 |
9 | var common = require('./common');
10 |
11 |
12 |
13 | ///-- API
14 |
15 | function symlink(req, res, next) {
16 | req.log.debug('symlink(%s, %s): entered', req.where.dir, req.where.name);
17 | res.error(nfs.NFS3ERR_NOTSUPP);
18 | next(false);
19 | }
20 |
21 |
22 | ///--- Exports
23 |
24 | module.exports = function chain() {
25 | return ([
26 | symlink
27 | ]);
28 | };
29 |
--------------------------------------------------------------------------------
/svc/upstart/mantanfs.conf:
--------------------------------------------------------------------------------
1 | # mantanfs - Manta NFS server
2 | #
3 | # The mantanfs server provides a NFS server frontend to Manta.
4 |
5 | description "Manta NFS server"
6 |
7 | start on runlevel [2345]
8 | stop on runlevel [!2345]
9 |
10 | respawn
11 | respawn limit 10 5
12 |
13 | console log
14 |
15 | # Assumes node is installed in /usr/bin
16 | # Assumes server.js is installed in /usr/local/bin
17 | # Adjust these paths as needed
18 |
19 | pre-start script
20 | test -x /usr/bin/node || { stop; exit 0; }
21 | test -e /usr/local/bin/server.js || { stop; exit 0; }
22 | test -e /usr/local/etc/manta-nfs.json || { stop; exit 0; }
23 | end script
24 |
25 | exec node /usr/local/bin/server.js -f /usr/local/etc/manta-nfs.json
26 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.smf.targ:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.smf.targ: see Makefile.smf.defs.
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 | .PHONY: check-manifests
13 | check-manifests: $(SMF_MANIFESTS:%=%.smfchk)
14 |
15 | %.smfchk: %
16 | $(XMLLINT) --path $(dir $(SMF_DTD)) --dtdvalid $(SMF_DTD) $^
17 |
18 | check: check-manifests
19 |
20 | $(SMF_MANIFESTS): %: %.in
21 | $(SED) -e 's#@@NODE@@#@@PREFIX@@/$(NODE_INSTALL)/bin/node#' $< > $@
22 |
--------------------------------------------------------------------------------
/svc/launchd/com.joyent.mantanfs.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Label
6 | com.joyent.mantanfs
7 | ProgramArguments
8 |
9 | /usr/local/bin/node
10 | /usr/local/manta-nfs/server.js
11 | -f
12 | /usr/local/manta-nfs/etc/manta-nfs.json
13 |
14 | StandardOutPath
15 | /var/log/manta-nfs.log
16 | StandardErrorPath
17 | /var/log/manta-nfs.log
18 | KeepAlive
19 |
20 | NetworkState
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/lib/nfs/getattr.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 |
9 | var common = require('./common');
10 |
11 |
12 |
13 | ///-- API
14 |
15 | function getattr(req, res, next) {
16 | var log = req.log;
17 |
18 | log.debug('getattr(%s, %s): entered', req.object, req._filename);
19 | req.fs.stat(req._filename, function (err, stats) {
20 | if (err) {
21 | req.log.warn(err, 'getattr: mantafs.stat failed');
22 | res.error(nfs.NFS3ERR_IO);
23 | next(false);
24 | return;
25 | }
26 |
27 | log.debug('getattr(%j): stats returned from cache', stats);
28 |
29 | res.setAttributes(stats);
30 | res.send();
31 | next();
32 | });
33 | }
34 |
35 |
36 |
37 | ///--- Exports
38 |
39 | module.exports = function chain() {
40 | return ([
41 | common.fhandle_to_filename,
42 | getattr
43 | ]);
44 | };
45 |
--------------------------------------------------------------------------------
/lib/nfs/commit.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var assert = require('assert-plus');
8 | var nfs = require('nfs');
9 |
10 | var common = require('./common');
11 |
12 | var fs = require('fs');
13 |
14 |
15 |
16 | ///-- API
17 |
18 |
19 | function commit(call, reply, next) {
20 | var log = call.log;
21 | var stats = call.stats;
22 |
23 | log.debug('commit(%s): entered', call.object);
24 |
25 | assert.ok(stats);
26 |
27 | call.fs.fsync(stats.fd, function (err) {
28 | if (err) {
29 | log.warn(err, 'commit: fsCache.fsync failed');
30 | reply.error(nfs.NFS3ERR_SERVERFAULT);
31 | next(false);
32 | return;
33 | }
34 |
35 | reply.send();
36 | next();
37 | });
38 | }
39 |
40 |
41 |
42 | ///--- Exports
43 |
44 | module.exports = function chain() {
45 | return ([
46 | common.fhandle_to_filename,
47 | common.open,
48 | commit
49 | ]);
50 | };
51 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.smf.defs:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.smf.defs: common targets for SMF manifests
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 | # This Makefile uses the following definitions:
13 | #
14 | # SMF_MANIFESTS_IN Source files for SMF manifests. The following
15 | # substitutions will be made on these files:
16 | #
17 | # @@NODE@@ path to installed node
18 | #
19 | # It updates SMF_MANIFESTS with the set of files generated by SMF_MANIFESTS_IN.
20 | # It also updates the "check" target to check the XML syntax of all manifests,
21 | # generated or otherwise.
22 | #
23 | # To use this file, be sure to also include Makefile.smf.targ after defining
24 | # targets.
25 | #
26 |
27 | SED ?= sed
28 | SMF_DTD ?= tools/service_bundle.dtd.1
29 | XMLLINT ?= xmllint --noout
30 |
31 | SMF_MANIFESTS += $(SMF_MANIFESTS_IN:%.in=%)
32 | CLEAN_FILES += $(SMF_MANIFESTS_IN:%.in=%)
33 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.deps:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.deps: Makefile for including common tools as dependencies
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 | # This file is separate from Makefile.targ so that teams can choose
13 | # independently whether to use the common targets in Makefile.targ and the
14 | # common tools here.
15 | #
16 |
17 | #
18 | # javascriptlint
19 | #
20 | JSL_EXEC ?= deps/javascriptlint/build/install/jsl
21 | JSL ?= $(JSL_EXEC)
22 |
23 | $(JSL_EXEC): | deps/javascriptlint/.git
24 | cd deps/javascriptlint && make install
25 |
26 | distclean::
27 | if [[ -f deps/javascriptlint/Makefile ]]; then \
28 | cd deps/javascriptlint && make clean; \
29 | fi
30 |
31 | #
32 | # jsstyle
33 | #
34 | JSSTYLE_EXEC ?= deps/jsstyle/jsstyle
35 | JSSTYLE ?= $(JSSTYLE_EXEC)
36 |
37 | $(JSSTYLE_EXEC): | deps/jsstyle/.git
38 |
39 | #
40 | # restdown
41 | #
42 | RESTDOWN_EXEC ?= deps/restdown/bin/restdown
43 | RESTDOWN ?= python $(RESTDOWN_EXEC)
44 | $(RESTDOWN_EXEC): | deps/restdown/.git
45 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "manta-nfs",
3 | "description": "NFS Gateway for the Joyent Manta Storage Service",
4 | "version": "0.1.0",
5 | "author": {
6 | "name": "Joyent, Inc.",
7 | "url": "http://joyent.com/"
8 | },
9 | "license": "MPL-2.0",
10 | "repository": {
11 | "type": "git",
12 | "url": "git://github.com/joyent/manta-nfs.git"
13 | },
14 | "bugs": {
15 | "url": "https://github.com/joyent/manta-nfs/issues"
16 | },
17 | "dependencies": {
18 | "assert-plus": "0.1.5",
19 | "bunyan": "0.22.0",
20 | "clone": "0.1.11",
21 | "dashdash": "1.3.2",
22 | "lru-cache": "2.5.0",
23 | "lstream": "0.0.3",
24 | "manta": "1.2.6",
25 | "mantafs": "0.1.0",
26 | "mkdirp": "0.3.5",
27 | "nfs": "0.1.0",
28 | "once": "1.2.0",
29 | "oncrpc": "0.1.0",
30 | "statvfs": "2.1.0",
31 | "userid": "0.1.1",
32 | "vasync": "1.4.0"
33 | },
34 | "devDependencies": {
35 | "nodeunit": "0.8.2",
36 | "nodeunit-plus": "0.0.1",
37 | "rimraf": "2.2.2"
38 | },
39 | "scripts": {
40 | "start:": "node ./server.js | ./node_modules/.bin/bunyan",
41 | "test": "nodeunit test/*.test.js"
42 | },
43 | "engines": {
44 | "node" : ">=0.10.18 <0.12"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.node.targ:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.node.targ: See Makefile.node.defs.
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 |
13 | ifneq ($(shell uname -s),SunOS)
14 | NODE_PREBUILT_VERSION ?= $(error You must define NODE_PREBUILT_VERSION to use Makefile.node.targ on non-SunOS)
15 | endif
16 |
17 | ifeq ($(shell uname -s),SunOS)
18 | $(NODE_EXEC) $(NPM_EXEC) $(NODE_WAF_EXEC): | deps/node/.git
19 | (cd deps/node; ./configure $(NODE_CONFIG_FLAGS) && $(MAKE) && $(MAKE) install)
20 | else
21 | $(NODE_EXEC) $(NPM_EXEC) $(NODE_WAF_EXEC):
22 | (mkdir -p $(BUILD) \
23 | && cd $(BUILD) \
24 | && [[ -d src-node ]] && (cd src-node && git checkout master && git pull) || git clone git://github.com/joyent/node.git src-node \
25 | && cd src-node \
26 | && git checkout $(NODE_PREBUILT_VERSION) \
27 | && ./configure $(NODE_CONFIG_FLAGS) \
28 | && $(MAKE) && $(MAKE) install)
29 | endif
30 |
31 | DISTCLEAN_FILES += $(NODE_INSTALL) $(BUILD)/src-node
32 |
33 | distclean::
34 | -([[ ! -d deps/node ]] || (cd deps/node && $(MAKE) distclean))
35 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2014, Joyent, Inc. All rights reserved.
3 | #
4 | # Makefile: for the manta nfs service
5 | #
6 |
7 | #
8 | # Tools
9 | #
10 | NODEUNIT := ./node_modules/.bin/nodeunit
11 |
12 | #
13 | # Files
14 | #
15 | DOC_FILES = index.restdown
16 | JS_FILES := $(shell ls *.js) $(shell find lib test -name '*.js')
17 | JSON_FILES = package.json
18 | JSL_CONF_NODE = tools/jsl.node.conf
19 | JSL_FILES_NODE = $(JS_FILES)
20 | JSSTYLE_FILES = $(JS_FILES)
21 | JSSTYLE_FLAGS = -f tools/jsstyle.conf
22 |
23 | NODE_PREBUILT_VERSION=v0.10.21
24 |
25 | ifeq ($(shell uname -s),SunOS)
26 | NODE_PREBUILT_CC_VERSION=4.6.2
27 | NODE_PREBUILT_TAG=zone
28 | endif
29 |
30 | include ./tools/mk/Makefile.defs
31 | #ifeq ($(shell uname -s),SunOS)
32 | # include ./tools/mk/Makefile.node_prebuilt.defs
33 | #else
34 | NPM := npm
35 | #endif
36 | include ./tools/mk/Makefile.smf.defs
37 |
38 | #
39 | # Repo-specific targets
40 | #
41 | .PHONY: all
42 | all: $(NODEUNIT) $(REPO_DEPS)
43 | $(NPM) rebuild
44 |
45 | $(NODEUNIT): | $(NPM_EXEC)
46 | $(NPM) install
47 |
48 | CLEAN_FILES += ./node_modules
49 |
50 | .PHONY: test
51 | test: $(NODEUNIT)
52 |
53 | # XXX write new tests
54 | # $(NODEUNIT) test/*.test.js
55 |
56 | include ./tools/mk/Makefile.deps
57 | ifeq ($(shell uname -s),SunOS)
58 | include ./tools/mk/Makefile.node_prebuilt.targ
59 | endif
60 | include ./tools/mk/Makefile.smf.targ
61 | include ./tools/mk/Makefile.targ
62 |
--------------------------------------------------------------------------------
/lib/nfs/fsstat.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 | var statvfs = require('statvfs');
9 |
10 | var common = require('./common');
11 |
12 |
13 |
14 | ///--- API
15 |
16 | // Stolen from: http://goo.gl/fBLulQ (IBM)
17 | function fsstat(call, reply, next) {
18 | var log = call.log;
19 |
20 | log.debug('fsstat(%s): entered', call.cachepath);
21 |
22 | statvfs(call.cachepath, function (err, stats) {
23 | if (err) {
24 | log.warn(err, 'fs_stat: statvfs failed');
25 | reply.error(nfs.NFS3ERR_IO);
26 | next(false);
27 | } else {
28 | reply.tbytes = stats.blocks * stats.bsize;
29 | reply.fbytes = stats.bfree * stats.bsize;
30 | reply.abytes = stats.bavail * stats.bsize;
31 | reply.tfiles = stats.files;
32 | reply.ffiles = stats.ffree;
33 | reply.afiles = stats.favail;
34 | reply.invarsec = 0;
35 |
36 | log.debug('fsstat(%s): done', call.cachepath);
37 | reply.send();
38 | next();
39 | }
40 | });
41 | }
42 |
43 |
44 |
45 | ///--- Exports
46 |
47 | module.exports = function chain() {
48 | return ([
49 | fsstat
50 | ]);
51 | };
52 |
--------------------------------------------------------------------------------
/lib/nfs/pathconf.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 |
9 | var common = require('./common');
10 |
11 |
12 |
13 | ///--- API
14 |
15 | // Stolen from: http://goo.gl/fBLulQ (IBM)
16 | function pathconf(call, reply, next) {
17 | var log = call.log;
18 |
19 | log.debug('pathconf(%s): entered', call.object);
20 |
21 | call.fs.stat(call._filename, function (err, stats) {
22 | if (err) {
23 | log.debug(err, 'pathconf(%s): stat failed', call._filename);
24 | reply.error(nfs.NFS3ERR_STALE);
25 | reply.send();
26 | next(false);
27 | } else {
28 | reply.setAttributes(stats);
29 |
30 | reply.linkmax = 0;
31 | reply.name_max = 1024;
32 | reply.no_trunc = true;
33 | reply.chown_restricted = true;
34 | reply.case_insensitive = false;
35 | reply.case_preserving = true;
36 |
37 | log.debug('pathconf(%s): done', call.object);
38 | reply.send();
39 | next();
40 | }
41 | });
42 | }
43 |
44 |
45 |
46 | ///--- Exports
47 |
48 | module.exports = function chain() {
49 | return ([
50 | common.fhandle_to_filename,
51 | pathconf
52 | ]);
53 | };
54 |
--------------------------------------------------------------------------------
/lib/nfs/access.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 |
9 | var common = require('./common');
10 |
11 |
12 |
13 | ///-- API
14 |
15 | function access_getattr(req, res, next) {
16 | var log = req.log;
17 |
18 | log.debug('access_getattr(%s, %s): entered', req.object, req._filename);
19 | req.fs.stat(req._filename, function (err, stats) {
20 | if (err) {
21 | req.log.warn(err, 'access_getattr: mantafs.stat failed');
22 | res.error(nfs.NFS3ERR_IO);
23 | next(false);
24 | return;
25 | }
26 |
27 | log.debug('access_getattr(%j): stats returned from cache', stats);
28 |
29 | res.setAttributes(stats);
30 | next();
31 | });
32 | }
33 |
34 |
35 | function access(call, reply, next) {
36 | reply.access =
37 | nfs.ACCESS3_READ |
38 | nfs.ACCESS3_LOOKUP |
39 | nfs.ACCESS3_MODIFY |
40 | nfs.ACCESS3_EXTEND |
41 | nfs.ACCESS3_DELETE |
42 | nfs.ACCESS3_EXECUTE;
43 | reply.send();
44 | next();
45 | }
46 |
47 |
48 |
49 | ///--- Exports
50 |
51 | module.exports = function chain() {
52 | return ([
53 | common.fhandle_to_filename,
54 | access_getattr,
55 | access
56 | ]);
57 | };
58 |
--------------------------------------------------------------------------------
/lib/nfs/write.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var assert = require('assert-plus');
8 | var nfs = require('nfs');
9 |
10 | var common = require('./common');
11 |
12 | var fs = require('fs');
13 |
14 |
15 | ///-- API
16 |
17 | function write(call, reply, next) {
18 | var c = call;
19 | var log = call.log;
20 | var stats = call.stats;
21 |
22 | log.debug('write(%s, %d, %d): entered', c.object, c.offset, c.count);
23 |
24 | assert.ok(stats);
25 |
26 | c.fs.write(stats.fd, c.data, 0, c.count, c.offset, function (err, n, b) {
27 | if (err) {
28 | log.warn(err, 'write: failed');
29 | reply.error(nfs.NFS3ERR_SERVERFAULT);
30 | next(false);
31 | return;
32 | }
33 |
34 | reply.count = n;
35 | reply.committed = nfs.stable_how.FILE_SYNC;
36 | reply.send();
37 |
38 | // This is a cache reference, so just updating it here will be enough
39 | if (c.offset + n > stats.size)
40 | stats.size = c.offset + n;
41 |
42 | log.debug('write(%d): done', n);
43 | next();
44 | });
45 | }
46 |
47 |
48 |
49 | ///--- Exports
50 |
51 | module.exports = function chain() {
52 | return ([
53 | common.fhandle_to_filename,
54 | common.open,
55 | write
56 | ]);
57 | };
58 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.node_deps.defs:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.node_deps.defs: Makefile for including npm modules whose sources
6 | # reside inside the repo. This should NOT be used for modules in the npm
7 | # public repo or modules that could be specified with git SHAs.
8 | #
9 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
10 | # into other repos as-is without requiring any modifications. If you find
11 | # yourself changing this file, you should instead update the original copy in
12 | # eng.git and then update your repo to use the new version.
13 | #
14 |
15 | #
16 | # This Makefile takes as input the following make variable:
17 | #
18 | # REPO_MODULES List of relative paths to node modules (i.e., npm
19 | # packages) inside this repo. For example:
20 | # src/node-canative, where there's a binary npm package
21 | # in src/node-canative.
22 | #
23 | # Based on the above, this Makefile defines the following new variables:
24 | #
25 | # REPO_DEPS List of relative paths to the installed modules. For
26 | # example: "node_modules/canative".
27 | #
28 | # The accompanying Makefile.node_deps.targ defines a target that will install
29 | # each of REPO_MODULES into REPO_DEPS and remove REPO_DEPS with "make clean".
30 | # The top-level Makefile is responsible for depending on REPO_DEPS where
31 | # appropriate (usually the "deps" or "all" target).
32 | #
33 |
34 | REPO_DEPS = $(REPO_MODULES:src/node-%=node_modules/%)
35 | CLEAN_FILES += $(REPO_DEPS)
36 |
--------------------------------------------------------------------------------
/svc/rc/mantanfs:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # mantanfs This shell script takes care of starting and stopping
4 | # the Manta NFS service.
5 |
6 | ### BEGIN INIT INFO
7 | # Provides: mantanfs
8 | # Default-Start: 3 4 5
9 | # Default-Stop: 0 1 6
10 | # Short-Description: Start up the Manta NFS server
11 | # Description: NFS is a popular protocol for file sharing across \
12 | # networks. This service provides NFS service with Manta \
13 | # as the backing store.
14 | ### END INIT INFO
15 |
16 | NODE="/usr/bin/node"
17 | SERVER="/usr/local/bin/server.js"
18 | CONFIG="/usr/local/etc/manta-nfs.json"
19 |
20 | uid=`id | cut -d\( -f1 | cut -d= -f2`
21 | RETVAL=0
22 |
23 | start() {
24 | [ -x $NODE ] || exit 5
25 | [ -e $SERVER ] || exit 5
26 | [ -e $CONFIG ] || exit 5
27 |
28 | # Only root can start the service
29 | [ $uid -ne 0 ] && exit 4
30 |
31 | # Make sure the server is not already running.
32 | if pgrep -f 'node.*server.js' > /dev/null ; then
33 | exit 0
34 | fi
35 |
36 | echo -n $"Starting Manta NFS server: "
37 | $NODE $SERVER -f $CONFIG >/var/log/mantanfs.log 2>&1 &
38 | RETVAL=$?
39 | echo
40 | return $RETVAL
41 | }
42 |
43 | stop() {
44 | # Only root can stop the service
45 | [ $uid -ne 0 ] && exit 4
46 |
47 | echo -n $"Stopping Manta NFS server: "
48 | pkill -f 'node.*server.js'
49 | RETVAL=$?
50 | echo
51 | return $RETVAL
52 | }
53 |
54 | # See how we were called.
55 | case "$1" in
56 | start)
57 | start
58 | ;;
59 | stop)
60 | stop
61 | ;;
62 | *)
63 | echo $"Usage: $0 {start|stop}"
64 | RETVAL=2
65 | ;;
66 | esac
67 |
68 | exit $RETVAL
69 |
70 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.defs:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.defs: common defines.
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 | # This makefile defines some useful defines. Include it at the top of
13 | # your Makefile.
14 | #
15 | # Definitions in this Makefile:
16 | #
17 | # TOP The absolute path to the project directory. The top dir.
18 | # BRANCH The current git branch.
19 | # TIMESTAMP The timestamp for the build. This can be set via
20 | # the TIMESTAMP envvar (used by MG-based builds).
21 | # STAMP A build stamp to use in built package names.
22 | #
23 |
24 | TOP := $(shell pwd)
25 |
26 | #
27 | # Mountain Gorilla-spec'd versioning.
28 | # See "Package Versioning" in MG's README.md:
29 | #
30 | #
31 | # Need GNU awk for multi-char arg to "-F".
32 | _AWK := $(shell (which gawk >/dev/null && echo gawk) \
33 | || (which nawk >/dev/null && echo nawk) \
34 | || echo awk)
35 | BRANCH := $(shell git symbolic-ref HEAD | $(_AWK) -F/ '{print $$3}')
36 | ifeq ($(TIMESTAMP),)
37 | TIMESTAMP := $(shell date -u "+%Y%m%dT%H%M%SZ")
38 | endif
39 | _GITDESCRIBE := g$(shell git describe --all --long --dirty | $(_AWK) -F'-g' '{print $$NF}')
40 | STAMP := $(BRANCH)-$(TIMESTAMP)-$(_GITDESCRIBE)
41 |
42 | # node-gyp will print build info useful for debugging with V=1
43 | export V=1
44 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.node_prebuilt.targ:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.node_prebuilt.targ: Makefile for including a prebuilt Node.js
6 | # build.
7 | #
8 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
9 | # into other repos as-is without requiring any modifications. If you find
10 | # yourself changing this file, you should instead update the original copy in
11 | # eng.git and then update your repo to use the new version.
12 |
13 |
14 | NODE_PREBUILT_TARBALL ?= $(error NODE_PREBUILT_TARBALL is not set: was Makefile.node_prebuilt.defs included?)
15 |
16 |
17 | # TODO: remove this limitation
18 | # Limitation: currently presuming that the NODE_INSTALL basename is
19 | # 'node' and that sdcnode tarballs have a 'node' top-level dir.
20 | $(NODE_EXEC) $(NPM_EXEC) $(NODE_WAF_EXEC):
21 | [[ $(shell basename $(NODE_INSTALL)) == "node" ]] \
22 | || (echo "Limitation: 'basename NODE_INSTALL' is not 'node'" && exit 1)
23 | rm -rf $(NODE_INSTALL) \
24 | $(BUILD)/prebuilt-node-* $(BUILD)/prebuilt-npm-*
25 | mkdir -p $(shell dirname $(NODE_INSTALL))
26 | if [[ $(shell echo $(NODE_PREBUILT_TARBALL) | cut -c 1-4) == "http" ]]; then \
27 | echo "Downloading '$(NODE_PREBUILT_BASE)'."; \
28 | curl -ksS --fail --connect-timeout 5 -o $(shell dirname $(NODE_INSTALL))/$(NODE_PREBUILT_BASE) $(NODE_PREBUILT_TARBALL); \
29 | (cd $(shell dirname $(NODE_INSTALL)) && $(TAR) xf $(NODE_PREBUILT_BASE)); \
30 | else \
31 | (cd $(shell dirname $(NODE_INSTALL)) && $(TAR) xf $(NODE_PREBUILT_TARBALL)); \
32 | fi
33 | ln -s $(TOP)/$(NODE_INSTALL)/bin/node $(NODE_EXEC)
34 | ln -s $(TOP)/$(NODE_INSTALL)/bin/npm $(NPM_EXEC)
35 |
--------------------------------------------------------------------------------
/lib/nfs/fsinfo.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 |
9 | var common = require('./common');
10 |
11 |
12 |
13 | ///--- API
14 |
15 | // Values obtained from: http://goo.gl/fBLulQ (IBM)
16 | function fsinfo(call, reply, next) {
17 | var log = call.log;
18 |
19 | log.debug('fsinfo(%s): entered', call.object);
20 |
21 | call.fs.stat(call._filename, function (err, stats) {
22 | if (err) {
23 | log.debug(err, 'fsinfo(%s): stat failed', call._filename);
24 | reply.error(nfs.NFS3ERR_STALE);
25 | reply.send();
26 | next(false);
27 | } else {
28 | reply.setAttributes(stats);
29 |
30 | reply.wtmax = reply.rtmax = 65536;
31 | reply.wtpref = reply.rtpref = 32768;
32 | reply.wtmult = reply.rtmult = 4096;
33 | reply.dtpref = 8192;
34 | reply.maxfilesize = 1099511627776; // 1T
35 | reply.time_delta = {
36 | seconds: 0,
37 | nseconds: 1000000
38 | }; // milliseconds
39 | reply.properties = nfs.FSF3_HOMOGENOUS;
40 |
41 | log.debug('fsinfo(%s): done', call.object);
42 | reply.send();
43 | next();
44 | }
45 | });
46 | }
47 |
48 |
49 |
50 | ///--- Exports
51 |
52 | module.exports = function chain() {
53 | return ([
54 | common.fhandle_to_filename,
55 | fsinfo
56 | ]);
57 | };
58 |
--------------------------------------------------------------------------------
/svc/smf/manta-nfs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
15 |
16 |
21 |
22 |
23 |
24 |
29 |
30 |
31 |
32 |
37 |
38 |
39 |
40 |
45 |
46 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | Manta NFS Server
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/lib/nfs/read.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var assert = require('assert-plus');
8 | var nfs = require('nfs');
9 |
10 | var common = require('./common');
11 |
12 | var fs = require('fs');
13 |
14 |
15 |
16 | ///-- API
17 |
18 |
19 |
20 |
21 | function read(call, reply, next) {
22 | var data = new Buffer(call.count);
23 | var log = call.log;
24 | var stats = call.stats;
25 |
26 | log.debug('read(%s, %d, %d): entered',
27 | call.object, call.offset, call.count);
28 |
29 | assert.ok(stats);
30 |
31 | call.fs.read(stats.fd, data, 0, call.count, call.offset, function (err, n) {
32 | if (err) {
33 | log.warn(err, 'read: fsCache.read failed');
34 | reply.error(nfs.NFS3ERR_IO);
35 | next(false);
36 | return;
37 | }
38 |
39 | // use stat.size to determine eof
40 | var eof = false;
41 | if (stats.size <= (call.offset + n)) {
42 | eof = true;
43 |
44 | // If we're at EOF, we assume we can close the FD out
45 | if (call.fd_cache.has(call.object))
46 | call.fd_cache.del(call.object);
47 |
48 | }
49 |
50 | // some NFS clients verify that the returned buffer
51 | // length matches the result count
52 | if (n < call.count)
53 | data = data.slice(0, n);
54 |
55 | log.debug('read(%s): done => %d', call.object, n);
56 |
57 | reply.count = n;
58 | reply.data = data;
59 | reply.eof = eof;
60 | reply.send();
61 | next();
62 | });
63 | }
64 |
65 |
66 |
67 | ///--- Exports
68 |
69 | module.exports = function chain() {
70 | return ([
71 | common.fhandle_to_filename,
72 | common.open,
73 | read
74 | ]);
75 | };
76 |
--------------------------------------------------------------------------------
/etc/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "manta": {
3 | "_comment": "the Manta environment variables can be used instead",
4 | "keyFile": "/Users/foo/.ssh/id_rsa",
5 | "keyId": "70:c0:50:d6:9e:1f:0c:74:04:8b:08:c9:12:a2:7c:9f",
6 | "url": "https://us-east.manta.joyent.com",
7 | "user": "foo.bar"
8 | },
9 | "database": {
10 | "_comment": "the default DB and cache is under /var/tmp/mfsdb",
11 | "location": "/var/tmp/mfsdb",
12 | "_comment2": "how much local disk space to use for caching",
13 | "sizeMB": 5120,
14 | "_comment3": "time-to-live in cache before cheking if stale (secs)",
15 | "ttl": 43200,
16 | "_comment4": "time for dirty file to be cached before writeback (secs)",
17 | "wbtime": 60,
18 | "_comment5": "number of parallel writebacks",
19 | "num_par": 2
20 | },
21 | "portmap": {
22 | "_comment": "usehost forces use of the system's portmapper",
23 | "usehost": 1
24 | },
25 | "mount": {
26 | "_comment": "set address if serving network beyond localhost",
27 | "address": "0.0.0.0",
28 | "_comment2": "can deny/allow mounting by given host addresses",
29 | "_comment3": "normally use only one of these lists",
30 | "hosts_deny": {
31 | "192.168.0.12": {},
32 | "192.168.0.13": {}
33 | },
34 | "hosts_allow": {
35 | "127.0.0.1": {},
36 | "192.168.0.10": {},
37 | "192.168.0.11": {}
38 | },
39 | "_comment4": "can limit access to user's Manta namespace",
40 | "exports": {
41 | "/foo.bar/stor/project": {},
42 | "/foo.bar/public": {}
43 | }
44 | },
45 | "nfs": {
46 | "_comment": "can specify uid/gid for 'nobody' on clients",
47 | "uid": 65534,
48 | "gid": 65534,
49 | "_comment2": "tunables for file descriptor cache",
50 | "fd_cache": {
51 | "max": 50,
52 | "ttl": 15
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib/nfs/setattr.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 |
9 | var common = require('./common');
10 |
11 |
12 |
13 | ///-- API
14 |
15 | // We implement setattr only for the special cases of:
16 | // - truncating an existing file down to 0 (i.e. when its being overwritten).
17 | // - chmod/chown (we just lie)
18 | //
19 | function setattr(req, res, next) {
20 | var attrs = req.new_attributes;
21 | var log = req.log;
22 |
23 | log.debug('setattr(%s, %d): entered', req.object, req.new_attributes.size);
24 |
25 | if (attrs.how_m_time === nfs.time_how.SET_TO_CLIENT_TIME) {
26 | // The client is touching the file. We use this as an indication to
27 | // refresh the cached data. We don't need to worry about supplying
28 | // valid times for atime and mtime here, and we still tell the client
29 | // that this is an error.
30 | req.fs.utimes(req._filename, 0, 0, function (err) {
31 | if (err) {
32 | log.warn(err, 'setattr: mantafs.utimes failed');
33 | res.error(nfs.NFS3ERR_SERVERFAULT);
34 | } else {
35 | res.error(nfs.NFS3ERR_ACCES);
36 | }
37 | next(false);
38 | });
39 | return;
40 | }
41 |
42 | // If attrs.how_a_time or attrs.how_m_time is SET_TO_SERVER_TIME we just
43 | // ignore that. Some apps, such as vi, seem to initiate that.
44 | // We also ignore attrs.mode, attrs.uid and attrs.gid since we can't
45 | // change those either but various apps try.
46 |
47 | // OK, we're setting the file size
48 | if (attrs.size !== null) {
49 | req.fs.truncate(req._filename, attrs.size, function (err) {
50 | if (err) {
51 | log.warn(err, 'setattr: mantafs.truncate failed');
52 | res.error(nfs.NFS3ERR_SERVERFAULT);
53 | next(false);
54 | return;
55 | }
56 |
57 | log.debug('setattr: done');
58 | res.send();
59 | next();
60 | });
61 | } else {
62 | log.debug('setattr: done');
63 | res.send();
64 | next();
65 | }
66 | }
67 |
68 |
69 | ///--- Exports
70 |
71 | module.exports = function chain() {
72 | return ([
73 | common.fhandle_to_filename,
74 | setattr
75 | ]);
76 | };
77 |
--------------------------------------------------------------------------------
/tools/bashstyle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /*
4 | * Copyright (c) 2012, Joyent, Inc. All rights reserved.
5 | *
6 | * bashstyle: check bash scripts for adherence to style guidelines, including:
7 | *
8 | * o no lines longer than 80 characters
9 | * o file does not end with a blank line
10 | *
11 | * Future enhancements could include:
12 | * o indents consistent with respect to tabs, spaces
13 | * o indents consistently sized (all are some multiple of the smallest
14 | * indent, which must be a tab or 4 or 8 spaces)
15 | */
16 |
17 | var mod_assert = require('assert');
18 | var mod_fs = require('fs');
19 |
20 | var nerrors = 0;
21 |
22 | main();
23 | process.exit(0);
24 |
25 | function main()
26 | {
27 | var files = process.argv.slice(2);
28 |
29 | if (files.length === 0) {
30 | console.error('usage: %s file1 [...]',
31 | process.argv.slice(0, 2).join(' '));
32 | process.exit(2);
33 | }
34 |
35 | files.forEach(checkFile);
36 |
37 | if (nerrors != 0)
38 | process.exit(1);
39 | }
40 |
41 | function checkFile(filename)
42 | {
43 | var text = mod_fs.readFileSync(filename, 'utf-8');
44 | var lines = text.split('\n');
45 | var i;
46 |
47 | mod_assert.ok(lines.length > 0);
48 |
49 | /*
50 | * Expand tabs in each line and check for long lines.
51 | */
52 | for (i = 1; i <= lines.length; i++) {
53 | var line = expandTabs(lines[i - 1]);
54 |
55 | if (line.length > 80) {
56 | nerrors++;
57 | console.log('%s: %d: line exceeds 80 columns',
58 | filename, i);
59 | }
60 | }
61 |
62 | /*
63 | * No sane editor lets you save a file without a newline at the very end.
64 | */
65 | if (lines[lines.length - 1].length !== 0) {
66 | nerrors++;
67 | console.log('%s: %d: file does not end with newline',
68 | filename, lines.length);
69 | }
70 |
71 | /*
72 | * Since the file will always end with a newline, the last entry of
73 | * "lines" will actually be blank.
74 | */
75 | if (lines.length > 1 && lines[lines.length - 2].length === 0) {
76 | nerrors++;
77 | console.log('%s: %d: file ends with a blank line',
78 | filename, lines.length - 1);
79 | }
80 | }
81 |
82 | function expandTabs(text)
83 | {
84 | var out = '';
85 | var col = 0;
86 | var j, k;
87 |
88 | for (j = 0; j < text.length; j++) {
89 | if (text[j] != '\t') {
90 | out += text[j];
91 | col++;
92 | continue;
93 | }
94 |
95 | k = 8 - (col % 8);
96 | col += k;
97 |
98 | do {
99 | out += ' ';
100 | } while (--k > 0);
101 |
102 | col += k;
103 | }
104 |
105 | return (out);
106 | }
107 |
--------------------------------------------------------------------------------
/lib/nfs/remove.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 | var path = require('path');
9 |
10 | var common = require('./common');
11 |
12 |
13 |
14 | ///-- API
15 |
16 | function remove_lookup_dir(call, reply, next) {
17 | var log = call.log;
18 |
19 | log.debug('remove_lookup_dir(%s): entered', call._object.dir);
20 | call.fs.fhandle(call._object.dir, function (err, name) {
21 | if (err) {
22 | log.warn(err, 'remove_lookup_dir(%s): fhandle notfound',
23 | call._object.dir);
24 | reply.error(nfs.NFS3ERR_STALE);
25 | next(false);
26 | } else {
27 | call._dirname = name;
28 | call._filename = path.join(name, call._object.name);
29 | log.debug('remove_lookup_dir(%s): done -> %s', call._object.dir,
30 | name);
31 | next();
32 | }
33 | });
34 | }
35 |
36 |
37 | function remove_stat_dir(call, reply, next) {
38 | var log = call.log;
39 |
40 | log.debug('remove_stat_dir(%s): entered', call._filename);
41 | call.fs.stat(call._filename, function (err, stats) {
42 | if (err) {
43 | log.warn(err, 'remove_stat_dir(%s): failed', call._filename);
44 | reply.error(nfs.NFS3ERR_IO);
45 | next(false);
46 | return;
47 | }
48 | if (stats.isDirectory()) {
49 | log.warn(err, 'remove_stat_dir(%s): is a directory',
50 | call._filename);
51 | reply.error(nfs.NFS3ERR_NOTDIR);
52 | next(false);
53 | return;
54 | }
55 |
56 | log.debug('remove_stat_dir(%s): done', call._filename);
57 | next();
58 | });
59 | }
60 |
61 |
62 | function remove(call, reply, next) {
63 | var log = call.log;
64 |
65 | log.debug('remove(%s): entered', call._filename);
66 | call.fs.unlink(call._filename, function (err) {
67 | if (err) {
68 | log.warn(err, 'remove(%s): failed', call._filename);
69 | common.handle_error(err, call, reply, next);
70 | return;
71 | }
72 |
73 | log.debug('remove(%s): done', call._filename);
74 | reply.send();
75 | next();
76 | });
77 | }
78 |
79 |
80 |
81 | ///--- Exports
82 |
83 | module.exports = function chain() {
84 | return ([
85 | remove_lookup_dir,
86 | remove_stat_dir,
87 | remove
88 | ]);
89 | };
90 |
--------------------------------------------------------------------------------
/lib/nfs/rmdir.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 | var path = require('path');
9 |
10 | var common = require('./common');
11 |
12 |
13 |
14 | ///-- API
15 |
16 | function rmdir_lookup_dir(call, reply, next) {
17 | var log = call.log;
18 |
19 | log.debug('rmdir_lookup_dir(%s): entered', call._object.dir);
20 | call.fs.fhandle(call._object.dir, function (err, name) {
21 | if (err) {
22 | log.warn(err, 'rmdir_lookup_dir(%s): fhandle notfound',
23 | call._object.dir);
24 | reply.error(nfs.NFS3ERR_STALE);
25 | next(false);
26 | } else {
27 | call._dirname = name;
28 | call._filename = path.join(name, call._object.name);
29 | log.debug('rmdir_lookup_dir(%s): done -> %s', call._object.dir,
30 | name);
31 | next();
32 | }
33 | });
34 | }
35 |
36 |
37 | function rmdir_stat_dir(call, reply, next) {
38 | var log = call.log;
39 |
40 | log.debug('rmdir_stat_dir(%s): entered', call._filename);
41 | call.fs.stat(call._filename, function (err, stats) {
42 | if (err) {
43 | log.warn(err, 'rmdir_stat_dir(%s): failed', call._filename);
44 | reply.error(nfs.NFS3ERR_IO);
45 | next(false);
46 | return;
47 | }
48 | if (!stats.isDirectory()) {
49 | log.warn(err, 'rmdir_stat_dir(%s): not a directory',
50 | call._filename);
51 | reply.error(nfs.NFS3ERR_NOTDIR);
52 | next(false);
53 | return;
54 | }
55 |
56 | log.debug('rmdir_stat_dir(%s): done', call._filename);
57 | next();
58 | });
59 | }
60 |
61 |
62 | function rmdir(call, reply, next) {
63 | var log = call.log;
64 |
65 | log.debug('rmdir(%s): entered', call._filename);
66 | call.fs.rmdir(call._filename, function (err) {
67 | if (err && err.code !== 'ENOENT') {
68 | if (err.code === 'ENOTEMPTY') {
69 | log.info('rmdir(%s): directory not empty', call._filename);
70 | } else {
71 | log.warn(err, 'rmdir(%s): failed', call._filename);
72 | }
73 | common.handle_error(err, call, reply, next);
74 | return;
75 | }
76 |
77 | log.debug('rmdir(%s): done', call._filename);
78 | reply.send();
79 | next();
80 | });
81 | }
82 |
83 |
84 |
85 | ///--- Exports
86 |
87 | module.exports = function chain() {
88 | return ([
89 | rmdir_lookup_dir,
90 | rmdir_stat_dir,
91 | rmdir
92 | ]);
93 | };
94 |
--------------------------------------------------------------------------------
/tools/mkrepo:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | // -*- mode: js -*-
3 | // Copyright 2012 Joyent, Inc. All rights reserved.
4 |
5 | var child_process = require('child_process');
6 | var fs = require('fs');
7 | var path = require('path');
8 |
9 |
10 |
11 | ///--- Globals
12 |
13 | var DIRS = [
14 | 'deps',
15 | 'docs',
16 | 'docs/media',
17 | 'lib',
18 | 'smf',
19 | 'smf/manifests',
20 | 'test',
21 | 'tools',
22 | 'tools/mk'
23 | ];
24 |
25 | var SUBMODULES = {
26 | 'javascriptlint': 'git://github.com/davepacheco/javascriptlint.git',
27 | 'jsstyle': 'git://github.com/davepacheco/jsstyle.git',
28 | 'restdown': 'git://github.com/trentm/restdown.git'
29 | };
30 |
31 |
32 |
33 | ///--- Internal Functions
34 |
35 | function usage(code, message) {
36 | if (message)
37 | console.error(message);
38 |
39 | console.error('usage: %s [repo ...]', path.basename(process.argv[1]));
40 | process.exit(code);
41 | }
42 |
43 |
44 | function ensureDirectoryNotExists(dir) {
45 | try {
46 | var stats = fs.statSync(dir);
47 | usage(1, dir + ' already exists');
48 | } catch (e) {
49 | return false;
50 | }
51 | }
52 |
53 |
54 | function cp(src, dest) {
55 | fs.createReadStream(src).pipe(fs.createWriteStream(dest));
56 | }
57 |
58 |
59 | function exec(cmd, dir, cb) {
60 | child_process.exec(cmd, {cwd: dir}, function (err, stdout, stderr) {
61 | if (err)
62 | process.exit(err.code || 1);
63 |
64 | if (typeof (cb) === 'function')
65 | return cb(null);
66 | });
67 | }
68 |
69 |
70 | function mkdir(d) {
71 | fs.mkdirSync(d, '0750');
72 | }
73 |
74 | function gitify(dir, repo) {
75 | exec('git init', dir, function () {
76 | exec('git remote add origin git@git.joyent.com:' + repo + '.git', dir);
77 |
78 | Object.keys(SUBMODULES).forEach(function (k) {
79 | // stub out the git submodule call
80 | console.error('Cloning into deps/' + k + '...');
81 | exec('git submodule add ' + SUBMODULES[k] + ' ./deps/' + k, dir);
82 | });
83 | });
84 | }
85 |
86 |
87 |
88 | ///--- Mainline
89 |
90 | if (process.argv.length < 3)
91 | usage(1, 'repo required');
92 |
93 | process.argv.slice(2).forEach(function (arg) {
94 | var repo = path.resolve(arg);
95 | ensureDirectoryNotExists(repo);
96 | mkdir(repo);
97 | DIRS.concat('.').forEach(function (d) {
98 | var dir = repo + '/' + d;
99 | if (d != '.')
100 | mkdir(dir);
101 |
102 | fs.readdirSync('./' + d).forEach(function (f) {
103 | var src = './' + d + '/' + f;
104 | var dest = dir + '/' + f;
105 | if (fs.statSync(src).isFile() && !/^\..*/.test(f))
106 | cp(src, dest);
107 | });
108 | });
109 |
110 | cp('./.gitignore', repo + '/.gitignore');
111 | gitify(repo, arg);
112 | });
113 |
--------------------------------------------------------------------------------
/lib/portmap.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var assert = require('assert-plus');
8 | var rpc = require('oncrpc');
9 |
10 |
11 |
12 | ///--- API
13 |
14 | function createPortmapClient(opts) {
15 | assert.object(opts, 'options');
16 | assert.object(opts.log, 'options.log');
17 | assert.string(opts.url, 'options.url');
18 |
19 | var c = rpc.createPortmapClient({
20 | log: opts.log,
21 | url: opts.url
22 | });
23 |
24 | return (c);
25 | }
26 |
27 |
28 | function createPortmapServer(opts) {
29 | assert.object(opts, 'options');
30 | assert.object(opts.log, 'options.log');
31 | assert.object(opts.mappings, 'options.mappings');
32 |
33 | var mappings = {};
34 | var s = rpc.createPortmapServer({
35 | log: opts.log
36 | });
37 |
38 | Object.keys(opts.mappings).forEach(function (k) {
39 | mappings[k] = opts.mappings[k].map(function (i) {
40 | assert.number(i.prog, k + '.prog');
41 | assert.number(i.vers, k + '.vers');
42 | assert.number(i.prot, k + '.prot');
43 | assert.number(i.port, k + '.port');
44 |
45 | return ({
46 | name: k,
47 | prog: i.prog,
48 | vers: i.vers,
49 | prot: i.prot,
50 | port: i.port
51 | });
52 | });
53 | });
54 |
55 | s.dump(function dump(req, res, next) {
56 | Object.keys(mappings).forEach(function (k) {
57 | mappings[k].forEach(function (i) {
58 | res.addMapping(i);
59 | });
60 | });
61 |
62 | res.send();
63 | next();
64 | });
65 |
66 | s.get_port(function get_port(req, res, next) {
67 | var m = req.mapping;
68 | Object.keys(mappings).forEach(function (k) {
69 | mappings[k].some(function (i) {
70 | if (i.prog === m.prog &&
71 | i.vers === m.vers &&
72 | i.prot === m.prot) {
73 |
74 | res.port = i.port;
75 | return (true);
76 | }
77 |
78 | return (false);
79 | });
80 | });
81 |
82 |
83 | res.send();
84 | next();
85 | });
86 |
87 | s.on('after', function (name, call, reply, err) {
88 | opts.log.debug({
89 | procedure: name,
90 | rpc_call: call,
91 | rpc_reply: reply,
92 | err: err
93 | }, 'portmapd: %s handled', name);
94 | });
95 |
96 | return (s);
97 | }
98 |
99 |
100 |
101 | ///--- Exports
102 |
103 | module.exports = {
104 | createPortmapServer: createPortmapServer,
105 | createPortmapClient: createPortmapClient
106 | };
107 |
--------------------------------------------------------------------------------
/tools/runtests.in:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Run the TODONAME tests.
6 | # Run `./runtests -h` for usage info.
7 | #
8 |
9 | if [ "$TRACE" != "" ]; then
10 | export PS4='${BASH_SOURCE}:${LINENO}: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
11 | set -o xtrace
12 | fi
13 | set -o errexit
14 | set -o pipefail
15 |
16 |
17 |
18 | #---- guard
19 |
20 | if [[ ! -f "/lib/sdc/.sdc-test-no-production-data" ]]; then
21 | cat < %s', call.what.dir, name);
30 | next();
31 | }
32 | });
33 | }
34 |
35 |
36 | function stat_file(call, reply, next) {
37 | var log = call.log;
38 |
39 | log.debug('stat_file(%s): entered', call._filename);
40 | call.fs.stat(call._filename, function (err, stats) {
41 | if (err) {
42 | log.debug(err, 'stat_file(%s): failed', call._filename);
43 | reply.error(nfs.NFS3ERR_NOENT);
44 | next(false);
45 | } else {
46 | // reply.object = uuid;
47 | reply.setAttributes(stats);
48 | log.debug({stats: stats}, 'stat_file(%s): done', call._filename);
49 | next();
50 | }
51 | });
52 | }
53 |
54 |
55 | function stat_dir(call, reply, next) {
56 | var log = call.log;
57 |
58 | log.debug('stat_dir(%s): entered', call._dirname);
59 | call.fs.stat(call._dirname, function (err, stats) {
60 | if (err) {
61 | log.debug(err, 'stat_dir(%s): failed', call._dirname);
62 | reply.error(nfs.NFS3ERR_IO);
63 | next(false);
64 | } else {
65 | reply.setDirAttributes(stats);
66 | log.debug({stats: stats}, 'stat_dir(%s): done', call._dirname);
67 | next();
68 | }
69 | });
70 | }
71 |
72 |
73 | function lookup(call, reply, next) {
74 | var log = call.log;
75 |
76 | log.debug('lookup(%s): entered', call._filename);
77 | call.fs.lookup(call._filename, function (err, fhandle) {
78 | if (err) {
79 | log.debug(err, 'lookup(%s): failed', call._filename);
80 | reply.error(nfs.NFS3ERR_NOENT);
81 | next(false);
82 | return;
83 | }
84 | reply.object = fhandle;
85 | reply.send();
86 | next();
87 | });
88 | }
89 |
90 |
91 |
92 | ///--- Exports
93 |
94 | module.exports = function chain() {
95 | return ([
96 | function cheat(call, reply, next) {
97 | call._object_override = call.what.dir;
98 | next();
99 | },
100 | lookup_dir,
101 | stat_dir,
102 | stat_file,
103 | lookup
104 | ]);
105 | };
106 |
--------------------------------------------------------------------------------
/lib/nfs/common.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var assert = require('assert-plus');
8 | var nfs = require('nfs');
9 | var once = require('once');
10 |
11 |
12 |
13 | ///-- API
14 |
15 | function fhandle_to_filename(call, reply, next) {
16 | var fhandle = call.fhandle || call.object;
17 | var log = call.log;
18 |
19 | log.debug('fhandle_to_filename(%s): entered', fhandle);
20 | assert.string(fhandle, 'call.fhandle');
21 |
22 |
23 | call.fs.fhandle(fhandle, function (err, name) {
24 | if (err) {
25 | log.warn(err, 'fhandle_to_filename(%s): failed', fhandle);
26 | reply.error(nfs.NFS3ERR_BADHANDLE);
27 | next(false);
28 | } else {
29 | call._filename = name;
30 | log.debug('fhandle_to_filename(%s): done: %s', fhandle, name);
31 | next();
32 | }
33 | });
34 | }
35 |
36 | function handle_error(err, req, res, next) {
37 | switch (err.code) {
38 | case 'EACCESS':
39 | res.error(nfs.NFS3ERR_ACCES);
40 | break;
41 |
42 | case 'ENOENT':
43 | res.error(nfs.NFS3ERR_NOENT);
44 | break;
45 |
46 | case 'ENOTDIR':
47 | res.error(nfs.NFS3ERR_NOTDIR);
48 | break;
49 |
50 | case 'ENOTEMPTY':
51 | res.error(nfs.NFS3ERR_NOTEMPTY);
52 | break;
53 |
54 | default:
55 | res.error(nfs.NFS3ERR_SERVERFAULT);
56 | break;
57 | }
58 | next(false);
59 | }
60 |
61 |
62 | function open(call, reply, next) {
63 | var log = call.log;
64 |
65 | log.debug('open(%s): entered', call.object);
66 |
67 | if (call.fd_cache.has(call.object)) {
68 | call.stats = call.fd_cache.get(call.object);
69 | next();
70 | return;
71 | }
72 |
73 | call.fs.stat(call._filename, function (st_err, stats) {
74 | if (st_err) {
75 | log.warn(st_err, 'open: fsCache.stat failed');
76 | reply.error(nfs.NFS3ERR_IO);
77 | next(false);
78 | return;
79 | }
80 |
81 | call.fs.open(call._filename, 'r+', function (err, fd) {
82 | if (err) {
83 | log.warn(err, 'open: failed');
84 | reply.error(nfs.NFS3ERR_SERVERFAULT);
85 | next(false);
86 | return;
87 | }
88 |
89 | call.stats = {
90 | fd: fd,
91 | size: stats.size
92 | };
93 | call.fd_cache.set(call.object, call.stats);
94 |
95 | log.debug('open(%s): done => %j', call.object, call.stats);
96 | next();
97 | });
98 | });
99 | }
100 |
101 |
102 | // based on http://stackoverflow.com/a/7616484
103 | function hash(s) {
104 | var h = 0, i, c;
105 |
106 | var l = s.length;
107 | if (l === 0)
108 | return (h);
109 | for (i = 0; i < l; i++) {
110 | c = s.charCodeAt(i);
111 | h = ((h << 5) - h) + c;
112 | h |= 0; // Convert to 32bit integer
113 | }
114 | return (Math.abs(h));
115 | }
116 |
117 |
118 | ///--- Exports
119 |
120 | module.exports = {
121 | fhandle_to_filename: fhandle_to_filename,
122 | handle_error: handle_error,
123 | open: open,
124 | hash: hash
125 | };
126 |
--------------------------------------------------------------------------------
/lib/nfs/readdir.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var path = require('path');
8 |
9 | var nfs = require('nfs');
10 |
11 | var common = require('./common');
12 |
13 | var rpc = require('oncrpc');
14 | var XDR = rpc.XDR;
15 |
16 |
17 | ///--- Helpers
18 |
19 | function rand() {
20 | return (Math.floor((Math.random() * Math.pow(2, 31)) + 1));
21 | }
22 |
23 |
24 |
25 | ///-- API
26 |
27 | function readdir(call, reply, next) {
28 | var log = call.log;
29 | log.debug('readdir(%s): entered', call._filename);
30 |
31 | call.fs.readdir(call._filename, function (err, files) {
32 | if (err) {
33 | log.warn(err, 'readdir(%s): failed', call.dir);
34 | reply.error(err.code === 'ENOTDIR' ?
35 | nfs.NFS3ERR_NOTDIR :
36 | nfs.NFS3ERR_IO);
37 | next(false);
38 | return;
39 | }
40 |
41 | // The cookieverf will be 0 on the initial call.
42 | var h = common.hash(call._filename);
43 | if (call.cookieverf.readUInt32LE(0) != 0) {
44 | // This is a follow-up call, confirm cookie.
45 | if (call.cookieverf.readUInt32LE(0) != h) {
46 | reply.error(nfs.NFS3ERR_BAD_COOKIE);
47 | next(false);
48 | return;
49 | }
50 | }
51 |
52 | reply.eof = true;
53 |
54 | var cook = 1;
55 | // Track the returned data size
56 | // status (4) + bool_dir_attrs (4) + fattr3.XDR_SIZE +
57 | // cookieverf3 (8) + bool_eof (4) + final_list_false (4)
58 | // See nfs readdir_reply.js.
59 | var sz = 116;
60 | files.every(function (f) {
61 | // The call cookie will be 0 on the initial call
62 | if (call.cookie != 0 && call.cookie >= cook) {
63 | // we need to scan the dir until we reach the right entry
64 | cook++;
65 | return (true);
66 | }
67 |
68 | // We need to track the returned data size to be sure we fit in
69 | // call.count bytes.
70 | // list_true (4) + fileid (8) + cookie (8) + name_len
71 | var delta = 20 + XDR.byteLength(f);
72 | if ((sz + delta) > call.count) {
73 | reply.eof = false;
74 | return (false);
75 | }
76 |
77 | reply.addEntry({
78 | fileid: common.hash(path.join(call._filename, f)),
79 | name: f,
80 | cookie: cook++
81 | });
82 | sz += delta;
83 | return (true);
84 | });
85 |
86 | reply.cookieverf = new Buffer(8);
87 | reply.cookieverf.fill(0);
88 | reply.cookieverf.writeUInt32LE(h, 0, true);
89 |
90 | call.fs.stat(call._filename, function (err2, stats) {
91 | if (err2) {
92 | log.warn(err2, 'readdir(%s): stat failed', call._filename);
93 | } else {
94 | reply.setDirAttributes(stats);
95 | }
96 | reply.send();
97 | next();
98 | });
99 | });
100 | }
101 |
102 |
103 | ///--- Exports
104 |
105 | module.exports = function chain() {
106 | return ([
107 | common.fhandle_to_filename,
108 | readdir
109 | ]);
110 | };
111 |
--------------------------------------------------------------------------------
/lib/nfs/rename.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 | var path = require('path');
9 |
10 | var common = require('./common');
11 |
12 |
13 |
14 | ///-- API
15 |
16 | function rename_get_from_dir(call, reply, next) {
17 | var log = call.log;
18 |
19 | log.debug('rename_get_from_dir(%s): entered', call.from.dir);
20 | call.fs.fhandle(call.from.dir, function (err, name) {
21 | if (err) {
22 | log.warn(err, 'rename_get_from_dir(%s): fhandle notfound',
23 | call.from.dir);
24 | reply.error(nfs.NFS3ERR_STALE);
25 | next(false);
26 | return;
27 | }
28 |
29 | call._from_dirname = name;
30 | call._from_filename = path.join(name, call.from.name);
31 | log.debug('rename_get_from_dir(%s): done -> %s', call.from.dir, name);
32 | next();
33 | });
34 | }
35 |
36 |
37 | function rename_get_to_dir(call, reply, next) {
38 | var log = call.log;
39 |
40 | log.debug('rename_get_to_dir(%s): entered', call.to.dir);
41 | call.fs.fhandle(call.to.dir, function (err, name) {
42 | if (err) {
43 | log.warn(err, 'rename_get_to_dir(%s): fhandle notfound',
44 | call.to.dir);
45 | reply.error(nfs.NFS3ERR_STALE);
46 | next(false);
47 | return;
48 | }
49 |
50 | call._to_dirname = name;
51 | call._to_filename = path.join(name, call.to.name);
52 | log.debug('rename_get_to_dir(%s): done -> %s', call.to.dir, name);
53 | next();
54 | });
55 | }
56 |
57 |
58 | // Check if trying to rename a directory. This is not supported.
59 | function rename_stat_from(call, reply, next) {
60 | var log = call.log;
61 |
62 | log.debug('rename_stat_from(%s): entered', call._dirname);
63 | call.fs.stat(call._from_filename, function (err, stats) {
64 | if (err) {
65 | log.warn(err, 'rename_stat_from(%s): failed', call._from_filename);
66 | reply.error(nfs.NFS3ERR_IO);
67 | next(false);
68 | return;
69 | }
70 |
71 | if (stats.isDirectory()) {
72 | log.debug('rename_stat_from(%s): is a directory',
73 | call._from_filename);
74 | reply.error(nfs.NFS3ERR_ISDIR);
75 | next(false);
76 | return;
77 | }
78 |
79 | log.debug('rename_stat_from(%s): done', call._from_filename);
80 | next();
81 | });
82 | }
83 |
84 | function rename(call, reply, next) {
85 | var log = call.log;
86 |
87 | log.debug('rename(%s -> %s): entered',
88 | call._from_filename, call._to_filename);
89 | call.fs.rename(call._from_filename, call._to_filename, function (err) {
90 | if (err) {
91 | log.warn(err, 'rename(%s, %s): failed', call._from_filename,
92 | call._to_filename);
93 | reply.error(nfs.NFS3ERR_NOENT);
94 | next(false);
95 | return;
96 | }
97 | log.debug('rename: done');
98 | reply.send();
99 | next();
100 | });
101 | }
102 |
103 |
104 |
105 | ///--- Exports
106 |
107 | module.exports = function chain() {
108 | return ([
109 | rename_get_from_dir,
110 | rename_get_to_dir,
111 | rename_stat_from,
112 | rename
113 | ]);
114 | };
115 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var fs = require('fs');
8 | var path = require('path');
9 |
10 | var assert = require('assert-plus');
11 | var bunyan = require('bunyan');
12 | var manta = require('manta');
13 | var once = require('once');
14 |
15 |
16 |
17 | ///--- Helpers
18 |
19 | function _export(obj) {
20 | Object.keys(obj).forEach(function (k) {
21 | module.exports[k] = obj[k];
22 | });
23 | }
24 |
25 |
26 |
27 | ///--- API
28 |
29 | var BUNYAN_SERIALIZERS = {
30 | err: bunyan.stdSerializers.err,
31 | rpc_call: function serialize_rpc_call(c) {
32 | return (c ? c.toString() : null);
33 | },
34 | rpc_reply: function serialize_rpc_reply(r) {
35 | return (r ? r.toString() : null);
36 | }
37 | };
38 |
39 |
40 | function createLogger(name, stream) {
41 | var l = bunyan.createLogger({
42 | name: name || path.basename(process.argv[1]),
43 | level: process.env.LOG_LEVEL || 'error',
44 | stream: stream || process.stdout,
45 | serializers: BUNYAN_SERIALIZERS
46 | });
47 |
48 | return (l);
49 | }
50 |
51 |
52 | function createMantaClient(opts) {
53 | assert.object(opts, 'options');
54 | assert.object(opts.log, 'options.log');
55 | assert.optionalString(opts.keyId, 'options.keyId');
56 | assert.optionalString(opts.keyFile, 'options.keyFile');
57 | assert.optionalString(opts.url, 'options.url');
58 | assert.optionalString(opts.user, 'options.user');
59 |
60 | var sign;
61 |
62 | if (opts.keyFile) {
63 | // assume if opts.keyFile is set, all 4 opts are set in config file
64 |
65 | opts.log.info('createMantaClient: using privateKeySigner (%s)',
66 | opts.keyFile);
67 | try {
68 | sign = manta.privateKeySigner({
69 | key: fs.readFileSync(opts.keyFile, 'utf8'),
70 | keyId: opts.keyId,
71 | user: opts.user
72 | });
73 | } catch (e) {
74 | opts.log.error('createMantaClient: unable to read %s',
75 | opts.keyFile);
76 | process.exit(1);
77 | }
78 | } else {
79 | // use the manta config from the environment
80 |
81 | if (process.env.MANTA_NO_AUTH === 'true') {
82 | opts.log.info('createMantaClient: Not using signer');
83 | sign = null;
84 | } else {
85 | if (!process.env.MANTA_USER || !process.env.MANTA_KEY_ID ||
86 | !process.env.MANTA_URL) {
87 | opts.log.error('no manta configuration and no manta ' +
88 | 'environment variables');
89 | process.exit(1);
90 | }
91 |
92 | opts.log.info('createMantaClient: using CLI signer');
93 | sign = manta.cliSigner({
94 | keyId: process.env.MANTA_KEY_ID,
95 | user: process.env.MANTA_USER
96 | });
97 | }
98 |
99 | opts.url = process.env.MANTA_URL;
100 | }
101 |
102 | var client = manta.createClient({
103 | sign: sign,
104 | log: opts.log.child({component: 'MantaClient'}, true),
105 | url: opts.url,
106 | user: opts.user
107 | });
108 |
109 | return (client);
110 | }
111 |
112 |
113 |
114 | ///--- Exports
115 |
116 | module.exports = {
117 | bunyan: {
118 | createLogger: createLogger,
119 | serializers: BUNYAN_SERIALIZERS
120 | },
121 | createLogger: createLogger,
122 | createMantaClient: createMantaClient
123 | };
124 |
125 | _export(require('./mount'));
126 | _export(require('./nfs'));
127 | _export(require('./portmap'));
128 |
--------------------------------------------------------------------------------
/lib/nfs/mkdir.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 | var path = require('path');
9 |
10 | var common = require('./common');
11 |
12 |
13 |
14 | ///-- API
15 |
16 | function mkdir_lookup_dir(call, reply, next) {
17 | var log = call.log;
18 |
19 | log.debug('mkdir_lookup_dir(%s): entered', call.where.dir);
20 | call.fs.fhandle(call.where.dir, function (err, name) {
21 | if (err) {
22 | log.warn(err, 'mkdir_lookup_dir(%s): fhandle notfound',
23 | call.where.dir);
24 | reply.error(nfs.NFS3ERR_STALE);
25 | next(false);
26 | } else {
27 | call._dirname = name;
28 | call._filename = path.join(name, call.where.name);
29 | log.debug('mkdir_lookup_dir(%s): done -> %s', call.where.dir, name);
30 | next();
31 | }
32 | });
33 | }
34 |
35 |
36 | function mkdir_stat_dir(call, reply, next) {
37 | var log = call.log;
38 |
39 | log.debug('mkdir_stat_dir(%s): entered', call._dirname);
40 | call.fs.stat(call._dirname, function (err, stats) {
41 | if (err) {
42 | log.warn(err, 'mkdir_stat_dir(%s): failed', call._dirname);
43 | reply.error(nfs.NFS3ERR_IO);
44 | next(false);
45 | return;
46 | }
47 | if (!stats.isDirectory()) {
48 | log.warn(err, 'mkdir_stat_dir(%s): not a directory', call._dirname);
49 | reply.error(nfs.NFS3ERR_NOTDIR);
50 | next(false);
51 | return;
52 | }
53 |
54 | log.debug('mkdir_stat_dir(%s): done', call._dirname);
55 | next();
56 | });
57 | }
58 |
59 |
60 | function mkdir(call, reply, next) {
61 | var log = call.log;
62 | var mode;
63 |
64 | if (call.attributes.mode !== null)
65 | mode = call.attributes.mode;
66 | else
67 | mode = 0755;
68 |
69 | log.debug('mkdir(%s, %d): entered', call._filename, mode);
70 | call.fs.mkdir(call._filename, mode, function (err) {
71 | if (err) {
72 | log.warn(err, 'mkdir(%s): failed', call._filename);
73 | reply.error(nfs.NFS3ERR_NOTDIR);
74 | next(false);
75 | return;
76 | }
77 |
78 | log.debug('mkdir(%s): done', call._filename);
79 | next();
80 | });
81 | }
82 |
83 |
84 | function mkdir_lookup(call, reply, next) {
85 | var log = call.log;
86 |
87 | log.debug('mkdir_lookup(%s): entered', call._filename);
88 | call.fs.lookup(call._filename, function (err, fhandle) {
89 | if (err) {
90 | log.warn(err, 'mkdir_lookup(%s): failed', call._filename);
91 | reply.error(nfs.NFS3ERR_NOENT);
92 | next(false);
93 | return;
94 | }
95 |
96 | log.debug('mkdir_lookup(%s): done', fhandle);
97 | reply.obj = fhandle;
98 | next();
99 | });
100 | }
101 |
102 |
103 | function mkdir_stat_newdir(call, reply, next) {
104 | var log = call.log;
105 |
106 | log.debug('mkdir_stat_newdir(%s): entered', call._filename);
107 | call.fs.stat(call._filename, function (err, stats) {
108 | if (err) {
109 | log.warn(err, 'mkdir_stat_newdir(%s): failed', call._filename);
110 | reply.error(nfs.NFS3ERR_NOENT);
111 | next(false);
112 | return;
113 | }
114 |
115 | reply.setObjAttributes(stats);
116 | log.debug({stats: stats}, 'mkdir_stat_newdir(%s): done',
117 | call._filename);
118 | reply.send();
119 | next();
120 | });
121 | }
122 |
123 |
124 |
125 | ///--- Exports
126 |
127 | module.exports = function chain() {
128 | return ([
129 | mkdir_lookup_dir,
130 | mkdir_stat_dir,
131 | mkdir,
132 | mkdir_lookup,
133 | mkdir_stat_newdir
134 | ]);
135 | };
136 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.node.defs:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.node.defs: Makefile for building and bundling your own Node.js.
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 |
13 | #
14 | # This Makefile facilitates building and bundling your own copy of Node.js in
15 | # your repo. All it does is define variables for node, node-waf, and npm for
16 | # you to use elsewhere in your Makefile and rules to build these tools when
17 | # needed.
18 | #
19 | # To use this facility, include "Makefile.node.defs", use the variables as
20 | # described below to define targets, and then include "Makefile.node.targ".
21 | #
22 | # There are two use cases addressed here:
23 | #
24 | # (1) Invoking node, node-waf, or npm as part of the build process, as in "npm
25 | # install" and "node-waf configure build". To facilitate this, this
26 | # Makefile defines Make variables NODE, NODE_WAF, and NPM that you can use
27 | # to invoke these commands during the build process. You MUST NOT assume
28 | # that these variables just evaluate to the filenames themselves, as they
29 | # may have environment variable definitions and other things that prevent
30 | # you from using them directly as a filename. If you want that, see (2).
31 | #
32 | # Wherever you use one of these variables, you MUST include a dependency on
33 | # the corresponding *_EXEC variable as well, like so:
34 | #
35 | # node_modules/restify: deps/restify $(NPM_EXEC)
36 | # $(NPM) install deps/restify
37 | #
38 | # or better, use an order-only dependency to avoid spurious rebuilds:
39 | #
40 | # node_modules/restify: deps/restify | $(NPM_EXEC)
41 | # $(NPM) install deps/restify
42 | #
43 | # Otherwise, the underlying file will not get built. We don't
44 | # automatically build them as part of "all" because that approach is
45 | # brittle.
46 | #
47 | # (2) Specifying paths for invoking node, node-waf, or npm at RUNTIME, as in
48 | # specifying the path to node used for the start method of your service's
49 | # SMF manifest. For this, this Makefile defines variables NODE_EXEC,
50 | # NODE_WAF_EXEC, and NPM_EXEC, which represent the relative paths of these
51 | # files from the root of the workspace. You MUST NOT use these variables
52 | # to invoke these commands during the build process. See (1) instead.
53 | #
54 | # However, in order to work at runtime, you must build the tool as well.
55 | # That is, if you use NODE_EXEC to specify the path to node, you must
56 | # depend on NODE_EXEC somewhere. This usually happens anyway because you
57 | # usually need them during the build process too, but if you don't then
58 | # you need to explicitly add NODE_EXEC (or whichever) to your "all"
59 | # target.
60 | #
61 | # When including this Makefile, you MAY also specify:
62 | #
63 | # BUILD top-level directory for built binaries
64 | # (default: "build")
65 | #
66 | # NODE_INSTALL where node should install its built items
67 | # (default: "$BUILD/node")
68 | #
69 | # NODE_CONFIG_FLAGS extra flags to pass to Node's "configure"
70 | # (default: "--with-dtrace" on SmartOS; empty
71 | # otherwise.)
72 | #
73 |
74 | TOP ?= $(error You must include Makefile.defs before this makefile)
75 |
76 | BUILD ?= build
77 | NODE_INSTALL ?= $(BUILD)/node
78 | DISTCLEAN_FILES += $(NODE_INSTALL)
79 |
80 | NODE_CONFIG_FLAGS += --prefix=$(TOP)/$(NODE_INSTALL)
81 |
82 | ifeq ($(shell uname -s),SunOS)
83 | NODE_CONFIG_FLAGS += --with-dtrace \
84 | --openssl-libpath=/opt/local/lib \
85 | --openssl-includes=/opt/local/include
86 | endif
87 |
88 | NODE_EXEC = $(NODE_INSTALL)/bin/node
89 | NODE_WAF_EXEC = $(NODE_INSTALL)/bin/node-waf
90 | NPM_EXEC = $(NODE_INSTALL)/bin/npm
91 |
92 | # Ensure these use absolute paths to the executables to allow running
93 | # from a dir other than the project top.
94 | NODE := $(TOP)/$(NODE_EXEC)
95 | NODE_WAF := $(TOP)/$(NODE_WAF_EXEC)
96 | NPM := PATH=$(TOP)/$(NODE_INSTALL)/bin:$(PATH) node $(TOP)/$(NPM_EXEC)
97 |
--------------------------------------------------------------------------------
/lib/nfs/index.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var path = require('path');
8 |
9 | var assert = require('assert-plus');
10 | var nfs = require('nfs');
11 |
12 | var auth = require('../auth');
13 |
14 | var access = require('./access');
15 | var create = require('./create');
16 | var commit = require('./commit');
17 | var fsinfo = require('./fsinfo');
18 | var fsstat = require('./fsstat');
19 | var getattr = require('./getattr');
20 | var link = require('./link');
21 | var lookup = require('./lookup');
22 | var mkdir = require('./mkdir');
23 | var mknod = require('./mknod');
24 | var pathconf = require('./pathconf');
25 | var read = require('./read');
26 | var readdir = require('./readdir');
27 | var readdirplus = require('./readdirplus');
28 | var readlink = require('./readlink');
29 | var remove = require('./remove');
30 | var rename = require('./rename');
31 | var rmdir = require('./rmdir');
32 | var setattr = require('./setattr');
33 | var symlink = require('./symlink');
34 | var write = require('./write');
35 |
36 |
37 |
38 | ///--- API
39 |
40 | function createNfsServer(opts) {
41 | assert.object(opts, 'options');
42 | assert.object(opts.fd_cache, 'options.fd_cache');
43 | assert.object(opts.fs, 'options.fs');
44 | assert.object(opts.log, 'options.log');
45 | assert.object(opts.manta, 'options.manta');
46 | assert.string(opts.cachepath, 'options.cachepath');
47 | assert.optionalObject(opts.hosts_allow, 'options.hosts_allow');
48 | assert.optionalObject(opts.hosts_deny, 'options.hosts_deny');
49 |
50 | // We have to check that each incoming NFS request is from an acceptable
51 | // host since each request is independent and there nothing that ties
52 | // the check we did in mountd to a request.
53 | function host_allowed(req, res) {
54 | assert.object(req.connection, 'req.connection');
55 |
56 | var ipaddr = req.connection.remoteAddress;
57 |
58 | // hosts_deny entries are optional
59 | // if the address is present, disallow the mount
60 | if (req.hosts_deny && req.hosts_deny[ipaddr]) {
61 | req.log.warn('nfsd request from (%s) denied', ipaddr);
62 | res.error(nfs.MNT3ERR_ACCES);
63 | return (false);
64 | }
65 |
66 | // hosts_allow entries are optional
67 | // if hosts_allow exists, then the address must be preset or we disallow
68 | // the mount
69 | if (req.hosts_allow && !req.hosts_allow[ipaddr]) {
70 | req.log.warn('nfsd request from (%s) was not allowed', ipaddr);
71 | res.error(nfs.MNT3ERR_ACCES);
72 | return (false);
73 | }
74 |
75 | return (true);
76 | }
77 |
78 | var s = nfs.createNfsServer({
79 | log: opts.log
80 | });
81 |
82 | s.use(auth.authorize);
83 | s.use(function setup(req, res, next) {
84 | req.hosts_allow = opts.hosts_allow;
85 | req.hosts_deny = opts.hosts_deny;
86 | if (!host_allowed(req, res)) {
87 | next(false);
88 | return;
89 | }
90 |
91 | req.fd_cache = opts.fd_cache;
92 | req.manta = opts.manta;
93 | req.fs = opts.fs;
94 | req.cachepath = opts.cachepath; // needed for fsstat
95 | next();
96 | });
97 |
98 | s.access(access());
99 | s.create(create());
100 | s.commit(commit());
101 | s.fsinfo(fsinfo());
102 | s.fsstat(fsstat());
103 | s.getattr(getattr());
104 | s.link(link());
105 | s.lookup(lookup());
106 | s.mkdir(mkdir());
107 | s.mknod(mknod());
108 | s.pathconf(pathconf());
109 | s.read(read());
110 | s.readdir(readdir());
111 | s.readdirplus(readdirplus());
112 | s.readlink(readlink());
113 | s.remove(remove());
114 | s.rename(rename());
115 | s.rmdir(rmdir());
116 | s.setattr(setattr());
117 | s.symlink(symlink());
118 | s.write(write());
119 |
120 | s.on('after', function (name, call, reply, err) {
121 | opts.log.debug({
122 | procedure: name,
123 | rpc_call: call,
124 | rpc_reply: reply,
125 | err: err
126 | }, 'nfsd: %s handled', name);
127 | });
128 |
129 | return (s);
130 | }
131 |
132 |
133 |
134 | ///--- Exports
135 |
136 | module.exports = {
137 | createNfsServer: createNfsServer
138 | };
139 |
--------------------------------------------------------------------------------
/lib/nfs/create.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var nfs = require('nfs');
8 | var path = require('path');
9 |
10 | var common = require('./common');
11 |
12 | var fs = require('fs');
13 |
14 |
15 | ///-- API
16 |
17 | function create_lookup_dir(call, reply, next) {
18 | var log = call.log;
19 |
20 | log.debug('create_lookup_dir(%s): entered', call.where.dir);
21 | call.fs.fhandle(call.where.dir, function (err, name) {
22 | if (err) {
23 | log.warn(err, 'create_lookup_dir(%s): fhandle notfound',
24 | call.where.dir);
25 | reply.error(nfs.NFS3ERR_STALE);
26 | next(false);
27 | } else {
28 | call._dirname = name;
29 | call._filename = path.join(name, call.where.name);
30 | log.debug('create_lookup_dir(%s): done -> %s', call.where.dir,
31 | name);
32 | next();
33 | }
34 | });
35 | }
36 |
37 |
38 | function do_create(flags, call, reply, next) {
39 | // ignore the passed in mode (call.obj_attributes.mode) since manta does
40 | // not support modes
41 | var mode = 0644;
42 |
43 | // We don't use the fd cache here since that only works with existing files
44 | // and always opens with the 'r+' flag. We need to create the file here
45 | // with either the 'w' or 'wx' flags.
46 | call.fs.open(call._filename, flags, mode, function (open_err, fd) {
47 | if (open_err) {
48 | call.log.warn(open_err, 'create: open failed');
49 | reply.error(nfs.NFS3ERR_SERVERFAULT);
50 | next(false);
51 | return;
52 | }
53 |
54 | call.fs.close(fd, function (close_err) {
55 | // we're ignoring errors on close
56 | next();
57 | });
58 | });
59 | }
60 |
61 |
62 | function create(call, reply, next) {
63 | var log = call.log;
64 |
65 | log.debug('create(%s, %d): entered', call.object, call.how);
66 |
67 | if (call.how === nfs.create_how.EXCLUSIVE) {
68 | call.fs.stat(call._filename, function (err, stats) {
69 | if (err && err.code === 'ENOENT') {
70 | // This is the "normal" code path (i.e. non-error)
71 | do_create('wx', call, reply, next);
72 | } else {
73 | log.debug('create (exclusive) file exists');
74 | reply.error(nfs.NFS3ERR_EXIST);
75 | next(false);
76 | }
77 | });
78 | } else if (call.how === nfs.create_how.UNCHECKED) {
79 | do_create('w', call, reply, next);
80 | } else { // call.how === nfs.create_how.GUARDED
81 | call.fs.stat(call._filename, function (err, stats) {
82 | if (err && err.code === 'ENOENT') {
83 | // This is the "normal" code path (i.e. non-error)
84 | do_create('w', call, reply, next);
85 | } else {
86 | log.debug('create (guarded) file exists');
87 | reply.error(nfs.NFS3ERR_EXIST);
88 | next(false);
89 | }
90 | });
91 | }
92 | }
93 |
94 |
95 | function create_lookup(call, reply, next) {
96 | var log = call.log;
97 |
98 | log.debug('create_lookup(%s): entered', call._filename);
99 | call.fs.lookup(call._filename, function (err, fhandle) {
100 | if (err) {
101 | log.warn(err, 'create_lookup(%s): failed', call._filename);
102 | reply.error(nfs.NFS3ERR_NOENT);
103 | next(false);
104 | return;
105 | }
106 |
107 | log.debug('create_lookup(%s): done', fhandle);
108 | reply.obj = fhandle;
109 |
110 | next();
111 | });
112 | }
113 |
114 |
115 | function create_stat(call, reply, next) {
116 | var log = call.log;
117 |
118 | log.debug('create_stat(%s): entered', call._filename);
119 | call.fs.stat(call._filename, function (err, stats) {
120 | if (err) {
121 | log.warn(err, 'create_stat(%s): failed', call._filename);
122 | reply.error(nfs.NFS3ERR_NOENT);
123 | next(false);
124 | return;
125 | }
126 |
127 | reply.setObjAttributes(stats);
128 | log.debug({stats: stats}, 'create_stat(%s): done', call._filename);
129 | reply.send();
130 | next();
131 | });
132 | }
133 |
134 |
135 | ///--- Exports
136 |
137 | module.exports = function chain() {
138 | return ([
139 | create_lookup_dir,
140 | create,
141 | create_lookup,
142 | create_stat
143 | ]);
144 | };
145 |
--------------------------------------------------------------------------------
/lib/nfs/readdirplus.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var path = require('path');
8 |
9 | var nfs = require('nfs');
10 | var vasync = require('vasync');
11 |
12 | var common = require('./common');
13 |
14 | var rpc = require('oncrpc');
15 | var XDR = rpc.XDR;
16 |
17 | ///--- Helpers
18 |
19 | function rand() {
20 | return (Math.floor((Math.random() * Math.pow(2, 31)) + 1));
21 | }
22 |
23 |
24 |
25 | ///-- API
26 |
27 | function readdirplus(call, reply, next) {
28 | var log = call.log;
29 | log.debug('readdirplus(%s): entered', call._filename);
30 |
31 | var error = null;
32 | var cook = 1;
33 |
34 | // Track the returned data size
35 | // status (4) + bool_dir_attrs (4) + fattr3.XDR_SIZE +
36 | // cookieverf3 (8) + bool_eof (4) + final_list_false (4)
37 | // See nfs readdirplus_reply.js.
38 | var totsz = 116;
39 |
40 | // total dir entries size, not including attributes and file handle portion
41 | var sz = 0;
42 |
43 | function process_entry(fname, nextent) {
44 | // The call cookie will be 0 on the initial call
45 | if (call.cookie != 0 && call.cookie >= cook) {
46 | // we need to scan the dir until we reach the right entry
47 | cook++;
48 | nextent();
49 | return;
50 | }
51 |
52 | if (reply.eof === false || error) {
53 | // We hit our return limit on a previous entry, skip the rest
54 | nextent();
55 | return;
56 | }
57 |
58 | // We need to track the basic returned data size to be sure we fit in
59 | // call.dircount bytes.
60 | // list_true (4) + fileid (8) + cookie (8) + name_len
61 | var delta = 20 + XDR.byteLength(fname);
62 | if ((sz + delta) > call.dircount) {
63 | reply.eof = false;
64 | nextent();
65 | return;
66 | }
67 | sz += delta;
68 |
69 | // We also need to track the total returned data size to be sure we
70 | // fit in call.maxcount bytes.
71 | // list_true (4) + fileid (8) + cookie (8) + name_len +
72 | // bool_name_attr (4) + name_attr_len +
73 | // bool_name_handle (4) + name_handle_len
74 | delta = 28 + XDR.byteLength(fname) + 84 + 64;
75 | if ((totsz + delta) > call.maxcount) {
76 | reply.eof = false;
77 | nextent();
78 | return;
79 | }
80 | totsz += delta;
81 |
82 | var p = path.join(call._filename, fname);
83 | call.fs.stat(p, function (err2, stats) {
84 | if (err2) {
85 | log.warn(err2, 'readdirplus(%s): stat failed', p);
86 | error = error || nfs.NFS3ERR_IO;
87 | nextent();
88 | } else {
89 | call.fs.lookup(p, function (err3, fhandle) {
90 | if (err3) {
91 | log.warn(err3, 'readdirplus(%s): lu failed', p);
92 | error = error || nfs.NFS3ERR_IO;
93 | } else {
94 | reply.addEntry({
95 | fileid: common.hash(p),
96 | name: fname,
97 | cookie: cook++,
98 | name_attributes: nfs.create_fattr3(stats),
99 | name_handle: fhandle
100 | });
101 | }
102 | nextent();
103 | });
104 | }
105 | });
106 | }
107 |
108 | function all_done() {
109 | if (error) {
110 | reply.error(error);
111 | next(false);
112 | } else {
113 | call.fs.stat(call._filename, function (err, stats) {
114 | if (err) {
115 | log.warn(err, 'readdirplus(%s): dir stat failed',
116 | call._filename);
117 | } else {
118 | reply.setDirAttributes(stats);
119 | }
120 | log.debug('readdirplus(%s): done', call._filename);
121 | reply.send();
122 | next();
123 | });
124 | }
125 | }
126 |
127 | call.fs.readdir(call._filename, function (err1, files) {
128 | if (err1) {
129 | log.warn(err1, 'readdirplus(%s): rd failed', call._filename);
130 | error = (err1.code === 'ENOTDIR' ?
131 | nfs.NFS3ERR_NOTDIR :
132 | nfs.NFS3ERR_IO);
133 | reply.error(error);
134 | next(false);
135 | return;
136 | }
137 |
138 | // The cookieverf will be 0 on the initial call.
139 | var h = common.hash(call._filename);
140 | if (call.cookieverf.readUInt32LE(0) != 0) {
141 | // This is a follow-up call, confirm cookie.
142 | if (call.cookieverf.readUInt32LE(0) != h) {
143 | reply.error(nfs.NFS3ERR_BAD_COOKIE);
144 | next(false);
145 | return;
146 | }
147 | }
148 |
149 | reply.eof = true;
150 |
151 | reply.cookieverf = new Buffer(8);
152 | reply.cookieverf.fill(0);
153 | reply.cookieverf.writeUInt32LE(h, 0, true);
154 |
155 | vasync.forEachPipeline({
156 | 'func': process_entry,
157 | 'inputs': files
158 | }, all_done);
159 | });
160 | }
161 |
162 |
163 |
164 | ///--- Exports
165 |
166 | module.exports = function chain() {
167 | return ([
168 | common.fhandle_to_filename,
169 | readdirplus
170 | ]);
171 | };
172 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.node_prebuilt.defs:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.node_prebuilt.defs: Makefile for including a prebuilt Node.js build.
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 |
13 | #
14 | # This Makefile facilitates downloading and bundling a prebuilt node.js
15 | # build (using the 'sdcnode' distro builds). This is an alternative to
16 | # the "Makefile.node.*" makefiles for *building* a node from source.
17 | #
18 | # Usage:
19 | #
20 | # - Define `NODE_PREBUILT_VERSION` in your Makefile to choose a node version.
21 | # E.g.: `NODE_PREBUILT_VERSION=v0.6.19`. See other optional variables
22 | # below.
23 | # - `include tools/mk/Makefile.node_prebuilt.defs` after this in your Makefile.
24 | # - `include tools/mk/Makefile.node_prebuilt.targ` near the end of your
25 | # Makefile.
26 | # - Have at least one of your Makefile targets depend on either `$(NODE_EXEC)`
27 | # or `$(NPM_EXEC)`. E.g.:
28 | #
29 | # node_modules/restify: deps/restify $(NPM_EXEC)
30 | # $(NPM) install deps/restify
31 | #
32 | # or better, use an order-only dependency to avoid spurious rebuilds:
33 | #
34 | # node_modules/restify: deps/restify | $(NPM_EXEC)
35 | # $(NPM) install deps/restify
36 | #
37 | # - Use `$(NPM)` or `$(NODE)` to use your node build.
38 | # - Include the "$(NODE_INSTALL)" tree in your release package.
39 | #
40 | #
41 | # When including this Makefile, you MUST also specify:
42 | #
43 | # NODE_PREBUILT_VERSION The node version in the prebuilt 'sdcnode'
44 | # package to use. Typically this is one of the
45 | # node version tags, e.g. "v0.6.18" but it
46 | # can be any commitish.
47 | #
48 | # When including this Makefile, you MAY also specify:
49 | #
50 | # NODE_PREBUILT_DIR The dir in which to find sdcnode builds. This
51 | # can either be a *local directory* or *a
52 | # URL* dir (with trailing '/') which serves
53 | # Apache/Nginx dir listing HTML.
54 | # (default: sdcnode master build dir on stuff)
55 | #
56 | # NODE_PREBUILT_TAG The 'sdcnode' project supports special
57 | # configuration builds of node, e.g. say a
58 | # build configured `--without-ssl`. These
59 | # special configurations are given a tag, e.g.
60 | # 'gz', that is used in the filename. Optionally
61 | # specify a tag name here.
62 | # (default: empty)
63 | #
64 | # NODE_PREBUILT_BRANCH Specify a particular branch of 'sdcnode' builds
65 | # from which to pull. Generally one should stick
66 | # with the default.
67 | # (default: master)
68 | #
69 | # NODE_PREBUILT_IMAGE If you have a zone image that differs from that
70 | # for an sdcnode build that you want to use (potential compat
71 | # issues be damned), then set this to the UUID of the sdcnode
72 | # build you want. See here for available build image uuids:
73 | #
74 | #
75 | # BUILD top-level directory for built binaries
76 | # (default: "build")
77 | #
78 | # NODE_INSTALL where node should install its built items
79 | # (default: "$BUILD/node")
80 | #
81 | #
82 | # Dev Notes:
83 | #
84 | # This works by getting "NODE_PREBUILT_NAME" from the provided "NODE_PREBUILT_*"
85 | # vars and the image version (via 'mdata-get sdc:image_uuid'). The image uuid is
86 | # included to ensure an exact match with the build machine. This name (e.g.
87 | # "v0.6.18-zone-$uuid") is used to find a matching "sdcnode-$name-*.tgz" build
88 | # in "NODE_PREBUILT_DIR" (either a local directory or a URL). That tarball is
89 | # downloaded and extracted into "NODE_INSTALL".
90 | #
91 | # The "*_EXEC" vars are set to named symlinks, e.g.
92 | # "build/prebuilt-node-v0.6.18-$uuid", so that a change of selected node
93 | # build (say the developer changes NODE_PREBUILT_VERSION) will recreate the
94 | # node install.
95 | #
96 | # See for details on 'sdcnode-*'
97 | # package naming.
98 | #
99 |
100 | TOP ?= $(error You must include Makefile.defs before this makefile)
101 | NODE_PREBUILT_VERSION ?= $(error NODE_PREBUILT_VERSION is not set.)
102 |
103 |
104 | BUILD ?= build
105 | NODE_INSTALL ?= $(BUILD)/node
106 | DISTCLEAN_FILES += $(NODE_INSTALL) \
107 | $(BUILD)/prebuilt-node-* $(BUILD)/prebuilt-npm-*
108 |
109 | NODE_PREBUILT_BRANCH ?= master
110 | NODE_PREBUILT_IMAGE ?= $(shell pfexec mdata-get sdc:image_uuid)
111 | ifeq ($(NODE_PREBUILT_TAG),)
112 | NODE_PREBUILT_NAME := $(NODE_PREBUILT_VERSION)-$(NODE_PREBUILT_IMAGE)
113 | else
114 | NODE_PREBUILT_NAME := $(NODE_PREBUILT_VERSION)-$(NODE_PREBUILT_TAG)-$(NODE_PREBUILT_IMAGE)
115 | endif
116 | NODE_PREBUILT_PATTERN := sdcnode-$(NODE_PREBUILT_NAME)-$(NODE_PREBUILT_BRANCH)-.*\.tgz
117 | NODE_PREBUILT_DIR ?= https://download.joyent.com/pub/build/sdcnode/$(NODE_PREBUILT_IMAGE)/$(NODE_PREBUILT_BRANCH)-latest/sdcnode/
118 | ifeq ($(shell echo $(NODE_PREBUILT_DIR) | cut -c 1-4),http)
119 | NODE_PREBUILT_BASE := $(shell curl -ksS --fail --connect-timeout 5 $(NODE_PREBUILT_DIR) | grep 'href=' | cut -d'"' -f2 | grep "^$(NODE_PREBUILT_PATTERN)$$" | sort | tail -1)
120 | ifneq ($(NODE_PREBUILT_BASE),)
121 | NODE_PREBUILT_TARBALL := $(NODE_PREBUILT_DIR)$(NODE_PREBUILT_BASE)
122 | endif
123 | else
124 | NODE_PREBUILT_BASE := $(shell ls -1 $(NODE_PREBUILT_DIR)/ | grep "^$(NODE_PREBUILT_PATTERN)$$" 2>/dev/null | sort | tail -1)
125 | ifneq ($(NODE_PREBUILT_BASE),)
126 | NODE_PREBUILT_TARBALL := $(NODE_PREBUILT_DIR)/$(NODE_PREBUILT_BASE)
127 | endif
128 | endif
129 | ifeq ($(NODE_PREBUILT_TARBALL),)
130 | NODE_PREBUILT_TARBALL = $(error NODE_PREBUILT_TARBALL is empty: no '$(NODE_PREBUILT_DIR)/$(NODE_PREBUILT_PATTERN)' found)
131 | endif
132 |
133 |
134 | # Prebuild-specific paths for the "*_EXEC" vars to ensure that
135 | # a prebuild change (e.g. if master Makefile's NODE_PREBUILT_VERSION
136 | # choice changes) causes a install of the new node.
137 | NODE_EXEC := $(BUILD)/prebuilt-node-$(NODE_PREBUILT_NAME)
138 | NODE_WAF_EXEC := $(BUILD)/prebuilt-node-waf-$(NODE_PREBUILT_NAME)
139 | NPM_EXEC := $(BUILD)/prebuilt-npm-$(NODE_PREBUILT_NAME)
140 |
141 | # Ensure these use absolute paths to the executables to allow running
142 | # from a dir other than the project top.
143 | NODE := $(TOP)/$(NODE_INSTALL)/bin/node
144 | NODE_WAF := $(TOP)/$(NODE_INSTALL)/bin/node-waf
145 | NPM := PATH=$(TOP)/$(NODE_INSTALL)/bin:$(PATH) node $(TOP)/$(NODE_INSTALL)/bin/npm
146 |
--------------------------------------------------------------------------------
/lib/mount.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var fs = require('fs');
8 | var path = require('path');
9 | var util = require('util');
10 |
11 | var assert = require('assert-plus');
12 | var clone = require('clone');
13 | var nfs = require('nfs');
14 | var once = require('once');
15 | var statvfs = require('statvfs');
16 |
17 | var auth = require('./auth');
18 | var common = require('./nfs/common');
19 |
20 |
21 |
22 | ///--- Globals
23 |
24 | var sprintf = util.format;
25 |
26 | var MNTPATHLEN = 1024; // This is defined by the RFC
27 |
28 |
29 |
30 | ///--- API
31 |
32 | function ensure_allowed(req, res, next) {
33 | assert.object(req.connection, 'req.connection');
34 |
35 | var ipaddr = req.connection.remoteAddress;
36 |
37 | // hosts_deny entries are optional
38 | // if the address is present, disallow the mount
39 | if (req.hosts_deny && req.hosts_deny[ipaddr]) {
40 | req.log.warn('mountd request from (%s) denied', ipaddr);
41 | res.error(nfs.MNT3ERR_ACCES);
42 | next(false);
43 | return;
44 | }
45 |
46 | // hosts_allow entries are optional
47 | // if hosts_allow exists, then the address must be preset or we disallow
48 | // the mount
49 | if (req.hosts_allow && !req.hosts_allow[ipaddr]) {
50 | req.log.warn('mountd request from (%s) was not allowed', ipaddr);
51 | res.error(nfs.MNT3ERR_ACCES);
52 | next(false);
53 | return;
54 | }
55 |
56 | next();
57 | }
58 |
59 |
60 | function ensure_exports(req, res, next) {
61 | assert.string(req.dirpath, 'req.dirpath');
62 |
63 | var p = path.normalize(req.dirpath);
64 |
65 | if (p.length > MNTPATHLEN) {
66 | res.error(nfs.MNT3ERR_NAMETOOLONG);
67 | next(false);
68 | return;
69 | }
70 |
71 | // export entries are optional
72 | if (req.exports) {
73 | // since we have exports, we must check each one since the client may
74 | // be trying to mount a subdir of an export
75 | var found = false;
76 | for (var i in req.exports) {
77 | if (p.indexOf(i) === 0) {
78 | found = true;
79 | break;
80 | }
81 | }
82 |
83 | if (!found) {
84 | req.log.warn('mountd (%s) is not exported', p);
85 | res.error(nfs.MNT3ERR_ACCES);
86 | next(false);
87 | return;
88 | }
89 | }
90 |
91 | req._dirpath = p;
92 | next();
93 | }
94 |
95 |
96 | function ensure_manta_dir(req, res, next) {
97 | var p = req._dirpath;
98 |
99 | req.log.debug('ensure_manta_directory(%s): entered', p);
100 | req.manta.info(p, function (err, info) {
101 | if (err) {
102 | req.log.warn(err, 'ensure_manta_directory: info(%s) failed', p);
103 | res.error(nfs.MNT3ERR_SERVERFAULT);
104 | next(false);
105 | return;
106 | }
107 |
108 | if (info.extension !== 'directory') {
109 | req.log.warn({
110 | path: p,
111 | info: info
112 | }, 'mount: manta location is not a directory');
113 | res.error(nfs.MNT3ERR_NOTDIR);
114 | next(false);
115 | return;
116 | }
117 |
118 | req.log.debug({
119 | info: info
120 | }, 'ensure_manta_directory(%s): done', p);
121 |
122 | req.info = info;
123 | next();
124 | });
125 | }
126 |
127 |
128 | function mount(call, reply, next) {
129 | var log = call.log;
130 |
131 | log.debug('mount(%s): entered', call._dirpath);
132 | call.fs.stat(call._dirpath, function (serr, dummystats) {
133 | if (serr) {
134 | log.warn(serr, 'mount(%s): failed to stat', call._dirpath);
135 | reply.error(nfs.MNT3ERR_SERVERFAULT);
136 | next(false);
137 | return;
138 | }
139 |
140 | call.fs.lookup(call._dirpath, function (lerr, fhandle) {
141 | if (lerr) {
142 | log.warn(lerr, 'mount(%s): failed to lookup', call._dirpath);
143 | reply.error(nfs.MNT3ERR_SERVERFAULT);
144 | next(false);
145 | return;
146 | }
147 |
148 | var ipaddr = call.connection.remoteAddress;
149 |
150 | reply.setFileHandle(fhandle);
151 | log.info('mount(%s) from (%s): done -> %s', call._dirpath, ipaddr,
152 | fhandle);
153 | reply.send();
154 | next();
155 |
156 | // We assume the client is going to immediately do an ls, so just
157 | // cache the root directory
158 | call.fs.readdir(call._dirpath, function () {});
159 | });
160 | });
161 | }
162 |
163 |
164 | function umount(call, reply, next) {
165 | var log = call.log;
166 |
167 | // We don't invoke call.fs.shutdown here since the server is still running
168 | // and they may want to mount again later.
169 |
170 | var ipaddr = call.connection.remoteAddress;
171 | log.info('umount(%s) from (%s) done', call._dirpath, ipaddr);
172 | reply.send();
173 | next();
174 | }
175 |
176 |
177 | function createMountServer(opts) {
178 | assert.object(opts, 'options');
179 | assert.optionalObject(opts.exports, 'options.exports');
180 | assert.optionalObject(opts.hosts_allow, 'options.hosts_allow');
181 | assert.optionalObject(opts.hosts_deny, 'options.hosts_deny');
182 | assert.object(opts.log, 'options.log');
183 | assert.object(opts.manta, 'options.manta');
184 | assert.object(opts.fs, 'options.fs');
185 |
186 | var s = nfs.createMountServer({
187 | log: opts.log
188 | });
189 |
190 | s.use(auth.authorize);
191 | s.use(function setup(req, res, next) {
192 | req.exports = opts.exports;
193 | req.hosts_allow = opts.hosts_allow;
194 | req.hosts_deny = opts.hosts_deny;
195 | req.manta = opts.manta;
196 | req.fs = opts.fs;
197 | next();
198 | });
199 | s.mnt(ensure_allowed,
200 | ensure_exports,
201 | ensure_manta_dir,
202 | mount);
203 |
204 | s.umnt(ensure_allowed,
205 | ensure_exports,
206 | umount);
207 |
208 | s.on('after', function (name, call, reply, err) {
209 | opts.log.debug({
210 | procedure: name,
211 | rpc_call: call,
212 | rpc_reply: reply,
213 | err: err
214 | }, 'mountd: %s handled', name);
215 | });
216 |
217 | return (s);
218 | }
219 |
220 |
221 |
222 | ///--- Exports
223 |
224 | module.exports = {
225 | createMountServer: createMountServer
226 | };
227 |
--------------------------------------------------------------------------------
/tools/jsl.web.conf:
--------------------------------------------------------------------------------
1 | #
2 | # Configuration File for JavaScript Lint
3 | # Developed by Matthias Miller (http://www.JavaScriptLint.com)
4 | #
5 | # This configuration file can be used to lint a collection of scripts, or to enable
6 | # or disable warnings for scripts that are linted via the command line.
7 | #
8 |
9 | ### Warnings
10 | # Enable or disable warnings based on requirements.
11 | # Use "+WarningName" to display or "-WarningName" to suppress.
12 | #
13 | +ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent
14 | +ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
15 | +ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
16 | +anon_no_return_value # anonymous function does not always return value
17 | +assign_to_function_call # assignment to a function call
18 | -block_without_braces # block statement without curly braces
19 | +comma_separated_stmts # multiple statements separated by commas (use semicolons?)
20 | +comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
21 | +default_not_at_end # the default case is not at the end of the switch statement
22 | +dup_option_explicit # duplicate "option explicit" control comment
23 | +duplicate_case_in_switch # duplicate case in switch statement
24 | +duplicate_formal # duplicate formal argument {name}
25 | +empty_statement # empty statement or extra semicolon
26 | +identifier_hides_another # identifer {name} hides an identifier in a parent scope
27 | +inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
28 | +incorrect_version # Expected /*jsl:content-type*/ control comment. The script was parsed with the wrong version.
29 | +invalid_fallthru # unexpected "fallthru" control comment
30 | +invalid_pass # unexpected "pass" control comment
31 | +jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
32 | +leading_decimal_point # leading decimal point may indicate a number or an object member
33 | +legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
34 | +meaningless_block # meaningless block; curly braces have no impact
35 | +mismatch_ctrl_comments # mismatched control comment; "ignore" and "end" control comments must have a one-to-one correspondence
36 | +misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
37 | +missing_break # missing break statement
38 | +missing_break_for_last_case # missing break statement for last case in switch
39 | +missing_default_case # missing default case in switch statement
40 | +missing_option_explicit # the "option explicit" control comment is missing
41 | +missing_semicolon # missing semicolon
42 | +missing_semicolon_for_lambda # missing semicolon for lambda assignment
43 | +multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
44 | +nested_comment # nested comment
45 | +no_return_value # function {name} does not always return a value
46 | +octal_number # leading zeros make an octal number
47 | +parseint_missing_radix # parseInt missing radix parameter
48 | +partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
49 | +redeclared_var # redeclaration of {name}
50 | +trailing_comma_in_array # extra comma is not recommended in array initializers
51 | +trailing_decimal_point # trailing decimal point may indicate a number or an object member
52 | +undeclared_identifier # undeclared identifier: {name}
53 | +unreachable_code # unreachable code
54 | +unreferenced_argument # argument declared but never referenced: {name}
55 | +unreferenced_function # function is declared but never referenced: {name}
56 | +unreferenced_variable # variable is declared but never referenced: {name}
57 | +unsupported_version # JavaScript {version} is not supported
58 | +use_of_label # use of label
59 | +useless_assign # useless assignment
60 | +useless_comparison # useless comparison; comparing identical expressions
61 | +useless_quotes # the quotation marks are unnecessary
62 | +useless_void # use of the void type may be unnecessary (void is always undefined)
63 | +var_hides_arg # variable {name} hides argument
64 | +want_assign_or_call # expected an assignment or function call
65 | +with_statement # with statement hides undeclared variables; use temporary variable instead
66 |
67 |
68 | ### Output format
69 | # Customize the format of the error message.
70 | # __FILE__ indicates current file path
71 | # __FILENAME__ indicates current file name
72 | # __LINE__ indicates current line
73 | # __COL__ indicates current column
74 | # __ERROR__ indicates error message (__ERROR_PREFIX__: __ERROR_MSG__)
75 | # __ERROR_NAME__ indicates error name (used in configuration file)
76 | # __ERROR_PREFIX__ indicates error prefix
77 | # __ERROR_MSG__ indicates error message
78 | #
79 | # For machine-friendly output, the output format can be prefixed with
80 | # "encode:". If specified, all items will be encoded with C-slashes.
81 | #
82 | # Visual Studio syntax (default):
83 | +output-format __FILE__(__LINE__): __ERROR__
84 | # Alternative syntax:
85 | #+output-format __FILE__:__LINE__: __ERROR__
86 |
87 |
88 | ### Context
89 | # Show the in-line position of the error.
90 | # Use "+context" to display or "-context" to suppress.
91 | #
92 | +context
93 |
94 |
95 | ### Control Comments
96 | # Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
97 | # the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
98 | # enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
99 | # although legacy control comments are enabled by default for backward compatibility.
100 | #
101 | -legacy_control_comments
102 |
103 |
104 | ### Defining identifiers
105 | # By default, "option explicit" is enabled on a per-file basis.
106 | # To enable this for all files, use "+always_use_option_explicit"
107 | +always_use_option_explicit
108 |
109 | # Define certain identifiers of which the lint is not aware.
110 | # (Use this in conjunction with the "undeclared identifier" warning.)
111 | #
112 | # Common uses for webpages might be:
113 | +define JSON
114 | +define Math
115 | +define $
116 | +define XMLHttpRequest
117 | +define alert
118 | +define clearInterval
119 | +define clearTimeout
120 | +define confirm
121 | +define document
122 | +define setInterval
123 | +define setTimeout
124 | +define window
125 |
126 | ### JavaScript Version
127 | # To change the default JavaScript version:
128 | #+default-type text/javascript;version=1.5
129 | #+default-type text/javascript;e4x=1
130 |
131 | ### Files
132 | # Specify which files to lint
133 | # Use "+recurse" to enable recursion (disabled by default).
134 | # To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
135 | # or "+process Folder\Path\*.htm".
136 | #
137 |
138 |
--------------------------------------------------------------------------------
/tools/jsl.node.conf:
--------------------------------------------------------------------------------
1 | #
2 | # Configuration File for JavaScript Lint
3 | #
4 | # This configuration file can be used to lint a collection of scripts, or to enable
5 | # or disable warnings for scripts that are linted via the command line.
6 | #
7 |
8 | ### Warnings
9 | # Enable or disable warnings based on requirements.
10 | # Use "+WarningName" to display or "-WarningName" to suppress.
11 | #
12 | +ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent
13 | +ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
14 | +ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
15 | +anon_no_return_value # anonymous function does not always return value
16 | +assign_to_function_call # assignment to a function call
17 | -block_without_braces # block statement without curly braces
18 | +comma_separated_stmts # multiple statements separated by commas (use semicolons?)
19 | +comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
20 | +default_not_at_end # the default case is not at the end of the switch statement
21 | +dup_option_explicit # duplicate "option explicit" control comment
22 | +duplicate_case_in_switch # duplicate case in switch statement
23 | +duplicate_formal # duplicate formal argument {name}
24 | +empty_statement # empty statement or extra semicolon
25 | +identifier_hides_another # identifer {name} hides an identifier in a parent scope
26 | -inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
27 | +incorrect_version # Expected /*jsl:content-type*/ control comment. The script was parsed with the wrong version.
28 | +invalid_fallthru # unexpected "fallthru" control comment
29 | +invalid_pass # unexpected "pass" control comment
30 | +jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
31 | +leading_decimal_point # leading decimal point may indicate a number or an object member
32 | +legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
33 | +meaningless_block # meaningless block; curly braces have no impact
34 | +mismatch_ctrl_comments # mismatched control comment; "ignore" and "end" control comments must have a one-to-one correspondence
35 | +misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
36 | +missing_break # missing break statement
37 | +missing_break_for_last_case # missing break statement for last case in switch
38 | +missing_default_case # missing default case in switch statement
39 | +missing_option_explicit # the "option explicit" control comment is missing
40 | +missing_semicolon # missing semicolon
41 | +missing_semicolon_for_lambda # missing semicolon for lambda assignment
42 | +multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
43 | +nested_comment # nested comment
44 | +no_return_value # function {name} does not always return a value
45 | -octal_number # leading zeros make an octal number
46 | +parseint_missing_radix # parseInt missing radix parameter
47 | +partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
48 | +redeclared_var # redeclaration of {name}
49 | +trailing_comma_in_array # extra comma is not recommended in array initializers
50 | +trailing_decimal_point # trailing decimal point may indicate a number or an object member
51 | +undeclared_identifier # undeclared identifier: {name}
52 | +unreachable_code # unreachable code
53 | -unreferenced_argument # argument declared but never referenced: {name}
54 | -unreferenced_function # function is declared but never referenced: {name}
55 | +unreferenced_variable # variable is declared but never referenced: {name}
56 | +unsupported_version # JavaScript {version} is not supported
57 | +use_of_label # use of label
58 | +useless_assign # useless assignment
59 | +useless_comparison # useless comparison; comparing identical expressions
60 | -useless_quotes # the quotation marks are unnecessary
61 | +useless_void # use of the void type may be unnecessary (void is always undefined)
62 | +var_hides_arg # variable {name} hides argument
63 | +want_assign_or_call # expected an assignment or function call
64 | +with_statement # with statement hides undeclared variables; use temporary variable instead
65 |
66 |
67 | ### Output format
68 | # Customize the format of the error message.
69 | # __FILE__ indicates current file path
70 | # __FILENAME__ indicates current file name
71 | # __LINE__ indicates current line
72 | # __COL__ indicates current column
73 | # __ERROR__ indicates error message (__ERROR_PREFIX__: __ERROR_MSG__)
74 | # __ERROR_NAME__ indicates error name (used in configuration file)
75 | # __ERROR_PREFIX__ indicates error prefix
76 | # __ERROR_MSG__ indicates error message
77 | #
78 | # For machine-friendly output, the output format can be prefixed with
79 | # "encode:". If specified, all items will be encoded with C-slashes.
80 | #
81 | # Visual Studio syntax (default):
82 | +output-format __FILE__(__LINE__): __ERROR__
83 | # Alternative syntax:
84 | #+output-format __FILE__:__LINE__: __ERROR__
85 |
86 |
87 | ### Context
88 | # Show the in-line position of the error.
89 | # Use "+context" to display or "-context" to suppress.
90 | #
91 | +context
92 |
93 |
94 | ### Control Comments
95 | # Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
96 | # the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
97 | # enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
98 | # although legacy control comments are enabled by default for backward compatibility.
99 | #
100 | -legacy_control_comments
101 |
102 |
103 | ### Defining identifiers
104 | # By default, "option explicit" is enabled on a per-file basis.
105 | # To enable this for all files, use "+always_use_option_explicit"
106 | -always_use_option_explicit
107 |
108 | # Define certain identifiers of which the lint is not aware.
109 | # (Use this in conjunction with the "undeclared identifier" warning.)
110 | #
111 | # Common uses for webpages might be:
112 | +define before
113 | +define after
114 | +define test
115 | +define __dirname
116 | +define __filename
117 | +define clearInterval
118 | +define clearTimeout
119 | +define console
120 | +define exports
121 | +define global
122 | +define module
123 | +define process
124 | +define require
125 | +define setImmediate
126 | +define setInterval
127 | +define setTimeout
128 | +define Buffer
129 | +define JSON
130 | +define Math
131 |
132 | ### JavaScript Version
133 | # To change the default JavaScript version:
134 | #+default-type text/javascript;version=1.5
135 | #+default-type text/javascript;e4x=1
136 |
137 | ### Files
138 | # Specify which files to lint
139 | # Use "+recurse" to enable recursion (disabled by default).
140 | # To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
141 | # or "+process Folder\Path\*.htm".
142 | #
143 |
144 |
--------------------------------------------------------------------------------
/tools/mk/Makefile.targ:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | #
3 | # Copyright (c) 2012, Joyent, Inc. All rights reserved.
4 | #
5 | # Makefile.targ: common targets.
6 | #
7 | # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped
8 | # into other repos as-is without requiring any modifications. If you find
9 | # yourself changing this file, you should instead update the original copy in
10 | # eng.git and then update your repo to use the new version.
11 | #
12 | # This Makefile defines several useful targets and rules. You can use it by
13 | # including it from a Makefile that specifies some of the variables below.
14 | #
15 | # Targets defined in this Makefile:
16 | #
17 | # check Checks JavaScript files for lint and style
18 | # Checks bash scripts for syntax
19 | # Checks SMF manifests for validity against the SMF DTD
20 | #
21 | # clean Removes built files
22 | #
23 | # docs Builds restdown documentation in docs/
24 | #
25 | # prepush Depends on "check" and "test"
26 | #
27 | # test Does nothing (you should override this)
28 | #
29 | # xref Generates cscope (source cross-reference index)
30 | #
31 | # For details on what these targets are supposed to do, see the Joyent
32 | # Engineering Guide.
33 | #
34 | # To make use of these targets, you'll need to set some of these variables. Any
35 | # variables left unset will simply not be used.
36 | #
37 | # BASH_FILES Bash scripts to check for syntax
38 | # (paths relative to top-level Makefile)
39 | #
40 | # CLEAN_FILES Files to remove as part of the "clean" target. Note
41 | # that files generated by targets in this Makefile are
42 | # automatically included in CLEAN_FILES. These include
43 | # restdown-generated HTML and JSON files.
44 | #
45 | # DOC_FILES Restdown (documentation source) files. These are
46 | # assumed to be contained in "docs/", and must NOT
47 | # contain the "docs/" prefix.
48 | #
49 | # JSL_CONF_NODE Specify JavaScriptLint configuration files
50 | # JSL_CONF_WEB (paths relative to top-level Makefile)
51 | #
52 | # Node.js and Web configuration files are separate
53 | # because you'll usually want different global variable
54 | # configurations. If no file is specified, none is given
55 | # to jsl, which causes it to use a default configuration,
56 | # which probably isn't what you want.
57 | #
58 | # JSL_FILES_NODE JavaScript files to check with Node config file.
59 | # JSL_FILES_WEB JavaScript files to check with Web config file.
60 | #
61 | # JSON_FILES JSON files to be validated
62 | #
63 | # JSSTYLE_FILES JavaScript files to be style-checked
64 | #
65 | # You can also override these variables:
66 | #
67 | # BASH Path to bash (default: "bash")
68 | #
69 | # CSCOPE_DIRS Directories to search for source files for the cscope
70 | # index. (default: ".")
71 | #
72 | # JSL Path to JavaScriptLint (default: "jsl")
73 | #
74 | # JSL_FLAGS_NODE Additional flags to pass through to JSL
75 | # JSL_FLAGS_WEB
76 | # JSL_FLAGS
77 | #
78 | # JSON Path to json tool (default: "json")
79 | #
80 | # JSSTYLE Path to jsstyle (default: "jsstyle")
81 | #
82 | # JSSTYLE_FLAGS Additional flags to pass through to jsstyle
83 | #
84 | # RESTDOWN_EXT By default '.restdown' is required for DOC_FILES
85 | # (see above). If you want to use, say, '.md' instead, then
86 | # set 'RESTDOWN_EXT=.md' in your Makefile.
87 | #
88 |
89 | #
90 | # Defaults for the various tools we use.
91 | #
92 | BASH ?= bash
93 | BASHSTYLE ?= tools/bashstyle
94 | CP ?= cp
95 | CSCOPE ?= cscope
96 | CSCOPE_DIRS ?= .
97 | JSL ?= jsl
98 | JSON ?= json
99 | JSSTYLE ?= jsstyle
100 | MKDIR ?= mkdir -p
101 | MV ?= mv
102 | RESTDOWN_FLAGS ?=
103 | RESTDOWN_EXT ?= .restdown
104 | RMTREE ?= rm -rf
105 | JSL_FLAGS ?= --nologo --nosummary
106 |
107 | ifeq ($(shell uname -s),SunOS)
108 | TAR ?= gtar
109 | else
110 | TAR ?= tar
111 | endif
112 |
113 |
114 | #
115 | # Defaults for other fixed values.
116 | #
117 | BUILD = build
118 | DISTCLEAN_FILES += $(BUILD)
119 | DOC_BUILD = $(BUILD)/docs/public
120 |
121 | #
122 | # Configure JSL_FLAGS_{NODE,WEB} based on JSL_CONF_{NODE,WEB}.
123 | #
124 | ifneq ($(origin JSL_CONF_NODE), undefined)
125 | JSL_FLAGS_NODE += --conf=$(JSL_CONF_NODE)
126 | endif
127 |
128 | ifneq ($(origin JSL_CONF_WEB), undefined)
129 | JSL_FLAGS_WEB += --conf=$(JSL_CONF_WEB)
130 | endif
131 |
132 | #
133 | # Targets. For descriptions on what these are supposed to do, see the
134 | # Joyent Engineering Guide.
135 | #
136 |
137 | #
138 | # Instruct make to keep around temporary files. We have rules below that
139 | # automatically update git submodules as needed, but they employ a deps/*/.git
140 | # temporary file. Without this directive, make tries to remove these .git
141 | # directories after the build has completed.
142 | #
143 | .SECONDARY: $($(wildcard deps/*):%=%/.git)
144 |
145 | #
146 | # This rule enables other rules that use files from a git submodule to have
147 | # those files depend on deps/module/.git and have "make" automatically check
148 | # out the submodule as needed.
149 | #
150 | deps/%/.git:
151 | git submodule update --init deps/$*
152 |
153 | #
154 | # These recipes make heavy use of dynamically-created phony targets. The parent
155 | # Makefile defines a list of input files like BASH_FILES. We then say that each
156 | # of these files depends on a fake target called filename.bashchk, and then we
157 | # define a pattern rule for those targets that runs bash in check-syntax-only
158 | # mode. This mechanism has the nice properties that if you specify zero files,
159 | # the rule becomes a noop (unlike a single rule to check all bash files, which
160 | # would invoke bash with zero files), and you can check individual files from
161 | # the command line with "make filename.bashchk".
162 | #
163 | .PHONY: check-bash
164 | check-bash: $(BASH_FILES:%=%.bashchk) $(BASH_FILES:%=%.bashstyle)
165 |
166 | %.bashchk: %
167 | $(BASH) -n $^
168 |
169 | %.bashstyle: %
170 | $(BASHSTYLE) $^
171 |
172 | .PHONY: check-json
173 | check-json: $(JSON_FILES:%=%.jsonchk)
174 |
175 | %.jsonchk: %
176 | $(JSON) --validate -f $^
177 |
178 | #
179 | # The above approach can be slow when there are many files to check because it
180 | # requires that "make" invoke the check tool once for each file, rather than
181 | # passing in several files at once. For the JavaScript check targets, we define
182 | # a variable for the target itself *only if* the list of input files is
183 | # non-empty. This avoids invoking the tool if there are no files to check.
184 | #
185 | JSL_NODE_TARGET = $(if $(JSL_FILES_NODE), check-jsl-node)
186 | .PHONY: check-jsl-node
187 | check-jsl-node: $(JSL_EXEC)
188 | $(JSL) $(JSL_FLAGS) $(JSL_FLAGS_NODE) $(JSL_FILES_NODE)
189 |
190 | JSL_WEB_TARGET = $(if $(JSL_FILES_WEB), check-jsl-web)
191 | .PHONY: check-jsl-web
192 | check-jsl-web: $(JSL_EXEC)
193 | $(JSL) $(JSL_FLAGS) $(JSL_FLAGS_WEB) $(JSL_FILES_WEB)
194 |
195 | .PHONY: check-jsl
196 | check-jsl: $(JSL_NODE_TARGET) $(JSL_WEB_TARGET)
197 |
198 | JSSTYLE_TARGET = $(if $(JSSTYLE_FILES), check-jsstyle)
199 | .PHONY: check-jsstyle
200 | check-jsstyle: $(JSSTYLE_EXEC)
201 | $(JSSTYLE) $(JSSTYLE_FLAGS) $(JSSTYLE_FILES)
202 |
203 | .PHONY: check
204 | check: check-jsl check-json $(JSSTYLE_TARGET) check-bash
205 | @echo check ok
206 |
207 | .PHONY: clean
208 | clean::
209 | -$(RMTREE) $(CLEAN_FILES)
210 |
211 | .PHONY: distclean
212 | distclean:: clean
213 | -$(RMTREE) $(DISTCLEAN_FILES)
214 |
215 | CSCOPE_FILES = cscope.in.out cscope.out cscope.po.out
216 | CLEAN_FILES += $(CSCOPE_FILES)
217 |
218 | .PHONY: xref
219 | xref: cscope.files
220 | $(CSCOPE) -bqR
221 |
222 | .PHONY: cscope.files
223 | cscope.files:
224 | find $(CSCOPE_DIRS) -name '*.c' -o -name '*.h' -o -name '*.cc' \
225 | -o -name '*.js' -o -name '*.s' -o -name '*.cpp' > $@
226 |
227 | #
228 | # The "docs" target is complicated because we do several things here:
229 | #
230 | # (1) Use restdown to build HTML and JSON files from each of DOC_FILES.
231 | #
232 | # (2) Copy these files into $(DOC_BUILD) (build/docs/public), which
233 | # functions as a complete copy of the documentation that could be
234 | # mirrored or served over HTTP.
235 | #
236 | # (3) Then copy any directories and media from docs/media into
237 | # $(DOC_BUILD)/media. This allows projects to include their own media,
238 | # including files that will override same-named files provided by
239 | # restdown.
240 | #
241 | # Step (3) is the surprisingly complex part: in order to do this, we need to
242 | # identify the subdirectories in docs/media, recreate them in
243 | # $(DOC_BUILD)/media, then do the same with the files.
244 | #
245 | DOC_MEDIA_DIRS := $(shell find docs/media -type d 2>/dev/null | grep -v "^docs/media$$")
246 | DOC_MEDIA_DIRS := $(DOC_MEDIA_DIRS:docs/media/%=%)
247 | DOC_MEDIA_DIRS_BUILD := $(DOC_MEDIA_DIRS:%=$(DOC_BUILD)/media/%)
248 |
249 | DOC_MEDIA_FILES := $(shell find docs/media -type f 2>/dev/null)
250 | DOC_MEDIA_FILES := $(DOC_MEDIA_FILES:docs/media/%=%)
251 | DOC_MEDIA_FILES_BUILD := $(DOC_MEDIA_FILES:%=$(DOC_BUILD)/media/%)
252 |
253 | #
254 | # Like the other targets, "docs" just depends on the final files we want to
255 | # create in $(DOC_BUILD), leveraging other targets and recipes to define how
256 | # to get there.
257 | #
258 | .PHONY: docs
259 | docs: \
260 | $(DOC_FILES:%$(RESTDOWN_EXT)=$(DOC_BUILD)/%.html) \
261 | $(DOC_FILES:%$(RESTDOWN_EXT)=$(DOC_BUILD)/%.json) \
262 | $(DOC_MEDIA_FILES_BUILD)
263 |
264 | #
265 | # We keep the intermediate files so that the next build can see whether the
266 | # files in DOC_BUILD are up to date.
267 | #
268 | .PRECIOUS: \
269 | $(DOC_FILES:%$(RESTDOWN_EXT)=docs/%.html) \
270 | $(DOC_FILES:%$(RESTDOWN_EXT)=docs/%json)
271 |
272 | #
273 | # We do clean those intermediate files, as well as all of DOC_BUILD.
274 | #
275 | CLEAN_FILES += \
276 | $(DOC_BUILD) \
277 | $(DOC_FILES:%$(RESTDOWN_EXT)=docs/%.html) \
278 | $(DOC_FILES:%$(RESTDOWN_EXT)=docs/%.json)
279 |
280 | #
281 | # Before installing the files, we must make sure the directories exist. The |
282 | # syntax tells make that the dependency need only exist, not be up to date.
283 | # Otherwise, it might try to rebuild spuriously because the directory itself
284 | # appears out of date.
285 | #
286 | $(DOC_MEDIA_FILES_BUILD): | $(DOC_MEDIA_DIRS_BUILD)
287 |
288 | $(DOC_BUILD)/%: docs/% | $(DOC_BUILD)
289 | $(CP) $< $@
290 |
291 | docs/%.json docs/%.html: docs/%$(RESTDOWN_EXT) | $(DOC_BUILD) $(RESTDOWN_EXEC)
292 | $(RESTDOWN) $(RESTDOWN_FLAGS) -m $(DOC_BUILD) $<
293 |
294 | $(DOC_BUILD):
295 | $(MKDIR) $@
296 |
297 | $(DOC_MEDIA_DIRS_BUILD):
298 | $(MKDIR) $@
299 |
300 | #
301 | # The default "test" target does nothing. This should usually be overridden by
302 | # the parent Makefile. It's included here so we can define "prepush" without
303 | # requiring the repo to define "test".
304 | #
305 | .PHONY: test
306 | test:
307 |
308 | .PHONY: prepush
309 | prepush: check test
310 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | // Copyright 2014 Joyent, Inc. All rights reserved.
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | var fs = require('fs');
8 | var os = require('os');
9 | var path = require('path');
10 | var util = require('util');
11 |
12 | var userid = require('userid');
13 | var assert = require('assert-plus');
14 | var bunyan = require('bunyan');
15 | var clone = require('clone');
16 | var dashdash = require('dashdash');
17 | var LRU = require('lru-cache');
18 | var nfs = require('nfs');
19 | var rpc = require('oncrpc');
20 | var mantafs = require('mantafs');
21 | var vasync = require('vasync');
22 |
23 | var app = require('./lib');
24 |
25 | // uid/gid for 'nobody' on non-windows systems
26 | var uid = 0;
27 | var gid = 0;
28 | var os_platform;
29 |
30 | ///--- Globals
31 |
32 | var LOG = app.bunyan.createLogger();
33 |
34 | var OPTIONS_PARSER = dashdash.createParser({
35 | options: [
36 | {
37 | names: ['file', 'f'],
38 | type: 'string',
39 | help: 'configuration file to use',
40 | helpArg: 'FILE'
41 | },
42 | {
43 | names: ['debug', 'd'],
44 | type: 'bool',
45 | help: 'turn on debug bunyan logging'
46 | },
47 | {
48 | names: ['verbose', 'v'],
49 | type: 'bool',
50 | help: 'turn on verbose bunyan logging'
51 | }
52 | ]
53 | });
54 |
55 |
56 |
57 | ///--- Functions
58 |
59 | function usage(msg) {
60 | var help = OPTIONS_PARSER.help({
61 | includeEnv: true
62 | }).trimRight();
63 |
64 | if (msg)
65 | console.error(util.format.apply(util, arguments));
66 | console.error('usage: nfsd [OPTIONS]\noptions:\n' + help);
67 |
68 | process.exit(msg ? 1 : 0);
69 | }
70 |
71 |
72 | function configure() {
73 | var opts;
74 |
75 | try {
76 | opts = OPTIONS_PARSER.parse(process.argv);
77 | } catch (e) {
78 | usage(e.message);
79 | }
80 |
81 | if (opts.verbose) {
82 | LOG = LOG.child({
83 | level: 'trace',
84 | src: true
85 | });
86 | } else if (opts.debug) {
87 | LOG = LOG.child({
88 | level: 'debug',
89 | src: true
90 | });
91 | } else {
92 | LOG = LOG.child({
93 | level: 'info',
94 | src: true
95 | });
96 | }
97 |
98 | if (opts.help)
99 | usage();
100 |
101 | var cfg;
102 | if (opts.file) {
103 | try {
104 | cfg = JSON.parse(fs.readFileSync(opts.file, 'utf8'));
105 | } catch (e) {
106 | usage('unable to load %s:\n%s\n', opts.file, e.toString());
107 | }
108 | } else {
109 | cfg = {};
110 | }
111 |
112 | // If no config, let createMantaClient handle setup using env
113 | if (!cfg.manta)
114 | cfg.manta = {};
115 |
116 | if (cfg.database) {
117 | assert.object(cfg.database, 'config.database');
118 | } else {
119 | cfg.database = {};
120 | }
121 |
122 | // default local cache config values if any are not provided
123 | if (!cfg.database.location)
124 | cfg.database.location = '/var/tmp/mfsdb';
125 |
126 | if (!cfg.database.sizeMB)
127 | cfg.database.sizeMB = 5120;
128 |
129 | if (!cfg.database.ttl)
130 | cfg.database.ttl = 43200;
131 |
132 | if (!cfg.database.wbtime)
133 | cfg.database.wbtime = 60;
134 |
135 | if (!cfg.database.num_par)
136 | cfg.database.num_par = 2;
137 |
138 | if (cfg.portmap) {
139 | assert.object(cfg.portmap, 'config.portmap');
140 | // Normally only define this section if setting
141 | // 'usehost': 1
142 | } else {
143 | // our built-in portmapper just hardcodes the standard info
144 | cfg.portmap = {
145 | 'port': 111,
146 | 'mappings': {
147 | 'mountd': [ {
148 | 'prog': 100005,
149 | 'vers': 3,
150 | 'prot': 6,
151 | 'port': 1892
152 | }, {
153 | 'prog': 100005,
154 | 'vers': 1,
155 | 'prot': 6,
156 | 'port': 1892
157 | }],
158 | 'nfsd': [ {
159 | 'prog': 100003,
160 | 'vers': 3,
161 | 'prot': 6,
162 | 'port': 2049
163 | }],
164 | 'portmapd': [ {
165 | 'prog': 100000,
166 | 'vers': 2,
167 | 'prot': 6,
168 | 'port': 111
169 | }]
170 | }
171 | };
172 | }
173 |
174 | // Can set 'address' to enable the mountd server to listen on an IP address
175 | // other than the loopback.
176 | // Can define hosts_allow and hosts_deny to list the addresses of hosts
177 | // which can/cannot mount. e.g.
178 | // 'hosts_allow': {
179 | // '192.168.0.10': {},
180 | // '192.168.0.11': {}
181 | // },
182 | // 'hosts_deny': {
183 | // '192.168.0.12': {},
184 | // '192.168.0.13': {}
185 | // }
186 | // Can set exports if you want to limit what parts of the manta namespace
187 | // can be mounted:
188 | // 'exports': {
189 | // '/user/stor/project': {},
190 | // '/user/public': {}
191 | // }
192 | cfg.mount = cfg.mount || {};
193 | assert.object(cfg.mount, 'config.mount');
194 |
195 | // Can set uid and gid to specify the uid/gid for 'nobody' on the client.
196 | // If not provided, the server's values for 'nobody' will be used.
197 | if (!cfg.nfs) {
198 | var t_uid;
199 | var t_gid;
200 |
201 | try {
202 | t_uid = convert_neg_id(userid.uid('nobody'));
203 | } catch (e1) {
204 | t_uid = 65534;
205 | }
206 |
207 | try {
208 | t_gid = convert_neg_id(userid.gid('nobody'));
209 | } catch (e1) {
210 | // Linux uses 'nogroup' instead of 'nobody'
211 | try {
212 | t_gid = convert_neg_id(userid.gid('nogroup'));
213 | } catch (e2) {
214 | t_gid = t_uid;
215 | }
216 | }
217 |
218 | cfg.nfs = {
219 | 'uid': t_uid,
220 | 'gid': t_gid
221 | };
222 | }
223 |
224 | assert.object(cfg.nfs, 'config.nfs');
225 | cfg.nfs.fd_cache = cfg.nfs.fd_cache || {
226 | max: 10000,
227 | ttl: 60
228 | };
229 | cfg.nfs.hosts_allow = cfg.mount.hosts_allow;
230 | cfg.nfs.hosts_deny = cfg.mount.hosts_deny;
231 |
232 | cfg.log = LOG;
233 | cfg.manta.log = LOG;
234 | cfg.mount.log = LOG;
235 | cfg.nfs.log = LOG;
236 | cfg.portmap.log = LOG;
237 |
238 | cfg.manta = app.createMantaClient(cfg.manta);
239 | cfg.mount.manta = cfg.manta;
240 | cfg.nfs.manta = cfg.manta;
241 |
242 | return (cfg);
243 | }
244 |
245 |
246 | function step_down() {
247 | try {
248 | process.setgid(gid);
249 | process.setuid(uid);
250 | LOG.info('server now running as \'nobody\'');
251 | } catch (e) {
252 | LOG.fatal(e, 'unable to setuid/setgid to nobody');
253 | process.exit(1);
254 | }
255 | }
256 |
257 | // Runs the mountd and nfsd servers. Called once we're registered with the
258 | // system's portmapper or once we've started our own portmapper.
259 | function run_servers(log, cfg_mount, cfg_nfs) {
260 | var barrier = vasync.barrier();
261 | var mountd = app.createMountServer(cfg_mount);
262 | var nfsd = app.createNfsServer(cfg_nfs);
263 |
264 | barrier.on('drain', function onRunning() {
265 | var ma = mountd.address();
266 | var na = nfsd.address();
267 |
268 | log.info('mountd: listening on: tcp://%s:%d',
269 | ma.address, ma.port);
270 | log.info('nfsd: listening on: tcp://%s:%d',
271 | na.address, na.port);
272 |
273 | if (uid !== 0) {
274 | // On non-windows machines we run as 'nobody'.
275 | // On sunos we have to wait until after we're listening on the nfs
276 | // port since the user 'nobody' will not have the sys_nfs priv.
277 | // On darwin 'nobody' is -2 and we error setting the uid/gid to a
278 | // negative number, so use the symbolic name.
279 | if (os_platform === 'darwin') {
280 | gid = uid = 'nobody';
281 | }
282 | step_down();
283 | }
284 | });
285 |
286 | mountd.on('error', function (e) {
287 | if (e.code == 'EADDRINUSE') {
288 | log.fatal('mountd already running, exiting.');
289 | } else {
290 | log.fatal(e, 'unable to run the mountd');
291 | }
292 | process.exit(1);
293 | });
294 |
295 | nfsd.on('error', function (e) {
296 | if (e.code == 'EADDRINUSE') {
297 | log.fatal('nfsd already running, exiting.');
298 | } else {
299 | log.fatal(e, 'unable to run the nfsd');
300 | }
301 | process.exit(1);
302 | });
303 |
304 | barrier.start('mount');
305 | mountd.listen(cfg_mount.port || 1892,
306 | cfg_mount.address || '127.0.0.1',
307 | barrier.done.bind(barrier, 'mount'));
308 |
309 | // nfsd needs to listen on the same IP as configured for the mountd
310 | barrier.start('nfs');
311 | nfsd.listen(cfg_nfs.port || 2049,
312 | cfg_mount.address || '127.0.0.1',
313 | barrier.done.bind(barrier, 'nfs'));
314 | }
315 |
316 | // Darwin uses negative numbers for 'nobody' but these get pulled out as a
317 | // large non-negative number. Convert to twos-complement.
318 | function convert_neg_id(id)
319 | {
320 | if (id > 0x7fffffff)
321 | return (-(~id + 1));
322 | else
323 | return (id);
324 | }
325 |
326 | ///--- Mainline
327 |
328 | (function main() {
329 | var cfg = configure();
330 | var log = cfg.log;
331 |
332 | os_platform = os.platform();
333 | if (os_platform !== 'win32' && os_platform !== 'darwin') {
334 | uid = convert_neg_id(userid.uid('nobody'));
335 | try {
336 | gid = convert_neg_id(userid.gid('nobody'));
337 | } catch (e1) {
338 | // Linux uses 'nogroup' instead of 'nobody'
339 | try {
340 | gid = convert_neg_id(userid.gid('nogroup'));
341 | } catch (e2) {
342 | gid = uid;
343 | }
344 | }
345 | }
346 |
347 | var mfs = mantafs.createClient({
348 | log: log.child({component: 'MantaFs'}, true),
349 | manta: cfg.manta,
350 | path: cfg.database.location,
351 | sizeMB: cfg.database.sizeMB,
352 | ttl: cfg.database.ttl,
353 | wbtime: cfg.database.wbtime,
354 | num_par: cfg.database.num_par,
355 | uid: cfg.nfs.uid || uid,
356 | gid: cfg.nfs.gid || gid
357 | });
358 |
359 | // must always use the system's portmapper on sunos
360 | if (os_platform === 'sunos')
361 | cfg.portmap.usehost = true;
362 |
363 | cfg.mount.fs = mfs;
364 | cfg.nfs.fs = mfs;
365 | cfg.nfs.fd_cache = LRU({
366 | dispose: function cache_close_fd(k, v) {
367 | mfs.close(v.fd, function on_close(err) {
368 | if (err)
369 | log.debug(err, 'failed to close(fd=%d) for %s', v.fd, k);
370 | });
371 | },
372 | max: cfg.nfs.fd_cache.max,
373 | maxAge: cfg.nfs.fd_cache.ttl * 1000 // 1m TTL
374 | });
375 |
376 | cfg.nfs.cachepath = cfg.database.location; // used by fsstat
377 |
378 | log.info('configuration: %s', util.inspect(cfg));
379 |
380 | var mntmapping = {
381 | prog: 100005,
382 | vers: 3,
383 | prot: 6,
384 | port: 1892
385 | };
386 |
387 | var nfsmapping = {
388 | prog: 100003,
389 | vers: 3,
390 | prot: 6,
391 | port: 2049
392 | };
393 |
394 | function cleanup() {
395 | mfs.shutdown(function (err) {
396 | if (err) {
397 | log.warn(err, 'mantafs shutdown error');
398 | }
399 |
400 | if (cfg.portmap.usehost) {
401 | var pmapclient = app.createPortmapClient(cfg.portmap);
402 |
403 | pmapclient.once('connect', function () {
404 | pmapclient.unset(mntmapping, function (err1) {
405 | if (err1) {
406 | log.warn(err1,
407 | 'unregistering mountd from the portmapper');
408 | }
409 |
410 | pmapclient.unset(nfsmapping, function (err2) {
411 | if (err2) {
412 | log.warn(err2,
413 | 'unregistering nfsd from the portmapper');
414 | }
415 | log.info('Shutdown complete, exiting.');
416 | process.exit(0);
417 | });
418 | });
419 | });
420 | } else {
421 | log.info('Shutdown complete, exiting.');
422 | process.exit(0);
423 | }
424 | });
425 | }
426 |
427 | process.on('SIGTERM', function () {
428 | log.info('Got SIGTERM, shutting down.');
429 | cleanup();
430 | });
431 |
432 | process.on('SIGINT', function () {
433 | log.info('Got SIGINT, shutting down.');
434 | cleanup();
435 | });
436 |
437 | mfs.once('error', function (err) {
438 | log.fatal(err, 'unable to initialize mantafs cache');
439 | process.exit(1);
440 | });
441 | mfs.once('ready', function () {
442 | // Cache exists now, ensure cache dir modes are more secure
443 | fs.chmodSync(mfs.cache.location, 0700);
444 | fs.chmodSync(path.join(mfs.cache.location, 'fscache'), 0700);
445 | fs.chmodSync(path.join(mfs.cache.location, 'mantafs.db'), 0600);
446 | if (uid !== 0) {
447 | // On non-windows machines we run as 'nobody'. Tighten up now.
448 | fs.chownSync(mfs.cache.location, uid, gid);
449 | fs.chownSync(path.join(mfs.cache.location, 'fscache'), uid, gid);
450 | fs.chownSync(path.join(mfs.cache.location, 'mantafs.db'), uid, gid);
451 | }
452 |
453 | // the portmapper needs to listen on all addresses, unlike our mountd
454 | // and nfsd which only listen on localhost by default for some basic
455 | // security
456 | cfg.portmap.address = cfg.portmap.address || '0.0.0.0';
457 | cfg.portmap.port = cfg.portmap.port || 111;
458 |
459 | // Use the system's portmapper
460 | function register_with_pmap() {
461 | // The Linux portmapper normally rejects requests that are not
462 | // made to the loopback address.
463 | cfg.portmap.url = util.format('udp://127.0.0.1:%d',
464 | cfg.portmap.port);
465 | var pmapclient = app.createPortmapClient(cfg.portmap);
466 |
467 | pmapclient.on('error', function (e) {
468 | log.fatal(e, 'unable to connect to the system`s portmapper');
469 | process.exit(1);
470 | });
471 |
472 | pmapclient.once('connect', function () {
473 | pmapclient.set(mntmapping, function (err1) {
474 | if (err1) {
475 | log.fatal(err1,
476 | 'unable to register mountd with the portmapper');
477 | process.exit(1);
478 | }
479 |
480 | pmapclient.set(nfsmapping, function (err2) {
481 | if (err2) {
482 | log.fatal(err2,
483 | 'unable to register nfsd with the portmapper');
484 | process.exit(1);
485 | }
486 |
487 | pmapclient.close();
488 | run_servers(cfg.log, cfg.mount, cfg.nfs);
489 | });
490 | });
491 | });
492 | }
493 |
494 | if (cfg.portmap.usehost) {
495 | register_with_pmap();
496 | } else {
497 | // Here we run our own portmapper
498 | var pmapd = app.createPortmapServer(cfg.portmap);
499 |
500 | pmapd.on('error', function (e) {
501 | if (e.code == 'EADDRINUSE') {
502 | log.info('Portmapper running, registering there...');
503 | cfg.portmap.usehost = 1;
504 | register_with_pmap();
505 | } else {
506 | log.fatal(e, 'unable to run the portmapper');
507 | process.exit(1);
508 | }
509 | });
510 |
511 | pmapd.listen(cfg.portmap.port, cfg.portmap.address, function () {
512 | run_servers(cfg.log, cfg.mount, cfg.nfs);
513 | });
514 | }
515 | });
516 | })();
517 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Mozilla Public License Version 2.0
2 | ==================================
3 |
4 | 1. Definitions
5 | --------------
6 |
7 | 1.1. "Contributor"
8 | means each individual or legal entity that creates, contributes to
9 | the creation of, or owns Covered Software.
10 |
11 | 1.2. "Contributor Version"
12 | means the combination of the Contributions of others (if any) used
13 | by a Contributor and that particular Contributor's Contribution.
14 |
15 | 1.3. "Contribution"
16 | means Covered Software of a particular Contributor.
17 |
18 | 1.4. "Covered Software"
19 | means Source Code Form to which the initial Contributor has attached
20 | the notice in Exhibit A, the Executable Form of such Source Code
21 | Form, and Modifications of such Source Code Form, in each case
22 | including portions thereof.
23 |
24 | 1.5. "Incompatible With Secondary Licenses"
25 | means
26 |
27 | (a) that the initial Contributor has attached the notice described
28 | in Exhibit B to the Covered Software; or
29 |
30 | (b) that the Covered Software was made available under the terms of
31 | version 1.1 or earlier of the License, but not also under the
32 | terms of a Secondary License.
33 |
34 | 1.6. "Executable Form"
35 | means any form of the work other than Source Code Form.
36 |
37 | 1.7. "Larger Work"
38 | means a work that combines Covered Software with other material, in
39 | a separate file or files, that is not Covered Software.
40 |
41 | 1.8. "License"
42 | means this document.
43 |
44 | 1.9. "Licensable"
45 | means having the right to grant, to the maximum extent possible,
46 | whether at the time of the initial grant or subsequently, any and
47 | all of the rights conveyed by this License.
48 |
49 | 1.10. "Modifications"
50 | means any of the following:
51 |
52 | (a) any file in Source Code Form that results from an addition to,
53 | deletion from, or modification of the contents of Covered
54 | Software; or
55 |
56 | (b) any new file in Source Code Form that contains any Covered
57 | Software.
58 |
59 | 1.11. "Patent Claims" of a Contributor
60 | means any patent claim(s), including without limitation, method,
61 | process, and apparatus claims, in any patent Licensable by such
62 | Contributor that would be infringed, but for the grant of the
63 | License, by the making, using, selling, offering for sale, having
64 | made, import, or transfer of either its Contributions or its
65 | Contributor Version.
66 |
67 | 1.12. "Secondary License"
68 | means either the GNU General Public License, Version 2.0, the GNU
69 | Lesser General Public License, Version 2.1, the GNU Affero General
70 | Public License, Version 3.0, or any later versions of those
71 | licenses.
72 |
73 | 1.13. "Source Code Form"
74 | means the form of the work preferred for making modifications.
75 |
76 | 1.14. "You" (or "Your")
77 | means an individual or a legal entity exercising rights under this
78 | License. For legal entities, "You" includes any entity that
79 | controls, is controlled by, or is under common control with You. For
80 | purposes of this definition, "control" means (a) the power, direct
81 | or indirect, to cause the direction or management of such entity,
82 | whether by contract or otherwise, or (b) ownership of more than
83 | fifty percent (50%) of the outstanding shares or beneficial
84 | ownership of such entity.
85 |
86 | 2. License Grants and Conditions
87 | --------------------------------
88 |
89 | 2.1. Grants
90 |
91 | Each Contributor hereby grants You a world-wide, royalty-free,
92 | non-exclusive license:
93 |
94 | (a) under intellectual property rights (other than patent or trademark)
95 | Licensable by such Contributor to use, reproduce, make available,
96 | modify, display, perform, distribute, and otherwise exploit its
97 | Contributions, either on an unmodified basis, with Modifications, or
98 | as part of a Larger Work; and
99 |
100 | (b) under Patent Claims of such Contributor to make, use, sell, offer
101 | for sale, have made, import, and otherwise transfer either its
102 | Contributions or its Contributor Version.
103 |
104 | 2.2. Effective Date
105 |
106 | The licenses granted in Section 2.1 with respect to any Contribution
107 | become effective for each Contribution on the date the Contributor first
108 | distributes such Contribution.
109 |
110 | 2.3. Limitations on Grant Scope
111 |
112 | The licenses granted in this Section 2 are the only rights granted under
113 | this License. No additional rights or licenses will be implied from the
114 | distribution or licensing of Covered Software under this License.
115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a
116 | Contributor:
117 |
118 | (a) for any code that a Contributor has removed from Covered Software;
119 | or
120 |
121 | (b) for infringements caused by: (i) Your and any other third party's
122 | modifications of Covered Software, or (ii) the combination of its
123 | Contributions with other software (except as part of its Contributor
124 | Version); or
125 |
126 | (c) under Patent Claims infringed by Covered Software in the absence of
127 | its Contributions.
128 |
129 | This License does not grant any rights in the trademarks, service marks,
130 | or logos of any Contributor (except as may be necessary to comply with
131 | the notice requirements in Section 3.4).
132 |
133 | 2.4. Subsequent Licenses
134 |
135 | No Contributor makes additional grants as a result of Your choice to
136 | distribute the Covered Software under a subsequent version of this
137 | License (see Section 10.2) or under the terms of a Secondary License (if
138 | permitted under the terms of Section 3.3).
139 |
140 | 2.5. Representation
141 |
142 | Each Contributor represents that the Contributor believes its
143 | Contributions are its original creation(s) or it has sufficient rights
144 | to grant the rights to its Contributions conveyed by this License.
145 |
146 | 2.6. Fair Use
147 |
148 | This License is not intended to limit any rights You have under
149 | applicable copyright doctrines of fair use, fair dealing, or other
150 | equivalents.
151 |
152 | 2.7. Conditions
153 |
154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
155 | in Section 2.1.
156 |
157 | 3. Responsibilities
158 | -------------------
159 |
160 | 3.1. Distribution of Source Form
161 |
162 | All distribution of Covered Software in Source Code Form, including any
163 | Modifications that You create or to which You contribute, must be under
164 | the terms of this License. You must inform recipients that the Source
165 | Code Form of the Covered Software is governed by the terms of this
166 | License, and how they can obtain a copy of this License. You may not
167 | attempt to alter or restrict the recipients' rights in the Source Code
168 | Form.
169 |
170 | 3.2. Distribution of Executable Form
171 |
172 | If You distribute Covered Software in Executable Form then:
173 |
174 | (a) such Covered Software must also be made available in Source Code
175 | Form, as described in Section 3.1, and You must inform recipients of
176 | the Executable Form how they can obtain a copy of such Source Code
177 | Form by reasonable means in a timely manner, at a charge no more
178 | than the cost of distribution to the recipient; and
179 |
180 | (b) You may distribute such Executable Form under the terms of this
181 | License, or sublicense it under different terms, provided that the
182 | license for the Executable Form does not attempt to limit or alter
183 | the recipients' rights in the Source Code Form under this License.
184 |
185 | 3.3. Distribution of a Larger Work
186 |
187 | You may create and distribute a Larger Work under terms of Your choice,
188 | provided that You also comply with the requirements of this License for
189 | the Covered Software. If the Larger Work is a combination of Covered
190 | Software with a work governed by one or more Secondary Licenses, and the
191 | Covered Software is not Incompatible With Secondary Licenses, this
192 | License permits You to additionally distribute such Covered Software
193 | under the terms of such Secondary License(s), so that the recipient of
194 | the Larger Work may, at their option, further distribute the Covered
195 | Software under the terms of either this License or such Secondary
196 | License(s).
197 |
198 | 3.4. Notices
199 |
200 | You may not remove or alter the substance of any license notices
201 | (including copyright notices, patent notices, disclaimers of warranty,
202 | or limitations of liability) contained within the Source Code Form of
203 | the Covered Software, except that You may alter any license notices to
204 | the extent required to remedy known factual inaccuracies.
205 |
206 | 3.5. Application of Additional Terms
207 |
208 | You may choose to offer, and to charge a fee for, warranty, support,
209 | indemnity or liability obligations to one or more recipients of Covered
210 | Software. However, You may do so only on Your own behalf, and not on
211 | behalf of any Contributor. You must make it absolutely clear that any
212 | such warranty, support, indemnity, or liability obligation is offered by
213 | You alone, and You hereby agree to indemnify every Contributor for any
214 | liability incurred by such Contributor as a result of warranty, support,
215 | indemnity or liability terms You offer. You may include additional
216 | disclaimers of warranty and limitations of liability specific to any
217 | jurisdiction.
218 |
219 | 4. Inability to Comply Due to Statute or Regulation
220 | ---------------------------------------------------
221 |
222 | If it is impossible for You to comply with any of the terms of this
223 | License with respect to some or all of the Covered Software due to
224 | statute, judicial order, or regulation then You must: (a) comply with
225 | the terms of this License to the maximum extent possible; and (b)
226 | describe the limitations and the code they affect. Such description must
227 | be placed in a text file included with all distributions of the Covered
228 | Software under this License. Except to the extent prohibited by statute
229 | or regulation, such description must be sufficiently detailed for a
230 | recipient of ordinary skill to be able to understand it.
231 |
232 | 5. Termination
233 | --------------
234 |
235 | 5.1. The rights granted under this License will terminate automatically
236 | if You fail to comply with any of its terms. However, if You become
237 | compliant, then the rights granted under this License from a particular
238 | Contributor are reinstated (a) provisionally, unless and until such
239 | Contributor explicitly and finally terminates Your grants, and (b) on an
240 | ongoing basis, if such Contributor fails to notify You of the
241 | non-compliance by some reasonable means prior to 60 days after You have
242 | come back into compliance. Moreover, Your grants from a particular
243 | Contributor are reinstated on an ongoing basis if such Contributor
244 | notifies You of the non-compliance by some reasonable means, this is the
245 | first time You have received notice of non-compliance with this License
246 | from such Contributor, and You become compliant prior to 30 days after
247 | Your receipt of the notice.
248 |
249 | 5.2. If You initiate litigation against any entity by asserting a patent
250 | infringement claim (excluding declaratory judgment actions,
251 | counter-claims, and cross-claims) alleging that a Contributor Version
252 | directly or indirectly infringes any patent, then the rights granted to
253 | You by any and all Contributors for the Covered Software under Section
254 | 2.1 of this License shall terminate.
255 |
256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all
257 | end user license agreements (excluding distributors and resellers) which
258 | have been validly granted by You or Your distributors under this License
259 | prior to termination shall survive termination.
260 |
261 | ************************************************************************
262 | * *
263 | * 6. Disclaimer of Warranty *
264 | * ------------------------- *
265 | * *
266 | * Covered Software is provided under this License on an "as is" *
267 | * basis, without warranty of any kind, either expressed, implied, or *
268 | * statutory, including, without limitation, warranties that the *
269 | * Covered Software is free of defects, merchantable, fit for a *
270 | * particular purpose or non-infringing. The entire risk as to the *
271 | * quality and performance of the Covered Software is with You. *
272 | * Should any Covered Software prove defective in any respect, You *
273 | * (not any Contributor) assume the cost of any necessary servicing, *
274 | * repair, or correction. This disclaimer of warranty constitutes an *
275 | * essential part of this License. No use of any Covered Software is *
276 | * authorized under this License except under this disclaimer. *
277 | * *
278 | ************************************************************************
279 |
280 | ************************************************************************
281 | * *
282 | * 7. Limitation of Liability *
283 | * -------------------------- *
284 | * *
285 | * Under no circumstances and under no legal theory, whether tort *
286 | * (including negligence), contract, or otherwise, shall any *
287 | * Contributor, or anyone who distributes Covered Software as *
288 | * permitted above, be liable to You for any direct, indirect, *
289 | * special, incidental, or consequential damages of any character *
290 | * including, without limitation, damages for lost profits, loss of *
291 | * goodwill, work stoppage, computer failure or malfunction, or any *
292 | * and all other commercial damages or losses, even if such party *
293 | * shall have been informed of the possibility of such damages. This *
294 | * limitation of liability shall not apply to liability for death or *
295 | * personal injury resulting from such party's negligence to the *
296 | * extent applicable law prohibits such limitation. Some *
297 | * jurisdictions do not allow the exclusion or limitation of *
298 | * incidental or consequential damages, so this exclusion and *
299 | * limitation may not apply to You. *
300 | * *
301 | ************************************************************************
302 |
303 | 8. Litigation
304 | -------------
305 |
306 | Any litigation relating to this License may be brought only in the
307 | courts of a jurisdiction where the defendant maintains its principal
308 | place of business and such litigation shall be governed by laws of that
309 | jurisdiction, without reference to its conflict-of-law provisions.
310 | Nothing in this Section shall prevent a party's ability to bring
311 | cross-claims or counter-claims.
312 |
313 | 9. Miscellaneous
314 | ----------------
315 |
316 | This License represents the complete agreement concerning the subject
317 | matter hereof. If any provision of this License is held to be
318 | unenforceable, such provision shall be reformed only to the extent
319 | necessary to make it enforceable. Any law or regulation which provides
320 | that the language of a contract shall be construed against the drafter
321 | shall not be used to construe this License against a Contributor.
322 |
323 | 10. Versions of the License
324 | ---------------------------
325 |
326 | 10.1. New Versions
327 |
328 | Mozilla Foundation is the license steward. Except as provided in Section
329 | 10.3, no one other than the license steward has the right to modify or
330 | publish new versions of this License. Each version will be given a
331 | distinguishing version number.
332 |
333 | 10.2. Effect of New Versions
334 |
335 | You may distribute the Covered Software under the terms of the version
336 | of the License under which You originally received the Covered Software,
337 | or under the terms of any subsequent version published by the license
338 | steward.
339 |
340 | 10.3. Modified Versions
341 |
342 | If you create software not governed by this License, and you want to
343 | create a new license for such software, you may create and use a
344 | modified version of this License if you rename the license and remove
345 | any references to the name of the license steward (except to note that
346 | such modified license differs from this License).
347 |
348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary
349 | Licenses
350 |
351 | If You choose to distribute Source Code Form that is Incompatible With
352 | Secondary Licenses under the terms of this version of the License, the
353 | notice described in Exhibit B of this License must be attached.
354 |
355 | Exhibit A - Source Code Form License Notice
356 | -------------------------------------------
357 |
358 | This Source Code Form is subject to the terms of the Mozilla Public
359 | License, v. 2.0. If a copy of the MPL was not distributed with this
360 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
361 |
362 | If it is not possible or desirable to put the notice in a particular
363 | file, then You may include the notice in a location (such as a LICENSE
364 | file in a relevant directory) where a recipient would be likely to look
365 | for such a notice.
366 |
367 | You may add additional accurate notices of copyright ownership.
368 |
369 | Exhibit B - "Incompatible With Secondary Licenses" Notice
370 | ---------------------------------------------------------
371 |
372 | This Source Code Form is "Incompatible With Secondary Licenses", as
373 | defined by the Mozilla Public License, v. 2.0.
374 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # manta-nfs
2 |
3 | `manta-nfs` implements a [NFS vers. 3](http://tools.ietf.org/html/rfc1813)
4 | server that uses
5 | [Joyent Manta](http://www.joyent.com/products/manta) as the backing store.
6 | The server implements all NFS functionality, although some OS-level commands,
7 | such as `chmod`, will have no effect since Manta does not support that concept.
8 | The server is implemented in [node.js](http://nodejs.org/) and **requires**
9 | v0.10.x.
10 |
11 | - [Overview](#overview)
12 | - [Getting Started](#getting-started)
13 | - [Configuration](#configuration)
14 | - [Usage](#usage)
15 | - [Limitations](#limitations)
16 | - [OS Specific Considerations](#os-specific-considerations)
17 | - [Darwin (OS X)](#darwin-os-x)
18 | - [Linux](#linux)
19 | - [SmartOS](#smartos)
20 | - [Windows](#windows)
21 |
22 |
23 | ## Overview
24 |
25 | The server is a process that runs locally on your laptop, in your
26 | zone, or on a standalone system, and services NFS requests. The server then
27 | acts as a gateway for those requests back into Manta. Manta objects are
28 | cached locally in the machine's file system so that all NFS operations can
29 | be supported. Unlike Manta, the server provides the typical POSIX write
30 | semantics via its use of the local object cache.
31 |
32 | The server cannot run on a system that is already acting as a NFS server
33 | since there would be a conflict on the required ports.
34 | In this case, the server will detect the existing server and exit.
35 |
36 | The server includes a built-in portmapper, but it will also interoperate
37 | transparently with the system's portmapper (usually `rpcbind`) if one is running.
38 | The server also includes a built-in `mountd` and `nfsd`. There is no `lockd` provided
39 | by the server.
40 |
41 | By default, the server only listens on the localhost address and only
42 | serves files locally. However, it can be configured to serve files to
43 | external hosts.
44 |
45 | Because the server caches Manta objects locally, care must be taken when
46 | accessing Manta in different ways or from different locations. There is no
47 | attempt to be coherent across multiple systems. Given this, you should
48 | not run more than one instance of the server for the same Manta user. Likewise,
49 | you should not write to the same object using both NFS and the CLI. Reading
50 | objects using both NFS and the CLI is obviously fine.
51 |
52 | If you write an object
53 | using one mechanism (e.g. NFS) and immediately read it using another (e.g. the
54 | CLI), you may not see the same data. The server holds an object locally
55 | for a period of time before writing it back to Manta. Likewise, if you update
56 | an existing object using the CLI, the server might have a stale copy in its
57 | cache. In this case you can wait for the server to notice the object has
58 | changed, or you can force the server to refresh its cached copy by
59 | simply `touch`ing the file.
60 |
61 | ## Getting Started
62 |
63 | Clone the repo then run `npm install` within the clone to build all of the
64 | dependencies. The 'Configuration' section of this readme describes how to
65 | configure the server before you can run it. The 'Usage' section of this
66 | readme describes how to start the server and how to perform an NFS mount.
67 |
68 | ## Configuration
69 |
70 | At a minimum the server needs the configuration information necessary to
71 | connect to a Manta account. If the Manta
72 | [environment variables](http://apidocs.joyent.com/manta/#setting-up-your-environment)
73 | are already set up, the server will use those and no other configuration is
74 | needed.
75 |
76 | In addition to the Manta account information, there are a variety of other
77 | configuration options. An example configuration file, showing all possible
78 | configuration options, is provided in `etc/example.json`, but you should not
79 | use that file to create your personal configuration. A simpler
80 | `etc/template.json` file is provided as a better starting point for your
81 | personal configuration. Each section of the configuration file is optional.
82 | The configuration file is specified to the server via the `-f` option:
83 |
84 | node server.js -f etc/myconfig.json
85 |
86 | Although most of the sections in `etc/example.json` should be
87 | self-explanatory, here is some additional information.
88 |
89 | * The `manta` section must be used to specify the required access information
90 | for Manta if the environment variables are not set. The configuration
91 | information takes precedence over the environment variables if both are
92 | set.
93 |
94 | * The `database` section can be used to configure where and how the server
95 | caches local copies of the Manta objects. The location, size of the
96 | cache, the time-to-live, writeback delay time, and number of parallel
97 | writebacks for the cache can be set in this section.
98 |
99 | The default cache is under `/var/tmp/mfsd` with a size limit of 5GB of
100 | local disk space. The time-to-live is the number of seconds a file will be
101 | cached before checking to see if it is stale. The default is twelve hours
102 | (43200 seconds). The writeback time is the number of seconds a dirty file
103 | will be cached before being written back to Manta. The default is one
104 | minute (60 seconds). If files are updated regularly (e.g. log files) then
105 | it might make sense to increase the timeout to reduce writeback traffic,
106 | but this also increases the window in which data only exists in the local
107 | cache. The number of parallel writebacks defaults to 2. That is, if there
108 | are multiple dirty files to writeback, two at a time will be written back.
109 |
110 | The cache size is not a hard limit. It is possible for more space to
111 | be used than is configured. For example, if an object is larger than the
112 | cache size, then if that object is pulled into the cache, the whole object
113 | must be downloaded and the space used by the object will be consumed. This
114 | would also force all of the other objects out of the cache, since the space
115 | used exceeds the size limit. Another example is with dirty files. These
116 | cannot be evicted from the cache until they have been uploaded back to
117 | Manta, so the cache space used can exceed the size limit until the objects
118 | have been completely uploaded.
119 |
120 | * The `mount` section's `address` field can be used to specify an address
121 | other than localhost for the server to listen on. Using '0.0.0.0' tells the
122 | server to listen on all addresses. Both the `mountd` and `nfsd` within the
123 | server will listen on the given address. Since the server has full access
124 | to all of the user's Manta data, it is a good idea to limit foreign host
125 | access when listening on the external network. The `hosts_allow` or
126 | `hosts_deny` sections can be used to restrict access to the given IP
127 | addresses. The `exports` section can also be used to restrict access to
128 | the specified portions of the Manta filesystem.
129 |
130 | * The `nfs` section can be used to set the `uid` and `gid` values for
131 | 'nobody'. This is useful if NFS clients are running a different OS, which
132 | uses different values for 'nobody', as compared to the server (e.g. Darwin
133 | vs. Linux). Over NFS all files will appear to be owned by 'nobody' since
134 | there is no mechanism to map a Manta username to a local uid on the various
135 | clients, but within Manta all files continue to be owned by the user
136 | account. The `fd-cache` section can be used to configure the server's file
137 | descriptor cache, although this is normally not necessary.
138 |
139 | ## Usage
140 |
141 | When running the server for the first time, you probably want to run it by
142 | hand to confirm that the configuration is correct and things are working as
143 | expected. Once you know things are working correctly, you may want to set up
144 | a service so that the server runs automatically.
145 |
146 | The server must be started as root since it needs access to the portmapper's
147 | privileged port. Once the server is running, it lowers its uid to 'nobody'
148 | to improve security. The `sudo` or `pfexec` commands are typically used to run
149 | a command as root, depending on which OS you're using.
150 |
151 | If you're using the Manta environment variables as the source of your Manta
152 | account information and you're using `sudo`, use the `-E` option to pass
153 | those forward. On some Linux distributions sudo will reset 'HOME' to root's
154 | home directory. On those distributions you must also set HOME back to your home
155 | directory.
156 |
157 | On Darwin or Linux, the server can be run with no config file like:
158 |
159 | sudo -E HOME=/home/foo node server.js
160 |
161 | On SmartOS, the server can be run like:
162 |
163 | pfexec node server.js
164 |
165 | To pass in a config file, use the -f option:
166 |
167 | sudo node server.js -f etc/myconfig.json
168 |
169 | All output logging is done via [bunyan](https://github.com/trentm/node-bunyan).
170 | Once started, the server will output an
171 | occasional log message, but the `-d` or `-v` options can be used to change the
172 | bunyan logging level to either 'debug' or 'trace'. Logging at either of these
173 | levels is not recommended, except during debugging, since there will be many
174 | log entries for each NFS operation. You may want to redirect the output from
175 | the server into a file:
176 |
177 | sudo node server.js -d -f etc/myconfig.json >log 2>&1
178 |
179 | To mount a Manta directory, use the standard NFS client `mount` command with
180 | a Manta path. The user name used here must be the same user as is configured
181 | for Manta access. For example, if Manta user 'foo' is configured, then to
182 | mount their 'public' directory:
183 |
184 | sudo mount 127.0.0.1:/foo/public /mnt
185 |
186 | Once you have confirmed that the server works as expected, you can set up a
187 | service on your system so that the server runs automatically when the system
188 | boots. Setting up a service like this is OS-specific and is discussed in that
189 | section for each operating system.
190 |
191 | ## Limitations
192 |
193 | There are certain NFS operations that cannot be supported because Manta
194 | itself does not support the underlying concept. These are:
195 |
196 | * Changing the owner uid or gid of a file
197 | * Changing the mtime or atime of a file
198 | * Changing or setting the mode of a file
199 | * Creating a file exclusively (O_EXCL - will happen only in the cache)
200 | * Making devices, sockets or FIFOs
201 | * Renaming or moving directories
202 | * Symlinks and hardlinks
203 |
204 | ## OS Specific Considerations
205 |
206 | This section discusses any issues that are specific to running the server on
207 | a given operating system.
208 |
209 |
210 | ### Darwin (OS X)
211 |
212 | There is normally no portmapper running on Darwin so the server runs with its
213 | built-in portmapper.
214 |
215 | The uid/gid for 'nobody' is -2.
216 |
217 | Because you cannot rename a directory, creating new folders using `Finder` is
218 | problematic. The new folder will initially be created by Finder with the name
219 | `untitled folder`, but you will not be able to rename it. Instead, you must use
220 | a terminal window and the command line to create directories with the correct
221 | name.
222 |
223 | The `svc/launchd/com.joyent.mantanfs.plist` file provides an example
224 | configuration for launchd(8). If necessary, edit the file and provide the
225 | correct paths to 'node', 'server.js' and your configuration file.
226 |
227 | Note that this configuration will bring the service up only if an interface
228 | other than `lo` has an IPV4/IPV6 address. However the reverse is not true, and
229 | launchd will not bring down the service if the network goes away.
230 |
231 | Run the following to load and start the service:
232 |
233 | sudo cp svc/launchd/com.joyent.mantanfs.plist /System/Library/LaunchDaemons/
234 | sudo launchctl load /System/Library/LaunchDaemons/com.joyent.mantanfs.plist
235 |
236 |
237 | ### Linux (including lx-branded zones)
238 |
239 | Some distributions (e.g. Ubuntu or Centos) may not come pre-installed with
240 | the `/sbin/mount.nfs` command which is needed to perform a mount, while others
241 | (e.g. Fedora) may be ready to go. On Ubuntu, install the `nfs-common` package.
242 |
243 | apt-get install nfs-common
244 |
245 | On Centos, install the `nfs-utils` package. Depending on the choices described
246 | below, you may also need to install the `rpcbind` package.
247 |
248 | yum install nfs-utils
249 | yum install rpcbind
250 |
251 | Based on the distribution's package manager and package dependencies, the
252 | 'rpcbind' command may have been installed and started. However, due to a
253 | mis-design in the Linux rpcbind code, the manta-nfs server will not be able to
254 | register with the system's rpcbind. There are two options to work around this:
255 |
256 | * Disable the system's rpcbind and let the server use its built-in
257 | portmapper. The method for disabling the system's rpcbind varies depending
258 | on the service manager that the system uses. If 'rpcbind' is in a seperate
259 | package from '/sbin/mount.nfs', then you could simply uninstall that
260 | package. To disable 'rpcbind' on Ubuntu you can run: `stop portmap`.
261 |
262 | * Run the system's rpcbind in 'insecure' mode using the -i option. The
263 | mechanism for specifying customized options for a service varies by
264 | distribution and release. The rpcbind configuration file may be named
265 | `/etc/init/portmap.conf` or `/etc/sysconfig/rpcbind`. For a distribution
266 | which uses traditional sysvinit rc files you may need to edit
267 | `/etc/init.d/rpcbind` and explicitly add the option to the invocation of
268 | rpcbind in the script.
269 |
270 | Here is an example entry for the `/etc/sysconfig/rpcbind` file.
271 | RPCBIND_ARGS="-i"
272 |
273 | If running the manta-nfs server inside an lx-branded zone, the built-in
274 | portmapper may not work properly. In this case, the second option above (using
275 | the system's rpcbind) must be used.
276 |
277 | On Linux the uid/gid for 'nobody' is 65534.
278 |
279 | There is no lock manager included in the server, so you must disable locking
280 | when you mount. e.g.
281 |
282 | mount -o nolock 127.0.0.1:/foo.bar/public /home/foo/mnt
283 |
284 | When mounting from inside an lx-branded zone you may need to explicitly
285 | specify that you want to use the NFSv3 protocol. e.g.
286 |
287 | mount -o nolock,vers=3 127.0.0.1:/foo.bar/public /home/foo/mnt
288 |
289 | To setup the server as a service, so that it runs automatically when the
290 | system boots, you need to hook into the system's service manager. Linux offers
291 | a variety of dfferent service managers, depending upon the distribution and
292 | release.
293 |
294 | * rc files
295 |
296 | The traditional Unix rc file mechanism is not really a service manager but
297 | it does provide a way to start or stop services when the system is booting
298 | or shutting down.
299 |
300 | The `svc/rc/mantanfs` file is a shell script that will start up the server.
301 | Make a copy of this file into `/etc/init.d`. If necessary, edit the file and
302 | provide the correct paths to 'node', 'server.js' and your configuration
303 | file.
304 |
305 | Symlink the following names to the 'mantanfs' file:
306 |
307 | ln -s /etc/rc3.d/S90mantanfs -> ../init.d/mantanfs
308 | ln -s /etc/rc4.d/S90mantanfs -> ../init.d/mantanfs
309 | ln -s /etc/rc5.d/S90mantanfs -> ../init.d/mantanfs
310 | ln -s /etc/rc0.d/K90mantanfs -> ../init.d/mantanfs
311 | ln -s /etc/rc1.d/K90mantanfs -> ../init.d/mantanfs
312 | ln -s /etc/rc2.d/K90mantanfs -> ../init.d/mantanfs
313 | ln -s /etc/rc6.d/K90mantanfs -> ../init.d/mantanfs
314 |
315 | The script directs the server log to '/var/log/mantanfs.log'.
316 |
317 | * Systemd
318 |
319 | See this [wiki](https://fedoraproject.org/wiki/Systemd) for more details
320 | on configuring and using systemd. Also see the `systemd.unit(5)` and
321 | `systemd.service(5)` man pages.
322 |
323 | The `svc/systemd/mantanfs.service` file provides an example configuration
324 | for systemd. Make a copy of this file into /lib/systemd/system. If
325 | necessary, edit the file and provide the correct paths to 'node',
326 | 'server.js' and your configuration file.
327 |
328 | Run the following to start the service:
329 |
330 | systemctl start mantanfs.service
331 |
332 | Since systemd has its own logging, you must use the 'journalctl' command to
333 | look at the logs.
334 |
335 | journalctl _SYSTEMD_UNIT=mantanfs.service
336 |
337 | * Upstart
338 |
339 | See this [cookbook](http://upstart.ubuntu.com/cookbook/) for more details
340 | on configuring and using upstart.
341 |
342 | The `svc/upstart/mantanfs.conf` file provides an example configuration for
343 | upstart. Make a copy of this file into /etc/init. If necessary, edit the
344 | file and provide the correct paths to 'node', 'server.js' and your
345 | configuration file.
346 |
347 | Run the following to start the service:
348 |
349 | initctl start mantanfs
350 |
351 | The server log should be available as '/var/log/upstart/mantanfs.log'.
352 |
353 | ### SmartOS
354 |
355 | In order to mount from the host, the system's 'rpcbind' must be running. The
356 | server's built-in portmapper cannot be used. If the svc is not already enabled,
357 | enable it.
358 |
359 | svcadm enable network/rpc/bind
360 |
361 | If you intend to serve external hosts, you must also ensure that the bind
362 | service is configured to allow access. To check this:
363 |
364 | svccfg -s bind listprop config/local_only
365 |
366 | If this is set to true, you need to change it to false.
367 |
368 | svccfg -s bind setprop config/local_only=false
369 | svcadm refresh bind
370 |
371 | Due to a mis-design in the SmartOS mount code, mounting will fail on older
372 | platforms. If you see the following, you know your mount code is incorrect.
373 |
374 | nfs mount: 127.0.0.1: : RPC: Program not registered
375 | nfs mount: retrying: /home/foo.bar/mnt
376 |
377 | You will either need to run on a newer platform or you can use this
378 | [fixed NFS mount command](http://us-east.manta.joyent.com/jjelinek/public/mount)
379 | explicitly. e.g.
380 |
381 | pfexec ./mount 127.0.0.1:/foo.bar/public /home/foo/mnt
382 |
383 | For unmounting, you can use this
384 | [fixed umount command](http://us-east.manta.joyent.com/jjelinek/public/umount)
385 | explicitly.
386 |
387 | On SmartOS the uid/gid for 'nobody' is 60001.
388 |
389 | The `svc/smf/manta-nfs.xml` file provides an example configuration for
390 | smf(5). If necessary, edit the file and provide the correct paths to 'node',
391 | 'server.js' and your configuration file.
392 |
393 | Run the following to load and start the service:
394 |
395 | svccfg -v import svc/smf/manta-nfs.xml
396 |
397 | ### Windows
398 |
399 | Because of the POSIX dependencies in the server, the code does not currently
400 | build on Windows. However, the Windows NFS client can be used with a server
401 | running on a Unix-based host. Before you can use NFS you may need to set it up
402 | on your Windows system. The procedure varies by which version of Windows
403 | is in use. See the documentation for your release for the correct procedure
404 | to install NFS.
405 |
406 | Once NFS is installed, you simply mount from the server as usual. Substitute
407 | the server's IP address and the correct user name in the following example:
408 |
409 | C:\>mount \\192.168.0.1\foo\public *
410 | Z: is now successfully connected to \\192.168.0.1\foo\public
411 |
412 | The command completed successfully.
413 |
414 | Windows will assign an unused drive letter for the mount. In this example the
415 | drive letter was Z:.
416 |
417 | Windows Explorer has the same limitation as Darwin's Finder when creating a
418 | new folder. The new folder will initially be created by Explorer with the name
419 | `New folder`, but you will not be able to rename it. Instead, you must use
420 | a terminal window and the command line to create directories with the correct
421 | name.
422 |
--------------------------------------------------------------------------------
/tools/service_bundle.dtd.1:
--------------------------------------------------------------------------------
1 |
2 |
24 |
25 |
32 |
33 |
39 |
40 |
45 |
46 |
47 |
48 |
49 |
52 |
58 |
59 |
62 |
65 |
66 |
77 |
78 |
79 |
80 |
83 |
84 |
85 |
86 |
96 |
97 |
98 |
99 |
101 |
102 |
124 |
125 |
127 |
128 |
129 |
130 |
132 |
133 |
134 |
135 |
137 |
138 |
139 |
140 |
142 |
143 |
144 |
145 |
147 |
148 |
149 |
150 |
152 |
153 |
154 |
155 |
157 |
158 |
159 |
160 |
162 |
163 |
164 |
165 |
167 |
168 |
169 |
170 |
172 |
173 |
174 |
175 |
177 |
178 |
179 |
180 |
182 |
183 |
184 |
185 |
187 |
188 |
189 |
190 |
192 |
193 |
194 |
195 |
196 |
197 |
213 |
214 |
220 |
221 |
227 | ]]>
228 |
229 |
235 |
236 |
242 | ]]>
243 |
244 |
262 |
263 |
265 |
266 |
273 | ]]>
274 |
275 |
277 |
278 |
285 | ]]>
286 |
287 |
308 |
309 |
312 |
313 |
317 | ]]>
318 |
319 |
322 |
323 |
327 | ]]>
328 |
329 |
339 |
340 |
341 |
342 |
344 |
345 |
346 |
347 |
382 |
383 |
385 |
386 |
393 |
394 |
395 |
396 |
421 |
422 |
424 |
425 |
432 |
433 |
434 |
435 |
443 |
444 |
445 |
446 |
449 |
450 |
456 |
457 |
458 |
459 |
460 |
461 |
471 |
472 |
473 |
474 |
476 |
477 |
500 |
501 |
502 |
503 |
509 |
510 |
535 |
537 |
538 |
542 |
543 |
544 |
545 |
574 |
575 |
577 |
578 |
584 |
585 |
594 |
595 |
597 |
598 |
599 |
600 |
603 |
604 |
618 |
619 |
620 |
621 |
624 |
625 |
640 |
641 |
642 |
643 |
647 |
648 |
656 |
657 |
659 |
660 |
661 |
662 |
672 |
674 |
675 |
677 |
678 |
686 |
688 |
689 |
690 |
691 |
699 |
701 |
702 |
703 |
704 |
709 |
710 |
712 |
713 |
714 |
715 |
728 |
729 |
730 |
731 |
733 |
734 |
745 |
746 |
748 |
749 |
751 |
752 |
757 |
758 |
760 |
761 |
762 |
763 |
777 |
778 |
779 |
780 |
783 |
784 |
792 |
793 |
795 |
796 |
797 |
798 |
808 |
809 |
810 |
811 |
814 |
815 |
820 |
821 |
823 |
824 |
825 |
837 |
838 |
839 |
840 |
842 |
843 |
851 |
852 |
854 |
855 |
856 |
857 |
873 |
874 |
877 |
878 |
884 |
885 |
913 |
914 |
916 |
917 |
922 |
923 |
937 |
939 |
940 |
941 |
942 |
943 |
944 |
945 |
946 |
949 |
950 |
952 |
953 |
955 |
956 |
957 |
958 |
960 |
961 |
963 |
964 |
967 |
968 |
974 |
975 |
977 |
978 |
979 |
980 |
981 |
982 |
994 |
995 |
996 |
997 |
999 |
1000 |
1006 |
1007 |
1008 |
1009 |
1010 |
1011 |
1029 |
1030 |
1034 |
1035 |
1038 |
1039 |
1059 |
1060 |
1065 |
1066 |
1070 |
1071 |
1085 |
1086 |
1088 |
1089 |
1092 |
--------------------------------------------------------------------------------