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