Page 1 of 3 123 LastLast
Results 1 to 15 of 44

Thread: expect на shell, или авто-телнеттинг

  1. #1
    Join Date
    Feb 2007
    Location
    Moscow, Russia
    Posts
    3,805

    как удаленно перезагрузить линуксовый ADSL модем

    В этом треде оказались административно объединены две малосвязанные вещи --- нативная компиляция expect с выложенными бинарниками достаточно древних версий expect и tcl, и весьма любопытный скрипт от cyrax вынесенный в название темы. Читателям, которые интересуются собственно темой треда, рекомендую пропустить первые 11 постов и идти сразу сюда: expect на shell, или авто-телнеттинг

    ----------

    Наблюдается многократно обсуждавшаяся проблема, что при разрыве соединения (предположительно со стороны провайдера), соединение не восстанавливается и в логе возникает (иногда многочасовая) вереница сообщений:

    May 9 11:27:33 pppd[6319]: Timeout waiting for PADO packets
    May 9 11:27:33 pppd[6319]: Unable to complete PPPoE Discovery

    Олег рекомендовал выставить в дополнительных опциях pppd "maxfail 0", у меня в этой строке в веб-интерфейсе не стоит ничего, однако pppd запускается коммандой pppd file /tmp/ppp/options.wan0, и файл /tmp/ppp/options.wan0 содержит:

    PHP Code:
    noauth refuse-eap
    user xxx
    password xxx
    nomppe nomppc
    plugin rp
    -pppoe.so rp_pppoe_service 'stream' nic-vlan1
    mru 1492 mtu 1492
    maxfail 0
    usepeerdns
    persist
    ipcp
    -accept-remote ipcp-accept-local noipdefault
    ktune
    default-asyncmap nopcomp noaccomp
    novj nobsdcomp nodeflate
    lcp
    -echo-interval 10
    lcp
    -echo-failure 6
    unit 0 
    Т.е. эта опция включена по дефолту

    Проблема решается в 95% случаев путем перезагрузки ADSL модема.

    Теперь собственно мой вопрос. Я могу сделать какую-нибудь сторожевую собаку, которая будет проверять лог на предмет этой ошибки и дальше хотелось бы удаленно перезагрузить модем. На модеме стоит тоже линукс, поддерживается логин через ssh и telnet. Как его перезагрузить...?

    Один вариант мне видится таким --- создать специального юзера и сделать ему логин-шелл=/sbin/reboot , но честно говоря это означает модификацию прошивки модема, к чему я морально не готов...

    В идеале хотелось бы что то вроде удаленного sh -c , но ничего подобного не могу найти

    P.S. Провайдер --- стрим, ADSL модем Dlink DSL-500T, wl500gP (7g)
    Last edited by al37919; 16-05-2011 at 14:31.

  2. #2
    Quote Originally Posted by al37919 View Post
    На модеме стоит тоже линукс, поддерживается логин через ssh и telnet. Как его перезагрузить...?

    Один вариант мне видится таким --- создать специального юзера и сделать ему логин-шелл=/sbin/reboot , но честно говоря это означает модификацию прошивки модема, к чему я морально не готов...

    В идеале хотелось бы что то вроде удаленного sh -c , но ничего подобного не могу найти

    P.S. Провайдер --- стрим, ADSL модем Dlink DSL-500T, wl500gP (7g)
    Так вчем проблема? Заходим по SSH и ребутим ... или я не понял вопроса...
    инфа для размышления http://www.lghost.ru/lib/samag/conte...(38)-12-14.pdf
    Last edited by Mirage-net; 09-05-2007 at 10:09.

  3. #3
    Join Date
    Feb 2007
    Location
    Moscow, Russia
    Posts
    3,805
    Спасибо за сценарии на перле. Это как раз то что надо. Я и сам думал что то подобное сделать с помощью expect, но понадеялся может есть готовое решение попроще. Впрочем expect --- тоже гут , жалко нет в пакетах.

  4. #4
    Quote Originally Posted by al37919 View Post
    Спасибо за сценарии на перле. Это как раз то что надо. Я и сам думал что то подобное сделать с помощью expect, но понадеялся может есть готовое решение попроще. Впрочем expect --- тоже гут , жалко нет в пакетах.
    Ну и что что нет в пакетах ... можно самому скомпилить ... но в нем немного не удобно с текстом работать (а ведь нужно лог обрабатывать) в прочем вариантов полно главное идея

  5. #5
    Join Date
    Feb 2007
    Location
    Moscow, Russia
    Posts
    3,805
    но в нем немного не удобно с текстом работать (а ведь нужно лог обрабатывать)
    с этим не соглашусь в корне --- tcl прекрасно поддерживает regexp.

    В общем, в результате, таки откомпилил expect и сделал в нем (лежит у меня все таки душа больше к tcl нежели к perl ). expect отказался кросс-компилиться со следующей ошибкой (выдаваемой ./configure):
    checking if WNOHANG requires _POSIX_SOURCE... configure: error: Expect can't be cross compiled
    Эту ошибку я побороть не смог (если кто понимает как это обойти --- feedback is welcome). В результате сделал нативную компиляцию обоих последних версий (как expect-5.43, так и tcl-8.4.14 ) [tcl пришлось побить на две части, т.к. аттачмент ограничен 1 Мб]. Не ведаю как изготовить ipk путем нативной компиляции, так что прилагаю просто билды как первого, так и второго ( обращаю внимание, что они скомпилены для установки в /opt/local, а не в /opt , так что пути в /opt/local/bin , /opt/local/man , /opt/local/share/man должны быть прописаны куда следует)

    В результате автоматическая перезагрузка ADSL модема у меня выглядит следующим образом (ежепятиминутно наличие соединения проверяется путем запуска из крона):
    /opt/etc/cron.5mins/check_adsl.exp:
    Code:
    #!/bin/sh
    # The following line is executed by /bin/sh and not by expect \
    exec expect -f "$0" ${1+"$@"}
    
    proc check1 {} {
      spawn ping -c 10 www.stream.ru
      expect {
               -re {\d*\sbytes\sfrom\s[\d\.]*:\sicmp_seq=\d*\sttl=\d*\stime=[\d\.]*\sms} exit
             }
      check2
    }
    
    proc check2 {} {
      spawn tail -n 3 /opt/var/log/syslog.log
      expect {
               "Timeout waiting for PADO packets"   reboot_adsl
               "Unable to complete PPPoE Discovery" reboot_adsl
             }
    }
    
    proc reboot_adsl {} {
      spawn telnet 192.168.2.1
      expect -exact "login: "
      send -- "admin\r"
      expect -exact "Password: "
      send -- "XXXXXXXX\r"
      expect -exact $::prompt_adsl
      send -- "reboot\r"
      set timeout 10
      expect
      exec logger "$::argv0\[[pid]\]: Rebooting ADSL modem."
      puts ""
    }
    
    set timeout 60
    
    set prompt_adsl "\r
    # "
    
    check1
    Attached Files Attached Files

  6. #6
    Join Date
    Feb 2007
    Location
    Moscow, Russia
    Posts
    3,805

    expect

    А может как раз expect задействовать [это типа в виде обмена идеи на идею . Он как раз с курсами общаться могет: http://expect.nist.gov/FAQ.html#q22 ]
    http://wl500g.info/showpost.php?p=55065&postcount=5
    Last edited by al37919; 13-05-2007 at 21:33.

  7. #7
    Join Date
    Dec 2003
    Location
    Russian Federation
    Posts
    8,356
    Я думаю, что можно перегрузить его и с помощью wget.

    ЗЫ: у меня DSL-500G, без линуха, работает месяцами без проблем.

    ЗЫЫ: А ещё, я не использую Service Name вообще.

  8. #8
    Join Date
    Feb 2007
    Location
    Moscow, Russia
    Posts
    3,805
    wget??? Т.е. послать через wget ту инструкцию, которая выполняется при нажати кнопки save&reboot или как там она называется? Любопытно попробовать.
    P.S. У этого случается заскок где то раз в неделю. Правда, обычно, когда что то подобное начинается, то повторяется несколько раз довольно часто, потом опять редко. Т.е., похоже, что-то происходит у провайдера. Вообще, для этого зверя тоже есть альтернативная прошивка, надо ее наконец будет попробовать.

  9. #9
    Join Date
    Dec 2003
    Location
    Russian Federation
    Posts
    8,356
    Да, про wget всё правильно. Возможно прийдётся использовать нормальный wget из пакетов. Или curl.

    Что касается СТРИМа, то если перегрузка модема помогает, то дело не в провайдере.

  10. #10
    приклеить к кнопке включения палочку, положить рядом сдюк подключенный к компу, если надо перегрузить, выдвигаем удаленно сидюк, он своим выдвижным столом давит на палочку, та на кнопочку

  11. #11
    Join Date
    Feb 2007
    Location
    Moscow, Russia
    Posts
    3,805
    При нажатии на 'Save and restart' вызывается:
    PHP Code:
    function SaveNBoot()
    {
        if(
    remote_user=="user")
            {
               
    alert("sorry, you're not authorised to modify this page.");
               return 
    false;
            }
        if(
    confirm("Save and restart?"))
        {
            
    document.getElementById("uiPostVarName").name  "logic:command/save";
            
    document.getElementById("pagename").value "../html/tools/restartmodem.htm";
            
    document.getElementById("commandname").value="restart";
            
    document.getElementById("uiPostrestart").value="1";
            
    document.getElementById("pppdisconnect").disabled false;
             
    document.getElementById("uiPostForm1").submit();
         }

    /usr/www/html/tools/restartmodem.htm:
    PHP Code:
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <link rel="stylesheet" href="../html/css/common.css" type="text/css">
    <script language="JavaScript" src="../html/js/menu1.js"></script>
    <script type='text/javascript'>
    function callset()
    {
            if(document.getElementById("uiPostrestart").value == 1)
            {
               <?   if  eq $var:com restart `document.getElementById("uiPostVarName").name = "logic:command/reboot";`
                    
    'document.getElementById("uiPostVarName").name  = "logic:command/defaults";' ?>
                    document.getElementById("uiPostrestart").value = 0;
                    document.getElementById("uiPostForm").submit();
            }
            // modify by Jarry for whether the lan IP change make sure the Reboot or Restore is correct 2005/02/19
            //else
            //{
                    <?      if  eq $var:com restart `setTimeout('document.location.href="http://<? query lan0:static:settings/ip ?>/cgi-bin/webcm?getpage=../html/index.html"', 45000);``<? if eq $var:ip restore `setTimeout('top.location.href="http://<? query lan0:static:settings/ip ?>/cgi-bin/webcm?getpage=../html/index.html"'35000);`
                    
    `setTimeout('document.location.href="../html/index.html"'35000);` ?>?>
            //}

            //setTimeout('document.location.href="http://192.168.1.1/cgi-bin/webcm?getpage=../html/index.html"', 42000);
    }

    </script>
    </head>
    <body topmargin=20 onload="callset()">
    <script type='text/javascript'>
            mainTableStart();
            MapContent();
            logo();
            secondRow();
            ThirdRowStart();
            //Write_Item_Images();//left area
            ThirdRowEnd();
            inTableStart();
    </script>

    <table width=540px border=0 cellpadding=0 cellspacing=0 align=top height="500px">

    <tr>
            <td  colspan=6 height="40" nowrap class="tabhead">Restarting...</td>
    </tr>

    <tr>
         <td class="tabdata" height="50">The system is now restarting. Please wait.</td>
    </tr>

    <tr><td colsapn="6"></td></tr>
    </table>





    <script type='text/javascript'>
            inTableEnd();
            mainTableEnd();
    </script>

    <form method="POST" action="webcm" target="_self" id="uiPostForm" >
    <!--
    <input type="hidden" name="getpage" id="pagename" value="../html/tools/restartmodem.htm">
    -->
    <input type="hidden" name="getpage" id="pagename" value="../html/home/home_wizard.htm">
    <input type="hidden" name="var:restart"   value="<? echo $var:restart ?>" id="uiPostrestart">
    <input type="hidden" id="uiPostVarName" name="" value="">

    </form>

    </body>
    </html>
    т.е. вроде такая страница есть, но каким должен быть url, чтобы вызвать корректное действие... ?
    http://192.168.2.1/tools/restartmodem.htm показывает страницу:
    PHP Code:
    Restarting...
    The system is now restartingPlease wait
    и ничего не делает. Надо передавать параметры... А как их передать если метод POST?

    Вроде с expect все как то проще получается

  12. #12

    expect на shell, или авто-телнеттинг

    Привет,

    да, давно не заходил сюда.

    В общем хочу поделиться недавно написанным скриптом для тех, кому нужен expect (например для автоматической работы через телнет или вроде того).

    Конечно есть пакет py_expect, но он на питоне и это не всегда удобно или возможно. Вот для таких случаев и будет полезен мой скрипт.

    Для начала - пример, как это работает. В качестве примера - получение даты с другого устройства, например на DSL модеме.

    Code:
    #!/bin/sh
    
    . /usr/local/sbin/mini-tools/expect.lib.sh
    # цепляем библиотеку (ее код дан ниже)
    
    expect_open -c telnet 192.168.10.1  
    # использование: expect_open [-c | -e <filename> ] <command> ....
    #опция -с включает дублирование вывода на консоль
    #опция -e включает дублирование вывода в <filename>
    #без опций - вывода нет
    
    expect login
    # ждем строку включающую в себя login - запрос имени пользователя
    
    send_line admin
    # отправляем строку с именем пользователя "admin" и перевод строки
    
    expect_eol
    # ждем перевод строки, который мы же и отправили ;)
    
    expect Password
    send_line password
    expect_eol
    
    expect_exact '#'
    # ждем строку состоящую только из # - запрос от shell'а
    
    expect_echo_start
    # для примера - включение вывода на консоль с этого момента
    
    send_line "date +%s;date +%m%d%H%M%Y.%S"
    expect_eol
    
    expect_capture_start 
    # начало захвата вывода в переменную $EXPECT_OUTPUT, очищает переменную
    
    expect_eol
    # ждем перевода строки, т.е. в $EXPECT_OUTPUT будет вывод от первого date
    
    if [ $EXPECT_OUTPUT -le 86400000 ]; then
    	echo 'Modem time is invalid'
    elif [ $EXPECT_OUTPUT -le `date +%s` ]; then
    	echo 'Modem time is out-of-date'
    else
    	expect_capture_start
    	expect_eol
    	#захватываем строку от второй команды date
    
    	expect_capture_stop
    	echo "Modem time is: $EXPECT_OUTPUT"
    #	date -s $EXPECT_OUTPUT
    fi
    
    expect_close 
    # закрываем запущенный процесс (телнет)
    Ну а теперь все остальное. Немного замудрено конечно с пайпами, но зато не надо в разных файлах ввод и вывод делать.

    Из того, что точно криво сделано - это вхождение строки проверяю через вызов grep, т.к. ~= дает ошибку, а другого способа не знаю.

    И еще не знаю как убрать CR когда он попадает в строку - это вызывает проблему с expect_exact если им ждать вывод с переводом строки.

    Из того, что не доделано - таймаут. Мне он не оч нужен, но это не сложно, и если будут желающие, то постараюсь прикрутить.

    expect.lib.sh
    Code:
    #!/bin/sh
    local EXPECT_APP_PIPE_IN
    local EXPECT_APP_PIPE_OUT
    local EXPECT_APP_ECHO
    local EXPECT_INJECT_LINE
    local EXPECT_OUTPUT
    local EXPECT_CAPTURE=false
    local EXPECT_APP_ID
    
    expect_open () { # $1=echo_file $2+=app
    	case "$1" in		
    		'-e') shift; expect_echo_start "$1"; shift;;
    		'-c') shift; expect_echo_start;;
    		*) expect_echo_stop;
    	esac
    	local RUN="$@"
    	set `dd if=/dev/urandom bs=1 count=4 2>/dev/null|od -D`
    	RND=${2##0000000 }
    	RND=${RND%% 0000004}
    	readonly EXPECT_APP_PIPE_IN=/tmp/tmp.$$.$RND.pipe-in
    	mkfifo $EXPECT_APP_PIPE_IN
    	readonly EXPECT_APP_PIPE_OUT=/tmp/tmp.$$.$RND.pipe-out
    	mkfifo $EXPECT_APP_PIPE_OUT
    	readonly EXPECT_INJECT_LINE="-INJECT-$$-$RND-"
    	$RUN <$EXPECT_APP_PIPE_IN >$EXPECT_APP_PIPE_OUT &
    	EXPECT_APP_ID=$!
    	exec 8>$EXPECT_APP_PIPE_IN #/proc/$EXPECT_APP_ID/fd/1
    	exec 9<$EXPECT_APP_PIPE_OUT
    	usleep 100000 #need to get the spawned app running as it is in background
    }
    
    expect_handle_input () { #$1 - handler #$2+ - handler params
    	local BUFFER
    	local LINE
    	local N_LINE 
    	local RET_RES
    	local HANDLER=$1
    	shift
    	local PARAMS="$@"
    	local HAD_DATA_LINE=false
    	export HAD_DATA_LINE
    	local STOP_LINE=false
    	export STOP_LINE
    	while true; do
    		echo $EXPECT_INJECT_LINE >$EXPECT_APP_PIPE_OUT
    		while read N_LINE <&9; do 
    			STOP_LINE=false
    			LINE="${N_LINE%$EXPECT_INJECT_LINE}"
    			if [ "$N_LINE" == "$LINE" ]; then 
    				HAD_DATA_LINE=true
    				LINE="$BUFFER${LINE%%' '}"
    				BUFFER=""
    				echo "$LINE" >$EXPECT_APP_ECHO
    				if $EXPECT_CAPTURE; then EXPECT_OUTPUT="$EXPECT_OUTPUT$LINE"; fi
    				# FULL-LINE
    				$HANDLER 0 "$LINE" "$@"
    			elif [ "$LINE" ]; then
    				BUFFER="$BUFFER$LINE"
    				LINE="${BUFFER}"
    				# PART-LINE
    				$HANDLER 1 "$LINE" "$@"
    			else
    				STOP_LINE=true
    				# HAD_DATA_LINE? PART-LINE
    				$HANDLER 2 "$LINE" "$@"
    			fi
    			RET_RES=$?;
    			if [ $RET_RES -ne 1 ]; then 
    				if [ "$BUFFER" ]; then
    					echo -n "$LINE" >$EXPECT_APP_ECHO
    					if $EXPECT_CAPTURE; then EXPECT_OUTPUT="$EXPECT_OUTPUT$LINE"; fi
    				fi
    				return $RET_RES
    			elif $STOP_LINE || [ "$BUFFER" ]; then 
    				break
    			fi
    		done
    		if [ ! -d  /proc/$EXPECT_APP_ID ]; then
    			break
    		fi
    		usleep 50000
    	done
    	echo "$BUFFER" >$EXPECT_APP_ECHO
    	if $EXPECT_CAPTURE; then EXPECT_OUTPUT="$EXPECT_OUTPUT$LINE"; fi
    	return 2
    }
    
    __input_handler_match_any () { 
    	if $STOP_LINE && $HAD_DATA_LINE; then
    		return 0
    	fi
    	return 1
    }
    __input_handler_match_all () { 
    	return 1
    }
    __input_handler_match_eol () { 
    	if [ $1 == 0 ]; then
    		return 0
    	fi
    	return 1
    }
    __input_handler_grep () { 
    	if echo "$2" | grep "$3" > /dev/null ; then
    		return 0
    	fi
    	return 1
    }
    
    __input_handler_match () { 
    	local T="${2%% }"
    	if [ "${T## }" == "$3" ]; then
    		return 0
    	fi
    	return 1	
    }
    
    expect_any_line () { 
    	expect_handle_input __input_handler_match_any
    }
    
    expect () { 
    	expect_handle_input __input_handler_grep "$1"
    }
    expect_exact () { 
    	expect_handle_input __input_handler_match "$1"
    }
    expect_eol () { 
    	expect_handle_input __input_handler_match_eol
    }
    send () {
    	echo -n "$@" >&8
    }
    send_line () {
    	echo "$@" >&8
    }
    expect_capture_start () {
    	EXPECT_OUTPUT=''
    	EXPECT_CAPTURE=true
    }
    expect_capture_continue () {
    	EXPECT_CAPTURE=true
    }
    expect_capture_stop () {
    	EXPECT_CAPTURE=false
    }
    expect_echo_start () {
    	if [ "$1" ]; then
    		EXPECT_APP_ECHO="$1"
    	else
    		EXPECT_APP_ECHO=/proc/$$/fd/1
    	fi
    }
    expect_echo_stop() {
    	EXPECT_APP_ECHO='/dev/null'
    }
    expect_close_now() {
    	exec 8>&-
    	exec 9<&-
    	rm $EXPECT_APP_PIPE_IN
    	rm $EXPECT_APP_PIPE_OUT
    }
    expect_close() {
    	exec 8>&-
    	if [ "$EXPECT_APP_ECHO" != '/dev/null' ]; then
    		expect_handle_input __input_handler_match_all
    	fi
    	exec 9<&-
    	rm $EXPECT_APP_PIPE_IN
    	rm $EXPECT_APP_PIPE_OUT
    }
    expect_clean_up() {
    	exec 8>&-
    	exec 9<&-
    	rm /tmp/tmp.$$.*.pipe-in
    	rm /tmp/tmp.$$.*.pipe-out
    }
    Надеюсь будет полезно кому-нить.
    Если что - пишите, но быстрой реакции не обещаю.

  13. #13

    ssh

    Я гашу "детский" комп через ssh. sshd на винде организовать не так уж сложно. Есть пакет copSSH. Это openssh из cygwin оформленный в виде виндового инсталятора. При установке могут быть проблеммы с именем группы Администраторы, тогда надо переименовать на латиницу. Сейчас не помню где было такое, под XP, w2k3 или вистой.
    Я юзаю openssh и другие полезные линуксовые утилиты устанавливая cygwin. В этом случае для запуска sshd доки нужно читать .

  14. #14
    Quote Originally Posted by A1ex View Post
    Я гашу "детский" комп через ssh. sshd на винде организовать не так уж сложно. Есть пакет copSSH. Это openssh из cygwin оформленный в виде виндового инсталятора. При установке могут быть проблеммы с именем группы Администраторы, тогда надо переименовать на латиницу. Сейчас не помню где было такое, под XP, w2k3 или вистой.
    Я юзаю openssh и другие полезные линуксовые утилиты устанавливая cygwin. В этом случае для запуска sshd доки нужно читать .
    A1ex, А вот у меня стоит OpenVPN на "детском" компе. Стало быть он автоматом коннектится к роутеру.

    А вот как "гасть" "детский" комп через OpenVPN пока в голову не пришло...

    У вас есть идеи?

  15. #15
    Quote Originally Posted by A1ex View Post
    Я гашу "детский" комп через ssh. sshd на винде организовать не так уж сложно. Есть пакет copSSH. Это openssh из cygwin оформленный в виде виндового инсталятора. При установке могут быть проблеммы с именем группы Администраторы, тогда надо переименовать на латиницу. Сейчас не помню где было такое, под XP, w2k3 или вистой.
    Я юзаю openssh и другие полезные линуксовые утилиты устанавливая cygwin. В этом случае для запуска sshd доки нужно читать .
    Спасибо большое за идею! Я тут http://www.itefix.no/phpws/index.php...age&PAGE_id=12

    нашел прогу для винды openssh

    Установил, Настроил, РАБОТАЕТ! Теперь гашу "детский" комп "вручную" c Putty-

    ssh username@192.158.1.51
    ввожу password
    shutdown -s

    Хочу это автоматизировать, чтобы запускать кроном...
    и теперь Сделал скрипт-remotepcshutdown.sh
    Code:
    #!/bin/sh
    spawn ssh username@192.158.1.51
    expect "Password:"
    send "password\r"
    send "shutdown -s"
    Но не заработало- выдает-
    Code:
    ./remotepcshutdown.sh: ./remotepcshutdown.sh: 2: spawn: not found
    ./remotepcshutdown.sh: ./remotepcshutdown.sh: 3: expect: not found
    ./remotepcshutdown.sh: ./remotepcshutdown.sh: 4: send: not found
    ./remotepcshutdown.sh: ./remotepcshutdown.sh: 5: send: not found
    А как исправить?

    Спасибо!

Page 1 of 3 123 LastLast

Similar Threads

  1. Ищутся добровольцы с WL500g или WL500b
    By lly in forum Russian Discussion - РУССКИЙ (RU)
    Replies: 19
    Last Post: 31-08-2008, 07:22
  2. Что быстрее: 54g only или Performance?
    By el-pashteto in forum Russian Discussion - РУССКИЙ (RU)
    Replies: 8
    Last Post: 05-12-2007, 20:27
  3. Printing in shell
    By thE_29 in forum WL-500gP Q&A
    Replies: 17
    Last Post: 19-10-2007, 12:40

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •