Browse Source

replaced node-udev with my own code

master
mortie 7 years ago
parent
commit
323562da16
10 changed files with 470 additions and 25 deletions
  1. 1
    0
      .gitignore
  2. 2
    0
      dedaemon.js
  3. 6
    9
      modules/display/index.js
  4. 7
    12
      modules/input/index.js
  5. 4
    4
      package.json
  6. 10
    0
      udev/Makefile
  7. 78
    0
      udev/index.js
  8. 59
    0
      udev/src/json.c
  9. 16
    0
      udev/src/json.h
  10. 287
    0
      udev/src/main.c

+ 1
- 0
.gitignore View File

@@ -1 +1,2 @@
node_modules
udev/udev-monitor

+ 2
- 0
dedaemon.js View File

@@ -3,6 +3,7 @@
var syscheck = require("./js/syscheck");
var parseConf = require("./js/parse-conf");
var async = require("./js/async");
var udev = require("./udev");

var modules = {
// display: require("./modules/display"),
@@ -49,6 +50,7 @@ function stopAll(cb) {
}

function onTerm() {
udev.exit();
stopAll(() => process.exit(1));
}


+ 6
- 9
modules/display/index.js View File

@@ -1,4 +1,4 @@
var udev = require("udev");
var udev = require("../../udev");

exports.start = start;
exports.stop = stop;
@@ -8,12 +8,10 @@ var conf;
var logger;
var modules;

var monitor;

function onchange(dev, evt) {
if (evt === "add")
function onchange(dev) {
if (dev.ACTION === "add")
logger.info("display added");
else if (evt === "change")
else if (dev.ACTION === "change")
logger.info("display changed");
else
logger.info(dev);
@@ -26,12 +24,11 @@ function start(conf_, logger_, modules_) {
logger = logger_ || logger;
modules = modules_ || modules;

monitor = udev.monitor("drm");
monitor.on("add", dev => onchange(dev, "add"));
monitor.on("change", dev => onchange(dev, "change"));
udev.monitor("drm", onchange);
}

function stop(cb) {
udev.unmonitor("drm", onchange);
cb();
}


+ 7
- 12
modules/input/index.js View File

@@ -1,4 +1,4 @@
var udev = require("udev");
var udev = require("../../udev");
var spawn = require("child_process").spawn;
var exec = require("child_process").exec;

@@ -12,8 +12,6 @@ var conf;
var logger;
var modules;

var monitor;

// Set an xinput property
function setProp(name, val, suppressWarnings) {
var args = [ "--set-prop", name ];
@@ -90,7 +88,7 @@ function nameMatches(dev, name) {
return true;
}

function onchange(dev, evt) {
function onchange(dev) {
if (!filter(dev))
return;

@@ -107,9 +105,9 @@ function onchange(dev, evt) {
inputType = "mouse";

// Log add/change
if (evt === "add")
if (dev.ACTION === "add")
logger.info(inputType, dev.NAME, "added");
else if (evt === "change")
else if (dev.ACTION === "change")
logger.info(inputType, dev.NAME, "changed");

// Run through and apply relevant rules
@@ -151,15 +149,12 @@ function start(conf_, logger_, modules_) {
logger = logger_ || logger;
modules = modules_ || modules;

udev.list("input").forEach(dev => onchange(dev, "init"));

monitor = udev.monitor("input");
monitor.on("add", dev => onchange(dev, "add"));
monitor.on("change", dev => onchange(dev, "change"));
udev.list("input", devs => devs.forEach(onchange))
udev.monitor("input", onchange);
}

function stop(cb) {
monitor.close();
udev.unmonitor("input", onchange);
cb();
}


+ 4
- 4
package.json View File

@@ -1,10 +1,11 @@
{
"name": "dedaemon",
"version": "0.0.1",
"version": "0.1.0",
"description": "",
"main": "daemon.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "echo \"Error: no test specified\" && exit 1",
"postinstall": "make -C udev"
},
"repository": {
"type": "git",
@@ -13,8 +14,7 @@
"author": "Martin Dørum Nygaard <martid0311@gmail.com> (http://mort.coffee)",
"license": "ISC",
"dependencies": {
"hconfig": "^0.4.0",
"udev": "^0.4.0"
"hconfig": "^0.4.0"
},
"bin": {
"dedaemon": "./dedaemon.js"

+ 10
- 0
udev/Makefile View File

@@ -0,0 +1,10 @@
TARGET=udev-monitor

SRC=src/main.c src/json.c
HDR=src/json.h

$(TARGET): $(SRC) $(HDR)
$(CC) -o $(TARGET) -g $(shell pkg-config --cflags --libs libudev) $(SRC)

clean:
rm -f $(TARGET)

+ 78
- 0
udev/index.js View File

@@ -0,0 +1,78 @@
var spawn = require("child_process").spawn;

var child = spawn(__dirname+"/udev-monitor");

exports.list = list;
exports.monitor = monitor;
exports.unmonitor = unmonitor;
exports.exit = exit;

var currstr = "";
child.stdout.setEncoding("utf8");
child.stdout.on("data", d => {
var lines = d.toString().split("\n");

currstr += lines[0];
if (lines.length === 1)
return;

ondata(JSON.parse(currstr));

for (var i = 1; i < lines.length -1; ++i) {
ondata(JSON.parse(lines[i]));
}

currstr = lines[lines.length - 1];
});
child.stderr.on("data", d => console.error(d.toString()));

var listq = [];
var monitors = {};

function ondata(obj) {
if (obj instanceof Array) {
if (listq.length === 0)
return;
var cb = listq.shift();
cb(obj);
} else {
var ss = obj.SUBSYSTEM;
if (monitors[ss]) {
monitors[ss].forEach(cb => cb(obj));
}
if (monitors["*"]) {
monitors["*"].forEach(cb => cb(obj));
}
}
}

function list(ss, cb) {
listq.push(cb);
child.stdin.write("list:"+ss+"\n");
}

function monitor(ss, cb) {
if (monitors[ss] == null) {
child.stdin.write("monitor:"+ss+"\n");
monitors[ss] = [];
}

monitors[ss].push(cb);
}

function unmonitor(ss, cb) {
if (monitors[ss] == null)
throw new Error("Callback function for "+ss+" not registered");

var removed = false;
for (var i in monitors[ss]) {
if (monitors[ss][i] === cb) {
monitors[ss].splice(i, 1);
removed = true;
}
}
}

function exit() {
child.kill("SIGTERM");
}

+ 59
- 0
udev/src/json.c View File

@@ -0,0 +1,59 @@
#include "json.h"
#include <stdio.h>

void json_str(FILE *f, const char *str)
{
int start, i;
char c;

fprintf(f, "\"");

start = 0;
i = 0;
while (1)
{
c = str[i];
if (c == '\0')
{
fwrite(str + start, 1, i - start, f);
break;
}
else if (c == '\\' || c == '\"')
{
fwrite(str + start, 1, i - start, f);
fprintf(f, "\\%c", str[i]);
start = i + 1;
}

i += 1;
}

fprintf(f, "\"");
}
void json_sep(FILE *f)
{
fprintf(f, ",");
}

void json_obj_start(FILE *f)
{
fprintf(f, "{");
}
void json_obj_key(FILE *f, const char *key)
{
json_str(f, key);
fprintf(f, ":");
}
void json_obj_end(FILE *f)
{
fprintf(f, "}");
}

void json_arr_start(FILE *f)
{
fprintf(f, "[");
}
void json_arr_end(FILE *f)
{
fprintf(f, "]");
}

+ 16
- 0
udev/src/json.h View File

@@ -0,0 +1,16 @@
#ifndef JSON_H
#define JSON_H

#include <stdio.h>

void json_str(FILE *f, const char *str);
void json_sep(FILE *f);

void json_obj_start(FILE *f);
void json_obj_key(FILE *f, const char *key);
void json_obj_end(FILE *f);

void json_arr_start(FILE *f);
void json_arr_end(FILE *f);

#endif

+ 287
- 0
udev/src/main.c View File

@@ -0,0 +1,287 @@
#include "json.h"
#include <libudev.h>
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>

struct udev *udev;

FILE *out;

struct listener
{
struct udev_monitor *mon;
int fd;
};

struct listener listeners[32];
int listenerc = 0;

struct udev_monitor *mons[32];

static void devinfo_print_json(
FILE *f,
struct udev *udev,
struct udev_device *dev)
{
struct udev_list_entry *entry, *sysattrs;
int first;
const char *key, *val;

json_obj_start(f);

sysattrs = udev_device_get_properties_list_entry(dev);
first = 1;
udev_list_entry_foreach(entry, sysattrs)
{
key = udev_list_entry_get_name(entry);
val = udev_list_entry_get_value(entry);

if (!first)
json_sep(f);
json_obj_key(f, key);
json_str(f, val);

first = 0;
}

json_obj_end(f);

udev_device_unref(dev);
}

static void enumerate(FILE *f, const char *subsystem)
{
struct udev_enumerate *en;
struct udev_list_entry *device, *devices;
struct udev_device *dev;
int first;
const char *name;

// Create enumerator
en = udev_enumerate_new(udev);
if (subsystem != NULL)
udev_enumerate_add_match_subsystem(en, subsystem);

json_arr_start(f);

// Enumerate
udev_enumerate_scan_devices(en);
devices = udev_enumerate_get_list_entry(en);
first = 1;
udev_list_entry_foreach(device, devices)
{
if (!first)
json_sep(f);

name = udev_list_entry_get_name(device);
dev = udev_device_new_from_syspath(udev, name);
devinfo_print_json(f, udev, dev);

first = 0;
}

json_arr_end(f);

printf("\n");
fflush(f);

udev_enumerate_unref(en);
}

int monitor(const char *subsystem)
{
struct udev_monitor *mon;
struct listener *l;

mon = udev_monitor_new_from_netlink(udev, "udev");
if (!mon)
return -1;

if (subsystem != NULL)
{
udev_monitor_filter_add_match_subsystem_devtype(
mon, subsystem, NULL);
}
udev_monitor_enable_receiving(mon);

l = &listeners[listenerc++];
l->mon = mon;
l->fd = udev_monitor_get_fd(mon);

return 0;
}

void oncommand(struct listener *l)
{
char buf[1024];
char *cmd, *arg;
int cnt, i;
char c;

memset(buf, 0, sizeof(buf));

cnt = read(l->fd, buf, sizeof(buf));
if (cnt == -1)
{
perror("stdin");
return;
}
else if (cnt == 0)
{
// don't try to read from stdin anymore if it's closed
l->fd = -1;
return;
}
else if (cnt == sizeof(buf))
{
fprintf(stderr, "input buffer too big\n");

// drain, so we don't end up reading stale data next time
do {
cnt = read(l->fd, buf, sizeof(buf));
if (cnt == -1)
{
perror("stdin");
return;
}
} while (cnt == sizeof(buf));
return;
}

// parse input into command and argument
cmd = buf;
arg = NULL;
i = 0;
while (1)
{
c = buf[i];

// colon: replace with \0 to terminate cmd,
// update arg to point to the charcater after :
if (c == ':')
{
buf[i] = '\0';
arg = buf + i + 1;
}

// newline: replace with \0 to terminate arg,
// respond to request, then update cmd and
// continue reading the buffer until we reach a \0
else if (c == '\n' || c == '\0')
{
buf[i] = '\0';

if (*cmd == '\0')
break;

// respond to request
if (strcmp(cmd, "list") == 0)
{
if (strcmp(arg, "*") == 0)
enumerate(out, NULL);
else
enumerate(out, arg);
}
else if (strcmp(cmd, "monitor") == 0)
{
if (strcmp(arg, "*") == 0)
monitor(NULL);
else
monitor(arg);
}
else
{
fprintf(stderr, "Unknown command: %s\n", cmd);
}

if (c == '\0')
break;

cmd = buf + i + 1;
}

i += 1;
}
}

void onevent(struct listener *l)
{
struct udev_device *dev = udev_monitor_receive_device(l->mon);
if (!dev)
{
fprintf(stderr, "No device even though an event occurred.\n");
return;
}

devinfo_print_json(out, udev, dev);
printf("\n");
fflush(out);
}

void readinput()
{
fd_set set;
FD_ZERO(&set);
int max = -1;
for (int i = 0; i < listenerc; ++i)
{
int fd = listeners[i].fd;
if (fd == -1)
continue;
FD_SET(fd, &set);
if (fd > max)
max = fd;
}

int activity;

activity = select(max + 1, &set, NULL, NULL, NULL);
if (activity < 0)
{
if (errno != EINTR)
perror("select");
return;
}

for (int i = 0; i < listenerc; ++i)
{
struct listener *l = &listeners[i];
int fd = l->fd;
if (!FD_ISSET(fd, &set))
continue;

if (fd == STDIN_FILENO)
oncommand(l);
else
onevent(l);
}
}

int main()
{
out = stdout;
memset(listeners, 0, sizeof(listeners));

// read stdin
listeners[listenerc++].fd = STDIN_FILENO;

// create udev
udev = udev_new();
if (!udev)
{
fprintf(stderr, "Failed to craete udev\n");
return 1;
}

// main loop
while (1) {
readinput();
}

udev_unref(udev);
}

Loading…
Cancel
Save