Systemd/src/libudev-util-private.c

243 lines
4.9 KiB
C
Raw Normal View History

/*
* libudev - interface to udev device information
*
2009-08-01 15:39:18 +02:00
* Copyright (C) 2003-2009 Kay Sievers <kay.sievers@vrfy.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
2008-07-30 01:45:23 +02:00
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
2009-07-07 19:30:19 +02:00
#include <sys/param.h>
#include "libudev.h"
#include "libudev-private.h"
static int create_path(struct udev *udev, const char *path, bool selinux)
{
char p[UTIL_PATH_SIZE];
char *pos;
struct stat stats;
int err;
2009-05-20 17:57:52 +02:00
util_strscpy(p, sizeof(p), path);
pos = strrchr(p, '/');
if (pos == NULL)
return 0;
while (pos != p && pos[-1] == '/')
pos--;
if (pos == p)
return 0;
pos[0] = '\0';
dbg(udev, "stat '%s'\n", p);
if (stat(p, &stats) == 0) {
if ((stats.st_mode & S_IFMT) == S_IFDIR)
return 0;
else
return -ENOTDIR;
}
err = util_create_path(udev, p);
if (err != 0)
return err;
dbg(udev, "mkdir '%s'\n", p);
if (selinux)
udev_selinux_setfscreatecon(udev, p, S_IFDIR|0755);
err = mkdir(p, 0755);
if (err != 0) {
err = -errno;
if (err == -EEXIST && stat(p, &stats) == 0) {
if ((stats.st_mode & S_IFMT) == S_IFDIR)
err = 0;
else
err = -ENOTDIR;
}
}
if (selinux)
udev_selinux_resetfscreatecon(udev);
return err;
}
int util_create_path(struct udev *udev, const char *path)
{
return create_path(udev, path, false);
}
int util_create_path_selinux(struct udev *udev, const char *path)
{
return create_path(udev, path, true);
}
int util_delete_path(struct udev *udev, const char *path)
{
char p[UTIL_PATH_SIZE];
char *pos;
int err = 0;
if (path[0] == '/')
while(path[1] == '/')
path++;
2009-08-29 16:17:54 +02:00
util_strscpy(p, sizeof(p), path);
pos = strrchr(p, '/');
if (pos == p || pos == NULL)
return 0;
2010-05-27 15:11:00 +02:00
for (;;) {
*pos = '\0';
pos = strrchr(p, '/');
/* don't remove the last one */
if ((pos == p) || (pos == NULL))
break;
err = rmdir(p);
if (err < 0) {
if (errno == ENOENT)
err = 0;
break;
}
}
return err;
}
uid_t util_lookup_user(struct udev *udev, const char *user)
{
char *endptr;
2011-04-13 01:47:56 +02:00
size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
char buf[buflen];
struct passwd pwbuf;
struct passwd *pw;
uid_t uid;
if (strcmp(user, "root") == 0)
return 0;
2008-11-06 02:56:45 +01:00
uid = strtoul(user, &endptr, 10);
if (endptr[0] == '\0')
return uid;
errno = getpwnam_r(user, &pwbuf, buf, buflen, &pw);
2008-11-06 02:56:45 +01:00
if (pw != NULL)
return pw->pw_uid;
if (errno == 0 || errno == ENOENT || errno == ESRCH)
err(udev, "specified user '%s' unknown\n", user);
else
err(udev, "error resolving user '%s': %m\n", user);
return 0;
}
gid_t util_lookup_group(struct udev *udev, const char *group)
2008-11-06 02:56:45 +01:00
{
char *endptr;
2011-04-13 01:47:56 +02:00
size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
fix util_lookup_group to handle large groups I have recently been getting the above message on fc11 and I have traced it down to a bug in util_lookup_group. As of 145 util_lookup_group reads: gid_t util_lookup_group(struct udev *udev, const char *group) { char *endptr; int buflen = sysconf(_SC_GETGR_R_SIZE_MAX); char buf[buflen]; struct group grbuf; struct group *gr; gid_t gid = 0; if (strcmp(group, "root") == 0) return 0; gid = strtoul(group, &endptr, 10); if (endptr[0] == '\0') return gid; errno = 0; getgrnam_r(group, &grbuf, buf, buflen, &gr); if (gr != NULL) return gr->gr_gid; if (errno == 0 || errno == ENOENT || errno == ESRCH) err(udev, "specified group '%s' unknown\n", group); else err(udev, "error resolving group '%s': %m\n", group); return 0; } The errno value from getgrnam_r here is ERANGE which is documented as "Insufficient buffer space supplied". When I call get getgrnam_r with a large enough buffer everything works. Indicating that the problem is that sysconf is returning a value too small. A quick google search tells me that sysconf(_S_GETGR_R_SIZE_MAX) is documented as: > sysconf(_S_GETGR_R_SIZE_MAX) returns either -1 or a good > suggested starting value for buflen. It does not return the > worst case possible for buflen. In my case I have a group with about 50 users in /etc/group and that is what triggered the problem in udev and caused all of the udevs group lookups to fail. The following patch which dynamically allocates the group member buffer should fix this problem. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2009-08-01 07:26:10 +02:00
char *buf;
2008-11-06 02:56:45 +01:00
struct group grbuf;
struct group *gr;
gid_t gid = 0;
2008-11-06 02:56:45 +01:00
if (strcmp(group, "root") == 0)
return 0;
2008-11-06 02:56:45 +01:00
gid = strtoul(group, &endptr, 10);
if (endptr[0] == '\0')
return gid;
fix util_lookup_group to handle large groups I have recently been getting the above message on fc11 and I have traced it down to a bug in util_lookup_group. As of 145 util_lookup_group reads: gid_t util_lookup_group(struct udev *udev, const char *group) { char *endptr; int buflen = sysconf(_SC_GETGR_R_SIZE_MAX); char buf[buflen]; struct group grbuf; struct group *gr; gid_t gid = 0; if (strcmp(group, "root") == 0) return 0; gid = strtoul(group, &endptr, 10); if (endptr[0] == '\0') return gid; errno = 0; getgrnam_r(group, &grbuf, buf, buflen, &gr); if (gr != NULL) return gr->gr_gid; if (errno == 0 || errno == ENOENT || errno == ESRCH) err(udev, "specified group '%s' unknown\n", group); else err(udev, "error resolving group '%s': %m\n", group); return 0; } The errno value from getgrnam_r here is ERANGE which is documented as "Insufficient buffer space supplied". When I call get getgrnam_r with a large enough buffer everything works. Indicating that the problem is that sysconf is returning a value too small. A quick google search tells me that sysconf(_S_GETGR_R_SIZE_MAX) is documented as: > sysconf(_S_GETGR_R_SIZE_MAX) returns either -1 or a good > suggested starting value for buflen. It does not return the > worst case possible for buflen. In my case I have a group with about 50 users in /etc/group and that is what triggered the problem in udev and caused all of the udevs group lookups to fail. The following patch which dynamically allocates the group member buffer should fix this problem. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2009-08-01 07:26:10 +02:00
buf = NULL;
gid = 0;
for (;;) {
char *newbuf;
newbuf = realloc(buf, buflen);
if (!newbuf)
fix util_lookup_group to handle large groups I have recently been getting the above message on fc11 and I have traced it down to a bug in util_lookup_group. As of 145 util_lookup_group reads: gid_t util_lookup_group(struct udev *udev, const char *group) { char *endptr; int buflen = sysconf(_SC_GETGR_R_SIZE_MAX); char buf[buflen]; struct group grbuf; struct group *gr; gid_t gid = 0; if (strcmp(group, "root") == 0) return 0; gid = strtoul(group, &endptr, 10); if (endptr[0] == '\0') return gid; errno = 0; getgrnam_r(group, &grbuf, buf, buflen, &gr); if (gr != NULL) return gr->gr_gid; if (errno == 0 || errno == ENOENT || errno == ESRCH) err(udev, "specified group '%s' unknown\n", group); else err(udev, "error resolving group '%s': %m\n", group); return 0; } The errno value from getgrnam_r here is ERANGE which is documented as "Insufficient buffer space supplied". When I call get getgrnam_r with a large enough buffer everything works. Indicating that the problem is that sysconf is returning a value too small. A quick google search tells me that sysconf(_S_GETGR_R_SIZE_MAX) is documented as: > sysconf(_S_GETGR_R_SIZE_MAX) returns either -1 or a good > suggested starting value for buflen. It does not return the > worst case possible for buflen. In my case I have a group with about 50 users in /etc/group and that is what triggered the problem in udev and caused all of the udevs group lookups to fail. The following patch which dynamically allocates the group member buffer should fix this problem. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2009-08-01 07:26:10 +02:00
break;
buf = newbuf;
errno = getgrnam_r(group, &grbuf, buf, buflen, &gr);
if (gr != NULL) {
fix util_lookup_group to handle large groups I have recently been getting the above message on fc11 and I have traced it down to a bug in util_lookup_group. As of 145 util_lookup_group reads: gid_t util_lookup_group(struct udev *udev, const char *group) { char *endptr; int buflen = sysconf(_SC_GETGR_R_SIZE_MAX); char buf[buflen]; struct group grbuf; struct group *gr; gid_t gid = 0; if (strcmp(group, "root") == 0) return 0; gid = strtoul(group, &endptr, 10); if (endptr[0] == '\0') return gid; errno = 0; getgrnam_r(group, &grbuf, buf, buflen, &gr); if (gr != NULL) return gr->gr_gid; if (errno == 0 || errno == ENOENT || errno == ESRCH) err(udev, "specified group '%s' unknown\n", group); else err(udev, "error resolving group '%s': %m\n", group); return 0; } The errno value from getgrnam_r here is ERANGE which is documented as "Insufficient buffer space supplied". When I call get getgrnam_r with a large enough buffer everything works. Indicating that the problem is that sysconf is returning a value too small. A quick google search tells me that sysconf(_S_GETGR_R_SIZE_MAX) is documented as: > sysconf(_S_GETGR_R_SIZE_MAX) returns either -1 or a good > suggested starting value for buflen. It does not return the > worst case possible for buflen. In my case I have a group with about 50 users in /etc/group and that is what triggered the problem in udev and caused all of the udevs group lookups to fail. The following patch which dynamically allocates the group member buffer should fix this problem. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2009-08-01 07:26:10 +02:00
gid = gr->gr_gid;
} else if (errno == ERANGE) {
fix util_lookup_group to handle large groups I have recently been getting the above message on fc11 and I have traced it down to a bug in util_lookup_group. As of 145 util_lookup_group reads: gid_t util_lookup_group(struct udev *udev, const char *group) { char *endptr; int buflen = sysconf(_SC_GETGR_R_SIZE_MAX); char buf[buflen]; struct group grbuf; struct group *gr; gid_t gid = 0; if (strcmp(group, "root") == 0) return 0; gid = strtoul(group, &endptr, 10); if (endptr[0] == '\0') return gid; errno = 0; getgrnam_r(group, &grbuf, buf, buflen, &gr); if (gr != NULL) return gr->gr_gid; if (errno == 0 || errno == ENOENT || errno == ESRCH) err(udev, "specified group '%s' unknown\n", group); else err(udev, "error resolving group '%s': %m\n", group); return 0; } The errno value from getgrnam_r here is ERANGE which is documented as "Insufficient buffer space supplied". When I call get getgrnam_r with a large enough buffer everything works. Indicating that the problem is that sysconf is returning a value too small. A quick google search tells me that sysconf(_S_GETGR_R_SIZE_MAX) is documented as: > sysconf(_S_GETGR_R_SIZE_MAX) returns either -1 or a good > suggested starting value for buflen. It does not return the > worst case possible for buflen. In my case I have a group with about 50 users in /etc/group and that is what triggered the problem in udev and caused all of the udevs group lookups to fail. The following patch which dynamically allocates the group member buffer should fix this problem. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2009-08-01 07:26:10 +02:00
buflen *= 2;
continue;
} else if (errno == 0 || errno == ENOENT || errno == ESRCH) {
fix util_lookup_group to handle large groups I have recently been getting the above message on fc11 and I have traced it down to a bug in util_lookup_group. As of 145 util_lookup_group reads: gid_t util_lookup_group(struct udev *udev, const char *group) { char *endptr; int buflen = sysconf(_SC_GETGR_R_SIZE_MAX); char buf[buflen]; struct group grbuf; struct group *gr; gid_t gid = 0; if (strcmp(group, "root") == 0) return 0; gid = strtoul(group, &endptr, 10); if (endptr[0] == '\0') return gid; errno = 0; getgrnam_r(group, &grbuf, buf, buflen, &gr); if (gr != NULL) return gr->gr_gid; if (errno == 0 || errno == ENOENT || errno == ESRCH) err(udev, "specified group '%s' unknown\n", group); else err(udev, "error resolving group '%s': %m\n", group); return 0; } The errno value from getgrnam_r here is ERANGE which is documented as "Insufficient buffer space supplied". When I call get getgrnam_r with a large enough buffer everything works. Indicating that the problem is that sysconf is returning a value too small. A quick google search tells me that sysconf(_S_GETGR_R_SIZE_MAX) is documented as: > sysconf(_S_GETGR_R_SIZE_MAX) returns either -1 or a good > suggested starting value for buflen. It does not return the > worst case possible for buflen. In my case I have a group with about 50 users in /etc/group and that is what triggered the problem in udev and caused all of the udevs group lookups to fail. The following patch which dynamically allocates the group member buffer should fix this problem. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2009-08-01 07:26:10 +02:00
err(udev, "specified group '%s' unknown\n", group);
} else {
fix util_lookup_group to handle large groups I have recently been getting the above message on fc11 and I have traced it down to a bug in util_lookup_group. As of 145 util_lookup_group reads: gid_t util_lookup_group(struct udev *udev, const char *group) { char *endptr; int buflen = sysconf(_SC_GETGR_R_SIZE_MAX); char buf[buflen]; struct group grbuf; struct group *gr; gid_t gid = 0; if (strcmp(group, "root") == 0) return 0; gid = strtoul(group, &endptr, 10); if (endptr[0] == '\0') return gid; errno = 0; getgrnam_r(group, &grbuf, buf, buflen, &gr); if (gr != NULL) return gr->gr_gid; if (errno == 0 || errno == ENOENT || errno == ESRCH) err(udev, "specified group '%s' unknown\n", group); else err(udev, "error resolving group '%s': %m\n", group); return 0; } The errno value from getgrnam_r here is ERANGE which is documented as "Insufficient buffer space supplied". When I call get getgrnam_r with a large enough buffer everything works. Indicating that the problem is that sysconf is returning a value too small. A quick google search tells me that sysconf(_S_GETGR_R_SIZE_MAX) is documented as: > sysconf(_S_GETGR_R_SIZE_MAX) returns either -1 or a good > suggested starting value for buflen. It does not return the > worst case possible for buflen. In my case I have a group with about 50 users in /etc/group and that is what triggered the problem in udev and caused all of the udevs group lookups to fail. The following patch which dynamically allocates the group member buffer should fix this problem. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2009-08-01 07:26:10 +02:00
err(udev, "error resolving group '%s': %m\n", group);
}
fix util_lookup_group to handle large groups I have recently been getting the above message on fc11 and I have traced it down to a bug in util_lookup_group. As of 145 util_lookup_group reads: gid_t util_lookup_group(struct udev *udev, const char *group) { char *endptr; int buflen = sysconf(_SC_GETGR_R_SIZE_MAX); char buf[buflen]; struct group grbuf; struct group *gr; gid_t gid = 0; if (strcmp(group, "root") == 0) return 0; gid = strtoul(group, &endptr, 10); if (endptr[0] == '\0') return gid; errno = 0; getgrnam_r(group, &grbuf, buf, buflen, &gr); if (gr != NULL) return gr->gr_gid; if (errno == 0 || errno == ENOENT || errno == ESRCH) err(udev, "specified group '%s' unknown\n", group); else err(udev, "error resolving group '%s': %m\n", group); return 0; } The errno value from getgrnam_r here is ERANGE which is documented as "Insufficient buffer space supplied". When I call get getgrnam_r with a large enough buffer everything works. Indicating that the problem is that sysconf is returning a value too small. A quick google search tells me that sysconf(_S_GETGR_R_SIZE_MAX) is documented as: > sysconf(_S_GETGR_R_SIZE_MAX) returns either -1 or a good > suggested starting value for buflen. It does not return the > worst case possible for buflen. In my case I have a group with about 50 users in /etc/group and that is what triggered the problem in udev and caused all of the udevs group lookups to fail. The following patch which dynamically allocates the group member buffer should fix this problem. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
2009-08-01 07:26:10 +02:00
break;
}
free(buf);
return gid;
2008-11-06 02:56:45 +01:00
}
2008-10-18 15:25:05 +02:00
2008-10-22 18:03:38 +02:00
/* handle "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */
int util_resolve_subsys_kernel(struct udev *udev, const char *string,
char *result, size_t maxsize, int read_value)
{
char temp[UTIL_PATH_SIZE];
char *subsys;
char *sysname;
struct udev_device *dev;
char *attr;
if (string[0] != '[')
return -1;
2009-05-20 17:57:52 +02:00
util_strscpy(temp, sizeof(temp), string);
2008-10-22 18:03:38 +02:00
subsys = &temp[1];
sysname = strchr(subsys, '/');
if (sysname == NULL)
return -1;
sysname[0] = '\0';
sysname = &sysname[1];
attr = strchr(sysname, ']');
if (attr == NULL)
return -1;
attr[0] = '\0';
attr = &attr[1];
if (attr[0] == '/')
attr = &attr[1];
if (attr[0] == '\0')
attr = NULL;
if (read_value && attr == NULL)
return -1;
dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname);
if (dev == NULL)
return -1;
if (read_value) {
const char *val;
val = udev_device_get_sysattr_value(dev, attr);
if (val != NULL)
2009-05-20 17:57:52 +02:00
util_strscpy(result, maxsize, val);
2008-10-22 18:03:38 +02:00
else
result[0] = '\0';
info(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
} else {
2009-05-20 17:57:52 +02:00
size_t l;
char *s;
s = result;
l = util_strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL);
if (attr != NULL)
util_strpcpyl(&s, l, "/", attr, NULL);
2008-10-22 18:03:38 +02:00
info(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
}
udev_device_unref(dev);
return 0;
}