1 /*
2  * Copyright 2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdlib.h>
8 #include <stdint.h>
9 #include <errno.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <sys/stat.h>
13 #include <string.h>
14 #include <signal.h>
15 #include "bs_tracing.h"
16 #include "bs_types.h"
17 #include "bs_oswrap.h"
18 #include "bs_string.h"
19 
20 #if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE>=200809))
21 /**
22  * Set the handler for the signals listed in <signals[<n>]>,
23  * Normally <signals> will be set to (int[]){SIGTERM, SIGINT}
24  *
25  * In some cases (the program is stuck) we may never actually exit.
26  * Therefore we set SA_RESETHAND: This way, the 2nd time the signal is received
27  * the default handler would be called to terminate the program no matter what.
28  *
29  * Note that SA_RESETHAND requires either _POSIX_C_SOURCE>=200809 or
30  * _XOPEN_SOURCE>=500
31  */
bs_set_sig_term_handler(void (* f)(int),int signals[],int n)32 void bs_set_sig_term_handler(void (*f)(int), int signals[], int n) {
33   struct sigaction act;
34 
35   act.sa_handler = f;
36   sigemptyset(&act.sa_mask);
37 
38   act.sa_flags = SA_RESETHAND;
39 
40   for (int i = 0 ; i < n ; i++) {
41     sigaction(signals[i], &act, NULL);
42   }
43 }
44 #else
bs_set_sig_term_handler(void (* f)(int),int signals[],int n)45 void bs_set_sig_term_handler(void (*f)(int), int signals[], int n) {
46   bs_trace_error_line("Compile with -D_POSIX_C_SOURCE>=200809\n");
47 }
48 #endif
49 
50 #if defined(__linux)
51 /**
52  * Return a process start time (the time the process started after system boot)
53  * in whatever format it is stored in /proc/<pid>/stat field 22
54  * See man proc(5) for more info
55  *
56  * Note that the format of /proc/<pid>/stat is not part of any standard or
57  * necessarily an stable API. But it has been stable in Linux.
58  * In case you are having trouble with this code, you may want to set
59  * DONT_READ_PROC_STAT
60  */
bs_get_process_start_time(long int pid)61 uint64_t bs_get_process_start_time(long int pid) {
62 #if DONT_READ_PROC_STAT
63   return 0;
64 #else
65   char filename[50];
66   FILE *fptr;
67   sprintf(filename, "/proc/%li/stat",pid);
68   fptr = bs_fopen(filename,"r");
69 
70   int c = fgetc(fptr);
71   while(c != ')' && c!= EOF) { //If the executable would have a ")" in its name we'd have a problem.. but nevermind that odd case..
72     c = fgetc(fptr);
73   }
74   int count = 1;
75   while (count!=21) {
76     c = fgetc(fptr);
77     if (c==' ')
78       count++;
79     if (c == EOF)
80       return 0;
81   }
82   long long unsigned int start_time;
83   fscanf(fptr,"%llu", &start_time);
84   fclose(fptr);
85   return start_time;
86 #endif
87 }
88 #endif
89 
90 /**
91  * Wrapper to OS malloc which exits if it cannot allocate mem
92  */
bs_malloc(size_t size)93 void* bs_malloc(size_t size) {
94   void* pointer;
95   pointer = malloc(size);
96   if (pointer == NULL) {
97     bs_trace_error_line("Can't allocate memory\n");
98   }
99   return pointer;
100 }
101 
102 /**
103  * Wrapper to OS aligned alloc which exits if it cannot allocate mem
104  */
bs_aligned_alloc(size_t alignment,size_t size)105 void* bs_aligned_alloc(size_t alignment, size_t size) {
106   void* memptr;
107   if (posix_memalign(&memptr, alignment, size) != 0) {
108     bs_trace_error_line("Can't allocate aligned memory\n");
109   }
110   return memptr;
111 }
112 
113 /**
114  * Wrapper to OS calloc which exits if it cannot allocate mem
115  */
bs_calloc(size_t nmemb,size_t size)116 void* bs_calloc(size_t nmemb, size_t size) {
117   void* pointer;
118   pointer = calloc(nmemb, size);
119   if (pointer == NULL) {
120     bs_trace_error_line("Can't allocate memory\n");
121   }
122   return pointer;
123 }
124 
125 /**
126  * Wrapper to OS realloc which exits if it cannot allocate mem
127  */
bs_realloc(void * ptr,size_t size)128 void* bs_realloc(void *ptr, size_t size) {
129   ptr = realloc(ptr, size);
130   if (ptr == NULL) {
131     bs_trace_error_line("Can't re-allocate memory\n");
132   }
133   return ptr;
134 }
135 
136 /**
137  * Move file pointer to the next line
138  */
bs_skipline(FILE * file)139 void bs_skipline(FILE *file) {
140   char c;
141   while (((c=getc(file)) != EOF ) && c!='\n') { }
142 }
143 
144 /**
145  * like fgets() but doesnt copy the end of line character to the buffer
146  */
bs_readline(char * s,int size,FILE * stream)147 void bs_readline(char *s, int size, FILE *stream){
148   char c;
149   uint i = 0;
150   while ( ( i < size - 1 ) && ( (c=getc(stream)) != EOF ) && c!='\n'){
151     s[i++] =c;
152   }
153   s[i] = 0;
154 }
155 
156 #define NO_FOLDER_WARNING "Can't create or access folder %s\n"
157 #define NO_FILE_WARNING "Cannot open file %s in mode %s\n"
158 
159 /*
160  * Create a folder if it doesn't exist
161  * Accounting for the fact that some other program may be racing to
162  * create it at the same time
163  *
164  * Note: can only create one directory level at a time
165  */
bs_createfolder(const char * folderpath)166 int bs_createfolder(const char* folderpath) {
167   if (access(folderpath, F_OK) == 0) {
168     return 0;
169   }
170   if (errno != ENOENT) {
171     bs_trace_warning_line(NO_FOLDER_WARNING, folderpath);
172     return 1;
173   }
174   if ((mkdir(folderpath ,S_IRWXG | S_IRWXU) != 0) && (access(folderpath, F_OK) != 0)) {
175     bs_trace_warning_line(NO_FOLDER_WARNING, folderpath);
176     return 1;
177   }
178 
179   return 0;
180 }
181 
182 /**
183  * Wrapper to OS fopen which exits if it cannot open the file
184  */
bs_fopen(const char * file_path,const char * open_type)185 FILE* bs_fopen(const char *file_path, const char *open_type) {
186   FILE* file_pointer;
187   file_pointer = fopen(file_path, open_type);
188   if (file_pointer == NULL) {
189     bs_trace_error_line(NO_FILE_WARNING, file_path, open_type);
190   }
191   return file_pointer;
192 }
193