summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--klibc_fixups.c37
-rw-r--r--klibc_fixups.h47
-rw-r--r--udev-add.c37
3 files changed, 119 insertions, 2 deletions
diff --git a/klibc_fixups.c b/klibc_fixups.c
index 927f2f649a..1241eb7d10 100644
--- a/klibc_fixups.c
+++ b/klibc_fixups.c
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <string.h>
#include <ctype.h>
+#include <fcntl.h>
#include <sys/types.h>
#include "klibc_fixups.h"
@@ -32,6 +33,8 @@
#define PW_FILE "/etc/passwd"
#define GR_FILE "/etc/group"
+#define UTMP_FILE "/var/run/utmp"
+
/* return the id of a passwd style line, selected by the users name */
static unsigned long get_id_by_name(const char *uname, const char *dbfile)
@@ -107,4 +110,38 @@ struct group *getgrnam(const char *name)
return &gr;
}
+
+int ufd = -1;
+
+void setutent()
+{
+ if (ufd < 0)
+ ufd = open(UTMP_FILE, O_RDONLY);
+ fcntl(ufd, F_SETFD, FD_CLOEXEC);
+ lseek(ufd, 0, SEEK_SET);
+}
+
+void endutent() {
+ if (ufd < 0)
+ return;
+ close(ufd);
+ ufd = -1;
+}
+
+struct utmp *getutent(void)
+{
+ static struct utmp utmp;
+ int retval;
+
+ if (ufd < 0) {
+ setutent();
+ if (ufd < 0)
+ return NULL;
+ }
+ retval = read(ufd, &utmp, sizeof(struct utmp));
+ if (retval < 1)
+ return NULL;
+ return &utmp;
+}
+
#endif
diff --git a/klibc_fixups.h b/klibc_fixups.h
index 19bfd51caa..f6c91cdd94 100644
--- a/klibc_fixups.h
+++ b/klibc_fixups.h
@@ -1,7 +1,7 @@
#ifdef __KLIBC__
#ifndef KLIBC_FIXUPS_H
-#define KLIBC_FIXUPS_H
+#define KLIBC_FIXUPS_H
struct passwd {
char *pw_name; /* user name */
@@ -23,6 +23,49 @@ struct group {
struct passwd *getpwnam(const char *name);
struct group *getgrnam(const char *name);
-#endif
+#define UT_LINESIZE 32
+#define UT_NAMESIZE 32
+#define UT_HOSTSIZE 256
+#define USER_PROCESS 7 /* normal process */
+#define ut_time ut_tv.tv_sec
+
+
+extern int ufd;
+
+struct exit_status {
+ short int e_termination; /* process termination status */
+ short int e_exit; /* process exit status */
+};
+
+struct utmp
+{
+ short int ut_type; /* type of login */
+ pid_t ut_pid; /* pid of login process */
+ char ut_line[UT_LINESIZE]; /* devicename */
+ char ut_id[4]; /* Inittab id */
+ char ut_user[UT_NAMESIZE]; /* username */
+ char ut_host[UT_HOSTSIZE]; /* hostname for remote login */
+ struct exit_status ut_exit; /* exit status of a process marked as DEAD_PROCESS */
+ /* The ut_session and ut_tv fields must be the same size for 32 and 64-bit */
+#if __WORDSIZE == 64 && defined __WORDSIZE_COMPAT32
+ int32_t ut_session; /* sid used for windowing */
+ struct {
+ int32_t tv_sec; /* seconds */
+ int32_t tv_usec; /* microseconds */
+ } ut_tv;
+#else
+ long int ut_session;
+ struct timeval ut_tv;
#endif
+ int32_t ut_addr_v6[4]; /* internet address of remote host */
+ char __unused[20]; /* reserved for future use */
+};
+
+struct utmp *getutent(void);
+void setutent(void);
+void endutent(void);
+
+
+#endif /* KLIBC_FIXUPS_H */
+#endif /* __KLIBC__ */
diff --git a/udev-add.c b/udev-add.c
index 3a72c544b8..19196bec54 100644
--- a/udev-add.c
+++ b/udev-add.c
@@ -32,6 +32,7 @@
#include <grp.h>
#ifndef __KLIBC__
#include <pwd.h>
+#include <utmp.h>
#endif
#include "libsysfs/sysfs/libsysfs.h"
@@ -44,6 +45,8 @@
#include "udevdb.h"
#include "klibc_fixups.h"
+#define LOCAL_USER "$local"
+
/*
* Right now the major/minor of a device is stored in a file called
* "dev" in sysfs.
@@ -132,6 +135,37 @@ static int make_node(char *filename, int major, int minor, unsigned int mode, ui
return 0;
}
+/* get the local logged in user */
+static void set_to_local_user(char *user)
+{
+ struct utmp *u;
+ time_t recent = 0;
+
+ strnfieldcpy(user, default_owner_str, OWNER_SIZE);
+ setutent();
+ while (1) {
+ u = getutent();
+ if (u == NULL)
+ break;
+
+ /* is this a user login ? */
+ if (u->ut_type != USER_PROCESS)
+ continue;
+
+ /* is this a local login ? */
+ if (strcmp(u->ut_host, ""))
+ continue;
+
+ if (u->ut_time > recent) {
+ recent = u->ut_time;
+ strfieldcpy(user, u->ut_user);
+ dbg("local user is '%s'", user);
+ break;
+ }
+ }
+ endutent();
+}
+
static int create_node(struct udevice *dev, int fake)
{
struct stat stats;
@@ -175,6 +209,9 @@ static int create_node(struct udevice *dev, int fake)
if (endptr[0] == '\0')
uid = (uid_t) id;
else {
+ if (strncmp(dev->owner, LOCAL_USER, sizeof(LOCAL_USER)) == 0)
+ set_to_local_user(dev->owner);
+
struct passwd *pw = getpwnam(dev->owner);
if (pw == NULL)
dbg("specified user unknown '%s'", dev->owner);