diff options
Diffstat (limited to 'modules/luci-base/src/lib')
-rw-r--r-- | modules/luci-base/src/lib/lmo.c | 636 | ||||
-rw-r--r-- | modules/luci-base/src/lib/lmo.h | 108 | ||||
-rw-r--r-- | modules/luci-base/src/lib/luci.c | 383 | ||||
-rw-r--r-- | modules/luci-base/src/lib/plural_formula.y | 43 |
4 files changed, 1170 insertions, 0 deletions
diff --git a/modules/luci-base/src/lib/lmo.c b/modules/luci-base/src/lib/lmo.c new file mode 100644 index 0000000000..da521bc98b --- /dev/null +++ b/modules/luci-base/src/lib/lmo.c @@ -0,0 +1,636 @@ +/* + * lmo - Lua Machine Objects - Base functions + * + * Copyright (C) 2009-2010 Jo-Philipp Wich <jow@openwrt.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lmo.h" +#include "plural_formula.h" + +/* + * Hash function from http://www.azillionmonkeys.com/qed/hash.html + * Copyright (C) 2004-2008 by Paul Hsieh + */ + +uint32_t sfh_hash(const char *data, size_t len, uint32_t init) +{ + uint32_t hash = init, tmp; + int rem; + + if (len <= 0 || data == NULL) return 0; + + rem = len & 3; + len >>= 2; + + /* Main loop */ + for (;len > 0; len--) { + hash += sfh_get16(data); + tmp = (sfh_get16(data+2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + data += 2*sizeof(uint16_t); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) { + case 3: hash += sfh_get16(data); + hash ^= hash << 16; + hash ^= (signed char)data[sizeof(uint16_t)] << 18; + hash += hash >> 11; + break; + case 2: hash += sfh_get16(data); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: hash += (signed char)*data; + hash ^= hash << 10; + hash += hash >> 1; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; +} + +uint32_t lmo_canon_hash(const char *str, int len, + const char *ctx, int ctxlen, int plural) +{ + char res[4096]; + char *ptr, *end, prev; + int off; + + if (!str) + return 0; + + ptr = res; + end = res + sizeof(res); + + if (ctx) + { + for (prev = ' ', off = 0; off < ctxlen; prev = *ctx, off++, ctx++) + { + if (ptr >= end) + return 0; + + if (isspace(*ctx)) + { + if (!isspace(prev)) + *ptr++ = ' '; + } + else + { + *ptr++ = *ctx; + } + } + + if ((ptr > res) && isspace(*(ptr-1))) + ptr--; + + if (ptr >= end) + return 0; + + *ptr++ = '\1'; + } + + for (prev = ' ', off = 0; off < len; prev = *str, off++, str++) + { + if (ptr >= end) + return 0; + + if (isspace(*str)) + { + if (!isspace(prev)) + *ptr++ = ' '; + } + else + { + *ptr++ = *str; + } + } + + if ((ptr > res) && isspace(*(ptr-1))) + ptr--; + + if (plural > -1) + { + if (plural >= 100 || ptr + 3 >= end) + return 0; + + ptr += snprintf(ptr, 3, "\2%d", plural); + } + + return sfh_hash(res, ptr - res, ptr - res); +} + +lmo_archive_t * lmo_open(const char *file) +{ + int in = -1; + uint32_t idx_offset = 0; + struct stat s; + + lmo_archive_t *ar = NULL; + + if (stat(file, &s) == -1) + goto err; + + if ((in = open(file, O_RDONLY)) == -1) + goto err; + + if ((ar = (lmo_archive_t *)malloc(sizeof(*ar))) != NULL) + { + memset(ar, 0, sizeof(*ar)); + + ar->fd = in; + ar->size = s.st_size; + + fcntl(ar->fd, F_SETFD, fcntl(ar->fd, F_GETFD) | FD_CLOEXEC); + + if ((ar->mmap = mmap(NULL, ar->size, PROT_READ, MAP_SHARED, ar->fd, 0)) == MAP_FAILED) + goto err; + + idx_offset = ntohl(*((const uint32_t *) + (ar->mmap + ar->size - sizeof(uint32_t)))); + + if (idx_offset >= ar->size) + goto err; + + ar->index = (lmo_entry_t *)(ar->mmap + idx_offset); + ar->length = (ar->size - idx_offset - sizeof(uint32_t)) / sizeof(lmo_entry_t); + ar->end = ar->mmap + ar->size; + + return ar; + } + +err: + if (in > -1) + close(in); + + if (ar != NULL) + { + if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED)) + munmap(ar->mmap, ar->size); + + free(ar); + } + + return NULL; +} + +void lmo_close(lmo_archive_t *ar) +{ + if (ar != NULL) + { + if ((ar->mmap != NULL) && (ar->mmap != MAP_FAILED)) + munmap(ar->mmap, ar->size); + + close(ar->fd); + free(ar); + + ar = NULL; + } +} + + +lmo_catalog_t *_lmo_catalogs = NULL; +lmo_catalog_t *_lmo_active_catalog = NULL; + +int lmo_load_catalog(const char *lang, const char *dir) +{ + DIR *dh = NULL; + char pattern[16]; + char path[PATH_MAX]; + struct dirent *de = NULL; + + lmo_archive_t *ar = NULL; + lmo_catalog_t *cat = NULL; + + if (!lmo_change_catalog(lang)) + return 0; + + if (!dir || !(dh = opendir(dir))) + goto err; + + if (!(cat = malloc(sizeof(*cat)))) + goto err; + + memset(cat, 0, sizeof(*cat)); + + snprintf(cat->lang, sizeof(cat->lang), "%s", lang); + snprintf(pattern, sizeof(pattern), "*.%s.lmo", lang); + + while ((de = readdir(dh)) != NULL) + { + if (!fnmatch(pattern, de->d_name, 0)) + { + snprintf(path, sizeof(path), "%s/%s", dir, de->d_name); + ar = lmo_open(path); + + if (ar) + { + ar->next = cat->archives; + cat->archives = ar; + } + } + } + + closedir(dh); + + cat->next = _lmo_catalogs; + _lmo_catalogs = cat; + + if (!_lmo_active_catalog) + _lmo_active_catalog = cat; + + return cat->archives ? 0 : -1; + +err: + if (dh) closedir(dh); + if (cat) free(cat); + + return -1; +} + +int lmo_change_catalog(const char *lang) +{ + lmo_catalog_t *cat; + + for (cat = _lmo_catalogs; cat; cat = cat->next) + { + if (!strncmp(cat->lang, lang, sizeof(cat->lang))) + { + _lmo_active_catalog = cat; + return 0; + } + } + + return -1; +} + +static lmo_entry_t * lmo_find_entry(lmo_archive_t *ar, uint32_t hash) +{ + unsigned int m, l, r; + uint32_t k; + + l = 0; + r = ar->length - 1; + + while (1) + { + m = l + ((r - l) / 2); + + if (r < l) + break; + + k = ntohl(ar->index[m].key_id); + + if (k == hash) + return &ar->index[m]; + + if (k > hash) + { + if (!m) + break; + + r = m - 1; + } + else + { + l = m + 1; + } + } + + return NULL; +} + +void *pluralParseAlloc(void *(*)(size_t)); +void pluralParse(void *, int, int, void *); +void pluralParseFree(void *, void (*)(void *)); + +static int lmo_eval_plural(const char *expr, int len, int val) +{ + struct { int num; int res; } s = { .num = val, .res = -1 }; + const char *p = NULL; + void *pParser = NULL; + int t, n; + char c; + + while (len > 7) { + if (*expr == 'p') { + if (!strncmp(expr, "plural=", 7)) { + p = expr + 7; + len -= 7; + break; + } + } + + expr++; + len--; + } + + if (!p) + goto out; + + pParser = pluralParseAlloc(malloc); + + if (!pParser) + goto out; + + while (len-- > 0) { + c = *p++; + t = -1; + n = 0; + + switch (c) { + case ' ': + case '\t': + continue; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + t = T_NUM; + n = c - '0'; + + while (*p >= '0' && *p <= '9') { + n *= 10; + n += *p - '0'; + p++; + } + + break; + + case '=': + if (*p == '=') { + t = T_EQ; + p++; + } + + break; + + case '!': + if (*p == '=') { + t = T_NE; + p++; + } + else { + t = T_NOT; + } + + break; + + case '&': + if (*p == '&') { + t = T_AND; + p++; + } + + break; + + case '|': + if (*p == '|') { + t = T_OR; + p++; + } + + break; + + case '<': + if (*p == '=') { + t = T_LE; + p++; + } + else { + t = T_LT; + } + + break; + + case '>': + if (*p == '=') { + t = T_GE; + p++; + } + else { + t = T_GT; + } + + break; + + case '*': + t = T_MUL; + break; + + case '/': + t = T_DIV; + break; + + case '%': + t = T_MOD; + break; + + case '+': + t = T_ADD; + break; + + case '-': + t = T_SUB; + break; + + case 'n': + t = T_N; + break; + + case '?': + t = T_QMARK; + break; + + case ':': + t = T_COLON; + break; + + case '(': + t = T_LPAREN; + break; + + case ')': + t = T_RPAREN; + break; + + case ';': + case '\n': + case '\0': + t = 0; + break; + } + + /* syntax error */ + if (t < 0) + goto out; + + pluralParse(pParser, t, n, &s); + + /* eof */ + if (t == 0) + break; + } + + pluralParse(pParser, 0, 0, &s); + +out: + pluralParseFree(pParser, free); + + return s.res; +} + +int lmo_translate(const char *key, int keylen, char **out, int *outlen) +{ + return lmo_translate_ctxt(key, keylen, NULL, 0, out, outlen); +} + +int lmo_translate_ctxt(const char *key, int keylen, + const char *ctx, int ctxlen, + char **out, int *outlen) +{ + uint32_t hash; + lmo_entry_t *e; + lmo_archive_t *ar; + + if (!key || !_lmo_active_catalog) + return -2; + + hash = lmo_canon_hash(key, keylen, ctx, ctxlen, -1); + + if (hash > 0) + { + for (ar = _lmo_active_catalog->archives; ar; ar = ar->next) + { + if ((e = lmo_find_entry(ar, hash)) != NULL) + { + *out = ar->mmap + ntohl(e->offset); + *outlen = ntohl(e->length); + return 0; + } + } + } + + return -1; +} + +int lmo_translate_plural(int n, const char *skey, int skeylen, + const char *pkey, int pkeylen, + char **out, int *outlen) +{ + return lmo_translate_plural_ctxt(n, skey, skeylen, pkey, pkeylen, + NULL, 0, out, outlen); +} + +int lmo_translate_plural_ctxt(int n, const char *skey, int skeylen, + const char *pkey, int pkeylen, + const char *ctx, int ctxlen, + char **out, int *outlen) +{ + int pid = -1; + uint32_t hash; + lmo_entry_t *e; + lmo_archive_t *ar; + + if (!skey || !pkey || !_lmo_active_catalog) + return -2; + + for (ar = _lmo_active_catalog->archives; ar; ar = ar->next) { + e = lmo_find_entry(ar, 0); + + if (e != NULL) { + pid = lmo_eval_plural(ar->mmap + ntohl(e->offset), ntohl(e->length), n); + break; + } + } + + if (pid == -1) + pid = (n != 1); + + hash = lmo_canon_hash(skey, skeylen, ctx, ctxlen, pid); + + if (hash == 0) + return -1; + + for (ar = _lmo_active_catalog->archives; ar; ar = ar->next) + { + if ((e = lmo_find_entry(ar, hash)) != NULL) + { + *out = ar->mmap + ntohl(e->offset); + *outlen = ntohl(e->length); + return 0; + } + } + + if (n != 1) + { + *out = (char *)pkey; + *outlen = pkeylen; + } + else + { + *out = (char *)skey; + *outlen = skeylen; + } + + return 0; +} + +void lmo_iterate(lmo_iterate_cb_t cb, void *priv) +{ + unsigned int i; + lmo_entry_t *e; + lmo_archive_t *ar; + + if (!_lmo_active_catalog) + return; + + for (ar = _lmo_active_catalog->archives; ar; ar = ar->next) + for (i = 0, e = &ar->index[0]; i < ar->length; e = &ar->index[++i]) + cb(ntohl(e->key_id), ar->mmap + ntohl(e->offset), ntohl(e->length), priv); +} + +void lmo_close_catalog(const char *lang) +{ + lmo_archive_t *ar, *next; + lmo_catalog_t *cat, *prev; + + for (prev = NULL, cat = _lmo_catalogs; cat; prev = cat, cat = cat->next) + { + if (!strncmp(cat->lang, lang, sizeof(cat->lang))) + { + if (prev) + prev->next = cat->next; + else + _lmo_catalogs = cat->next; + + for (ar = cat->archives; ar; ar = next) + { + next = ar->next; + lmo_close(ar); + } + + free(cat); + break; + } + } +} diff --git a/modules/luci-base/src/lib/lmo.h b/modules/luci-base/src/lib/lmo.h new file mode 100644 index 0000000000..744209f62c --- /dev/null +++ b/modules/luci-base/src/lib/lmo.h @@ -0,0 +1,108 @@ +/* + * lmo - Lua Machine Objects - General header + * + * Copyright (C) 2009-2012 Jo-Philipp Wich <jow@openwrt.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _TEMPLATE_LMO_H_ +#define _TEMPLATE_LMO_H_ + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <errno.h> +#include <fnmatch.h> +#include <dirent.h> +#include <ctype.h> +#include <limits.h> + +#if (defined(__GNUC__) && defined(__i386__)) +#define sfh_get16(d) (*((const uint16_t *) (d))) +#else +#define sfh_get16(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif + +#ifndef __hidden +#define __hidden __attribute__((visibility("hidden"))) +#endif + + +struct lmo_entry { + uint32_t key_id; + uint32_t val_id; + uint32_t offset; + uint32_t length; +} __attribute__((packed)); + +typedef struct lmo_entry lmo_entry_t; + + +struct lmo_archive { + int fd; + int length; + uint32_t size; + lmo_entry_t *index; + char *mmap; + char *end; + struct lmo_archive *next; +}; + +typedef struct lmo_archive lmo_archive_t; + + +struct lmo_catalog { + char lang[6]; + struct lmo_archive *archives; + struct lmo_catalog *next; +}; + +typedef struct lmo_catalog lmo_catalog_t; + +typedef void (*lmo_iterate_cb_t)(uint32_t, const char *, int, void *); + +__hidden uint32_t sfh_hash(const char *data, size_t len, uint32_t init); +__hidden uint32_t lmo_canon_hash(const char *data, int len, + const char *ctx, int ctxlen, int plural); + +__hidden lmo_archive_t * lmo_open(const char *file); +__hidden void lmo_close(lmo_archive_t *ar); + + +__hidden extern lmo_catalog_t *_lmo_catalogs; +__hidden extern lmo_catalog_t *_lmo_active_catalog; + +__hidden int lmo_load_catalog(const char *lang, const char *dir); +__hidden int lmo_change_catalog(const char *lang); +__hidden int lmo_translate(const char *key, int keylen, char **out, int *outlen); +__hidden int lmo_translate_ctxt(const char *key, int keylen, + const char *ctx, int ctxlen, char **out, int *outlen); +__hidden int lmo_translate_plural(int n, const char *skey, int skeylen, + const char *pkey, int pkeylen, + char **out, int *outlen); +__hidden int lmo_translate_plural_ctxt(int n, const char *skey, int skeylen, + const char *pkey, int pkeylen, + const char *ctx, int ctxlen, + char **out, int *outlen); +__hidden void lmo_iterate(lmo_iterate_cb_t cb, void *priv); +__hidden void lmo_close_catalog(const char *lang); + +#endif diff --git a/modules/luci-base/src/lib/luci.c b/modules/luci-base/src/lib/luci.c new file mode 100644 index 0000000000..e6860e727d --- /dev/null +++ b/modules/luci-base/src/lib/luci.c @@ -0,0 +1,383 @@ +/* + * LuCI low level routines - ucode binding + * + * Copyright (C) 2009-2022 Jo-Philipp Wich <jo@mein.io> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lmo.h" + +#include <pwd.h> +#include <crypt.h> +#include <shadow.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/utsname.h> +#include <sys/sysinfo.h> +#include <sys/statvfs.h> + +#include <ucode/module.h> + +/* translation catalog functions */ + +static uc_value_t * +uc_luci_load_catalog(uc_vm_t *vm, size_t nargs) { + uc_value_t *lang = uc_fn_arg(0); + uc_value_t *dir = uc_fn_arg(1); + + if (lang && ucv_type(lang) != UC_STRING) + return NULL; + + if (dir && ucv_type(dir) != UC_STRING) + return NULL; + + return ucv_boolean_new(lmo_load_catalog( + lang ? ucv_string_get(lang) : "en", + ucv_string_get(dir)) == 0); +} + +static uc_value_t * +uc_luci_close_catalog(uc_vm_t *vm, size_t nargs) { + uc_value_t *lang = uc_fn_arg(0); + + if (lang && ucv_type(lang) != UC_STRING) + return NULL; + + lmo_close_catalog(lang ? ucv_string_get(lang) : "en"); + + return ucv_boolean_new(true); +} + +static uc_value_t * +uc_luci_change_catalog(uc_vm_t *vm, size_t nargs) { + uc_value_t *lang = uc_fn_arg(0); + + if (lang && ucv_type(lang) != UC_STRING) + return NULL; + + return ucv_boolean_new(lmo_change_catalog( + lang ? ucv_string_get(lang) : "en") == 0); +} + +static void +uc_luci_get_translations_cb(uint32_t key, const char *val, int len, void *priv) { + uc_vm_t *vm = priv; + + uc_vm_stack_push(vm, ucv_get(uc_vm_stack_peek(vm, 0))); + uc_vm_stack_push(vm, ucv_uint64_new(key)); + uc_vm_stack_push(vm, ucv_string_new_length(val, (size_t)len)); + + if (uc_vm_call(vm, false, 2) == EXCEPTION_NONE) + ucv_put(uc_vm_stack_pop(vm)); +} + +static uc_value_t * +uc_luci_get_translations(uc_vm_t *vm, size_t nargs) { + lmo_iterate(uc_luci_get_translations_cb, vm); + + return ucv_boolean_new(true); +} + +static uc_value_t * +uc_luci_translate(uc_vm_t *vm, size_t nargs) { + uc_value_t *key = uc_fn_arg(0); + uc_value_t *ctx = uc_fn_arg(1); + int trlen; + char *tr; + + if (ucv_type(key) != UC_STRING) + return NULL; + + if (ctx && ucv_type(ctx) != UC_STRING) + return NULL; + + if (lmo_translate_ctxt(ucv_string_get(key), ucv_string_length(key), + ucv_string_get(ctx), ucv_string_length(ctx), + &tr, &trlen) != 0) + return NULL; + + return ucv_string_new_length(tr, (size_t)trlen); +} + +static uc_value_t * +uc_luci_ntranslate(uc_vm_t *vm, size_t nargs) { + uc_value_t *cnt = uc_fn_arg(0); + uc_value_t *skey = uc_fn_arg(1); + uc_value_t *pkey = uc_fn_arg(2); + uc_value_t *ctx = uc_fn_arg(3); + int trlen; + char *tr; + + if (ucv_type(skey) != UC_STRING || ucv_type(pkey) != UC_STRING) + return NULL; + + if (ctx && ucv_type(ctx) != UC_STRING) + return NULL; + + if (lmo_translate_plural_ctxt(ucv_int64_get(cnt), + ucv_string_get(skey), ucv_string_length(skey), + ucv_string_get(pkey), ucv_string_length(pkey), + ucv_string_get(ctx), ucv_string_length(ctx), + &tr, &trlen) != 0) + return NULL; + + return ucv_string_new_length(tr, (size_t)trlen); +} + +static uc_value_t * +uc_luci_hash(uc_vm_t *vm, size_t nargs) { + uc_value_t *key = uc_fn_arg(0); + uc_value_t *init = uc_fn_arg(1); + + if (ucv_type(key) != UC_STRING) + return NULL; + + if (init && ucv_type(init) != UC_INTEGER) + return NULL; + + return ucv_uint64_new(sfh_hash(ucv_string_get(key), ucv_string_length(key), + init ? ucv_uint64_get(init) : ucv_string_length(key))); +} + + +/* user functions */ + +static uc_value_t * +uc_luci_getspnam(uc_vm_t *vm, size_t nargs) { + uc_value_t *name = uc_fn_arg(0), *rv; + struct spwd *s; + + if (ucv_type(name) != UC_STRING) + return NULL; + + s = getspnam(ucv_string_get(name)); + + if (!s) + return NULL; + + rv = ucv_object_new(vm); + + ucv_object_add(rv, "namp", ucv_string_new(s->sp_namp)); + ucv_object_add(rv, "pwdp", ucv_string_new(s->sp_pwdp)); + ucv_object_add(rv, "lstchg", ucv_int64_new(s->sp_lstchg)); + ucv_object_add(rv, "min", ucv_int64_new(s->sp_min)); + ucv_object_add(rv, "max", ucv_int64_new(s->sp_max)); + ucv_object_add(rv, "warn", ucv_int64_new(s->sp_warn)); + ucv_object_add(rv, "inact", ucv_int64_new(s->sp_inact)); + ucv_object_add(rv, "expire", ucv_int64_new(s->sp_expire)); + + return rv; +} + +static uc_value_t * +uc_luci_getpwnam(uc_vm_t *vm, size_t nargs) { + uc_value_t *name = uc_fn_arg(0), *rv; + struct passwd *p; + + if (ucv_type(name) != UC_STRING) + return NULL; + + p = getpwnam(ucv_string_get(name)); + + if (!p) + return NULL; + + rv = ucv_object_new(vm); + + ucv_object_add(rv, "name", ucv_string_new(p->pw_name)); + ucv_object_add(rv, "passwd", ucv_string_new(p->pw_passwd)); + ucv_object_add(rv, "uid", ucv_int64_new(p->pw_uid)); + ucv_object_add(rv, "gid", ucv_int64_new(p->pw_gid)); + ucv_object_add(rv, "gecos", ucv_string_new(p->pw_gecos)); + ucv_object_add(rv, "dir", ucv_string_new(p->pw_dir)); + ucv_object_add(rv, "shell", ucv_string_new(p->pw_shell)); + + return rv; +} + +static uc_value_t * +uc_luci_crypt(uc_vm_t *vm, size_t nargs) { + uc_value_t *phrase = uc_fn_arg(0); + uc_value_t *setting = uc_fn_arg(1); + char *hash; + + if (ucv_type(phrase) != UC_STRING || ucv_type(setting) != UC_STRING) + return NULL; + + errno = 0; + hash = crypt(ucv_string_get(phrase), ucv_string_get(setting)); + + if (hash == NULL || errno != 0) + return NULL; + + return ucv_string_new(hash); +} + +static uc_value_t * +uc_luci_getuid(uc_vm_t *vm, size_t nargs) { + return ucv_int64_new(getuid()); +} + +static uc_value_t * +uc_luci_getgid(uc_vm_t *vm, size_t nargs) { + return ucv_int64_new(getgid()); +} + +static uc_value_t * +uc_luci_setuid(uc_vm_t *vm, size_t nargs) { + uc_value_t *uid = uc_fn_arg(0); + + if (ucv_type(uid) != UC_INTEGER) + return NULL; + + return ucv_boolean_new(setuid(ucv_int64_get(uid)) == 0); +} + +static uc_value_t * +uc_luci_setgid(uc_vm_t *vm, size_t nargs) { + uc_value_t *gid = uc_fn_arg(0); + + if (ucv_type(gid) != UC_INTEGER) + return NULL; + + return ucv_boolean_new(setgid(ucv_int64_get(gid)) == 0); +} + + +/* misc functions */ + +static uc_value_t * +uc_luci_kill(uc_vm_t *vm, size_t nargs) { + uc_value_t *pid = uc_fn_arg(0); + uc_value_t *sig = uc_fn_arg(1); + + if (ucv_type(pid) != UC_INTEGER || ucv_type(sig) != UC_INTEGER) + return NULL; + + return ucv_boolean_new(kill(ucv_int64_get(pid), ucv_int64_get(sig)) == 0); +} + +static uc_value_t * +uc_luci_uname(uc_vm_t *vm, size_t nargs) { + struct utsname u; + uc_value_t *rv; + + if (uname(&u) == -1) + return NULL; + + rv = ucv_object_new(vm); + + ucv_object_add(rv, "sysname", ucv_string_new(u.sysname)); + ucv_object_add(rv, "nodename", ucv_string_new(u.nodename)); + ucv_object_add(rv, "release", ucv_string_new(u.release)); + ucv_object_add(rv, "version", ucv_string_new(u.version)); + ucv_object_add(rv, "machine", ucv_string_new(u.machine)); + + return rv; +} + +static uc_value_t * +uc_luci_sysinfo(uc_vm_t *vm, size_t nargs) { + uc_value_t *rv, *loads; + struct sysinfo i; + + if (sysinfo(&i) == -1) + return NULL; + + rv = ucv_object_new(vm); + loads = ucv_array_new_length(vm, 3); + + ucv_array_push(loads, ucv_uint64_new(i.loads[0])); + ucv_array_push(loads, ucv_uint64_new(i.loads[1])); + ucv_array_push(loads, ucv_uint64_new(i.loads[2])); + + ucv_object_add(rv, "uptime", ucv_int64_new(i.uptime)); + ucv_object_add(rv, "loads", loads); + ucv_object_add(rv, "totalram", ucv_uint64_new(i.totalram)); + ucv_object_add(rv, "freeram", ucv_uint64_new(i.freeram)); + ucv_object_add(rv, "sharedram", ucv_uint64_new(i.sharedram)); + ucv_object_add(rv, "bufferram", ucv_uint64_new(i.bufferram)); + ucv_object_add(rv, "totalswap", ucv_uint64_new(i.totalswap)); + ucv_object_add(rv, "freeswap", ucv_uint64_new(i.freeswap)); + ucv_object_add(rv, "procs", ucv_uint64_new(i.procs)); + ucv_object_add(rv, "totalhigh", ucv_uint64_new(i.totalhigh)); + ucv_object_add(rv, "freehigh", ucv_uint64_new(i.freehigh)); + ucv_object_add(rv, "mem_unit", ucv_uint64_new(i.mem_unit)); + + return rv; +} + +static uc_value_t * +uc_luci_statvfs(uc_vm_t *vm, size_t nargs) { + uc_value_t *path = uc_fn_arg(0), *rv; + struct statvfs s; + + if (ucv_type(path) != UC_STRING) + return NULL; + + if (statvfs(ucv_string_get(path), &s) == -1) + return NULL; + + rv = ucv_object_new(vm); + + ucv_object_add(rv, "bsize", ucv_uint64_new(s.f_bsize)); + ucv_object_add(rv, "frsize", ucv_uint64_new(s.f_frsize)); + + ucv_object_add(rv, "blocks", ucv_uint64_new(s.f_blocks)); + ucv_object_add(rv, "bfree", ucv_uint64_new(s.f_bfree)); + ucv_object_add(rv, "bavail", ucv_uint64_new(s.f_bavail)); + + ucv_object_add(rv, "files", ucv_uint64_new(s.f_files)); + ucv_object_add(rv, "ffree", ucv_uint64_new(s.f_ffree)); + ucv_object_add(rv, "favail", ucv_uint64_new(s.f_favail)); + + ucv_object_add(rv, "fsid", ucv_uint64_new(s.f_fsid)); + ucv_object_add(rv, "flag", ucv_uint64_new(s.f_flag)); + ucv_object_add(rv, "namemax", ucv_uint64_new(s.f_namemax)); + + return rv; +} + + +static const uc_function_list_t luci_fns[] = { + { "load_catalog", uc_luci_load_catalog }, + { "close_catalog", uc_luci_close_catalog }, + { "change_catalog", uc_luci_change_catalog }, + { "get_translations", uc_luci_get_translations }, + { "translate", uc_luci_translate }, + { "ntranslate", uc_luci_ntranslate }, + { "hash", uc_luci_hash }, + + { "getspnam", uc_luci_getspnam }, + { "getpwnam", uc_luci_getpwnam }, + { "crypt", uc_luci_crypt }, + { "getuid", uc_luci_getuid }, + { "setuid", uc_luci_setuid }, + { "getgid", uc_luci_getgid }, + { "setgid", uc_luci_setgid }, + + { "kill", uc_luci_kill }, + { "uname", uc_luci_uname }, + { "sysinfo", uc_luci_sysinfo }, + { "statvfs", uc_luci_statvfs }, +}; + + +void uc_module_init(uc_vm_t *vm, uc_value_t *scope) +{ + uc_function_list_register(scope, luci_fns); +} diff --git a/modules/luci-base/src/lib/plural_formula.y b/modules/luci-base/src/lib/plural_formula.y new file mode 100644 index 0000000000..1623f8b282 --- /dev/null +++ b/modules/luci-base/src/lib/plural_formula.y @@ -0,0 +1,43 @@ +%name pluralParse +%token_type {int} +%extra_argument {struct parse_state *s} + +%right T_QMARK. +%left T_OR. +%left T_AND. +%left T_EQ T_NE. +%left T_LT T_LE T_GT T_GE. +%left T_ADD T_SUB. +%left T_MUL T_DIV T_MOD. +%right T_NOT. +%nonassoc T_COLON T_N T_LPAREN T_RPAREN. + +%include { +#include <assert.h> + +struct parse_state { + int num; + int res; +}; +} + +input ::= expr(A). { s->res = A; } + +expr(A) ::= expr(B) T_QMARK expr(C) T_COLON expr(D). { A = B ? C : D; } +expr(A) ::= expr(B) T_OR expr(C). { A = B || C; } +expr(A) ::= expr(B) T_AND expr(C). { A = B && C; } +expr(A) ::= expr(B) T_EQ expr(C). { A = B == C; } +expr(A) ::= expr(B) T_NE expr(C). { A = B != C; } +expr(A) ::= expr(B) T_LT expr(C). { A = B < C; } +expr(A) ::= expr(B) T_LE expr(C). { A = B <= C; } +expr(A) ::= expr(B) T_GT expr(C). { A = B > C; } +expr(A) ::= expr(B) T_GE expr(C). { A = B >= C; } +expr(A) ::= expr(B) T_ADD expr(C). { A = B + C; } +expr(A) ::= expr(B) T_SUB expr(C). { A = B - C; } +expr(A) ::= expr(B) T_MUL expr(C). { A = B * C; } +expr(A) ::= expr(B) T_DIV expr(C). { A = B / C; } +expr(A) ::= expr(B) T_MOD expr(C). { A = B % C; } +expr(A) ::= T_NOT expr(B). { A = !B; } +expr(A) ::= T_N. { A = s->num; } +expr(A) ::= T_NUM(B). { A = B; } +expr(A) ::= T_LPAREN expr(B) T_RPAREN. { A = B; } |