Introduce run_as for mkdir_recursive
[lttng-tools.git] / lttng-sessiond / utils.c
CommitLineData
8e68d1c8 1/*
996b65c8 2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
1e307fab 3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8e68d1c8 4 *
7272acf5
YB
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; only version 2 of the License.
8e68d1c8 8 *
7272acf5
YB
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
8e68d1c8 13 *
7272acf5
YB
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307, USA.
8e68d1c8
DG
17 */
18
19#define _GNU_SOURCE
20#include <errno.h>
21#include <limits.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
fedf5c6b 25#include <sys/wait.h>
8e68d1c8
DG
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <unistd.h>
29
7272acf5
YB
30#include <lttngerr.h>
31
8e68d1c8
DG
32#include "utils.h"
33
54d01ffb
DG
34/*
35 * Write to writable pipe used to notify a thread.
36 */
37int notify_thread_pipe(int wpipe)
38{
39 int ret;
40
41 ret = write(wpipe, "!", 1);
42 if (ret < 0) {
7272acf5 43 PERROR("write poll pipe");
54d01ffb
DG
44 }
45
46 return ret;
47}
48
b082db07 49/*
050349bb 50 * Return pointer to home directory path using the env variable HOME.
b082db07 51 *
050349bb 52 * No home, NULL is returned.
b082db07
DG
53 */
54const char *get_home_dir(void)
55{
56 return ((const char *) getenv("HOME"));
57}
58
59/*
050349bb 60 * Create recursively directory using the FULL path.
b082db07 61 */
fedf5c6b
MD
62static
63int _mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid)
8e68d1c8 64{
49a1d1ed
MD
65 int ret;
66 char *p, tmp[PATH_MAX];
67 size_t len;
68 mode_t old_umask;
8e68d1c8 69
49a1d1ed 70 ret = snprintf(tmp, sizeof(tmp), "%s", path);
8e68d1c8 71 if (ret < 0) {
7272acf5 72 PERROR("snprintf mkdir");
8e68d1c8
DG
73 goto error;
74 }
75
49a1d1ed
MD
76 len = ret;
77 if (tmp[len - 1] == '/') {
78 tmp[len - 1] = 0;
79 }
8e68d1c8 80
49a1d1ed
MD
81 old_umask = umask(0);
82 for (p = tmp + 1; *p; p++) {
83 if (*p == '/') {
84 *p = 0;
85 ret = mkdir(tmp, mode);
86 if (ret < 0) {
87 if (!(errno == EEXIST)) {
7272acf5 88 PERROR("mkdir recursive");
996b65c8
MD
89 ret = -errno;
90 goto umask_error;
91 }
49a1d1ed
MD
92 }
93 *p = '/';
94 }
95 }
8e68d1c8 96
49a1d1ed 97 ret = mkdir(tmp, mode);
8e68d1c8 98 if (ret < 0) {
7272acf5
YB
99 if (!(errno == EEXIST)) {
100 PERROR("mkdir recursive last piece");
101 ret = -errno;
102 } else {
103 ret = 0;
104 }
8e68d1c8
DG
105 }
106
107umask_error:
108 umask(old_umask);
109error:
49a1d1ed 110 return ret;
8e68d1c8 111}
fedf5c6b
MD
112
113static
114int run_as(int (*cmd)(const char *path, mode_t mode, uid_t uid, gid_t gid),
115 const char *path, mode_t mode, uid_t uid, gid_t gid)
116{
117 int ret = 0;
118 pid_t pid;
119
120 /*
121 * If we are non-root, we can only deal with our own uid.
122 */
123 if (geteuid() != 0) {
124 if (uid != geteuid()) {
125 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
126 uid, geteuid());
127 return -EPERM;
128 }
129 return (*cmd)(path, mode, uid, gid);
130 }
131
132 pid = fork();
133 if (pid > 0) {
134 int status;
135
136 /*
137 * Parent: wait for child to return, in which case the
138 * shared memory map will have been created.
139 */
140 pid = wait(&status);
141 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
142 ret = -1;
143 goto end;
144 }
145 goto end;
146 } else if (pid == 0) {
147 /* Child */
148 setegid(gid);
149 if (ret < 0) {
150 perror("setegid");
151 exit(EXIT_FAILURE);
152 }
153 ret = seteuid(uid);
154 if (ret < 0) {
155 perror("seteuid");
156 exit(EXIT_FAILURE);
157 }
158 ret = (*cmd)(path, mode, uid, gid);
159 if (!ret)
160 exit(EXIT_SUCCESS);
161 else
162 exit(EXIT_FAILURE);
163 } else {
164 return -1;
165 }
166end:
167 return ret;
168}
169
170int mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid)
171{
172 DBG3("mkdir() recursive %s with mode %d for uid %d and gid %d",
173 path, mode, uid, gid);
174 return run_as(_mkdir_recursive, path, mode, uid, gid);
175}
This page took 0.031335 seconds and 4 git commands to generate.