Month: March 2013

  • InnoDB Storage Engine Data Recovery สำหรับ MySQL database

    ปัญหาของการลืม password ของ root ของ MySQL ไม่ได้เป็นปัญหาเดียวที่ผมเจอ ในเรื่องของการใช้งาน MySQL Database Server ถึงแม้จะไม่บ่อยนัก แต่ก็บ่อยมากพอที่จะทำให้ ใน 2-3 ครั้งให้หลัง ผม “จำ” วิธีการแก้ปัญหาได้ โดยไม่ต้องพึ่งพา google อีกต่อไป

    ถ้าจะว่าไป ถ้าปัญหานี้ เกิดขึ้น “บ่อย” กว่าเดิมอีกซักหน่อย ผมก็คง “จำ” root password ได้ (เพราะต้องใช้บ่อยขึ้น) และส่งผลในทางกลับ ทำให้ ไม่ลืม root password และทำให้ปัญหานี้ไม่ใช่ปัญหาอีกต่อไป — ฟังดูย้อนแย้ง ชวนขยักขย่อน หรือเปล่าครับ 🙂

    แต่ไม่ว่าอย่างไร … การลืม password ในระดับสร้างความหงุดหงิดรำคาญใจแค่นั้นเอง ความรู้สึกอย่างมากก็คือ “ลืมอีกแล้ว ต้องรีเซ็ทพาสเวิร์ดอีกรอบ งี่เง่าจริงๆ!”  แต่มีปัญหาอีกอย่างที่ … ไม่ได้เกิดขึ้นบ่อย … นานๆเกิดที แต่พอเกิดขึ้นมาแล้ว ทำให้ระดับความเครียดของ sysadmin พุ่งขึ้นสูงอย่างฉับพลัน

    ปัญหาแบบที่ว่า เกิดขึ้น ในลักษณะนี้ ครับ นี่คือข้อความทีี่มีอยู่ในไฟล์ “/var/log/mysql/error.log”

    InnoDB: Database was not shut down normally!
    InnoDB: Starting crash recovery.
    InnoDB: Reading tablespace information from the .ibd files...
    InnoDB: Restoring possible half-written data pages from the doublewrite
    InnoDB: buffer...
    InnoDB: Doing recovery: scanned up to log sequence number 7 3581528990
    InnoDB: Error: page 4 log sequence number 7 3581552218
    InnoDB: is in the future! Current system log sequence number 7 3581528990.
    InnoDB: Your database may be corrupt or you may have copied the InnoDB
    InnoDB: tablespace but not the InnoDB log files. See
    InnoDB: http://dev.mysql.com/doc/refman/5.1/en/forcing-recovery.html
    InnoDB: for more information.

    ก่อนที่จะมาถึงที่จุดนี้ อาการของตัว mysql server ก็คือว่า load ของ mysqld ตัว daemon ทำงานอยู่แกว่งอยู่ในช่วง 90-100% อยู่ตลอดเวลา หลังจาก boot เครื่องขึ้นมา และถึงแม้จะไม่มีการใช้งาน mysql server จาก process อื่นๆเลย (ผมทดสอบโดยการ shutdown ตัว web server ซึ่งเป็น client เพียงตัวเดียวที่ใช้งาน mysql server อยู่) ก็ไม่ได้ทำให้ load ของตัว mysqld ลดลง

    หลังจากลองตรวจสอบจาก system log ของระบบ จนไปเจอข้อความข้างบนใน error log ของ mysql เองก็เลยรู้ว่าปัญหาอยู่ที่ ไฟล์ที่บันทึกข้อมูล/transaction ของ MySQL มีปัญหา

    ปัญหานั้นมาจากใหน? ปัญหาเกิดขึ้นจากข้อมูลของ MySQL database ที่ผมได้มานั้น ได้มาจากการ copy (อันที่จริง rsync — แต่นั่นไม่ใช่ประเด็น)  ไฟล์ข้อมูลของ MySQL database ในขณะที่ตัว database server ยังเปิดใช้งานอยู่

    เมื่อมาคิดอีกทีในตอนหลัง วิธีการที่ดีกว่าสำหรับการ copy database มาครั้งนั้น สิ่งที่ควรจะทำก็คือการ dump database โดยใช้คำสั่ง mysqldump แล้วเอาไฟล์ sql ที่ได้จากการ dump อันนั้นมา import กลับเข้า  database อีกทีในตอนหลัง

    แต่จะว่าไปชีวิตของ admin ก็ไม่ง่ายอย่างนั้น ข้อแรกการที่ผมจะ dump ข้อมูลจาก database server ออกมาทั้งหมดได้ ผมจะต้องรู้ root password ของ database server อันนั้น … ถึงแม้ผมจะสามารถใช้สิทธิของ root บนระบบนั้นๆได้ แต่ … ผมไม่รู้ทั้ง root password ของ system และ ไม่รู้ root password ของ mysql ด้วยเหมือนกัน … อ้าว งั้นก็ reset root password ของ mysql เสียก่อนสิ โดยใช้วิธีการที่ผมได้อธิบายไปแล้ว ในบันทึกที่แล้ว … จะมีปัญหาอะไรล่ะ? มีครับ ระบบที่ว่ามีการใช้งานอยู่ตลอดเวลา database server เป็นองค์ประกอบสำคัญ ในขณะนั้นผมไมแน่ใจว่า การที่จะ shutdown และ restart mysql server จะส่งผลกระทบต่อการทำงานของส่วนอื่นๆของระบบอย่างไรบ้าง ถ้า restart ตัว database server แล้ว การทำงานส่วนอื่นๆที่เหลือ จะกลับมาทำงานได้ตามปกติหรือเปล่า? หรือผมจะต้อง restart สซอฟต์วแร์ส่วนอื่นๆที่เกี่ยวข้องด้วย? … ผมไม่มีคำตอบในขณะนั้น และไม่อยากจะเสี่ยงหาคำตอบบนระบบที่มีคนใช้งานอยู่จริง (แบบว่ากล้วน่ะครับ ทำงานเป็น admin มาหลายปี ก็ยังทำใจไม่ได้ครับ)

    ผมมี database อยู่ในมือแล้ว มันมีปัญหา ก็ซ่อมมันสิ … สมมติว่า database ตัวที่ใช้งานจริงมีปัญหาแบบเดียวกัน จะทำยังไง? ก็ต้องหาวิธีการแก้ไขแบบเดียวกันใช่ใหม?

    เอ่อ … อันที่จริง วิธีการที่ดีกว่า สำหรับ ระบบที่ใช้งานอยู่จริงๆ ก็คือ “ป้องกัน” และ “สำรอง” ครับ แต่ในขณะที่ผมยังไม่มี ระบบที่ว่าอยู่ในมือ ก็สมมติเอาก่อนแล้วกันว่า ผมเจอปัญหากับ database พัง แล้วต้องหาวิธีการกู้ database ให้กลับมาใช้งานให้ได้ …

    โอเค, งั้นก็ได้ เริ่มกันเลย ใน error message ของ mysql เองก็มี URL ให้อยู่แล้ว ดีกว่าระบบอื่นๆอีก 2-3 ระบบที่ผมเคยเจอมา นอกเหนือจากจะไม่มีตัวช่วย ที่จะชี้ว่าจะไปหาข้อมูลเพิ่ม เพื่อแก้ปัญหาได้ที่ใหน ข้อมูลเกีี่ยวกับ error ที่แสดงออกมายัง มากเกินความจำเป็น ข้อมูลที่สำคัญที่เกี่ยวกับข้อผิดพลาด ถูกซ่อนเอาไว้ในกองของข้อมูลอื่นที่ไม่เกี่ยวข้อง ที่นอกจากจะไม่ช่วยในการแก้ปัญหาแล้ว ยังช่วยให้หลงทางอีกต่างหาก

    นี่, มี URL ให้แล้ว http://dev.mysql.com/doc/refman/5.1/en/forcing-recovery.html ก็เปิด web browser ขึ้นมาอ่านเลยสิ

    ถ้าคุณอ่านมาจนถึงบรรทัดนี้แล้ว และจะลอง ตัด/แปะ URL อันที่ว่านี่ใน web browser ดูนะครับ คุณก็จะเจอว่า

    แป่ว … Page Not Found …

    อันนี้ ไม่ใช่ว่า MySQL version 5.1 มันจะเก่าจนเกินไปนะครับ เพราะถ้าลองหาอย่างอื่นดู ในส่วนของ reference/manual ก็จะหาเจอ แต่ว่า ส่วนของ forcing-recovery สำหรับ InnoDB Engine อันที่จริงแล้ว อยู่ที่นี่ครับ

    http://dev.mysql.com/doc/refman/5.1/en/forcing-innodb-recovery.html

    มี bug อยู่ใน error message ของ MySQL ครับ

    แต่ถึงกระนั้น หลังจากลองทำตามดูตามคำแนะนำ ใน page ที่ว่านี่แล้ว (ปรับค่า innodb_force_recovery ขึ้นไปเรื่อยๆ แล้ว restart mysql ดู) ก็ยังมีปัญหาอย่างเดิม ยังไม่สามารถแก้ปัญหาได้

    อาจจะเป็นกรณีที่โชคยังดีอยู่บ้าง ตรงที่ว่า ถึงแม้จะมี error เกิดขึ้นแต่ตัว server ก็ยังทำงานได้ และรับการติดต่อจากตัว mysql client แสดงว่าส่วนของฐานข้อมูลที่มีปัญหา “น่าจะ” (ผมเดาเอา) ยังไม่ร้ายแรงมาก เมื่อลอง query ข้อมูลดูบางส่วนก็ปรากฏว่ายังใช้งานได้ หลังจากลองทำตามคำแนะนำใน mysql document เองแล้วงยังไม่ work หาอ่านคำแนะนำจากที่อื่น มีคำแนะนำให้ dump database ออกมา แล้วค่อยใส่กลับเข้าไปใหม่ ผมก็เลยลองดู …

    ปรากฏว่า วิธีการนี้สามารถใช้งานได้ มีขั้นตอนที่ผมลองผิดลองถูกเพิ่มขึ้นอีกหน่อยนึง ถึงจะทำให้ database กลับมาใช้งานได้ ก็เลยคิดว่าจะเอามาบันทึกไว้ที่นี่

    โดยสรุป: ผมยังไม่รู้วิธีการที่จะแก้ปัญหาทั้งหมดนะครับ สมมติว่า ถ้า database เกิดพังมากกว่านี้ วิธีการนี้ก็อาจจะใช้งานไม่ได้ (ผมเคยลองพัง database ที่ใช้ InnoDB engine แล้ว ปรากฏว่า mysqld ไม่สามารถ start ขึ้นมาทำงานได้ … ซึ่งถ้าเป้นกรณีนั้น วิธีการที่ผมจะพูดถึงก็ไม่มีประโยชน์อะไรเหมือนกัน) แต่ถ้ามันอาการแย่กว่า แบบที่ document ของ MySQL แนะนำเอาไว้แล้ว ทำตามแล้วยังมีปัญหาอยู่ วิธีการนี้ก็อาจจะมีประโยชน์อยู่บ้างในบางระดับ … ผมหวังเอาไว้อย่างนั้นนะครับ

    โดยหลักแล้วก็คือ การ dump database ออกมาเป็น sql file แล้วก็ import กลับเข้าไปแค่นั้นเองครับ … ในกรณีนี้ ผมยังไม่รู้ root password ของ mysql และ ผมจะเปลี่ยนมันทหลัง แต่ในตอนนี้ผมต้องการให้ database ทั้งหมดถูกต้อง และ mysql server กลับมาทำงานได้ โดย load ไม่ได้อยู่ที่ 90-100% ตลอดเวลาก่อน

    ขั้นตอน

    $ sudo service mysql stop
    $ sudo /usr/sbin/mysqld --skip-grant-tables &
    $ MYPID=$!
    $ mysqldump --all-databases > all.sql
    $ sudo kill -QUIT $MYPID

    เพื่อที่จะให้สามารถ dump database ได้ โดยที่ผมไม่รู้ root password ผมก็ต้องให้ mysql ทำงานใน mode ที่ไม่ตรวจสอบ privileges โดยการใช้ option “–skip-grant-tables” ซึ่งหลังจากนั้น ก็จะทำให้ผมใช้คำสั่ง mysqldump สำหรับ dump database ได้ เมื่อใช้ option –all-databases ก็จะเป็นการ dump ทุกๆ database ที่มีอยู่ และเก็บลงในไฟล์ชื่อ all.sql

    หลังจาก dump เสร็จก็ terminate mysqld process โดยการส่ง SIGQUIT signal ให้กับ process ของ mysqld

    หลังจากนี้ เพื่อที่จะเก็บ ข้อมูลเดิมทั้งหมดเอาไว้ก่อน ผมก็จะย้าย directory ที่เก็บข้อมูลของ mysql ไปเก็บไว้ในชื่อ mysql.0 และสร้าง directory สำหรับ mysql ขึ้นมาใหม่ โดยการใช้คำสั่งต่อไปนี้ครับ

    $ sudo mv /var/lib/mysql /var/lib/mysql.0
    $ sudo mkdir /var/lib/mysql
    $ sudo chown mysql:mysql /var/lib/mysql
    $ sudo chmod 700 /var/lib/mysql

    หลังจากนั้นก็จะเป็นการ import ข้อมูลของ mysql กลับเข้าไป ซึ่งก็ต้อง start mysql server กลับขึ้นมาอีกรอบ และให้มันสร้างไฟล์อื่นๆที่จำเป็นใน mysql directory

    $ sudo /usr/sbin/mysqld --skip-grant-tables &
    $ MYPID=$!
    $ mysql < all.sql
    $ sudo kill -QUIT $MYPID
    
    

    ถึงขั้นตอนนี้ database ที่เรา dump ออกมาในตอนแรกก็ถูก import กลับเขาไปใน database อีกครั้ง รวมทั้ง privileges และ password ทั้งหมดด้วย ซึ่งเราสามารถใช้คำสั่ง

    $ sudo service mysql start

    เพื่อให้ database กลับมาทำงานตามปกติ

    ซึ่งในกรณีของผม ตัว database สามารถกลับมาทำงานได้ load ของ mysqld กลับเข้าสู่สภาวะปกติ (เข้าใกล้ 0 เมื่อไม่มีการใช้งาน) ไม่มีข้อความแสดง error ในไฟล์ /var/log/mysql/error.log จะมีแต่ข้อความแสดงการทำงานตามปกติ) และตัว application ที่ใช้งาน database ใช้งานได้อย่างถูกต้อง

    ผมอาจจะแค่โชคดี สำหรับการซ่อมแซม database ที่พังเสียหายในกรณีนี้ แต่คิดว่าบันทึกในสิ่งที่ทำไว้ ก็อาจจะมีประโยชน์สำหรับคนที่อาจจะเจอเหตุการณ์แบบเดียวกันครับ

  • Solved Firefox browser with adobe flash player outdated

    ผมรัน Firefox browser แล้วพบว่ามันจะแจ้งว่า Adobe Flash Player Plugin ไม่ปลอดภัยเนื่องจาก Outdated จึงคลิกเข้าไปในหน้า Addons แล้ว ดาวน์โหลดจากเว็บ http://get.adobe.com/flashplayer/ ได้ไฟล์ install_flash_player_11_linux.x86_64.tar.gz จากนั้นแตกไฟล์ออกมาอย่างง่ายๆ เพราะใช้ GUI อยู่ ได้ไฟล์มาดังนี้

    libflashplayer.so และไดเรกทอรี usr

    flashplayer-outdated

    แล้วเปิดอ่าน readme.txt สั่งว่าให้อัปเดตแบบ manual ก็ต้องทำตาม ทั้งๆที่อยากทำแบบคลิกๆๆๆ จะสะดวกสำหรับผู้ใช้มากกว่า

    ตอนนี้ผมอยู่ที่หน้าต่าง terminal ของ linux mint ทำตามดังนี้

    sudo cp libflashplayer.so /opt/mint-flashplugin-11/
    sudo cp -r usr/* /usr

    รัน firefox ใหม่ ตอนนี้ใช้งานได้แล้ว

    หมายเหตุ

    เครื่องที่ใช้งานคือ

    ผมใช้คำสั่ง cat /etc/lsb-release ได้ดังนี้

    DISTRIB_ID=LinuxMint
    DISTRIB_RELEASE=13
    DISTRIB_CODENAME=maya
    DISTRIB_DESCRIPTION="Linux Mint 13 Maya"

    ผมใช้คำสั่ง uname -a ได้ดังนี้

    Linux HP-ProBook-6450b 3.2.0-39-generic #62-Ubuntu SMP Thu Feb 28 00:28:53 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

    จบครับ

  • Script สำหรับการ reset mysql root’s password

    สำหรับ admin ของ Linux Server โดยทั่วไปแล้ว มักจะหลีกไม่พ้นที่จะต้อง ติดตั้ง database server สักครั้งนึง เพราะว่า สำหรับ application โดยส่วนใหญ่แล้ว โดยเฉพาะ web application ในปัจจุบัน มักจะต้องการใช้ database server เป็น backend สำหรับการเก็บข้อมูล

    และบน Linux ส่วนใหญ่ก็จะหนีไม่พ้นการใช้งาน MySQL เป็น Server … เพราะเป็นตัวที่มีคนใช้กันมากที่สุด และรองรับโดยหลายๆ framework ของ Web App ทั้งหลาย

    แน่นอน ตอนที่ติดตั้งครั้งแรก ตัวซอฟต์แวร์ที่ใช้ในการติดตั้ง ก็ถาม root password ของ MySQL สำหรับการ กำหนดสิทธิในการใช้งาน

    สำหรับคนที่ใช้งาน database server มานานระดับหนึ่ง ก็จะรู้ว่า password ที่จะใช้สำหรับ root ของ MySQL นั้น ไม่จำเป็นจะต้องเป็นตัวเดียวกับ root password ของระบบ … และ ไม่ควรที่จะเป็นตัวเดียวกัน … สำหรับคนที่ไม่รู้ในเรื่องนี้ ก็มักจะต้อง “เรียนรู้” ด้วยความยากลำบากในทีหลัง … ผมรู้สิน่า ผม “จ่าย” ค่าเล่าเรียนเรื่องนี้ด้วยราคาที่ “แพง” พอสมควรเชียวล่ะ

    หลังจากที่รู้แล้วว่า มัน “จะต้อง” ไม่ใช่ password เดียวกันกับ password ที่สำคัญของระบบ ปัญหาที่จะตามมาก็คือว่า เราก็อาจจะตั้ง password ของ root ของ MySQL แบบง่ายๆ เช่น “1234”, “abcd” อะไรทำนองนี้ เพราะว่า ในแง่ของการให้บริการ MySQL server ก็มักจะให้บริการกับ “client” ท่อยู่บนเครื่องเดียวกัน ไม่ได้ให้บริการผ่าน network ไปให้เครื่องอื่นๆ หรือ ถ้าจำเป้นจะต้องให้บริการ ก้ให้บริการกับ server  ที่อยู่ใน cluster เดียวกัน จะมีเฉพาะ admin ด้วยกันที่จะรู้ว่ามี mysql ให้บริการอยู่บนเครื่องนี้

    แน่นอน ความคิดเช่นนี้ ก็มักจะนำบทเรียน “ราคาแพง” บทที่สอง เกี่ยวกับ root password ของ mysql มาให้ อีกเหมือนกัน และมันมักจะพ่วงมากับ “phpmyadmin” ที่จะทำให้ ตัว mysql server ซึ่งเคยเข้าใจว่า “ไม่สามารถเข้าถึงจาก server อื่นๆได้” กลับเข้าถึงได้ง่ายๆ ผ่าน “web” และเมื่อเจอกับ bot ที่โจมตีแบบอัตโนมัติ หายนะ … ก็มาเยือนได้ง่ายๆ เหมือนกัน

    นั่นก็จะเป็นบทเรียนราคาแพงอีกบทนึงเช่นกัน

    ข้อสรุปของผม หลังจากได้บทเรียนอย่างนั้นมาก็คือ password ของ root ไม่ว่าจะเป็นของระบบเอง หรือ จะเป็นของ database “จะต้อง” เป็นคนละตัวกัน  _และ_ จะต้องมีระดับของความปลอดภัยสูงใกล้ๆกัน

    ได้ password ที่ secure มา … ก็ดี … แต่ปัญหาของ password ที่ secure ก็คือ จำยาก … สำหรับ root’s password ของระบบ ที่ยังมีการใช้งานค่อนข้างบ่อย ก็จะมีโอกาสที่จะลืมได้น้อยกว่า … วิธีการที่จะทำให้ ไม่ลืม และยังมี password ที่ secure ก็มีแน่ๆ แต่นั่นไม่ใช่สิ่งที่ผมอยากจะพูดถึงในบันทึกนี้ (อันที่จริงก็เขียนเอาไว้ที่อื่นแล้วด้วย)

    ที่จะมาแก้ปัญหาในบันทึกนี้ ก็คือ password ของ root ของ MySQL … โอเค … ก็รู้แล้วล่ะว่าจะต้อง set ให้มัน secure … ก็ set ไปแล้ว แต่ก็ลืมไปแล้วด้วย (ฮา) … งั้นทำไงดีล่ะ?

    ครับ ถ้าลืม root password ไม่ว่าจะเป็นของระบบเอง หรือ จะเป็นของ MySQL server ถ้าจะให้สามารถ “ยึดอำนาจ” ของ root กลับมาได้ ก็คงต้องใช้วิธีการ reset password กัน

    วิธีการ reset password ของ root ระบบที่ใช้ Linux ที่ไม่ได้การ encrypt ระบบไฟล์เอาไว้ และ ไม่ได้ lock password ที่ระดับของ bios ก็ไม่ได้ยุ่งยากอะไรมาก … แต่ก็ไม่ได้เป็นเรื่องที่ตั้งใจจะเขียนในบันทึกฉบับนี้อีกเหมือนกัน และคิดว่า admin แทบทุกท่านก็น่าจะรู้วิธีการกันอยู่ดีพอสมควรแล้ว

    ที่ตั้งใจจะพูดถึงก็คือ การ reset password ของ root ของ MySQL Server

    ซึ่งอันที่จริง ก็ไม่ได้เป็นความลับอะไร ถ้าลอง search หาด้วย google ก็จะเจอในระยะไม่เกิน 2-3 click ของ mouse

    แต่โดยตัวผมเอง ที่จำเป็นจะต้อง เกี่ยวข้องกับ MySQL Server บนหลายเครื่อง และเกิดเหตุการณ์จำเป็นให้ต้อง reset password ของ MySQL อยู่ 2-3 รอบ ในช่วงไม่กี่เดือนที่ผ่านมา ก็ชักจะรู้สึกหงุดหงิอยู่นิดหน่อย ตรงที่ว่า วิธีการที่มี มันจะต้องทำแบบ manual และ จะต้องเปิด terminal ขึ้นมามากกว่า 2 terminal หรือ 2 tab เพื่อที่จะจัดการให้เสร็จเรียบร้อย เพราะจะต้อง run โปรแกรม server บน terminal นึง และ run โปรแกรม client อีก terminal นึง ขนานกันไป

    ทำอยู่ หลายรอบ … รอบสุดท้ายที่ทำ ก็ชักเบื่อ แล้วก็ถามตัวเองว่า จะเขียนมันเป็น script แล้ว run ครั้งเดียวเสร็จ ไม่ได้เชียวหรือ?

    ลองกลับไป ล้วง,แคะ,แกะ,เกา shell script และตัว mysqld กับ mysql client ใหม่อีกรอบ ก็ทำให้ได้ script ตัวนี้มาครับ

    #!/bin/sh
    
    PASSWD="$1"
    [ -z "$PASSWD" ] && echo "Usage: $0 newpassword" && exit
    
    [ `id -u` != "0" ] && echo "Must be root!" && exit
    
    # Is mysql installed?
    [ ! -x /usr/bin/mysql ]    && \
        echo "[?] Is mysql-server & mysql client installed?" && \
        exit
    
    RUNNING=0
    # is mysql server running?
    if [ "`ps auxw | grep [/]usr/sbin/mysqld`" ]; then
        echo "[*] mysqld is running, try to stop it..."
        RUNNING=1
        # yes, then shutdown it
        service mysql stop
        for i in `seq 1 10`; do
            [ "$i" = "10" ] && {
                echo "[?] Hmm? can't stop mysqld server";
                exit;
            }
            [ -z "`ps auxw | grep [/]usr/sbin/mysqld`" ] && {
                echo "[*] mysqld stopped!";
                break;
            }
            echo -n "."
            sleep 1
        done
        echo ""
    fi
    
    # Start mysqld not using grant tables
    echo "[*] Start mysqld without using grant tables"
    /usr/sbin/mysqld --skip-grant-tables 2>/dev/null &
    MPID=$!
    
    echo "[*] Wait for mysqld to be ready ..."
    sleep 5
    
    echo "[*] Now, set new password..."
    cat <<EOT | /usr/bin/mysql
    UPDATE mysql.user SET Password=PASSWORD("$PASSWD") WHERE User='root';
    FLUSH PRIVILEGES;
    EOT
    
    echo "[*] Done! now stop the mysqld again ..."
    kill -QUIT $MPID
    sleep 3
    
    [ "$RUNNING" = "1" ] && {
        echo "[*] Restart mysqld using normal running method..";
        service mysql start;
    }

    วิธีการ ใช้งาน  ก็ save โปรแกรมลงในไฟล์ สมมติว่าชื่อ reset-mysql-root-password

    $ chmod +x bin/reset-mysql-root-password
    $ bin/reset-mysql-root-password NewSecretPasswd2013

    ครับ เรียกใช้โปรแกรมตามด้วย password ที่ต้องการจะให้ set ใหม่แค่นั้นเองครับ

    ตัว script เขียนขึ้นมาเพื่อให้ใช้งานได้กับ Debian และ Ubuntu

    ผมใช้ delay เพื่อรอให้การ start/stop ของ mysqld เสร็จเรียบร้อยก่อนที่จะทำงานต่อไป ซึ่งก็ขึ้นอยู่กับว่า load ของเครื่อง และความเร็วของเครื่องที่ใช้อยู่เป้นอย่างไร ถ้ามีปัญหา ก็อาจจะต้องปรับเพิ่มค่า delay ที่มีอยู่ใน script ให้มากขึ้นกว่าเดิมอีกหน่อยครับ

    จริงๆแล้วผมควรที่จะอธิบายเพิ่มว่า เทคนิคที่ใช้ใน script มีอะไรบ้าง แต่ก็คาดว่า หลายๆคนที่เตยเจอปัญหาแบบเดียวกัน ก็น่าจะเคยอ่านจาก document ของ MySQL เองแล้ว ก็น่าจะไม่จำเป็นมาก ที่ผมต้องการจะเสนอในที่นี ก็คือ tool เป้น shell script ที่จะช่วยให้ทำงานให้ง่ายขึ้น แทนที่จะต้องใช้วิธีการแบบ manual น่ะครับ

    แต่ยังไงถ้ามีข้อสงสัย ก็ comment / ถามมาก็แล้วกันนะครับ ผมจะกลับมาตอบ ถ้ามีคำถามครับ 🙂

  • วิธีลดขนาดไฟล์ Microsoft Word ให้เล็กลง

    ในการทำเอกสารต่างๆ โดยเฉพาะ Microsoft Word ผู้ใช้มักจะ ใส่รูปภาพ เข้ามาในไฟล์ เพื่อให้เกิดความสวยงาม และสื่อความหมายในการบรรยาย

    บ่อยครั้ง เป็นภาพ “หน้าจอ” โดยการ “Print Screen” หรือ การ เอาภาพจากกล้องดิจิตอล ซึ่งปัจจุบันมีความละเอียดสูง เช่นกล้อง 5MP เป็นอย่างต่ำ หรือกล้องใหม่ๆ 12 MP กันเลยทีเดียว ซึ่งภาพที่ได้จะมีขนาดใหญ่มาก เมื่อนำมาใส่ในไฟล์เอกสาร แล้วทำการ Resize ภาพ หรือ Crop เอาเฉพาะบางส่วนของภาพ ก็มักจะคิดว่า ขนาดของไฟล์ จะลดลงไปด้วย

    ซึ่งความจริงไม่ใช่อย่างนั้น เพราะโปรแกรม Microsoft Word จะยังเก็บภาพขนาดเดิมเอาไว้ เพียงแต่เลือกแสดงบางส่วน หรือ ลดขนาดการแสดงผลเท่านั้น จึงทำให้ไฟล์มีขนาดใหญ่ … และอาจจะเป็นปัญหาได้ เมื่อไฟล์มีขนาดใหญ่มากๆ, การส่งไฟล์ผ่าน email ก็จะมีขนาดใหญ่ จนบางครั้ง ผู้รับไม่สามารถรับได้ เช่นส่งไฟล์ขนาดเกิน 25 MB ไปยัง Gmail/Hotmail เป็นต้น

    วิธีการลดขนาดไฟล์

    1. คลิกที่ภาพในไฟล์ >Pictures Tools > Format > Compress Pictures
    แล้วเลือกความละเอียดขนาดแค่ email ก็พอ
    คลิก OK แล้ว Save

    MicrosoftWord-PictureCompress

    2. ผลการลดขนาด จะทำให้ไฟล์เดิมขนาด 6 MB ลดเหลือ 2 MB ในทันที

    fileresize-result

  • เปลี่ยน uptime timestamp ในคำสั่ง dmesg ให้เป็น date/time timestamp

    เคยใหมครับ เมื่อใช้คำสั่ง dmesg เพื่อที่จะดู kernel message แล้วสงสัยว่า เวลาที่แสดงในเครื่องหมาย square bracket ที่อยู่ด้านหน้าของ message น่ะมันเป็นเวลาเท่าไหร่กันแน่?

    อาจจะไม่บ่อยนัก แต่ผมก็เคยมีปัญหานั้น

    ถ้าใช้คำสั่ง dmesg บน command line เราอาจจะเห็น message ประมาณนี้

     [   10.738140] udev[228]: starting version 164
     [   12.840798] ACPI: PCI Interrupt Link [LNKD] enabled at IRQ 9
     [   12.842168] PCI: setting IRQ 9 as level-triggered
     [   12.843002] pci 0000:00:04.0: PCI INT A -> Link[LNKD] -> GSI 9 (level, low) -> IRQ 9
     [   12.856454] input: PC Speaker as /devices/platform/pcspkr/input/input2
     [   12.911121] vboxguest: major 0, IRQ 9, I/O port d020, MMIO at 00000000f0400000 (size 0x400000)
     [   12.912531] vboxguest: Successfully loaded version 3.2.10_OSE (interface 0x00010004)
     [   13.165633] piix4_smbus 0000:00:07.0: SMBus base address uninitialized - upgrade BIOS or use force_addr=0xaddr
     [   13.233473] parport_pc 00:05: reported by Plug and Play ACPI
     [   13.314410] ACPI: AC Adapter [AC] (on-line)
     [   13.318154] input: Power Button as /devices/LNXSYSTM:00/LNXPWRBN:00/input/input3
     [   13.345820] ACPI: Power Button [PWRF]
     [   13.376871] input: Sleep Button as /devices/LNXSYSTM:00/LNXSLPBN:00/input/input4
     [   13.420217] ACPI: Sleep Button [SLPF]
     [   13.455000] input: ImExPS/2 Generic Explorer Mouse as /devices/platform/i8042/serio1/input/input5
     [   15.017345] Intel ICH 0000:00:05.0: PCI INT A -> Link[LNKA] -> GSI 5 (level, low) -> IRQ 5
     [   15.019308] Intel ICH 0000:00:05.0: setting latency timer to 64
     [   15.344130] intel8x0_measure_ac97_clock: measured 54439 usecs (10177 samples)
     [   15.346177] intel8x0: measured clock 186943 rejected
     [   15.704139] intel8x0_measure_ac97_clock: measured 55930 usecs (10470 samples)
     [   15.705569] intel8x0: measured clock 187198 rejected
     [   16.064125] intel8x0_measure_ac97_clock: measured 55919 usecs (10451 samples)
     [   16.065415] intel8x0: measured clock 186895 rejected
     [   16.066703] intel8x0: clocking to 48000
     [   17.234971] EXT3 FS on dm-0, internal journal
     [   17.967548] loop: module loaded
     [   23.754984] Adding 8388600k swap on /dev/mapper/lv-nilanont--swap.  Priority:-1 extents:1 across:8388600k
     [   30.580221] kjournald starting.  Commit interval 5 seconds
     [   30.581590] EXT3 FS on dm-2, internal journal
     [   30.582599] EXT3-fs: mounted filesystem with ordered data mode.
     [   31.094231] FAT: utf8 is not a recommended IO charset for FAT filesystems, filesystem will be case sensitive!
     [   35.777014] e1000: eth0 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX
     [   39.640499] fuse init (API version 7.13)
     [   40.373844] binfmt_misc: Unknown symbol bprm_change_interp
     [   40.469771] binfmt_misc: Unknown symbol bprm_change_interp
     [   41.587335] vboxsf: Successfully loaded version 3.2.10_OSE (interface 0x00010004)
     [   52.668229] lp: driver loaded but no devices found
     [   52.742090] ppdev: user-space parallel port driver
     [   64.384194] device eth0 entered promiscuous mode
     [   66.379973] device eth0 left promiscuous mode
     [   73.139965] tun: Universal TUN/TAP device driver, 1.6
     [   73.141787] tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>

    ตัวเลขที่อยู่ภายใน [ ] เช่น “[   73.141787]” ในบรรทัดสุดท้าย 73.141787 หมายความว่า ข้อความของ kernel ในบรรทัดนั้น

    tun: (C) 1999-2004 ...

    พิมพ์ออกมาหลังจากเครื่องเริ่มต้นทำงานไปแล้วประมาณ 17 วินาทีกับอีกนิดหน่อย 141787 ที่อยู่ข้างหลัง จะแสดงเวลาที่เป็นหน่วยย่อยในระดับ micro-second

    ซึ่งการแสดงผลแบบนี้ จะไม่มีปัญหาซักเท่าไหร่ สำหรับเครื่องที่เพิ่งเปิดขึ้นมาใหม่ๆ เช่นเครื่อง desktop หรือ notebook ทั่วไป แต่สำหรับเครื่องที่ทำงานเป็น Server ซึ่งเปิดทิ้งเอาไว้เป็นชั่วนาตาปี, โขง, ชี, มูล, ปิง, วัง, ยม, น่าน นั้น บางทีเวลาเราใช้คำสั่ง dmesg ออกมา อาจจะเห็นเป็น message แบบนี้

     ...
     [201089.204812] br0: topology change detected, propagating
     [201089.204815] br0: port 1(eth0) entering forwarding state
     [201089.204838] br0: port 1(eth0) entering forwarding state
     [237531.522878] br0: port 1(eth0) entering forwarding state
     [237531.671857] r8169 0000:02:00.0: eth0: link down
     [237531.671888] r8169 0000:02:00.0: eth0: link down
     ...

    จะเห็นว่าบรรทัด “br0: port 1(eth0) enter forwarding state” ในสองบรรทัดแรก กับบรรทัดที่สาม จะเกิดห่างกันพอสมควร ระยะเวลาห่างกันเท่าไหร่ เป็นเวลากี่วินาที ก็เอาตัวเลขทั้งสองตัวมาหักลบกันได้ ยุ่งยากนิดหน่อย แต่ก็ไม่มากจนเกินไป

    แต่ปัญหาที่เกิดขึ้นก็คือ หลายครั้ง ผมอยากจะรู้ว่า “มันเกิดขึ้นเมื่อไหร่?” มากกว่า ที่อยากจะรู้ว่า “มันเกิดขึ้นหลังจากครั้งที่แล้วนานเท่าไหร่?”

    อืม แล้วถ้าเป็นอย่างนั้นผมจะหาคำตอบได้ยังไง?
    เนื่องจากเวลาที่คำสั่ง dmesg แสดงออกมา เป็นเวลานับเป็นจำนวนวินาที นับตั้งแต่เครื่องเริ่มต้นทำงาน เพราะฉะนั้น ถ้าเรา “รู้” ว่าเราเริ่มเปิดเครื่องเมื่อไหร่ เราก็สามารถ ใช้เวลานั้นเป็นเวลาตั้งต้น แล้วบวกเวลาด้วยจำนวนวินาทีที่ผ่านไป แล้วค่อยแปลงเวลานั่นกลับมาเป็นวันเดือนปีอีกครั้ง เราก็จะรู้เวลาที่เกิดเหตุการณ์นั้นขึ้นใช่ใหมครับ

    ฟังดูไม่ยาก … รึเปล่า?

    เวลาที่เครื่องเริ่มต้นทำงานเราจะเอามันมาจากใหนได้บ้างล่ะนี่?

    ถ้าเครื่องของเราเพิ่ง reboot มาเมื่อไม่นานเท่าไหร่ เราอาจจะใช้คำสั่ง last ในการหาเวลา boot ของเครื่องได้โดยประมาณแบบนี้

     $ last | grep reboot
     reboot   system boot  3.2.0-4-amd64    Tue Mar 19 18:14 - 02:25 (6+08:10)

    อืม … เครื่องของผมเพิ่ง reboot ไปเมื่อวันที่ 19 มีค. เวลา 18:14 และ เวลาขณะที่เขียนบันทึกฉบับนี้ เวลาผ่านไปแล้ว 6 วัน 8 ชม. กับอีก 10 นาที … แต่ว่า วิธีการนี้จะมีปัญหากับเครื่อง boot มาแล้วตั้งแต่เดือนที่แล้ว หรือ นานกว่านั้น เพราะ /var/log/wtmp จะเก็บข้อมูลเฉพาะเดือนนี้ และ โดยทั่วไปแล้วจะมีข้อมูลเก็บย้อนหลังอีกแค่ 1 เดือนเท่านั้น (สำหรับ server ที่ผมดูแลอยู่ ข้อมูลของ wtmp จะระบุใน logrotate config ให้เก็บย้อนหลังไปอย่างน้อย 12 เดือน) … ไม่ว่าอย่างไร วิธีการนี้จะมีปัญหาถ้าต้องการที่จะได้ข้อมูลที่ถูกต้องแน่นอนทุกครั้ง

    งั้นมีวิธีใหนอีกบ้าง? คำสั่ง uptime ล่ะ

     $ uptime
     02:31:56 up 6 days, 8:17, 23 users, load average: 1.00, 0.98, 0.95

    แต่ … เอ วิธีการนี้เราจะได้มาแค่ ระยะเวลาที่เครื่องทำงานอยู่เท่านั้นนี่นา ไม่ได้บอกว่าเครื่อง ‘เริ่ม’ ทำงานเมื่อไหร่ … ใช่ใหม?

    ใช่แล้วครับ! แต่เรามีคำสั่งที่จะช่วยอีก 1 คำสั่งคือคำสั่ง date

     $ date;uptime
     Tue Mar 26 02:33:05 ICT 2013
     02:33:05 up 6 days, 8:18, 23 users, load average: 0.85, 0.95, 0.94

    เอาล่ะ คราวนี้ เราได้เวลา ‘ขณะนี้’ ของเครื่องออกมาแล้ว จากคำสั่ง date และเราได้ ‘ระยะเวลาที่เครื่องทำงาน’ มาจากคำสั่ง uptime เพราะฉะนั้น ถ้าผมนับย้อนหลังจากเวลา ‘ขณะนี้’ ไปเท่ากับเวลา ‘uptime’ ผมก็จะได้เวลาที่เครืองเริ่มต้นทำงานขึ้นมา … ใช่ใหมครับ

    start_time = "Tue Mar 26 02:33:05 ICT 2013" - "6 days, 8:18"

    เอ่อ … จะง่ายไปใหมเนี่ย เอามันมาลบได้อย่างนั้นน่ะ? ถ้าทำอย่างได้จริง ชีวิตของ sysadmin ก็คงง่ายขึ้นครับ แต่ชีวิตจริงของ admin มันไม่ง่ายดายขนาดนั้น

    แต่ถ้าจะให้ผมแปลง string ของวันที่กลับมาเป็นตัวเลข และแปลง string ของระยะเวลา กลับมาเป็นตัวเลข โดยใช้ shell script เองก็คงไม่ไหวเหมือนกันแหละครับ 🙂

    บน unix เรามี tools ซึ่งช่วยในการจัดการเรื่อง วัน/เวลาอยู่แล้ว คำสั่งนั้นก็คือ คำสั่ง date เพื่อนเก่าของเราน่ะเอง

    ถ้าเราใช้คำสั่งนี้แบบธรรมดา เราก็จะได้ string ของ ข้อความที่เป็นแบบที่เรียกว่า human readable date string ออกมาตามตัวอย่าง  เราสามารถระบุให้คำสั่ง date แสดงข้อความออกมาเป็นรูปแบบอื่นๆได้อีกด้วย เช่น แสดงเวลานับเป็นวินาทีเริ่มจาก เวลาอ้างอิงของระบบปฏิบัติการแบบ unix ที่เรียกกันโดยทั่วไปว่า epoch ซึ่งเวลาที่ว่านั่นก็คือ 1970-01-01 00:00:00 … ถ้าจะถาม ว่าทำไมเวลาอ้างอิง หรือ epoch ถึงต้องเป็นวัน/เวลานี้ด้วย  คำตอบคงจะต้องเท้าความถึงประวัติศาสตร์ของ Unix ค่อนข้างไกล … ซึ่งคงจะออกนอกเรื่องไปอีกพอสมควร เพราะฉะนั้นขอละไว้เพียงแค่นี้ก่อนก็แล้วกันครับ ผู้ที่สนใจลองหาอ่านเองโดยใช้ google ช่วยได้ครับ

    คำสั่ง date สามารถแสดงผลออกมาได้หลากหลายรูปแบบมาก รายละเอียดสามารถอ่านได้จาก man page ของคำสั่ง date นะครับ แต่สำหรับกรณีของการแสดงเวลาเป็นวินาทีนับจากเวลาอ้างอิง ก็สามารถใช้คำสั่ง

    date +%s

    รูปแบบ +%… จะเป็นการกำหนดรูปแบบการแสดงผล นะครับ ตัวอย่างเช่น บนเครื่องของผมขณะที่เขียนบันทึกอยู่ขณะนี้

     $ date;date +%s
     Tue Mar 26 02:50:49 ICT 2013
     1364241049

    เวลา 1364241049 วินาทีนับจาก epoch ก็เป็นเวลาเดียวกันกับ Tue Mar 26 02:50:49 ICT 2013 เพียงแต่แสดงในรูปแบบที่ต่างกัน

    เอาล่ะเราได้เวลาที่เป็น เวลาปัจจุบัน แสดงออกมาเป็นวินาทีแล้ว … แล้วทีนี้ ค่าเวลา uptime ล่ะ เราจะแปลง “6 days, 8:18” หรือ 6 วัน 8 ชม. 18 นาที มาเป็นตัวเลขวินาทียังไง … ดูแล้วก็น่าจะไม่ยากมากเท่าไหร่ … แต่ก็ไม่ง่าย …(ฮา)

    จริงๆแล้ว ก็มีวิธีง่ายๆอยู่ครับ ค่าของ uptime เราสามารถอ่านมาจากไฟล์ /proc/uptime ได้ โดยไม่ต้องไปแปลงจาก string ของ “N days, HH:MM” โดยตรง

     $ cat /proc/uptime
     549627.40 1106209.61

    ตัวเลขตัวแรกเป็น uptime ส่วนตัวที่สองเป็น cpu idle time

    เอ๊ะ.. ทำไม idle time ถึงมากกว่า uptime ล่ะ? … คือว่าเครื่องที่ผมใช้งานอยู่มันมี core ของ processor อยู่จำนวน 4 core ใน 1 cpu น่ะครับ ค่า idle time นับของ cpu ทุกตัวรวมกัน ตัวเลขก็เลยออกมาสูงกว่า cpu uptime

    เอาล่ะ เราสามารถ หาวัน/เวลา ที่เครื่องเริ่มต้นทำงานได้ โดยการใช้คำสั่งของ shell ได้คร่าวๆประมาณนี้ครับ

     NOW=`date +%s`
     UPTIME=`cat /proc/uptime | cut -f1 -d.`
     STARTTIME=`expr $NOW - $UPTIME`
     echo $STARTTIME

    เวลาของ UPTIME เราใช้เฉพาะหน่วยวินาทีโดยการใช้ จุดเป็นตัวคั่น แล้วตัดส่วนที่เหลือทิ้งไปทั้งหมด (รวมทั้ง idle time ด้วย) ส่วนการคำนวณ ก็ใช้คำสั่ง expr เป็นตัวช่วย

    แต่เวลาที่ได้เป็นตัวเลข จำนวนเป็นวินาทีนี่!! ดูไปก็ยังไม่รู้ว่ามันเป็นวัน/เวลาใหนกันแน่ … จะต้องแปลงตัวเลขกลับยังไงนี่

    ตรงนี้ไม่ยากครับ ใช้คำสั่ง date อีกนั่นแหละ เราสามารถใช้ option -d หรือ –date= สำหรับการระบุเวลาที่ต้องการเป็นเวลาอื่น แทนที่จะเป็นเวลา “ปัจจุบัน” ได้ โดยที่ ถ้าเราจะระบุเวลาเป็น จำนวนวินาทีนับจากเวลาอ้างอิง — epoch ก็ให้ใส่เครื่องหมาย @ หน้าตัวเลขนั้นครับ ซึ่ง สามารถลองได้ประมาณนี้

     $ date -d @0
     Thu Jan  1 07:00:00 ICT 1970
     $ date -d @1363691682
     Tue Mar 19 18:14:42 ICT 2013

    ถ้าใช้ @0 นั่นก็คือระบุเวลาอ้างอิงเลย ก็จะได้เป็นวันที่ 1 มค. 1970 เวลา 00:00:00 UTC — เวลาที่แสดงเป็น 07:00:00 ICT ซึ่งเป็นเวลาของประเทศไทย (=GMT+7)  และ เวลาที่เครื่องคอมพิวเตอร์ที่ผมใช้ reboot ครั้งสุดท้ายเมื่อ วันที่ 19 มีค. เวลา 18:14 น.

    ส่วนที่เหลือก็คือ รับข้อมูลแต่ละบรรทัดจาก คำสั่ง dmesg เข้ามาแล้วก็แปลงข้อมูลของ time stamp ที่อยู่ในรูปแบบ uptime ซึ่งอยู่ระหว่างเครื่องหมาย [] ข้างหน้าออกมา ส่วนนี้ สามารถใช้คำสั่ง read ช่วย เช่น dmesg บรรทัดสุดท้ายได้ข้อมูลออกมาเป็น

     $ dmesg | tail -1
     [288163.997319] br0: port 1(eth0) entering forwarding state

    คำสั่ง read จะอ่านค่ามาเก็บไว้ในตัวแปร โดยจะแบ่งโดยใช้ space

     $ dmesg | tail -1 | (read STAMP REST; echo "STAMP=$STAMP REST=$REST")
     STAMP=[288163.997319] REST=br0: port 1(eth0) entering forwarding state

    ในกรณีนี้ เราจะได้ค่าเวลา ซึ่งมี เครื่องหมาย [] คร่อม อยู่ในตัวแปร shell ชื่อ STAMP และ ส่วนที่เหลือทั้งหมด จะอยู่ในตัวแปร shell ที่ชื่อว่า REST

    ในส่วนของ เวลา อาจจะอยู่ในรูปแบบ  [ 0.00000] ก็ได้ ซึ่งจะมีช่องว่างอยู่หลัง ‘[‘ และก่อนตัวเลข ซึ่งสามารถกำจัดทิ้งได้ ด้วยคำสั่ง sed และ เครื่องหมาย ‘]’ ด้านหลังตัวเลขก็จะสามารถตัดทิ้งได้ด้วย sed เช่นเดียวกัน หรือ อาจจะใช้คำสั่ง tr  ด้วย option -d ก็ได้

    ตัวเลขที่ได้ ตัดเอามาเฉพาะส่วนที่เป็นวินาที แล้วเอามาบวกกับค่า STARTTIME โดยใช้คำสั่ง expr เป็นตัวช่วยเหมือนเดิม

    เอาล่ะ ใช้สิ่งที่ได้เรียนรู้จากข้างต้น เราก็จะสามารถเขียนเป็น shell script ออกมาได้ประมาณนี้

    #!/bin/sh
    DSTR1="+%b %d %H:%M:%S"                    # Syslog format Month Date Hour:Min:Sec
    DSTR2="+%Y-%m-%d %H:%M:%S"                 # ISO format
    NOW=`date +%s`                             # current timestamp in second
    UPTIME=`cat /proc/uptime | cut -f1 -d.`    # current uptime
    START=`expr $NOW - $UPTIME                 # start time of this machine
    cat - | sed 's/^\[ *//' |\
    while read STAMP REST; do
        SEC=`echo $STAMP | tr -d '[]' | cut -f1 -d.`
        TIME=`expr $START + $SEC`
        DATE=`date -d @$TIME "$DSTR1"`
        echo "$DATE $REST"
    done

    ส่วนที่เพิ่มขึ้นมาก็คือ การเลือกแสดงผล ออกมาเป้นรูปแบบเดียวกับ date/time stamp ที่ใช้ใน log file (DSTR1) หรือ จะใช้แบบ ISO format (DSTR2)

    วิธีการใช้งาน script ตัวนี้ ซึ่งสมมติให้มีชื่อว่า dmesg-datestamp ก็ใช้แบบนี้ครับ

    $ dmesg | ./dmesg-datestamp

    ซึ่งในกรณีที่มี ข้อความใน dmesg จำนวนมาก ก็อาจจะใช้เวลาค่อนข้างนานเพราะในแต่ละบรรทัด ของ dmesg จะต้องมีการคำนวณ เวลาและแปลงเป็นวันที่ใหม่ โดยการใช้คำสั่ง expr และ date ตามลำดับ ซึ่งสามารถลดเวลาที่ใช้ในการแสดงผล โดยเลือกเอาเฉพาะ dmesg ในบรรทัดที่เราสนใจได้ เช่น

    $ dmesg | grep eth0 | ./dmesg-datestamp

    หรืออาจจะ redirection ลงไปเก็บไว้ในไฟล์ แล้วอ่านจากไฟล์ แทนที่จะอ่านจากคำสั่ง dmesg ทุกครั้ง

    สำหรับคนที่ ทนอ่านมาจนถึงบรรทัดนี้ แล้วกำลังจะบอกผมว่า … จริงๆแล้ว ไม่ต้องทำถึงขนาดนั้นก็ได้ครับ คำสั่ง /bin/dmesg มี option -T ซึ่ง สามารถแปลง time stamp ให้อยู่ในรูปแบบ human readable ให้อยู่แล้วโดยไม่จำเป็นจะต้องพึ่งพา shell script ใดๆเลย

    แหะๆ ครับ Hit with Brick

    ผมก็ทราบแล้วครับ … แต่ว่านั่นมันหลังจากผมเขียน script เสร็จแล้ว (ฮา)

    บน Debian Linux ถ้าใช้ wheezy ก็จะสามารถใช้

    $ dmesg -T

    ได้เลย แต่บน Debian squeeze ซึ่งเป็น stable release ของ Debian ในตอนนี้ คำสั่ง dmesg ยังไม่สามารถใช้งาน option -T ได้ แต่ปัญหานี้ก็คงมีอีกไม่นานเท่าไหร่ เพราะ wheezy กำลังจะกลายเป็น stable release ในของ Debian ภายในไม่ช้า …

    แต่ … จะทำยังไงได้ล่ะ ก็เขียนไปแล้วนี่ …

    ส่วนใครที่อ่านมาจนถึงบรรทัดนี้แล้ว … ก็อ่านไปแล้วนี่ ช่วยอะไรไม่ได้เนอะ …

    ขอจบเอาดื้อๆแค่นี้แหละคร้าบ …

  • Facebook นั่นแหล่ะ ทำให้มีจดหมายขยะมากขึ้น ?!?!

    ต้องยอมรับว่า ทุกวันนี้ ใครที่ทำงานกับคอมพิวเตอร์ เริ่มต้นสิ่งแรกๆที่มักจะทำ คือ เปิด Internet Browser แล้ว เว็บไซต์ที่จะเปิดลำดับแรกๆ คือ Facebook และพฤติกรรมที่มันจะทำคือ Login ค้างเอาไว้ แล้วไปทำงานอย่างอื่นต่อ

    แล้วเมื่อ Facebook เป็นที่นิยมอย่างมาก ก็ทำให้ website ต่างๆ อำนวยความสะดวกในการใช้งานกับผู้ใช้มากยิ่งขึ้น โดยให้ผู้ใช้ สามารถ Login เข้าใช้งานได้ โดยไม่ต้องสมัคร ขอเพียงมี Facebook Account ก็สามารถเข้าใช้งานได้

    สิ่งที่ตามมา แต่ผู้ใช้จำนวนมาก “ไม่รู้” เนื่องจาก “ไม่อ่าน” คือ เมื่อใช้ Facebook Account ในการ Login แล้ว ระบบเหล่านั้น จะสอบถาม “สิทธิ” การเข้าถึงข้อมูล ส่วนตัว บน Facebook Account ด้วย และมันจะเสริมด้วยบริการ “แจ้งให้เพื่อนๆทราบ” ว่าเราได้เข้าใช้งานแล้ว โดยการเข้าไปอ่าน รายชื่อ เพื่อนๆ (Friends) แล้วส่ง Notification ไปยังเพื่อนๆของเรา … ปัญหาคือ เพื่อนๆของเรา ก็ “ไม่อ่าน” เช่นกัน เห็นอะไรมา ก็ คลิก คลิก คลิก ก็เลยทำให้การกระจายข้อมูล Website นั้นๆ ไปทั่วระบบ Social Network อย่างที่เป็นไปในปัจจุบัน ซึ่ง ก็จะบรรลุวัตถุประสงค์ของเจ้าของ Website เขาหล่ะ

    และนั่น … เป็นที่มาของปัญหา จดหมายขยะ มากมาย เพราะบางอย่างก็เป็นสิ่งที่ต้องการสำหรับบางคน แต่บางคนก็ไม่ต้องการ

    คราวนี้มาดูรายละเอียด และให้ “อ่าน” ให้มากขึ้นก่อนจะ คลิก อะไรไป

    1. ขอยกตัวอย่าง Linked-in และ SkillPage ซึ่งเป็นปัญหาในปัจจุบัน ที่มีผู้ใช้หลายท่านกำลังรู้สึกรำคาญกับข้อมูลเหล่านี้
    Linked-in และ SkillPage เป็น Social Network “อีกตัวหนึ่ง” สำหรับผู้ที่อยากจะ หางาน หรือเปิดตัวสู่สังคม ส่วน SkillPage จะไว้สำหรับให้ผู้ที่อยากหางานโดยเน้นให้ใส่ข้อมูลเกี่ยวกับความสามารถ (Skill) ที่มี

    หน้าจอการ Login ด้วย Facebook Account ของ Linked-in

    01-linkedin-join

    หน้าจอการ Login ด้วย Facebook Account ของ SkillPage

    02-skillpage-join

    จะเห็นว่า มีปุ่มให้คลิก เพื่อ Login ด้วย Facebook Account/ Google Account เป็นต้น

    2. เมื่อคลิกเข้ามาแล้ว หาก Login Facebook ค้างเอาไว้ ก็จะมาหน้าที่ระบบจะถาม Permission ในการเข้าถึงข้อมูล … ซึ่งถ้าไม่อ่าน ก็จะเปิดให้พวกนี้เข้าอ่าน Friends ของเราได้ และเป็นช่องทางในการกระจายตัวต่อไป

    Linked-in

    03-linkedin-facebook

    SkillPage

    04-skillpage-facebook

     

    3. หลังจากนั้น จะให้เราอนุญาต ให้เขา Post ข้อความต่างๆบน Facebook แทนตัวเรา และมักจะตบท้ายด้วย การ “เชิญเพื่อนๆของคุณสิ”
    Grow Your Network … ใช่สิ Network เขาคุณไง ไม่ใช่ของฉัน

    05-GrowYourNetwork-Linkedin

     

    4. เมื่อคลิก Continue ก็จะพยายามให้ Login ด้วย Gmail Account และจะขออ่าน Google  Contact ของเรา

    06-LinkedIn-gmailcontact

     

    จากนั้น หากเราหลงกล ระบบก็จะอ่าน Google Contact ของท่าน แล้วส่ง email ไปหาทุกคนในนั้น เชิญให้มาสมัคร .. และเมื่อเพื่อนท่าน “ไม่อ่าน” อะไรเลย คลิกไปเรื่อย … ก็จะมี Account Linked-In หรืออะไรก็แล้วแต่ เต็มไปหมด

    สำหรับผู้ที่อ่านบทความนี้แล้ว ก็อยากเชิญชวนให้ “อ่าน” ให้ดีๆก่อนจะสมัครอะไร

    แต่ก็เชื่อว่า บทความยาวๆอย่างนี้ จะมีมีบางคน

    ไม่อ่าน !!! อีกตามเคย

  • อัปเดต wordpress เปลี่ยน theme และเพิ่ม plugins

    ผมได้รับความช่วยเหลือจากเพื่อนร่วมงาน น้องใหญ่ เพื่อที่จะปรับปรุงให้หน้าแรกไม่ยืดยาวจนเกินไปในลักษณะแสดงข้อความส่วนต้นๆของเรื่องเท่านั้น  ก็ได้ theme ชื่อ toothpaste ดังรูปtheme-toothpaste

    และได้เพิ่ม plugin ชื่อ Authors Widget เพื่อแสดงรายชื่อผู้ที่เขียนบล็อก เพื่อความสะดวก ดังรูป

    plugin-authors-widget

    และได้เพิ่ม plugin ช่ื่อ List Category Posts เพื่อแสดงเฉพาะรายการชื่อเรื่องเท่านั้นดูได้ในเมนู หมวดหมู่ ดังรูป

    plugin-list-category-posts

    และได้ตั้งค่าให้แสดง Categories, Authors และ Archives เป็นแบบ Drop Down List รวมทั้งตั้งให้แสดงหน้าแรกเพียง 3 เรื่องล่าสุด เพื่อให้หน้าจอสั้นลง

    หวังว่าเพื่อนๆคงถูกใจครับ

  • วิธี Forward As Attachment บน Thunderbird

    การส่งต่อ email หรือการ Forward นั้น สามารถทำได้ 2 แบบคือ

    1) แบบ Inline คือจดหมายที่ส่งต่อไป จะปรากฏอยู่ในเนื้อจดหมาย โดยจะมีเครื่องหมาย > นำหน้าบรรทัดต่างๆ

    2) แบบ Attachment คือ จดหมายทั้งฉบับรวมถึงข้อมูลสำคัญของจดหมาย เช่น Header ต่างๆ รวมถึง Attachment จะตามมาด้วย

    ใน ThunderBird สามารถทำได้ทั้งสองแบบ แต่โดย Default จะทำการ Forward แบบ Inline

    ต่อไปนี้เป็นวิธีการ Forward As Attachment

    1. ใน ThunderBird เปิดจดหมายที่ต้องการ Forward As Attachment

    01-testmessage

    2. ไปที่เมนู (เครื่องหมาย ขีดๆๆ สามอันด้านขวามือของหน้าจอ) แล้วเลือก Message > Forward As > Attachment

    02-MessageMenu

    3. ก็จะสามารถ Forward As Attachment ได้

    03-forwardasattachment

  • สมัยนี้เขาไม่แนบไฟล์ใหญ่ๆกันแล้ว (Google Drive)

    มีผู้ใช้ถามมาว่า “จะส่งภาพงานอบรมให้เพื่อน ที่ Gmail แต่ทำไมส่งไปไม่ได้ ไม่กี่ภาพเอง ถามเพื่อนเขาก็ว่าพื้นที่เขาไม่เต็ม ทำไม PSU เราไม่ให้ส่งหล่ะ ?!?!?!” …

    ตรวจสอบพบว่า … ไม่กี่ภาพ แต่ขนาดรวมทั้งสิ้น 125 MB, และ Gmail ก็มีข้อจำกัด ไม่ให้ส่ง email ที่มีขนาดรวมไฟล์แนบเกิน 25 MB ในขณะที่ PSU เองไม่ได้จำกัดการส่งออกครับ

    แล้ว … ทำไงดี ???

    ต่อไปนี้เป็นหนึ่งในหลายๆวิธีครับ นั่นคือ ใช้ Google Drive เพื่อการแชร์ไฟล์
    โดยจะใช้วิธีสร้าง Folder แล้วแชร์ทั้งหมด ให้กับผู้อื่น แบบไม่ต้องใช้ Google Account ในการเข้ามาดู
    วิธีการใช้งานมีดังนี้

    0. ท่านต้องมี Google Account (Gmail Account นั่นแหล่ะ)

    1. Login ที่ https://drive.google.com

    login-drive

    2. คลิกที่ Create แล้วเลือก Folder

    create-folder

     

    3. ตั้งชื่อ “ภาพของฉัน”

    newfolder-ภาพของฉัน

     

    4. Upload ภาพไปเก็บใน “ภาพของฉัน” โดยคลิกที่ “ภาพของฉัน” แล้วคลิกที่ Upload (ภาพลูกศรชื้ขึ้น)
    แล้วเลือก Files, จากนั้น เลือกภาพที่ต้องการ เสร็จแล้วคลิกปุ่ม Open

    upload-pics

    5. รอให้ Upload เสร็จ

    upload-complete

    6.  คลิกที่เมนูด้านหลัง “ภาพของฉัน” แล้วคลิก Share … > Share

    share-share

    7. หากต้องการแชร์ให้ผู้อื่น “ที่มี Link” ดูได้ โดยไม่ต้อง Login ให้เลือก Anyone with the link

    แล้วเลือก Can View ดังภาพ แล้วคลิก Save

    (หากต้องการให้ Login ด้วย Google Account เลือก Private
    หากต้องการให้ทุกคน เห็นได้ เลือก Public on the Web)

    sharing-setting

     

    8.ใส่ email address ผู้รับลงไป คั่นด้วย Comma (,)
    หากต้องใส่ข้อความด้วย ก็สามารถทำได้ จากนั้นคลิก Share & Save

    share-save

    9. ผลคือ จะมี email ส่งไปถึงผู้รับ คล้ายอย่างนี้

    email

    10. เมื่อผู้รับคลิก “ภาพของฉัน” ก็จะได้ผลดังนี้ (มาที่ Google)

    result

     

    จึงเรียนมาเพื่อทราบ