nuttx-apps/testing/drivers/nand_sim/nand_sim_main.c
Marco Casaroli f1033082f9 netutils/dropbear, testing/nand_sim: do not use fork() to run in background.
Neither of these wants fork() semantics.  Both reach for fork() only to put
work in the background, and each has a NuttX-native way to do that, so
neither needs a fork primitive at all -- which matters once apache/nuttx#19562
makes ARCH_HAVE_FORK conditional on the architecture implementing POSIX
fork().

netutils/dropbear: the port already routes every fork-then-exec through
vfork(), because sysoptions.h selects DROPBEAR_VFORK when HAVE_FORK is
undefined and the port leaves it undefined.  spawn_command() in dbutil.c and
both call sites in scp.c follow that switch.  The one exception is the
daemon() fallback that compat.c compiles under #ifndef HAVE_DAEMON, which
calls fork() directly and bypasses it.  NuttX provides daemon() in
libs/libc/unistd/lib_daemon.c and declares it in unistd.h, so the fallback is
redundant; define HAVE_DAEMON alongside the HAVE_STRLCAT and HAVE_STRLCPY
entries that are there for exactly the same reason.  The code was unreachable
in any case -- the port hands svr_getopts() an argv containing -F, so
svr_opts.forkbg is always zero and dropbear never calls daemon() at all.

testing/drivers/nand_sim: forked so that the parent could return to the shell
while the child registered the MTD device and slept forever.  Nothing from
before the fork is used after it, so the child is a self-contained entry
point, and task_create() expresses that directly.  The emulator body moves
into nand_sim_daemon() unchanged.  TESTING_NAND_SIM therefore needs no fork
dependency, and the two sim configurations that enable it keep working
whatever ARCH_HAVE_FORK is set to.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-03 09:22:39 -03:00

240 lines
6.9 KiB
C

/****************************************************************************
* apps/testing/drivers/nand_sim/nand_sim_main.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/debug.h>
#include <sched.h>
#include <stdio.h>
#include <nuttx/drivers/drivers.h>
#include <nuttx/mtd/nand.h>
#include <nuttx/mtd/nand_scheme.h>
#include <nuttx/mtd/nand_ram.h>
#include <nuttx/mtd/nand_wrapper.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define NAND_SIM_NAME "nand"
#define NAND_SIM_PATH "/dev/" NAND_SIM_NAME
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
FAR struct mtd_dev_s *g_nand_sim_mtd_wrapper;
FAR struct mtd_dev_s *g_nand_sim_mtd_under;
FAR struct nand_raw_s *g_nand_mtd_raw;
/****************************************************************************
* External Functions
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: wrapper_init
*
* Description:
* Initializes the wrapper by allocating memory and assigning the methods.
*
* Returned Value:
* 0: Successful
* -ENOMEM: No memory left to allocate device
*
****************************************************************************/
int wrapper_init(void)
{
struct nand_dev_s *under;
struct nand_dev_s *wrapper;
g_nand_sim_mtd_wrapper = kmm_zalloc(sizeof(struct nand_wrapper_dev_s));
if (g_nand_sim_mtd_wrapper == NULL)
{
return -ENOMEM;
}
under = &((struct nand_wrapper_dev_s *)g_nand_sim_mtd_wrapper)->under;
wrapper = &((struct nand_wrapper_dev_s *)g_nand_sim_mtd_wrapper)->wrapper;
memcpy(under, g_nand_sim_mtd_under, sizeof(struct nand_dev_s));
memcpy(wrapper, g_nand_sim_mtd_under, sizeof(struct nand_dev_s));
nand_wrapper_initialize();
((struct mtd_dev_s *)wrapper)->name = NAND_SIM_NAME;
((struct mtd_dev_s *)wrapper)->erase = nand_wrapper_erase;
((struct mtd_dev_s *)wrapper)->bread = nand_wrapper_bread;
((struct mtd_dev_s *)wrapper)->bwrite = nand_wrapper_bwrite;
((struct mtd_dev_s *)wrapper)->ioctl = nand_wrapper_ioctl;
((struct mtd_dev_s *)wrapper)->isbad = nand_wrapper_isbad;
((struct mtd_dev_s *)wrapper)->markbad = nand_wrapper_markbad;
return OK;
}
/****************************************************************************
* Name: terminate
*
* Description:
* Handles the SIGTERM signal by exiting gracefully.
*
****************************************************************************/
void terminate(int sig)
{
kmm_free(g_nand_sim_mtd_under);
kmm_free(g_nand_sim_mtd_wrapper);
unregister_mtddriver(NAND_SIM_PATH);
syslog(LOG_DEBUG, "Exited!\n");
}
/****************************************************************************
* Name: nand_sim_daemon
*
* Description:
* Body of the device emulator. Registers the simulated MTD device and
* then sleeps forever; all events are handled by signals.
*
****************************************************************************/
static int nand_sim_daemon(int argc, FAR char *argv[])
{
int ret;
if (daemon(0, 1) == -1)
{
ret = EXIT_FAILURE;
goto errout;
}
/* Signal Handlers */
signal(SIGTERM, terminate);
/* Initializers */
/* Raw NAND MTD Device */
g_nand_mtd_raw = kmm_zalloc(sizeof(struct nand_raw_s));
if (g_nand_mtd_raw == NULL)
{
ret = -ENOMEM;
goto errout_with_logs;
}
g_nand_sim_mtd_under = nand_ram_initialize(g_nand_mtd_raw);
if (g_nand_sim_mtd_under == NULL)
{
ret = -EINVAL;
goto errout_with_raw_s;
}
ret = wrapper_init();
if (ret < 0)
{
goto errout_with_mtd_under;
}
/* Under device driver is already copied to wrapper, so free. */
kmm_free(g_nand_sim_mtd_under);
ret = register_mtddriver(NAND_SIM_PATH,
g_nand_sim_mtd_wrapper,
0777, NULL);
if (ret < 0)
{
goto errout_with_mtd_wrapper;
}
printf("Driver running!\n");
/* To keep the daemon still running. All events are handled by signals */
while (1)
{
sleep(1);
}
/* Won't reach this point */
return OK;
errout_with_mtd_wrapper:
kmm_free(g_nand_sim_mtd_wrapper);
errout_with_mtd_under:
kmm_free(g_nand_sim_mtd_under);
errout_with_raw_s:
kmm_free(g_nand_mtd_raw);
errout_with_logs:
unregister_mtddriver(NAND_SIM_PATH);
errout:
return ret;
}
/****************************************************************************
* Name: nand_sim_main
*
* Description:
* Entry point of the device emulator. Starts the emulator as an
* independent task so that the caller gets its shell back.
*
****************************************************************************/
int main(int argc, FAR char *argv[])
{
int ret;
ret = task_create(NAND_SIM_NAME, SCHED_PRIORITY_DEFAULT,
CONFIG_TESTING_NAND_SIM_STACK, nand_sim_daemon, NULL);
if (ret < 0)
{
return EXIT_FAILURE;
}
return OK;
}