7

I checked everywhere so I am hopefully not repeating a question.

I want to add a portable update feature to some C code I am writing. The program may not be in any specific location, and I would prefer to keep it to a single binary (No dynamic library loading)

Then after the update is complete, I want the program to be able to restart (not a loop, actually reload from the HDD)

Is there any way to do this in C on Linux?

nhahtdh
  • 55,989
  • 15
  • 126
  • 162
Drumm
  • 73
  • 1
  • 4

2 Answers2

10

If you know where the program is saved on disk, then you can exec() the program:

char args[] = { "/opt/somewhere/bin/program", 0 };

execv(args[0], args);
fprintf(stderr, "Failed to reexecute %s\n", args[0]);
exit(1);

If you don't know where the program is on disk, either use execvp() to search for it on $PATH, or find out. On Linux, use the /proc file system — and /proc/self/exe specifically; it is a symlink to the executable, so you would need to use readlink() to get the value. Beware: readlink() does not null terminate the string it reads.

If you want, you can arrange to pass an argument which indicates to the new process that it is being restarted after update; the bare minimum argument list I provided can be as complex as you need (a list of the files currently open for edit, perhaps, or any other appropriate information and options).

Also, don't forget to clean up before reexecuting — cleanly close any open files, for example. Remember, open file descriptors are inherited by the executed process (unless you mark them for closure on exec with FD_CLOEXEC or O_CLOEXEC), but the new process won't know what they're for unless you tell it (in the argument list) so it won't be able to use them. They'll just be cluttering up the process without helping in the least.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • You are sure this will read the program image from disk, and not reuse the one currently executing in memory? – Bart van Ingen Schenau Dec 18 '12 at 16:05
  • I confirm that the program image is read from disk using exec – benjarobin Dec 18 '12 at 16:07
  • I saw this, but I did see a comment about /prov/self/exe not being a definite path? Sometimes it's there, other times it's not. – Drumm Dec 18 '12 at 17:00
  • @Drumm: That'll be for you to investigate...I'd go with knowing where the program is installed. One other possibility to think about and check on before using `/proc/self/exe`: if your program was installed in `/opt/somewhere/bin/program` and you arrange to overwrite that file, does the symlink still point to the same place? It is not the 'same file' any more. I don't know; I haven't investigated; in your shoes, if you plan to exploit `/proc/self/exe`, I think you should check what happens. – Jonathan Leffler Dec 18 '12 at 17:18
  • I'll look into alternative locations of /proc/self/exe, do some more investigating, but this will solve my problem. Many thanks! – Drumm Dec 18 '12 at 17:25
  • @Drumm: The link `/proc//exe` is **not** valid anymore after having deleted and recreated the file the link pointed to, so I suspose this would be the same for `/proc/self/exe`. But whatsoever this does not matter as one it interessted only in the locaton the link points too, which still could be read using `readlink()`. – alk Dec 18 '12 at 17:40
  • @alk: Interesting; thanks for the info. It sounds as though you should read the location of the executable before starting the self-update. That way, you'd know where to write the self-updated code (after the successful download to a different file!) and would know which file to execute to restart. The key is to grab `/proc/self/exe` early enough (before wrecking it). – Jonathan Leffler Dec 18 '12 at 18:06
  • Just implemented this in my program. Seems to be working fine, though at first I did overlook the closing of my sockets. – Drumm Dec 18 '12 at 20:05
2

Yes, you need to call the proper exec() function. There might be some complications, it can be troublesome to find the absolute path name. You need to:

  • Store the current directory in main().
  • Store the argc and (all) argv[] values from main().

Since calling exec() replaces the current process, that should be all you need to do in order to restart yourself. You might also need to take care to close any opened files, since they might otherwise be "inherited" back to yourself, which is seldom what you want.

unwind
  • 391,730
  • 64
  • 469
  • 606