1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
52 #include <lustre/lustre_user.h>
54 #define CHECK_DURATION_START \
56 time_t __check_start = time(NULL)
58 #define CHECK_DURATION_END(str, secs) \
59 if (time(NULL) > __check_start + (secs)) \
60 errlog("LONG OP %s: %d elapsed, %d expected\n", str, \
61 time(NULL) - __check_start, secs); \
64 void usage(FILE *out, const char *progname)
66 fprintf(out, "\nusage: %s [-v] {-d | <mdsname>} <uid>\n"
68 "Normally invoked as an upcall from Lustre, set via:\n"
69 " /proc/fs/lustre/mds/{mdsname}/group_upcall\n"
70 "\t-d: debug, print values to stdout instead of Lustre\n"
71 "\t-s: sleep, mlock memory in core and sleep forever\n"
72 "\t-v: verbose, log start/stop to syslog\n",
76 static int compare_u32(const void *v1, const void *v2)
78 return (*(__u32 *)v1 - *(__u32 *)v2);
81 static void errlog(const char *fmt, ...)
87 vsyslog(LOG_NOTICE, fmt, arg);
90 vfprintf(stderr, fmt, carg);
94 int get_groups_local(struct mds_grp_downcall_data **grp)
96 struct mds_grp_downcall_data *param;
97 int i, maxgroups, size, saved_errno;
101 CHECK_DURATION_START;
102 pw = getpwuid((*grp)->mgd_uid);
104 CHECK_DURATION_END("getpwuid", 2);
106 errlog("no such user %u\n", (*grp)->mgd_uid);
107 (*grp)->mgd_err = saved_errno ? saved_errno : EIDRM;
108 return sizeof(*param);
110 (*grp)->mgd_gid = pw->pw_gid;
112 maxgroups = sysconf(_SC_NGROUPS_MAX);
113 size = offsetof(struct mds_grp_downcall_data, mgd_groups[maxgroups]);
114 param = malloc(size);
116 errlog("fail to alloc %d bytes for uid %u with %d groups\n",
117 size, (*grp)->mgd_uid, maxgroups);
118 return sizeof(*param);
121 memcpy(param, *grp, sizeof(*param));
122 param->mgd_groups[param->mgd_ngroups++] = pw->pw_gid;
124 CHECK_DURATION_START;
125 while ((gr = getgrent())) {
126 if (gr->gr_gid == pw->pw_gid)
130 for (i = 0; gr->gr_mem[i]; i++) {
131 if (strcmp(gr->gr_mem[i], pw->pw_name) == 0) {
132 param->mgd_groups[param->mgd_ngroups++] =
137 if (param->mgd_ngroups == maxgroups)
140 CHECK_DURATION_END("getgrent loop", 3);
142 qsort(param->mgd_groups, param->mgd_ngroups,
143 sizeof(param->mgd_groups[0]), compare_u32);
148 /* Note that we need to make the downcall regardless of error, so that the
149 * MDS doesn't continue to wait on the upcall. */
150 int main(int argc, char **argv)
153 int debug = 0, sleepy = 0, verbose = 0, print_usage = 0;
155 struct mds_grp_downcall_data sparam = { MDS_GRP_DOWNCALL_MAGIC };
156 struct mds_grp_downcall_data *param = &sparam;
157 char pathname[1024], *end, *progname, *mdsname = NULL;
159 progname = strrchr(argv[0], '/');
160 if (progname == NULL)
165 if (strstr(progname, "verbose"))
168 openlog(progname, LOG_PERROR, LOG_AUTHPRIV);
171 while ((c = getopt(argc, argv, "dhsv")) != -1) {
183 errlog("bad parameter '%c'\n", optopt);
191 /* sleep has 0 param, debug has 1 param, upcall has 2 param */
192 if (!sleepy && optind + !sleepy + !debug != argc)
196 usage(stderr, progname);
197 return print_usage > 1 ? EINVAL : 0;
201 param->mgd_uid = strtoul(argv[optind + !debug], &end, 0);
203 errlog("invalid uid '%s'", argv[optind + !debug]);
204 usage(stderr, progname);
208 mdsname = argv[optind];
214 syslog(LOG_DEBUG, "starting l_getgroups(pid %u) for uid %u\n",
215 mypid, param->mgd_uid);
217 CHECK_DURATION_START;
218 size = get_groups_local(¶m);
219 CHECK_DURATION_END("get_groups_local", 10);
222 if (param->mgd_err) {
223 if (param->mgd_err != ENXIO)
224 errlog("error getting uid %d groups: %s\n",
225 param->mgd_uid,strerror(param->mgd_err));
228 printf("uid=%d gid=", param->mgd_uid);
229 for (i = 0; i < param->mgd_ngroups; i++)
230 printf("%s%d", i > 0 ? "," : "",
231 param->mgd_groups[i]);
236 rc = mlockall(MCL_CURRENT);
237 errlog("%s all pages in RAM (pid %u): rc %d\n",
238 rc ? "failed to lock" : "locked", mypid, rc);
241 snprintf(pathname, 1024, "/proc/fs/lustre/mds/%s/group_info",
243 CHECK_DURATION_START;
244 fd = open(pathname, O_WRONLY);
246 errlog("can't open device %s: %s\n",
247 pathname, strerror(errno));
250 rc = write(fd, param, size);
256 CHECK_DURATION_END("group_info write", 1);
259 syslog(LOG_DEBUG, "ending l_getgroups(pid %u) for uid %u\n",
260 mypid, param->mgd_uid);