SafeAPI Backend POSIX
POSIX/Linux OAL backend for safeAPIFreamwork
Loading...
Searching...
No Matches
sapi_posix_backend_reboot.c
Go to the documentation of this file.
1/* _XOPEN_SOURCE 700 (implies _POSIX_C_SOURCE 200809L) rather than
2 * _POSIX_C_SOURCE alone: setenv()/putenv() below are XSI extensions, not
3 * base POSIX. */
4#define _XOPEN_SOURCE 700
5
56
57#include <limits.h>
58#include <stdbool.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <unistd.h>
62
63#if defined(__APPLE__)
64#include <mach-o/dyld.h>
65#endif
66
67extern char **environ;
68
70/* No dynamic allocation (REQ-OAL-REBOOT-001's fixed-storage convention,
71 * project-wide "no malloc/free/realloc" rule) - a fixed-capacity static
72 * array of pointers, not copies of the strings themselves (see
73 * sapi_posix_backend_reboot_set_argv()'s own doc for why storing the
74 * pointers is sufficient). +1 slot for the NULL terminator execv()
75 * requires. */
76#define SAPI_POSIX_REBOOT_MAX_ARGV 8U
77
79
85static bool resolve_self_exe_path(char *out_path, size_t out_path_size, const char *argv0);
86static sapi_status_t backend_request(uint16_t reason_code);
87
90static bool s_argv_registered = false;
91static const sapi_reboot_backend_t s_posix_reboot_backend = { backend_request };
92
94
95
97void sapi_posix_backend_reboot_set_argv(int argc, char *const argv[])
98{
99 int count = (argc < 0) ? 0 : argc;
100 int i;
101
102 if (count > (int)SAPI_POSIX_REBOOT_MAX_ARGV)
103 {
104 count = (int)SAPI_POSIX_REBOOT_MAX_ARGV;
105 }
106 for (i = 0; i < count; i++)
107 {
108 s_registered_argv[i] = argv[i];
109 }
110 s_registered_argv[count] = NULL;
111 s_argv_registered = true;
112}
113
114const sapi_reboot_backend_t *sapi_posix_backend_reboot(void)
115{
116 return &s_posix_reboot_backend;
117}
118
119
120/****Local functions ****/
121
122static bool resolve_self_exe_path(char *out_path, size_t out_path_size, const char *argv0)
123{
124#if defined(__APPLE__)
125 uint32_t size = (uint32_t)out_path_size;
126
127 if (_NSGetExecutablePath(out_path, &size) == 0)
128 {
129 return true;
130 }
131 /* size now holds the required buffer length, but out_path_size is a
132 * fixed compile-time buffer here (PATH_MAX) - if that was not enough,
133 * there is nothing more this stand-in backend can do. */
134 (void)argv0;
135 return false;
136#elif defined(__linux__)
137 ssize_t written = readlink("/proc/self/exe", out_path, out_path_size - 1U);
138
139 if ((written <= 0) || ((size_t)written >= out_path_size))
140 {
141 (void)argv0;
142 return false;
143 }
144 out_path[written] = '\0';
145 return true;
146#else
147 /* Unknown UNIX: best effort only - argv0 may not be a resolvable path
148 * (e.g. found via $PATH), which is an honest, documented limitation of
149 * this fallback branch, not silently hidden. */
150 if ((argv0 == NULL) || (out_path_size == 0U))
151 {
152 return false;
153 }
154 (void)snprintf(out_path, out_path_size, "%s", argv0);
155 return true;
156#endif
157}
158
159static sapi_status_t backend_request(uint16_t reason_code)
160{
161 char reason_env[32];
162 int written;
163 char self_path[PATH_MAX];
164
165 written = snprintf(reason_env, sizeof(reason_env), "SAPI_REBOOT_REASON_CODE=%u", (unsigned int)reason_code);
166 if ((written > 0) && ((size_t)written < sizeof(reason_env)))
167 {
168 (void)putenv(reason_env);
169 }
170
171 /* No argv0 threaded through to this backend (see file header) - the
172 * unknown-UNIX fallback branch of resolve_self_exe_path() simply will
173 * not have one to fall back to and returns false, same as any other
174 * unresolvable-path case. */
175 if (!resolve_self_exe_path(self_path, sizeof(self_path), NULL))
176 {
177 return SAPI_STATUS_NOT_SUPPORTED;
178 }
179
180 /* Prefer the caller's own original argv (sapi_posix_backend_
181 * reboot_set_argv()) if registered, so a re-exec resumes with
182 * whatever command-line arguments the caller's own main() depends on
183 * - see this file's own header and sapi_posix_backend.h's doc.
184 * Otherwise fall back to a self-contained placeholder argv[0]; the
185 * kernel/loader resolves the actual executable from self_path either
186 * way, not from argv[0]'s string content. */
187 if (s_argv_registered)
188 {
189 (void)execv(self_path, s_registered_argv);
190 }
191 else
192 {
193 char *const argv_stub[] = { (char *)"sapi-reboot", NULL };
194
195 (void)execv(self_path, argv_stub);
196 }
197
198 /* Reached only if execv() failed. */
199 return SAPI_STATUS_NOT_SUPPORTED;
200}
Real POSIX/Linux backend for every OAL service (ADR-018).
const sapi_reboot_backend_t * sapi_posix_backend_reboot(void)
The POSIX sapi_reboot backend (execv() re-exec of the current process image, self-path resolved porta...
void sapi_posix_backend_reboot_set_argv(int argc, char *const argv[])
Registers the original process argv[] the POSIX reboot backend should re-exec with (instead of its ow...
#define SAPI_POSIX_REBOOT_MAX_ARGV
static char * s_registered_argv[SAPI_POSIX_REBOOT_MAX_ARGV+1U]
static bool resolve_self_exe_path(char *out_path, size_t out_path_size, const char *argv0)