Logo Search packages:      
Sourcecode: affix version File versions

btutils.c

/* 
   Affix - Bluetooth Protocol Stack for Linux
   Copyright (C) 2001 Nokia Corporation
   Dmitry Kasatkin <dmitry.kasatkin@nokia.com>

   Based on the from Pontus Fuchs <pontus.fuchs@tactel.se>
   Copyright (c) 1999, 2000 Pontus Fuchs, All Rights Reserved.
   
   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2 of the License, or (at your
   option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License along
   with this program; if not, write to the Free Software Foundation, Inc.,
   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

/*
   $Id: btutils.c,v 1.39 2003/02/18 13:39:11 kds Exp $

   utility functions for Affix

   Fixes: 
            Dmitry Kasatkin
*/

#include <affix/config.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/file.h>

#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>

/* pidof */
#include <sys/wait.h>
#include <dirent.h>

#include <stdint.h>

#include <affix/btcore.h>
#include <affix/utils.h>


/* Info about a process. */
typedef struct _proc_
{
      char *fullname;   /* Name as found out from argv[0] */
      char *basename;   /* Only the part after the last / */
      char *statname;   /* the statname without braces    */
      ino_t ino;        /* Inode number                 */
      dev_t dev;        /* Device it is on              */
      pid_t pid;        /* Process ID.                  */
      int sid;          /* Session ID.                  */
      struct _proc_ *next;    /* Pointer to next struct.      */
} PROC;

/* pid queue */
typedef struct _pidq_ {
      struct _pidq_ *front;
      struct _pidq_ *next;
      struct _pidq_ *rear;
      PROC        *proc;
} PIDQ;

/* List of processes. */
static PROC *plist = NULL;
/* Did we stop a number of processes? */
static int scripts_too = 0;


//
// Get some file-info. (size and lastmod)
//
int get_fileinfo(const char *name, char *lastmod)
{
      struct stat stats;
      struct tm *tm;
      
      stat(name, &stats);
      tm = gmtime(&stats.st_mtime);
      snprintf(lastmod, 21, "%04d-%02d-%02dT%02d:%02d:%02dZ",
                  tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
                  tm->tm_hour, tm->tm_min, tm->tm_sec);
      return (int) stats.st_size;
}


//
// Read a file and alloc a buffer for it
//
uint8_t* easy_readfile(const char *filename, int *file_size)
{
      int actual;
      int fd;
      uint8_t *buf;


      fd = open(filename, O_RDONLY, 0);
      if (fd == -1) {
            return NULL;
      }
      *file_size = get_filesize(filename);
      DBPRT("name=%s, size=%d\n", filename, *file_size);
      if(! (buf = malloc(*file_size)) ) {
            return NULL;
      }

      actual = read(fd, buf, *file_size);
      close(fd); 

      *file_size = actual;
      return buf;
}

/*
 *    Read the proc filesystem.
 */
