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