Compare commits

...

16 Commits

Author SHA1 Message Date
Pieter De Gendt
db069aa115 drivers: gpio: mcux: Fix updating ICR registers without IRQ lock
During configuration the base->ICR1 or base->ICR2 register is written
without an IRQ lock. This can result in unwanted side-effects if the status
bit isn't cleared, or the edge select still needs to be updated.

Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
(cherry picked from commit 8402a4f8e5)
2026-01-23 12:55:41 +00:00
Keith Short
b0683aba74 posix: c_lib_ext: fnmatch: fix llvm warning
The tolower() function takes an int parameter. LLVM compilers generate a
warning if a char is passed instead.

Signed-off-by: Keith Short <keithshort@google.com>
2026-01-13 12:42:05 -05:00
Chris Friedt
53f18035d5 posix: c_lib_ext: fnmatch: fix character class support
A couple of tests were inconsistent with glibc and picolibc.

Significant rework done to the `fnmatch()` implementation which included
refreshing that and the `rangematch()` implementations from commit

0a3b2e376d150258c8294c12a85bec99546ab84b

in https://github.com/lattera/freebsd

Removed `match_posix_class()` and implemented that functionality as
`rangematch_cc()`, which uses 64-bit integer comparison for matching
`[:alnum:]` et al instead of string comparison. That likely only works
for the "C" locale.

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
Signed-off-by: Harun Spago <harun.spago.code@gmail.com>
(cherry picked from commit de2d0c9563)
2026-01-13 12:42:05 -05:00
Chris Friedt
26f00561a9 posix: c_lib_ext: fnmatch: fix escape-oriented regression
A regression in 936d0278bd introduced a
subtle bug in the way that escaped expressions were handled.

The regression originated with the assumption that test data (originally
adapted from a 3rd-party testsuite) was correct when it was in fact
flawed.

Specifically, `fnmatch("[[?*\\]", "\\", 0)` should fail (`FNM_NOMATCH`),
since the "\\" sequence (a single backslash after compilation) escapes
the following ']' character, thus leaving the bracket expression
incomplete.

As @keith-packard  has pointed out,
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/\
V3_chap02.html#tag_18_13_01 says that a bracket expression is only
interpreted as a bracket expression, when a proper bracket expression
is formed.

Therefore, the pattern is interpreted as the sequence
`'['`, `'['`, `'?'`, `*` (wildcard), `']'` and the call should return
`FNM_NOMATCH` to indicate failure rather than 0 to indicate success.

Added new test cases from #98827 and some commentary for subsequent
reviewers.

This change does not completely fix #55186 but is related to it.

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
(cherry picked from commit 637080e7ec)
2026-01-13 12:42:05 -05:00
Chris Friedt
5206f493b9 libc: minimal: add missing ctype.h functions
Add the functions below to the minimal libc ctype.h since they are
missing, and are required as of C89 (C99 for `isblank()`)

* `isblank()`
* `islower()`
* `ispunct()`

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
2026-01-13 12:42:05 -05:00
Chris Friedt
06e38d511c libc: minimal: ctype: remove unnecessary casts
A review comment in the PR below requested that unnecessary casts were
removed from ctype.h in the PR below.

https://github.com/zephyrproject-rtos/zephyr/pull/99451

Tested with manual compilation in C and C++ mode with the arguments
```shell
gcc -Wconversion -Werror -Wall -Wextra -Wint-conversion
clang -Wconversion -Werror -Wall -Wextra -Wint-conversion
gcc -Wconversion -Werror -Wall -Wimplicit--Wextra
clang++ -Wconversion -Werror -Wall -Wextra
```

and also with `-- -DCONFIG_COMPILER_WARNINGS_AS_ERRORS=y`

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
2026-01-13 12:42:05 -05:00
Chris Friedt
cbd2cea099 libc: minimal: ctype: express ctype limits in more direct fashion
Based on review feedback, it was suggested to express ctype
character checks in a more direct fashion, rather than using
arithmetic, and allow the compiler to optimize as it sees fit.

https://github.com/zephyrproject-rtos/zephyr/pull/99451#\
discussion_r2530339430

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
2026-01-13 12:42:05 -05:00
Chris Friedt
316cf05463 libc: minimal: ctype: use unsigned int instead of unsigned
The "check warns" workflow in CI warned over the use of `unsigned` as a
shorthand for `unsigned int` in several locations in
`lib/libc/minimal/include/ctype.h`.

```
 UNSPECIFIED_INT: Prefer 'unsigned int' to bare use of 'unsigned'
File:lib/libc/minimal/include/ctype.h
```

Adjust `unsigned` to `unsigned int` to avoid linter warnings.

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
2026-01-13 12:42:05 -05:00
Joel Schaller
59e779d9ed shell: backend: telnet: No Error ENETDOWN
Set Log Level to Info when the Telnet socket reports ENETDOWN,
instead of logging an error each time the network is down.

Signed-off-by: Joel Schaller <joel.schaller16@gmail.com>
(cherry picked from commit 8f6b216ec0)
2026-01-12 12:50:23 -05:00
Sven Ginka
fd649f17f0 drivers: ethernet: dsa_nxp_imx_netc: fix zephyr random mac
zephyr,random-mac-address defaults to 0 or 1, which is always
available in generated code. so we can use the value itself.

Signed-off-by: Sven Ginka <s.ginka@sensry.de>
(cherry picked from commit c4a4d8aa87)
2026-01-12 12:48:16 -05:00
Missael Maciel
e0a24d3471 drivers: uart: save interrupts in PM Action
Removed usart_intenset attribute from conditional compilation
in mcux_flexcomm_data structure since this parameter needs to
be saved/restored independently if the interrupts are enabled
or not based on the PR feedback

