summaryrefslogtreecommitdiff
path: root/lib/rpmug.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rpmug.c')
-rw-r--r--lib/rpmug.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/lib/rpmug.c b/lib/rpmug.c
new file mode 100644
index 000000000..47aa6ccf5
--- /dev/null
+++ b/lib/rpmug.c
@@ -0,0 +1,174 @@
+#include "system.h"
+
+#include <pwd.h>
+#include <grp.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmstring.h>
+
+#include "lib/rpmug.h"
+#include "debug.h"
+
+/*
+ * These really ought to use hash tables. I just made the
+ * guess that most files would be owned by root or the same person/group
+ * who owned the last file. Those two values are cached, everything else
+ * is looked up via getpw() and getgr() functions. If this performs
+ * too poorly I'll have to implement it properly :-(
+ */
+
+int rpmugUid(const char * thisUname, uid_t * uid)
+{
+ static char * lastUname = NULL;
+ static size_t lastUnameLen = 0;
+ static size_t lastUnameAlloced;
+ static uid_t lastUid;
+ struct passwd * pwent;
+ size_t thisUnameLen;
+
+ if (!thisUname) {
+ lastUnameLen = 0;
+ return -1;
+ } else if (rstreq(thisUname, "root")) {
+ *uid = 0;
+ return 0;
+ }
+
+ thisUnameLen = strlen(thisUname);
+ if (lastUname == NULL || thisUnameLen != lastUnameLen ||
+ !rstreq(thisUname, lastUname))
+ {
+ if (lastUnameAlloced < thisUnameLen + 1) {
+ lastUnameAlloced = thisUnameLen + 10;
+ lastUname = xrealloc(lastUname, lastUnameAlloced); /* XXX memory leak */
+ }
+ strcpy(lastUname, thisUname);
+
+ pwent = getpwnam(thisUname);
+ if (pwent == NULL) {
+ /* FIX: shrug */
+ endpwent();
+ pwent = getpwnam(thisUname);
+ if (pwent == NULL) return -1;
+ }
+
+ lastUid = pwent->pw_uid;
+ }
+
+ *uid = lastUid;
+
+ return 0;
+}
+
+int rpmugGid(const char * thisGname, gid_t * gid)
+{
+ static char * lastGname = NULL;
+ static size_t lastGnameLen = 0;
+ static size_t lastGnameAlloced;
+ static gid_t lastGid;
+ size_t thisGnameLen;
+ struct group * grent;
+
+ if (thisGname == NULL) {
+ lastGnameLen = 0;
+ return -1;
+ } else if (rstreq(thisGname, "root")) {
+ *gid = 0;
+ return 0;
+ }
+
+ thisGnameLen = strlen(thisGname);
+ if (lastGname == NULL || thisGnameLen != lastGnameLen ||
+ !rstreq(thisGname, lastGname))
+ {
+ if (lastGnameAlloced < thisGnameLen + 1) {
+ lastGnameAlloced = thisGnameLen + 10;
+ lastGname = xrealloc(lastGname, lastGnameAlloced); /* XXX memory leak */
+ }
+ strcpy(lastGname, thisGname);
+
+ grent = getgrnam(thisGname);
+ if (grent == NULL) {
+ /* FIX: shrug */
+ endgrent();
+ grent = getgrnam(thisGname);
+ if (grent == NULL) {
+ return -1;
+ }
+ }
+ lastGid = grent->gr_gid;
+ }
+
+ *gid = lastGid;
+
+ return 0;
+}
+
+const char * rpmugUname(uid_t uid)
+{
+ static uid_t lastUid = (uid_t) -1;
+ static char * lastUname = NULL;
+ static size_t lastUnameLen = 0;
+
+ if (uid == (uid_t) -1) {
+ lastUid = (uid_t) -1;
+ return NULL;
+ } else if (uid == (uid_t) 0) {
+ return "root";
+ } else if (uid == lastUid) {
+ return lastUname;
+ } else {
+ struct passwd * pwent = getpwuid(uid);
+ size_t len;
+
+ if (pwent == NULL) return NULL;
+
+ lastUid = uid;
+ len = strlen(pwent->pw_name);
+ if (lastUnameLen < len + 1) {
+ lastUnameLen = len + 20;
+ lastUname = xrealloc(lastUname, lastUnameLen);
+ }
+ strcpy(lastUname, pwent->pw_name);
+
+ return lastUname;
+ }
+}
+
+const char * rpmugGname(gid_t gid)
+{
+ static gid_t lastGid = (gid_t) -1;
+ static char * lastGname = NULL;
+ static size_t lastGnameLen = 0;
+
+ if (gid == (gid_t) -1) {
+ lastGid = (gid_t) -1;
+ return NULL;
+ } else if (gid == (gid_t) 0) {
+ return "root";
+ } else if (gid == lastGid) {
+ return lastGname;
+ } else {
+ struct group * grent = getgrgid(gid);
+ size_t len;
+
+ if (grent == NULL) return NULL;
+
+ lastGid = gid;
+ len = strlen(grent->gr_name);
+ if (lastGnameLen < len + 1) {
+ lastGnameLen = len + 20;
+ lastGname = xrealloc(lastGname, lastGnameLen);
+ }
+ strcpy(lastGname, grent->gr_name);
+
+ return lastGname;
+ }
+}
+
+void rpmugFree(void)
+{
+ rpmugUid(NULL, NULL);
+ rpmugGid(NULL, NULL);
+ rpmugUname(-1);
+ rpmugGname(-1);
+}