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