Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merging from indexzero/daemon.node.

  • Loading branch information...
commit 4a38be9a371b3c0371aa660b378572fd26564974 2 parents 9d1b0b8 + ce60d6e
@DanBUK authored
View
3  .gitignore
@@ -1,2 +1,3 @@
-build/
.lock-wscript
+build/
+build/*
View
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2009 Arthur (Slashed), Pedro Teixeira, James Halliday, Zak Taylor, Charlie Robbins
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
View
10 README
@@ -1,10 +0,0 @@
-daemon-tools addon for nodejs
-
-To install please use npm:
-
-> npm install daemon-tools
-
-Or to build this module, type:
-> node-waf configure build
-
-You can see example usage in example.js and test_chroot.js.
View
68 README.md
@@ -0,0 +1,68 @@
+# daemon.node
+
+A C++ add-on for Node.js to enable simple daemons in Javascript plus some useful wrappers in Javascript.
+
+## Installation
+
+### Installing npm (node package manager)
+```
+ curl http://npmjs.org/install.sh | sh
+```
+
+### Installing daemon.node with npm
+```
+ [sudo] npm install daemon
+```
+
+### Installing daemon.node locally
+```
+ node-waf configure build
+```
+
+## Usage
+
+There is a great getting started article on daemons and node.js by Slashed that you [can read here][0]. The API has changed slightly from that version thanks to contributions from ptge and [fugue][1]; there is no longer a daemon.closeIO() method, this is done automatically for you.
+
+### Starting a daemon:
+Starting a daemon is easy, just call daemon.start() and daemon.lock().
+
+``` js
+ var daemon = require('daemon');
+
+ // Your awesome code here
+
+ fs.open('somefile.log', 'w+', function (err, fd) {
+ daemon.start(fd);
+ daemon.lock('/tmp/yourprogram.pid');
+ });
+```
+
+This library also exposes a higher level facility through javascript for starting daemons:
+
+``` js
+ var sys = require('sys'),
+ daemon = require('daemon');
+
+ // Your awesome code here
+
+ daemon.daemonize('somefile.log', '/tmp/yourprogram.pid', function (err, pid) {
+ // We are now in the daemon process
+ if (err) return sys.puts('Error starting daemon: ' + err);
+
+ sys.puts('Daemon started successfully with pid: ' + pid);
+ });
+```
+
+### The Fine Print
+This library is available under the MIT LICENSE. See the LICENSE file for more details. It was created by [Slashed][2] and [forked][3] / [improved][4] / [hacked upon][1] by a lot of good people. Special thanks to [Isaacs][5] for npm and a great example in [glob][6].
+
+#### Author: [Slashed](http://github.com/slashed)
+#### Contributors: [Charlie Robbins](http://nodejitsu.com), [Pedro Teixeira](https://github.com/pgte), [James Halliday](https://github.com/substack), [Zak Taylor](https://github.com/dobl), [Daniel Bartlett](https://github.com/danbuk)
+
+[0]: http://slashed.posterous.com/writing-daemons-in-javascript-with-nodejs-0
+[1]: https://github.com/pgte/fugue/blob/master/deps/daemon.cc
+[2]: https://github.com/slashed/daemon.node
+[3]: https://github.com/substack/daemon.node/
+[4]: https://github.com/dobl/daemon.node
+[5]: https://github.com/isaacs/npm
+[6]: https://github.com/isaacs/node-glob
View
57 example.js
@@ -1,57 +0,0 @@
-try {
- var daemon-tools = require('build/default/daemon-tools');
-} catch (e) {
- try {
- var daemon-tools = require('daemon-tools');
- } catch (e) {
- console.log("Have you actually built the module yet?");
- console.log("eg. node-waf configure build install");
- }
-}
-var fs = require('fs');
-var http = require('http');
-var sys = require('sys');
-
-var config = {
- lockFile: '/tmp/testd.pid' //Location of lockFile
-};
-
-var args = process.argv;
-var dPID;
-
-// Handle start stop commands
-switch(args[2]) {
- case "stop":
- var exit_val = 0;
- try {
- process.kill(parseInt(fs.readFileSync(config.lockFile)));
- } catch (e) {
- if (e.message == 'No such process') {
- sys.puts("Error: Process is not running or wrong PID value.");
- exit_val = 1;
- } else {
- sys.puts("Error unknown: " + sys.inspect(e));
- exit_val = 2;
- }
- }
- process.exit(exit_val);
- break;
-
- case "start":
- dPID = daemon-tools.start(false);
- daemon-tools.lock(config.lockFile);
- daemon-tools.closeIO();
- break;
-
- default:
- sys.puts('Usage: [start|stop]');
- process.exit(0);
-}
-
-// Start HTTP Server
-http.createServer(function(req, res) {
- res.writeHead(200, {'Content-Type': 'text/html'});
- res.write('<h1>Hello, World!</h1>');
- res.close();
-}).listen(8000);
-
View
54 example/bindings.js
@@ -0,0 +1,54 @@
+/*
+ * bindings.js: Example for running daemons directly using methods exposed by add-on bindings.
+ *
+ * (C) 2010, Charlie Robbins.
+ *
+ */
+
+var sys = require('sys'),
+ fs = require('fs'),
+ http = require('http');
+
+var daemon;
+try {
+ daemon = require('../lib/daemon');
+}
+catch (ex) {
+ sys.puts("Couldn't find 'daemon' add-on, did you install it yet?");
+ process.exit(0);
+}
+
+var config = {
+ lockFile: '/tmp/testd.pid', // Location of lockFile
+ logFile: '/tmp/testd.log' // Location of logFile
+};
+
+var args = process.argv;
+
+// Handle start stop commands
+switch(args[2]) {
+ case "stop":
+ process.kill(parseInt(fs.readFileSync(config.lockFile)));
+ process.exit(0);
+ break;
+
+ case "start":
+ fs.open(config.logFile, 'w+', function (err, fd) {
+ if (err) return sys.puts('Error starting daemon: ' + err);
+
+ daemon.start(fd);
+ daemon.lock(config.lockFile);
+ });
+ break;
+
+ default:
+ sys.puts('Usage: [start|stop]');
+ process.exit(0);
+}
+
+// Start HTTP Server
+http.createServer(function(req, res) {
+ res.writeHead(200, { 'Content-Type': 'text/html' });
+ res.write('<h1>Hello, World!</h1>');
+ res.end();
+}).listen(8000);
View
59 example/wrapper.js
@@ -0,0 +1,59 @@
+/*
+ * wrapper.js: Example for running daemons using friendly wrapper methods exposed in Javascript.
+ *
+ * (C) 2010, Charlie Robbins.
+ *
+ */
+
+var sys = require('sys'),
+ fs = require('fs'),
+ http = require('http');
+
+var daemon;
+try {
+ daemon = require('../lib/daemon');
+}
+catch (ex) {
+ sys.puts("Couldn't find 'daemon' add-on, did you install it yet?");
+ process.exit(0);
+}
+
+var config = {
+ lockFile: '/tmp/testd.pid', // Location of lockFile
+ logFile: '/tmp/testd.log' // Location of logFile
+};
+
+var args = process.argv;
+
+// Handle start stop commands
+switch(args[2]) {
+ case "stop":
+ daemon.kill(config.lockFile, function (err, pid) {
+ if (err) return sys.puts('Error stopping daemon: ' + err);
+ sys.puts('Successfully stopped daemon with pid: ' + pid);
+ });
+ break;
+
+ case "start":
+ // Start HTTP Server
+ http.createServer(function(req, res) {
+ // sys.puts('Incoming request for: ' + req.url);
+ res.writeHead(200, { 'Content-Type': 'text/html' });
+ res.write('<h1>Hello, World!</h1>');
+ res.end();
+ }).listen(8000);
+
+ daemon.daemonize(config.logFile, config.lockFile, function (err, started) {
+ if (err) {
+ console.dir(err.stack);
+ return sys.puts('Error starting daemon: ' + err);
+ }
+ sys.puts('Successfully started daemon');
+ });
+ break;
+
+ default:
+ sys.puts('Usage: [start|stop]');
+ break;
+}
+
View
70 lib/daemon.js
@@ -0,0 +1,70 @@
+/*
+ * daemon.js: Wrapper for C++ bindings
+ *
+ * (C) 2010 and Charlie Robbins
+ * MIT LICENCE
+ *
+ */
+
+var fs = require('fs'),
+ binding = require('../build/default/daemon'),
+ daemon = exports;
+
+//
+// Export the raw bindings directly
+//
+Object.keys(binding).forEach(function (k) { daemon[k] = binding[k] });
+
+//
+// function daemonize ([out, lock, callback])
+// Run is designed to encapsulate the basic daemon operation in a single async call.
+// When the callback returns you are in the the child process.
+//
+daemon.daemonize = function (out, lock, callback) {
+ //
+ // If we only get one argument assume it's an fd and
+ // simply return with the pid from binding.daemonize(fd);
+ //
+ if (arguments.length === 1) {
+ return binding.daemonize(out);
+ }
+
+ fs.open(out, 'a+', 0666, function (err, fd) {
+ if (err) return callback(err);
+
+ try {
+ var pid = daemon.start(fd);
+ daemon.lock(lock);
+ callback(null, pid);
+ }
+ catch (ex) {
+ callback(ex);
+ }
+ });
+};
+
+//
+// function kill (lock, callback)
+// Asynchronously stop the process in the lock file and
+// remove the lock file
+//
+daemon.kill = function (lock, callback) {
+ fs.readFile(lock, function (err, data) {
+ if (err) return callback(err);
+
+ try {
+ // Stop the process with the pid in the lock file
+ var pid = parseInt(data.toString());
+ process.kill(pid);
+
+ // Remove the lock file
+ fs.unlink(lock, function (err) {
+ if (err) return callback(err);
+ callback(null, pid);
+ });
+ }
+ catch (ex) {
+ callback(ex);
+ }
+ });
+};
View
64 package.json
@@ -1,52 +1,24 @@
{
- "name": "daemon-tools",
- "description": "Add-on for creating *nix daemons, handling chroots, etc.",
- "homepage": "https://github.com/DanBUK/node-daemon-tools",
- "version": "0.1.3",
- "maintainers": [
- {
- "name": "Daniel Bartlett",
- "email": "dan@f-box.org"
- }
- ],
+ "name" : "daemon",
+ "version" : "0.3.1",
+ "description" : "Add-on for creating *nix daemons",
+ "author": "Arthur (Slashed) <arthur@norgic.com>",
"contributors": [
- {
- "name": "Daniel Bartlett",
- "email": "dan@f-box.org"
- }
- ],
- "bugs": {
- "url": "https://github.com/DanBUK/node-daemon-tools/issues"
- },
- "licenses": [
- {
- "type": "MIT"
- }
+ { "name": "Pedro Teixeira", "email": "pedro.teixeira@gmail.com" },
+ { "name": "Charlie Robbins", "email": "charlie.robbins@gmail.com" },
+ { "name": "James Halliday", "email": "mail@substack.net" },
+ { "name": "Zak Taylor", "email": "zak@dobl.com" },
+ { "name": "Daniel Bartlett", "email": "dan@f-box.org" }
],
- "repositories": [
- {
- "type": "git",
- "url": "git://github.com/DanBUK/node-daemon-tools.git"
- }
- ],
- "main": "./daemon-tools",
- "scripts": {
- "build": "node-waf configure build",
- "test": "node-waf test",
- "doc": "node-waf doc",
- "preinstall": "node-waf configure build install"
- },
- "engines": {
- "node": ">=0.2.5"
+ "repository" : {
+ "type" : "git",
+ "url" : "http://github.com/indexzero/daemon.node.git"
},
- "_id": "daemon-tools@0.1.3",
- "_nodeSupported": true,
- "_npmVersion": "0.2.15",
- "_nodeVersion": "v0.2.5",
- "dist": {
- "shasum": "",
- "tarball": ""
+ "main": "./lib/daemon",
+ "scripts" : {
+ "preinstall" : "node-waf configure build"
},
- "_engineSupported": true,
- "_defaultsLoaded": true
+ "engines" : {
+ "node" : ">= 0.4.0"
+ }
}
View
206 src/daemon.cc
@@ -0,0 +1,206 @@
+/*
+* Daemon.node: A node.JS addon that allows creating Unix/Linux Daemons in pure Javascript.
+ *
+* Copyright 2010 (c) <arthur@norgic.com>
+* Modified By: Pedro Teixeira 2010
+* Modified By: James Haliday 2010
+* Modified By: Charlie Robbins 2010
+* Modified By: Zak Taylor 2010
+* Modified By: Daniel Bartlett 2011
+* Modified By: Charlie Robbins 2011
+*
+* Under MIT License. See LICENSE file.
+*
+*/
+
+#include <v8.h>
+#include <node.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pwd.h>
+
+#define PID_MAXLEN 10
+
+using namespace v8;
+using namespace node;
+
+//
+// Go through special routines to become a daemon.
+// if successful, returns daemon pid
+//
+static Handle<Value> Start(const Arguments& args) {
+ HandleScope scope;
+
+ pid_t sid, pid = fork();
+ int i, new_fd;
+
+ if (pid < 0) exit(1);
+ else if (pid > 0) exit(0);
+
+ if (pid == 0) {
+ // Child process: We need to tell libev that we are forking because
+ // kqueue can't deal with this gracefully.
+ //
+ // See: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#code_ev_fork_code_the_audacity_to_re
+ ev_default_fork();
+
+ sid = setsid();
+ if(sid < 0) exit(1);
+
+ // Close stdin
+ freopen("/dev/null", "r", stdin);
+
+ if (args.Length() > 0 && args[0]->IsInt32()) {
+ new_fd = args[0]->Int32Value();
+ dup2(new_fd, STDOUT_FILENO);
+ dup2(new_fd, STDERR_FILENO);
+ }
+ else {
+ freopen("/dev/null", "w", stderr);
+ freopen("/dev/null", "w", stdout);
+ }
+ }
+
+ return scope.Close(Number::New(getpid()));
+}
+
+//
+// Close stdin by redirecting it to /dev/null
+//
+Handle<Value> CloseStdin(const Arguments& args) {
+ freopen("/dev/null", "r", stdin);
+}
+
+//
+// Close stderr by redirecting to /dev/null
+//
+Handle<Value> CloseStderr(const Arguments& args) {
+ freopen("/dev/null", "w", stderr);
+}
+
+//
+// Close stdout by redirecting to /dev/null
+//
+Handle<Value> CloseStdout(const Arguments& args) {
+ freopen("/dev/null", "w", stdout);
+}
+
+//
+// Closes all stdio by redirecting to /dev/null
+//
+Handle<Value> CloseStdio(const Arguments& args) {
+ freopen("/dev/null", "r", stdin);
+ freopen("/dev/null", "w", stderr);
+ freopen("/dev/null", "w", stdout);
+}
+
+//
+// File-lock to make sure that only one instance of daemon is running, also for storing pid
+// lock (filename)
+// @filename: a path to a lock-file.
+//
+// Note: if filename doesn't exist, it will be created when function is called.
+//
+Handle<Value> LockD(const Arguments& args) {
+ if (!args[0]->IsString())
+ return Boolean::New(false);
+
+ String::Utf8Value data(args[0]->ToString());
+ char pid_str[PID_MAXLEN+1];
+
+ int lfp = open(*data, O_RDWR | O_CREAT | O_TRUNC, 0640);
+ if(lfp < 0) exit(1);
+ if(lockf(lfp, F_TLOCK, 0) < 0) return Boolean::New(false);
+
+ int len = snprintf(pid_str, PID_MAXLEN, "%d", getpid());
+ write(lfp, pid_str, len);
+ fsync(lfp);
+
+ return Boolean::New(true);
+}
+
+Handle<Value> SetSid(const Arguments& args) {
+ pid_t sid;
+ sid = setsid();
+ return Integer::New(sid);
+}
+
+const char* ToCString(const v8::String::Utf8Value& value) {
+ return *value ? *value : "<string conversion failed>";
+}
+
+//
+// Set the chroot of this process. You probably want to be sure stuff is in here.
+// chroot (folder)
+// @folder {string}: The new root
+//
+Handle<Value> Chroot(const Arguments& args) {
+ if (args.Length() < 1) {
+ return ThrowException(Exception::TypeError(
+ String::New("Must have one argument; a string of the folder to chroot to.")
+ ));
+ }
+ uid_t uid;
+ int rv;
+
+ String::Utf8Value folderUtf8(args[0]->ToString());
+ const char *folder = ToCString(folderUtf8);
+ rv = chroot(folder);
+ if (rv != 0) {
+ return ThrowException(ErrnoException(errno, "chroot"));
+ }
+ chdir("/");
+
+ return Boolean::New(true);
+}
+
+//
+// Allow changing the real and effective user ID of this process
+// so a root process can become unprivileged
+//
+Handle<Value> SetReuid(const Arguments& args) {
+ if (args.Length() == 0 || (!args[0]->IsString() && !args[0]->IsInt32()))
+ return ThrowException(Exception::Error(
+ String::New("Must give a uid or username to become")
+ ));
+
+ if (args[0]->IsString()) {
+ String::AsciiValue username(args[0]);
+
+ struct passwd* pwd_entry = getpwnam(*username);
+
+ if (pwd_entry) {
+ setreuid(pwd_entry->pw_uid, pwd_entry->pw_uid);
+ }
+ else {
+ return ThrowException(Exception::Error(
+ String::New("User not found")
+ ));
+ }
+ }
+ else if (args[0]->IsInt32()) {
+ uid_t uid;
+ uid = args[0]->Int32Value();
+ setreuid(uid, uid);
+ }
+}
+
+//
+// Initialize this add-on
+//
+extern "C" void init(Handle<Object> target) {
+ HandleScope scope;
+
+ NODE_SET_METHOD(target, "start", Start);
+ NODE_SET_METHOD(target, "lock", LockD);
+ NODE_SET_METHOD(target, "setsid", SetSid);
+ NODE_SET_METHOD(target, "chroot", Chroot);
+ NODE_SET_METHOD(target, "setreuid", SetReuid);
+ NODE_SET_METHOD(target, "closeStderr", CloseStderr);
+ NODE_SET_METHOD(target, "closeStdout", CloseStdout);
+ NODE_SET_METHOD(target, "closeStdin", CloseStdin);
+ NODE_SET_METHOD(target, "closeStdio", CloseStdio);
+}
View
8 wscript
@@ -1,3 +1,7 @@
+import Options
+from os import unlink, symlink
+from os.path import exists
+
srcdir = "."
blddir = "build"
VERSION = "0.1.0"
@@ -11,5 +15,5 @@ def configure(conf):
def build(bld):
obj = bld.new_task_gen("cxx", "shlib", "node_addon")
- obj.target = "daemon-tools"
- obj.source = "daemon-tools.cc"
+ obj.target = "daemon"
+ obj.source = bld.glob("src/daemon.cc")
Please sign in to comment.
Something went wrong with that request. Please try again.