Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_common.c
Go to the documentation of this file.
1
9#include "nilorea/n_common.h"
10#include "nilorea/n_log.h"
11#include "nilorea/n_str.h"
12
13#include <limits.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <libgen.h>
17
18#ifdef __windows__
19#include <windows.h>
20#else
21#include <errno.h>
22#include <strings.h>
23#include <unistd.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <sys/wait.h>
28#ifdef __linux__
29#include <string.h>
30#include <linux/limits.h>
31#include <unistd.h>
32#endif
33#endif
34
39void n_abort(char const* format, ...) {
40 char str[1024] = "";
41 va_list args;
42 va_start(args, format);
43
44 vsnprintf(str, sizeof str, format, args);
45 va_end(args);
46 fprintf(stderr, "%s", str);
47 exit(1);
48}
49
56int get_computer_name(char* computer_name, size_t len) {
57 memset(computer_name, 0, len);
58#ifdef WIN32
59 TCHAR infoBuf[len];
60 DWORD bufCharCount = len;
61 if (GetComputerName(infoBuf, &bufCharCount)) {
62 memcpy(computer_name, infoBuf, len);
63 } else {
64 strcpy(computer_name, "Unknown_Host_Name");
65 return FALSE;
66 }
67#else
68 if (gethostname(computer_name, len) == -1) {
69 int error = errno;
70 strcpy(computer_name, "Unknown_Host_Name");
71 n_log(LOG_ERR, "%s on gethostname !", strerror(error));
72 return FALSE;
73 }
74#endif
75 return TRUE;
76} /* get_computer_name */
77
83int file_exist(const char* filename) {
84 FILE* file = NULL;
85 if ((file = fopen(filename, "r")) != NULL) {
86 fclose(file);
87 return 1;
88 }
89 return 0;
90} /* file_exist */
91
96char* get_prog_dir(void) {
97 char strbuf[PATH_MAX] = "";
98
99 int error = 0;
100#ifdef __windows__
101 unsigned long int bytes = GetModuleFileName(NULL, strbuf, PATH_MAX);
102 error = errno;
103 if (bytes != 0) {
104 return strdup(dirname(strbuf));
105 }
106#else
107 char procbuf[PATH_MAX] = "";
108#ifdef __linux__
109 sprintf(procbuf, "/proc/%d/exe", (int)getpid());
110#elif defined __sun
111 sprintf(procbuf, "/proc/%d/path/a.out", (int)getpid());
112#endif
113 ssize_t bytes = MIN(readlink(procbuf, strbuf, PATH_MAX), PATH_MAX - 1);
114 error = errno;
115 if (bytes >= 0) {
116 strbuf[bytes] = '\0';
117 return strdup(dirname(strbuf));
118 }
119#endif
120 fprintf(stderr, "%s", strerror(error));
121 return NULL;
122} /* get_prog_dir */
123
128char* get_prog_name(void) {
129 char strbuf[PATH_MAX] = "";
130 int error = 0;
131#ifdef __windows__
132 unsigned long int bytes = GetModuleFileName(NULL, strbuf, PATH_MAX);
133 error = errno;
134 if (bytes != 0) {
135 return strdup(basename(strbuf));
136 }
137#else
138 char procbuf[PATH_MAX] = "";
139#ifdef __linux__
140 sprintf(procbuf, "/proc/%d/exe", (int)getpid());
141#elif defined __sun
142 sprintf(procbuf, "/proc/%d/path/a.out", (int)getpid());
143#endif
144 ssize_t bytes = MIN(readlink(procbuf, strbuf, PATH_MAX), PATH_MAX - 1);
145 error = errno;
146 if (bytes >= 0) {
147 strbuf[bytes] = '\0';
148 return strdup(basename(strbuf));
149 }
150#endif
151 fprintf(stderr, "%s", strerror(error));
152 return NULL;
153} /* get_prog_dir */
154
163int n_popen(char* cmd, size_t read_buf_size, void** nstr_output, int* ret) {
164 __n_assert(cmd, return FALSE);
165
166 if (read_buf_size > INT_MAX) {
167 n_log(LOG_ERR, "read_buf_size buffer size is too large for fgets (%zu>%d)", read_buf_size, INT_MAX);
168 return FALSE;
169 }
170
171 N_STR* output_pointer = new_nstr(read_buf_size + 1);
172
173 FILE* fp = NULL;
174 int status = 0;
175 char read_buf[read_buf_size];
176
177 fp = popen(cmd, "r");
178 int err = errno;
179 if (fp == NULL) {
180 n_log(LOG_ERR, "popen( %s ) returned NULL , %s (%d)", cmd, strerror(err), err);
181 free_nstr(&output_pointer);
182 return FALSE;
183 }
184 size_t length = 0;
185 while (fgets(read_buf, (int)read_buf_size, fp) != NULL) {
186 length = strlen(read_buf);
187 if (read_buf[length - 1] == '\n') {
188 read_buf[length - 1] = '\0';
189 }
190 nstrprintf_cat(output_pointer, "%s", read_buf);
191 }
192 status = pclose(fp);
193 err = errno;
194 if (status == -1) {
195 n_log(LOG_ERR, "pclose( %s ) returned -1 , %s (%d)", cmd, strerror(err), err);
196 if (WIFEXITED(status)) {
197 n_log(LOG_ERR, "Child exited with RC=%d", WEXITSTATUS(status));
198 (*ret) = WEXITSTATUS(status);
199 }
200 free_nstr(&output_pointer);
201 return FALSE;
202 }
203 (*ret) = WEXITSTATUS(status);
204 (*nstr_output) = output_pointer;
205 return TRUE;
206} /* n_popen( ... ) */
207
208#ifndef __windows__
213void sigchld_handler(int sig) {
214 // waitpid() might overwrite errno, so we save and restore it:
215 int saved_errno = errno;
216
217 while (waitpid(-1, NULL, WNOHANG) > 0);
218
219 errno = saved_errno;
220 n_log(LOG_DEBUG, "Signal %d", sig);
221}
222
228 struct sigaction sa;
229 sa.sa_handler = sigchld_handler; // reap all dead processes
230 sigemptyset(&sa.sa_mask);
231 sa.sa_flags = SA_RESTART;
232 if (sigaction(SIGCHLD, &sa, NULL) == -1) {
233 int error = errno;
234 n_log(LOG_ERR, "sigaction error: %s", strerror(error));
235 return FALSE;
236 }
237 return TRUE;
238}
239
244void log_environment(int loglevel) {
245 extern char** environ;
246 for (char** env = environ; *env != 0; env++) {
247 n_log(loglevel, "env: %s", *env);
248 }
249}
250
258
265 int error = 0;
266
267 /* Fork off the parent process */
268 pid_t pid = fork();
269 error = errno;
270 if (pid < 0) {
271 n_log(LOG_ERR, "Error: unable to fork child: %s", strerror(error));
272 exit(1);
273 }
274 if (pid > 0) {
275 n_log(LOG_NOTICE, "Child started successfuly !");
276 exit(0);
277 }
278
279 if (!(mode & N_DAEMON_NO_SETSID)) {
280 /* On success: The child process becomes session leader
281 * setsid is detaching the process from the terminal */
282 if (setsid() < 0) {
283 error = errno;
284 n_log(LOG_ERR, "Error: unable to set session leader with setsid(): %s", strerror(error));
285 exit(1);
286 } else {
287 n_log(LOG_NOTICE, "Session leader set !");
288 }
289 }
290
291 if (!(mode & N_DAEMON_NO_SIGCHLD_IGN)) {
292 /* Ignore signal sent from child to parent process */
293 signal(SIGCHLD, SIG_IGN);
294 }
295
297 /* catching signal */
299 }
300
301 if (!(mode & N_DAEMON_NO_DOUBLE_FORK)) {
302 /* Double fork to detach from the parent, and be adopted by init process */
303 pid = fork();
304 error = errno;
305 if (pid < 0) {
306 n_log(LOG_ERR, "Error: unable to double fork child: %s", strerror(error));
307 exit(1);
308 }
309 if (pid > 0) {
310 n_log(LOG_NOTICE, "Double fork child started successfuly !");
311 exit(0);
312 }
313 }
314
315 if (!(mode & N_DAEMON_NO_UMASK)) {
316 /* reset umask */
317 umask(0);
318 }
319
320 if (!(mode & N_DAEMON_NO_CHDIR)) {
321 /* set working directory */
322 if (chdir("/") < 0) {
323 error = errno;
324 n_log(LOG_ERR, "couldn't chdir() to '/': %s", strerror(error));
325 return errno;
326 }
327 }
328
329 if (!(mode & N_DAEMON_NO_CLOSE)) {
330 /* Close all open file descriptors except standard ones (stdin, stdout, stderr) */
331 for (int x = 3; x < sysconf(_SC_OPEN_MAX); x++) {
332 close(x);
333 }
334 }
335
337 /* redirect stdin,stdout,stderr to /dev/null */
338 int fd = open("/dev/null", O_RDWR, 0);
339 error = errno;
340 if (fd != -1) {
341 dup2(fd, STDIN_FILENO);
342 dup2(fd, STDOUT_FILENO);
343 dup2(fd, STDERR_FILENO);
344 if (fd > 2) {
345 close(fd);
346 }
347 } else {
348 n_log(LOG_ERR, "Failed to open /dev/null: %s", strerror(errno));
349 }
350 }
351
352 return TRUE;
353} /* n_daemonize(...) */
354
362pid_t system_nb(const char* command, int* infp, int* outfp) {
363 __n_assert(command, return -1);
364
365 int p_stdin[2] = {-1, -1};
366 int p_stdout[2] = {-1, -1};
367 pid_t pid = -1;
368
369 if (outfp != NULL) {
370 if (pipe(p_stdin) != 0)
371 return -1;
372 }
373 if (infp != NULL) {
374 if (pipe(p_stdout) != 0) {
375 if (outfp != NULL) {
376 close(p_stdin[0]);
377 close(p_stdin[1]);
378 }
379 return (-1);
380 }
381 }
382
383 pid = fork();
384
385 if (pid < 0) {
386 n_log(LOG_ERR, "Couldn't fork command %s", command);
387 if (outfp != NULL) {
388 close(p_stdin[0]);
389 close(p_stdin[1]);
390 }
391 if (infp != NULL) {
392 close(p_stdout[0]);
393 close(p_stdout[1]);
394 }
395 return pid;
396 }
397 if (pid == 0) {
398 if (outfp != NULL) {
399 close(p_stdin[1]);
400 dup2(p_stdin[0], 0);
401 }
402 if (infp != NULL) {
403 close(p_stdout[0]);
404 dup2(p_stdout[1], 1);
405 }
406 execlp("sh", "sh", "-c", command, (char*)NULL);
407 // should never get here
408 int error = errno;
409 n_log(LOG_ERR, "%s:%d: exec failed: %s", __FILE__, __LINE__, strerror(error));
410 exit(42);
411 }
412 if (infp != NULL) {
413 close(p_stdout[1]);
414 *infp = p_stdout[0];
415 }
416 if (outfp != NULL) {
417 close(p_stdin[0]);
418 *outfp = p_stdin[1];
419 }
420 return pid;
421} /* system_nb */
422
423#endif /* ifndef __windows__ */
424
430void N_HIDE_STR(char* buf, ...) {
431 size_t it = 0;
432 va_list args;
433
434 va_start(args, buf);
435
436 int arg = 0;
437
438 while ((arg = va_arg(args, int))) {
439 buf[it] = (char)arg;
440 it++;
441 }
442 buf[it] = '\0';
443 va_end(args);
444} /* N_HIDE_STR */
445
451char* n_get_file_extension(char path[]) {
452 char* result = NULL;
453 size_t i = 0, n = 0;
454
455 __n_assert(path, return "");
456
457 n = strlen(path);
458 i = n - 1;
459 while ((i > 0) && (path[i] != '.') && (path[i] != '/') && (path[i] != '\\')) {
460 i--;
461 }
462 if ((i > 0) && (i < n - 1) && (path[i] == '.') && (path[i - 1] != '/') && (path[i - 1] != '\\')) {
463 result = path + i;
464 } else {
465 result = path + n;
466 }
467 return result;
468}
int mode
Network for managing conenctions.
Definition ex_network.c:22
void log_environment(int loglevel)
log environment variables in syslog
Definition n_common.c:244
#define N_DAEMON_NO_UMASK
daemonize flag: do not call umask( 0 )
Definition n_common.h:491
char * get_prog_name(void)
get current program name
Definition n_common.c:128
#define N_DAEMON_NO_DOUBLE_FORK
daemonize flag: do not double fork
Definition n_common.h:487
void N_HIDE_STR(char *buf,...)
store a hidden version of a string
Definition n_common.c:430
#define N_DAEMON_NO_SIGCHLD_IGN
daemonize flag: do not ignore SIGCHLD
Definition n_common.h:495
#define N_DAEMON_NO_CHDIR
daemonize flag: do not call chdir("/")
Definition n_common.h:493
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:256
#define N_DAEMON_NO_CLOSE
daemonize flag: no descriptor close at all
Definition n_common.h:483
#define N_DAEMON_NO_SIGCHLD_HANDLER
daemonize flag: do not use internal zombie SIGCHLD handler
Definition n_common.h:497
#define N_DAEMON_NO_STD_REDIRECT
daemonize flag: just do not redirect stdin/out/err to /dev/null
Definition n_common.h:485
int get_computer_name(char *computer_name, size_t len)
abort program with a text
Definition n_common.c:56
#define N_DAEMON_NO_SETSID
daemonize flag: do not call setsid
Definition n_common.h:489
void sigchld_handler(int sig)
Handles SIGCHLD issues when forking.
Definition n_common.c:213
pid_t system_nb(const char *command, int *infp, int *outfp)
Non blocking system call.
Definition n_common.c:362
char * n_get_file_extension(char path[])
get extension of path+filename
Definition n_common.c:451
char * get_prog_dir(void)
get current program running directory
Definition n_common.c:96
int n_daemonize_ex(int mode)
Daemonize program.
Definition n_common.c:264
void n_abort(char const *format,...)
abort program with a text
Definition n_common.c:39
int sigchld_handler_installer()
install signal SIGCHLD handler to reap zombie processes
Definition n_common.c:227
int n_daemonize(void)
Daemonize program.
Definition n_common.c:255
int file_exist(const char *filename)
test if file exist and if it's readable
Definition n_common.c:83
int n_popen(char *cmd, size_t read_buf_size, void **nstr_output, int *ret)
launch a command abd return output and status
Definition n_common.c:163
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:70
#define LOG_DEBUG
debug-level messages
Definition n_log.h:65
#define LOG_ERR
error conditions
Definition n_log.h:57
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:61
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:176
#define nstrprintf_cat(__nstr_var, __format,...)
Macro to quickly allocate and sprintf and cat to a N_STR.
Definition n_str.h:98
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
Definition n_str.c:180
A box including a string and his lenght.
Definition n_str.h:39
Common headers and low-level functions & define.
Generic log system.
N_STR and string function declaration.