Whamcloud - gitweb
b=13201
[fs/lustre-release.git] / lustre / utils / l_facl.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2004-2006 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #include <stdlib.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <pwd.h>
31 #include <grp.h>
32 #include <stdarg.h>
33 #include <stddef.h>
34 #include <libgen.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 #include <mntent.h>
38
39 #include <lustre/liblustreapi.h>
40 #include <lustre/lustre_user.h>
41
42 #include "obdctl.h"
43
44 static char *progname;
45
46 static void usage(void)
47 {
48         fprintf(stderr,
49                 "\nusage: %s {uid} {gid} {mdtname} {key} {handle} {cmd}\n"
50                 "Normally invoked as an upcall from Lustre, set via:\n"
51                 "  /proc/fs/lustre/mdt/{mdtname}/rmtacl_upcall\n",
52                 progname);
53 }
54
55 static inline void show_result(struct rmtacl_downcall_data *data)
56 {
57         fprintf(stdout, "buflen %d\n\n%s\n", data->add_buflen, data->add_buf);
58 }
59
60 #define MDS_ERR "server processing error"
61
62 static void errlog(char *buf, const char *fmt, ...)
63 {
64         va_list args;
65
66         va_start(args, fmt);
67         vsprintf(buf, fmt, args);
68         va_end(args);
69 }
70
71 static char *get_lustre_mount(void)
72 {
73         FILE *fp;
74         struct mntent *mnt;
75         static char mntpath[PATH_MAX] = "";
76
77         fp = setmntent(MOUNTED, "r");
78         if (fp == NULL) {
79                 fprintf(stderr, "setmntent %s failed: %s\n",
80                         MOUNTED, strerror(errno));
81                 return NULL;
82         }
83
84         while (1) {
85                 mnt = getmntent(fp);
86                 if (!mnt)
87                         break;
88
89                 if (!llapi_is_lustre_mnttype(mnt->mnt_type))
90                         continue;
91
92                 /*
93                  * XXX: The fsname can be configed by user, it should pass into as a parameter.
94                  *      Since we only need one client on mdt node for remote set{get}facl, it is
95                  *      unnecessary to do the accurate match for fsname, but match ":/" temporary.
96                  */
97                 //if (strstr(mnt->mnt_fsname, ":/lustre")) {
98                         /* save the mountpoint dir part */
99                         strncpy(mntpath, mnt->mnt_dir, sizeof(mntpath));
100                         endmntent(fp);
101                         return mntpath;
102                 //}
103         }
104         endmntent(fp);
105
106         return NULL;
107 }
108
109 int main(int argc, char **argv)
110 {
111         struct rmtacl_downcall_data *data;
112         char procname[1024], *buf, *mntpath;
113         int out_pipe[2], err_pipe[2], pid, size, buflen, fd, rc;
114
115         progname = basename(argv[0]);
116
117         if (argc != 7) {
118                 usage();
119                 return 1;
120         }
121
122         size = offsetof(struct rmtacl_downcall_data, add_buf[RMTACL_SIZE_MAX]);
123         data = malloc(size);
124         if (!data) {
125                 fprintf(stderr, "malloc %d failed\n", size);
126                 return 1;
127         }
128         memset(data, 0, size);
129         data->add_magic = RMTACL_DOWNCALL_MAGIC;
130         data->add_key = strtoll(argv[4], NULL, 10);
131         data->add_handle = strtoul(argv[5], NULL, 10);
132         buf = data->add_buf;
133
134         mntpath = get_lustre_mount();
135         if (!mntpath) {
136                 errlog(buf, MDS_ERR"(no lustre mounted on MDS)\n");
137                 goto downcall;
138         }
139
140         /* create pipe */
141         if (pipe(out_pipe) < 0 || pipe(err_pipe) < 0) {
142                 errlog(buf, MDS_ERR"(pipe failed): %s\n", strerror(errno));
143                 goto downcall;
144         }
145
146         if ((pid = fork()) < 0) {
147                 errlog(buf, MDS_ERR"(fork failed): %s\n", strerror(errno));
148                 goto downcall;
149         } else if (pid == 0) {
150                 uid_t uid;
151                 gid_t gid;
152
153                 close(out_pipe[0]);
154                 if (out_pipe[1] != STDOUT_FILENO) {
155                         dup2(out_pipe[1], STDOUT_FILENO);
156                         close(out_pipe[1]);
157                 }
158                 close(err_pipe[0]);
159                 if (err_pipe[1] != STDERR_FILENO) {
160                         dup2(err_pipe[1], STDERR_FILENO);
161                         close(err_pipe[1]);
162                 }
163                 close(STDIN_FILENO);
164
165                 if (chdir(mntpath) < 0) {
166                         fprintf(stderr, "chdir %s failed: %s\n",
167                                 mntpath, strerror(errno));
168                         return 1;
169                 }
170
171                 gid = (gid_t)atoi(argv[2]);
172                 if (gid) {
173                         if (setgid(gid) == -1) {
174                                 fprintf(stderr, "setgid %u failed: %s\n",
175                                         gid, strerror(errno));
176                                 return 1;
177                         }
178                 }
179
180                 uid = (uid_t)atoi(argv[1]);
181                 if (uid) {
182                         if (setuid(uid) == -1) {
183                                 fprintf(stderr, "setuid %u failed: %s\n",
184                                         uid, strerror(errno));
185                                 return 1;
186                         }
187                 }
188
189                 execl("/bin/sh", "sh", "-c", argv[6], NULL);
190                 fprintf(stderr, "execl %s failed: %s\n",
191                         argv[6], strerror(errno));
192
193                 return 1;
194         }
195
196         /* parent process handling */
197         close(out_pipe[1]);
198         close(err_pipe[1]);
199
200         buflen = 0;
201         while (1) {
202                 rc = read(out_pipe[0], buf + buflen, RMTACL_SIZE_MAX - buflen);
203                 if (rc < 0) {
204                         errlog(buf, MDS_ERR"(read failed): %s\n",
205                                strerror(errno));
206                         break;
207                 }
208                 if (rc == 0)
209                         break;
210                 buflen += rc;
211                 if (buflen >= RMTACL_SIZE_MAX)
212                         break;
213         }
214
215         if (buflen != 0) {
216                 wait(&rc);
217                 goto downcall;
218         }
219
220         while (1) {
221                 rc = read(err_pipe[0], buf + buflen, RMTACL_SIZE_MAX - buflen);
222                 if (rc < 0) {
223                         errlog(buf, MDS_ERR"(read failed): %s\n",
224                                strerror(errno));
225                         break;
226                 }
227                 if (rc == 0)
228                         break;
229                 buflen += rc;
230                 if (buflen >= RMTACL_SIZE_MAX)
231                         break;
232         }
233
234         wait(&rc);
235
236 downcall:
237         buf[RMTACL_SIZE_MAX - 1] = 0;
238         data->add_buflen = strlen(buf) + 1;
239         if (getenv("L_FACL_TEST")) {
240                 show_result(data);
241                 free(data);
242                 return 0;
243         }
244
245         snprintf(procname, sizeof(procname),
246                  "/proc/fs/lustre/mdt/%s/rmtacl_info", argv[3]);
247         fd = open(procname, O_WRONLY);
248         if (fd < 0) {
249                 fprintf(stderr, "open %s failed: %s\n",
250                         procname, strerror(errno));
251                 free(data);
252                 return 1;
253         }
254
255         buflen = offsetof(struct rmtacl_downcall_data,
256                           add_buf[data->add_buflen]);
257         rc = write(fd, data, buflen);
258         close(fd);
259         if (rc != buflen) {
260                 fprintf(stderr, "write %s len %d return %d: %s\n",
261                         procname, buflen, rc, strerror(errno));
262                 free(data);
263                 return 1;
264         }
265
266         free(data);
267         return 0;
268 }