static int readproc(void)
{
      DIR *dir;
      struct dirent *d;
      char path[256];
      char buf[256];
      char *s, *q;
      FILE *fp;
      int pid, f;
      PROC *p, *n;
      struct stat st;
      int c;

      /* Open the /proc directory. */
      if ((dir = opendir("/proc")) == NULL) {
            BTERROR("cannot opendir(/proc)");
            return -1;
      }

      /* Free the already existing process list. */
      for (p = plist; p; p = n) {
            n = p->next;
            if (p->fullname)
                  free(p->fullname);
            if (p->statname)
                  free(p->statname);
            free(p);
      }
      plist = NULL;
      /* Walk through the directory. */
      while ((d = readdir(dir)) != NULL) {
            /* See if this is a process */
            if ((pid = atoi(d->d_name)) == 0) continue;
            /* Get a PROC struct . */
            p = (PROC *)malloc(sizeof(PROC));
            memset(p, 0, sizeof(PROC));
            /* Open the status file. */
            snprintf(path, sizeof(path), "/proc/%s/stat", d->d_name);

            /* Read SID & statname from it. */
            if ((fp = fopen(path, "r")) != NULL) {
                  buf[0] = 0;
                  fgets(buf, 256, fp);

                  /* See if name starts with '(' */
                  s = buf;
                  while (*s != ' ') s++;
                  s++;
                  if (*s == '(') {
                        /* Read program name. */
                        q = strrchr(buf, ')');
                        if (q == NULL) {
                              p->sid = 0;
                              BTERROR("can't get program name from %s\n", path);
                              free(p);
                              continue;
                        }
                        s++;
                  } else {
                        q = s;
                        while (*q != ' ') q++;
                  }
                  *q++ = 0;
                  while (*q == ' ') q++;
                  p->statname = strdup(s);

                  /* This could be replaced by getsid(pid) */
                  if (sscanf(q, "%*c %*d %*d %d", &p->sid) != 1) {
                        p->sid = 0;
                        BTERROR("can't read sid from %s\n",
                                    path);
                        free(p);
                        continue;
                  }
                  fclose(fp);
            } else {
                  /* Process disappeared.. */
                  free(p);
                  continue;
            }

            /* Now read argv[0] */
            snprintf(path, sizeof(path), "/proc/%s/cmdline", d->d_name);
            if ((fp = fopen(path, "r")) != NULL) {
                  f = 0;
                  while(f < 127 && (c = fgetc(fp)) != EOF && c)
                        buf[f++] = c;
                  buf[f++] = 0;
                  fclose(fp);

                  /* Store the name into malloced memory. */
                  p->fullname = strdup(buf);

                  /* Get a pointer to the basename. */
                  if ((p->basename = strrchr(p->fullname, '/')) != NULL)
                        p->basename++;
                  else
                        p->basename = p->fullname;
            } else {
                  /* Process disappeared.. */
                  free(p);
                  continue;
            }

            /* Try to stat the executable. */
            snprintf(path, sizeof(path), "/proc/%s/exe", d->d_name);
            if (stat(path, &st) == 0) {
                  p->dev = st.st_dev;
                  p->ino = st.st_ino;
            }

            /* Link it into the list. */
            p->next = plist;
            plist = p;
            p->pid = pid;
      }
      closedir(dir);
      /* Done. */
      return 0;
}

static inline PIDQ *init_pid_q(PIDQ *q)
{
      q->front =  q->next = q->rear = NULL;
      q->proc = NULL;
      return q;
}

static inline int empty_q(PIDQ *q)
{
      return (q->front == NULL);
}

static inline int add_pid_to_q(PIDQ *q, PROC *p)
{
      PIDQ *tmp;

      tmp = (PIDQ *)malloc(sizeof(PIDQ));

      tmp->proc = p;
      tmp->next = NULL;

      if (empty_q(q)) {
            q->front = tmp;
            q->rear  = tmp;
      } else {
            q->rear->next = tmp;
            q->rear = tmp;
      }
      return 0;
}

static inline PROC *get_next_from_pid_q(PIDQ *q)
{
      PROC *p;
      PIDQ *tmp = q->front;

      if (!empty_q(q)) {
            p = q->front->proc;
            q->front = tmp->next;
            free(tmp);
            return p;
      }

      return NULL;
}

/* Try to get the process ID of a given process. */
static PIDQ *pidof(char *prog)
{
      struct stat st;
      int dostat = 0;
      PROC *p;
      PIDQ *q;
      char *s;
      int foundone = 0;
      int ok = 0;

      /* Try to stat the executable. */
      if (prog[0] == '/' && stat(prog, &st) == 0) dostat++;

      /* Get basename of program. */
      if ((s = strrchr(prog, '/')) == NULL)
            s = prog;
      else
            s++;

      q = (PIDQ *)malloc(sizeof(PIDQ));
      q = init_pid_q(q);

      /* First try to find a match based on dev/ino pair. */
      if (dostat) {
            for (p = plist; p; p = p->next) {
                  if (p->dev == st.st_dev && p->ino == st.st_ino) {
                        add_pid_to_q(q, p);
                        foundone++;
                  }
            }
      }

      /* If we didn't find a match based on dev/ino, try the name. */
      if (!foundone) {
            for (p = plist; p; p = p->next) {
                  ok = 0;

                  ok += (strcmp(p->fullname, prog) == 0);
                  ok += (strcmp(p->basename, s) == 0);

                  if (p->fullname[0] == 0 ||
                              strchr(p->fullname, ' ') ||
                              scripts_too)
                        ok += (strcmp(p->statname, s) == 0);

                  if (ok) add_pid_to_q(q, p);
            }
      }

      return q;
}

