Compare commits

...
43 Commits
Author SHA1 Message Date
fengzeroz b8b4dc55fd Merge pull request #1538 from fengzeroz/v2.6
version: 2.6.0
2023-09-15 18:11:47 +08:00
fengzero 65a5c9e0c5 version: 2.6.0 2023-09-15 10:11:17 +00:00
fengzeroz d165a0caf1 Merge pull request #1537 from eeff/v2.6
Pick to v2.6 fix(monitor): group update json event encoding
2023-09-15 09:28:51 +08:00
eeff d251eb9409 fix(monitor): group update json event encoding 2023-09-14 18:10:42 +08:00
fengzeroz 428f65a53e Merge pull request #1535 from fengzeroz/v2.6
fix(driver): validate tag when loading tags
2023-09-14 14:50:08 +08:00
fengzero e68d469e3d fix(driver): validate tag when loading tags 2023-09-14 06:40:04 +00:00
fengzeroz f2026ac304 Merge pull request #1532 from fengzeroz/v2.6
fix(event): check io is null
2023-09-14 11:33:56 +08:00
fengzero e427211c63 fix(event): check io is null 2023-09-14 03:16:18 +00:00
fengzeroz 09adbcdd4d Merge pull request #1527 from eeff/v2.6
Pick to v2.6 fix: zero out trailing hash key string
2023-09-13 10:57:56 +08:00
eeff bb77c59e2b fix: zero out trailing hash key string 2023-09-13 10:48:09 +08:00
fengzeroz 71885810ca Merge pull request #1522 from fengzeroz/v2.6
fix(driver): check tags size
2023-09-11 16:26:08 +08:00
fengzero 911d7d7f8c fix(driver): check tags size 2023-09-11 08:18:45 +00:00
fengzeroz 9c5c41b264 Merge pull request #1520 from eeff/v2.6
Pick to v2.6 feat: add virtual license sql schema
2023-09-11 09:32:05 +08:00
eeff 636cb69c65 feat: add virtual license sql schema 2023-09-08 18:11:57 +08:00
fengzeroz bd75e295ba Merge pull request #1517 from eeff/v2.6
Pick to v2.6 fix(mqtt): enable SNI only when configured host is not IP address
2023-09-07 14:49:49 +08:00
eeff 1860519927 fix(mqtt): enable SNI only when configured host is not IP address 2023-09-07 14:14:26 +08:00
fengzeroz c817c0d4f4 Merge pull request #1514 from ZhouBox/v2.6
fixbug:buffer size too small,host:port be truncated
2023-09-07 09:30:45 +08:00
fengzeroz e7b960e71b Merge pull request #1513 from eeff/v2.6
Pick to v2.6 feat(restful): support update template group name
2023-09-07 09:30:17 +08:00
xiang.zhou 71e820674f fixbug:buffer size too small,host:port be truncated 2023-09-06 19:00:58 +08:00
eeff 57dc135db7 test: add ft for template group name update 2023-09-06 18:21:53 +08:00
eeff 5993b6e28c feat(restful): support update template group name 2023-09-06 18:21:53 +08:00
eeff 076f63e87b feat(core): support update template group name 2023-09-06 18:21:53 +08:00
eeff 4d22cb60b4 feat: add json parser for updating template group 2023-09-06 18:21:53 +08:00
fengzeroz 5801cf213f Merge pull request #1511 from ZhouBox/v2.6
feat:add tag cache type
2023-09-06 18:20:35 +08:00
xiang.zhou b9cac5b4a7 feat:add tag cache type 2023-09-06 17:39:51 +08:00
fengzeroz 69eaca2046 Merge pull request #1510 from eeff/v2.6
Pick to v2.6 fix(metrics): update NEU_METRIC_TAGS_TOTAL when deleting group
2023-09-06 17:33:15 +08:00
eeff f1cf74ffe3 fix(metrics): update NEU_METRIC_TAGS_TOTAL when deleting group 2023-09-06 17:23:43 +08:00
fengzeroz d5cf105c2e Merge pull request #1502 from eeff/v2.6
Pick to v2.6 fix(core): trigger group change when updating group name
2023-09-05 18:00:23 +08:00
fengzeroz 0b922f98c5 Merge pull request #1504 from ZhouBox/v2.6
[v2.6]fixbug:send sigkill when stop timeout
2023-09-05 18:00:09 +08:00
fengzeroz bb4ce7ba0c Merge pull request #1507 from fengzeroz/v2.6
reduce retry time
2023-09-05 17:59:52 +08:00
fengzero 11fadeee4d reduce retry time 2023-09-05 09:58:33 +00:00
xiang.zhou 52b74ee3a2 fixbug:send sigkill when stop timeout 2023-09-05 17:30:44 +08:00
eeff d1401c88d1 fix(core): trigger group change when updating group name 2023-09-05 14:45:40 +08:00
fengzeroz 1ed6dbba14 Merge pull request #1499 from ZhouBox/v2.6
[v2.6]fixbug:log file name filtering error
2023-09-05 10:24:42 +08:00
xiang.zhou 98ac2456e3 fixbug:log file name filtering error 2023-09-05 09:56:30 +08:00
fengzeroz e4f30a5cb2 Merge pull request #1497 from ZhouBox/v2.6
[v2.6]fixbug:index error when endian in BL or LB
2023-09-05 09:48:47 +08:00
xiang.zhou c6be6f8018 fixbug:index error when endian in BL or LB 2023-09-05 08:53:15 +08:00
fengzeroz 7c1680f285 Merge pull request #1495 from fengzeroz/v2.6
fix workflow
2023-09-04 15:34:00 +08:00
fengzero ab4bc4cdc4 fix workflow 2023-09-04 07:00:45 +00:00
fengzeroz 6fb94430b2 Merge pull request #1494 from fengzeroz/v2.6
branch v2.6
2023-09-04 14:55:55 +08:00
fengzero bce294d7f1 branch v2.6 2023-09-04 06:55:29 +00:00
fengzeroz 2205e60dc2 Merge pull request #1493 from fengzeroz/v2.6
fix(core): trans data dup
2023-09-04 14:26:40 +08:00
fengzero e7beacb632 fix(core): trans data dup 2023-09-04 06:24:32 +00:00
37 changed files with 457 additions and 99 deletions
+3 -3
View File
@@ -40,7 +40,7 @@ jobs:
ut:
runs-on: ubuntu-20.04
container: ghcr.io/neugates/build:x86_64-main
container: ghcr.io/neugates/build:x86_64-v2.6
steps:
@@ -75,7 +75,7 @@ jobs:
ft:
runs-on: ubuntu-20.04
container: ghcr.io/neugates/build:x86_64-main
container: ghcr.io/neugates/build:x86_64-v2.6
steps:
- uses: actions/checkout@v2
@@ -108,7 +108,7 @@ jobs:
pyft:
runs-on: ubuntu-20.04
container: ghcr.io/neugates/build:x86_64-main
container: ghcr.io/neugates/build:x86_64-v2.6
steps:
- uses: actions/checkout@v2
+4 -4
View File
@@ -9,8 +9,8 @@ on:
env:
VERSION: 2.6.0
UI_VERSION: 2.5.0
BRANCH: main
UI_VERSION: 2.6.0
BRANCH: v2.6
jobs:
cross-build:
@@ -21,7 +21,7 @@ jobs:
- [aarch64-linux-gnu, aarch64, arm64]
- [arm-linux-gnueabihf, armv4, armhf]
- [x86_64-linux-gnu, x86_64, amd64]
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-main
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-v2.6
steps:
- uses: actions/checkout@v3
@@ -64,7 +64,7 @@ jobs:
matrix:
arch:
- [x86_64-linux-gnu, x86_64, amd64]
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-main
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-v2.6
steps:
- uses: actions/checkout@v3
+1 -1
View File
@@ -1,7 +1,7 @@
set(CMAKE_SYSTEM_NAME Linux)
set(COMPILER_PREFIX aarch64-linux-gnu)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(LIBRARY_DIR /home/neuron/main/libs)
set(LIBRARY_DIR /home/neuron/v2.6/libs)
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
+1 -1
View File
@@ -1,7 +1,7 @@
set(CMAKE_SYSTEM_NAME Linux)
set(COMPILER_PREFIX arm-linux-gnueabi)
set(CMAKE_SYSTEM_PROCESSOR armv5tejl)
set(LIBRARY_DIR /home/neuron/main/libs)
set(LIBRARY_DIR /home/neuron/v2.6/libs)
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
+1 -1
View File
@@ -1,7 +1,7 @@
set(CMAKE_SYSTEM_NAME Linux)
set(COMPILER_PREFIX arm-linux-gnueabihf)
set(CMAKE_SYSTEM_PROCESSOR armv7l)
set(LIBRARY_DIR /home/neuron/main/libs)
set(LIBRARY_DIR /home/neuron/v2.6/libs)
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
+1 -1
View File
@@ -1,7 +1,7 @@
set(CMAKE_SYSTEM_NAME Linux)
set(COMPILER_PREFIX x86_64-linux-gnu)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(LIBRARY_DIR /home/neuron/main/libs)
set(LIBRARY_DIR /home/neuron/v2.6/libs)
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
+3 -2
View File
@@ -258,8 +258,9 @@ Add Template Group
[RETURN] ${res}[0]
Put Template Group
[Arguments] ${tmpl} ${group} ${interval}
PUT /api/v2/template/group {"template": "${tmpl}", "group": "${group}", "interval": ${interval}}
[Arguments] ${tmpl} ${group} &{updates}
${data} = Evaluate json.dumps({"template": "${tmpl}", "group": "${group}", **$updates}) json
PUT /api/v2/template/group ${data}
${res} = Object response body
[RETURN] ${res}[0]
+96 -9
View File
@@ -496,7 +496,7 @@ Get groups from existent template having one group, it should success.
Update group interval when template does not exist, it should fail.
${res} = Put Template Group ${g_template} ${g_group1}[name] ${1000}
${res} = Put Template Group ${g_template} ${g_group1}[name] interval=${1000}
Check Response Status ${res} 404
Check Error Code ${res} ${NEU_ERR_TEMPLATE_NOT_FOUND}
@@ -508,7 +508,7 @@ Update group using too long template name in request, it should fail.
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Put Template Group ${g_long_str} ${g_group1}[name] ${2000}
${res} = Put Template Group ${g_long_str} ${g_group1}[name] interval=${2000}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_TEMPLATE_NAME_TOO_LONG}
@@ -520,7 +520,7 @@ Update group using too long group name in request, it should fail.
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Put Template Group ${g_template} ${g_long_str} ${2000}
${res} = Put Template Group ${g_template} ${g_long_str} interval=${2000}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_GROUP_NAME_TOO_LONG}
@@ -532,7 +532,7 @@ Update group interval when group does not exist, it should fail.
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Put Template Group ${g_template} ${g_group1}[name] ${1000}
${res} = Put Template Group ${g_template} ${g_group1}[name] interval=${1000}
Check Response Status ${res} 404
Check Error Code ${res} ${NEU_ERR_GROUP_NOT_EXIST}
@@ -544,7 +544,7 @@ Update group interval to invalid value, it should fail.
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Put Template Group ${g_template} ${g_group1}[name] ${10}
${res} = Put Template Group ${g_template} ${g_group1}[name] interval=${10}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_GROUP_PARAMETER_INVALID}
@@ -556,7 +556,7 @@ Update group interval, it should success.
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Put Template Group ${g_template} ${g_group1}[name] ${1000}
${res} = Put Template Group ${g_template} ${g_group1}[name] interval=${1000}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
@@ -568,6 +568,93 @@ Update group interval, it should success.
[Teardown] Del Template ${g_template}
Update group with empty new name, it should fail.
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Put Template Group ${g_template} ${g_group1}[name] new_name=${EMPTY}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_BODY_IS_WRONG}
[Teardown] Del Template ${g_template}
Update group with too long new name, it should fail.
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Put Template Group ${g_template} ${g_group1}[name] new_name=${g_long_str}
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_GROUP_NAME_TOO_LONG}
[Teardown] Del Template ${g_template}
Update group name to conflicting group name, it should fail.
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Add Template Group ${g_template} grp ${1000}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Put Template Group ${g_template} ${g_group1}[name] new_name=grp
Check Response Status ${res} 409
Check Error Code ${res} ${NEU_ERR_GROUP_EXIST}
[Teardown] Del Template ${g_template}
Update group name, it should success.
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Put Template Group ${g_template} ${g_group1}[name] new_name=grp
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Get Template Groups ${g_template}
Check Response Status ${res} 200
Should Have Only One Group ${res}[groups] grp ${g_group1}[interval]
Group Tag Count Should Be ${res}[groups][0] 2
[Teardown] Del Template ${g_template}
Update group with at least name or interval, otherwise it should fail.
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Put Template Group ${g_template} ${g_group1}[name]
Check Response Status ${res} 400
Check Error Code ${res} ${NEU_ERR_BODY_IS_WRONG}
[Teardown] Del Template ${g_template}
Update group name and interval, it should success.
${res} = Add Template ${g_template} ${g_plugin} ${g_groups}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Put Template Group ${g_template} ${g_group1}[name] new_name=grp interval=${1000}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
${res} = Get Template Groups ${g_template}
Check Response Status ${res} 200
Should Have Only One Group ${res}[groups] grp ${1000}
Group Tag Count Should Be ${res}[groups][0] 2
[Teardown] Del Template ${g_template}
Delete group from nonexistent template, it should fail.
${res} = Del Template Group ${g_template} ${g_group1}[name]
Check Response Status ${res} 404
@@ -642,7 +729,7 @@ Template groups should be persisted.
Should Have Only One Group ${res}[groups] ${g_group1}[name] ${g_group1}[interval]
Group Tag Count Should Be ${res}[groups][0] 0
${res} = Put Template Group ${g_template} ${g_group1}[name] ${1000}
${res} = Put Template Group ${g_template} ${g_group1}[name] new_name=grp interval=${1000}
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
@@ -650,10 +737,10 @@ Template groups should be persisted.
${res} = Get Template Groups ${g_template}
Check Response Status ${res} 200
Should Have Only One Group ${res}[groups] ${g_group1}[name] ${1000}
Should Have Only One Group ${res}[groups] grp ${1000}
Group Tag Count Should Be ${res}[groups][0] 0
${res} = Del Template Group ${g_template} ${g_group1}[name]
${res} = Del Template Group ${g_template} grp
Check Response Status ${res} 200
Check Error Code ${res} ${NEU_ERR_SUCCESS}
+8 -1
View File
@@ -612,7 +612,14 @@ typedef struct {
char tmpl[NEU_TEMPLATE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
uint32_t interval;
} neu_req_add_template_group_t, neu_req_update_template_group_t;
} neu_req_add_template_group_t;
typedef struct {
char tmpl[NEU_TEMPLATE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
char new_name[NEU_GROUP_NAME_LEN];
uint32_t interval;
} neu_req_update_template_group_t;
typedef struct {
char tmpl[NEU_TEMPLATE_NAME_LEN];
+6 -1
View File
@@ -45,7 +45,7 @@
extern int default_log_level;
extern bool disable_jwt;
extern char host_port[24];
extern char host_port[32];
typedef enum neu_plugin_kind {
NEU_PLUGIN_KIND_STATIC = 0,
@@ -72,4 +72,9 @@ typedef enum {
NEU_NODE_RUNNING_STATE_STOPPED = 4,
} neu_node_running_state_e;
typedef enum {
NEU_TAG_CACHE_TYPE_INTERVAL = 0,
NEU_TAG_CACHE_TYPE_NEVER,
} neu_tag_cache_type_e;
#endif
+2
View File
@@ -383,10 +383,12 @@ int neu_persister_store_template_group(const char * tmpl_name,
/**
* Update template group.
* @param tmpl_name template name.
* @param group_name group name.
* @param group_info group info to persist.
* @return 0 on success, non-zero otherwise
*/
int neu_persister_update_template_group(const char * tmpl_name,
const char * group_name,
neu_persist_group_info_t *group_info);
/**
+1
View File
@@ -116,6 +116,7 @@ typedef struct neu_plugin_module {
bool single;
const char * single_name;
neu_event_timer_type_e timer_type;
neu_tag_cache_type_e cache_type;
} neu_plugin_module_t;
inline static neu_plugin_common_t *
@@ -0,0 +1,24 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2023 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
BEGIN;
CREATE TABLE
IF NOT EXISTS virtual_license (license TEXT NOT NULL);
COMMIT;
+2 -2
View File
@@ -140,8 +140,8 @@ static char *generate_event_json(neu_plugin_t *plugin, neu_reqresp_type_e event,
update_grp->interval >= NEU_GROUP_INTERVAL_LIMIT;
json_req.update_grp.interval = update_grp->interval;
*topic_p = plugin->config->group_update_topic;
neu_json_encode_by_fn(&json_req, neu_json_encode_add_group_config_req,
&json_str);
neu_json_encode_by_fn(
&json_req, neu_json_encode_update_group_config_req, &json_str);
break;
}
case NEU_REQ_ADD_TAG_EVENT:
+2 -2
View File
@@ -134,7 +134,7 @@ static inline void route_tbl_update_driver(route_entry_t **tbl,
{
if (0 == strcmp(e->key.driver, driver)) {
HASH_DEL(*tbl, e);
strcpy(e->key.driver, new_name);
strncpy(e->key.driver, new_name, sizeof(e->key.driver));
HASH_ADD(hh, *tbl, key, sizeof(e->key), e);
}
}
@@ -147,7 +147,7 @@ static inline void route_tbl_update_group(route_entry_t **tbl,
route_entry_t *e = route_tbl_get(tbl, driver, group);
if (e) {
HASH_DEL(*tbl, e);
strcpy(e->key.group, new_name);
strncpy(e->key.group, new_name, sizeof(e->key.group));
HASH_ADD(hh, *tbl, key, sizeof(e->key), e);
}
}
+67 -11
View File
@@ -338,8 +338,8 @@ void handle_get_templates_resp(nng_aio *aio, neu_resp_get_templates_t *resp)
}
static inline int
send_template_mod_group_req(nng_aio *aio, neu_reqresp_type_e type,
neu_json_template_mod_group_req_t *req)
send_template_add_group_req(nng_aio * aio,
neu_json_template_add_group_req_t *req)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
@@ -358,7 +358,7 @@ send_template_mod_group_req(nng_aio *aio, neu_reqresp_type_e type,
neu_reqresp_head_t header = {
.ctx = aio,
.type = type,
.type = NEU_REQ_ADD_TEMPLATE_GROUP,
};
if (0 != neu_plugin_op(plugin, header, &cmd)) {
@@ -368,13 +368,12 @@ send_template_mod_group_req(nng_aio *aio, neu_reqresp_type_e type,
return 0;
}
static inline void process_mod_template_group(nng_aio * aio,
neu_reqresp_type_e type)
void handle_add_template_group(nng_aio *aio)
{
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_template_mod_group_req_t,
neu_json_decode_template_mod_group_req, {
int ret = send_template_mod_group_req(aio, type, req);
aio, neu_json_template_add_group_req_t,
neu_json_decode_template_add_group_req, {
int ret = send_template_add_group_req(aio, req);
if (ret != 0) {
NEU_JSON_RESPONSE_ERROR(
ret, { neu_http_response(aio, ret, result_error); });
@@ -382,14 +381,71 @@ static inline void process_mod_template_group(nng_aio * aio,
})
}
void handle_add_template_group(nng_aio *aio)
static inline int
send_template_update_group_req(nng_aio * aio,
neu_json_template_update_group_req_t *req)
{
process_mod_template_group(aio, NEU_REQ_ADD_TEMPLATE_GROUP);
neu_plugin_t *plugin = neu_rest_get_plugin();
if (strlen(req->tmpl) >= NEU_TEMPLATE_NAME_LEN) {
return NEU_ERR_TEMPLATE_NAME_TOO_LONG;
} else if (strlen(req->group) >= NEU_GROUP_NAME_LEN) {
return NEU_ERR_GROUP_NAME_TOO_LONG;
} else if (req->set_interval &&
(req->interval < NEU_GROUP_INTERVAL_LIMIT ||
req->interval > UINT32_MAX)) {
return NEU_ERR_GROUP_PARAMETER_INVALID;
}
// for backward compatibility,
// `new_name` or `interval` (inclusive) should be provided
if (!req->new_name && !req->set_interval) {
return NEU_ERR_BODY_IS_WRONG;
}
neu_req_update_template_group_t cmd = { 0 };
if (req->new_name) {
// if `new_name` is provided, then it should be valid
int len = strlen(req->new_name);
if (0 == len) {
return NEU_ERR_BODY_IS_WRONG;
} else if (len >= NEU_GROUP_NAME_LEN) {
return NEU_ERR_GROUP_NAME_TOO_LONG;
}
strcpy(cmd.new_name, req->new_name);
} else {
// if `new_name` is omitted, then keep the group name
strcpy(cmd.new_name, req->group);
}
strcpy(cmd.tmpl, req->tmpl);
strcpy(cmd.group, req->group);
cmd.interval = req->interval;
neu_reqresp_head_t header = {
.ctx = aio,
.type = NEU_REQ_UPDATE_TEMPLATE_GROUP,
};
if (0 != neu_plugin_op(plugin, header, &cmd)) {
return NEU_ERR_IS_BUSY;
}
return 0;
}
void handle_update_template_group(nng_aio *aio)
{
process_mod_template_group(aio, NEU_REQ_UPDATE_TEMPLATE_GROUP);
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_template_update_group_req_t,
neu_json_decode_template_update_group_req, {
int ret = send_template_update_group_req(aio, req);
if (ret != 0) {
NEU_JSON_RESPONSE_ERROR(
ret, { neu_http_response(aio, ret, result_error); });
}
})
}
static inline int
+5
View File
@@ -301,6 +301,11 @@ neu_node_type_e neu_adapter_get_type(neu_adapter_t *adapter)
return adapter->module->type;
}
neu_tag_cache_type_e neu_adapter_get_tag_cache_type(neu_adapter_t *adapter)
{
return adapter->module->cache_type;
}
static int adapter_register_metric(neu_adapter_t *adapter, const char *name,
const char *help, neu_metric_type_e type,
uint64_t init)
+2 -1
View File
@@ -75,7 +75,8 @@ int neu_adapter_start(neu_adapter_t *adapter);
int neu_adapter_start_single(neu_adapter_t *adapter);
int neu_adapter_stop(neu_adapter_t *adapter);
neu_node_type_e neu_adapter_get_type(neu_adapter_t *adapter);
neu_node_type_e neu_adapter_get_type(neu_adapter_t *adapter);
neu_tag_cache_type_e neu_adapter_get_tag_cache_type(neu_adapter_t *adapter);
int neu_adapter_uninit(neu_adapter_t *adapter);
void neu_adapter_destroy(neu_adapter_t *adapter);
+17 -6
View File
@@ -79,6 +79,7 @@ static int report_callback(void *usr_data);
static int read_callback(void *usr_data);
static int write_callback(void *usr_data);
static void read_group(int64_t timestamp, int64_t timeout,
neu_tag_cache_type_e cache_type,
neu_driver_cache_t *cache, const char *group,
UT_array *tags, neu_resp_tag_value_meta_t *datas);
static int read_report_group(int64_t timestamp, int64_t timeout,
@@ -365,6 +366,7 @@ void neu_adapter_driver_read_group(neu_adapter_driver_t *driver,
read_group(global_timestamp,
neu_group_get_interval(group) *
NEU_DRIVER_TAG_CACHE_EXPIRE_TIME,
neu_adapter_get_tag_cache_type(&driver->adapter),
driver->cache, cmd->group, tags, resp.tags);
}
@@ -411,7 +413,7 @@ static void fix_value(neu_datatag_t *tag, neu_type_e value_type,
switch (tag->option.value32.endian) {
case NEU_DATATAG_ENDIAN_LB32:
neu_ntohs_p((uint16_t *) value->value.bytes.bytes);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes + 2);
neu_ntohs_p((uint16_t *) (value->value.bytes.bytes + 2));
break;
case NEU_DATATAG_ENDIAN_BB32:
value->value.u32 = htonl(value->value.u32);
@@ -419,7 +421,7 @@ static void fix_value(neu_datatag_t *tag, neu_type_e value_type,
case NEU_DATATAG_ENDIAN_BL32:
value->value.u32 = htonl(value->value.u32);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes + 2);
neu_ntohs_p((uint16_t *) (value->value.bytes.bytes + 2));
break;
case NEU_DATATAG_ENDIAN_LL32:
default:
@@ -435,7 +437,7 @@ static void fix_value(neu_datatag_t *tag, neu_type_e value_type,
switch (tag->option.value32.endian) {
case NEU_DATATAG_ENDIAN_LB32:
neu_ntohs_p((uint16_t *) value->value.bytes.bytes);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes + 2);
neu_ntohs_p((uint16_t *) (value->value.bytes.bytes + 2));
break;
case NEU_DATATAG_ENDIAN_BB32:
value->value.u32 = htonl(value->value.u32);
@@ -443,7 +445,7 @@ static void fix_value(neu_datatag_t *tag, neu_type_e value_type,
case NEU_DATATAG_ENDIAN_BL32:
value->value.u32 = htonl(value->value.u32);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes + 2);
neu_ntohs_p((uint16_t *) (value->value.bytes.bytes + 2));
break;
case NEU_DATATAG_ENDIAN_LL32:
default:
@@ -775,6 +777,7 @@ int neu_adapter_driver_update_group(neu_adapter_driver_t *driver,
find->grp.group_name = new_name_cp2;
neu_adapter_metric_update_group_name((neu_adapter_t *) driver, name,
new_name);
find->timestamp = global_timestamp; // trigger group_change
HASH_ADD_STR(driver->groups, name, find);
} else {
free(new_name_cp1);
@@ -845,6 +848,10 @@ int neu_adapter_driver_del_group(neu_adapter_driver_t *driver, const char *name)
}
}
driver->tag_cnt -= neu_group_tag_size(find->group);
driver->adapter.cb_funs.update_metric(
&driver->adapter, NEU_METRIC_TAGS_TOTAL, driver->tag_cnt, NULL);
utarray_free(find->static_tags);
utarray_free(find->grp.tags);
utarray_free(find->wt_tags);
@@ -982,6 +989,8 @@ int neu_adapter_driver_add_tag(neu_adapter_driver_t *driver, const char *group,
group_t *find = NULL;
neu_datatag_parse_addr_option(tag, &tag->option);
driver->adapter.module->intf_funs->driver.validate_tag(
driver->adapter.plugin, tag);
HASH_FIND_STR(driver->groups, group, find);
if (find == NULL) {
@@ -1316,7 +1325,7 @@ static int read_callback(void *usr_data)
group_change);
}
if (group->grp.tags != NULL) {
if (group->grp.tags != NULL && utarray_len(group->grp.tags) > 0) {
int64_t spend = global_timestamp;
group->driver->adapter.module->intf_funs->driver.group_timer(
@@ -1495,6 +1504,7 @@ static int read_report_group(int64_t timestamp, int64_t timeout,
}
static void read_group(int64_t timestamp, int64_t timeout,
neu_tag_cache_type_e cache_type,
neu_driver_cache_t *cache, const char *group,
UT_array *tags, neu_resp_tag_value_meta_t *datas)
{
@@ -1574,7 +1584,8 @@ static void read_group(int64_t timestamp, int64_t timeout,
break;
}
if (!neu_tag_attribute_test(tag, NEU_ATTRIBUTE_STATIC) &&
if (cache_type != NEU_TAG_CACHE_TYPE_NEVER &&
!neu_tag_attribute_test(tag, NEU_ATTRIBUTE_STATIC) &&
(timestamp - value.timestamp) > timeout) {
datas[index].value.type = NEU_TYPE_ERROR;
datas[index].value.value.i32 = NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED;
+2 -2
View File
@@ -54,8 +54,8 @@ void adapter_storage_update_group(const char *node, const char *group,
int rv = neu_persister_update_group(node, group, &info);
if (0 != rv) {
nlog_error("fail update adapter:%s group:%s, interval: %u", node, group,
interval);
nlog_error("fail update adapter:%s group:%s, new_name:%s interval: %u",
node, group, new_name, interval);
}
}
+27 -2
View File
@@ -145,8 +145,8 @@ int neu_template_del_group(neu_template_t *tmpl, const char *group)
return 0;
}
int neu_template_update_group(neu_template_t *tmpl, const char *group,
uint32_t interval)
int neu_template_update_group_interval(neu_template_t *tmpl, const char *group,
uint32_t interval)
{
group_entry_t *ent = NULL;
HASH_FIND(hh, tmpl->groups, group, strlen(group), ent);
@@ -157,6 +157,31 @@ int neu_template_update_group(neu_template_t *tmpl, const char *group,
return neu_group_update(ent->group, interval);
}
int neu_template_update_group_name(neu_template_t *tmpl, const char *group,
const char *new_name)
{
if (0 == strcmp(group, new_name)) {
return 0;
}
if (NULL != neu_template_get_group(tmpl, new_name)) {
return NEU_ERR_GROUP_EXIST;
}
group_entry_t *ent = NULL;
HASH_FIND(hh, tmpl->groups, group, strlen(group), ent);
if (NULL == ent) {
return NEU_ERR_GROUP_NOT_EXIST;
}
HASH_DEL(tmpl->groups, ent);
int rv = neu_group_set_name(ent->group, new_name);
new_name = neu_group_get_name(ent->group);
HASH_ADD_KEYPTR(hh, tmpl->groups, new_name, strlen(new_name), ent);
return rv;
}
size_t neu_template_group_num(const neu_template_t *tmpl)
{
return HASH_COUNT(tmpl->groups);
+4 -2
View File
@@ -51,8 +51,10 @@ neu_group_t *neu_template_get_group(const neu_template_t *tmpl,
int neu_template_add_group(neu_template_t *tmpl, const char *group,
uint32_t interval);
int neu_template_del_group(neu_template_t *tmpl, const char *group);
int neu_template_update_group(neu_template_t *tmpl, const char *group,
uint32_t interval);
int neu_template_update_group_interval(neu_template_t *tmpl, const char *group,
uint32_t interval);
int neu_template_update_group_name(neu_template_t *tmpl, const char *group,
const char *new_name);
// Iterate through groups in the template and apply `cb` each.
// NOTE: `cb` must not alter the group name or delete the group.
+1 -1
View File
@@ -348,7 +348,7 @@ ssize_t neu_conn_send(neu_conn_t *conn, uint8_t *buf, ssize_t len)
}
} else {
if (rc == -1 && errno == EAGAIN) {
if (retry > 50) {
if (retry > 5) {
zlog_error(conn->param.log,
"conn fd: %d, send buf len: %zd, ret: %zd, "
"errno: %s(%d)",
+6 -1
View File
@@ -23,6 +23,8 @@
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#define NNG_SUPP_TLS 1
#define NNG_SUPP_SQLITE 1
#include <nng/mqtt/mqtt_client.h>
@@ -1045,7 +1047,10 @@ int neu_mqtt_client_set_tls(neu_mqtt_client_t *client, bool enabled,
client->tls_cfg = cfg;
}
if (0 != (rv = nng_tls_config_server_name(client->tls_cfg, client->host))) {
// validate server name and enable SNI only when host is not an IP address
struct sockaddr_in sa;
if (0 == inet_pton(AF_INET, client->host, &sa.sin_addr) &&
0 != (rv = nng_tls_config_server_name(client->tls_cfg, client->host))) {
log(error, "nng_tls_config_server_name fail: %s", nng_strerror(rv));
rv = -1;
goto end;
+4 -6
View File
@@ -441,15 +441,11 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
(neu_req_update_template_group_t *) &header[1];
neu_resp_error_t e = { 0 };
if (cmd->interval < NEU_GROUP_INTERVAL_LIMIT) {
e.error = NEU_ERR_GROUP_PARAMETER_INVALID;
} else {
e.error = neu_manager_update_template_group(manager, cmd);
}
e.error = neu_manager_update_template_group(manager, cmd);
if (e.error == NEU_ERR_SUCCESS) {
manager_storage_update_template_group(cmd->tmpl, cmd->group,
cmd->interval);
cmd->new_name, cmd->interval);
}
neu_msg_exchange(header);
@@ -1191,6 +1187,8 @@ inline static nng_msg *trans_data_dup(nng_msg *msg)
for (int i = 0; i < cmd->n_tag; i++) {
if (cmd->tags[i].value.type == NEU_TYPE_PTR) {
uint8_t *ptr = calloc(cmd->tags[i].value.value.ptr.length, 1);
memcpy(ptr, cmd->tags[i].value.value.ptr.ptr,
cmd->tags[i].value.value.ptr.length);
cmd->tags[i].value.value.ptr.ptr = ptr;
}
}
+15 -1
View File
@@ -332,7 +332,21 @@ int neu_manager_update_template_group(neu_manager_t * manager,
return NEU_ERR_TEMPLATE_NOT_FOUND;
}
return neu_template_update_group(tmpl, req->group, req->interval);
int rv = 0;
if (strlen(req->new_name) > 0 && 0 != strcmp(req->group, req->new_name)) {
rv = neu_template_update_group_name(tmpl, req->group, req->new_name);
if (0 != rv) {
return rv;
}
}
if (req->interval >= NEU_GROUP_INTERVAL_LIMIT) {
rv = neu_template_update_group_interval(tmpl, req->new_name,
req->interval);
}
return rv;
}
int neu_manager_del_template_group(neu_manager_t * manager,
+7 -5
View File
@@ -234,17 +234,19 @@ void manager_storage_add_template_group(const char *tmpl, const char *group,
}
void manager_storage_update_template_group(const char *tmpl, const char *group,
uint32_t interval)
const char *new_name,
uint32_t interval)
{
neu_persist_group_info_t info = {
.name = (char *) group,
.name = (char *) new_name,
.interval = interval,
};
int rv = neu_persister_update_template_group(tmpl, &info);
int rv = neu_persister_update_template_group(tmpl, group, &info);
if (0 != rv) {
nlog_error("update template:%s grp:%s, interval:%" PRIu32 " fail", tmpl,
group, interval);
nlog_error("update template:%s group:%s, new_name:%s interval:%" PRIu32
" fail",
tmpl, group, new_name, interval);
}
}
+2 -1
View File
@@ -55,7 +55,8 @@ void manager_storage_clear_templates(neu_manager_t *manager);
void manager_storage_add_template_group(const char *tmpl, const char *group,
uint32_t interval);
void manager_storage_update_template_group(const char *tmpl, const char *group,
uint32_t interval);
const char *new_name,
uint32_t interval);
void manager_storage_del_template_group(const char *tmpl, const char *group);
void manager_storage_add_template_tag(const char *tmpl, const char *group,
const neu_datatag_t *tag);
+3 -3
View File
@@ -304,7 +304,7 @@ int neu_subscribe_manager_update_app_name(neu_subscribe_mgr_t *mgr,
utarray_foreach(el->apps, neu_app_subscribe_t *, sub_app)
{
if (strcmp(app, sub_app->app_name) == 0) {
strcpy(sub_app->app_name, new_name);
strncpy(sub_app->app_name, new_name, sizeof(sub_app->app_name));
}
}
}
@@ -322,7 +322,7 @@ int neu_subscribe_manager_update_driver_name(neu_subscribe_mgr_t *mgr,
{
if (strcmp(driver, el->key.driver) == 0) {
HASH_DEL(mgr->ss, el);
strcpy(el->key.driver, new_name);
strncpy(el->key.driver, new_name, sizeof(el->key.driver));
HASH_ADD(hh, mgr->ss, key, sizeof(sub_elem_key_t), el);
}
}
@@ -348,7 +348,7 @@ int neu_subscribe_manager_update_group_name(neu_subscribe_mgr_t *mgr,
}
HASH_DEL(mgr->ss, find);
strcpy(find->key.group, new_name);
strncpy(find->key.group, new_name, sizeof(find->key.group));
HASH_ADD(hh, mgr->ss, key, sizeof(sub_elem_key_t), find);
return 0;
+5 -1
View File
@@ -35,7 +35,7 @@
#include "daemon.h"
#define STOP_TIMEOUT 20000
#define STOP_TIMEOUT 10000
#define STOP_TICK 2000
void daemonize()
@@ -205,6 +205,10 @@ int neuron_stop()
if (0 == kill((pid_t)(-gid), SIGINT)) {
if (neuron_wait_exit(STOP_TIMEOUT) == 0) {
ret = 0;
} else {
if (0 == kill((pid_t)(-gid), SIGKILL)) {
ret = 0;
}
}
} else {
nlog_error("cannot kill gpid:%ld reason: %s\n", (long) gid,
+4
View File
@@ -260,6 +260,10 @@ neu_event_io_t *neu_event_add_io(neu_events_t *events, neu_event_io_param_t io)
int neu_event_del_io(neu_events_t *events, neu_event_io_t *io)
{
if (io == NULL) {
return 0;
}
struct event_data *data = (struct event_data *) io->event_data;
zlog_notice(neuron, "del io: %d from epoll: %d", io->fd, events->epoll_fd);
+1 -1
View File
@@ -35,7 +35,7 @@ static neu_manager_t *g_manager = NULL;
zlog_category_t * neuron = NULL;
bool disable_jwt = false;
int default_log_level = ZLOG_LEVEL_NOTICE;
char host_port[24] = { 0 };
char host_port[32] = { 0 };
int64_t global_timestamp = 0;
+81 -8
View File
@@ -378,10 +378,10 @@ int neu_json_encode_get_templates_resp(void *json_obj, void *param)
NEU_JSON_ELEM_SIZE(req_elems));
}
int neu_json_encode_template_mod_group_req(void *json_obj, void *param)
int neu_json_encode_template_add_group_req(void *json_obj, void *param)
{
int ret = 0;
neu_json_template_mod_group_req_t *req = param;
neu_json_template_add_group_req_t *req = param;
neu_json_elem_t req_elems[] = { {
.name = "template",
@@ -404,12 +404,12 @@ int neu_json_encode_template_mod_group_req(void *json_obj, void *param)
return ret;
}
int neu_json_decode_template_mod_group_req(
char *buf, neu_json_template_mod_group_req_t **result)
int neu_json_decode_template_add_group_req(
char *buf, neu_json_template_add_group_req_t **result)
{
int ret = 0;
void * json_obj = NULL;
neu_json_template_mod_group_req_t *req = NULL;
neu_json_template_add_group_req_t *req = NULL;
json_obj = neu_json_decode_new(buf);
if (NULL == json_obj) {
@@ -449,13 +449,13 @@ int neu_json_decode_template_mod_group_req(
return 0;
decode_fail:
neu_json_decode_template_mod_group_req_free(req);
neu_json_decode_template_add_group_req_free(req);
neu_json_decode_free(json_obj);
return -1;
}
void neu_json_decode_template_mod_group_req_free(
neu_json_template_mod_group_req_t *req)
void neu_json_decode_template_add_group_req_free(
neu_json_template_add_group_req_t *req)
{
if (req) {
free(req->tmpl);
@@ -464,6 +464,79 @@ void neu_json_decode_template_mod_group_req_free(
}
}
int neu_json_decode_template_update_group_req(
char *buf, neu_json_template_update_group_req_t **result)
{
int ret = 0;
neu_json_template_update_group_req_t *req = calloc(1, sizeof(*req));
if (req == NULL) {
return -1;
}
void *json_obj = neu_json_decode_new(buf);
if (NULL == json_obj) {
free(req);
return -1;
}
neu_json_elem_t req_elems[] = {
{
.name = "template",
.t = NEU_JSON_STR,
},
{
.name = "group",
.t = NEU_JSON_STR,
},
{
.name = "new_name",
.t = NEU_JSON_STR,
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
},
};
ret = neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(req_elems),
req_elems);
req->tmpl = req_elems[0].v.val_str;
req->group = req_elems[1].v.val_str;
req->new_name = req_elems[2].v.val_str;
if (0 != ret) {
goto error;
}
json_t *json_interval = json_object_get(json_obj, "interval");
if (NULL != json_interval) {
if (!json_is_integer(json_interval)) {
nlog_error("decode interval is not integer");
goto error;
}
req->set_interval = true;
req->interval = json_integer_value(json_interval);
} else if (NULL == req->new_name) {
// at least one of `new_name` or `interval` should be provided
goto error;
}
*result = req;
neu_json_decode_free(json_obj);
return 0;
error:
neu_json_decode_template_update_group_req_free(req);
neu_json_decode_free(json_obj);
return -1;
}
void neu_json_decode_template_update_group_req_free(
neu_json_template_update_group_req_t *req)
{
free(req->tmpl);
free(req->group);
free(req->new_name);
free(req);
}
int neu_json_encode_template_del_group_req(void *json_object, void *param)
{
int ret = 0;
+19 -6
View File
@@ -81,13 +81,26 @@ typedef struct {
char * tmpl;
char * group;
int64_t interval;
} neu_json_template_mod_group_req_t;
} neu_json_template_add_group_req_t;
int neu_json_encode_template_mod_group_req(void *json_obj, void *param);
int neu_json_decode_template_mod_group_req(
char *buf, neu_json_template_mod_group_req_t **result);
void neu_json_decode_template_mod_group_req_free(
neu_json_template_mod_group_req_t *req);
int neu_json_encode_template_add_group_req(void *json_obj, void *param);
int neu_json_decode_template_add_group_req(
char *buf, neu_json_template_add_group_req_t **result);
void neu_json_decode_template_add_group_req_free(
neu_json_template_add_group_req_t *req);
typedef struct {
char * tmpl;
char * group;
char * new_name;
bool set_interval;
int64_t interval;
} neu_json_template_update_group_req_t;
int neu_json_decode_template_update_group_req(
char *buf, neu_json_template_update_group_req_t **result);
void neu_json_decode_template_update_group_req_free(
neu_json_template_update_group_req_t *req);
typedef struct {
char *tmpl;
+24 -4
View File
@@ -1487,12 +1487,32 @@ int neu_persister_store_template_group(const char * tmpl_name,
}
int neu_persister_update_template_group(const char * tmpl_name,
const char * group_name,
neu_persist_group_info_t *group_info)
{
return execute_sql(
global_db,
"UPDATE template_groups SET interval=%i WHERE tmpl_name=%Q AND name=%Q",
group_info->interval, tmpl_name, group_info->name);
int ret = -1;
bool update_name = (0 != strcmp(group_name, group_info->name));
bool update_interval = (NEU_GROUP_INTERVAL_LIMIT <= group_info->interval);
if (update_name && update_interval) {
ret = execute_sql(global_db,
"UPDATE template_groups SET name=%Q, interval=%i "
"WHERE tmpl_name=%Q AND name=%Q",
group_info->name, group_info->interval, tmpl_name,
group_name);
} else if (update_name) {
ret = execute_sql(global_db,
"UPDATE template_groups SET name=%Q "
"WHERE tmpl_name=%Q AND name=%Q",
group_info->name, tmpl_name, group_name);
} else if (update_interval) {
ret = execute_sql(global_db,
"UPDATE template_groups SET interval=%i "
"WHERE tmpl_name=%Q AND name=%Q",
group_info->interval, tmpl_name, group_name);
}
return ret;
}
int neu_persister_load_template_groups(const char *tmpl_name,
+5 -8
View File
@@ -27,11 +27,10 @@
static UT_array *collect_logs(const char *dir, const char *node)
{
DIR * dirp = NULL;
struct dirent *dent = NULL;
UT_array * files = NULL;
char flag[NEU_NODE_NAME_LEN + 2] = { 0 };
char flag_[NEU_NODE_NAME_LEN + 2] = { 0 };
DIR * dirp = NULL;
struct dirent *dent = NULL;
UT_array * files = NULL;
char flag[NEU_NODE_NAME_LEN + 2] = { 0 };
if ((dirp = opendir(dir)) == NULL) {
nlog_error("fail open dir: %s", dir);
@@ -40,11 +39,9 @@ static UT_array *collect_logs(const char *dir, const char *node)
utarray_new(files, &ut_str_icd);
snprintf(flag, sizeof(flag), "%s.", node);
snprintf(flag_, sizeof(flag_), "%s_", node);
while (NULL != (dent = readdir(dirp))) {
if (strstr(dent->d_name, flag) != NULL ||
strstr(dent->d_name, flag_) != NULL) {
if (strstr(dent->d_name, flag) != NULL) {
char *file = dent->d_name;
utarray_push_back(files, &file);
}
+1 -1
View File
@@ -1 +1 @@
2.6.0-dev
2.6.0