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