4 * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 #define WS_LOG_DOMAIN LOG_DOMAIN_WSLUA
16 /* WSLUA_MODULE Utility Utility Functions */
20 #include <epan/stat_tap_ui.h>
21 #include <epan/prefs.h>
22 #include <epan/prefs-int.h>
25 WSLUA_FUNCTION
wslua_get_version(lua_State
* L
) { /* Gets the Wireshark version as a string. */
26 const char* str
= VERSION
;
27 lua_pushstring(L
,str
);
28 WSLUA_RETURN(1); /* The version string, e.g. "3.2.5". */
32 static char* current_plugin_version
= NULL
;
34 const char* get_current_plugin_version(void) {
35 return current_plugin_version
? current_plugin_version
: "";
38 void clear_current_plugin_version(void) {
39 if (current_plugin_version
!= NULL
) {
40 g_free(current_plugin_version
);
41 current_plugin_version
= NULL
;
45 WSLUA_FUNCTION
wslua_set_plugin_info(lua_State
* L
) {
47 Set a Lua table with meta-data about the plugin, such as version.
49 The passed-in Lua table entries need to be keyed/indexed by the following:
51 * "version" with a string value identifying the plugin version (required)
52 * "description" with a string value describing the plugin (optional)
53 * "author" with a string value of the author's name(s) (optional)
54 * "repository" with a string value of a URL to a repository (optional)
56 Not all of the above key entries need to be in the table. The 'version'
57 entry is required, however. The others are not currently used for anything, but
58 might be in the future and thus using them might be useful. Table entries keyed
59 by other strings are ignored, and do not cause an error.
68 repository = "https://github.com/octocat/Spoon-Knife"
71 set_plugin_info(my_info)
74 #define WSLUA_ARG_set_plugin_info_TABLE 1 /* The Lua table of information. */
76 if ( lua_istable(L
,WSLUA_ARG_set_plugin_info_TABLE
) ) {
78 lua_getfield(L
, WSLUA_ARG_set_plugin_info_TABLE
, "version");
80 if (lua_isstring(L
, top
)) {
81 clear_current_plugin_version();
82 current_plugin_version
= g_strdup( luaL_checkstring(L
, top
) );
87 return luaL_error(L
,"the Lua table must have a 'version' key entry with a string value");
90 return luaL_error(L
,"a Lua table with at least a 'version' string entry");
97 WSLUA_FUNCTION
wslua_format_date(lua_State
* LS
) { /* Formats an absolute timestamp into a human readable date. */
98 #define WSLUA_ARG_format_date_TIMESTAMP 1 /* A timestamp value to convert. */
99 lua_Number timestamp
= luaL_checknumber(LS
,WSLUA_ARG_format_date_TIMESTAMP
);
103 then
.secs
= (time_t)(floor(timestamp
));
104 then
.nsecs
= (uint32_t) ( (timestamp
-(double)(then
.secs
))*1000000000);
105 str
= abs_time_to_str(NULL
, &then
, ABSOLUTE_TIME_LOCAL
, true);
106 lua_pushstring(LS
,str
);
107 wmem_free(NULL
, str
);
109 WSLUA_RETURN(1); /* A string with the formated date */
112 WSLUA_FUNCTION
wslua_format_time(lua_State
* LS
) { /* Formats a relative timestamp in a human readable time. */
113 #define WSLUA_ARG_format_time_TIMESTAMP 1 /* A timestamp value to convert. */
114 lua_Number timestamp
= luaL_checknumber(LS
,WSLUA_ARG_format_time_TIMESTAMP
);
118 then
.secs
= (time_t)(floor(timestamp
));
119 then
.nsecs
= (uint32_t) ( (timestamp
-(double)(then
.secs
))*1000000000);
120 str
= rel_time_to_str(NULL
, &then
);
121 lua_pushstring(LS
,str
);
122 wmem_free(NULL
, str
);
124 WSLUA_RETURN(1); /* A string with the formated time */
127 WSLUA_FUNCTION
wslua_get_preference(lua_State
*L
) {
128 /* Get a preference value. */
129 #define WSLUA_ARG_get_preference_PREFERENCE 1 /* The name of the preference. */
130 const char* preference
= luaL_checkstring(L
,WSLUA_ARG_get_preference_PREFERENCE
);
132 /* Split preference from module.preference */
133 char *module_name
= g_strdup(preference
);
134 char *preference_name
= strchr(module_name
, '.');
137 if (preference_name
) {
138 *preference_name
= '\0';
141 module_t
*module
= prefs_find_module(module_name
);
142 pref
= prefs_find_preference(module
, preference_name
);
144 g_free (module_name
);
147 switch (prefs_get_type(pref
)) {
150 unsigned uint_value
= prefs_get_uint_value(pref
, pref_current
);
151 lua_pushinteger(L
, uint_value
);
156 bool bool_value
= prefs_get_bool_value(pref
, pref_current
);
157 lua_pushboolean(L
, bool_value
);
162 const enum_val_t
*enums
;
163 int enum_value
= prefs_get_enum_value(pref
, pref_current
);
165 for (enums
= prefs_get_enumvals(pref
); enums
->name
; enums
++) {
166 if (enums
->value
== enum_value
) {
167 lua_pushstring(L
,enums
->name
);
172 if (!enums
|| !enums
->name
) {
173 /* Enum preference has an unknown value. */
174 lua_pushstring(L
,"");
179 case PREF_SAVE_FILENAME
:
180 case PREF_OPEN_FILENAME
:
184 const char *string_value
= prefs_get_string_value(pref
, pref_current
);
185 lua_pushstring(L
,string_value
);
190 char *range_value
= range_convert_range(NULL
, prefs_get_range_value_real(pref
, pref_current
));
191 lua_pushstring(L
,range_value
);
192 wmem_free(NULL
, range_value
);
196 /* Get not supported for this type. */
197 return luaL_error(L
, "preference type %d is not supported.", prefs_get_type(pref
));
200 /* No such preference. */
204 WSLUA_RETURN(1); /* The preference value, or nil if not found. */
207 WSLUA_FUNCTION
wslua_set_preference(lua_State
*L
) {
208 /* Set a preference value. */
209 #define WSLUA_ARG_set_preference_PREFERENCE 1 /* The name of the preference. */
210 #define WSLUA_ARG_set_preference_VALUE 2 /* The preference value to set. */
211 const char* preference
= luaL_checkstring(L
,WSLUA_ARG_set_preference_PREFERENCE
);
213 /* Split preference from module.preference */
214 char *module_name
= g_strdup(preference
);
215 char *preference_name
= strchr(module_name
, '.');
216 module_t
*module
= NULL
;
219 if (preference_name
) {
220 *preference_name
= '\0';
223 module
= prefs_find_module(module_name
);
224 pref
= prefs_find_preference(module
, preference_name
);
226 g_free (module_name
);
229 unsigned int changed
= 0;
230 switch (prefs_get_type(pref
)) {
233 unsigned uint_value
= (unsigned)luaL_checkinteger(L
,WSLUA_ARG_set_preference_VALUE
);
234 changed
= prefs_set_uint_value(pref
, uint_value
, pref_current
);
235 module
->prefs_changed_flags
|= changed
;
236 lua_pushboolean(L
, changed
);
241 bool bool_value
= wslua_checkboolean(L
, WSLUA_ARG_set_preference_VALUE
);
242 changed
= prefs_set_bool_value(pref
, bool_value
, pref_current
);
243 module
->prefs_changed_flags
|= changed
;
244 lua_pushboolean(L
, changed
);
249 const char *enum_value
= luaL_checkstring(L
,WSLUA_ARG_set_preference_VALUE
);
250 changed
= prefs_set_enum_string_value(pref
, enum_value
, pref_current
);
251 module
->prefs_changed_flags
|= changed
;
252 lua_pushboolean(L
, changed
);
256 case PREF_SAVE_FILENAME
:
257 case PREF_OPEN_FILENAME
:
261 const char *string_value
= luaL_checkstring(L
,WSLUA_ARG_set_preference_VALUE
);
262 changed
= prefs_set_string_value(pref
, string_value
, pref_current
);
263 module
->prefs_changed_flags
|= changed
;
264 lua_pushboolean(L
, changed
);
269 const char *range_value
= luaL_checkstring(L
,WSLUA_ARG_set_preference_VALUE
);
270 range_t
*range
= NULL
;
271 convert_ret_t ret
= range_convert_str(NULL
, &range
, range_value
, prefs_get_max_value(pref
));
272 if (ret
== CVT_NUMBER_TOO_BIG
) {
273 return luaL_error(L
, "illegal range (number too big)");
274 } else if (ret
!= CVT_NO_ERROR
) {
275 return luaL_error(L
, "illegal range (syntax error)");
277 changed
= prefs_set_range_value(pref
, range
, pref_current
);
278 wmem_free(NULL
, range
);
279 module
->prefs_changed_flags
|= changed
;
280 lua_pushboolean(L
, changed
);
284 /* Set not supported for this type. */
285 return luaL_error(L
, "preference type %d is not supported.", prefs_get_type(pref
));
288 /* No such preference. */
292 WSLUA_RETURN(1); /* true if changed, false if unchanged or nil if not found. */
295 WSLUA_FUNCTION
wslua_reset_preference(lua_State
*L
) {
296 /* Reset a preference to default value. */
297 #define WSLUA_ARG_reset_preference_PREFERENCE 1 /* The name of the preference. */
298 const char* preference
= luaL_checkstring(L
,WSLUA_ARG_reset_preference_PREFERENCE
);
300 // Split preference from module.preference
301 char *module_name
= g_strdup(preference
);
302 char *preference_name
= strchr(module_name
, '.');
305 if (preference_name
) {
306 *preference_name
= '\0';
309 module_t
*module
= prefs_find_module(module_name
);
310 pref
= prefs_find_preference(module
, preference_name
);
315 lua_pushboolean(L
, true);
317 /* No such preference. */
322 WSLUA_RETURN(1); /* true if valid preference */
325 WSLUA_FUNCTION
wslua_apply_preferences(lua_State
*L
) {
326 /* Write preferences to file and apply changes. */
327 char *pf_path
= NULL
;
328 int err
= write_prefs(&pf_path
);
331 /* Make a copy of pf_path because luaL_error() will return */
332 char pf_path_copy
[256];
333 (void) g_strlcpy(pf_path_copy
, pf_path
, sizeof pf_path_copy
);
336 return luaL_error(L
, "can't open preferences file\n\"%s\": %s.",
337 pf_path_copy
, g_strerror(err
));
345 WSLUA_FUNCTION
wslua_report_failure(lua_State
* LS
) { /* Reports a failure to the user. */
346 #define WSLUA_ARG_report_failure_TEXT 1 /* Message text to report. */
347 const char* s
= luaL_checkstring(LS
,WSLUA_ARG_report_failure_TEXT
);
348 report_failure("%s",s
);
352 /* The returned filename is g_malloc()'d so the caller must free it */
353 /* except when NULL is returned if file doesn't exist */
354 char* wslua_get_actual_filename(const char* fname
) {
355 char fname_clean
[256];
359 (void) g_strlcpy(fname_clean
,fname
,255);
360 fname_clean
[255] = '\0';
362 for(f
= fname_clean
; *f
; f
++) {
365 *f
= *(G_DIR_SEPARATOR_S
);
372 if ( file_exists(fname_clean
) ) {
373 return g_strdup(fname_clean
);
376 filename
= get_persconffile_path(fname_clean
,false);
378 if ( file_exists(filename
) ) {
384 * Try to look in global data directory, nothing extraordinary for normal
385 * installations. For executions from the build dir, it will look for files
386 * copied to DATAFILE_DIR.
388 filename
= get_datafile_path(fname_clean
);
389 if ( file_exists(filename
) ) {
397 WSLUA_FUNCTION
wslua_dofile(lua_State
* L
) {
399 Loads a Lua file and executes it as a Lua chunk, similar to the standard
400 https://www.lua.org/manual/5.4/manual.html#pdf-dofile[dofile]
401 but searches additional directories.
402 The search order is the current directory, followed by the user's
403 https://www.wireshark.org/docs/wsug_html_chunked/ChAppFilesConfigurationSection.html[personal configuration]
404 directory, and finally the
405 https://www.wireshark.org/docs/wsug_html_chunked/ChAppFilesConfigurationSection.html[global configuration]
409 .The configuration directories are not the plugin directories.
411 The configuration directories searched are not the global and personal plugin
412 directories. All Lua files in the plugin directories are loaded at startup;
413 `dofile` is for loading files from additional locations.
414 The file path can be absolute or relative to one of the search directories.
418 #define WSLUA_ARG_dofile_FILENAME 1 /* Name of the file to be run. If the file does not exist in the current directory, the user and system directories are searched. */
419 const char *given_fname
= luaL_checkstring(L
, WSLUA_ARG_dofile_FILENAME
);
420 char* filename
= wslua_get_actual_filename(given_fname
);
424 WSLUA_ARG_ERROR(dofile
,FILENAME
,"file does not exist");
429 if (luaL_loadfile(L
, filename
) != 0) lua_error(L
);
431 lua_call(L
, 0, LUA_MULTRET
);
432 return lua_gettop(L
) - n
;
435 WSLUA_FUNCTION
wslua_loadfile(lua_State
* L
) {
437 Loads a Lua file and compiles it into a Lua chunk, similar to the standard
438 https://www.lua.org/manual/5.4/manual.html#pdf-loadfile[loadfile]
439 but searches additional directories.
440 The search order is the current directory, followed by the user's
441 https://www.wireshark.org/docs/wsug_html_chunked/ChAppFilesConfigurationSection.html[personal configuration]
442 directory, and finally the
443 https://www.wireshark.org/docs/wsug_html_chunked/ChAppFilesConfigurationSection.html[global configuration]
450 -- Assume foo.lua contains definition for foo(a,b). Load the chunk
451 -- from the file and execute it to add foo(a,b) to the global table.
452 -- These two lines are effectively the same as dofile('foo.lua').
453 local loaded_chunk = assert(loadfile('foo.lua'))
456 -- ok to call foo at this point
460 #define WSLUA_ARG_loadfile_FILENAME 1 /* Name of the file to be loaded. If the file does not exist in the current directory, the user and system directories are searched. */
461 const char *given_fname
= luaL_checkstring(L
, WSLUA_ARG_loadfile_FILENAME
);
464 filename
= wslua_get_actual_filename(given_fname
);
467 WSLUA_ARG_ERROR(loadfile
,FILENAME
,"file does not exist");
471 if (luaL_loadfile(L
, filename
) == 0) {
482 typedef struct _statcmd_t
{
487 static int statcmd_init_cb_error_handler(lua_State
* L _U_
) {
491 static void statcmd_init(const char *opt_arg
, void* userdata
) {
492 statcmd_t
* sc
= (statcmd_t
*)userdata
;
493 lua_State
* L
= sc
->L
;
496 lua_pushcfunction(L
,statcmd_init_cb_error_handler
);
497 lua_rawgeti(L
, LUA_REGISTRYINDEX
, sc
->func_ref
);
499 lua_pushstring(L
,opt_arg
);
501 switch ( lua_pcall(L
,1,0,1) ) {
505 ws_warning("Runtime error while calling statcmd callback");
508 ws_warning("Memory alloc error while calling statcmd callback");
511 ws_warning("Error while running the error handler function for statcmd callback");
514 ws_assert_not_reached();
520 WSLUA_FUNCTION
wslua_register_stat_cmd_arg(lua_State
* L
) {
521 /* Register a function to handle a `-z` option */
522 #define WSLUA_ARG_register_stat_cmd_arg_ARGUMENT 1 /* The name of the option argument. */
523 #define WSLUA_OPTARG_register_stat_cmd_arg_ACTION 2 /* The function to be called when the command is invoked. */
524 const char* arg
= luaL_checkstring(L
,WSLUA_ARG_register_stat_cmd_arg_ARGUMENT
);
525 statcmd_t
* sc
= g_new0(statcmd_t
, 1); /* XXX leaked */
529 lua_pushvalue(L
, WSLUA_OPTARG_register_stat_cmd_arg_ACTION
);
530 sc
->func_ref
= luaL_ref(L
, LUA_REGISTRYINDEX
);
533 ui_info
.group
= REGISTER_PACKET_STAT_GROUP_UNSORTED
; /* XXX - need an argument? */
534 ui_info
.title
= NULL
;
535 ui_info
.cli_string
= arg
;
536 ui_info
.tap_init_cb
= statcmd_init
;
538 ui_info
.params
= NULL
;
539 register_stat_tap_ui(&ui_info
, sc
);
544 * Editor modelines - https://www.wireshark.org/tools/modelines.html
549 * indent-tabs-mode: nil
552 * vi: set shiftwidth=4 tabstop=8 expandtab:
553 * :indentSize=4:tabSize=8:noTabs=true: