61 va_start(args, format);
63 vsnprintf(str,
sizeof str, format, args);
65 fprintf(stderr,
"%s", str);
76 if (!computer_name || len == 0)
return FALSE;
77 memset(computer_name, 0, len);
80 DWORD bufCharCount = (DWORD)len;
81 if (GetComputerName(infoBuf, &bufCharCount)) {
82 memcpy(computer_name, infoBuf, len);
84 strncpy(computer_name,
"Unknown_Host_Name", len - 1);
85 computer_name[len - 1] =
'\0';
89 if (gethostname(computer_name, len) == -1) {
91 strncpy(computer_name,
"Unknown_Host_Name", len - 1);
92 computer_name[len - 1] =
'\0';
107 if ((file = fopen(filename,
"r")) != NULL) {
119 char strbuf[PATH_MAX] =
"";
123 unsigned long int bytes = GetModuleFileName(NULL, strbuf, PATH_MAX);
126 return strdup(dirname(strbuf));
129 char procbuf[PATH_MAX] =
"";
131 snprintf(procbuf, PATH_MAX,
"/proc/%d/exe", (
int)getpid());
133 snprintf(procbuf, PATH_MAX,
"/proc/%d/path/a.out", (
int)getpid());
135 ssize_t bytes = MIN(readlink(procbuf, strbuf, PATH_MAX), PATH_MAX - 1);
138 strbuf[bytes] =
'\0';
139 return strdup(dirname(strbuf));
142 fprintf(stderr,
"%s", strerror(error));
151 char strbuf[PATH_MAX] =
"";
154 unsigned long int bytes = GetModuleFileName(NULL, strbuf, PATH_MAX);
157 return strdup(basename(strbuf));
160 char procbuf[PATH_MAX] =
"";
162 snprintf(procbuf, PATH_MAX,
"/proc/%d/exe", (
int)getpid());
164 snprintf(procbuf, PATH_MAX,
"/proc/%d/path/a.out", (
int)getpid());
166 ssize_t bytes = MIN(readlink(procbuf, strbuf, PATH_MAX), PATH_MAX - 1);
169 strbuf[bytes] =
'\0';
170 return strdup(basename(strbuf));
173 fprintf(stderr,
"%s", strerror(error));
185int n_popen(
char* cmd,
size_t read_buf_size,
void** nstr_output,
int* ret) {
188 if (read_buf_size > INT_MAX) {
189 n_log(
LOG_ERR,
"read_buf_size buffer size is too large for fgets (%zu>%d)", read_buf_size, INT_MAX);
192 if (read_buf_size > 65536) {
193 n_log(
LOG_ERR,
"read_buf_size %zu exceeds safe stack limit", read_buf_size);
201 char read_buf[read_buf_size];
203 fp = popen(cmd,
"r");
206 n_log(
LOG_ERR,
"popen( %s ) returned NULL , %s (%d)", cmd, strerror(err), err);
210 while (fgets(read_buf, (
int)read_buf_size, fp) != NULL) {
211 size_t length = strlen(read_buf);
212 if (length > 0 && read_buf[length - 1] ==
'\n') {
213 read_buf[length - 1] =
'\0';
220 n_log(
LOG_ERR,
"pclose( %s ) returned -1 , %s (%d)", cmd, strerror(err), err);
224 if (ret) (*ret) = WEXITSTATUS(status);
226 (*nstr_output) = output_pointer;
247static int append_quoted(
char* out,
size_t out_len,
size_t* used,
const char* arg) {
249 const char* p = NULL;
253 if (*used + 1 >= out_len) \
255 out[(*used)++] = (c); \
261 for (p = arg; *p; p++) {
269 for (k = 0; k < slashes * 2 + 1; k++)
274 for (k = 0; k < slashes; k++)
283 for (k = 0; k < slashes * 2; k++)
300 PROCESS_INFORMATION pi;
304 if (!append_quoted(
line,
sizeof(
line), &used, program))
306 for (i = 0; args && args[i]; i++) {
307 if (!append_quoted(
line,
sizeof(
line), &used, args[i])) {
308 n_log(
LOG_ERR,
"n_spawn_detached: the command line is too long");
312 memset(&si, 0,
sizeof(si));
314 memset(&pi, 0,
sizeof(pi));
315 if (!CreateProcessA(NULL,
line, NULL, NULL, FALSE, DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,
316 NULL, NULL, &si, &pi)) {
317 n_log(
LOG_ERR,
"n_spawn_detached: cannot start %s (%lu)", program, (
unsigned long)GetLastError());
320 CloseHandle(pi.hThread);
321 CloseHandle(pi.hProcess);
326 const char* argv[64];
332 for (i = 0; args && args[i]; i++) {
333 if (n >=
sizeof(argv) /
sizeof(argv[0]) - 1) {
334 n_log(
LOG_ERR,
"n_spawn_detached: more than %zu arguments",
sizeof(argv) /
sizeof(argv[0]) - 2);
347 n_log(
LOG_ERR,
"n_spawn_detached: fork failed: %s", strerror(errno));
351 pid_t grandchild = 0;
355 if (grandchild == 0) {
356 execvp(program, (
char*
const*)argv);
359 _exit(grandchild < 0 ? 1 : 0);
361 if (waitpid(child, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
362 n_log(
LOG_ERR,
"n_spawn_detached: could not start %s", program);
370int n_spawn_wait(
const char* program,
const char*
const* args,
int* exit_code) {
374int n_spawn_wait_cancel(
const char* program,
const char*
const* args,
int* exit_code,
const volatile int* cancel) {
383 PROCESS_INFORMATION pi;
388 if (!append_quoted(
line,
sizeof(
line), &used, program))
390 for (i = 0; args && args[i]; i++) {
391 if (!append_quoted(
line,
sizeof(
line), &used, args[i])) {
392 n_log(
LOG_ERR,
"n_spawn_wait: the command line is too long");
396 memset(&si, 0,
sizeof(si));
398 memset(&pi, 0,
sizeof(pi));
400 if (!CreateProcessA(NULL,
line, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
401 n_log(
LOG_ERR,
"n_spawn_wait: cannot start %s (%lu)", program, (
unsigned long)GetLastError());
404 CloseHandle(pi.hThread);
406 WaitForSingleObject(pi.hProcess, INFINITE);
410 while (WaitForSingleObject(pi.hProcess, 100) == WAIT_TIMEOUT) {
412 TerminateProcess(pi.hProcess, 1);
413 WaitForSingleObject(pi.hProcess, INFINITE);
414 CloseHandle(pi.hProcess);
420 if (!GetExitCodeProcess(pi.hProcess, &code))
422 CloseHandle(pi.hProcess);
424 *exit_code = (int)code;
425 return code == 0 ? TRUE : FALSE;
429 const char* argv[64];
435 for (i = 0; args && args[i]; i++) {
436 if (n >=
sizeof(argv) /
sizeof(argv[0]) - 1) {
437 n_log(
LOG_ERR,
"n_spawn_wait: more than %zu arguments",
sizeof(argv) /
sizeof(argv[0]) - 2);
446 n_log(
LOG_ERR,
"n_spawn_wait: fork failed: %s", strerror(errno));
451 execvp(program, (
char*
const*)argv);
462 struct timespec tick = {0, 100000000L};
463 pid_t got = waitpid(child, &status, WNOHANG);
467 if (got < 0 && errno != EINTR) {
468 n_log(
LOG_ERR,
"n_spawn_wait_cancel: waiting for %s failed: %s", program, strerror(errno));
473 kill(child, SIGTERM);
474 else if (asked == 20)
475 kill(child, SIGKILL);
478 nanosleep(&tick, NULL);
487 while (waitpid(child, &status, 0) < 0) {
488 if (errno != EINTR) {
489 n_log(
LOG_ERR,
"n_spawn_wait: waiting for %s failed: %s", program, strerror(errno));
494 if (!WIFEXITED(status)) {
495 n_log(
LOG_ERR,
"n_spawn_wait: %s was ended by a signal", program);
499 *exit_code = WEXITSTATUS(status);
500 if (WEXITSTATUS(status) == 127)
501 n_log(
LOG_ERR,
"n_spawn_wait: %s could not be found or started", program);
502 return WEXITSTATUS(status) == 0 ? TRUE : FALSE;
535 size_t used = 0, i = 0;
537 PROCESS_INFORMATION pi;
538 SECURITY_ATTRIBUTES sa;
539 HANDLE read_end = NULL, log = INVALID_HANDLE_VALUE;
542 if (!append_quoted(
line,
sizeof(
line), &used, program)) {
546 for (i = 0; args && args[i]; i++) {
547 if (!append_quoted(
line,
sizeof(
line), &used, args[i])) {
548 n_log(
LOG_ERR,
"n_spawn_pipe_open: the command line is too long");
553 memset(&sa, 0,
sizeof(sa));
554 sa.nLength =
sizeof(sa);
555 sa.bInheritHandle = TRUE;
556 if (!CreatePipe(&read_end, &sp->
input, &sa, 0)) {
557 n_log(
LOG_ERR,
"n_spawn_pipe_open: no pipe (%lu)", (
unsigned long)GetLastError());
563 SetHandleInformation(sp->
input, HANDLE_FLAG_INHERIT, 0);
565 log = CreateFileA(log_path, GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
566 if (log == INVALID_HANDLE_VALUE)
567 n_log(
LOG_ERR,
"n_spawn_pipe_open: cannot write %s (%lu)", log_path, (
unsigned long)GetLastError());
569 memset(&si, 0,
sizeof(si));
571 si.dwFlags = STARTF_USESTDHANDLES;
572 si.hStdInput = read_end;
573 si.hStdOutput = log != INVALID_HANDLE_VALUE ? log : GetStdHandle(STD_OUTPUT_HANDLE);
574 si.hStdError = log != INVALID_HANDLE_VALUE ? log : GetStdHandle(STD_ERROR_HANDLE);
575 memset(&pi, 0,
sizeof(pi));
576 if (!CreateProcessA(NULL,
line, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
577 n_log(
LOG_ERR,
"n_spawn_pipe_open: cannot start %s (%lu)", program, (
unsigned long)GetLastError());
578 CloseHandle(read_end);
579 CloseHandle(sp->
input);
580 if (log != INVALID_HANDLE_VALUE)
586 CloseHandle(read_end);
587 if (log != INVALID_HANDLE_VALUE)
589 CloseHandle(pi.hThread);
590 sp->process = pi.hProcess;
595 const char* argv[64];
597 int fds[2] = {-1, -1};
601 for (i = 0; args && args[i]; i++) {
602 if (n >=
sizeof(argv) /
sizeof(argv[0]) - 1) {
603 n_log(
LOG_ERR,
"n_spawn_pipe_open: more than %zu arguments",
sizeof(argv) /
sizeof(argv[0]) - 2);
610 if (pipe(fds) != 0) {
611 n_log(
LOG_ERR,
"n_spawn_pipe_open: no pipe: %s", strerror(errno));
617 fcntl(fds[1], F_SETFD, FD_CLOEXEC);
618 fcntl(fds[0], F_SETFD, FD_CLOEXEC);
620 log = open(log_path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
622 n_log(
LOG_ERR,
"n_spawn_pipe_open: cannot write %s: %s", log_path, strerror(errno));
626 n_log(
LOG_ERR,
"n_spawn_pipe_open: fork failed: %s", strerror(errno));
634 if (sp->
child == 0) {
637 if (dup2(fds[0], STDIN_FILENO) < 0)
640 dup2(log, STDOUT_FILENO);
641 dup2(log, STDERR_FILENO);
643 execvp(program, (
char*
const*)argv);
656 const char* at = (
const char*)data;
665 DWORD chunk = len > 0x40000000u ? 0x40000000u : (DWORD)len, wrote = 0;
667 if (!WriteFile(sp->
input, at, chunk, &wrote, NULL) || wrote == 0) {
668 n_log(
LOG_ERR,
"n_spawn_pipe_write: %s stopped reading (%lu)", sp->
program, (
unsigned long)GetLastError());
677 sigset_t pipe_set, before;
678 int ok = TRUE, raised = 0;
686 sigemptyset(&pipe_set);
687 sigaddset(&pipe_set, SIGPIPE);
688 pthread_sigmask(SIG_BLOCK, &pipe_set, &before);
690 ssize_t wrote = write(sp->
input, at, len);
697 n_log(
LOG_ERR,
"n_spawn_pipe_write: %s stopped reading: %s", sp->
program, strerror(errno));
702 len -= (size_t)wrote;
705 struct timespec none = {0, 0};
707 while (sigtimedwait(&pipe_set, NULL, &none) < 0 && errno == EINTR)
710 pthread_sigmask(SIG_SETMASK, &before, NULL);
722 if (!pipe_ptr || !*pipe_ptr)
727 DWORD code = (DWORD)-1;
730 TerminateProcess(sp->process, 1);
733 CloseHandle(sp->
input);
734 WaitForSingleObject(sp->process, INFINITE);
735 if (!
stop && GetExitCodeProcess(sp->process, &code)) {
737 *exit_code = (int)code;
738 ok = code == 0 ? TRUE : FALSE;
740 CloseHandle(sp->process);
744 int status = 0, asked = 0;
747 kill(sp->
child, SIGTERM);
753 pid_t got = waitpid(sp->
child, &status,
stop ? WNOHANG : 0);
755 if (got == sp->
child)
760 n_log(
LOG_ERR,
"n_spawn_pipe_close: waiting for %s failed: %s", sp->
program, strerror(errno));
767 kill(sp->
child, SIGKILL);
769 struct timespec tick = {0, 100000000L};
771 nanosleep(&tick, NULL);
776 }
else if (!WIFEXITED(status)) {
780 *exit_code = WEXITSTATUS(status);
781 if (WEXITSTATUS(status) == 127)
783 ok = WEXITSTATUS(status) == 0 ? TRUE : FALSE;
796 HINSTANCE
done = ShellExecuteA(NULL,
"open", path, NULL, NULL, SW_SHOWNORMAL);
799 if ((INT_PTR)
done <= 32) {
800 n_log(
LOG_ERR,
"n_open_with_default: cannot open %s (%ld)", path, (
long)(INT_PTR)
done);
807 const char* args[2] = {path, NULL};
822#if defined(_WIN32) || defined(__MINGW32__) || defined(__windows__)
823 LPCH env_block = GetEnvironmentStrings();
824 if (!env_block)
return;
825 for (LPCH var = env_block; *var !=
'\0'; var += strlen(var) + 1) {
826 n_log(loglevel,
"env: %s", var);
828 FreeEnvironmentStrings(env_block);
830 extern char** environ;
831 for (
char** env = environ; *env != NULL; env++) {
832 n_log(loglevel,
"env: %s", *env);
844 int saved_errno = errno;
846 while (waitpid(-1, NULL, WNOHANG) > 0);
859 sigemptyset(&sa.sa_mask);
860 sa.sa_flags = SA_RESTART;
861 if (sigaction(SIGCHLD, &sa, NULL) == -1) {
889 n_log(
LOG_ERR,
"Error: unable to fork child: %s", strerror(error));
902 n_log(
LOG_ERR,
"Error: unable to set session leader with setsid(): %s", strerror(error));
911 signal(SIGCHLD, SIG_IGN);
924 n_log(
LOG_ERR,
"Error: unable to double fork child: %s", strerror(error));
940 if (chdir(
"/") < 0) {
942 n_log(
LOG_ERR,
"couldn't chdir() to '/': %s", strerror(error));
949 for (
int x = 3; x < sysconf(_SC_OPEN_MAX); x++) {
956 int fd = open(
"/dev/null", O_RDWR, 0);
958 dup2(fd, STDIN_FILENO);
959 dup2(fd, STDOUT_FILENO);
960 dup2(fd, STDERR_FILENO);
965 n_log(
LOG_ERR,
"Failed to open /dev/null: %s", strerror(errno));
979pid_t
system_nb(
const char* command,
int* infp,
int* outfp) {
982 int p_stdin[2] = {-1, -1};
983 int p_stdout[2] = {-1, -1};
987 if (pipe(p_stdin) != 0)
991 if (pipe(p_stdout) != 0) {
1004 if (outfp != NULL) {
1015 if (outfp != NULL) {
1017 dup2(p_stdin[0], 0);
1021 dup2(p_stdout[1], 1);
1023 execlp(
"sh",
"sh",
"-c", command, (
char*)NULL);
1026 n_log(
LOG_ERR,
"%s:%d: exec failed: %s", __FILE__, __LINE__, strerror(error));
1031 *infp = p_stdout[0];
1033 if (outfp != NULL) {
1035 *outfp = p_stdin[1];
1052 va_start(args, buf);
1056 while ((arg = va_arg(args,
int))) {
1057 buf[it] = (char)arg;
1070 char* result = NULL;
1071 size_t i = 0, n = 0;
1077 while ((i > 0) && (path[i] !=
'.') && (path[i] !=
'/') && (path[i] !=
'\\')) {
1080 if ((i > 0) && (i < n - 1) && (path[i] ==
'.') && (path[i - 1] !=
'/') && (path[i - 1] !=
'\\')) {
static void stop(int sig)
volatile sig_atomic_t done
void line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color)
draw a line
void log_environment(int loglevel)
log environment variables in syslog
#define N_DAEMON_NO_UMASK
daemonize flag: do not call umask( 0 )
char * get_prog_name(void)
get current program name
int n_open_with_default(const char *path)
Open a file or a URL with whatever the desktop opens it with.
int n_spawn_wait(const char *program, const char *const *args, int *exit_code)
Run a program with arguments and wait for it to finish.
int n_spawn_detached(const char *program, const char *const *args)
Start a program and do not wait for it.
#define N_DAEMON_NO_DOUBLE_FORK
daemonize flag: do not double fork
void N_HIDE_STR(char *buf,...)
store a hidden version of a string
int n_spawn_wait_cancel(const char *program, const char *const *args, int *exit_code, const volatile int *cancel)
Run a program and wait for it, ending it early when asked.
#define N_DAEMON_NO_SIGCHLD_IGN
daemonize flag: do not ignore SIGCHLD
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
#define N_DAEMON_NO_CHDIR
daemonize flag: do not call chdir("/")
#define __n_assert(__ptr, __ret)
macro to assert things
#define N_DAEMON_NO_CLOSE
daemonize flag: no descriptor close at all
#define N_DAEMON_NO_SIGCHLD_HANDLER
daemonize flag: do not use internal zombie SIGCHLD handler
#define N_DAEMON_NO_STD_REDIRECT
daemonize flag: just do not redirect stdin/out/err to /dev/null
int get_computer_name(char *computer_name, size_t len)
get the computer name
#define N_DAEMON_NO_SETSID
daemonize flag: do not call setsid
void sigchld_handler(int sig)
Handles SIGCHLD issues when forking.
pid_t system_nb(const char *command, int *infp, int *outfp)
Non blocking system call.
char * n_get_file_extension(char path[])
get extension of path+filename
int n_spawn_pipe_close(N_SPAWN_PIPE **pipe_ptr, int stop, int *exit_code)
End a program's input, or end the program, and wait for it.
char * get_prog_dir(void)
get current program running directory
int n_daemonize_ex(int mode)
Daemonize program.
void n_abort(char const *format,...)
abort program with a text
int n_daemonize(void)
Daemonize program.
N_SPAWN_PIPE * n_spawn_pipe_open(const char *program, const char *const *args, const char *log_path)
Start a program whose standard input is fed by the caller.
int n_spawn_pipe_write(N_SPAWN_PIPE *sp, const void *data, size_t len)
Write to a program's standard input, all of it.
int file_exist(const char *filename)
test if file exist and if it's readable
#define Free(__ptr)
Free Handler to get errors.
int n_popen(char *cmd, size_t read_buf_size, void **nstr_output, int *ret)
launch a command and return output and status
int sigchld_handler_installer(void)
install signal SIGCHLD handler to reap zombie processes
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
#define LOG_NOTICE
normal but significant condition
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
#define nstrprintf_cat(__nstr_var, __format,...)
Macro to quickly allocate and sprintf and cat to a N_STR.
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
A box including a string and his lenght.
char program[256]
for the log lines
int input
write end of the program's standard input, -1 once closed
A program started with its standard input on a pipe the caller writes to (n_spawn_pipe_open()).
Common headers and low-level functions & define.
N_STR and string function declaration.