]> git.saurik.com Git - apple/libc.git/blobdiff - gen/utmpx-darwin.c
Libc-1353.11.2.tar.gz
[apple/libc.git] / gen / utmpx-darwin.c
index 312f4e5b1618a9d2da4e75999bff92e75e7a5006..d9e555a79c1444df40864fa9337745d1e2c1a8e9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#ifdef UTMP_COMPAT
 #include <utmp.h>
+#endif /* UTMP_COMPAT */
 #include <utmpx.h>
 #include <utmpx-darwin.h>
+#include <utmpx_thread.h>
 #include <asl.h>
-#include <asl_private.h>
 #include <pwd.h>
 #include <stddef.h>
 
 #include <mach/mach_types.h>
 #include <servers/bootstrap.h>
 #include <pthread.h>
-#include <asl_ipc.h>
 
 #ifdef UTMP_COMPAT
 #include <ttyent.h>
 #endif /* UTMP_COMPAT */
 
+__private_extern__ const char __utx_magic__[UTMPX_MAGIC] = __UTX_MAGIC__;
+
 extern const char _utmpx_vers[];       /* in utmpx.c */
-extern char *asl_list_to_string(asl_search_result_t *, uint32_t *);
-extern asl_search_result_t *asl_list_from_string(const char *);
 
-static void msg2lastlogx(const aslmsg, struct lastlogx *);
-static void msg2utmpx(const aslmsg, struct utmpx *);
-static void utmpx2msg(const struct utmpx *, aslmsg);
+static void msg2lastlogx(asl_object_t, struct lastlogx *);
+static void msg2utmpx(asl_object_t, struct utmpx *);
+static void utmpx2msg(const struct utmpx *, asl_object_t);
 
-static mach_port_t asl_server_port = MACH_PORT_NULL;
-static int pw_size = 0;
+static size_t pw_size = 0;
 
-#define ASL_SERVICE_NAME       "com.apple.system.logger"
 #define FACILITY               "Facility"
 #define WTMP_COUNT             32
 
-/* ASL timeout in milliseconds */
-#define ASL_QUERY_TIMEOUT 4000
+/* ASL timeout in microseconds */
+#define ASL_QUERY_TIMEOUT 4000000
 
 /* indirection causes argument to be substituted before stringification */
 #define STR(x)         __STRING(x)
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#ifdef UTMP_COMPAT
 static char *
 _pwnam_r(const char *user, struct passwd *pw)
 {
@@ -96,6 +99,7 @@ _pwnam_r(const char *user, struct passwd *pw)
        }
        return buf;
 }
+#endif
 
 static char *
 _pwuid_r(uid_t uid, struct passwd *pw)
@@ -137,93 +141,77 @@ getlastlogx(uid_t uid, struct lastlogx *lx)
 struct lastlogx *
 getlastlogxbyname(const char *user, struct lastlogx *lx)
 {
-       aslmsg q;
-       asl_msg_t *m[1];
-       asl_search_result_t s, *l;
-       char *qstr, *res;
-       uint32_t len, reslen, status;
-       uint64_t cmax;
-       security_token_t sec;
-       caddr_t vmstr;
+       asl_object_t m, query, res;
+       size_t cmax;
        struct lastlogx *result = NULL;
-       mach_port_t port;
-
-       if (!user || !*user)
-               return NULL;
 
-       if (bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &port) != KERN_SUCCESS)
-               return NULL;
+       if (!user || !*user) return NULL;
 
        /*
         * We search for the last LASTLOG_FACILITY entry that has the
         * ut_user entry matching the user's name.
         */
