Модераторы: xvr
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> определения типа файловой системы 
:(
    Опции темы
rukudias
Дата 16.12.2010, 22:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 201
Регистрация: 28.2.2007

Репутация: нет
Всего: 0



Привет всем!

Вопрос собственно как узнать тип файл системы для раздела используя Си?
Те понятно нужно читать файл /dev/sda1 но какой байт в "метадате" определяет тип ФС  ?


Спасибо.
PM MAIL   Вверх
triclosan
Дата 17.12.2010, 01:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 515
Регистрация: 18.8.2006

Репутация: нет
Всего: 12



имхо, стандарта нет
PM MAIL   Вверх
svlary
Дата 17.12.2010, 06:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 207
Регистрация: 8.9.2009

Репутация: 4
Всего: 4



Цитата

как узнать тип файл системы для раздела 

Прочитать файл  /etc/mtab. Он содержит нечто вроде :

Код

rootfs / rootfs rw 0 0                                                                                                             
/dev/root / ext3 rw,noatime,errors=continue,barrier=0,data=writeback 0 0                                                           
proc /proc proc rw,relatime 0 0                                                                                                    
rc-svcdir /lib64/rc/init.d tmpfs rw,nosuid,nodev,noexec,relatime,size=1024k,mode=755 0 0                                           
sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0                                                                               
udev /dev tmpfs rw,nosuid,relatime,size=10240k,mode=755 0 0                                                                        
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620 0 0                                                                
shm /dev/shm tmpfs rw,nosuid,nodev,noexec,relatime 0 0                                                                             
cachedir /lib64/splash/cache tmpfs rw,relatime,size=4096k,mode=644 0 0                                                             
/dev/sda3 /home ext3 rw,noatime 0 0                                                                                                
/dev/sda4 /usr ext3 rw,noatime 0 0                                                                                                 
usbfs /proc/bus/usb usbfs rw,noexec,nosuid,devmode=0664,devgid=85 0 0                                                              
binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,noexec,nosuid,nodev 0 0                                                        
 

По моему - все понятно.
PM MAIL   Вверх
powerfox
Дата 17.12.2010, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I wanna fork()
****


Профиль
Группа: Комодератор
Сообщений: 3990
Регистрация: 1.10.2005
Где: Санкт-Петербург

Репутация: 5
Всего: 97



В линукс есть такая штука, как filesystem id (fs id). Например, у ext3 fs id = 0x83 (Linux native). Посмотреть можно с помощью blkid.
Код

Crypta2:~ # blkid /dev/sdb2 
/dev/sdb2: UUID="da027798-d530-494d-ae20-8029bbdf48e1" TYPE="ext4"

man страница по blkid должна помочь. Ещё можно посмотреть на GUID раздела: GUID_Partition_Table. По идее, тип фс, возможно, берётся оттуда.

Это сообщение отредактировал(а) powerfox - 17.12.2010, 14:48


--------------------
user posted image
PM WWW   Вверх
rukudias
Дата 23.12.2010, 01:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 201
Регистрация: 28.2.2007

Репутация: нет
Всего: 0



Спасибо за ответы!
Возникло дополнительное условие 
Как это все выполнить на Embedded linux  где только BusyBox?

думал на PC вызвать SOMEtrace blkid /dev/sdb2 и посмотреть откуда берётся инфа
но как то с наскока не получилось. 
PM MAIL   Вверх
svlary
Дата 23.12.2010, 06:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 207
Регистрация: 8.9.2009

Репутация: 4
Всего: 4



Цитата(rukudias @  23.12.2010,  01:00 Найти цитируемый пост)
на Embedded linux

  • Не очень понял термин в данном контексте. Слышал про Embedded Windows... А что такое Embedded linux ?
  • Не понял, причем тут BusyBox? Открыть файл /etc/mtab и прочитать его содержимое можно в ЛЮБОЙ коныфигурации.
    Например, на том ARM-е, для которого я сейчас пишу программу, содержимое этого файла выглядит так :
Код

# cat /etc/mtab
rootfs / rootfs rw 0 0
ubi0:rootfs / ubifs rw,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
rc-svcdir /lib/rc/init.d tmpfs rw,nosuid,nodev,noexec,relatime,size=1024k,mode=755 0 0
sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
debugfs /sys/kernel/debug debugfs rw,nosuid,nodev,noexec,relatime 0 0
udev /dev tmpfs rw,nosuid,relatime,size=10240k,mode=755 0 0
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
shm /dev/shm tmpfs rw,nosuid,nodev,noexec,relatime 0 0
ubi0:optfs /opt ubifs rw,compr=zlib 0 0
tmpfs /tmp tmpfs rw,size=1M 0 0
usbfs /proc/bus/usb usbfs rw,noexec,nosuid,devmode=0664,devgid=85 0 0


PM MAIL   Вверх
triclosan
Дата 23.12.2010, 11:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 515
Регистрация: 18.8.2006

Репутация: нет
Всего: 12



Цитата(svlary @  23.12.2010,  06:13 Найти цитируемый пост)
Не очень понял термин в данном контексте. 

Я так понимаю это прошивка к какой-то железке. Автор, если не прав, поправь пожалуйста.
PM MAIL   Вверх
powerfox
Дата 23.12.2010, 23:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I wanna fork()
****


Профиль
Группа: Комодератор
Сообщений: 3990
Регистрация: 1.10.2005
Где: Санкт-Петербург

Репутация: 5
Всего: 97



Цитата(svlary @  23.12.2010,  07:13 Найти цитируемый пост)
Открыть файл /etc/mtab и прочитать его содержимое можно в ЛЮБОЙ коныфигурации.

Это если раздел смонтирован.

Цитата(rukudias @  23.12.2010,  02:00 Найти цитируемый пост)
думал на PC вызвать SOMEtrace blkid /dev/sdb2 и посмотреть откуда берётся инфа

Скачайте исходники и посмотрите.
Цитата(svlary @  23.12.2010,  07:13 Найти цитируемый пост)
Не очень понял термин в данном контексте. Слышал про Embedded Windows... А что такое Embedded linux ?

http://en.wikipedia.org/wiki/Embedded_Linux



--------------------
user posted image
PM WWW   Вверх
svlary
Дата 24.12.2010, 06:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 207
Регистрация: 8.9.2009

Репутация: 4
Всего: 4




Там написано : 
Цитата

Embedded Linux is the use of Linux in embedded computer systems such as mobile phones, personal digital assistants

Т.е. ничего конкретного... Про ОС, которая стоит на девайсе, для которого я пишу ПО, я могу сказать, что это Gentoo 2008 года. Windows embeded - это тоже вполне конкретный вариант ОС Windows. Вот я и хотел уточнить. Как написано в правилах форума :
Цитата

Телепатов на форуме нет!

Насколько я понял первоначальную постановку вопроса, речь не идет о том, что бы определять тип ФС на этапе загрузки ОС.
Поэтому :
Цитата

Это если раздел смонтирован.

я думаю, выполняется...

Добавлено через 11 минут и 40 секунд
Цитата(triclosan @ 23.12.2010,  11:08)
Цитата(svlary @  23.12.2010,  06:13 Найти цитируемый пост)
Не очень понял термин в данном контексте. 

Я так понимаю это прошивка к какой-то железке. Автор, если не прав, поправь пожалуйста.

Цитата

это прошивка к какой-то железке

  Не совсем понял, что имеется в виду под словом "прошивка" ?
То, что я привел, это просто содержимое файла /etc/mtab !  В моем сообщении прямо написано :
Код

# cat /etc/mtab

Если Вы удивляетесь, почему там нет строк, содержащих /dev/sda.... то это просто потому, что в моей железяке нет винчестеров, только память на флэшках. А для инструментального моего компа, этот фай имеет вид :

Код

# cat /etc/mtab
rootfs / rootfs rw 0 0
/dev/root / ext3 rw,noatime,errors=continue,barrier=0,data=writeback 0 0
proc /proc proc rw,relatime 0 0
rc-svcdir /lib64/rc/init.d tmpfs rw,nosuid,nodev,noexec,relatime,size=1024k,mode=755 0 0
sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
udev /dev tmpfs rw,nosuid,relatime,size=10240k,mode=755 0 0
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620 0 0
shm /dev/shm tmpfs rw,nosuid,nodev,noexec,relatime 0 0
cachedir /lib64/splash/cache tmpfs rw,relatime,size=4096k,mode=644 0 0
/dev/sda3 /home ext3 rw,noatime 0 0
/dev/sda4 /usr ext3 rw,noatime 0 0
usbfs /proc/bus/usb usbfs rw,noexec,nosuid,devmode=0664,devgid=85 0 0
binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,noexec,nosuid,nodev 0 0
//192.168.21.46/Net_Buf /mnt/zebra cifs rw,mand 0 0


PM MAIL   Вверх
powerfox
Дата 25.12.2010, 13:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


I wanna fork()
****


Профиль
Группа: Комодератор
Сообщений: 3990
Регистрация: 1.10.2005
Где: Санкт-Петербург

Репутация: 5
Всего: 97



Цитата(svlary @  24.12.2010,  07:26 Найти цитируемый пост)
Т.е. ничего конкретного...

Само понятие «Embedded» довольно размыто. Это может быть мобильник, а может быть стиральная машина. Часто с Embedded Linux связывают Realtime Linux.

Цитата(svlary @  24.12.2010,  07:26 Найти цитируемый пост)
То, что я привел, это просто содержимое файла /etc/mtab !  В моем сообщении прямо написано :

При загрузке необязательно монтировать разделы. Более того монтирование раздела может его модифицировать.
Ваше решение рабочее и простое, но это workaround, а не generic.


--------------------
user posted image
PM WWW   Вверх
bsa
Дата 27.12.2010, 23:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 16
Всего: 196



читать /etc/mtab нет никакого смысла. уж лучше /proc/mounts.
Но более надежно посмотреть исходники udev. 
Вот еще код из nash:
Код
/*
 * taken from util-linux 2.11g and hacked into nash
 *
 * mount_by_label.c - aeb
 *
 * 1999-02-22 Arkadiusz Mi<B6>kiewicz <[email protected]>
 * - added Native Language Support
 * 2000-01-20 James Antill <[email protected]>
 * - Added error message if /proc/partitions cannot be opened
 * 2000-05-09 Erik Troan <[email protected]>
 * - Added cache for UUID and disk labels
 * 2000-11-07 Nathan Scott <[email protected]>
 * - Added XFS support
 */

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include "linux_fs.h"
#include "mount_by_label.h"

#define PROC_PARTITIONS "/proc/partitions"
#define DEVLABELDIR     "/dev"

#define _(str) (str)

static struct uuidCache_s {
        struct uuidCache_s *next;
        char uuid[16];
        char *device;
        char *label;
        int major, minor;
} *uuidCache = NULL;

typedef int (*GetLabelUuidProc)(int fd, char **label, char *uuid);

static int get_label_uuid_ext2(int fd, char **label, char *uuid);
static int get_label_uuid_xfs(int fd, char **label, char *uuid);
static int get_label_uuid_reiserfs(int fd, char **label, char *uuid);

/* for now, only ext2, ext3, reiserfs and xfs are supported */
static const 
GetLabelUuidProc get_label_uuid_proc_table[] =
{
        get_label_uuid_ext2,
        get_label_uuid_reiserfs,
        get_label_uuid_xfs,
        NULL
};

static int 
get_label_uuid_ext2(int fd, char **label, char *uuid)
{
        struct ext2_super_block e2sb;
        if ( ( lseek(fd, 1024, SEEK_SET) == 1024 )
                        && read(fd, (char *) &e2sb, sizeof(e2sb)) == sizeof(e2sb)
                        && (ext2magic(e2sb) == EXT2_SUPER_MAGIC)) {
                size_t namesize;
                memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid));
                namesize = sizeof(e2sb.s_volume_name);
                if ((*label = calloc(namesize + 1, 1)) != NULL)
                        memcpy(*label, e2sb.s_volume_name, namesize);
                return 0;
        }
        return 1;
}