#define PIDOF_OMITSZ    5

/*
 *    Pidof functionality.
 */
int affix_pidof(char *name, int flags, pid_t pid)
{
      PROC *p;
      PIDQ *q;
      int i,oind;
      pid_t opid[PIDOF_OMITSZ], spid = 0;

      for (oind = PIDOF_OMITSZ-1; oind > 0; oind--)
            opid[oind] = 0;

      if (flags&PIDOF_SCRIPTS)
            scripts_too++;

      if (flags&PIDOF_OMIT) {
            opid[oind] = pid;
            oind++;
      }
      if (flags&PIDOF_POMIT) {
            opid[oind] = getppid();
            oind++;
      }

      /* Print out process-ID's one by one. */
      readproc();
      if ((q = pidof(name)) != NULL) {
            spid = 0;
            while ((p = get_next_from_pid_q(q))) {
                  if (flags & PIDOF_OMIT) {
                        for (i = 0; i < oind; i++)
                              if (opid[i] == p->pid)
                                    break;
                        /*
                         *    On a match, continue with
                         *    the for loop above.
                         */
                        if (i < oind)
                              continue;
                  }
                  if (flags & PIDOF_SINGLE) {
                        if (spid)
                              continue;
                        else
                              spid = p->pid;
                  }
            }
      }
      return spid;
}



#define isblank(c) (c == ' ' || c == '\t')

char *xml_element(char **buf, char **attr)
{
      char  *start = *buf, *next;

      // find first <
      start = strchr(start, '<');
      if (start == NULL)
            return NULL;
      start++;

      // find last >
      next = strchr(start, '>');
      if (next == NULL) {
            // broken
            return NULL;
      }
      *next = '\0';
      next++;
      *buf = next;

      // get first later of the element
      while (isblank(*start) && *start != '\0')
            start++;

      next = start+1;
      while (!isblank(*next) && *next != '\0')
            next++;
      
      *next = '\0';
      *attr = next+1;

      // check for "/"
      next = *buf-1;
      while (*next == '\0' || isblank(*next))
            next--;
      if (*next == '/')
            *next = '\0';

      return start;
}

char *xml_attribute(char **buf, char **value)
{
      char *start = *buf, *next;
      int flag = 0;

      //find attr name
      while (isblank(*start) && *start != '\0')
            start++;
      
      if (*start == '\0')
            return NULL;

      next = start+1;
      
      //find end
      while (!isblank(*next) && *next != '=' && *next != '\0')
            next++;

      if (*next == '=')
            flag = 1;
      
      *next = '\0';
      next++;
      
      if (flag == 0) {
            next = strchr(next, '=');
            if (next == NULL)
                  return NULL;
            next++;
      }
      
      next = strchr(next, '"');
      if (next == NULL)
            return NULL;
      *value = next+1;
      next = strchr(next+1, '"');
      if (next == NULL)
            return NULL;
      *next = '\0';
      *buf = next+1;
      
      return start;
}

int rmkdir(char *new_dir, int mode)
{
      size_t i = 0;

      DBPRT("new_dir: %s\n", new_dir);    
      if (new_dir == NULL || new_dir[0] == '\0')
            return -1;

      if (access(new_dir, R_OK|X_OK) == 0)
            return 0;
      
      if (new_dir[0] == '/')
            i++;
      
      for (; new_dir[i] != '\0'; i++) {
            if (new_dir[i] == '/') {
                  char tmpdir[PATH_MAX + 1];

                  strncpy (tmpdir, new_dir, i);
                  tmpdir[i] = '\0';

                  if ((mkdir(tmpdir, mode) == -1) && (errno != EEXIST))
                        return -1;
            }     
      }

      if (mkdir(new_dir, mode) == -1 && errno != EEXIST)
            return -1;

      return 0;
}

/* speed stuff */
int get_speed(int size, struct timeval *tv_start, struct timeval *tv_end,
            long int *rsec, long int *rusec, double *speed)
{
      long int    sec, usec;

      sec = tv_end->tv_sec - tv_start->tv_sec;
      usec = (1000000 * sec) + tv_end->tv_usec - tv_start->tv_usec;
      *rsec = usec/1000000;
      *rusec = (usec - (*rsec * 1000000))/10000;
      *speed = (double)(size)/((double)(*rsec) + (double)(*rusec)/100);
      return 0;
}

