Accept uid and gid parameters in utils_mkdir()/utils_mkdir_recursive()
[lttng-tools.git] / src / common / utils.c
index f9e6a99eafeec26afa4c7640f8a8d5a2c64178b1..db2ed8e7d11dee928a6f96be4167a94669f015c6 100644 (file)
@@ -532,12 +532,42 @@ error:
 }
 
 /*
- * Recursively create directory using the given path and mode.
+ * Create directory using the given path and mode.
  *
  * On success, return 0 else a negative error code.
  */
 LTTNG_HIDDEN
-int utils_mkdir_recursive(const char *path, mode_t mode)
+int utils_mkdir(const char *path, mode_t mode, int uid, int gid)
+{
+       int ret;
+
+       if (uid < 0 || gid < 0) {
+               ret = mkdir(path, mode);
+       } else {
+               ret = run_as_mkdir(path, mode, uid, gid);
+       }
+       if (ret < 0) {
+               if (errno != EEXIST) {
+                       PERROR("mkdir %s, uid %d, gid %d", path ? path : "NULL",
+                                       uid, gid);
+               } else {
+                       ret = 0;
+               }
+       }
+
+       return ret;
+}
+
+/*
+ * Internal version of mkdir_recursive. Runs as the current user.
+ * Don't call directly; use utils_mkdir_recursive().
+ *
+ * This function is ominously marked as "unsafe" since it should only
+ * be called by a caller that has transitioned to the uid and gid under which
+ * the directory creation should occur.
+ */
+LTTNG_HIDDEN
+int _utils_mkdir_recursive_unsafe(const char *path, mode_t mode)
 {
        char *p, tmp[PATH_MAX];
        size_t len;
@@ -582,7 +612,7 @@ int utils_mkdir_recursive(const char *path, mode_t mode)
        ret = mkdir(tmp, mode);
        if (ret < 0) {
                if (errno != EEXIST) {
-                       PERROR("mkdir recursive last piece");
+                       PERROR("mkdir recursive last element");
                        ret = -errno;
                } else {
                        ret = 0;
@@ -593,8 +623,34 @@ error:
        return ret;
 }
 
+/*
+ * Recursively create directory using the given path and mode, under the
+ * provided uid and gid.
+ *
+ * On success, return 0 else a negative error code.
+ */
+LTTNG_HIDDEN
+int utils_mkdir_recursive(const char *path, mode_t mode, int uid, int gid)
+{
+       int ret;
+
+       if (uid < 0 || gid < 0) {
+               /* Run as current user. */
+               ret = _utils_mkdir_recursive_unsafe(path, mode);
+       } else {
+               ret = run_as_mkdir_recursive(path, mode, uid, gid);
+       }
+       if (ret < 0) {
+               PERROR("mkdir %s, uid %d, gid %d", path ? path : "NULL",
+                               uid, gid);
+       }
+
+       return ret;
+}
+
 /*
  * Create the stream tracefile on disk.
+ * path is the output parameter. It needs to be PATH_MAX len.
  *
  * Return 0 on success or else a negative value.
  */
@@ -1050,9 +1106,11 @@ char *utils_generate_optstring(const struct option *long_options,
                        break;
                }
 
-               optstring[str_pos++] = (char)long_options[i].val;
-               if (long_options[i].has_arg) {
-                       optstring[str_pos++] = ':';
+               if (long_options[i].val != '\0') {
+                       optstring[str_pos++] = (char) long_options[i].val;
+                       if (long_options[i].has_arg) {
+                               optstring[str_pos++] = ':';
+                       }
                }
        }
 
@@ -1062,13 +1120,13 @@ end:
 
 /*
  * Try to remove a hierarchy of empty directories, recursively. Don't unlink
- * any file.
+ * any file. Try to rmdir any empty directory within the hierarchy.
  */
 LTTNG_HIDDEN
 int utils_recursive_rmdir(const char *path)
 {
        DIR *dir;
-       int dir_fd, ret = 0, closeret;
+       int dir_fd, ret = 0, closeret, is_empty = 1;
        struct dirent *entry;
 
        /* Open directory */
@@ -1098,15 +1156,14 @@ int utils_recursive_rmdir(const char *path)
                                PATH_MAX - strlen(subpath) - 1);
                        strncat(subpath, entry->d_name,
                                PATH_MAX - strlen(subpath) - 1);
-                       ret = utils_recursive_rmdir(subpath);
-                       if (ret) {
-                               goto end;
+                       if (utils_recursive_rmdir(subpath)) {
+                               is_empty = 0;
                        }
                        break;
                }
                case DT_REG:
-                       ret = -EBUSY;
-                       goto end;
+                       is_empty = 0;
+                       break;
                default:
                        ret = -EINVAL;
                        goto end;
@@ -1117,7 +1174,7 @@ end:
        if (closeret) {
                PERROR("closedir");
        }
-       if (!ret) {
+       if (is_empty) {
                DBG3("Attempting rmdir %s", path);
                ret = rmdir(path);
        }
This page took 0.024669 seconds and 4 git commands to generate.