blob: 312cc9b5a0aa0eef28d921a50c6c89b3be692591 [file] [log] [blame]
/*
* Copyright (c) 2016 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* pci.c: Linux user space PCI bus management.
*
* Copyright (c) 2008 Eliot Dresselhaus
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <vlib/vlib.h>
#include <vlib/unix/unix.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
clib_error_t *
foreach_directory_file (char *dir_name,
clib_error_t * (*f) (void *arg, u8 * path_name,
u8 * file_name), void *arg,
int scan_dirs)
{
DIR *d;
struct dirent *e;
clib_error_t *error = 0;
u8 *s, *t;
d = opendir (dir_name);
if (!d)
{
if (errno == ENOENT)
return 0;
return clib_error_return_unix (0, "open `%s'", dir_name);
}
s = t = 0;
while (1)
{
e = readdir (d);
if (!e)
break;
if (scan_dirs)
{
if (e->d_type == DT_DIR
&& (!strcmp (e->d_name, ".") || !strcmp (e->d_name, "..")))
continue;
}
else
{
if (e->d_type == DT_DIR)
continue;
}
s = format (s, "%s/%s", dir_name, e->d_name);
t = format (t, "%s", e->d_name);
error = f (arg, s, t);
_vec_len (s) = 0;
_vec_len (t) = 0;
if (error)
break;
}
vec_free (s);
closedir (d);
return error;
}
clib_error_t *
vlib_sysfs_write (char *file_name, char *fmt, ...)
{
u8 *s;
int fd;
clib_error_t *error = 0;
fd = open (file_name, O_WRONLY);
if (fd < 0)
return clib_error_return_unix (0, "open `%s'", file_name);
va_list va;
va_start (va, fmt);
s = va_format (0, fmt, &va);
va_end (va);
if (write (fd, s, vec_len (s)) < 0)
error = clib_error_return_unix (0, "write `%s'", file_name);
vec_free (s);
close (fd);
return error;
}
clib_error_t *
vlib_sysfs_read (char *file_name, char *fmt, ...)
{
unformat_input_t input;
u8 *s = 0;
int fd;
ssize_t sz;
uword result;
fd = open (file_name, O_RDONLY);
if (fd < 0)
return clib_error_return_unix (0, "open `%s'", file_name);
vec_validate (s, 4095);
sz = read (fd, s, vec_len (s));
if (sz < 0)
{
close (fd);
vec_free (s);
return clib_error_return_unix (0, "read `%s'", file_name);
}
_vec_len (s) = sz;
unformat_init_vector (&input, s);
va_list va;
va_start (va, fmt);
result = va_unformat (&input, fmt, &va);
va_end (va);
vec_free (s);
close (fd);
if (result == 0)
return clib_error_return (0, "unformat error");
return 0;
}
u8 *
vlib_sysfs_link_to_name (char *link)
{
char *p, buffer[64];
unformat_input_t in;
u8 *s = 0;
int r;
r = readlink (link, buffer, sizeof (buffer) - 1);
if (r < 0)
return 0;
buffer[r] = 0;
p = strrchr (buffer, '/');
if (!p)
return 0;
unformat_init_string (&in, p + 1, strlen (p + 1));
if (unformat (&in, "%s", &s) != 1)
clib_unix_warning ("no string?");
unformat_free (&in);
return s;
}
int
vlib_sysfs_get_free_hugepages (unsigned int numa_node, int page_size)
{
struct stat sb;
u8 *p = 0;
int r = -1;
p = format (p, "/sys/devices/system/node/node%u%c", numa_node, 0);
if (stat ((char *) p, &sb) == 0)
{
if (S_ISDIR (sb.st_mode) == 0)
goto done;
}
else if (numa_node == 0)
{
vec_reset_length (p);
p = format (p, "/sys/kernel/mm%c", 0);
if (stat ((char *) p, &sb) < 0 || S_ISDIR (sb.st_mode) == 0)
goto done;
}
else
goto done;
_vec_len (p) -= 1;
p = format (p, "/hugepages/hugepages-%ukB/free_hugepages%c", page_size, 0);
vlib_sysfs_read ((char *) p, "%d", &r);
done:
vec_free (p);
return r;
}
clib_error_t *
vlib_unix_recursive_mkdir (char *path)
{
clib_error_t *error = 0;
char *c = 0;
int i = 0;
while (path[i] != 0)
{
if (c && path[i] == '/')
{
vec_add1 (c, 0);
if ((mkdir (c, 0755)) && (errno != EEXIST))
{
error = clib_error_return_unix (0, "mkdir '%s'", c);
goto done;
}
_vec_len (c)--;
}
vec_add1 (c, path[i]);
i++;
}
if ((mkdir (path, 0755)) && (errno != EEXIST))
{
error = clib_error_return_unix (0, "mkdir '%s'", path);
goto done;
}
done:
vec_free (c);
return error;
}
clib_error_t *
vlib_unix_validate_runtime_file (unix_main_t * um,
const char *path, u8 ** full_path)
{
u8 *fp = 0;
char *last_slash = 0;
if (path[0] == '\0')
{
return clib_error_return (0, "path is an empty string");
}
else if (strncmp (path, "../", 3) == 0 || strstr (path, "/../"))
{
return clib_error_return (0, "'..' not allowed in runtime path");
}
else if (path[0] == '/')
{
/* Absolute path. Has to start with runtime directory */
if (strncmp ((char *) um->runtime_dir, path,
strlen ((char *) um->runtime_dir)))
{
return clib_error_return (0,
"file %s is not in runtime directory %s",
path, um->runtime_dir);
}
fp = format (0, "%s%c", path, '\0');
}
else
{
/* Relative path, just append to runtime */
fp = format (0, "%s/%s%c", um->runtime_dir, path, '\0');
}
/* We don't want to create a directory out of the last file */
if ((last_slash = strrchr ((char *) fp, '/')) != NULL)
*last_slash = '\0';
clib_error_t *error = vlib_unix_recursive_mkdir ((char *) fp);
if (last_slash != NULL)
*last_slash = '/';
if (error)
vec_free (fp);
*full_path = fp;
return error;
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/