/* Mapping */

char *val2str(struct affix_tupla *map, int value)
{
      for (;map; map++) {
            if (map->value == value)
                  return map->str;
      }
      return "";
}


int str2val(struct affix_tupla *map, char *str, unsigned int *val)
{
      char              *fp, *tmp;
      struct affix_tupla      *m;
      int               found;

      if (!str || !(str = strdup(str)))
            return 0;

      *val = 0;
      found = 1;

      for (fp = strtok_r(str, ", ", &tmp); fp; fp = strtok_r(NULL, ", ", &tmp)) {
            //printf("arg: [%s]\n", fp);
            for (m = map; m->match || (found = 0); m++) {
                  if (strcasecmp(fp, m->match) == 0) {
                        *val = m->value;
                        free(str);
                        return 1;
                  }
            }
            if (!found) {
                  free(str);
                  return 0;
            }
      }
      free(str);
      return 0;
}


int str2mask(struct affix_tupla *map, char *str, unsigned int *mask)
{
      char              *fp, *tmp;
      struct affix_tupla      *m;
      int               found;

      if (!str || !(str = strdup(str)))
            return 0;

      *mask = 0;
      found = 1;

      for (fp = strtok_r(str, ", ", &tmp); fp; fp = strtok_r(NULL, ", ", &tmp)) {
            //printf("arg: [%s]\n", fp);
            for (m = map; m->match || (found = 0); m++) {
                  if (strcasecmp(fp, m->match) == 0) {
                        *mask |= m->value;
                        break;
                  }
            }
            if (!found) {
                  free(str);
                  return 0;
            }
      }
      free(str);
      return 1;
}

int mask2str(struct affix_tupla *map, char *str, unsigned int mask)
{
      int               i = 0;
      struct affix_tupla      *m;

      str[0] = '\0';
      for (m = map; m->match; m++) {
            if (m->value & mask)
                  i += sprintf(str + i, "%s ", m->match);
      }
      if (i)
            str[i-1] = '\0';
      return 0;
}

int mask2str_comma(struct affix_tupla *map, char *str, unsigned int mask)
{
      int               i = 0;
      struct affix_tupla      *m;

      str[0] = '\0';
      for (m = map; m->match; m++) {
            if (m->value & mask)
                  i += sprintf(str + i, "%s, ", m->match);
      }
      if (i)
            str[i-2] = '\0';
      return 0;
}

int str2cod(char *str, uint32_t *cod)
{
      struct affix_tupla      *map;
      int               found = 1;
      char              *arg, *tmp;

      if (!str || !(str = strdup(str)))
            return -1;

      /* get Major */
      arg = strtok_r(str, ", ", &tmp);
      if (arg == NULL) {
            free(str);
            return -1;
      }

      *cod = 0;
      for (map = codMajorClassMnemonic; map->match || (found=0); map++) {
            if (strncasecmp(map->match, arg, 3) == 0) {
                  *cod |= map->value;
                  break;
            }
      }
      if (!found){
            free(str);
            return -1;
      }

      /* get minor */
      arg = strtok_r(NULL, ", ", &tmp);
      if (arg == NULL) {
            free(str);
            return -1;
      }

      switch (*cod & HCI_COD_MAJOR) {
            case HCI_COD_COMPUTER:
                  for (map = codMinorComputerMnemonic; map->match || (found=0); map++) {
                        if (strncasecmp(map->match, arg, 3) == 0) {
                              *cod |= map->value;
                              break;
                        }
                  }
                  break;
            case HCI_COD_PHONE:
                  for (map = codMinorPhoneMnemonic; map->match || (found=0); map++) {
                        if (strncasecmp(map->match, arg, 3) == 0) {
                              *cod |= map->value;
                              break;
                        }
                  }
                  break;
            case HCI_COD_MAUDIO:
                  for (map = codMinorAudioMnemonic; map->match || (found=0); map++) {
                        if (strncasecmp(map->match, arg, 3) == 0) {
                              *cod |= map->value;
                              break;
                        }
                  }
                  break;
            default:
                  found = 0;
      }

      if (!found) {
            free(str);
            return -1;
      }

      /* get services */
      while ((arg = strtok_r(NULL, ", ", &tmp))) {
            for (map = codServiceClassMnemonic; map->match || (found=0); map++) {
                  if (strncasecmp(map->match, arg, 3) == 0) {
                        *cod |= map->value;
                        break;
                  }
            }
            if (!found) {
                  free(str);
                  return -1;
            }
      }

      free(str);
      return 0;
}