static int 
get_label_uuid_xfs(int fd, char **label, char *uuid)
{
        struct xfs_super_block xfsb;
        if ( (lseek(fd, 0, SEEK_SET) == 0)
                        && (read(fd, (char *) &xfsb, sizeof(xfsb)) == sizeof(xfsb) )
                        && (strncmp((const char*)xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0) ) {
                size_t namesize;
                memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid));
                namesize = sizeof(xfsb.s_fname);
                if ((*label = calloc(namesize + 1, 1)) != NULL)
                        memcpy(*label, xfsb.s_fname, namesize);
                return 0;
        }
        return 1;
}

static inline int reiserfs_magic_version(const char *magic)
{
        int rc = 0;
        if ( !strncmp(magic, REISERFS_SUPER_MAGIC_STRING, strlen(REISERFS_SUPER_MAGIC_STRING)) )
                rc = 1;
        if ( !strncmp(magic, REISER2FS_SUPER_MAGIC_STRING, strlen(REISER2FS_SUPER_MAGIC_STRING)) )
                rc = 2;
        if ( !strncmp(magic, REISER3FS_SUPER_MAGIC_STRING, strlen(REISER3FS_SUPER_MAGIC_STRING)) )
                rc = 3;
        return rc;
}                                                                                                                                                       
                                                                                                   

