Fix DEBUG_THREADS when lock is acquired in __constructor__
[asterisk/asterisk.git] / main / utils.c
index 04f6127..e2c5e2c 100644 (file)
@@ -34,12 +34,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <ctype.h>
 #include <fcntl.h>
 #include <sys/stat.h>
-#include <sys/stat.h>
 #include <sys/syscall.h>
 #include <unistd.h>
-#if defined(HAVE_CRYPT_R)
-#include <crypt.h>
-#endif
 #if defined(__APPLE__)
 #include <mach/mach.h>
 #elif defined(HAVE_SYS_THR_H)
@@ -601,6 +597,8 @@ struct thr_lock_info {
                enum ast_lock_type type;
                /*! This thread is waiting on this lock */
                int pending:2;
+               /*! A condition has suspended this lock */
+               int suspended:1;
 #ifdef HAVE_BKTR
                struct ast_bt *backtrace;
 #endif
@@ -787,6 +785,60 @@ int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, in
        return 0;
 }
 
+void ast_suspend_lock_info(void *lock_addr)
+{
+       struct thr_lock_info *lock_info;
+       int i = 0;
+
+       if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) {
+               return;
+       }
+
+       pthread_mutex_lock(&lock_info->lock);
+
+       for (i = lock_info->num_locks - 1; i >= 0; i--) {
+               if (lock_info->locks[i].lock_addr == lock_addr)
+                       break;
+       }
+
+       if (i == -1) {
+               /* Lock not found :( */
+               pthread_mutex_unlock(&lock_info->lock);
+               return;
+       }
+
+       lock_info->locks[i].suspended = 1;
+
+       pthread_mutex_unlock(&lock_info->lock);
+}
+
+void ast_restore_lock_info(void *lock_addr)
+{
+       struct thr_lock_info *lock_info;
+       int i = 0;
+
+       if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
+               return;
+
+       pthread_mutex_lock(&lock_info->lock);
+
+       for (i = lock_info->num_locks - 1; i >= 0; i--) {
+               if (lock_info->locks[i].lock_addr == lock_addr)
+                       break;
+       }
+
+       if (i == -1) {
+               /* Lock not found :( */
+               pthread_mutex_unlock(&lock_info->lock);
+               return;
+       }
+
+       lock_info->locks[i].suspended = 0;
+
+       pthread_mutex_unlock(&lock_info->lock);
+}
+
+
 #ifdef HAVE_BKTR
 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
 #else
@@ -867,7 +919,7 @@ static void append_backtrace_information(struct ast_str **str, struct ast_bt *bt
                        ast_str_append(str, 0, "\t%s\n", symbols[frame_iterator]);
                }
 
-               free(symbols);
+               ast_std_free(symbols);
        } else {
                ast_str_append(str, 0, "\tCouldn't retrieve backtrace symbols\n");
        }
@@ -880,7 +932,7 @@ static void append_lock_information(struct ast_str **str, struct thr_lock_info *
        ast_mutex_t *lock;
        struct ast_lock_track *lt;
 
-       ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d)\n",
+       ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d%s)\n",
                                   lock_info->locks[i].pending > 0 ? "Waiting for " :
                                   lock_info->locks[i].pending < 0 ? "Tried and failed to get " : "", i,
                                   lock_info->locks[i].file,
@@ -888,7 +940,8 @@ static void append_lock_information(struct ast_str **str, struct thr_lock_info *
                                   lock_info->locks[i].line_num,
                                   lock_info->locks[i].func, lock_info->locks[i].lock_name,
                                   lock_info->locks[i].lock_addr,
-                                  lock_info->locks[i].times_locked);
+                                  lock_info->locks[i].times_locked,
+                                  lock_info->locks[i].suspended ? " - suspended" : "");
 #ifdef HAVE_BKTR
        append_backtrace_information(str, lock_info->locks[i].backtrace);
 #endif
