#include "log.h"
-#define UXC_VERSION "0.2"
+#define UXC_VERSION "0.3"
#define OCI_VERSION_STRING "1.0.2"
#define UXC_ETC_CONFDIR "/etc/uxc"
#define UXC_VOL_CONFDIR "/tmp/run/uvol/.meta/uxc"
printf("\tenable <conf>\t\t\t\tstart container <conf> on boot\n");
printf("\tdisable <conf>\t\t\t\tdon't start container <conf> on boot\n");
printf("\tdelete <conf> [--force]\t\t\tdelete <conf>\n");
- return EINVAL;
+ return -EINVAL;
}
enum {
struct blob_buf *target;
if (asprintf(&globstr, "%s/%s*.json", UXC_ETC_CONFDIR, load_settings?"settings/":"") == -1)
- return ENOMEM;
+ return -ENOMEM;
res = glob(globstr, gl_flags, NULL, &gl);
if (res == 0)
if (!stat(UXC_VOL_CONFDIR, &sb)) {
if (sb.st_mode & S_IFDIR) {
if (asprintf(&globstr, "%s/%s*.json", UXC_VOL_CONFDIR, load_settings?"settings/":"") == -1)
- return ENOMEM;
+ return -ENOMEM;
res = glob(globstr, gl_flags, NULL, &gl);
free(globstr);
free(item);
}
- blob_buf_free(&settingsbuf);
return;
}
avl_init(&runtime, avl_strcmp, false, NULL);
if (ubus_lookup_id(ctx, "container", &id) ||
ubus_invoke(ctx, id, "list", NULL, list_cb, &runtime, 3000))
- return EIO;
+ return -EIO;
avl_for_each_element_safe(&runtime, item, avl, tmp)
get_ocistate(&item->ocistate, item->jail_name);
struct termios newtios;
if (!isatty(fd)) {
- return -1;
+ return -EIO;
}
/* Get current termios */
- if (tcgetattr(fd, oldtios))
- return -1;
+ if (tcgetattr(fd, oldtios) < 0)
+ return -errno;
newtios = *oldtios;
newtios.c_cc[VTIME] = 0;
/* Set new attributes */
- if (tcsetattr(fd, TCSAFLUSH, &newtios))
- return -1;
+ if (tcsetattr(fd, TCSAFLUSH, &newtios) < 0)
+ return -errno;
return 0;
}
ctx = ubus_connect(NULL);
if (!ctx) {
fprintf(stderr, "can't connect to ubus!\n");
- return -1;
+ return -ECONNREFUSED;
}
/* open pseudo-terminal pair */
if (client_fd < 0) {
fprintf(stderr, "can't create virtual console!\n");
ubus_free(ctx);
- return -1;
+ return -EIO;
}
setup_tios(client_fd, &oldtermios);
grantpt(client_fd);
fprintf(stderr, "can't open virtual console!\n");
close(client_fd);
ubus_free(ctx);
- return -1;
+ return -EIO;
}
setup_tios(server_fd, &oldtermios);
close(server_fd);
close(client_fd);
ubus_free(ctx);
- return -1;
+ return -EIO;
}
setup_tios(tty_fd, &oldtermios);
close(client_fd);
blob_buf_free(&req);
ubus_free(ctx);
- return -2;
+ return -ENXIO;
}
close(server_fd);
if (ocistate) {
state = blobmsg_format_json_indent(ocistate, true, 0);
if (!state)
- return 1;
+ return -ENOMEM;
printf("%s\n", state);
free(state);
}
if (!bundle)
- return ENOENT;
+ return -ENOENT;
blob_buf_init(&buf, 0);
blobmsg_add_string(&buf, "ociVersion", OCI_VERSION_STRING);
tmp = blobmsg_format_json_indent(buf.head, true, 0);
if (!tmp) {
blob_buf_free(&buf);
- return ENOMEM;
+ return -ENOMEM;
}
printf("%s\n", tmp);
tmp = blobmsg_format_json_indent(buf.head, true, 0);
if (!tmp) {
blob_buf_free(&buf);
- return ENOMEM;
+ return -ENOMEM;
}
printf("%s\n", tmp);
free(tmp);
return 0;
}
+static int uxc_exists(char *name)
+{
+ struct runtime_state *rsstate = NULL;
+ rsstate = avl_find_element(&runtime, name, rsstate, avl);
+
+ if (rsstate && (rsstate->running))
+ return -EEXIST;
+
+ return 0;
+}
+
static int uxc_create(char *name, bool immediately)
{
static struct blob_buf req;
struct blob_attr *cur, *tb[__CONF_MAX];
- int rem, ret;
+ int rem, ret = 0;
uint32_t id;
- struct runtime_state *rsstate = NULL;
struct settings *usettings = NULL;
char *path = NULL, *jailname = NULL, *pidfile = NULL, *tmprwsize = NULL, *writepath = NULL;
void *in, *ins, *j;
bool found = false;
- rsstate = avl_find_element(&runtime, name, rsstate, avl);
-
- if (rsstate && (rsstate->running))
- return EEXIST;
-
blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
if (!tb[CONF_NAME] || !tb[CONF_PATH])
}
if (!found)
- return ENOENT;
+ return -ENOENT;
path = blobmsg_get_string(tb[CONF_PATH]);
char *tmp;
tmp = blobmsg_format_json_indent(req.head, true, 1);
if (!tmp)
- return ENOMEM;
+ return -ENOMEM;
fprintf(stderr, "adding container to procd:\n\t%s\n", tmp);
free(tmp);
}
- ret = 0;
if (ubus_lookup_id(ctx, "container", &id) ||
ubus_invoke(ctx, id, "add", req.head, NULL, NULL, 3000)) {
blob_buf_free(&req);
- ret = EIO;
+ ret = -EIO;
}
return ret;
}
if (asprintf(&objname, "container.%s", name) == -1)
- return ENOMEM;
+ return -ENOMEM;
if (ubus_lookup_id(ctx, objname, &id))
- return ENOENT;
+ return -ENOENT;
free(objname);
return ubus_invoke(ctx, id, "start", NULL, NULL, NULL, 3000);
}
if (!found)
- return ENOENT;
+ return -ENOENT;
rsstate = avl_find_element(&runtime, name, rsstate, avl);
if (!rsstate || !(rsstate->running))
- return ENOENT;
+ return -ENOENT;
blob_buf_init(&req, 0);
blobmsg_add_u32(&req, "signal", signal);
blobmsg_add_string(&req, "name", name);
if (asprintf(&objname, "container.%s", name) == -1)
- return ENOMEM;
+ return -ENOMEM;
ret = ubus_lookup_id(ctx, objname, &id);
free(objname);
if (ret)
- return ENOENT;
+ return -ENOENT;
if (ubus_invoke(ctx, id, "kill", req.head, NULL, NULL, 3000))
- return EIO;
+ return -EIO;
return 0;
}
-static int uxc_set(char *name, char *path, signed char _autostart, bool add, char *pidfile, char *_tmprwsize, char *_writepath, char *requiredmounts)
+static int uxc_set(char *name, char *path, signed char autostart, char *pidfile, char *tmprwsize, char *writepath, char *requiredmounts)
{
static struct blob_buf req;
struct settings *usettings = NULL;
const char *cfname = NULL;
const char *sfname = NULL;
char *fname = NULL;
- char *tmprwsize = NULL;
- char *writepath = NULL;
char *curvol, *tmp, *mnttok;
void *mntarr;
int f;
struct stat sb;
- signed char autostart = -1;
- if (add) {
- tmprwsize = _tmprwsize;
- writepath = _writepath;
- autostart = _autostart;
- }
+ /* nothing to do */
+ if (!path && (autostart<0) && !pidfile && !tmprwsize && !writepath && !requiredmounts)
+ return 0;
blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
break;
}
- if (cfname && add)
- return EEXIST;
-
- if (!cfname && !add)
- return ENOENT;
+ if (cfname && path)
+ return -EEXIST;
- if (add && !path)
- return EINVAL;
+ if (!cfname && !path)
+ return -ENOENT;
if (path) {
if (stat(path, &sb) == -1)
- return ENOENT;
+ return -ENOENT;
if ((sb.st_mode & S_IFMT) != S_IFDIR)
- return ENOTDIR;
+ return -ENOTDIR;
}
usettings = avl_find_element(&settings, blobmsg_get_string(tb[CONF_NAME]), usettings, avl);
- if (!add && usettings) {
+ if (path && usettings)
+ return -EIO;
+
+ if (usettings) {
sfname = usettings->fname;
- if (usettings->tmprwsize) {
- tmprwsize = usettings->tmprwsize;
- writepath = NULL;
- }
- if (usettings->writepath) {
- writepath = usettings->writepath;
- tmprwsize = NULL;
+ if (!tmprwsize && !writepath) {
+ if (usettings->tmprwsize) {
+ tmprwsize = usettings->tmprwsize;
+ writepath = NULL;
+ }
+ if (usettings->writepath) {
+ writepath = usettings->writepath;
+ tmprwsize = NULL;
+ }
}
- if (usettings->autostart >= 0)
+ if (usettings->autostart >= 0 && autostart < 0)
autostart = !!(usettings->autostart);
-
- if (_autostart >= 0)
- autostart = _autostart;
}
- if (add) {
+ if (path) {
ret = mkdir(confdir, 0755);
if (ret && errno != EEXIST)
- return ret;
+ return -errno;
if (asprintf(&fname, "%s/%s.json", confdir, name) == -1)
- return ENOMEM;
+ return -ENOMEM;
f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (f < 0)
- return errno;
+ return -errno;
free(fname);
} else {
char *t1, *t2;
t1 = strdup(cfname);
t2 = strrchr(t1, '/');
+ if (!t2)
+ return -EINVAL;
+
*t2 = '\0';
- if (asprintf(&t2, "%s/settings", t1, name) == -1)
- return ENOMEM;
+ if (asprintf(&t2, "%s/settings", t1) == -1)
+ return -ENOMEM;
ret = mkdir(t2, 0755);
if (ret && ret != EEXIST)
- return ret;
+ return -ret;
free(t2);
if (asprintf(&t2, "%s/settings/%s.json", t1, name) == -1)
- return ENOMEM;
+ return -ENOMEM;
free(t1);
f = open(t2, O_WRONLY | O_CREAT | O_TRUNC, 0644);
free(t2);
}
if (f < 0)
- return errno;
+ return -errno;
}
blob_buf_init(&req, 0);
blobmsg_add_string(&req, "name", name);
- if (add)
+ if (path)
blobmsg_add_string(&req, "path", path);
if (autostart >= 0)
if (writepath)
blobmsg_add_string(&req, "write-overlay-path", writepath);
- if (!add && usettings && usettings->volumes)
+ if (!requiredmounts && usettings && usettings->volumes)
blobmsg_add_blob(&req, usettings->volumes);
- if (add && requiredmounts) {
+ if (requiredmounts) {
mntarr = blobmsg_open_array(&req, "volumes");
for (mnttok = requiredmounts; ; mnttok = NULL) {
curvol = strtok_r(mnttok, ",;", &tmp);
blob_buf_free(&req);
close(f);
- return 0;
+ return 1;
}
enum {
/* check if device 'devname' is mounted according to blockd */
-static int checkblock(const char *uuid)
+static bool checkblock(const char *uuid)
{
struct blob_attr *tb[__BLOCK_INFO_MAX];
struct blob_attr *cur;
continue;
if (!strcmp(uuid, blobmsg_get_string(tb[BLOCK_INFO_UUID])))
- return 0;
+ return false;
}
- return 1;
+ return true;
}
enum {
};
/* check status of each required volume */
-static int checkvolumes(struct blob_attr *volumes)
+static bool checkvolumes(struct blob_attr *volumes)
{
struct blob_attr *cur;
int rem;
blobmsg_for_each_attr(cur, volumes, rem) {
if (checkblock(resolveuuid(blobmsg_get_string(cur))))
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static void block_cb(struct ubus_request *req, int type, struct blob_attr *msg)
ret = ubus_lookup_id(ctx, "block", &id);
if (ret)
- return ENOENT;
+ return -ENOENT;
ret = ubus_invoke(ctx, id, "info", NULL, block_cb, NULL, 3000);
if (ret)
- return ENXIO;
+ return -ENXIO;
ret = ubus_lookup_id(ctx, "uci", &id);
if (ret)
- return ENOENT;
+ return -ENOENT;
blob_buf_init(&req, 0);
blobmsg_add_string(&req, "config", "fstab");
ret = ubus_invoke(ctx, id, "get", req.head, fstab_cb, NULL, 3000);
if (ret)
- return ENXIO;
+ return ret;
blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
continue;
name = strdup(blobmsg_get_string(tb[CONF_NAME]));
- ret += uxc_create(name, true);
+ if (uxc_exists(name))
+ continue;
+
+ if (uxc_create(name, true))
+ ++ret;
+
free(name);
}
}
if (!cfname)
- return ENOENT;
+ return -ENOENT;
rsstate = avl_find_element(&runtime, name, rsstate, avl);
goto errout;
} else {
- ret = EWOULDBLOCK;
+ ret = -EWOULDBLOCK;
goto errout;
}
}
if (ubus_invoke(ctx, id, "delete", req.head, NULL, NULL, 3000)) {
blob_buf_free(&req);
- ret = EIO;
+ ret = -EIO;
goto errout;
}
}
if (sfname) {
if (stat(sfname, &sb) == -1) {
- ret = ENOENT;
+ ret = -ENOENT;
goto errout;
}
if (unlink(sfname) == -1) {
- ret = errno;
+ ret = -errno;
goto errout;
}
}
if (stat(cfname, &sb) == -1) {
- ret = ENOENT;
+ ret = -ENOENT;
goto errout;
}
if (unlink(cfname) == -1)
- ret = errno;
+ ret = -errno;
errout:
return ret;
blob_buf_free(&conf);
conf_load(false);
settings_free();
+ blob_buf_free(&settingsbuf);
conf_load(true);
settings_add();
}
int main(int argc, char **argv)
{
enum uxc_cmd cmd = CMD_UNKNOWN;
- int ret = EINVAL;
+ int ret = -EINVAL;
char *bundle = NULL;
char *pidfile = NULL;
char *tmprwsize = NULL;
ctx = ubus_connect(NULL);
if (!ctx)
- return ENODEV;
+ return -ENODEV;
ret = conf_load(false);
- if (ret)
+ if (ret < 0)
goto out;
- conf_load(true);
- settings_add();
+ ret = conf_load(true);
+ if (ret < 0)
+ goto conf_out;
+
+ ret = settings_add();
+ if (ret < 0)
+ goto settings_out;
ret = runtime_load();
if (ret)
- goto conf_out;
+ goto settings_avl_out;
while (true) {
int option_index = 0;
if (optind != argc - 2)
goto usage_out;
- ret = uxc_set(argv[optind + 1], NULL, 1, false, NULL, NULL, NULL, NULL);
+ ret = uxc_set(argv[optind + 1], NULL, 1, NULL, NULL, NULL, NULL);
break;
case CMD_DISABLE:
if (optind != argc - 2)
goto usage_out;
- ret = uxc_set(argv[optind + 1], NULL, 0, false, NULL, NULL, NULL, NULL);
+ ret = uxc_set(argv[optind + 1], NULL, 0, NULL, NULL, NULL, NULL);
break;
case CMD_DELETE:
if (optind != argc - 2)
goto usage_out;
- if (bundle) {
- ret = uxc_set(argv[optind + 1], bundle, autostart, true, pidfile, tmprwsize, writepath, requiredmounts);
- if (ret)
- goto runtime_out;
+ ret = uxc_exists(argv[optind + 1]);
+ if (ret)
+ goto runtime_out;
+
+ ret = uxc_set(argv[optind + 1], bundle, autostart, pidfile, tmprwsize, writepath, requiredmounts);
+ if (ret < 0)
+ goto runtime_out;
+ if (ret > 0)
reload_conf();
- }
ret = uxc_create(argv[optind + 1], false);
break;
goto runtime_out;
usage_out:
- usage();
+ ret = usage();
runtime_out:
runtime_free();
+settings_avl_out:
+ settings_free();
+settings_out:
+ blob_buf_free(&settingsbuf);
conf_out:
blob_buf_free(&conf);
out:
ubus_free(ctx);
- if (ret != 0)
- fprintf(stderr, "uxc error: %s\n", strerror(ret));
+ if (ret < 0)
+ fprintf(stderr, "uxc error: %s\n", strerror(-ret));
return ret;
}