static int 
get_label_uuid_reiserfs(int fd, char **label, char *uuid)
{
        struct reiserfs_super_block reiserfssb;
        if ( (lseek(fd, REISERFS_DISK_OFFSET_IN_BYTES, SEEK_SET) == REISERFS_DISK_OFFSET_IN_BYTES)
                        && ( read(fd, (char *) &reiserfssb, sizeof(reiserfssb)) == sizeof(reiserfssb) )
                        /* Only 3.6.x format supers have labels or uuids. 
                        Label and UUID can be set by reiserfstune -l/-u. */
                        && (reiserfs_magic_version((const char*)reiserfssb.s_magic) > 1) ) {

                size_t namesize;
                memcpy(uuid, reiserfssb.s_uuid, sizeof(reiserfssb.s_uuid));
                namesize = sizeof(reiserfssb.s_label);
                if ((*label = calloc(namesize + 1, 1)) != NULL)
                        memcpy(*label, reiserfssb.s_label, namesize);
                return 0;
    }
        return 1;
}

static int
get_label_uuid(const char *device, char **label, char *uuid)
{
        int fd;
        int rv = 1;
        const GetLabelUuidProc *proc = get_label_uuid_proc_table;

        fd = open(device, O_RDONLY);
        if (fd < 0)
                return rv;

        while(*proc) {
                rv = (*proc)(fd, label, uuid);
                if ( !rv )
                        break;
                ++proc;
        }

        close(fd);
        return rv;
}