Signed-off-by: Missael Maciel <davidmissael.maciel@nxp.com>
(cherry picked from commit 726e7b64c2)
2026-01-12 14:39:08 +02:00
Missael Maciel
1ff7fbbaa2 drivers: uart: save interrupts in PM Action
The PM action saves the interrupts enabled using a
global variable called usart_intenset. The problem is
when you have multiple uart instances that have different
configurations, when entering/exiting from a power level,
only one configuration is saved and will be applied to all
uart instances when exiting from a power level. We need to
keep this setting individual for each instance. To do this,
usart_intenset was added as a new element to mcux_flexcomm_data
structure. In this way, each uart instance will keep/restore
each own setting.

Signed-off-by: Missael Maciel <davidmissael.maciel@nxp.com>
(cherry picked from commit a84e0b5413)
2026-01-12 14:39:08 +02:00
Pieter De Gendt
ee992eb6a8 scripts: west: packages: Print warning on windows or run new command
On non-Windows systems execute a new program, replacing the west packages
call, when trying to install packages using pip.
For Windows, update the documented way of installing python packages,
or using 'west packages pip --install' print a warning.

Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
(cherry picked from commit 7f97d3dd0a)
2026-01-12 14:35:56 +02:00
Tomasz Chyrowicz
ef1b2dfd56 mcumgr: Prevent FW loader from self-destruction
The FW loader reports and manages exactly two slots:
 - slot 0: this is the slot for the application code to update
 - slot 1: this is the slot, in which the FW loader is placed

The slot 1 is reported, so tools can fetch metadata about the
FW loader installed on the device.
Unfortunately, currently SMP-based FW loader allows to issue slot erase
command for the slot 1, effectively erasing the FW loader code that is
being executed.

This change correctly identifies the slot 1 as an active one, marking it
as used and blocking erase operation on that slot.

Signed-off-by: Tomasz Chyrowicz <tomasz.chyrowicz@nordicsemi.no>
(cherry picked from commit 26128ab73d)
2026-01-12 14:35:44 +02:00
Alberto Escolar Piedras
cde22a3191 drivers: xen: Fix uninitialized variable warning
gcc complains about the posibility of ret and gfn being used
unitialiazed (with the input npages == 0).
Let's fix it by initializing ret to 0.

The warnings being:
```
      zephyr/CMakeFiles/zephyr.dir/drivers/xen/gnttab.c.obj
In file included from include/zephyr/logging/log.h:11,
                 from drivers/xen/gnttab.c:31:
include/zephyr/logging/log_core.h: In function 'gnttab_get_pages':
include/zephyr/logging/log_core.h:221:9: warning: 'gfn' may be used
uninitialized [-Wmaybe-uninitialized]
  221 |         z_log_minimal_printk("%c: " fmt "\n", \
      |         ^~~~~~~~~~~~~~~~~~~~
drivers/xen/gnttab.c:202:19: note: 'gfn' was declared here
  202 |         xen_pfn_t gfn;
      |                   ^~~
include/zephyr/logging/log_core.h:221:9: warning: 'ret' may be used
uninitialized [-Wmaybe-uninitialized]
  221 |         z_log_minimal_printk("%c: " fmt "\n", \
      |         ^~~~~~~~~~~~~~~~~~~~
drivers/xen/gnttab.c:199:13: note: 'ret' was declared here
  199 |         int ret;
      |             ^~~
```

Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
(cherry picked from commit 139b7c20c2)
2026-01-12 14:35:33 +02:00
Martin Stumpf
6173a3cb3e MCUmgr: OS: fix set datetime millisecond handling
According to the docs the millis were in the format `.SSSSSS`. In
reality though, it only accepted exactly `.SSS`, not `.SS` or `.SSSS`
and specifically also not `.SSSSSS`, contrary to the docs. Further, it did
not fail with an error message but simply produced the wrong value.

With this change it accepts everything from `.` to `.SSSSSS` and
produces the correct result. This is compatible with the previous
behavior, with the documentation and with everything in between.

Signed-off-by: Martin Stumpf <finomnis@gmail.com>
(cherry picked from commit ffb046b797)
2026-01-12 14:35:12 +02:00
15 changed files with 506 additions and 193 deletions

View File

@@ -83,7 +83,7 @@ of i.MX NETC.
.phy_mode = NETC_PHY_MODE(port), \
}; \
struct dsa_port_config dsa_##n##_##port##_config = { \
.use_random_mac_addr = DT_NODE_HAS_PROP(port, zephyr_random_mac_address), \
.use_random_mac_addr = DT_PROP(port, zephyr_random_mac_address), \
.mac_addr = DT_PROP_OR(port, local_mac_address, {0}), \
.port_idx = DT_REG_ADDR(port), \
.phy_dev = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(port, phy_handle)), \

View File

@@ -136,16 +136,39 @@ Keeping Zephyr updated
To update the Zephyr project source code, you need to get the latest
changes via ``git``. Afterwards, run ``west update`` as mentioned in
the previous paragraph.
Additionally, in the case of updated or added Python dependencies, running
``west packages pip --install`` will make sure these are up-to-date.
Additionally, check for updated or added Python dependencies.
.. code-block:: console
.. tabs::
# replace zephyrproject with the path you gave west init
cd zephyrproject/zephyr
git pull
west update
west packages pip --install
.. group-tab:: Linux/macOS
.. code-block:: console
# replace zephyrproject with the path you gave west init
cd zephyrproject/zephyr
git pull
west update
west packages pip --install
.. group-tab:: Windows
.. tabs::
.. code-tab:: bat
:: replace zephyrproject with the path you gave west init
cd zephyrproject\zephyr
git pull
west update
cmd /c scripts\utils\west-packages-pip-install.cmd
.. code-tab:: powershell
# replace zephyrproject with the path you gave west init
cd zephyrproject\zephyr
git pull
west update
python -m pip install @((west packages pip) -split ' ')
Export Zephyr CMake package
***************************

View File