int str2cod_svc(char *str, uint32_t *cod)
{
      struct affix_tupla      *map;
      int               found = 1;
      char              *arg, *tmp;

      if (!str || !(str = strdup(str)))
            return -1;

      /* get services */
      for (arg = strtok_r(str, ", ", &tmp); arg; arg = strtok_r(NULL, ", ", &tmp)) {
            for (map = codServiceClassMnemonic; map->match || (found=0); map++) {
                  if (strncasecmp(map->match, arg, 3) == 0) {
                        *cod |= map->value;
                        break;
                  }
            }
            if (!found) {
                  free(str);
                  return -1;
            }
      }

      free(str);
      return 0;
}


int str2pkt_type(char *str, unsigned int *pkt_type)
{
      return str2mask(pkt_type_map, str, pkt_type);
}

int str2sec_level(char *str, unsigned int *sec_level)
{
      return str2mask(sec_level_map, str, sec_level);
}


/* device inquiry/known cache */

btdev_struct *btdev_cache_lookup(btdev_list *list, BD_ADDR *bda)
{
      btdev_struct      *entry;
      int         i;
      
      for (i = 0; (entry = s_list_nth_data(list->head, i)); i++) {
            if (bda_equal(bda, &entry->bda))
                  return entry;
      }
      return NULL;
}

int btdev_cache_del(btdev_list *list, btdev_struct *entry)
{
      s_list_remove(&list->head, entry);
      free(entry);
      return 0;
}

btdev_struct *btdev_cache_add(btdev_list *list, BD_ADDR *bda)
{
      btdev_struct      *entry, *mount;
      int         i, num = -1;

      for (i = 0; (entry = s_list_nth_data(list->head, i)); i++) {
            if (bda_equal(bda, &entry->bda)) {
                  s_list_remove(&list->head, entry);
                  num = i;
                  break;
            }
      }
      if (!entry) {
            /* create new */
            entry = malloc(sizeof(btdev_struct));
            if (!entry) {
                  perror("btdev_cache allocation failed\n");
                  return NULL;
            }
            memset(entry, 0, sizeof(btdev_struct));
            entry->bda = *bda;
            entry->state = DEVSTATE_UNKNOWN;
      }
      /* find linking position */
      for (i = 0; (mount = s_list_nth_data(list->head, i)); i++) {
            if (mount->state == DEVSTATE_RANGE)
                  continue;
            if (mount->state == DEVSTATE_GONE || i == num)
                  break;
      }
      s_list_insert(&list->head, entry, i);
      return entry;
}