static void
uuidcache_addentry(char * device, int major, int minor, char *label, char *uuid) {
        struct uuidCache_s *last;
    
        if (!uuidCache) {
                last = uuidCache = malloc(sizeof(*uuidCache));
        } else {
                for (last = uuidCache; last->next; last = last->next) ;
                last->next = malloc(sizeof(*uuidCache));
                last = last->next;
        }
        last->next = NULL;
        last->label = label;
        last->device = device;
        last->major = major;
        last->minor = minor;
        memcpy(last->uuid, uuid, sizeof(last->uuid));
}

static void
uuidcache_init(void) {
        char line[100];
        char *s;
        int ma, mi, sz;
        static char ptname[100];
        FILE *procpt;
        char uuid[16], *label;
        char device[110];
        int firstPass;
        int handleOnFirst;
        char * chptr, * endptr;

        if (uuidCache)
                return;

        procpt = fopen(PROC_PARTITIONS, "r");

        if (!procpt) {
                static int warn = 0;
                if (!warn++)
                    fprintf (stderr, _("mount: could not open %s, so UUID and LABEL "
                             "conversion cannot be done.\n"),
                       PROC_PARTITIONS);
                return;
        }

        for (firstPass = 1; firstPass >= 0; firstPass--) {
            fseek(procpt, 0, SEEK_SET);

            while (fgets(line, sizeof(line), procpt)) {
                /* The original version of this code used sscanf, but
                   diet's sscanf is quite limited */
                chptr = line;
                if (*chptr++ != ' ') continue;

                ma = strtol(chptr, &endptr, 0);
                if (endptr == chptr) continue;
                while (isspace(*endptr)) endptr++;
                chptr = endptr;

                mi = strtol(chptr, &endptr, 0);
                if (endptr == chptr) continue;
                while (isspace(*endptr)) endptr++;
                chptr = endptr;

                sz = strtol(chptr, &endptr, 0);
                if (endptr == chptr) continue;
                while (isspace(*endptr)) endptr++;
                chptr = endptr;

                while (!isspace(*endptr) && *endptr != '\n') endptr++;
                if (chptr == endptr) continue;
                strncpy(ptname, chptr, endptr - chptr);

                ptname[endptr - chptr] = '\0';

                /* skip extended partitions (heuristic: size 1) */
                if (sz == 1)
                        continue;

                /* look only at md devices on first pass */
                handleOnFirst = !strncmp(ptname, "md", 2);
                if (firstPass != handleOnFirst)
                        continue;

                /* skip entire disk (minor 0, 64, ... on ide;
                   0, 16, ... on sd) */
                /* heuristic: partition name ends in a digit */

                for(s = ptname; *s; s++);

                if (isdigit(s[-1])) {
                        char * ptr;
                        char * deviceDir = NULL;
                        int mustRemove = 0;
                        int mustRemoveDir = 0;
                        int i;

                        snprintf(device, 110, "%s/%s", DEVLABELDIR, ptname);
                        if (access(device, F_OK)) {
                            ptr = device;
                            i = 0;
                            while (*ptr)
                                if (*ptr++ == '/')
                                    i++;
                            if (i > 2) {
                                deviceDir = alloca(strlen(device) + 1);
                                strcpy(deviceDir, device);
                                ptr = deviceDir + (strlen(device) - 1);
                                while (*ptr != '/')

                                    *ptr-- = '\0';
                                if (mkdir(deviceDir, 0644)) {
                                    printf("mkdir: cannot create directory %s: %d\n", deviceDir, errno);
                                } else {
                                    mustRemoveDir = 1;
                                }
                            }

                            mknod(device, S_IFBLK | 0600, makedev(ma, mi));
                            mustRemove = 1;
                        }
                        if (!get_label_uuid(device, &label, uuid))
                                uuidcache_addentry(strdup(device), ma, mi, 
                                                   label, uuid);

                        if (mustRemove) unlink(device);
                        if (mustRemoveDir) rmdir(deviceDir);
                }
            }
        }

        fclose(procpt);
}

