}
/*
- * 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;
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;
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.
*/
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++] = ':';
+ }
}
}
/*
* 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 */
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;
if (closeret) {
PERROR("closedir");
}
- if (!ret) {
+ if (is_empty) {
DBG3("Attempting rmdir %s", path);
ret = rmdir(path);
}