int btdev_cache_reload(btdev_list *list)
{
      char        buf[256];
      FILE        *cfd;
      size_t            read;
      char        *next = NULL, *elem, *attrs, *attr, *value;
      BD_ADDR           bda;
      int         found = 0, eof = 0;

      if (btdev_cache_lock(list) < 0) {
            return -1;
      }

      cfd = fopen(list->file, "r");
      if (!cfd){
            fprintf(stderr, "Unable to open cache: %s\n", list->file);
            return -1;
      }

      if (list->head) {
            s_list_destroy(&list->head);
            list->head = NULL;
            list->count = 0;
      }
      
      for (;;) {
            int   free;
            
            if (next) {
                  /* we have some info in the buffer */
                  free =  next - buf;
                  memmove(buf, next, sizeof(buf) - free);
            } else
                  free = sizeof(buf);
                  
            if (!eof) {
                  //printf("reading %d butes\n", free);
                  read = fread(buf + sizeof(buf) - free, 1, free, cfd);
                  if (!read)
                        eof = 1;
            }

            next = (void*)buf;
            elem = xml_element(&next, &attrs);
            if (!elem)
                  break;

            if (!found)
                  if (strcmp(elem, "device-listing") == 0) {
                        found = 1;
                        continue;
                  }

            if (strcmp(elem, "/device-listing") == 0)
                  break;
            //printf("element: %s\n", elem);
            //printf("attr left: %s\n", attrs);
            // get attributes
            if (strcmp(elem, "device") == 0) {
                  btdev_struct      *entry;
                  entry = NULL;
                  while ((attr = xml_attribute(&attrs, &value))) {
                        //printf("%s = %s\n", attr, value);
                        if (!entry) {
                              if (strcmp(attr, "bda") == 0) {
                                    str2bda(&bda, value);
                                    entry = btdev_cache_add(list, &bda);
                              }
                        } else if (strcmp(attr, "class") == 0) {
                              sscanf(value, "%x", &entry->cod);
                        } else if (strcmp(attr, "name") == 0) {
                              strcpy(entry->name, value);
                        } else if (strcmp(attr, "key") == 0) {
                              unsigned int      val;
                              int         i;
                              /* convert key to binary format */
                              for (i = 0; sscanf(value, "%2x", &val) > 0 && i < 16; i++, value += 2) {
                                    entry->link_key[i] = val;
                              }
                              if (i)
                                    entry->flags |= BTDEV_KEY;
                        }
                  }
            }
      }
      fclose(cfd);
      return 0;
}

int btdev_cache_load(char *cachefile, btdev_list *list)
{
      int   err;
      
      list->file = strdup(cachefile);
      if (!list->file)
            return -1;

      list->head = NULL;
      list->count = 0;
      list->lock = -1;

      err =  btdev_cache_reload(list);
      btdev_cache_unlock(list);

      return err;
}

int btdev_cache_save(btdev_list *list)
{
      btdev_struct      *entry;
      FILE        *cfd;
      int         i, k;

      if (list->lock == -1 && btdev_cache_lock(list) < 0)
            return -1;

      cfd = fopen(list->file, "w");
      if (!cfd) {
            fprintf(stderr, "Unable to fdopen cache file: %s\n", list->file);
            btdev_cache_unlock(list);
            return -1;
      }
      fprintf(cfd, "<device-listing>\n");
      for (i = 0; (entry = s_list_nth_data(list->head, i)); i++) {
            fprintf(cfd, "<device bda=\"%s\"", bda2str(&entry->bda));
            if (entry->cod)
                  fprintf(cfd, " class=\"%x\"", entry->cod);
            if (entry->name[0] != '\0')
                  fprintf(cfd, " name=\"%s\"", entry->name);
            if (entry->flags & BTDEV_KEY) {
                  fprintf(cfd, " key=\"");
                  for (k = 0; k < 16; k++)
                        fprintf(cfd, "%02x", entry->link_key[k]);
                  fprintf(cfd, "\"");
            }

            fprintf(cfd, "/>\n");
      }
      fprintf(cfd, "</device-listing>\n");
      fclose(cfd);
      btdev_cache_unlock(list);
      return 0;
}

void btdev_cache_free(btdev_list *list)
{
      if (list->head) {
            s_list_destroy(&list->head);
            list->head = NULL;
            list->count = 0;
      }
//    if (list->file)
//          free(list->file);
}

int btdev_cache_lock(btdev_list *list)
{
      list->lock = open(list->file, O_CREAT, 0644);
      if (list->lock < 0) {
            fprintf(stderr, "Unable to open cache for locking: %s\n", list->file);
            return list->lock;
      }

      if (flock(list->lock, LOCK_EX) < 0) {
            fprintf(stderr, "Unable to lock cache\n");
            close(list->lock);
            list->lock = -1;
            return -1;
      }
      return 0;
}

void btdev_cache_unlock(btdev_list *list)
{
      if (list->lock < 0)
            return;

      close(list->lock);
      list->lock = -1;
}

/*
 * Inquiry Cache Stuff
 */
void btdev_cache_retire(btdev_list *list)
{
      btdev_struct      *entry;
      int         i;
      
      for (i = 0; (entry = s_list_nth_data(list->head, i)); i++)
            entry->state = DEVSTATE_GONE;
}

