diff --git a/components/dfs/Kconfig b/components/dfs/Kconfig index 61453895c95..2c7ae22267f 100644 --- a/components/dfs/Kconfig +++ b/components/dfs/Kconfig @@ -169,14 +169,16 @@ if RT_USING_DFS_V1 default n endif - config RT_USING_DFS_ROMFS + menuconfig RT_USING_DFS_ROMFS bool "Enable ReadOnly file system on flash" default n - config RT_USING_DFS_ROMFS_USER_ROOT - bool "Use user's romfs root" - depends on RT_USING_DFS_ROMFS - default n + if RT_USING_DFS_ROMFS + config RT_USING_DFS_ROMFS_USER_ROOT + bool "Use user's romfs root" + depends on RT_USING_DFS_V1 + default n + endif if RT_USING_SMART config RT_USING_DFS_PTYFS diff --git a/components/dfs/dfs_v2/include/dfs_fs.h b/components/dfs/dfs_v2/include/dfs_fs.h index d30967aac53..dcf2fa2b98b 100644 --- a/components/dfs/dfs_v2/include/dfs_fs.h +++ b/components/dfs/dfs_v2/include/dfs_fs.h @@ -20,6 +20,38 @@ extern "C" { #endif +#define MS_RDONLY 1 +#define MS_NOSUID 2 +#define MS_NODEV 4 +#define MS_NOEXEC 8 +#define MS_SYNCHRONOUS 16 +#define MS_REMOUNT 32 +#define MS_MANDLOCK 64 +#define MS_DIRSYNC 128 +#define MS_NOATIME 1024 +#define MS_NODIRATIME 2048 +#define MS_BIND 4096 +#define MS_MOVE 8192 +#define MS_REC 16384 +#define MS_SILENT 32768 +#define MS_POSIXACL (1<<16) +#define MS_UNBINDABLE (1<<17) +#define MS_PRIVATE (1<<18) +#define MS_SLAVE (1<<19) +#define MS_SHARED (1<<20) +#define MS_RELATIME (1<<21) +#define MS_KERNMOUNT (1<<22) +#define MS_I_VERSION (1<<23) +#define MS_STRICTATIME (1<<24) +#define MS_LAZYTIME (1<<25) +#define MS_NOREMOTELOCK (1<<27) +#define MS_NOSEC (1<<28) +#define MS_BORN (1<<29) +#define MS_ACTIVE (1<<30) +#define MS_NOUSER (1U<<31) + +#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|MS_LAZYTIME) + /* file system partition table */ struct dfs_partition { @@ -87,6 +119,7 @@ int dfs_unregister(struct dfs_filesystem_type *fs); int dfs_register(struct dfs_filesystem_type *fs); const char *dfs_filesystem_get_mounted_path(struct rt_device *device); +int dfs_remount(const char *path, rt_ubase_t flags, void *data); int dfs_mount(const char *device_name, const char *path, const char *filesystemtype, diff --git a/components/dfs/dfs_v2/include/dfs_mnt.h b/components/dfs/dfs_v2/include/dfs_mnt.h index 207c9b6bfd0..da99ec2ab1e 100644 --- a/components/dfs/dfs_v2/include/dfs_mnt.h +++ b/components/dfs/dfs_v2/include/dfs_mnt.h @@ -39,6 +39,8 @@ struct dfs_mnt #define MNT_IS_UMOUNT 0x8 /* the mnt is unmount */ #define MNT_IS_LOCKED 0x10 /* the mnt is locked */ #define MNT_FORCE 0x20 /* the mnt force unmount */ +#define MNT_LAZY_UMNT 0x40 /* the mnt has pending umount */ +#define MNT_RDONLY 0x80 /* the mnt is read only */ rt_atomic_t ref_count; /* reference count */ @@ -60,9 +62,16 @@ const char *dfs_mnt_get_mounted_path(struct rt_device *device); struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt); int dfs_mnt_unref(struct dfs_mnt* mnt); +int dfs_mnt_umount(struct dfs_mnt *mnt, int flags); +int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags); + rt_bool_t dfs_mnt_has_child_mnt(struct dfs_mnt *mnt, const char* fullpath); int dfs_mnt_foreach(struct dfs_mnt* (*func)(struct dfs_mnt *mnt, void *parameter), void *parameter); +int dfs_mnt_umount_iter(rt_bool_t (*filter)(struct dfs_mnt *mnt, void *parameter), void *parameter); + +typedef void (*dfs_mnt_umnt_cb_t)(struct dfs_mnt *mnt); +RT_OBJECT_HOOKLIST_DECLARE(dfs_mnt_umnt_cb_t, dfs_mnt_umnt); #ifdef __cplusplus } diff --git a/components/dfs/dfs_v2/include/dfs_pcache.h b/components/dfs/dfs_v2/include/dfs_pcache.h index 01abfe31504..545219687b0 100644 --- a/components/dfs/dfs_v2/include/dfs_pcache.h +++ b/components/dfs/dfs_v2/include/dfs_pcache.h @@ -118,6 +118,7 @@ int dfs_aspace_mmap_write(struct dfs_file *file, struct rt_varea *varea, void *d void dfs_pcache_release(size_t count); void dfs_pcache_unmount(struct dfs_mnt *mnt); +void dfs_pcache_clean(struct dfs_mnt *mnt); #ifdef __cplusplus } diff --git a/components/dfs/dfs_v2/src/dfs_fs.c b/components/dfs/dfs_v2/src/dfs_fs.c index 755b257191e..ee077cd77ae 100644 --- a/components/dfs/dfs_v2/src/dfs_fs.c +++ b/components/dfs/dfs_v2/src/dfs_fs.c @@ -95,6 +95,52 @@ int dfs_unregister(struct dfs_filesystem_type *fs) return ret; } +#define REMNT_UNSUPP_FLAGS (~(MS_REMOUNT | MS_RMT_MASK)) +int dfs_remount(const char *path, rt_ubase_t flags, void *data) +{ + int rc = 0; + char *fullpath = RT_NULL; + struct dfs_mnt *mnt = RT_NULL; + + if (flags & REMNT_UNSUPP_FLAGS) + { + return -EINVAL; + } + + fullpath = dfs_normalize_path(RT_NULL, path); + if (!fullpath) + { + rc = -ENOENT; + } + else + { + DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt = dfs_mnt_lookup(%s)", fullpath); + mnt = dfs_mnt_lookup(fullpath); + if (mnt) + { + dfs_lock(); + dfs_mnt_setflags(mnt, flags); + dfs_unlock(); + } + else + { + struct stat buf = {0}; + if (dfs_file_stat(fullpath, &buf) == 0 && S_ISBLK(buf.st_mode)) + { + /* path was not already mounted on target */ + rc = -EINVAL; + } + else + { + /* path is not a directory */ + rc = -ENOTDIR; + } + } + } + + return rc; +} + /* * parent(mount path) * mnt_parent <- - - - - - - + @@ -300,7 +346,7 @@ int dfs_mount(const char *device_name, int dfs_umount(const char *specialfile, int flags) { - int ret = -RT_ERROR; + int ret = -1; char *fullpath = RT_NULL; struct dfs_mnt *mnt = RT_NULL; @@ -314,7 +360,7 @@ int dfs_umount(const char *specialfile, int flags) if (strcmp(mnt->fullpath, fullpath) == 0) { /* is the mount point */ - rt_atomic_t ref_count = rt_atomic_load(&(mnt->ref_count)); + rt_base_t ref_count = rt_atomic_load(&(mnt->ref_count)); if (!(mnt->flags & MNT_IS_LOCKED) && rt_list_isempty(&mnt->child) && (ref_count == 1 || (flags & MNT_FORCE))) { @@ -327,17 +373,19 @@ int dfs_umount(const char *specialfile, int flags) } else { - LOG_E("the file system is busy!"); + LOG_I("the file system is busy!"); + ret = -EBUSY; } } else { - LOG_E("the path:%s is not a mountpoint!", fullpath); + LOG_I("the path:%s is not a mountpoint!", fullpath); + ret = -EINVAL; } } else { - LOG_E("no filesystem found."); + LOG_I("no filesystem found."); } rt_free(fullpath); } diff --git a/components/dfs/dfs_v2/src/dfs_mnt.c b/components/dfs/dfs_v2/src/dfs_mnt.c index 4ad73c6dee9..a2070720b01 100644 --- a/components/dfs/dfs_v2/src/dfs_mnt.c +++ b/components/dfs/dfs_v2/src/dfs_mnt.c @@ -10,17 +10,21 @@ #include -#include "dfs.h" -#include "dfs_mnt.h" -#include "dfs_dentry.h" #include "dfs_private.h" +#include +#include +#include +#include + #define DBG_TAG "DFS.mnt" #define DBG_LVL DBG_WARNING #include static struct dfs_mnt *_root_mnt = RT_NULL; +RT_OBJECT_HOOKLIST_DEFINE(dfs_mnt_umnt); + /* * mnt tree structure * @@ -75,6 +79,7 @@ int dfs_mnt_insert(struct dfs_mnt* mnt, struct dfs_mnt* child) child = _root_mnt; rt_atomic_sub(&(_root_mnt->parent->ref_count), 1); rt_atomic_sub(&(_root_mnt->ref_count), 1); + _root_mnt->flags &= ~MNT_IS_LOCKED; _root_mnt = dfs_mnt_ref(mnt); mnt->parent = dfs_mnt_ref(mnt); @@ -242,21 +247,24 @@ struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt) return mnt; } -int dfs_mnt_unref(struct dfs_mnt* mnt) +int dfs_mnt_unref(struct dfs_mnt *mnt) { rt_err_t ret = RT_EOK; + rt_base_t ref_count; if (mnt) { - rt_atomic_sub(&(mnt->ref_count), 1); + ref_count = rt_atomic_sub(&(mnt->ref_count), 1) - 1; - if (rt_atomic_load(&(mnt->ref_count)) == 0) + if (ref_count == 0) { dfs_lock(); if (mnt->flags & MNT_IS_UMOUNT) { mnt->fs_ops->umount(mnt); + + RT_OBJECT_HOOKLIST_CALL(dfs_mnt_umnt, (mnt)); } /* free full path */ @@ -278,6 +286,21 @@ int dfs_mnt_unref(struct dfs_mnt* mnt) return ret; } +int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags) +{ + int error = 0; + + if (flags & MS_RDONLY) + { + mnt->flags |= MNT_RDONLY; +#ifdef RT_USING_PAGECACHE + dfs_pcache_clean(mnt); +#endif + } + + return error; +} + int dfs_mnt_destroy(struct dfs_mnt* mnt) { rt_err_t ret = RT_EOK; diff --git a/components/dfs/dfs_v2/src/dfs_pcache.c b/components/dfs/dfs_v2/src/dfs_pcache.c index 6868170b9cb..ad99623762b 100644 --- a/components/dfs/dfs_v2/src/dfs_pcache.c +++ b/components/dfs/dfs_v2/src/dfs_pcache.c @@ -161,7 +161,7 @@ void dfs_pcache_release(size_t count) dfs_pcache_unlock(); } -void dfs_pcache_unmount(struct dfs_mnt *mnt) +static void _pcache_clean(struct dfs_mnt *mnt, int (*cb)(struct dfs_aspace *aspace)) { rt_list_t *node = RT_NULL; struct dfs_aspace *aspace = RT_NULL; @@ -176,7 +176,7 @@ void dfs_pcache_unmount(struct dfs_mnt *mnt) if (aspace && aspace->mnt == mnt) { dfs_aspace_clean(aspace); - dfs_aspace_release(aspace); + cb(aspace); } } @@ -188,13 +188,28 @@ void dfs_pcache_unmount(struct dfs_mnt *mnt) if (aspace && aspace->mnt == mnt) { dfs_aspace_clean(aspace); - dfs_aspace_release(aspace); + cb(aspace); } } dfs_pcache_unlock(); } +void dfs_pcache_unmount(struct dfs_mnt *mnt) +{ + _pcache_clean(mnt, dfs_aspace_release); +} + +static int _dummy_cb(struct dfs_aspace *mnt) +{ + return 0; +} + +void dfs_pcache_clean(struct dfs_mnt *mnt) +{ + _pcache_clean(mnt, _dummy_cb); +} + static int dfs_pcache_limit_check(void) { int index = 4; @@ -1139,14 +1154,21 @@ int dfs_aspace_write(struct dfs_file *file, const void *buf, size_t count, off_t if (file && file->vnode && file->vnode->aspace) { - if (!(file->vnode->aspace->ops->write)) - return ret; struct dfs_vnode *vnode = file->vnode; struct dfs_aspace *aspace = vnode->aspace; struct dfs_page *page; char *ptr = (char *)buf; + if (!(aspace->ops->write)) + { + return ret; + } + else if (aspace->mnt && (aspace->mnt->flags & MNT_RDONLY)) + { + return -EROFS; + } + ret = 0; while (count) diff --git a/components/lwp/Kconfig b/components/lwp/Kconfig index f815c7da998..1d64e1c908e 100644 --- a/components/lwp/Kconfig +++ b/components/lwp/Kconfig @@ -14,9 +14,17 @@ if RT_USING_LWP config LWP_DEBUG_INIT select RT_USING_HOOKLIST bool "Enable debug mode of init process" - default n + depends on LWP_USING_RUNTIME + default y endif + config LWP_USING_RUNTIME + bool "Using processes runtime environment (INIT process)" + default y + help + Runtime environment provide by init process including boot scripts, + poweroff, shutdown, reboot, etc. + config RT_LWP_MAX_NR int "The max number of light-weight process" default 30 diff --git a/components/lwp/SConscript b/components/lwp/SConscript index 3182254e7d3..cd8a2428a5b 100644 --- a/components/lwp/SConscript +++ b/components/lwp/SConscript @@ -45,6 +45,10 @@ for item in termios_path: src += Glob(item + '*.c') CPPPATH += ['./terminal/'] +# Remove optional sources +if not GetDepend(['LWP_USING_RUNTIME']): + SrcRemove(src, 'lwp_runtime.c') + group = DefineGroup('lwP', src, depend = ['RT_USING_SMART'], CPPPATH = CPPPATH) group = group + SConscript(os.path.join('vdso', 'SConscript')) diff --git a/components/lwp/libc_musl.h b/components/lwp/libc_musl.h index fbc2ad5cb41..586fd4961db 100644 --- a/components/lwp/libc_musl.h +++ b/components/lwp/libc_musl.h @@ -11,6 +11,15 @@ #ifndef __LIBC_MUSL_H__ #define __LIBC_MUSL_H__ +/* from reboot.h */ +#define RB_AUTOBOOT 0x01234567 +#define RB_HALT_SYSTEM 0xcdef0123 +#define RB_ENABLE_CAD 0x89abcdef +#define RB_DISABLE_CAD 0 +#define RB_POWER_OFF 0x4321fedc +#define RB_SW_SUSPEND 0xd000fce2 +#define RB_KEXEC 0x45584543 + /* from internal/futex.h */ #define FUTEX_WAIT 0 diff --git a/components/lwp/lwp.c b/components/lwp/lwp.c index e8092226cae..4da9acaffcf 100644 --- a/components/lwp/lwp.c +++ b/components/lwp/lwp.c @@ -83,87 +83,6 @@ static int lwp_component_init(void) } INIT_COMPONENT_EXPORT(lwp_component_init); -rt_weak int lwp_startup_debug_request(void) -{ - return 0; -} - -#define LATENCY_TIMES (3) -#define LATENCY_IN_MSEC (128) -#define LWP_CONSOLE_PATH "CONSOLE=/dev/console" -const char *init_search_path[] = { - "/sbin/init", - "/bin/init", -}; - -/** - * Startup process 0 and do the essential works - * This is the "Hello World" point of RT-Smart - */ -static int lwp_startup(void) -{ - int error; - - const char *init_path; - char *argv[] = {0, "&"}; - char *envp[] = {LWP_CONSOLE_PATH, 0}; - -#ifdef LWP_DEBUG_INIT - int command; - int countdown = LATENCY_TIMES; - while (countdown) - { - command = lwp_startup_debug_request(); - if (command) - { - return 0; - } - rt_kprintf("Press any key to stop init process startup ... %d\n", countdown); - countdown -= 1; - rt_thread_mdelay(LATENCY_IN_MSEC); - } - rt_kprintf("Starting init ...\n"); -#endif /* LWP_DEBUG_INIT */ - - for (size_t i = 0; i < sizeof(init_search_path)/sizeof(init_search_path[0]); i++) - { - struct stat s; - init_path = init_search_path[i]; - error = stat(init_path, &s); - if (error == 0) - { - argv[0] = (void *)init_path; - error = lwp_execve((void *)init_path, 0, sizeof(argv)/sizeof(argv[0]), argv, envp); - if (error < 0) - { - LOG_E("%s: failed to startup process 0 (init)\n" - "Switching to legacy mode...", __func__); - } - else if (error != 1) - { - LOG_E("%s: pid 1 is already allocated", __func__); - error = -EBUSY; - } - else - { - rt_lwp_t p = lwp_from_pid_locked(1); - p->sig_protected = 1; - - error = 0; - } - break; - } - } - - if (error) - { - LOG_D("%s: init program not found\n" - "Switching to legacy mode...", __func__); - } - return error; -} -INIT_APP_EXPORT(lwp_startup); - void lwp_setcwd(char *buf) { struct rt_lwp *lwp = RT_NULL; diff --git a/components/lwp/lwp.h b/components/lwp/lwp.h index 24b4150270e..2c95deea74f 100644 --- a/components/lwp/lwp.h +++ b/components/lwp/lwp.h @@ -340,6 +340,8 @@ int lwp_session_set_foreground(rt_session_t session, pid_t pgid); /* complete the job control related bussiness on process exit */ void lwp_jobctrl_on_exit(struct rt_lwp *lwp); +sysret_t lwp_teardown(struct rt_lwp *lwp, void (*cb)(void)); + #ifdef __cplusplus } #endif diff --git a/components/lwp/lwp_pid.c b/components/lwp/lwp_pid.c index af32818162a..e45554434da 100644 --- a/components/lwp/lwp_pid.c +++ b/components/lwp/lwp_pid.c @@ -69,13 +69,30 @@ static int lwp_pid_ary_alloced = 0; static struct lwp_avl_struct *lwp_pid_root = RT_NULL; static pid_t current_pid = 0; static struct rt_mutex pid_mtx; +static struct rt_wqueue _pid_emptyq; int lwp_pid_init(void) { + rt_wqueue_init(&_pid_emptyq); rt_mutex_init(&pid_mtx, "pidmtx", RT_IPC_FLAG_PRIO); return 0; } +int lwp_pid_wait_for_empty(int wait_flags, rt_tick_t to) +{ + int error; + + if (wait_flags == RT_INTERRUPTIBLE) + { + error = rt_wqueue_wait_interruptible(&_pid_emptyq, 0, to); + } + else + { + error = rt_wqueue_wait_killable(&_pid_emptyq, 0, to); + } + return error; +} + void lwp_pid_lock_take(void) { LWP_DEF_RETURN_CODE(rc); @@ -93,6 +110,35 @@ void lwp_pid_lock_release(void) RT_ASSERT(0); } +struct pid_foreach_param +{ + int (*cb)(pid_t pid, void *data); + void *data; +}; + +static int _before_cb(struct lwp_avl_struct *node, void *data) +{ + struct pid_foreach_param *param = data; + pid_t pid = node->avl_key; + return param->cb(pid, param->data); +} + +int lwp_pid_for_each(int (*cb)(pid_t pid, void *data), void *data) +{ + int error; + struct pid_foreach_param buf = + { + .cb = cb, + .data = data, + }; + + lwp_pid_lock_take(); + error = lwp_avl_traversal(lwp_pid_root, _before_cb, &buf); + lwp_pid_lock_release(); + + return error; +} + struct lwp_avl_struct *lwp_get_pid_ary(void) { return lwp_pid_ary; @@ -182,7 +228,15 @@ void lwp_pid_put(struct rt_lwp *lwp) lwp_pid_lock_take(); lwp_pid_put_locked(lwp->pid); - lwp_pid_lock_release(); + if (lwp_pid_root == AVL_EMPTY) + { + rt_wqueue_wakeup_all(&_pid_emptyq, RT_NULL); + /* refuse any new pid allocation now */ + } + else + { + lwp_pid_lock_release(); + } /* reset pid field */ lwp->pid = 0; @@ -1510,6 +1564,7 @@ static void _notify_parent(rt_lwp_t lwp) static void _resr_cleanup(struct rt_lwp *lwp) { + int need_cleanup_pid = RT_FALSE; lwp_jobctrl_on_exit(lwp); LWP_LOCK(lwp); @@ -1579,7 +1634,7 @@ static void _resr_cleanup(struct rt_lwp *lwp) * if process is orphan, it doesn't have parent to do the recycling. * Otherwise, its parent had setup a flag to mask out recycling event */ - lwp_pid_put(lwp); + need_cleanup_pid = RT_TRUE; } LWP_LOCK(lwp); @@ -1599,6 +1654,11 @@ static void _resr_cleanup(struct rt_lwp *lwp) { LWP_UNLOCK(lwp); } + + if (need_cleanup_pid) + { + lwp_pid_put(lwp); + } } static int _lwp_setaffinity(int tid, int cpu) diff --git a/components/lwp/lwp_pid.h b/components/lwp/lwp_pid.h index 5e170f652da..826f7a9105a 100644 --- a/components/lwp/lwp_pid.h +++ b/components/lwp/lwp_pid.h @@ -15,6 +15,8 @@ extern "C" { #endif +#include + #define LWP_CREATE_FLAG_NONE 0x0000 #define LWP_CREATE_FLAG_ALLOC_PID 0x0001 /* allocate pid on lwp object create */ #define LWP_CREATE_FLAG_INIT_USPACE 0x0002 /* do user space initialization */ @@ -24,6 +26,8 @@ struct rt_lwp; struct lwp_avl_struct *lwp_get_pid_ary(void); int lwp_pid_init(void); +int lwp_pid_wait_for_empty(int wait_flags, rt_tick_t to); +int lwp_pid_for_each(int (*cb)(pid_t pid, void *data), void *data); void lwp_pid_put(struct rt_lwp *lwp); void lwp_pid_lock_take(void); void lwp_pid_lock_release(void); diff --git a/components/lwp/lwp_runtime.c b/components/lwp/lwp_runtime.c new file mode 100644 index 00000000000..34174d63c32 --- /dev/null +++ b/components/lwp/lwp_runtime.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2006-2024, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2024-11-11 Shell moved lwp_startup() from lwp.c; + * added lwp_teardown() + */ + +#define DBG_TAG "lwp" +#define DBG_LVL DBG_INFO +#include + +#include "lwp_internal.h" + +#include +#include + +#include +#include +#include + +/** + * lwp_runtime: + * Runtime environment provide by init process including boot scripts, + * poweroff, shutdown, reboot, service management etc. In the kernel, lwp will + * provide the underlying software bootstrap and cleanup for the init proc. + * + */ + +rt_weak int lwp_startup_debug_request(void) +{ + return 0; +} + +#define LATENCY_TIMES (3) +#define LATENCY_IN_MSEC (128) +#define LWP_CONSOLE_PATH "CONSOLE=/dev/console" +const char *init_search_path[] = { + "/sbin/init", + "/bin/init", +}; + +/** + * Startup process 1 and do the essential works + */ +static int lwp_startup(void) +{ + int error; + + const char *init_path; + char *argv[] = {0, "&"}; + char *envp[] = {LWP_CONSOLE_PATH, 0}; + +#ifdef LWP_DEBUG_INIT + int command; + int countdown = LATENCY_TIMES; + while (countdown) + { + command = lwp_startup_debug_request(); + if (command) + { + return 0; + } + rt_kprintf("Press any key to stop init process startup ... %d\n", countdown); + countdown -= 1; + rt_thread_mdelay(LATENCY_IN_MSEC); + } + rt_kprintf("Starting init ...\n"); +#endif /* LWP_DEBUG_INIT */ + + for (size_t i = 0; i < sizeof(init_search_path)/sizeof(init_search_path[0]); i++) + { + struct stat s; + init_path = init_search_path[i]; + error = stat(init_path, &s); + if (error == 0) + { + argv[0] = (void *)init_path; + error = lwp_execve((void *)init_path, 0, sizeof(argv)/sizeof(argv[0]), argv, envp); + if (error < 0) + { + LOG_W("%s: failed to setup runtime environment\b" + "\tlwp_execve() failed with code %d", __func__, error); + } + else if (error != 1) + { + LOG_W("%s: pid 1 is already allocated", __func__); + error = -EBUSY; + } + else + { + rt_lwp_t p = lwp_from_pid_locked(1); + p->sig_protected = 1; + + error = 0; + } + break; + } + } + + if (error) + { + LOG_D("%s: failed to setup runtime environment\b" + "\tinit program not found", __func__); + } + return error; +} +INIT_APP_EXPORT(lwp_startup); + +/* don't use heap for safety */ +static struct rt_work _teardown_work; + +#define INIT_PID 1 +static void _teardown_entry(struct rt_work *work, void *work_data) +{ + int error; + void (*cb_on_reboot)(void) = work_data; + + /* cleanup of process */ + do + { + error = lwp_pid_wait_for_empty(RT_KILLABLE, RT_WAITING_FOREVER); + } + while (error); + LOG_I("All processes exited"); + + cb_on_reboot(); + return; +} + +static int _get_parent_pid(struct rt_lwp *lwp) +{ + return lwp->parent ? lwp->parent->pid : 0; +} + +/* reverse operation of lwp_startup() */ +sysret_t lwp_teardown(struct rt_lwp *lwp, void (*cb)(void)) +{ + struct rt_work *work; + + if (lwp->pid != INIT_PID && _get_parent_pid(lwp) != INIT_PID) + { + /* The calling process has insufficient privilege */ + return -EPERM; + } + + work = &_teardown_work; + rt_work_init(work, _teardown_entry, cb); + +#define SOME_DELAY (RT_TICK_PER_SECOND / 10) /* allow idle to cleanup resource */ + rt_work_submit(work, SOME_DELAY); + + lwp_exit(lwp, LWP_CREATE_STAT_EXIT(EXIT_SUCCESS)); + + /* never return */ + RT_ASSERT(0); + return 0; +} diff --git a/components/lwp/lwp_signal.c b/components/lwp/lwp_signal.c index 1f20ad50960..0bbb98c5d25 100644 --- a/components/lwp/lwp_signal.c +++ b/components/lwp/lwp_signal.c @@ -1442,3 +1442,41 @@ rt_err_t lwp_pgrp_signal_kill(rt_processgroup_t pgrp, long signo, long code, return rc; } + +struct kill_all_param +{ + long signo; + long code; + lwp_siginfo_ext_t value; +}; + +static int _kill_each(pid_t pid, void *data) +{ + struct kill_all_param *param = data; + rt_lwp_t lwp; + rt_err_t error; + + lwp = lwp_from_pid_locked(pid); + if (lwp && !lwp->sig_protected) + { + error = lwp_signal_kill(lwp, param->signo, param->code, param->value); + } + else + { + error = RT_EOK; + } + + return error; +} + +rt_err_t lwp_signal_kill_all(long signo, long code, lwp_siginfo_ext_t value) +{ + struct kill_all_param buf = + { + .signo = signo, + .code = code, + .value = value, + }; + + return lwp_pid_for_each(_kill_each, &buf); +} diff --git a/components/lwp/lwp_signal.h b/components/lwp/lwp_signal.h index f98b43dd3fd..7e7bbad9205 100644 --- a/components/lwp/lwp_signal.h +++ b/components/lwp/lwp_signal.h @@ -229,6 +229,8 @@ rt_err_t lwp_signal_setitimer(struct rt_lwp *lwp, int which, rt_bool_t lwp_signal_restart_syscall(struct rt_lwp *lwp, int error_code); +rt_err_t lwp_signal_kill_all(long signo, long code, lwp_siginfo_ext_t value); + #ifdef __cplusplus } #endif diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index 3239c6cb046..bad2852bb86 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -994,7 +994,7 @@ sysret_t sys_kill(int pid, int signo) * of system processes) for which the process has permission to send * that signal. */ - kret = -RT_ENOSYS; + kret = lwp_signal_kill_all(signo, SI_USER, 0); } switch (kret) @@ -5743,79 +5743,94 @@ sysret_t sys_fstatfs64(int fd, size_t sz, struct statfs *buf) return ret; } -sysret_t sys_mount(char *source, char *target, - char *filesystemtype, - unsigned long mountflags, void *data) +static char *_cp_from_usr_string(char *dst, char *src, size_t length) { - char *copy_source; - char *copy_target; - char *copy_filesystemtype; - size_t len_source, copy_len_source; - size_t len_target, copy_len_target; - size_t len_filesystemtype, copy_len_filesystemtype; + char *rc; + size_t copied_bytes; + if (length) + { + copied_bytes = lwp_get_from_user(dst, src, length); + dst[copied_bytes] = '\0'; + rc = dst; + } + else + { + rc = RT_NULL; + } + return rc; +} + +sysret_t sys_mount(char *source, char *target, char *filesystemtype, + unsigned long mountflags, void *data) +{ + char *kbuffer, *ksource, *ktarget, *kfs; + size_t len_source, len_target, len_fs; char *tmp = NULL; int ret = 0; struct stat buf = {0}; + char *dev_fullpath = RT_NULL; - len_source = lwp_user_strlen(source); - if (len_source <= 0) + len_source = source ? lwp_user_strlen(source) : 0; + if (len_source < 0) return -EINVAL; - len_target = lwp_user_strlen(target); + len_target = target ? lwp_user_strlen(target) : 0; if (len_target <= 0) return -EINVAL; - len_filesystemtype = lwp_user_strlen(filesystemtype); - if (len_filesystemtype <= 0) + len_fs = filesystemtype ? lwp_user_strlen(filesystemtype) : 0; + if (len_fs < 0) return -EINVAL; - copy_source = (char*)rt_malloc(len_source + 1 + len_target + 1 + len_filesystemtype + 1); - if (!copy_source) + kbuffer = (char *)rt_malloc(len_source + 1 + len_target + 1 + len_fs + 1); + if (!kbuffer) { return -ENOMEM; } - copy_target = copy_source + len_source + 1; - copy_filesystemtype = copy_target + len_target + 1; - copy_len_source = lwp_get_from_user(copy_source, source, len_source); - copy_source[copy_len_source] = '\0'; - copy_len_target = lwp_get_from_user(copy_target, target, len_target); - copy_target[copy_len_target] = '\0'; - copy_len_filesystemtype = lwp_get_from_user(copy_filesystemtype, filesystemtype, len_filesystemtype); - copy_filesystemtype[copy_len_filesystemtype] = '\0'; + /* get parameters from user space */ + ksource = kbuffer; + ktarget = ksource + len_source + 1; + kfs = ktarget + len_target + 1; + ksource = _cp_from_usr_string(ksource, source, len_source); + ktarget = _cp_from_usr_string(ktarget, target, len_target); + kfs = _cp_from_usr_string(kfs, filesystemtype, len_fs); - if (strcmp(copy_filesystemtype, "nfs") == 0) + if (mountflags & MS_REMOUNT) { - tmp = copy_source; - copy_source = NULL; + ret = dfs_remount(ktarget, mountflags, data); } - if (strcmp(copy_filesystemtype, "tmp") == 0) + else { - copy_source = NULL; - } + if (strcmp(kfs, "nfs") == 0) + { + tmp = ksource; + ksource = NULL; + } + if (strcmp(kfs, "tmp") == 0) + { + ksource = NULL; + } - if (copy_source && stat(copy_source, &buf) && S_ISBLK(buf.st_mode)) - { - char *dev_fullpath = dfs_normalize_path(RT_NULL, copy_source); - RT_ASSERT(rt_strncmp(dev_fullpath, "/dev/", sizeof("/dev/") - 1) == 0); - ret = dfs_mount(dev_fullpath + sizeof("/dev/") - 1, copy_target, copy_filesystemtype, 0, tmp); - if (ret < 0) + if (ksource && !dfs_file_stat(ksource, &buf) && S_ISBLK(buf.st_mode)) { - ret = -rt_get_errno(); + dev_fullpath = dfs_normalize_path(RT_NULL, ksource); + RT_ASSERT(rt_strncmp(dev_fullpath, "/dev/", sizeof("/dev/") - 1) == 0); + ret = dfs_mount(dev_fullpath + sizeof("/dev/") - 1, ktarget, kfs, 0, tmp); } - rt_free(copy_source); - rt_free(dev_fullpath); - } - else - { - ret = dfs_mount(copy_source, copy_target, copy_filesystemtype, 0, tmp); + else + { + ret = dfs_mount(ksource, ktarget, kfs, 0, tmp); + } + if (ret < 0) { ret = -rt_get_errno(); } - rt_free(copy_source); } + rt_free(kbuffer); + rt_free(dev_fullpath); return ret; } @@ -6171,16 +6186,27 @@ sysret_t sys_chown(const char *pathname, uid_t owner, gid_t group) return (ret < 0 ? GET_ERRNO() : ret); } -#include -sysret_t sys_reboot(int magic, int magic2, int type) +#ifndef LWP_USING_RUNTIME +sysret_t lwp_teardown(struct rt_lwp *lwp, void (*cb)(void)) +{ + /* if no LWP_USING_RUNTIME configured */ + return -ENOSYS; +} +#endif + +sysret_t sys_reboot(int magic, int magic2, int type, void *arg) { sysret_t rc; switch (type) { - /* TODO add software poweroff protocols */ + /* Hardware reset */ case RB_AUTOBOOT: + rc = lwp_teardown(lwp_self(), rt_hw_cpu_reset); + break; + + /* Stop system and switch power off */ case RB_POWER_OFF: - rt_hw_cpu_reset(); + rc = lwp_teardown(lwp_self(), rt_hw_cpu_shutdown); break; default: rc = -ENOSYS;