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