void btdev_cache_print(btdev_list *list, int state)
{
      btdev_struct      *entry;
      char        buf[256], *name;
      int         i;
      char        ch;
      
      for (i = 0; (entry = s_list_nth_data(list->head, i)); i++) {
            if (!(entry->state & state))
                  continue;
            parse_cod(buf, entry->cod);
            if (entry->name[0] != '\0')
                  name = entry->name;
            else
                  name = "Unknown";
            switch (entry->state) {
                  case DEVSTATE_RANGE:
                        ch = '+';
                        break;
                  case DEVSTATE_GONE:
                        ch = '-';
                        break;
                  case DEVSTATE_UNKNOWN:
                  default:
                        ch = ' ';
            }
            printf("%c%d: Address: %s, Class: 0x%06X, Key: \"%s\"", 
                        ch, i+1, bda2str(&entry->bda), entry->cod, (entry->flags & BTDEV_KEY)?"yes":"no");
            printf(", Name: \"%s\"\n", name);
            printf("    %s\n", buf);
      }
}

int btdev_cache_resolve(btdev_list *list, BD_ADDR *bda, int id)
{
      btdev_struct      *entry;
      
      if (id < 0)
            return -1;
      entry = s_list_nth_data(list->head, id - 1);
      if (!entry)
            return -1;
      *bda = entry->bda;
      return 0;
}

btdev_struct *__btdev_cache_add(btdev_list *list, BD_ADDR bda, uint32_t cod, char *name)
{
      btdev_struct *entry;

      entry = btdev_cache_add(list, &bda);
      if (!entry)
            return NULL;

      entry->state = DEVSTATE_RANGE;
      entry->cod = cod;
      if (name)
            strcpy(entry->name, name);

      return entry;
}

/* ------------------------------------------------------------- */

int btdev_get_bda(btdev_list *list, BD_ADDR *bda, char *arg)
{
      int   err;
      
      err = str2bda(bda, arg);
      if (!err) {
            /* try resolve */
            int   id;
            id = atoi(arg);
            //printf("id: %d\n", id);
            if (!id) 
                  return -1;
            err = btdev_cache_resolve(list, bda, id);
            if (err)
                  return -1;
      }
      return 0;
}

/*
 * CLASS Of Device stuff
 */
int parse_cod(char *buf, uint32_t  cod)
{
      int               count = 0, found = 1;
      struct affix_tupla      *map;

      switch (cod & HCI_COD_MAJOR) {
            case HCI_COD_COMPUTER:
                  for (map = codMinorComputerMnemonic; map->str || (found=0); map++) {
                        if (map->value == (cod & HCI_COD_MINOR)) {
                              count += sprintf(buf+count, "Computer (%s)", map->str);
                              break;
                        }
                  }
                  if (!found)
                        count += sprintf(buf+count, "Computer (Unclassified)");
                  break;
            case HCI_COD_PHONE:
                  for (map = codMinorPhoneMnemonic; map->str || (found=0); map++) {
                        if (map->value == (cod & HCI_COD_MINOR)) {
                              count += sprintf(buf+count, "Phone (%s)", map->str);
                              break;
                        }
                  }
                  if (!found)
                        count += sprintf(buf+count, "Phone (Unclassified)");
                  break;
            case HCI_COD_MAUDIO:
                  for (map = codMinorAudioMnemonic; map->str || (found=0); map++) {
                        if (map->value == (cod & HCI_COD_MINOR)) {
                              count += sprintf(buf+count, "Audio (%s)", map->str);
                              break;
                        }
                  }
                  if (!found)
                        count += sprintf(buf+count, "Audio (Unclassified)");
                  break;
            default:
                  for (map = codMajorClassMnemonic; map->str || (found=0); map++) {
                        if (map->value == (cod & HCI_COD_MAJOR)) {
                              count += sprintf(buf+count, "%s (Unclassified)", map->str);
                              break;
                        }
                  }
                  if (!found)
                        count += sprintf(buf+count, "Unclassified (Unclassified)");
      }
      count += sprintf(buf+count, " [");
      for (map = codServiceClassMnemonic; map->str; map++) {
            if (map->value & cod) {
                  count += sprintf(buf+count, "%s,", map->str);
            }
      }
      count--;    // remove ,
      count += sprintf(buf+count, "]");

      return 0;
}

