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
34
35
40void n_abort( char const *format, ... )
41{
42 char str[1024] = "" ;
43 va_list args;
44 va_start(args, format);
45
46 vsnprintf(str, sizeof str, format, args);
47 va_end(args);
48 fprintf(stderr, "%s", str);
49 exit(1);
50}
51
52
53
60int get_computer_name( char *computer_name , size_t len )
61{
62 memset(computer_name, 0, len);
63#ifdef WIN32
64 TCHAR infoBuf[len];
65 DWORD bufCharCount = len;
66 if( GetComputerName( infoBuf, &bufCharCount ) )
67 {
68 memcpy( computer_name , infoBuf , len );
69 }
70 else
71 {
72 strcpy(computer_name, "Unknown_Host_Name");
73 return FALSE ;
74 }
75#else
76 if( gethostname(computer_name, len) == -1 )
77 {
78 int error = errno ;
79 strcpy(computer_name, "Unknown_Host_Name");
80 n_log( LOG_ERR , "%s on gethostname !" , strerror( error ) );
81 return FALSE ;
82 }
83#endif
84 return TRUE ;
85} /* get_computer_name */
86
87
88
94int file_exist( const char *filename )
95{
96 FILE *file = NULL ;
97 if( ( file = fopen( filename, "r" ) ) != NULL )
98 {
99 fclose(file);
100 return 1 ;
101 }
102 return 0;
103} /* file_exist */
104
105
106
111char *get_prog_dir( void )
112{
113 char strbuf[ PATH_MAX ] = "" ;
114
115 int error = 0 ;
116#ifdef __windows__
117 unsigned long int bytes = GetModuleFileName( NULL, strbuf, PATH_MAX );
118 error = errno ;
119 if(bytes != 0)
120 {
121 return strdup( dirname(strbuf ) );
122 }
123#else
124 char procbuf[ PATH_MAX ] = "" ;
125#ifdef __linux__
126 sprintf( procbuf, "/proc/%d/exe", (int)getpid() );
127#elif defined __sun
128 sprintf( procbuf, "/proc/%d/path/a.out", (int)getpid() );
129#endif
130 int bytes = MIN( readlink( procbuf, strbuf, PATH_MAX ), PATH_MAX - 1 );
131 error = errno ;
132 if( bytes >= 0 )
133 {
134 strbuf[ bytes ] = '\0';
135 return strdup( dirname( strbuf ) );
136 }
137#endif
138 fprintf( stderr, "%s", strerror( error ) );
139 return NULL ;
140} /* get_prog_dir */
141
142
147char *get_prog_name( void )
148{
149 char strbuf[ PATH_MAX ] = "" ;
150 int error = 0 ;
151#ifdef __windows__
152 unsigned long int bytes = GetModuleFileName( NULL, strbuf, PATH_MAX );
153 error = errno ;
154 if(bytes != 0)
155 {
156 return strdup( basename(strbuf ) );
157 }
158#else
159 char procbuf[ PATH_MAX ] = "" ;
160#ifdef __linux__
161 sprintf( procbuf, "/proc/%d/exe", (int)getpid() );
162#elif defined __sun
163 sprintf( procbuf, "/proc/%d/path/a.out", (int)getpid() );
164#endif
165 int bytes = MIN( readlink( procbuf, strbuf, PATH_MAX ), PATH_MAX - 1 );
166 error = errno ;
167 if( bytes >= 0 )
168 {
169 strbuf[ bytes ] = '\0';
170 return strdup( basename( strbuf ) );
171 }
172#endif
173 fprintf( stderr, "%s", strerror( error ) );
174 return NULL ;
175} /* get_prog_dir */
176
177
178
187int n_popen( char *cmd, int read_buf_size, void **nstr_output, int *ret )
188{
189 __n_assert( cmd, return FALSE );
190
191 N_STR *output_pointer = new_nstr( read_buf_size + 1 );
192
193 FILE *fp = NULL ;
194 int status = 0 ;
195 char read_buf[ read_buf_size ] ;
196
197 fp = popen( cmd, "r" );
198 int err = errno ;
199 if (fp == NULL)
200 {
201 n_log( LOG_ERR, "popen( %s ) returned NULL , %s (%d)", cmd, strerror( err ), err );
202 return FALSE ;
203 }
204
205 int length = 0 ;
206 while( fgets( read_buf, read_buf_size, fp ) != NULL )
207 {
208 length = strlen( read_buf );
209 if( read_buf[ length - 1 ] == '\n' )
210 {
211 read_buf[ length - 1 ] = '\0' ;
212 }
213 nstrprintf_cat( output_pointer, "%s", read_buf );
214 }
215 status = pclose( fp );
216 err = errno ;
217 if( status == -1 )
218 {
219 n_log( LOG_ERR, "pclose( %s ) returned -1 , %s (%d)", cmd, strerror( err ), err );
220 if( WIFEXITED( status ) )
221 {
222 n_log( LOG_ERR, "Child exited with RC=%d", WEXITSTATUS( status ) );
223 (*ret) = WEXITSTATUS( status );
224 }
225 return FALSE ;
226 }
227 (*ret) = WEXITSTATUS( status );
228 (*nstr_output) = output_pointer ;
229 return TRUE ;
230} /* n_popen( ... ) */
231
232
233#ifndef __windows__
238void sigchld_handler( int sig )
239{
240 // waitpid() might overwrite errno, so we save and restore it:
241 int saved_errno = errno;
242
243 while(waitpid(-1, NULL, WNOHANG) > 0);
244
245 errno = saved_errno;
246 n_log( LOG_DEBUG, "Signal %d", sig );
247}
248
254{
255 struct sigaction sa;
256 sa.sa_handler = sigchld_handler; // reap all dead processes
257 sigemptyset(&sa.sa_mask);
258 sa.sa_flags = SA_RESTART;
259 if (sigaction(SIGCHLD, &sa, NULL) == -1)
260 {
261 int error = errno ;
262 n_log( LOG_ERR , "sigaction error: %s" , strerror( error ) );
263 return FALSE ;
264 }
265 return TRUE ;
266}
267
268
273void log_environment( int loglevel )
274{
275 extern char **environ;
276 for( char **env = environ ; *env != 0 ; env++ )
277 {
278 n_log( loglevel , "env: %s" , *env );
279 }
280}
281
290
296int n_daemonize_ex( int mode )
297{
298 int error = 0 ;
299
300 /* Fork off the parent process */
301 pid_t pid = fork();
302 error = errno ;
303 if( pid < 0 )
304 {
305 n_log( LOG_ERR, "Error: unable to fork child: %s", strerror( error ) );
306 exit( 1 );
307 }
308 if( pid > 0 )
309 {
310 n_log( LOG_NOTICE, "Child started successfuly !" );
311 exit( 0 );
312 }
313
314 if( !(mode&N_DAEMON_NO_SETSID) )
315 {
316 /* On success: The child process becomes session leader
317 * setsid is detaching the process from the terminal */
318 if( setsid() < 0 )
319 {
320 error = errno ;
321 n_log( LOG_ERR, "Error: unable to set session leader with setsid(): %s", strerror( error ) );
322 exit( 1 );
323 }
324 else
325 {
326 n_log( LOG_NOTICE, "Session leader set !" );
327 }
328 }
329
330 if( !(mode&N_DAEMON_NO_SIGCHLD_IGN) )
331 {
332 /* Ignore signal sent from child to parent process */
333 signal(SIGCHLD, SIG_IGN);
334 }
335
336 if( !(mode&N_DAEMON_NO_SIGCHLD_HANDLER) )
337 {
338 /* catching signal */
340 }
341
342 if( !(mode&N_DAEMON_NO_DOUBLE_FORK) )
343 {
344 /* Double fork to detach from the parent, and be adopted by init process */
345 pid = fork();
346 error = errno ;
347 if( pid < 0 )
348 {
349 n_log( LOG_ERR, "Error: unable to double fork child: %s", strerror( error ) );
350 exit( 1 );
351 }
352 if( pid > 0 )
353 {
354 n_log( LOG_NOTICE, "Double fork child started successfuly !" );
355 exit( 0 );
356 }
357 }
358
359 if( !(mode&N_DAEMON_NO_UMASK) )
360 {
361 /* reset umask */
362 umask( 0 );
363 }
364
365 if( !(mode&N_DAEMON_NO_CHDIR) )
366 {
367 /* set working directory */
368 if( chdir( "/" ) < 0 )
369 {
370 error = errno ;
371 n_log( LOG_ERR, "couldn't chdir() to '/': %s" , strerror( error ) );
372 return errno;
373 }
374 }
375
376 if( !(mode&N_DAEMON_NO_CLOSE) )
377 {
378 /* Close all open file descriptors except standard ones (stdin, stdout, stderr) */
379 for(int x = 3 ; x < sysconf( _SC_OPEN_MAX ) ; x++ )
380 {
381 close(x);
382 }
383 }
384
385 if( !(mode&N_DAEMON_NO_STD_REDIRECT) )
386 {
387 /* redirect stdin,stdout,stderr to /dev/null */
388 int fd = open("/dev/null",O_RDWR, 0);
389 error = errno ;
390 if (fd != -1)
391 {
392 dup2 (fd, STDIN_FILENO);
393 dup2 (fd, STDOUT_FILENO);
394 dup2 (fd, STDERR_FILENO);
395 if (fd > 2)
396 {
397 close (fd);
398 }
399 }
400 else
401 {
402 n_log( LOG_ERR, "Failed to open /dev/null: %s" , strerror( errno ) );
403 }
404 }
405
406 return TRUE ;
407} /* n_daemonize(...) */
408
409
417pid_t system_nb(const char *command, int *infp, int *outfp) {
418
419 __n_assert( command, return -1 );
420
421 int p_stdin[2] = { -1, -1 };
422 int p_stdout[2] = { -1, -1 };
423 pid_t pid = -1 ;
424
425 if( outfp != NULL )
426 {
427 if( pipe( p_stdin ) != 0 )
428 return -1 ;
429 }
430 if( infp != NULL )
431 {
432 if( pipe( p_stdout ) != 0 )
433 {
434 if( outfp != NULL )
435 {
436 close(p_stdin[0]);
437 close(p_stdin[1]);
438 }
439 return(-1);
440 }
441 }
442
443 pid = fork();
444
445 if (pid < 0)
446 {
447 n_log( LOG_ERR, "Couldn't fork command %s", command );
448 if (outfp != NULL) {
449 close(p_stdin[0]);
450 close(p_stdin[1]);
451 }
452 if (infp != NULL) {
453 close(p_stdout[0]);
454 close(p_stdout[1]);
455 }
456 return pid;
457 }
458 if (pid==0)
459 {
460 if (outfp != NULL)
461 {
462 close(p_stdin[1]);
463 dup2(p_stdin[0], 0);
464 }
465 if (infp != NULL)
466 {
467 close(p_stdout[0]);
468 dup2(p_stdout[1], 1);
469 }
470 execlp("sh", "sh", "-c", command, (char *)NULL);
471 // should never get here
472 int error = errno ;
473 n_log( LOG_ERR , "%s:%d: exec failed: %s", __FILE__, __LINE__, strerror( error ));
474 exit(42);
475 }
476 if (infp != NULL)
477 {
478 close(p_stdout[1]);
479 *infp = p_stdout[0];
480 }
481 if (outfp != NULL)
482 {
483 close(p_stdin[0]);
484 *outfp = p_stdin[1];
485 }
486 return pid;
487} /* system_nb */
488
489#endif /* ifndef __windows__ */
490
496void N_HIDE_STR(char *buf, ...)
497{
498 size_t it = 0;
499 va_list args;
500
501 va_start (args, buf);
502
503 char arg = '\0' ;
504
505 while((arg = va_arg(args, int)))
506 {
507 buf[ it ] = arg ;
508 it ++ ;
509 }
510 buf[ it ] = '\0' ;
511 va_end (args);
512} /* N_HIDE_STR */
513
519char *n_get_file_extension( char path[])
520{
521 char *result = NULL ;
522 int i, n;
523
524 __n_assert(path , return "" );
525
526 n = strlen(path);
527 i = n - 1;
528 while ((i > 0) && (path[i] != '.') && (path[i] != '/') && (path[i] != '\\')) {
529 i--;
530 }
531 if ((i > 0) && (i < n - 1) && (path[i] == '.') && (path[i - 1] != '/') && (path[i - 1] != '\\')) {
532 result = path + i;
533 } else {
534 result = path + n;
535 }
536 return result;
537}
void log_environment(int loglevel)
log environment in syslog
Definition n_common.c:273
#define N_DAEMON_NO_UMASK
daemonize flag: do not call umask( 0 )
Definition n_common.h:506
char * get_prog_name(void)
get current program name
Definition n_common.c:147
#define N_DAEMON_NO_DOUBLE_FORK
daemonize flag: do not double fork
Definition n_common.h:502
void N_HIDE_STR(char *buf,...)
store a hidden version of a string
Definition n_common.c:496
#define N_DAEMON_NO_SIGCHLD_IGN
daemonize flag: do not ignore SIGCHLD
Definition n_common.h:510
#define N_DAEMON_NO_CHDIR
daemonize flag: do not call chdir("/")
Definition n_common.h:508
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:284
#define N_DAEMON_NO_CLOSE
daemonize flag: no descriptor close at all
Definition n_common.h:498
#define N_DAEMON_NO_SIGCHLD_HANDLER
daemonize flag: do not use internal zombie SIGCHLD handler
Definition n_common.h:512
#define N_DAEMON_NO_STD_REDIRECT
daemonize flag: just do not redirect stdin/out/err to /dev/null
Definition n_common.h:500
int get_computer_name(char *computer_name, size_t len)
abort program with a text
Definition n_common.c:60
#define N_DAEMON_NO_SETSID
daemonize flag: do not call setsid
Definition n_common.h:504
void sigchld_handler(int sig)
Handles SIGCHLD issues when forking.
Definition n_common.c:238
pid_t system_nb(const char *command, int *infp, int *outfp)
Non blocking system call.
Definition n_common.c:417
char * n_get_file_extension(char path[])
get extension of path+filename
Definition n_common.c:519
int n_popen(char *cmd, int read_buf_size, void **nstr_output, int *ret)
launch a command abd return output and status
Definition n_common.c:187
char * get_prog_dir(void)
get current program running directory
Definition n_common.c:111
int n_daemonize_ex(int mode)
Daemonize program.
Definition n_common.c:296
void n_abort(char const *format,...)
abort program with a text
Definition n_common.c:40
int sigchld_handler_installer()
install signal SIGCHLD handler to reap zombie processes
Definition n_common.c:253
int n_daemonize(void)
Daemonize program.
Definition n_common.c:286
int file_exist(const char *filename)
test if file exist and if it's readable
Definition n_common.c:94
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:74
#define LOG_DEBUG
debug-level messages
Definition n_log.h:66
#define LOG_ERR
error conditions
Definition n_log.h:58
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:62
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
Definition n_str.c:215
#define nstrprintf_cat(__nstr_var,...)
Macro to quickly allocate and sprintf and cat to a N_STR *.
Definition n_str.h:117
A box including a string and his lenght.
Definition n_str.h:173
Common headers and low-level hugly functions & define.
Generic log system.
N_STR and string function declaration.