vppinfra: Add method for getting current executable name
[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 #else
46 #include <sys/sysctl.h>
47 #endif
48
49 #include <sys/stat.h>
50 #include <sys/types.h>
51 #include <sys/syscall.h>
52 #include <sys/uio.h>            /* writev */
53 #include <fcntl.h>
54 #include <stdio.h>              /* for sprintf */
55 #include <limits.h>
56
57 __clib_export __thread uword __os_thread_index = 0;
58 __clib_export __thread uword __os_numa_index = 0;
59
60 clib_error_t *
61 clib_file_n_bytes (char *file, uword * result)
62 {
63   struct stat s;
64
65   if (stat (file, &s) < 0)
66     return clib_error_return_unix (0, "stat `%s'", file);
67
68   if (S_ISREG (s.st_mode))
69     *result = s.st_size;
70   else
71     *result = 0;
72
73   return /* no error */ 0;
74 }
75
76 clib_error_t *
77 clib_file_read_contents (char *file, u8 * result, uword n_bytes)
78 {
79   int fd = -1;
80   uword n_done, n_left;
81   clib_error_t *error = 0;
82   u8 *v = result;
83
84   if ((fd = open (file, 0)) < 0)
85     return clib_error_return_unix (0, "open `%s'", file);
86
87   n_left = n_bytes;
88   n_done = 0;
89   while (n_left > 0)
90     {
91       int n_read;
92       if ((n_read = read (fd, v + n_done, n_left)) < 0)
93         {
94           error = clib_error_return_unix (0, "open `%s'", file);
95           goto done;
96         }
97
98       /* End of file. */
99       if (n_read == 0)
100         break;
101
102       n_left -= n_read;
103       n_done += n_read;
104     }
105
106   if (n_left > 0)
107     {
108       error =
109         clib_error_return (0,
110                            " `%s' expected to read %wd bytes; read only %wd",
111                            file, n_bytes, n_bytes - n_left);
112       goto done;
113     }
114
115 done:
116   close (fd);
117   return error;
118 }
119
120 __clib_export clib_error_t *
121 clib_file_contents (char *file, u8 ** result)
122 {
123   uword n_bytes;
124   clib_error_t *error = 0;
125   u8 *v;
126
127   if ((error = clib_file_n_bytes (file, &n_bytes)))
128     return error;
129
130   v = 0;
131   vec_resize (v, n_bytes);
132
133   error = clib_file_read_contents (file, v, n_bytes);
134
135   if (error)
136     vec_free (v);
137   else
138     *result = v;
139
140   return error;
141 }
142
143 __clib_export u8 *
144 clib_file_get_resolved_basename (char *fmt, ...)
145 {
146   va_list va;
147   char *p, buffer[PATH_MAX];
148   u8 *link, *s = 0;
149   int r;
150
151   va_start (va, fmt);
152   link = va_format (0, fmt, &va);
153   va_end (va);
154   vec_add1 (link, 0);
155
156   r = readlink ((char *) link, buffer, sizeof (buffer) - 1);
157   vec_free (link);
158
159   if (r < 1)
160     return 0;
161
162   buffer[r] = 0;
163   p = buffer + r - 1;
164   while (p > buffer && p[-1] != '/')
165     p--;
166
167   while (p[0])
168     vec_add1 (s, p++[0]);
169
170   vec_add1 (s, 0);
171   return s;
172 }
173
174 clib_error_t *
175 unix_proc_file_contents (char *file, u8 ** result)
176 {
177   u8 *rv = 0;
178   uword pos;
179   int bytes, fd;
180
181   /* Unfortunately, stat(/proc/XXX) returns zero... */
182   fd = open (file, O_RDONLY);
183
184   if (fd < 0)
185     return clib_error_return_unix (0, "open `%s'", file);
186
187   vec_validate (rv, 4095);
188   pos = 0;
189   while (1)
190     {
191       bytes = read (fd, rv + pos, 4096);
192       if (bytes < 0)
193         {
194           close (fd);
195           vec_free (rv);
196           return clib_error_return_unix (0, "read '%s'", file);
197         }
198
199       if (bytes == 0)
200         {
201           vec_set_len (rv, pos);
202           break;
203         }
204       pos += bytes;
205       vec_validate (rv, pos + 4095);
206     }
207   *result = rv;
208   close (fd);
209   return 0;
210 }
211
212 void os_panic (void) __attribute__ ((weak));
213
214 __clib_export void
215 os_panic (void)
216 {
217   abort ();
218 }
219
220 void os_exit (int) __attribute__ ((weak));
221
222 void
223 os_exit (int code)
224 {
225   exit (code);
226 }
227
228 void os_puts (u8 * string, uword string_length, uword is_error)
229   __attribute__ ((weak));
230
231 void
232 os_puts (u8 * string, uword string_length, uword is_error)
233 {
234   int cpu = os_get_thread_index ();
235   int nthreads = os_get_nthreads ();
236   char buf[64];
237   int fd = is_error ? 2 : 1;
238   struct iovec iovs[2];
239   int n_iovs = 0;
240
241   if (nthreads > 1)
242     {
243       snprintf (buf, sizeof (buf), "%d: ", cpu);
244
245       iovs[n_iovs].iov_base = buf;
246       iovs[n_iovs].iov_len = strlen (buf);
247       n_iovs++;
248     }
249
250   iovs[n_iovs].iov_base = string;
251   iovs[n_iovs].iov_len = string_length;
252   n_iovs++;
253
254   if (writev (fd, iovs, n_iovs) < 0)
255     ;
256 }
257
258 __clib_export __clib_weak void
259 os_out_of_memory (void)
260 {
261   os_panic ();
262 }
263
264 __clib_export __clib_weak uword
265 os_get_nthreads (void)
266 {
267   return 1;
268 }
269
270 __clib_export clib_bitmap_t *
271 os_get_online_cpu_core_bitmap ()
272 {
273 #if __linux__
274   return clib_sysfs_read_bitmap ("/sys/devices/system/cpu/online");
275 #else
276   return 0;
277 #endif
278 }
279
280 __clib_export clib_bitmap_t *
281 os_get_cpu_affinity_bitmap (int pid)
282 {
283 #if __linux
284   int index, ret;
285   cpu_set_t cpuset;
286   uword *affinity_cpus;
287
288   clib_bitmap_alloc (affinity_cpus, sizeof (cpu_set_t));
289   clib_bitmap_zero (affinity_cpus);
290
291   __CPU_ZERO_S (sizeof (cpu_set_t), &cpuset);
292
293   ret = syscall (SYS_sched_getaffinity, 0, sizeof (cpu_set_t), &cpuset);
294
295   if (ret < 0)
296     {
297       clib_bitmap_free (affinity_cpus);
298       return 0;
299     }
300
301   for (index = 0; index < sizeof (cpu_set_t); index++)
302     if (__CPU_ISSET_S (index, sizeof (cpu_set_t), &cpuset))
303       clib_bitmap_set (affinity_cpus, index, 1);
304   return affinity_cpus;
305 #else
306   return 0;
307 #endif
308 }
309
310 __clib_export clib_bitmap_t *
311 os_get_online_cpu_node_bitmap ()
312 {
313 #if __linux__
314   return clib_sysfs_read_bitmap ("/sys/devices/system/node/online");
315 #else
316   return 0;
317 #endif
318 }
319 __clib_export clib_bitmap_t *
320 os_get_cpu_on_node_bitmap (int node)
321 {
322 #if __linux__
323   return clib_sysfs_read_bitmap ("/sys/devices/system/node/node%u/cpulist",
324                                  node);
325 #else
326   return 0;
327 #endif
328 }
329
330 __clib_export clib_bitmap_t *
331 os_get_cpu_with_memory_bitmap ()
332 {
333 #if __linux__
334   return clib_sysfs_read_bitmap ("/sys/devices/system/node/has_memory");
335 #else
336   return 0;
337 #endif
338 }
339
340 __clib_export int
341 os_get_cpu_phys_core_id (int cpu_id)
342 {
343 #if __linux
344   int core_id = -1;
345   clib_error_t *err;
346   u8 *p;
347
348   p =
349     format (0, "/sys/devices/system/cpu/cpu%u/topology/core_id%c", cpu_id, 0);
350   err = clib_sysfs_read ((char *) p, "%d", &core_id);
351   vec_free (p);
352   if (err)
353     {
354       clib_error_free (err);
355       return -1;
356     }
357   return core_id;
358 #else
359   return -1;
360 #endif
361 }
362
363 __clib_export u8 *
364 os_get_exec_path ()
365 {
366   u8 *rv = 0;
367 #ifdef __linux__
368   char tmp[PATH_MAX];
369   ssize_t sz = readlink ("/proc/self/exe", tmp, sizeof (tmp));
370
371   if (sz <= 0)
372     return 0;
373 #else
374   char tmp[MAXPATHLEN];
375   int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
376   size_t sz = MAXPATHLEN;
377
378   if (sysctl (mib, 4, tmp, &sz, NULL, 0) == -1)
379     return 0;
380 #endif
381   vec_add (rv, tmp, sz);
382   return rv;
383 }
384
385 /*
386  * fd.io coding-style-patch-verification: ON
387  *
388  * Local Variables:
389  * eval: (c-set-style "gnu")
390  * End:
391  */