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