#define UUID   1
#define VOL    2

static char *
get_spec_by_x(int n, const char *t, int * majorPtr, int * minorPtr) {
        struct uuidCache_s *uc;

        uuidcache_init();
        uc = uuidCache;

        while(uc) {
                switch (n) {
                case UUID:
                        if (!memcmp(t, uc->uuid, sizeof(uc->uuid))) {
                                *majorPtr = uc->major;
                                *minorPtr = uc->minor;
                                return uc->device;
                        }
                        break;
                case VOL:
                        if (!strcmp(t, uc->label)) {
                                *majorPtr = uc->major;
                                *minorPtr = uc->minor;
                                return uc->device;
                        }
                        break;
                }
                uc = uc->next;
        }
        return NULL;
}

static unsigned char
fromhex(char c) {
        if (isdigit(c))
                return (c - '0');
        else if (islower(c))
                return (c - 'a' + 10);
        else
                return (c - 'A' + 10);
}

char *
get_spec_by_uuid(const char *s, int * major, int * minor) {
        unsigned char uuid[16];
        int i;

        if (strlen(s) != 36 ||
            s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
                goto bad_uuid;
        for (i=0; i<16; i++) {
            if (*s == '-') s++;
            if (!isxdigit(s[0]) || !isxdigit(s[1]))
                    goto bad_uuid;
            uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
            s += 2;
        }
        return get_spec_by_x(UUID, (const char*)uuid, major, minor);

 bad_uuid:
        fprintf(stderr, _("mount: bad UUID"));
        return 0;
}

char *
get_spec_by_volume_label(const char *s, int * major, int * minor) {
        return get_spec_by_x(VOL, s, major, minor);
}

int display_uuid_cache(void) {
        struct uuidCache_s * u;
        size_t i;

        uuidcache_init();

        u = uuidCache;
        while (u) {
            printf("%s %s ", u->device, u->label);
            for (i = 0; i < sizeof(u->uuid); i++) {
                if (i == 4 || i == 6 || i == 8 || i == 10)
                    printf("-");
                printf("%x", u->uuid[i] & 0xff);
            }
            printf("\n");
            u = u->next;
        }

        return 0;
}

PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.1533 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.