@@ -930,7 +983,7 @@ static void append_lock_information(struct ast_str **str, struct thr_lock_info *
        which will give a stack trace and continue. -- that aught to do the job!
 
 */
-void log_show_lock(void *this_lock_addr)
+void ast_log_show_lock(void *this_lock_addr)
 {
        struct thr_lock_info *lock_info;
        struct ast_str *str;
@@ -961,24 +1014,12 @@ void log_show_lock(void *this_lock_addr)
 }
 
 
-static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+struct ast_str *ast_dump_locks(void)
 {
        struct thr_lock_info *lock_info;
        struct ast_str *str;
 
-       if (!(str = ast_str_create(4096)))
-               return CLI_FAILURE;
-
-       switch (cmd) {
-       case CLI_INIT:
-               e->command = "core show locks";
-               e->usage =
-                       "Usage: core show locks\n"
-                       "       This command is for lock debugging.  It prints out which locks\n"
-                       "are owned by each active thread.\n";
-               return NULL;
-
-       case CLI_GENERATE:
+       if (!(str = ast_str_create(4096))) {
                return NULL;
        }
 
@@ -991,38 +1032,74 @@ static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_
                       "=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr> (times locked)\n"
                       "===\n", ast_get_version());
 
-       if (!str)
-               return CLI_FAILURE;
+       if (!str) {
+               return NULL;
+       }
 
        pthread_mutex_lock(&lock_infos_lock.mutex);
        AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
                int i;
-               if (lock_info->num_locks) {
-                       ast_str_append(&str, 0, "=== Thread ID: 0x%lx (%s)\n", (long) lock_info->thread_id,
-                               lock_info->thread_name);
-                       pthread_mutex_lock(&lock_info->lock);
-                       for (i = 0; str && i < lock_info->num_locks; i++) {
-                               append_lock_information(&str, lock_info, i);
+               int header_printed = 0;
+               pthread_mutex_lock(&lock_info->lock);
+               for (i = 0; str && i < lock_info->num_locks; i++) {
+                       /* Don't show suspended locks */
+                       if (lock_info->locks[i].suspended) {
+                               continue;
                        }
-                       pthread_mutex_unlock(&lock_info->lock);
-                       if (!str)
-                               break;
+
+                       if (!header_printed) {
+                               ast_str_append(&str, 0, "=== Thread ID: 0x%lx (%s)\n", (long) lock_info->thread_id,
+                                       lock_info->thread_name);
+                               header_printed = 1;
+                       }
+
+                       append_lock_information(&str, lock_info, i);
+               }
+               pthread_mutex_unlock(&lock_info->lock);
+               if (!str) {
+                       break;
+               }
+               if (header_printed) {
                        ast_str_append(&str, 0, "=== -------------------------------------------------------------------\n"
-                                      "===\n");
-                       if (!str)
-                               break;
+                               "===\n");
+               }
+               if (!str) {
+                       break;
                }
        }
        pthread_mutex_unlock(&lock_infos_lock.mutex);
 
-       if (!str)
-               return CLI_FAILURE;
+       if (!str) {
+               return NULL;
+       }
 
        ast_str_append(&str, 0, "=======================================================================\n"
                       "\n");
 
-       if (!str)
+       return str;
+}
+
+static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+       struct ast_str *str;
+
+       switch (cmd) {
+       case CLI_INIT:
+               e->command = "core show locks";
+               e->usage =
+                       "Usage: core show locks\n"
+                       "       This command is for lock debugging.  It prints out which locks\n"
+                       "are owned by each active thread.\n";
+               return NULL;
+
+       case CLI_GENERATE:
+               return NULL;
+       }
+
+       str = ast_dump_locks();
+       if (!str) {
                return CLI_FAILURE;
+       }
 
        ast_cli(a->fd, "%s", ast_str_buffer(str));
 
@@ -2367,171 +2444,6 @@ int ast_get_tid(void)
        return ret;
 }
 
