e0591ff4604e424c56bc65577228d9ede7527f59
[vpp.git] / src / vppinfra / unix-misc.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16   Copyright (c) 2005 Eliot Dresselhaus
17
18   Permission is hereby granted, free of charge, to any person obtaining
19   a copy of this software and associated documentation files (the
20   "Software"), to deal in the Software without restriction, including
21   without limitation the rights to use, copy, modify, merge, publish,
22   distribute, sublicense, and/or sell copies of the Software, and to
23   permit persons to whom the Software is furnished to do so, subject to
24   the following conditions:
25
26   The above copyright notice and this permission notice shall be
27   included in all copies or substantial portions of the Software.
28
29   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37
38 #include <vppinfra/error.h>
39 #include <vppinfra/os.h>
40 #include <vppinfra/bitmap.h>
41 #include <vppinfra/unix.h>
42 #include <vppinfra/format.h>
43 #ifdef __linux__
44 #include <vppinfra/linux/sysfs.h>
45 #endif
46
47 #include <sys/stat.h>
48 #include <sys/types.h>
49 #include <sys/uio.h>            /* writev */
50 #include <fcntl.h>
51 #include <stdio.h>              /* for sprintf */
52 #include <limits.h>
53
54 __clib_export __thread uword __os_thread_index = 0;
55 __clib_export __thread uword __os_numa_index = 0;
56
57 clib_error_t *
58 clib_file_n_bytes (char *file, uword * result)
59 {
60   struct stat s;
61
62   if (stat (file, &s) < 0)
63     return clib_error_return_unix (0, "stat `%s'", file);
64
65   if (S_ISREG (s.st_mode))
66     *result = s.st_size;
67   else
68     *result = 0;
69
70   return /* no error */ 0;
71 }
72
73 clib_error_t *
74 clib_file_read_contents (char *file, u8 * result, uword n_bytes)
75 {
76   int fd = -1;
77   uword n_done, n_left;
78   clib_error_t *error = 0;
79   u8 *v = result;
80
81   if ((fd = open (file, 0)) < 0)
82     return clib_error_return_unix (0, "open `%s'", file);
83
84   n_left = n_bytes;
85   n_done = 0;
86   while (n_left > 0)
87     {
88       int n_read;
89       if ((n_read = read (fd, v + n_done, n_left)) < 0)
90         {
91           error = clib_error_return_unix (0, "open `%s'", file);
92           goto done;
93         }
94
95       /* End of file. */
96       if (n_read == 0)
97         break;
98
99       n_left -= n_read;
100       n_done += n_read;
101     }
102
103   if (n_left > 0)
104     {
105       error =
106         clib_error_return (0,
107                            " `%s' expected to read %wd bytes; read only %wd",
108                            file, n_bytes, n_bytes - n_left);
109       goto done;
110     }
111
112 done:
113   close (fd);
114   return error;
115 }
116
117 __clib_export clib_error_t *
118 clib_file_contents (char *file, u8 ** result)
119 {
120   uword n_bytes;
121   clib_error_t *error = 0;
122   u8 *v;
123
124   if ((error = clib_file_n_bytes (file, &n_bytes)))
125     return error;
126
127   v = 0;
128   vec_resize (v, n_bytes);
129
130   error = clib_file_read_contents (file, v, n_bytes);
131
132   if (error)
133     vec_free (v);
134   else
135     *result = v;
136
137   return error;
138 }
139
140 __clib_export u8 *
141 clib_file_get_resolved_basename (char *fmt, ...)
142 {
143   va_list va;
144   char *p, buffer[PATH_MAX];
145   u8 *link, *s = 0;
146   int r;
147
148   va_start (va, fmt);
149   link = va_format (0, fmt, &va);
150   va_end (va);
151   vec_add1 (link, 0);
152
153   r = readlink ((char *) link, buffer, sizeof (buffer) - 1);
154   vec_free (link);
155
156   if (r < 1)
157     return 0;
158
159   buffer[r] = 0;
160   p = buffer + r - 1;
161   while (p > buffer && p[-1] != '/')
162     p--;
163
164   while (p[0])
165     vec_add1 (s, p++[0]);
166
167   vec_add1 (s, 0);
168   return s;
169 }
170
171 clib_error_t *
172 unix_proc_file_contents (char *file, u8 ** result)
173 {
174   u8 *rv = 0;
175   uword pos;
176   int bytes, fd;
177
178   /* Unfortunately, stat(/proc/XXX) returns zero... */
179   fd = open (file, O_RDONLY);
180
181   if (fd < 0)
182     return clib_error_return_unix (0, "open `%s'", file);
183
184   vec_validate (rv, 4095);
185   pos = 0;
186   while (1)
187     {
188       bytes = read (fd, rv + pos, 4096);
189       if (bytes < 0)
190         {
191           close (fd);
192           vec_free (rv);
193           return clib_error_return_unix (0, "read '%s'", file);
194         }
195
196       if (bytes == 0)
197         {
198           vec_set_len (rv, pos);
199           break;
200         }
201       pos += bytes;
202       vec_validate (rv, pos + 4095);
203     }
204   *result = rv;
205   close (fd);
206   return 0;
207 }
208
209 void os_panic (void) __attribute__ ((weak));
210
211 __clib_export void
212 os_panic (void)
213 {
214   abort ();
215 }
216
217 void os_exit (int) __attribute__ ((weak));
218
219 void
220 os_exit (int code)
221 {
222   exit (code);
223 }
224
225 void os_puts (u8 * string, uword string_length, uword is_error)
226   __attribute__ ((weak));
227
228 void
229 os_puts (u8 * string, uword string_length, uword is_error)
230 {
231   int cpu = os_get_thread_index ();
232   int nthreads = os_get_nthreads ();
233   char buf[64];
234   int fd = is_error ? 2 : 1;
235   struct iovec iovs[2];
236   int n_iovs = 0;
237
238   if (nthreads > 1)
239     {
240       snprintf (buf, sizeof (buf), "%d: ", cpu);
241
242       iovs[n_iovs].iov_base = buf;
243       iovs[n_iovs].iov_len = strlen (buf);
244       n_iovs++;
245     }
246
247   iovs[n_iovs].iov_base = string;
248   iovs[n_iovs].iov_len = string_length;
249   n_iovs++;
250
251   if (writev (fd, iovs, n_iovs) < 0)
252     ;
253 }
254
255 __clib_export __clib_weak void
256 os_out_of_memory (void)
257 {
258   os_panic ();
259 }
260
261 __clib_export __clib_weak uword
262 os_get_nthreads (void)
263 {
264   return 1;
265 }
266
267 __clib_export clib_bitmap_t *
268 os_get_online_cpu_core_bitmap ()
269 {
270 #if __linux__
271   return clib_sysfs_read_bitmap ("/sys/devices/system/cpu/online");
272 #else
273   return 0;
274 #endif
275 }
276
277 __clib_export clib_bitmap_t *
278 os_get_online_cpu_node_bitmap ()
279 {
280 #if __linux__
281   return clib_sysfs_read_bitmap ("/sys/devices/system/node/online");
282 #else
283   return 0;
284 #endif
285 }
286 __clib_export clib_bitmap_t *
287 os_get_cpu_on_node_bitmap (int node)
288 {
289 #if __linux__
290   return clib_sysfs_read_bitmap ("/sys/devices/system/node/node%u/cpulist",
291                                  node);
292 #else
293   return 0;
294 #endif
295 }
296
297 __clib_export clib_bitmap_t *
298 os_get_cpu_with_memory_bitmap ()
299 {
300 #if __linux__
301   return clib_sysfs_read_bitmap ("/sys/devices/system/node/has_memory");
302 #else
303   return 0;
304 #endif
305 }
306
307 __clib_export int
308 os_get_cpu_phys_core_id (int cpu_id)
309 {
310 #if __linux
311   int core_id = -1;
312   clib_error_t *err;
313   u8 *p;
314
315   p =
316     format (0, "/sys/devices/system/cpu/cpu%u/topology/core_id%c", cpu_id, 0);
317   err = clib_sysfs_read ((char *) p, "%d", &core_id);
318   vec_free (p);
319   if (err)
320     {
321       clib_error_free (err);
322       return -1;
323     }
324   return core_id;
325 #else
326   return -1;
327 #endif
328 }
329
330 /*
331  * fd.io coding-style-patch-verification: ON
332  *
333  * Local Variables:
334  * eval: (c-set-style "gnu")
335  * End:
336  */