@@ -266,6 +266,10 @@ chosen. You'll also install Zephyr's additional Python dependencies in a
west packages pip --install
.. note::
This could downgrade or upgrade west itself.
.. group-tab:: macOS
#. Create a new virtual environment:
@@ -317,6 +321,10 @@ chosen. You'll also install Zephyr's additional Python dependencies in a
west packages pip --install
.. note::
This could downgrade or upgrade west itself.
.. group-tab:: Windows
#. Open a ``cmd.exe`` or PowerShell terminal window **as a regular user**
@@ -389,9 +397,19 @@ chosen. You'll also install Zephyr's additional Python dependencies in a
#. Install Python dependencies using ``west packages``.
.. code-block:: bat
.. tabs::
west packages pip --install
.. code-tab:: bat
cmd /c scripts\utils\west-packages-pip-install.cmd
.. code-tab:: powershell
python -m pip install @((west packages pip) -split ' ')
.. note::
This could downgrade or upgrade west itself.
Install the Zephyr SDK
**********************

View File

@@ -451,7 +451,7 @@ static struct dsa_api dsa_netc_api = {
.phy_mode = NETC_PHY_MODE(port), \
}; \
struct dsa_port_config dsa_##n##_##port##_config = { \
.use_random_mac_addr = DT_NODE_HAS_PROP(port, zephyr_random_mac_address), \
.use_random_mac_addr = DT_PROP(port, zephyr_random_mac_address), \
.mac_addr = DT_PROP_OR(port, local_mac_address, {0}), \
.port_idx = DT_REG_ADDR(port), \
.phy_dev = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(port, phy_handle)), \
@@ -482,6 +482,6 @@ static struct dsa_api dsa_netc_api = {
POST_KERNEL, \
CONFIG_ETH_INIT_PRIORITY, \
NULL); \
DSA_SWITCH_INST_INIT(n, &dsa_netc_api, &dsa_netc_data_##n, DSA_NETC_PORT_INST_INIT); \
DSA_SWITCH_INST_INIT(n, &dsa_netc_api, &dsa_netc_data_##n, DSA_NETC_PORT_INST_INIT);
DT_INST_FOREACH_STATUS_OKAY(DSA_NETC_DEVICE);

View File

@@ -288,6 +288,10 @@ static int mcux_igpio_pin_interrupt_configure(const struct device *dev,
return -ENOTSUP;
}
if (pin >= 32) {
return -EINVAL;
}
if (mode == GPIO_INT_MODE_DISABLED) {
key = irq_lock();
@@ -310,18 +314,16 @@ static int mcux_igpio_pin_interrupt_configure(const struct device *dev,
icr = 0;
}
key = irq_lock();
if (pin < 16) {
shift = 2 * pin;
base->ICR1 = (base->ICR1 & ~(3 << shift)) | (icr << shift);
} else if (pin < 32) {
} else {
shift = 2 * (pin - 16);
base->ICR2 = (base->ICR2 & ~(3 << shift)) | (icr << shift);
} else {
return -EINVAL;
}
key = irq_lock();
WRITE_BIT(base->EDGE_SEL, pin, trig == GPIO_INT_TRIG_BOTH);
WRITE_BIT(base->ISR, pin, 1);
WRITE_BIT(base->IMR, pin, 1);

View File

@@ -108,6 +108,7 @@ struct mcux_flexcomm_data {
bool pm_policy_state_lock;
struct k_work pm_lock_work;
#endif
uint32_t usart_intenset;
};
#ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
@@ -1205,10 +1206,10 @@ static void mcux_flexcomm_pm_restore_wake(const struct device *dev,
}
#endif /* FC_UART_IS_WAKEUP */
static uint32_t usart_intenset;
static int mcux_flexcomm_pm_action(const struct device *dev, enum pm_device_action action)
{
const struct mcux_flexcomm_config *config = dev->config;
struct mcux_flexcomm_data *data = dev->data;
int ret;
switch (action) {
@@ -1217,14 +1218,14 @@ static int mcux_flexcomm_pm_action(const struct device *dev, enum pm_device_acti
case PM_DEVICE_ACTION_SUSPEND:
break;
case PM_DEVICE_ACTION_TURN_OFF:
usart_intenset = USART_GetEnabledInterrupts(config->base);
data->usart_intenset = USART_GetEnabledInterrupts(config->base);
break;
case PM_DEVICE_ACTION_TURN_ON:
ret = mcux_flexcomm_init_common(dev);
if (ret) {
return ret;
}
USART_EnableInterrupts(config->base, usart_intenset);
USART_EnableInterrupts(config->base, data->usart_intenset);
break;
default:
return -ENOTSUP;

View File

@@ -196,7 +196,7 @@ static void gop_eagain_retry(int cmd, struct gnttab_map_grant_ref *gref)
void *gnttab_get_pages(unsigned int npages)
{
int ret;
int ret = 0;
void *page_addr;
unsigned int removed;
xen_pfn_t gfn;

View File

@@ -15,63 +15,82 @@ extern "C" {
static inline int isupper(int a)
{
return (int)(((unsigned)(a)-(unsigned)'A') < 26U);
return (('A' <= a) && (a <= 'Z'));
}
static inline int isalpha(int c)
{
return (int)((((unsigned)c|32u)-(unsigned)'a') < 26U);
/* force to lowercase */
c |= 32;
return (('a' <= c) && (c <= 'z'));
}
static inline int isblank(int c)
{
return ((c == ' ') || (c == '\t'));
}
static inline int isspace(int c)
{
return (int)(c == (int)' ' || ((unsigned)c-(unsigned)'\t') < 5U);
return ((c == ' ') || (('\t' <= c) && (c <= '\r')));
}
static inline int isgraph(int c)
{
return (int)((((unsigned)c) > ' ') &&
(((unsigned)c) <= (unsigned)'~'));
return ((' ' < c) && (c <= '~'));
}
static inline int isprint(int c)
{
return (int)((((unsigned)c) >= ' ') &&
(((unsigned)c) <= (unsigned)'~'));
return ((' ' <= c) && (c <= '~'));
}
static inline int isdigit(int a)
{
return (int)(((unsigned)(a)-(unsigned)'0') < 10U);
return (('0' <= a) && (a <= '9'));
}
static inline int islower(int c)
{
return (('a' <= c) && (c <= 'z'));
}
static inline int isxdigit(int a)
{
unsigned int ua = (unsigned int)a;
if (isdigit(a) != 0) {
return 1;
}
return (int)(((ua - (unsigned)'0') < 10U) ||
((ua | 32U) - (unsigned)'a' < 6U));
/* force to lowercase */
a |= 32;
return (('a' <= a) && (a <= 'f'));
}
static inline int tolower(int chr)
{
return (chr >= (int)'A' && chr <= (int)'Z') ? (chr + 32) : (chr);
return (chr >= 'A' && chr <= 'Z') ? (chr + 32) : (chr);
}
static inline int toupper(int chr)
{
return (int)((chr >= (int)'a' && chr <=
(int)'z') ? (chr - 32) : (chr));
return ((chr >= 'a' && chr <= 'z') ? (chr - 32) : (chr));
}
static inline int isalnum(int chr)
{
return (int)(isalpha(chr) || isdigit(chr));
return (isalpha(chr) || isdigit(chr));
}
static inline int ispunct(int c)
{
return (isgraph(c) && !isalnum(c));
}
static inline int iscntrl(int c)
{
return (int)((((unsigned int)c) <= 31U) || (((unsigned int)c) == 127U));
return ((((unsigned int)c) <= 31U) || (((unsigned int)c) == 127U));
}
#ifdef __cplusplus

View File

@@ -9,6 +9,11 @@
* This code is derived from software contributed to Berkeley by
* Guido van Rossum.
*
* Copyright (c) 2011 The FreeBSD Foundation
* All rights reserved.
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -48,26 +53,121 @@
#define EOS '\0'
#ifndef FNM_NORES
#define FNM_NORES 3
#endif
#ifndef FNM_LEADING_DIR
#define FNM_LEADING_DIR 0x08
#endif
#ifndef FNM_CASEFOLD
#define FNM_CASEFOLD 0x10
#endif
#define FOLDCASE(ch, flags) foldcase((unsigned char)(ch), (flags))
#define RANGE_ERROR (-1)
#define RANGE_NOMATCH 1
#define RANGE_MATCH 0
/* POSIX character class matching was missing from the BSD version. This was added in 2025 */
static int rangematch_cc(const char **pattern, int ch)
{
typedef unsigned long long ull;
/*
* [:alnum:] et al are 9 characters. [:xdigits:] is 10.
* If we first check for the leading "[:", then we have at most 8 remaining characters to
* compare. Rather than using string comparison, encode the 8 characters into an integer and
* compare to a precomputed constants. This likely only works for the "C" locale.
*/
#define FNM_CC5(a, b, c, d, e) \
(((ull)(a) << 48) | ((ull)(b) << 40) | ((ull)(c) << 32) | ((ull)(d) << 24) | \
((ull)(e) << 16) | ((ull)':' << 8) | ((ull)']' << 0))
#define FNM_CC6(a, b, c, d, e, f) \
(((ull)(a) << 56) | ((ull)(b) << 48) | ((ull)(c) << 40) | ((ull)(d) << 32) | \
((ull)(e) << 24) | ((ull)(f) << 16) | ((ull)':' << 8) | ((ull)']' << 0))
ull key;
int ret;
const char *p = *pattern;
/* check the leading "[:" */
if ((p[0] != '[') || (p[1] != ':')) {
return RANGE_ERROR;
}
/* encode the remaining characters into a 64-bit integer */
for (p += 2, key = 0; *p != EOS; ++p) {
if (*(p - 1) == ']') {
break;
}
key <<= 8;
key |= (unsigned char)(*p);
}
switch (key) {
case FNM_CC5('a', 'l', 'n', 'u', 'm'):
ret = !isalnum(ch);
break;
case FNM_CC5('a', 'l', 'p', 'h', 'a'):
ret = !isalpha(ch);
break;
case FNM_CC5('b', 'l', 'a', 'n', 'k'):
ret = !isblank(ch);
break;
case FNM_CC5('c', 'n', 't', 'r', 'l'):
ret = !iscntrl(ch);
break;
case FNM_CC5('d', 'i', 'g', 'i', 't'):
ret = !isdigit(ch);
break;
case FNM_CC5('g', 'r', 'a', 'p', 'h'):
ret = !isgraph(ch);
break;
case FNM_CC5('l', 'o', 'w', 'e', 'r'):
ret = !islower(ch);
break;
case FNM_CC5('p', 'r', 'i', 'n', 't'):
ret = !isprint(ch);
break;
case FNM_CC5('p', 'u', 'n', 'c', 't'):
ret = !ispunct(ch);
break;
case FNM_CC5('s', 'p', 'a', 'c', 'e'):
ret = !isspace(ch);
break;
case FNM_CC5('u', 'p', 'p', 'e', 'r'):
ret = !isupper(ch);
break;
case FNM_CC6('x', 'd', 'i', 'g', 'i', 't'):
ret = !isxdigit(ch);
break;
default:
return RANGE_ERROR;
}
*pattern = p;
return ret;
}
static inline int foldcase(int ch, int flags)
{
if ((flags & FNM_CASEFOLD) != 0 && isupper(ch)) {
if (((flags & FNM_CASEFOLD) != 0) && isupper(ch)) {
return tolower(ch);
}
return ch;
}
#define FOLDCASE(ch, flags) foldcase((unsigned char)(ch), (flags))
static const char *rangematch(const char *pattern, int test, int flags)
static int rangematch(const char **pattern, char test, int flags)
{
bool negate, ok, need;
char c, c2;
if (pattern == NULL) {
return NULL;
}
int negate, ok;
const char *origpat;
const char *pat = *pattern;
/*
* A bracket expression starting with an unquoted circumflex
@@ -76,90 +176,113 @@ static const char *rangematch(const char *pattern, int test, int flags)
* consistency with the regular expression syntax.
* J.T. Conklin (conklin@ngai.kaleida.com)
*/
negate = *pattern == '!' || *pattern == '^';
negate = (*pat == '!' || *pat == '^');
if (negate) {
++pattern;
++pat;
}
for (need = true, ok = false, c = FOLDCASE(*pattern++, flags); c != ']' || need;
c = FOLDCASE(*pattern++, flags)) {
need = false;
test = FOLDCASE(test, flags);
if (c == '/' && (flags & FNM_PATHNAME)) {
return (void *)-1;
}
if (c == '\\' && !(flags & FNM_NOESCAPE)) {
if (*pattern != ']' && *pattern != EOS) {
c = FOLDCASE(*pattern++, flags);
/*
* A right bracket shall lose its special meaning and represent
* itself in a bracket expression if it occurs first in the list.
* -- POSIX.2 2.8.3.2
*/
ok = 0;
origpat = pat;
for (;;) {
if (*pat == ']' && pat > origpat) {
pat++;
break;
} else if (*pat == '\0') {
return RANGE_ERROR;
} else if (*pat == '/' && (flags & FNM_PATHNAME)) {
return RANGE_NOMATCH;
} else if (*pat == '\\' && !(flags & FNM_NOESCAPE)) {
pat++;
} else {
switch (rangematch_cc(&pat, test)) {
case RANGE_ERROR:
/* not a character class, proceed below */
break;
case RANGE_MATCH:
/* a valid character class that was matched */
ok = 1;
continue;
case RANGE_NOMATCH:
/* a valid character class that was not matched */
continue;
}
}
if (c == EOS) {
return NULL;
}
c = FOLDCASE(*pat++, flags);
if (*pattern == '-') {
c2 = FOLDCASE(*(pattern + 1), flags);
if (c2 != EOS && c2 != ']') {
pattern += 2;
if (c2 == '\\' && !(flags & FNM_NOESCAPE)) {
c2 = FOLDCASE(*pattern++, flags);
if (*pat == '-' && *(pat + 1) != EOS && *(pat + 1) != ']') {
if (*++pat == '\\' && !(flags & FNM_NOESCAPE)) {
if (*pat != EOS) {
pat++;
}
}
c2 = FOLDCASE(*pat, flags);
pat++;
if (c2 == EOS) {
return RANGE_ERROR;
}
if (c2 == EOS) {
return NULL;
}
if (flags & FNM_CASEFOLD) {
c2 = tolower((int)c2);
}
if (c <= test && test <= c2) {
ok = true;
}
if (c <= test && test <= c2) {
ok = 1;
}
} else if (c == test) {
ok = true;
ok = 1;
}
}
return ok == negate ? NULL : pattern;
if (ok != negate) {
*pattern = pat;
return RANGE_MATCH;
}
return RANGE_NOMATCH;
}
static int fnmatchx(const char *pattern, const char *string, int flags, size_t recursion)
static int fnmatchx(const char *pattern, const char *string, const char *stringstart, int flags,
size_t recursion)
{
const char *stringstart, *r;
char c, test;
if (pattern == NULL || string == NULL) {
return FNM_NOMATCH;
}
char c;
char pc, sc;
if (recursion-- == 0) {
return FNM_NORES;
}
for (stringstart = string;;) {
c = FOLDCASE(*pattern++, flags);
switch (c) {
while (true) {
pc = FOLDCASE(*pattern++, flags);
sc = FOLDCASE(*string, flags);
switch (pc) {
case EOS:
if ((flags & FNM_LEADING_DIR) && *string == '/') {
if (((flags & FNM_LEADING_DIR) != 0) && (sc == '/')) {
return 0;
}
return *string == EOS ? 0 : FNM_NOMATCH;
if (sc == EOS) {
return 0;
}
return FNM_NOMATCH;
case '?':
if (*string == EOS) {
if (sc == EOS) {
return FNM_NOMATCH;
}
if (*string == '/' && (flags & FNM_PATHNAME)) {
if ((sc == '/') && ((flags & FNM_PATHNAME) != 0)) {
return FNM_NOMATCH;
}
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/'))) {
if ((sc == '.') && ((flags & FNM_PERIOD) != 0) &&
((string == stringstart) ||
(((flags & FNM_PATHNAME) != 0) && (*(string - 1) == '/')))) {
return FNM_NOMATCH;
}
++string;
break;
case '*':
@@ -169,107 +292,85 @@ static int fnmatchx(const char *pattern, const char *string, int flags, size_t r
c = FOLDCASE(*++pattern, flags);
}
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/'))) {
if ((sc == '.') && ((flags & FNM_PERIOD) != 0) &&
((string == stringstart) ||
(((flags & FNM_PATHNAME) != 0) && (*(string - 1) == '/')))) {
return FNM_NOMATCH;
}
/* Optimize for pattern with * at end or before /. */
if (c == EOS) {
if (flags & FNM_PATHNAME) {
return (flags & FNM_LEADING_DIR) ||
strchr(string, '/') == NULL
? 0
: FNM_NOMATCH;
} else {
if ((flags & FNM_PATHNAME) == 0) {
return 0;
}
} else if (c == '/' && flags & FNM_PATHNAME) {
if (((flags & FNM_LEADING_DIR) != 0) ||
(strchr(string, '/') == NULL)) {
return 0;
}
return FNM_NOMATCH;
} else if ((c == '/') && ((flags & FNM_PATHNAME) != 0)) {
string = strchr(string, '/');
if (string == NULL) {
return FNM_NOMATCH;
}
break;
}
/* General case, use recursion. */
do {
test = FOLDCASE(*string, flags);
if (test == EOS) {
while (sc != EOS) {
if (fnmatchx(pattern, string, stringstart, flags, recursion) == 0) {
return 0;
}
sc = FOLDCASE(*string, flags);
if ((sc == '/') && ((flags & FNM_PATHNAME) != 0)) {
break;
}
int e = fnmatchx(pattern, string, flags & ~FNM_PERIOD, recursion);
if (e != FNM_NOMATCH) {
return e;
}
if (test == '/' && flags & FNM_PATHNAME) {
break;
}
++string;
} while (true);
}
return FNM_NOMATCH;
case '[':
if (*string == EOS) {
if (sc == EOS) {
return FNM_NOMATCH;
}
if ((sc == '/') && ((flags & FNM_PATHNAME) != 0)) {
return FNM_NOMATCH;
}
if ((sc == '.') && ((flags & FNM_PERIOD) != 0) &&
((string == stringstart) ||
(((flags & FNM_PATHNAME) != 0) && (*(string - 1) == '/')))) {
return FNM_NOMATCH;
}
if (*string == '/' && flags & FNM_PATHNAME) {
return FNM_NOMATCH;
}
if (*string == '.' && (flags & FNM_PERIOD) &&
(string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/'))) {
return FNM_NOMATCH;
}
r = rangematch(pattern, FOLDCASE(*string, flags), flags);
if (r == NULL) {
if (FOLDCASE('[', flags) != FOLDCASE(*string, flags)) {
return FNM_NOMATCH;
}
++string;
switch (rangematch(&pattern, sc, flags)) {
case RANGE_ERROR:
goto norm;
case RANGE_MATCH:
break;
case RANGE_NOMATCH:
return FNM_NOMATCH;
}
if (r == (void *)-1) {
if (*string != '[') {
return FNM_NOMATCH;
}
} else {
pattern = r;
}
++string;
break;
case '\\':
if (!(flags & FNM_NOESCAPE)) {
c = FOLDCASE(*pattern++, flags);
if (c == EOS) {
c = '\0';
--pattern;
}
if ((flags & FNM_NOESCAPE) == 0) {
pc = FOLDCASE(*pattern++, flags);
}
__fallthrough;
default:
if (c != FOLDCASE(*string++, flags)) {
norm:
if (pc != sc) {
return FNM_NOMATCH;
}
++string;
break;
}
}
CODE_UNREACHABLE;
}
int fnmatch(const char *pattern, const char *string, int flags)
{
return fnmatchx(pattern, string, flags, 64);
return fnmatchx(pattern, string, string, flags, 64);
}

View File

@@ -0,0 +1,27 @@
:: SPDX-FileCopyrightText: Copyright The Zephyr Project Contributors
:: SPDX-License-Identifier: Apache-2.0
@echo off
rem Collect packages from west and install them with a single pip call.
setlocal enabledelayedexpansion
set "PACKAGES="
for /f "usebackq delims=" %%p in (`west packages pip`) do (
if defined PACKAGES (
set "PACKAGES=!PACKAGES! %%p"
) else (
set "PACKAGES=%%p"
)
)
if not defined PACKAGES (
echo west packages pip returned no packages to install.
exit /b 0
)
echo Installing packages with: python.exe -m pip install %PACKAGES%
python.exe -m pip install %PACKAGES%
set "RESULT=%ERRORLEVEL%"
endlocal & exit /b %RESULT%

View File

@@ -4,13 +4,15 @@
import argparse
import os
import platform
import subprocess
import sys
import textwrap
from itertools import chain
from pathlib import Path
from pathlib import Path, PureWindowsPath
from west.commands import WestCommand
from west.util import quote_sh_list
from zephyr_ext_common import ZEPHYR_BASE
sys.path.append(os.fspath(Path(__file__).parent.parent))
@@ -157,11 +159,38 @@ class Packages(WestCommand):
self.die("Running pip install outside of a virtual environment")
if len(requirements) > 0:
subprocess.check_call(
[sys.executable, "-m", "pip", "install"]
+ list(chain.from_iterable([("-r", r) for r in requirements]))
+ manager_args
cmd = [sys.executable, "-m", "pip", "install"]
cmd += chain.from_iterable([("-r", str(r)) for r in requirements])
cmd += manager_args
self.dbg(quote_sh_list(cmd))
# Use os.execv to execute a new program, replacing the current west process,
# this unloads all python modules first and allows for pip to update packages safely
if platform.system() != 'Windows':
os.execv(cmd[0], cmd)
# Only reachable on Windows systems
# Windows does not really support os.execv:
# https://github.com/python/cpython/issues/63323
# https://github.com/python/cpython/issues/101191
# Warn the users about permission errors as those reported in:
# https://github.com/zephyrproject-rtos/zephyr/issues/100296
cmdscript = (
PureWindowsPath(__file__).parents[1] / "utils" / "west-packages-pip-install.cmd"
)
self.wrn(
"Updating packages on Windows with 'west packages pip --install', that are "
"currently in use by west, results in permission errors. Leaving your "
"environment with conflicting package versions. Recommended is to start with "
"a new environment in that case.\n\n"
"To avoid this using powershell run the following command instead:\n"
f"{sys.executable} -m pip install @((west packages pip) -split ' ')\n\n"
"Using cmd.exe execute the helper script:\n"
f"cmd /c {cmdscript}\n\n"
"Running 'west packages pip --install -- --dry-run' can provide information "
"without actually updating the environment."
)
subprocess.check_call(cmd)
else:
self.inf("Nothing to install")
return

View File

@@ -361,15 +361,13 @@ img_mgmt_state_any_pending(void)
int
img_mgmt_slot_in_use(int slot)
{
#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_FIRMWARE_UPDATER)
return 0;
#else
int image = img_mgmt_slot_to_image(slot);
int active_slot = img_mgmt_active_slot(image);
#if !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) && \
!defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) && \
!defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT)
!defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT) && \
!defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_FIRMWARE_UPDATER)
enum img_mgmt_next_boot_type type = NEXT_BOOT_TYPE_NORMAL;
int nbs = img_mgmt_get_next_boot_slot(image, &type);
@@ -391,7 +389,6 @@ img_mgmt_slot_in_use(int slot)
#endif
return (active_slot == slot);
#endif /* !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_FIRMWARE_UPDATER) */
}
/**

View File

@@ -18,6 +18,7 @@
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <zcbor_common.h>
#include <zcbor_encode.h>
@@ -117,8 +118,6 @@ struct datetime_parser {
#define RTC_DATETIME_MINUTE_MAX 59
#define RTC_DATETIME_SECOND_MIN 0
#define RTC_DATETIME_SECOND_MAX 59
#define RTC_DATETIME_MILLISECOND_MIN 0
#define RTC_DATETIME_MILLISECOND_MAX 999
/* Size used for datetime creation buffer */
#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_MS
@@ -129,7 +128,7 @@ struct datetime_parser {
/* Minimum/maximum size of a datetime string that a client can provide */
#define RTC_DATETIME_MIN_STRING_SIZE 19
#define RTC_DATETIME_MAX_STRING_SIZE 26
#define RTC_DATETIME_MAX_STRING_SIZE 31
#endif
/* Specifies what the "all" ('a') of info parameter shows */
@@ -969,7 +968,7 @@ static int os_mgmt_datetime_write(struct smp_streamer *ctxt)
bool ok = true;
char *pos;
char *new_pos;
char date_string[RTC_DATETIME_MAX_STRING_SIZE];
char date_string[RTC_DATETIME_MAX_STRING_SIZE + 1];
struct rtc_time new_time = {
.tm_wday = -1,
.tm_yday = -1,
@@ -1024,7 +1023,7 @@ static int os_mgmt_datetime_write(struct smp_streamer *ctxt)
if (zcbor_map_decode_bulk(zsd, datetime_decode, ARRAY_SIZE(datetime_decode), &decoded)) {
return MGMT_ERR_EINVAL;
} else if (datetime.len < RTC_DATETIME_MIN_STRING_SIZE ||
datetime.len >= RTC_DATETIME_MAX_STRING_SIZE) {
datetime.len > RTC_DATETIME_MAX_STRING_SIZE) {
return MGMT_ERR_EINVAL;
}
@@ -1060,16 +1059,20 @@ static int os_mgmt_datetime_write(struct smp_streamer *ctxt)
}
#ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_MS
if (*(pos - 1) == '.' && *pos != '\0') {
/* Provided value has a ms value, extract it */
new_time.tm_nsec = strtol(pos, &new_pos, RTC_DATETIME_NUMERIC_BASE);
if (*(pos - 1) == '.') {
uint32_t msec = 0;
uint32_t mul = 100; /* first digit: 10^-1 second = 100 ms */
if (new_time.tm_nsec < RTC_DATETIME_MILLISECOND_MIN ||
new_time.tm_nsec > RTC_DATETIME_MILLISECOND_MAX) {
return MGMT_ERR_EINVAL;
/* Parse up to 3 fractional digits */
while (isdigit((unsigned char)*pos) && mul >= 1) {
msec += (uint32_t)(*pos - '0') * mul;
mul /= 10;
pos++;
}
new_time.tm_nsec *= RTC_DATETIME_MS_TO_NS;
/* "." without digits yields 0 µs */
new_time.tm_nsec = msec * RTC_DATETIME_MS_TO_NS;
}
#endif

View File

@@ -465,6 +465,7 @@ error:
static void telnet_server_cb(struct net_socket_service_event *evt)
{
int sock_error;
int ret;
socklen_t optlen = sizeof(int);
if (sh_telnet == NULL) {
@@ -475,7 +476,14 @@ static void telnet_server_cb(struct net_socket_service_event *evt)
(evt->event.revents & ZSOCK_POLLNVAL)) {
(void)zsock_getsockopt(evt->event.fd, SOL_SOCKET,
SO_ERROR, &sock_error, &optlen);
NET_ERR("Telnet socket %d error (%d)", evt->event.fd, sock_error);
ret = -sock_error;
if (ret == -ENETDOWN) {
LOG_INF("Network is down");
} else {
LOG_ERR("Telnet socket %d error (%d)", evt->event.fd, ret);
}
if (evt->event.fd == sh_telnet->fds[SOCK_ID_CLIENT].fd) {
telnet_end_client_connection();

View File

@@ -1,20 +1,35 @@
/*
* Copyright (c) 2023 Meta
* Copyright (c) The Zephyr Project Contributors
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <ctype.h>
#include <zephyr/posix/fnmatch.h>
#include <zephyr/ztest.h>
/*
* Note: the \x00 control character is specifically excluded below, since testing for it is
* equivalent to reading past the end of a '\0'-terminated string (i.e. can fault).
*/
#define TEST_BLANK_CHARS " \t"
#define TEST_CNTRL_CHARS \
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16" \
"\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f"
#define TEST_DIGIT_CHARS "0123456789"
#define TEST_LOWER_CHARS "abcdefghijklmnopqrstuvwxyz"
#define TEST_PUNCT_CHARS "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
#define TEST_SPACE_CHARS " \f\n\r\t\v"
#define TEST_UPPER_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define TEST_XDIGIT_CHARS "0123456789ABCDEFabcdef"
/*
* Adapted from
* https://git.musl-libc.org/cgit/libc-testsuite/tree/fnmatch.c
*/
ZTEST(posix_c_lib_ext, test_fnmatch)
{
/* Note: commented out lines indicate known problems to be addressed in #55186 */
zassert_ok(fnmatch("*.c", "foo.c", 0));
zassert_ok(fnmatch("*.c", ".c", 0));
zassert_equal(fnmatch("*.a", "foo.c", 0), FNM_NOMATCH);
@@ -30,8 +45,31 @@ ZTEST(posix_c_lib_ext, test_fnmatch)
zassert_equal(fnmatch("a*.c", "a/x.c", FNM_PATHNAME), FNM_NOMATCH);
zassert_ok(fnmatch("*/foo", "/foo", FNM_PATHNAME));
zassert_ok(fnmatch("-O[01]", "-O1", 0));
zassert_ok(fnmatch("[[?*\\]", "\\", 0));
zassert_ok(fnmatch("[]?*\\]", "]", 0));
/*
* '\' in pattern escapes ']'. bracket expression is incomplete. pattern is interpreted as
* literal sequence '[[?*\]'. which does not match input '\'
*/
zassert_equal(fnmatch("[[?*\\]", "\\", 0), FNM_NOMATCH);
/* '\' in pattern does not escape ']'. bracket expression complete. '\' matches input '\' */
zassert_ok(fnmatch("[[?*\\]", "\\", FNM_NOESCAPE));
/* '\' in pattern escapes '\', match '\' */
zassert_ok(fnmatch("[[?*\\\\]", "\\", 0));
/*
* "[]" (empty bracket expression) is an invalid pattern.
* > The ( ']' ) shall lose its special meaning and represent itself in a bracket expression
* > if it occurs first in the list (after an initial ( '^' ), if any)
* https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03_05
*
* So the next test is (again) and incomplete bracket expression and should return error.
* The two tests that follow it also require the ']' to be treated as a literal character to
* match within the bracket expression.
*/
zassert_equal(fnmatch("[]?*\\]", "]", 0), FNM_NOMATCH);
/* '\' in pattern does not escape. bracket expression complete. ']' matches input ']' */
zassert_ok(fnmatch("[]?*\\]", "]", FNM_NOESCAPE));
/* '\' in pattern escapes '\'. bracket expression complete. ']' matches input ']' */
zassert_ok(fnmatch("[]?*\\\\]", "]", 0));
zassert_ok(fnmatch("[!]a-]", "b", 0));
zassert_ok(fnmatch("[]-_]", "^", 0));
zassert_ok(fnmatch("[!]-_]", "X", 0));
@@ -73,11 +111,58 @@ ZTEST(posix_c_lib_ext, test_fnmatch)
zassert_equal(fnmatch("*/*", "a/.b", FNM_PATHNAME | FNM_PERIOD), FNM_NOMATCH);
zassert_ok(fnmatch("*?*/*", "a/.b", FNM_PERIOD));
zassert_ok(fnmatch("*[.]/b", "a./b", FNM_PATHNAME | FNM_PERIOD));
/* zassert_ok(fnmatch("*[[:alpha:]]/""*[[:alnum:]]", "a/b", FNM_PATHNAME)); */
zassert_not_equal(fnmatch("*[![:digit:]]*/[![:d-d]", "a/b", FNM_PATHNAME), 0);
zassert_not_equal(fnmatch("*[![:digit:]]*/[[:d-d]", "a/[", FNM_PATHNAME), 0);
zassert_not_equal(fnmatch("*[![:digit:]]*/[![:d-d]", "a/[", FNM_PATHNAME), 0);
zassert_ok(fnmatch("*[[:alpha:]]/*[[:alnum:]]", "a/b", FNM_PATHNAME));
zassert_ok(fnmatch("*[![:digit:]]*/[![:d-d]", "a/b", FNM_PATHNAME), 0);
zassert_ok(fnmatch("*[![:digit:]]*/[[:d-d]", "a/[", FNM_PATHNAME), 0);
zassert_equal(fnmatch("*[![:digit:]]*/[![:d-d]", "a/[", FNM_PATHNAME), FNM_NOMATCH);
zassert_ok(fnmatch("a?b", "a.b", FNM_PATHNAME | FNM_PERIOD));
zassert_ok(fnmatch("a*b", "a.b", FNM_PATHNAME | FNM_PERIOD));
zassert_ok(fnmatch("a[.]b", "a.b", FNM_PATHNAME | FNM_PERIOD));
/* Additional test cases for POSIX character classes (C-locale only) */
static const struct test_data_s {
const char *pattern;
const char *match;
const char *nomatch;
} test_data[] = {
{"[[:alnum:]]", TEST_DIGIT_CHARS TEST_UPPER_CHARS TEST_LOWER_CHARS, " "},
{"[[:alpha:]]", TEST_UPPER_CHARS TEST_LOWER_CHARS, "0"},
{"[[:blank:]]", TEST_BLANK_CHARS, "x"},
{"[[:cntrl:]]", TEST_CNTRL_CHARS, "x"},
{"[[:digit:]]", TEST_DIGIT_CHARS, "a"},
{"[[:graph:]]", TEST_DIGIT_CHARS TEST_UPPER_CHARS TEST_LOWER_CHARS TEST_PUNCT_CHARS,
" "},
{"[[:lower:]]", TEST_LOWER_CHARS, "X"},
{"[[:print:]]",
TEST_DIGIT_CHARS TEST_UPPER_CHARS TEST_LOWER_CHARS TEST_PUNCT_CHARS " ", "\t"},
{"[[:punct:]]", TEST_PUNCT_CHARS, "x"},
{"[[:space:]]", TEST_SPACE_CHARS, "x"},
{"[[:upper:]]", TEST_UPPER_CHARS, "x"},
{"[[:xdigit:]]", TEST_XDIGIT_CHARS, "h"},
};
ARRAY_FOR_EACH_PTR(test_data, data) {
/* ensure that characters in "nomatch" do not match "pattern" */
for (size_t j = 0; j < strlen(data->nomatch); j++) {
char c = data->nomatch[j];
char input[] = {c, '\0'};
zexpect_equal(fnmatch(data->pattern, input, 0), FNM_NOMATCH,
"pattern \"%s\" unexpectedly matched char 0x%02x (%c)",
data->pattern, c, isprint(c) ? c : '.');
}
/* ensure that characters in "match" do match "pattern" */
for (size_t j = 0; j < strlen(data->match); j++) {
char c = data->match[j];
char input[] = {c, '\0'};
zexpect_ok(fnmatch(data->pattern, input, 0),
"pattern \"%s\" did not match char 0x%02x (%c)", data->pattern,
c, isprint(c) ? c : '.');
}
}
/* ensure that an invalid character class generates an error */
zassert_equal(fnmatch("[[:foobarbaz:]]", "Z", 0), FNM_NOMATCH);
}