void argv2str(char *str, char *argv[])
{
      int   i = 0;
      char  *arg;
      
      while ((arg = *argv++)) {
            i += sprintf(str + i, "%s ", arg);
      }
      str[i - 1] = '\0'; // remove last space
}

/* slist_t */

slist_t *s_list_append(slist_t **list, void *data)
{
      slist_t     *entry, *prev;

      entry = (slist_t*)malloc(sizeof(slist_t));
      if (!entry)
            return NULL;
      entry->data = data;
      entry->next = NULL;
      
      if (!(*list)) {
            *list = entry;
            return entry;
      }
      
      for (prev = *list; prev->next; prev = prev->next) ;
      
      prev->next = entry;
      return entry;
}

slist_t *s_list_insert(slist_t **list, void *data, int i)
{
      slist_t     *entry, *prev;
      int   count;

      for (count = 0, prev = NULL, entry = *list; entry; 
                  prev = entry, entry = entry->next, count++)
            if (count == i)
                  break;

      entry = (slist_t*)malloc(sizeof(slist_t));
      if (!entry)
            return NULL;
      entry->data = data;
      if (!prev) {
            entry->next = *list;
            *list = entry;
      } else {
            entry->next = prev->next;
            prev->next = entry;
      }
      return entry;
}

slist_t *s_list_insert_sorted(slist_t **list, void *data, slist_sort_func *func)
{
      slist_t     *entry, *prev;

      if (!func)
            return NULL;
      for (prev = NULL, entry = *list; entry; prev = entry, entry = entry->next) {
            if (func(data, entry->data) < 0)
                  break;
      }
      entry = (slist_t*)malloc(sizeof(slist_t));
      if (!entry)
            return NULL;
      entry->data = data;
      if (!prev) {
            entry->next = *list;
            *list = entry;
      } else {
            entry->next = prev->next;
            prev->next = entry;
      }
      return entry;
}

void *s_list_dequeue(slist_t **list)
{
      void  *data;
      slist_t     *entry = *list;
      
      if (entry == NULL)
            return NULL;
      *list = entry->next;
      data = entry->data;
      free(entry);
      return data;
}

void s_list_remove(slist_t **list, void *data)
{
      slist_t     *entry, *prev;

      for (prev = NULL, entry = *list; entry; prev = entry, entry = entry->next) {
            if (entry->data == data) {
                  if (prev)
                        prev->next = entry->next;
                  else
                        *list = entry->next;
                  free(entry);
                  break;
            }
      }
}

void s_list_remove_custom(slist_t **list, void *data, slist_sort_func *func)
{
      slist_t     *entry = *list, *prev = NULL, *next = *list;

      if (!func)
            return;

      while (next) {
            entry = next;
            next = entry->next;                       
            if (func(entry->data, data) == 0) {
                  if (prev)
                        prev->next = entry->next;
                  else
                        *list = entry->next;
                  free(entry);
            } else
                  prev = entry;
      }
}

void s_list_destroy(slist_t **list)
{
      slist_t     *entry;
      
      while (*list) {
            entry = *list;
            *list = entry->next;
            if (entry->data)
                  free(entry->data);
            free(entry);
      }
}


int s_list_length(slist_t *list)
{
      slist_t     *entry;
      int   count;

      for (count = 0, entry = list; entry; entry = entry->next, count++) ;
      return count;
}

void s_list_free(slist_t **list)
{
      slist_t     *entry;

      while (*list) {
            entry = *list;
            *list = entry->next;
            free(entry);
      }
}

void *s_list_nth_data(slist_t *list, int i)
{
      slist_t     *entry;
      int   count;

      for (count = 0, entry = list; entry; entry = entry->next, count++)
            if (count == i)
                  return entry->data;
      return NULL;
}

void s_list_foreach(slist_t *list, slist_func *func, void *param)
{
      slist_t     *entry;

      if (!func)
            return;
      for (entry = list; entry; entry = entry->next)
            func(entry->data, param);
}

slist_t *s_list_find_custom(slist_t *list, void *data, slist_sort_func *func)
{
      slist_t     *entry;

      if (!func)
            return NULL;
      for (entry = list; entry; entry = entry->next)
            if (func(entry->data, data) == 0)
                  return entry;
      return NULL;
}



Generated by  Doxygen 1.6.0   Back to index