vppinfra: add clib_file_get_resolved_basename
[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/unix.h>
41 #include <vppinfra/format.h>
42
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <sys/uio.h>            /* writev */
46 #include <fcntl.h>
47 #include <stdio.h>              /* for sprintf */
48 #include <limits.h>
49
50 __clib_export __thread uword __os_thread_index = 0;
51 __clib_export __thread uword __os_numa_index = 0;
52
53 clib_error_t *
54 clib_file_n_bytes (char *file, uword * result)
55 {
56   struct stat s;
57
58   if (stat (file, &s) < 0)
59     return clib_error_return_unix (0, "stat `%s'", file);
60
61   if (S_ISREG (s.st_mode))
62     *result = s.st_size;
63   else
64     *result = 0;
65
66   return /* no error */ 0;
67 }
68
69 clib_error_t *
70 clib_file_read_contents (char *file, u8 * result, uword n_bytes)
71 {
72   int fd = -1;
73   uword n_done, n_left;
74   clib_error_t *error = 0;
75   u8 *v = result;
76
77   if ((fd = open (file, 0)) < 0)
78     return clib_error_return_unix (0, "open `%s'", file);
79
80   n_left = n_bytes;
81   n_done = 0;
82   while (n_left > 0)
83     {
84       int n_read;
85       if ((n_read = read (fd, v + n_done, n_left)) < 0)
86         {
87           error = clib_error_return_unix (0, "open `%s'", file);
88           goto done;
89         }
90
91       /* End of file. */
92       if (n_read == 0)
93         break;
94
95       n_left -= n_read;
96       n_done += n_read;
97     }
98
99   if (n_left > 0)
100     {
101       error =
102         clib_error_return (0,
103                            " `%s' expected to read %wd bytes; read only %wd",
104                            file, n_bytes, n_bytes - n_left);
105       goto done;
106     }
107
108 done:
109   close (fd);
110   return error;
111 }
112
113 __clib_export clib_error_t *
114 clib_file_contents (char *file, u8 ** result)
115 {
116   uword n_bytes;
117   clib_error_t *error = 0;
118   u8 *v;
119
120   if ((error = clib_file_n_bytes (file, &n_bytes)))
121     return error;
122
123   v = 0;
124   vec_resize (v, n_bytes);
125
126   error = clib_file_read_contents (file, v, n_bytes);
127
128   if (error)
129     vec_free (v);
130   else
131     *result = v;
132
133   return error;
134 }
135
136 __clib_export u8 *
137 clib_file_get_resolved_basename (char *fmt, ...)
138 {
139   va_list va;
140   char *p, buffer[PATH_MAX];
141   u8 *link, *s = 0;
142   int r;
143
144   va_start (va, fmt);
145   link = va_format (0, fmt, &va);
146   va_end (va);
147   vec_add1 (link, 0);
148
149   r = readlink ((char *) link, buffer, sizeof (buffer) - 1);
150   vec_free (link);
151
152   if (r < 1)
153     return 0;
154
155   p = buffer + r - 1;
156   while (p > buffer && p[-1] != '/')
157     p--;
158
159   while (p[0])
160     vec_add1 (s, p++[0]);
161
162   return s;
163 }
164
165 clib_error_t *
166 unix_proc_file_contents (char *file, u8 ** result)
167 {
168   u8 *rv = 0;
169   uword pos;
170   int bytes, fd;
171
172   /* Unfortunately, stat(/proc/XXX) returns zero... */
173   fd = open (file, O_RDONLY);
174
175   if (fd < 0)
176     return clib_error_return_unix (0, "open `%s'", file);
177
178   vec_validate (rv, 4095);
179   pos = 0;
180   while (1)
181     {
182       bytes = read (fd, rv + pos, 4096);
183       if (bytes < 0)
184         {
185           close (fd);
186           vec_free (rv);
187           return clib_error_return_unix (0, "read '%s'", file);
188         }
189
190       if (bytes == 0)
191         {
192           vec_set_len (rv, pos);
193           break;
194         }
195       pos += bytes;
196       vec_validate (rv, pos + 4095);
197     }
198   *result = rv;
199   close (fd);
200   return 0;
201 }
202
203 void os_panic (void) __attribute__ ((weak));
204
205 __clib_export void
206 os_panic (void)
207 {
208   abort ();
209 }
210
211 void os_exit (int) __attribute__ ((weak));
212
213 void
214 os_exit (int code)
215 {
216   exit (code);
217 }
218
219 void os_puts (u8 * string, uword string_length, uword is_error)
220   __attribute__ ((weak));
221
222 void
223 os_puts (u8 * string, uword string_length, uword is_error)
224 {
225   int cpu = os_get_thread_index ();
226   int nthreads = os_get_nthreads ();
227   char buf[64];
228   int fd = is_error ? 2 : 1;
229   struct iovec iovs[2];
230   int n_iovs = 0;
231
232   if (nthreads > 1)
233     {
234       snprintf (buf, sizeof (buf), "%d: ", cpu);
235
236       iovs[n_iovs].iov_base = buf;
237       iovs[n_iovs].iov_len = strlen (buf);
238       n_iovs++;
239     }
240
241   iovs[n_iovs].iov_base = string;
242   iovs[n_iovs].iov_len = string_length;
243   n_iovs++;
244
245   if (writev (fd, iovs, n_iovs) < 0)
246     ;
247 }
248
249 __clib_export __clib_weak void
250 os_out_of_memory (void)
251 {
252   os_panic ();
253 }
254
255 __clib_export __clib_weak uword
256 os_get_nthreads (void)
257 {
258   return 1;
259 }
260
261 /*
262  * fd.io coding-style-patch-verification: ON
263  *
264  * Local Variables:
265  * eval: (c-set-style "gnu")
266  * End:
267  */