clinuxbashpetalinux

Linux C program restart itself after a delay


I have an embedded system running petalinux 2021.2 and running my application "my_app". I need to be able to send it a command to update itself with a new compiled binary. My app should respond that it is about to update and then restart itself.

I figured I would do it like this:

/* Updated binary my_app has already been copied to /usr/bin */
char* command = "( sleep 3; killall -2 my_app; sleep 3; my_app) &";

/* Start the update process */
system(command);

/* Respond to user */
sendUpdateResponse();

......
/* Eventually SIGINT is sent and app cleans up and exits */

Unfortunately when my app starts again it does not work properly, specifically the servers it creates don't work as expected. I also notice two new processes are running:

  1. sh -c ( sleep 3; killall -2 my_app; sleep 3; my_app) &
  2. my_app

However, if I just use ctrl^c to quit the program and then run it again from the command line it works great. I can do this any number of times with no issue. Something about the way I am having it restart itself with a background process is causing issues.

I am sure this is a very dumb way to do this, any suggestions are much appreciated.

Edit: Some more info

I can start process like so: my_app &

I can then run: (sleep 3; killall -2 my_app; sleep 3; my_app) &

No problem here, working as expected. So it has to be something about the fact that the process is the one calling this command


Solution

  • Thank you all for your comments, they lead me to the answer.

    The problem was that when I run the updating script it is running as a child process meaning all open file descriptors are inherited by the child process.

    The child process sends SIGINT to the running app and the app closes all of its descriptors. The child process then starts the new updated version of the app, however, the app is now running with all the opened descriptors it inherited. This was causing problems. To fix, I had to follow these steps:

    1. When update command received, fork()
    2. Child process will then need to close all file descriptors (except in, out, err) and then use execl() to run the updating script
    3. Updating script sends SIGINT to the app, app closes
    4. Updating script starts new version of the app

    App is now running from a clean slate with only stdin, stderr, and stdout open. Now it works great