Whamcloud - gitweb
- debug info to investigate a source of small writes
[fs/lustre-release.git] / lustre / utils / lsd_upcall.c
index 8b55d45..e1fbf5b 100644 (file)
 #include <fcntl.h>
 #include <pwd.h>
 #include <grp.h>
+#include <syslog.h>
 
 #include <liblustre.h>
 #include <linux/lustre_idl.h>
 #include <linux/obd.h>
 #include <linux/lustre_mds.h>
 
+#include <portals/types.h>
+#include <portals/ptlctl.h>
+
 /*
  * return:
  *  0:      fail to insert (found identical)
@@ -76,7 +80,7 @@ int get_groups_local(uid_t uid, gid_t *gid, int *ngroups, gid_t **groups)
 
         pw = getpwuid(uid);
         if (!pw)
-                return -errno;
+                return -ENOENT;
 
         *gid = pw->pw_gid;
 
@@ -97,34 +101,335 @@ int get_groups_local(uid_t uid, gid_t *gid, int *ngroups, gid_t **groups)
         return 0;
 }
 
-int main (int argc, char **argv)
+#define LINEBUF_SIZE    (1024)
+static char linebuf[LINEBUF_SIZE];
+
+int readline(FILE *fp, char *buf, int bufsize)
 {
-        char   *pathname = "/proc/fs/lustre/mds/lsd_downcall";
-        int     fd, rc;
-        struct lsd_downcall_args ioc_data;
+        char *p = buf;
+        int i = 0;
+
+        if (fgets(buf, bufsize, fp) == NULL)
+                return -1;
+
+        while (*p) {
+                if (*p == '#') {
+                        *p = '\0';
+                        break;
+                }
+                if (*p == '\n') {
+                        *p = '\0';
+                        break;
+                }
+                i++;
+                p++;
+        }
+
+        return i;
+}
+
+#define IS_SPACE(c) ((c) == ' ' || (c) == '\t')
+
+void remove_space_head(char **buf)
+{
+        char *p = *buf;
+
+        while (IS_SPACE(*p))
+                p++;
+
+        *buf = p;
+}
 
-        if (argc != 2) {
-                printf("bad parameter\n");
-                return -EINVAL;
+void remove_space_tail(char **buf)
+{
+        char *p = *buf;
+        char *spc = NULL;
+
+        while (*p) {
+                if (!IS_SPACE(*p)) {
+                        if (spc) spc = NULL;
+                } else
+                        if (!spc) spc = p;
+                p++;
         }
 
-        ioc_data.uid = atoi(argv[1]);
+        if (spc)
+                *spc = '\0';
+}
+
+int get_next_uid_range(char **buf, uid_t *uid_range)
+{
+        char *p = *buf;
+        char *comma, *sub;
+
+        remove_space_head(&p);
+        if (strlen(p) == 0)
+                return -1;
+
+        comma = strchr(p, ',');
+        if (comma) {
+                *comma = '\0';
+                *buf = comma + 1;
+        } else
+                *buf = p + strlen(p);
+
+        sub = strchr(p, '-');
+        if (!sub) {
+                uid_range[0] = uid_range[1] = atoi(p);
+        } else {
+                *sub++ = '\0';
+                uid_range[0] = atoi(p);
+                uid_range[1] = atoi(sub);
+        }
+
+        return 0;
+}
+
+/*
+ * return 0: ok
+ */
+int remove_bracket(char **buf)
+{
+        char *p = *buf;
+        char *p2;
+
+        if (*p++ != '[')
+                return -1;
+
+        p2 = strchr(p, ']');
+        if (!p2)
+                return -1;
+
+        *p2++ = '\0';
+        while (*p2) {
+                if (*p2 != ' ' && *p2 != '\t')
+                        return -1;
+                p2++;
+        }
+
+        remove_space_tail(&p);
+        *buf = p;
+        return 0;
+}
+
+/* return 0: found a match */
+int search_uid(FILE *fp, uid_t uid)
+{
+        char *p;
+        uid_t uid_range[2];
+        int rc;
+
+        while (1) {
+                rc = readline(fp, linebuf, LINEBUF_SIZE);
+                if (rc < 0)
+                        return rc;
+                if (rc == 0)
+                        continue;
+
+                p = linebuf;
+                if (remove_bracket(&p))
+                        continue;
+
+                while (get_next_uid_range(&p, uid_range) == 0) {
+                        if (uid >= uid_range[0] && uid <= uid_range[1]) {
+                                return 0;
+                        }
+                }
+                continue;
+        }
+}
+
+static struct {
+        char   *name;
+        __u32   bit;
+} perm_types[] =  {
+        {"setuid",      LSD_PERM_SETUID},
+        {"setgid",      LSD_PERM_SETGID},
+        {"setgrp",      LSD_PERM_SETGRP},
+};
+#define N_PERM_TYPES    (3)
+
+int parse_perm(__u32 *perm, char *str)
+{
+        char *p = str;
+        char *comma;
+        int i;
+
+        *perm = 0;
+
+        while (1) {
+                p = str;
+                comma = strchr(str, ',');
+                if (comma) {
+                        *comma = '\0';
+                        str = comma + 1;
+                }
 
-        fd = open(pathname, O_WRONLY);
-        if (fd < 0) {
-                rc = -errno;
-                printf("can't open device %s\n", pathname);
+                for (i = 0; i < N_PERM_TYPES; i++) {
+                        if (!strcasecmp(p, perm_types[i].name)) {
+                                *perm |= perm_types[i].bit;
+                                break;
+                        }
+                }
+
+                if (i >= N_PERM_TYPES) {
+                        printf("unkown perm type: %s\n", p);
+                        return -1;
+                }
+
+                if (!comma)
+                        break;
+        }
+        return 0;
+}
+
+int parse_nid(ptl_nid_t *nidp, char *nid_str)
+{
+        if (!strcmp(nid_str, "*")) {
+                *nidp = PTL_NID_ANY;
+                return 0;
+        }
+
+        return ptl_parse_nid(nidp, nid_str);
+}
+
+int get_one_perm(FILE *fp, struct lsd_permission *perm)
+{
+        char nid_str[256], perm_str[256];
+        int rc;
+
+again:
+        rc = readline(fp, linebuf, LINEBUF_SIZE);
+        if (rc < 0)
                 return rc;
+        if (rc == 0)
+                goto again;
+
+        rc = sscanf(linebuf, "%s %s", nid_str, perm_str);
+        if (rc != 2)
+                return -1;
+
+        if (parse_nid(&perm->nid, nid_str))
+                return -1;
+
+        if (parse_perm(&perm->perm, perm_str))
+                return -1;
+
+        perm->netid = 0;
+        return 0;
+}
+
+#define MAX_PERMS       (50)
+
+int get_perms(FILE *fp, uid_t uid, int *nperms, struct lsd_permission **perms)
+{
+        static struct lsd_permission _perms[MAX_PERMS];
+
+        if (search_uid(fp, uid))
+                return -1;
+
+        *nperms = 0;
+        while (*nperms < MAX_PERMS) {
+                if (get_one_perm(fp, &_perms[*nperms]))
+                        break;
+                (*nperms)++;
+        }
+        *perms = _perms;
+        return 0;
+}
+
+void show_result(struct lsd_downcall_args *dc)
+{
+        int i;
+
+        printf("err: %d, uid %u, gid %d\n"
+               "ngroups: %d\n",
+               dc->err, dc->uid, dc->gid, dc->ngroups);
+        for (i = 0; i < dc->ngroups; i++)
+                printf("\t%d\n", dc->groups[i]);
+
+        printf("nperms: %d\n", dc->nperms);
+        for (i = 0; i < dc->nperms; i++)
+                printf("\t: netid %u, nid "LPX64", bits %x\n", i,
+                        dc->perms[i].nid, dc->perms[i].perm);
+}
+
+#define log_msg(testing, fmt, args...)                  \
+        {                                               \
+                if (testing)                            \
+                        printf(fmt, ## args);           \
+                else                                    \
+                        syslog(LOG_ERR, fmt, ## args);  \
         }
 
+void usage(char *prog)
+{
+        printf("Usage: %s [-t] uid\n", prog);
+        exit(1);
+}
+
+int main (int argc, char **argv)
+{
+        char   *dc_name = "/proc/fs/lustre/mds/lsd_downcall";
+        int     dc_fd;
+        char   *conf_name = "/etc/lustre/lsd.conf";
+        FILE   *conf_fp;
+        struct lsd_downcall_args ioc_data;
+        extern char *optarg;
+        int     opt, testing = 0, rc;
+
+        while ((opt = getopt(argc, argv, "t")) != -1) {
+                switch (opt) {
+                case 't':
+                        testing = 1;
+                        break;
+                default:
+                        usage(argv[0]);
+                }
+        }
+
+        if (optind >= argc)
+                usage(argv[0]);
+
+        memset(&ioc_data, 0, sizeof(ioc_data));
+        ioc_data.uid = atoi(argv[optind]);
+
+        /* read user/group database */
         ioc_data.err = get_groups_local(ioc_data.uid, &ioc_data.gid,
-                                        &ioc_data.ngroups, &ioc_data.groups);
+                                        (int *)&ioc_data.ngroups,
+                                        &ioc_data.groups);
+        if (ioc_data.err)
+                goto do_downcall;
 
-        /* FIXME get these from config file */
-        ioc_data.allow_setuid = 1;
-        ioc_data.allow_setgid = 1;
-        ioc_data.allow_setgrp = 1;
+        /* read lsd config database */
+        conf_fp = fopen(conf_name, "r");
+        if (conf_fp) {
+                get_perms(conf_fp, ioc_data.uid,
+                          (int *)&ioc_data.nperms,
+                          &ioc_data.perms);
+                fclose(conf_fp);
+        }
+
+do_downcall:
+        if (testing) {
+                show_result(&ioc_data);
+                return 0;
+        } else {
+                dc_fd = open(dc_name, O_WRONLY);
+                if (dc_fd < 0) {
+                        log_msg(testing, "can't open device %s: %s\n",
+                                dc_name, strerror(errno));
+
+                        return -errno;
+                }
 
-        rc = write(fd, &ioc_data, sizeof(ioc_data));
-        return (rc != sizeof(ioc_data));
+                rc = write(dc_fd, &ioc_data, sizeof(ioc_data));
+                if (rc != sizeof(ioc_data)) {
+                        log_msg(testing, "partial write ret %d: %s\n",
+                                rc, strerror(errno));
+                        return 1;
+                }
+
+                return 0;
+        }
 }