-/*!
- * \brief Max length of a salt string.
- *
- * $[1,5,6]$[a–zA–Z0–9./]{1,16}$, plus null terminator
- */
-#define MAX_SALT_LEN 21
-
-static char salt_chars[] =
-       "abcdefghijklmnopqrstuvwxyz"
-       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-       "0123456789"
-       "./";
-
-/*! Randomly select a character for a salt string */
-static char gen_salt_char(void)
-{
-       int which = ast_random_double() * 64;
-       return salt_chars[which];
-}
-
-/*!
- * \brief Generates a salt to try with crypt.
- *
- * If given an empty string, will generate a salt for the most secure algorithm
- * to try with crypt(). If given a previously generated salt, the algorithm will
- * be lowered by one level of security.
- *
- * \param[out] current_salt Output string in which to generate the salt.
- *                          This can be an empty string, or the results of a
- *                          prior gen_salt call.
- * \param max_len Length of \a current_salt.
- * \return 0 on success.
- * \return Non-zero on error.
- */
-static int gen_salt(char *current_salt, size_t maxlen)
-{
-       int i;
-
-       if (maxlen < MAX_SALT_LEN || current_salt == NULL) {
-               return -1;
-       }
-
-       switch (current_salt[0]) {
-       case '\0':
-               /* Initial generation; $6$ = SHA-512 */
-               *current_salt++ = '$';
-               *current_salt++ = '6';
-               *current_salt++ = '$';
-               for (i = 0; i < 16; ++i) {
-                       *current_salt++ = gen_salt_char();
-               }
-               *current_salt++ = '$';
-               *current_salt++ = '\0';
-               return 0;
-       case '$':
-               switch (current_salt[1]) {
-               case '6':
-                       /* Downgrade to SHA-256 */
-                       current_salt[1] = '5';
-                       return 0;
-               case '5':
-                       /* Downgrade to MD5 */
-                       current_salt[1] = '1';
-                       return 0;
-               case '1':
-                       /* Downgrade to traditional crypt */
-                       *current_salt++ = gen_salt_char();
-                       *current_salt++ = gen_salt_char();
-                       *current_salt++ = '\0';
-                       return 0;
-               default:
-                       /* Unrecognized algorithm */
-                       return -1;
-               }
-       default:
-               /* Was already as insecure as it gets */
-               return -1;
-       }
-
-}
-
-#if defined(HAVE_CRYPT_R)
-
-char *ast_crypt(const char *key, const char *salt)
-{
-       struct crypt_data data = {};
-       const char *crypted = crypt_r(key, salt, &data);
-
-       /* Crypt may return success even if it doesn't recognize the salt. But
-        * in those cases it always mangles the salt in some way.
-        */
-       if (!crypted || !ast_begins_with(crypted, salt)) {
-               return NULL;
-       }
-
-       return ast_strdup(crypted);
-}
-
-int ast_crypt_validate(const char *key, const char *expected)
-{
-       struct crypt_data data = {};
-       return strcmp(expected, crypt_r(key, expected, &data)) == 0;
-}
-
-#elif defined(HAVE_CRYPT)
-
-/* crypt is not reentrant. A global mutex is neither ideal nor perfect, but good
- * enough if crypt_r support is unavailable
- */
-AST_MUTEX_DEFINE_STATIC(crypt_mutex);
-
-char *ast_crypt(const char *key, const char *salt)
-{
-       const char *crypted;
-       SCOPED_MUTEX(lock, &crypt_mutex);
-
-       crypted = crypt(key, salt);
-
-       /* Crypt may return success even if it doesn't recognize the salt. But
-        * in those cases it always mangles the salt in some way.
-        */
-       if (!crypted || !ast_begins_with(crypted, salt)) {
-               return NULL;
-       }
-
-       return ast_strdup(crypted);
-}
-
-int ast_crypt_validate(const char *key, const char *expected)
-{
-       SCOPED_MUTEX(lock, &crypt_mutex);
-       return strcmp(expected, crypt(key, expected)) == 0;
-}
-
-#else /* No crypt support */
-
-char *ast_crypt(const char *key, const char *salt)
-{
-       ast_log(LOG_WARNING,
-               "crypt() support not available; cannot encrypt password\n");
-       return NULL;
-}
-
-int ast_crypt_validate(const char *key, const char *expected)
-{
-       ast_log(LOG_WARNING,
-               "crypt() support not available; cannot validate password\n");
-       return 0;
-}
-
-#endif  /* No crypt support */
-
-char *ast_crypt_encrypt(const char *key)
-{
-       char salt[MAX_SALT_LEN] = {};
-       while (gen_salt(salt, sizeof(salt)) == 0) {
-               char *crypted = ast_crypt(key, salt);
-               if (crypted) {
-                       return crypted;
-               }
-       }
-       return NULL;
-}
-
-
 char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size)
 {
        const char *envPATH = getenv("PATH");