| Age | Commit message (Collapse) | Author |
|
triton: reject concurrent config reload requests
|
|
cli: proper ipv6 support for cli interface
|
|
triton_conf_reload() kept the notify callback in a single global slot,
and the CLI reload command likewise stored its wakeup context in a
global. A second reload issued while the first was still pending (from
another CLI connection or SIGUSR1) overwrote both, so only the last
requester was notified when the reload completed; the earlier CLI
context slept forever in triton_context_schedule() and that connection
hung while the rest of the daemon kept running.
Make triton_conf_reload() return -1 when a reload is already pending,
checked atomically under threads_lock, and pass a caller-provided arg
through to the notify callback so each requester keeps its own state
instead of sharing globals. The CLI reload's request struct is
heap-allocated rather than kept on reload_exec's stack, since
triton_context_schedule() can migrate a suspended context onto a
different worker thread's stack before the notify callback runs,
which would otherwise leave conf_reload_notify() writing through a
stale stack pointer.
Also mark the reload as running (need_config_reload = 2) before
dropping threads_lock to call __config_reload(). Previously a worker
woken during the reload (e.g. by the notify callback waking the CLI
context, or any stray context wakeup) could loop through the idle
path, decrement the active count back to zero and re-enter
__config_reload() while need_config_reload was still set, running a
second concurrent conf_reload() and invoking the notify callback
twice - corrupting the wakeup list and, with the CLI's heap request,
writing through freed memory.
The SIGUSR1 handler used to call triton_conf_reload() directly from
signal context, taking spinlocks and potentially running the whole
config parse inside the handler. It now only sets a flag; the main
thread waits with sigtimedwait() and performs the reload (and logs a
warning when one is already in progress) from normal thread context.
The CLI now replies "reload is already in progress" instead of losing
the first requester's wakeup.
|
|
We had several flaws on server side that was breaking ipv6 cli support.
accel-pppd/cli/cli_p.h — three shared helpers used by both listeners: cli_parse_hostport() (accepts host:port, [ipv6]:port, bare ::1:port via last-colon split, and :port for wildcard), cli_bind_addr()
(builds an IPv4 or IPv6 sockaddr, modeled on the existing SSTP pattern), and cli_addr_str() (formats peer addresses for logging, including v4-mapped).
accel-pppd/cli/tcp.c and telnet.c — listeners now create a socket of whichever family the configured address is; client address storage switched from sockaddr_in to sockaddr_storage so connection logging prints IPv6 peers correctly.
An invalid address now logs an error instead of silently binding garbage (previously inet_addr() failure went unchecked). Also fixed a pre-existing quirk where the fd itself was passed as the SO_REUSEADDR option value.
accel-pppd/accel-ppp.conf.5 — documented the new [::1]:2000 syntax and [::]:port for the IPv6 wildcard.
Might fix: https://github.com/accel-ppp/accel-ppp/issues/317
Signed-off-by: Denys Fedoryshchenko <denys.f@collabora.com>
|
|
Group the Triton core statistics in struct triton_stat_t and keep the storage private to triton.c instead of exporting the writable triton_stat object through triton.h. This keeps ownership inside the Triton core while preserving the existing CLI and ACCEL-PPP-MIB counter semantics.
Route counter updates through triton_stat_*() helpers. Thread, context, md handler, timer, mempool, CPU, and start-time update paths no longer open-code direct triton_stat mutations; the update policy now lives beside the Triton-owned storage and uses relaxed atomic operations for the simple counters.
Make the CLI show-stat path render from a local snapshot and update statCore SNMP readers to use triton_stat_start_time() and triton_stat_cpu(). Out-of-tree modules that accessed the exported triton_stat object directly must switch to the new accessors, because triton_stat is no longer part of the public ABI.
Signed-off-by: Denys Fedoryshchenko <denys.f@collabora.com>
|
|
Group the core session starting, active, and finishing statistics behind the private ap_session_stat storage in session.c instead of exposing writable counters through ap_session.h. This keeps ownership inside the session core while preserving the existing CLI and ACCEL-PPP-MIB counter semantics.
Route session counter updates through ap_session_stat_*() helpers. Session start, activation, termination, finish, and shutdown-idle paths no longer open-code individual counter increments/decrements; the update policy now lives beside the session-owned storage and uses relaxed atomic operations for the simple state counters.
Make the CLI show-stat path render from a local snapshot and convert the PPP SNMP starting/active/finishing scalars from watched raw pointers to scalar handlers. PPP controllers now read max-session limits through ap_session_stat_starting() and ap_session_stat_active(), removing external direct access to ap_session_stat.
Signed-off-by: Denys Fedoryshchenko <denys.f@collabora.com>
|
|
|
|
We are living in 64-bit world long time, so there is very likely mempool
stats might overflow past 4GB and report incorrect values.
Updated mempool stats to use 64-bit counters so they don’t
wrap past 4 GB and print correctly in CLI.
Signed-off-by: Denys Fedoryshchenko <denys.f@collabora.com>
|
|
PCRE is not supported anymore and removed from several distros
|
|
show sessions command
|
|
|
|
handling.
When a link has a relatively high throughput, the 32-bit packet and byte counters could overflow multiple times between accounting runs.
To accommodate this limitation, directly use 64-bit interface statistics.
This also gets rid of the internal giga-word counters.
|
|
|
|
Co-authored-by: Sergey V. Lobanov <svlobanov@users.noreply.github.com>
Co-authored-by: Vladislav Grishenko <themiron@users.noreply.github.com>
|
|
|
|
fix 4b52c1a3590b43ca892c460d9b1478e1da742156
|
|
|
|
* Fix errors found by valgrind
==12312== Syscall param sendmsg(msg.msg_iov[0]) points to uninitialised byte(s)
==12312== at 0x486CCF0: sendmsg (in /lib/libpthread-2.22.so)
==12312== by 0x12F57F: rtnl_talk (libnetlink.c:316)
==12312== by 0x132DA3: genl_resolve_mcg (genl.c:52)
==12312== by 0x484E1CB: init (vlan_mon.c:528)
==12312== by 0x484CDC0: vlan_mon_register_proto (vlan_mon.c:48)
==12312== by 0x510B763: load_vlan_mon (pppoe.c:1914)
==12312== by 0x510BFF2: load_config (pppoe.c:2064)
==12312== by 0x510C22A: pppoe_init (pppoe.c:2108)
==12312== by 0x483E9EB: triton_load_modules (triton.c:704)
==12312== by 0x1384B2: main (main.c:339)
==12312== Address 0xbedacdd8 is on thread 1's stack
==12312== in frame #2, created by genl_resolve_mcg (genl.c:23)
==12312== 15 bytes in 1 blocks are definitely lost in loss record 352 of 836
==12312== at 0x482A9A9: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==12312== by 0x4B97524: strdup (in /lib/libc-2.22.so)
==12312== by 0x12C30C: init (telnet.c:769)
==12312== by 0x483E9EB: triton_load_modules (triton.c:704)
==12312== by 0x1384B2: main (main.c:339)
==12312==
==12312== 15 bytes in 1 blocks are definitely lost in loss record 353 of 836
==12312== at 0x482A9A9: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==12312== by 0x4B97524: strdup (in /lib/libc-2.22.so)
==12312== by 0x12D60A: init (tcp.c:392)
==12312== by 0x483E9EB: triton_load_modules (triton.c:704)
==12312== by 0x1384B2: main (main.c:339)
* Fix another warnings by cppcheck
[accel-pppd/ctrl/ipoe/arp.c:256]: (error) Uninitialized variable: n
[accel-pppd/ctrl/pppoe/mac_filter.c:90]: (warning) %x in format string (no. 1) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:90]: (warning) %x in format string (no. 2) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:90]: (warning) %x in format string (no. 3) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:90]: (warning) %x in format string (no. 4) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:90]: (warning) %x in format string (no. 5) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:90]: (warning) %x in format string (no. 6) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:129]: (warning) %x in format string (no. 1) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:129]: (warning) %x in format string (no. 2) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:129]: (warning) %x in format string (no. 3) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:129]: (warning) %x in format string (no. 4) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:129]: (warning) %x in format string (no. 5) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:129]: (warning) %x in format string (no. 6) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:158]: (warning) %x in format string (no. 1) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:158]: (warning) %x in format string (no. 2) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:158]: (warning) %x in format string (no. 3) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:158]: (warning) %x in format string (no. 4) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:158]: (warning) %x in format string (no. 5) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/mac_filter.c:158]: (warning) %x in format string (no. 6) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ctrl/pppoe/pppoe.c:738]: (warning) Possible null pointer dereference
[accel-pppd/ipv6/dhcpv6.c:911]: (warning) %x in format string (no. 1) requires 'unsigned int *' but the argument type is 'int *'.
[accel-pppd/ipv6/dhcpv6.c:911]: (warning) %x in format string (no. 2) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ipv6/dhcpv6.c:911]: (warning) %x in format string (no. 3) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ipv6/dhcpv6.c:911]: (warning) %x in format string (no. 4) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/libnetlink/libnetlink.c:515]: (warning) Possible null pointer dereference
[accel-pppd/ppp/ipv6cp_opt_intfid.c:185]: (warning) %x in format string (no. 1) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ppp/ipv6cp_opt_intfid.c:298]: (warning) %x in format string (no. 1) requires 'unsigned int *' but the argument type is 'int *'.
[accel-pppd/ppp/ipv6cp_opt_intfid.c:298]: (warning) %x in format string (no. 2) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ppp/ipv6cp_opt_intfid.c:298]: (warning) %x in format string (no. 3) requires 'unsigned int *' but the argument type is 'signed int *'.
[accel-pppd/ppp/ipv6cp_opt_intfid.c:298]: (warning) %x in format string (no. 4) requires 'unsigned int *' but the argument type is 'signed int *'.
* Suppress compiler warnings
* Fix locking errors
/opt/pvs/accel-ppp/accel-pppd/extra/pppd_compat.c 279 warn V1020 The function exited without calling the 'sigchld_unlock' function. Check lines: 279, 249.
/opt/pvs/accel-ppp/accel-pppd/extra/pppd_compat.c 333 warn V1020 The function exited without calling the 'sigchld_unlock' function. Check lines: 333, 315.
/opt/pvs/accel-ppp/accel-pppd/extra/pppd_compat.c 422 warn V1020 The function exited without calling the 'sigchld_unlock' function. Check lines: 422, 372.
/opt/pvs/accel-ppp/accel-pppd/extra/pppd_compat.c 488 warn V1020 The function exited without calling the 'sigchld_unlock' function. Check lines: 488, 468.
/opt/pvs/accel-ppp/accel-pppd/triton/mempool.c 119 warn V1020 The function exited without calling the 'pthread_spin_unlock' function. Check lines: 119, 116.
* Fix array len errors
/opt/pvs/accel-ppp/accel-pppd/triton/conf_file.c 75 warn V557 Array underrun is possible. The value of 'len - 1' index could reach -1.
/opt/pvs/accel-ppp/accel-pppd/triton/conf_file.c 76 warn V557 Array underrun is possible. The value of '-- len' index could reach -1.
* Fix possible memory leaks
/opt/pvs/accel-ppp/accel-pppd/radius/radius.c 936 err V773 The function was exited without releasing the 'str' pointer. A memory leak is possible.
/opt/pvs/accel-ppp/accel-pppd/radius/serv.c 622 err V773 The function was exited without releasing the 'str' pointer. A memory leak is possible.
/opt/pvs/accel-ppp/accel-pppd/triton/conf_file.c 144 err V773 The function was exited without releasing the 'raw' pointer. A memory leak is possible.
* Fix unsafe code
/opt/pvs/accel-ppp/accel-pppd/cli/tcp.c 364 warn V1004 The 'host' pointer was used unsafely after it was verified against nullptr. Check lines: 338, 364.
/opt/pvs/accel-ppp/accel-pppd/cli/telnet.c 701 warn V1004 The 'host' pointer was used unsafely after it was verified against nullptr. Check lines: 675, 701.
/opt/pvs/accel-ppp/accel-pppd/extra/ippool.c 241 err V614 Potentially uninitialized pointer 'pos' used.
/opt/pvs/accel-ppp/accel-pppd/radius/dict.c 165 err V614 Uninitialized pointer 'parent_items' used.
* Remove duplicate code
/opt/pvs/accel-ppp/accel-pppd/radius/serv.c 202 warn V547 Expression 'ts.tv_sec < req->serv->fail_time' is always false.
* Fix treating signed bool variables as unsigned
* Add nullptr checking
/opt/pvs/accel-ppp/accel-pppd/ipv6/dhcpv6.c 886 err V595 The 'opt->val' pointer was utilized before it was verified against nullptr. Check lines: 886, 890.
/opt/pvs/accel-ppp/accel-pppd/ipv6/nd.c 479 err V595 The 'opt->val' pointer was utilized before it was verified against nullptr. Check lines: 479, 483.
/opt/pvs/accel-ppp/accel-pppd/radius/auth.c 152 err V595 The 'rpd->auth_ctx' pointer was utilized before it was verified against nullptr. Check lines: 152, 154.
/opt/pvs/accel-ppp/accel-pppd/triton/conf_file.c 114 err V595 The 'cur_sect' pointer was utilized before it was verified against nullptr. Check lines: 114, 117.
* Add logging of exit conditions
* Clarify calculation
[accel-pppd/ppp/ccp_mppe.c:281]: (style) Clarify calculation precedence for '&' and '?'.
[accel-pppd/ppp/ccp_mppe.c:282]: (style) Clarify calculation precedence for '&' and '?'.
[accel-pppd/ppp/ccp_mppe.c:283]: (style) Clarify calculation precedence for '&' and '?'.
[accel-pppd/ppp/ccp_mppe.c:284]: (style) Clarify calculation precedence for '&' and '?'.
[accel-pppd/ppp/ccp_mppe.c:285]: (style) Clarify calculation precedence for '&' and '?'.
[accel-pppd/ppp/ccp_mppe.c:286]: (style) Clarify calculation precedence for '&' and '?'.
[drivers/ipoe/ipoe.c:307]: (style) Clarify calculation precedence for '&' and '?'.
* Fix void calculations
[accel-pppd/ctrl/pppoe/disc.c:211]: (portability) 'pkt' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/ctrl/pptp/pptp.c:150]: (portability) 'buf' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/radius/acct.c:37]: (portability) 'req.pack.buf' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/radius/auth.c:35]: (portability) 'req.pack.buf' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/radius/auth.c:79]: (portability) 'req.pack.buf' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/radius/dm_coa.c:43]: (portability) 'pack.buf' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/radius/dm_coa.c:47]: (portability) 'pack.buf' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/radius/dm_coa.c:57]: (portability) 'pack.buf' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/radius/dm_coa.c:65]: (portability) 'req.buf' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/radius/dm_coa.c:97]: (portability) 'req.buf' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/radius/serv.c:364]: (portability) 'req.pack.buf' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/triton/mempool.c:115]: (portability) 'mmap_ptr' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/triton/mempool.c:122]: (portability) 'mmap_ptr' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/triton/mempool.c:276]: (portability) 'ptr' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
* Fix void part 2
[accel-pppd/ipv6/dhcpv6.c:844]: (portability) 'conf_dnssl' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/ipv6/nd.c:199]: (portability) '(void*)dnsslinfo' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
[accel-pppd/ipv6/nd.c:432]: (portability) 'conf_dnssl' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.
* Fix null pointer dereference
[accel-pppd/ctrl/ipoe/ipoe.c:2048]: (warning) Possible null pointer dereference: eth
[accel-pppd/ctrl/ipoe/ipoe.c:2049]: (warning) Possible null pointer dereference: iph
* Remove redundant check
/opt/pvs/accel-ppp/accel-pppd/ctrl/l2tp/packet.c 656 warn V547 Expression 'attr->length <= 16' is always false.
* PR fixes
* PR fixes 2
|
|
|
|
[accel-pppd/cli/tcp.c:305]: (error) Uninitialized variable: cln
[accel-pppd/cli/telnet.c:642]: (error) Uninitialized variable: cln
[accel-pppd/ctrl/l2tp/l2tp.c:4302]: (error) Uninitialized variable: msg_attr
[accel-pppd/ctrl/l2tp/l2tp.c:4484]: (error) Uninitialized variable: msg_type
[accel-pppd/ctrl/pppoe/disc.c:169]: (error) Uninitialized variable: n
[accel-pppd/ctrl/pppoe/pppoe.c:1588]: (error) Uninitialized variable: pado
|
|
|
|
small check for zero buffer length on load history
|
|
|
|
list.h is an accel-ppp internal file.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
|
|
Define a new column, called "netns", that prints the network namespace
in which sessions are set.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
|
|
Several modules assume that if ses->ipv6 is set, then
ses->ipv6->addr_list contains at least one element. But this is not
true if ipv6 was allocated by the pseudo ipdb backend of ipv6cp
(ipv6cp_opt_intfid.c). That is, if the PPP session only has an
automatic link-local address.
This leads modules like pppd-compat and dhcpv6 to access invalid memory
when trying to retrieve the IPv6 address of a PPP session.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
|
|
|
|
|
|
Introduced 4 priorities:
0 - management (cli)
1 - starting sessions (default priority)
2 - active sessions
3 - finishing sessions
|
|
|
|
|
|
Hello,
small patch to avoid gcc -Wformat warnings on Debian x32 where time_t
is "long long" (64-bit signed, to be 2038 safe), not "unsigned long"
(32-bit unsigned) corresponding to "%lu" format strings.
Regards,
Marek
|
|
The telnet and tcp servers disconnect as soon as they receive the
'exit' command or see a disconnection from the client. In this case,
all data queued for transmission are lost. This can lead to truncated
output when big amount of data is being sent.
For example, on a moderately loaded server with a few thouthands
connections, the output of the 'accel-cmd show sessions' command can be
truncated.
The problem is that accel-cmd sends the 'show sessions' command,
followed by 'exit'. It does so because it has to stop running once all
data has been received from the server. But it never knows whether more
data are going to arrive. Disconnection must then come from the server,
hence the use of 'exit' (although the same effect could be achieved
with shutdown(SHUT_WR)).
The telnet and tcp modules behave very similarly and are modified in
the same way:
* For a soft disconnection, cln_read() doesn't call disconnect()
anymore if there are data queued for transmission. Instead it
sets the 'disconnect' flag and stops listening to its peer (no
need to process further messages).
* cln_write() checks the 'disconnect' flag once it has sent all
pending data and actually performs the disconnection if necessary.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
|
|
In tcp and telnet backends, the first buffer been queued is directly
pointed to by cln->xmit_buf. It's not added to cln->xmit_queue.
Therefore testing if ->xmit_queue is empty doesn't reliably tells
if data has already been queued.
We should test if ->xmit_buf is non-NULL instead. This is reliable
because ->xmit_buf is re-filled with the first buffer from ->xmit_queue
after every successful write().
Failure to properly check if data has already been queued can lead to
message miss-ordering because cli_client_send() or telnet_send() will
try to directly write() their input buffer, effectively bypassing the
one previously queued up in ->xmit_buf.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
|
|
When queueing output data for later write(), the 'n' first bytes of the
buffer have already been sent (we have n > 0 if EAGAIN was returned
after some other write() calls succeeded). Therefore, we need to skip
these bytes when initialising the buffer to be queued.
The size passed to memcpy() did already take that space into account.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
|
|
|
|
|
|
|
|
|
|
|
|
If verbose=0 then cli won't produce any logging
if verbose=1 then log only connections
if verbose=2 then log also executed commands
|
|
|
|
|
|
|
|
|
|
default)
|
|
Define the "sessions-columns" option (in the [cli] section) to let
the user select the default set of columns that will be displayed by
the "show sessions" command.
Unrecognised column names are silently discarded.
Configuration example:
[cli]
telnet=127.0.0.1:2000
password=secret
sessions-columns=ifname,ip,username
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
|
|
Gracefully handle the case where no column has been selected for the
"show sessions" command. Such situation will be possible once the set
of default displayed columns will be made configurable from
accel-ppp.conf.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
|
|
Handle CLI_CMD_FAILED like other command errors (i.e. return 0 to the
caller and send a generic error message).
This makes the CLI handler to flush its input buffer, so that
processing of the next command will be made correctly. This also makes
the telnet handler to send its prompt message.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
|
|
Call regexp command handler without command line's leading spaces.
This makes leading spaces handling consistent between the exec and help
command handlers (leading spaces are already skipped before calling
help handlers).
This also gives the possibility to register an anchored regexp command
without having to manage the leading spaces in that regexp.
Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
|