-       if ((q = asl_new(ASL_TYPE_QUERY)) == NULL)
-               goto out;
-       asl_set_query(q, FACILITY, LASTLOG_FACILITY, ASL_QUERY_OP_EQUAL);
-       asl_set_query(q, "ut_user", user, ASL_QUERY_OP_EQUAL);
-       m[0] = q;
-       s.count = 1;
-       s.msg = m;
-
-       len = 0;
-       qstr = asl_list_to_string(&s, &len);
-       asl_free(q);
-
-       if (qstr == NULL)
-               goto out;
-
-       /* the server frees this memory */
-       if (vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, len, TRUE) != KERN_SUCCESS) {
-               free(qstr);
-               goto out;
+       m = asl_new(ASL_TYPE_QUERY);
+       if (m == NULL)
+       {
+               return NULL;
+       }
+
+       asl_set_query(m, FACILITY, LASTLOG_FACILITY, ASL_QUERY_OP_EQUAL);
+       asl_set_query(m, "ut_user", user, ASL_QUERY_OP_EQUAL);
+
+       query = asl_new(ASL_TYPE_LIST);
+       if (query == NULL)
+       {
+               asl_release(m);
+               return NULL;
        }
 
-       strcpy(vmstr, qstr);
-       free(qstr);
+       asl_append(query, m);
+       asl_release(m);
 
        res = NULL;
-       reslen = 0;
        cmax = 0;
-       sec.val[0] = -1;
-       sec.val[1] = -1;
-       status = 0;
-
-       _asl_server_query_timeout(port, vmstr, len, -1, 1, 1, ASL_QUERY_TIMEOUT, (caddr_t *)&res, &reslen, &cmax, (int *)&status, &sec);
-
-       if (res == NULL)
-               goto out;
-       l = asl_list_from_string(res);
-       vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
-       q = aslresponse_next(l);
-       if (q == NULL) {
-               aslresponse_free(l);
-               goto out;
+
+       res = asl_match(NULL, query, &cmax, -1, 1, ASL_QUERY_TIMEOUT, ASL_MATCH_DIRECTION_REVERSE);
+       asl_release(query);
+
+       if (res == NULL) return NULL;
+
+       m = asl_next(res);
+
+       if (m == NULL)
+       {
+               asl_release(res);
+               return NULL;
        }
 
-       if (lx == NULL) {
-               if ((lx = (struct lastlogx *)malloc(sizeof(*lx))) == NULL) {
-                       aslresponse_free(l);
-                       goto out;
+       if (lx == NULL)
+       {
+               if ((lx = (struct lastlogx *)malloc(sizeof(*lx))) == NULL)
+               {
+                       asl_release(res);
+                       return NULL;
                }
        }
-       msg2lastlogx(q, lx);
-       aslresponse_free(l);
+
+       msg2lastlogx(m, lx);
+       asl_release(res);
        result = lx;
-out:
-       mach_port_deallocate(mach_task_self(), port);
+
        return result;
 }
 
-#define IGET(e,p)      if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
-                               u->p##_##e = strtol(cp, NULL, 10);
-#define LGET(e,p)      IGET(e,p)
-#define SGET(e,p)      if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
-                               strncpy(u->p##_##e, cp, sizeof(u->p##_##e))
+#define IGET(e,p)      do { if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
+                               u->p##_##e = (int)strtol(cp, NULL, 10); } while (0)
+#define LGET(e,p)      do { if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
+                               u->p##_##e = strtol(cp, NULL, 10); } while (0)
+#define SGET(e,p)      do { if ((cp = asl_get(m, __STRING(ut_##e))) != NULL) \
+                               strncpy(u->p##_##e, cp, sizeof(u->p##_##e)); } while (0)
 
-/* fill in a struct lastlogx from a aslmsg */
+/* fill in a struct lastlogx from an ASL message */
 static void
-msg2lastlogx(const aslmsg m, struct lastlogx *u)
+msg2lastlogx(asl_object_t m, struct lastlogx *u)
 {
        const char *cp;
 
@@ -234,9 +222,9 @@ msg2lastlogx(const aslmsg m, struct lastlogx *u)
        SGET(host, ll);
 }
 
-/* fill in a struct utmpx from a aslmsg */
+/* fill in a struct utmpx from an ASL message */
 static void
-msg2utmpx(const aslmsg m, struct utmpx *u)
+msg2utmpx(asl_object_t m, struct utmpx *u)
 {
        const char *cp;
 
@@ -251,12 +239,12 @@ msg2utmpx(const aslmsg m, struct utmpx *u)
        SGET(host, ut);
 }
 
-/* fill in a aslmsg from a struct utmpx */
+/* fill in an ASL message from a struct utmpx */
 static void
-utmpx2msg(const struct utmpx *u, aslmsg m)
+utmpx2msg(const struct utmpx *u, asl_object_t m)
 {
        char buf[_UTX_HOSTSIZE + 1];    /* the largest string in struct utmpx */
-       char *cp;
+       const char *cp;
 #define ISET(e)        { snprintf(buf, sizeof(buf), "%d", u->e); \
                asl_set(m, #e, buf); }
 #define LSET(e)        { snprintf(buf, sizeof(buf), "%ld", u->e); \
@@ -268,7 +256,7 @@ utmpx2msg(const struct utmpx *u, aslmsg m)
                }
 
        SSET(ut_user);
-       cp = u->ut_id + sizeof(u->ut_id);
+       cp = (char *)u->ut_id + sizeof(u->ut_id);
        while(--cp >= u->ut_id && isprint(*cp)) {}
        if(cp < u->ut_id) {
            SSET(ut_id);
@@ -302,18 +290,18 @@ static const char *utmpx_types[] = {
        "SHUTDOWN_TIME",        /* 11 */
 };
 
-/* send a struct utmpx record using asl */
+/* send a struct utmpx record using ASL */
 __private_extern__ void
 _utmpx_asl(const struct utmpx *u)
 {
-       aslclient asl = asl_open(NULL, NULL, ASL_OPT_NO_REMOTE); /* could be NULL, but still works */
-       aslmsg m;
+       asl_object_t asl = asl_open(NULL, NULL, ASL_OPT_NO_REMOTE);
+       asl_object_t m;
        char msg[64];
 
        if (u->ut_type == EMPTY)
                return;
        if ((m = asl_new(ASL_TYPE_MSG)) == NULL) {
-               asl_close(asl);
+               asl_release(asl);
                return;
        }
        /*
@@ -354,9 +342,8 @@ _utmpx_asl(const struct utmpx *u)
        }
        asl_set(m, ASL_KEY_MSG, msg);
        asl_send(asl, m);
-       asl_free(m);
-       if (asl)
-               asl_close(asl);
+       asl_release(m);
+       asl_release(asl);
 }
 
 #define UT_USER        (1 << 0)
@@ -440,7 +427,7 @@ _utmpx_working_copy(const struct utmpx *utx, struct utmpx *temp, int onlyid)
        /* UT_ID is set only if we already know we need to add it */
        if ((which & UT_ID)) {
                char *cp;
-               int i = sizeof(temp->ut_line);
+               ssize_t i = sizeof(temp->ut_line);
 
                for(cp = temp->ut_line; i > 0 && *cp; i--)
                        cp++;
@@ -490,10 +477,11 @@ static struct {
        get_asl,
        set_asl
 };
+
 static struct {
        uint64_t start;
        int dir;
-       asl_search_result_t *res;
+       asl_object_t res;
        char *str;
        uint32_t len;
        char inited;
@@ -502,7 +490,7 @@ static struct {
 static struct {
        int fd;
        int dir;
-       char file[MAXPATHLEN];
+       char *file;
        off_t off;
        size_t count;
 #ifdef __LP64__
@@ -553,21 +541,27 @@ wtmpxname(const char *fname)
        }
 
        len = strlen(fname);
-       if (len >= sizeof(wtmp_file.file))
+       if (len >= MAXPATHLEN)
                return 0;
 
        /* must end in x! */
        if (fname[len - 1] != 'x')
                return 0;
 
-       (void)strlcpy(wtmp_file.file, fname, sizeof(wtmp_file.file));
-
        if (wtmp_func.which == WTMP_ASL)
                end_asl();
        else if (wtmp_file.fd >= 0) {
                close(wtmp_file.fd);
                wtmp_file.fd = -1;
        }
+
+       if (wtmp_file.file)
+               free(wtmp_file.file);
+
+       wtmp_file.file = strdup(fname);
+       if (wtmp_file.file == NULL)
+               return 0;
+
        wtmp_func.which = WTMP_FILE;
        wtmp_func.end = end_file;
        wtmp_func.get = get_file;
@@ -578,16 +572,14 @@ wtmpxname(const char *fname)
 static void
 end_asl(void)
 {
-       if (wtmp_asl.res) {
-               aslresponse_free(wtmp_asl.res);
+       if (wtmp_asl.res != NULL)
+       {
+               asl_release(wtmp_asl.res);
                wtmp_asl.res = NULL;
        }
+
        wtmp_asl.inited = 0;
        wtmp_asl.done = 0;
-       if (asl_server_port != MACH_PORT_NULL) {
-               mach_port_deallocate(mach_task_self(), asl_server_port);
-               asl_server_port = MACH_PORT_NULL;
-       }
 }
 
 static void
@@ -606,61 +598,25 @@ end_file(void)
 static struct utmpx *
 get_asl(void)
 {
-       aslmsg q;
-       char *res;
-       uint32_t reslen, status;
-       security_token_t sec;
-       caddr_t vmstr;
+       asl_object_t m;
        static struct utmpx utx;
 
-get_asl_repeat:
-       if (wtmp_asl.res) {
-               if ((q = aslresponse_next(wtmp_asl.res)) != NULL) {
-                       msg2utmpx(q, &utx);
-                       return &utx;
-               }
-               aslresponse_free(wtmp_asl.res);
-               wtmp_asl.res = NULL;
-       } else if (!wtmp_asl.inited) {
-               set_asl(-1);
-               if (!wtmp_asl.inited)
-                       return NULL;
-       }
+       if (wtmp_asl.inited == 0) set_asl(-1);
+       if (wtmp_asl.done != 0) return NULL;
 
-       if (wtmp_asl.done)
+       m = asl_next(wtmp_asl.res);
+       if (m == NULL)
+       {
+               asl_release(wtmp_asl.res);
+               wtmp_asl.res = NULL;
+               wtmp_asl.done = 1;
                return NULL;
-
-       if (asl_server_port == MACH_PORT_NULL) {
-               if (bootstrap_look_up(bootstrap_port, ASL_SERVICE_NAME, &asl_server_port) != KERN_SUCCESS) {
-get_asl_done:
-                   wtmp_asl.done = 1;
-                   return NULL;
-               }
        }
 
-       /* the server frees this memory */
-       if (vm_allocate(mach_task_self(), (vm_address_t *)&vmstr, wtmp_asl.len, TRUE) != KERN_SUCCESS)
-               goto get_asl_done;
-
-       /* the search string is defined in set_asl */
-       strcpy(vmstr, wtmp_asl.str);
-
-       res = NULL;
-       reslen = 0;
-       sec.val[0] = -1;
-       sec.val[1] = -1;
-       status = 0;
-
-       _asl_server_query_timeout(asl_server_port, vmstr, wtmp_asl.len, wtmp_asl.start, WTMP_COUNT, wtmp_asl.dir, ASL_QUERY_TIMEOUT, (caddr_t *)&res, &reslen, &wtmp_asl.start, (int *)&status, &sec);
-
-       if (res == NULL)
-               goto get_asl_done;
-       wtmp_asl.res = asl_list_from_string(res);
-       vm_deallocate(mach_task_self(), (vm_address_t)res, reslen);
-       if(!wtmp_asl.res)
-               goto get_asl_done;
-       goto get_asl_repeat;
+       msg2utmpx(m, &utx);
+       return &utx;
 }
+       
 
 static struct utmpx *
 get_file(void)
@@ -735,57 +691,80 @@ get_file_done:
 static void
 _set_dir(int forward)
 {
-       if (forward < 0)
-               return;
-       if (forward) {
-               wtmp_asl.dir = 0;
-               wtmp_asl.start = 0;
-               wtmp_file.dir = 1;
-       } else {
-               wtmp_asl.dir = 1;
+       if (forward < 0) return;
+
+       if (forward == 0)
+       {
+               /* go backward */
+               wtmp_asl.dir = -1;
                wtmp_asl.start = -1;
                wtmp_file.dir = -1;
        }
+       else
+       {
+               /* go forward */
+               wtmp_asl.dir = 1;
+               wtmp_asl.start = 0;
+               wtmp_file.dir = 1;
+       }
 }
 
 static void
 set_asl(int forward)
 {
+       asl_object_t q0, q1, query;
+       size_t cmax;
+
        _set_dir(forward);
-       if (!wtmp_asl.str) {
-               aslmsg q0, q1;
-               asl_msg_t *m[2];
-               asl_search_result_t s;
-
-               /*
-                * Create a search string that matches either UTMPX_FACILITY
-                * or LASTLOG_FACILITY.
-                */
-               if ((q0 = asl_new(ASL_TYPE_QUERY)) == NULL)
-                       return;
-               if ((q1 = asl_new(ASL_TYPE_QUERY)) == NULL) {
-                       asl_free(q0);
-                       return;
-               }
-               asl_set_query(q0, FACILITY, UTMPX_FACILITY, ASL_QUERY_OP_EQUAL);
-               asl_set_query(q1, FACILITY, LASTLOG_FACILITY, ASL_QUERY_OP_EQUAL);
-
-               m[0] = q0;
-               m[1] = q1;
-               s.count = 2;
-               s.msg = m;
-
-               wtmp_asl.len = 0;
-               wtmp_asl.str = asl_list_to_string(&s, &wtmp_asl.len);
-               asl_free(q1);
-               asl_free(q0);
-               if(!wtmp_asl.str)
-                       return;
-       }
-       if (wtmp_asl.res) {
-               aslresponse_free(wtmp_asl.res);
+
+       wtmp_asl.inited = 0;
+       wtmp_asl.done = 0;
+
+       if (wtmp_asl.res != NULL)
+       {
+               asl_release(wtmp_asl.res);
                wtmp_asl.res = NULL;
        }
+
+       /*
+        * Create a search query that matches either UTMPX_FACILITY
+        * or LASTLOG_FACILITY.
+        */
+       q0 = asl_new(ASL_TYPE_QUERY);
+       if (q0 == NULL) return;
+
+       asl_set_query(q0, FACILITY, UTMPX_FACILITY, ASL_QUERY_OP_EQUAL);
+
+       q1 = asl_new(ASL_TYPE_QUERY);
+       if (q1 == NULL)
+       {
+               asl_release(q0);
+               return;
+       }
+
+       asl_set_query(q1, FACILITY, LASTLOG_FACILITY, ASL_QUERY_OP_EQUAL);
+
+       query = asl_new(ASL_TYPE_LIST);
+       if (query == NULL)
+       {
+               asl_release(q0);
+               asl_release(q1);
+               return;
+       }
+
+       asl_append(query, q0);
+       asl_append(query, q1);
+
+       asl_release(q0);
+       asl_release(q1);
+
+       cmax = 0;
+
+       wtmp_asl.res = asl_match(NULL, query, &cmax, wtmp_asl.start, 0, ASL_QUERY_TIMEOUT, wtmp_asl.dir);
+       asl_release(query);
+       
+       if (wtmp_asl.res == NULL) return;
+
        wtmp_asl.inited = 1;
        wtmp_asl.done = 0;
 }
@@ -1170,3 +1149,45 @@ _write_wtmp(const struct utmp *u)
        (void) close(fd);
 }
 #endif /* UTMP_COMPAT */
+
+/*
+ * thread aware SPI
+ */
+utmpx_t
+_openutx(const char *name)
+{
+       struct _utmpx *U;
+
+       if ((U = calloc(1, sizeof(struct _utmpx))) == NULL)
+               return NULL;
+       memcpy(U->magic, __utx_magic__, UTMPX_MAGIC);
+       U->utmpx_mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
+       if (__utmpxname(U, name) == 0) {
+               if (!U->utfile_system)
+                       free(U->utfile);
+               free(U);
+               errno = EINVAL;
+               return NULL;
+       }
+       return (utmpx_t)U;
+}
+
+int
+_closeutx(utmpx_t u)
+{
+       struct _utmpx *U = (struct _utmpx *)u;
+
+       if (!U || memcmp(U->magic, __utx_magic__, UTMPX_MAGIC) != 0) {
+               errno = EINVAL;
+               return -1;
+       }
+       UTMPX_LOCK(U);
+       __endutxent(U);
+       if (!U->utfile_system)
+               free(U->utfile);
+       UTMPX_UNLOCK(U);
+       free(U);
+       return 0;
+}
+
+#pragma clang diagnostic pop