Whamcloud - gitweb
LU-9121 lnet: add show udsp command
[fs/lustre-release.git] / libcfs / libcfs / util / string.c
index e5ef108..ce96090 100644 (file)
  *
  * You should have received a copy of the GNU General Public License
  * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * http://www.gnu.org/licenses/gpl-2.0.html
  *
  * GPL HEADER END
  */
@@ -27,7 +23,7 @@
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2012, 2014, Intel Corporation.
+ * Copyright (c) 2012, 2017, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
+#include <unistd.h>
 #include <libcfs/util/string.h>
 
-/*
- * According manual of strlcpy() and strlcat() the functions should return
- * the total length of the string they tried to create. For strlcpy() that
- * means the length of src. For strlcat() that means the initial length of
- * dst plus the length of src. So, the function strnlen() cannot be used
- * otherwise the return value will be wrong.
- */
-#ifndef HAVE_STRLCPY /* not in glibc for RHEL 5.x, remove when obsolete */
-size_t strlcpy(char *dst, const char *src, size_t size)
-{
-       size_t ret = strlen(src);
-
-       if (size) {
-               size_t len = (ret >= size) ? size - 1 : ret;
-               memcpy(dst, src, len);
-               dst[len] = '\0';
-       }
-       return ret;
-}
-#endif
-
-#ifndef HAVE_STRLCAT /* not in glibc for RHEL 5.x, remove when obsolete */
-size_t strlcat(char *dst, const char *src, size_t size)
-{
-       size_t dsize = strlen(dst);
-       size_t len = strlen(src);
-       size_t ret = dsize + len;
-
-       dst  += dsize;
-       size -= dsize;
-       if (len >= size)
-               len = size-1;
-       memcpy(dst, src, len);
-       dst[len] = '\0';
-       return ret;
-}
-#endif
-
 /**
  * Extracts tokens from strings.
  *
@@ -295,17 +255,17 @@ cfs_expr_list_print(char *buffer, int count, struct cfs_expr_list *expr_list)
                numexprs++;
 
        if (numexprs > 1)
-               i += snprintf(buffer + i, count - i, "[");
+               i += scnprintf(buffer + i, count - i, "[");
 
        list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
                if (j++ != 0)
-                       i += snprintf(buffer + i, count - i, ",");
+                       i += scnprintf(buffer + i, count - i, ",");
                i += cfs_range_expr_print(buffer + i, count - i, expr,
                                          numexprs > 1);
        }
 
        if (numexprs > 1)
-               i += snprintf(buffer + i, count - i, "]");
+               i += scnprintf(buffer + i, count - i, "]");
 
        return i;
 }
@@ -331,11 +291,64 @@ cfs_expr_list_match(__u32 value, struct cfs_expr_list *expr_list)
 }
 
 /**
+ * Convert express list (\a expr_list) to an array of all matched values
+ *
+ * \retval N N is total number of all matched values
+ * \retval 0 if expression list is empty
+ * \retval < 0 for failure
+ */
+int
+cfs_expr_list_values(struct cfs_expr_list *expr_list, int max, __u32 **valpp)
+{
+       struct cfs_range_expr   *expr;
+       __u32                   *val;
+       int                     count = 0;
+       int                     i;
+
+       list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
+               for (i = expr->re_lo; i <= expr->re_hi; i++) {
+                       if (((i - expr->re_lo) % expr->re_stride) == 0)
+                               count++;
+               }
+       }
+
+       if (count == 0) /* empty expression list */
+               return 0;
+
+       if (count > max)
+               return -EINVAL;
+
+       val = calloc(sizeof(val[0]), count);
+       if (val == NULL)
+               return -ENOMEM;
+
+       count = 0;
+       list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
+               for (i = expr->re_lo; i <= expr->re_hi; i++) {
+                       if (((i - expr->re_lo) % expr->re_stride) == 0)
+                               val[count++] = i;
+               }
+       }
+
+       *valpp = val;
+       return count;
+}
+
+void
+cfs_expr_list_values_free(__u32 *values, int num)
+{
+       /* This array is allocated by LIBCFS_ALLOC(), so it shouldn't be freed
+        * by OBD_FREE() if it's called by module other than libcfs & LNet,
+        * otherwise we will see fake memory leak */
+       free(values);
+}
+
+/**
  * Frees cfs_range_expr structures of \a expr_list.
  *
  * \retval none
  */
-static void
+void
 cfs_expr_list_free(struct cfs_expr_list *expr_list)
 {
        while (!list_empty(&expr_list->el_exprs)) {
@@ -431,3 +444,83 @@ cfs_expr_list_free_list(struct list_head *list)
                cfs_expr_list_free(el);
        }
 }
+
+/**
+ * cfs_abs_path() - Get the absolute path of a relative path
+ * @request_path:      The relative path to be resolved
+ * @resolved_path:     Set to the resolved absolute path
+ *
+ * Returns the canonicalized absolute pathname.  This function is a wrapper to
+ * realpath, but will work even if the target file does not exist.  All
+ * directories in the path must exist.
+ *
+ * Return: On success, 0 is returned and resolved_path points to an allocated
+ * string containing the absolute pathname.  On error, errno is set
+ * appropriately, -errno is returned, and resolved_path points to NULL.
+ */
+int cfs_abs_path(const char *request_path, char **resolved_path)
+{
+       char  buf[PATH_MAX + 1] = "";
+       char *path;
+       char *ptr;
+       int len;
+       int rc = 0;
+       const char *fmt;
+
+       path = malloc(sizeof(buf));
+       if (path == NULL)
+               return -ENOMEM;
+
+       if (request_path[0] != '/') {
+               if (getcwd(path, sizeof(buf) - 1) == NULL) {
+                       rc = -errno;
+                       goto out;
+               }
+               len = snprintf(buf, sizeof(buf), "%s/%s", path, request_path);
+               if (len >= sizeof(buf)) {
+                       rc = -ENAMETOOLONG;
+                       goto out;
+               }
+       } else {
+               /* skip duplicate leading '/' */
+               len = snprintf(buf, sizeof(buf), "%s",
+                              request_path + strspn(request_path, "/") - 1);
+               if (len >= sizeof(buf)) {
+                       rc = -ENAMETOOLONG;
+                       goto out;
+               }
+       }
+
+       /* if filename not in root directory, call realpath for parent path */
+       ptr = strrchr(buf, '/');
+       if (ptr != buf) {
+               *ptr = '\0';
+               if (path != realpath(buf, path)) {
+                       rc = -errno;
+                       goto out;
+               }
+               /* add the filename back */
+               len = strlen(path);
+               fmt = (path[len - 1] == '/') ? "%s" : "/%s";
+               len = snprintf(path + len, sizeof(buf) - len, fmt, ptr + 1);
+               if (len >= sizeof(buf) - len) {
+                       rc = -ENAMETOOLONG;
+                       goto out;
+               }
+       } else {
+               len = snprintf(path, sizeof(buf), "%s", buf);
+               if (len >= sizeof(buf)) {
+                       rc = -ENAMETOOLONG;
+                       goto out;
+               }
+       }
+
+out:
+       if (rc == 0) {
+               *resolved_path = path;
+       } else {
+               *resolved_path = NULL;
+               free(path);
+       }
+       return rc;
+}