2015/7/20

在Linux系統上製作Windows的USB安裝隨身碟(EFI支援的GPT格式)

不論在Linux或是Windows上要製作Linux安裝隨身碟都有現成套件可以輕易完成(如UNetbootin),但反過來要在Linux系統上製作Windows安裝隨身碟就沒這麼容易了,但也只需要幾個步驟就可以了!
目前還是EFI跟Legacy BIOS的接棒時期,安裝隨身碟也就分為EFI支援的GPT格式跟Legacy BIOS的MBR格式,這篇文章方法僅適用GPT格式。

先安裝gparted套件對隨身碟進行磁區分割
sudo apt-get install gparted
sudo gparted
  1. 在右上角下拉式選單中,選擇隨身碟裝置。
  2. 卸載隨身碟裝置
    功能列選單:Partition > Unmount
  3. 建立Partition表格
    功能列選單:Device > Create Partition Table ...
    選擇gpt
  4. 建立分割區
    功能列選單:Partition > New
    選擇fat32
  5. 儲存變更
    Ctrl + Enter
  6. 關閉gparted
掛載windows安裝印象檔(*.iso)並將內容複製到隨身碟
sudo mkdir /mnt/iso /mnt/usb
sudo mount *.iso /mnt/iso
sudo mount /dev/sdXY /mnt/usb
sudo cp -R /mnt/iso/* /mnt/usb

完成上述步驟後就可以重新開機,並將開機裝置指定到隨身碟,就會進入Windows安裝界面了。目前驗證過Windows7(64-bits)與Windows8(64-bits)均能成功進入安裝畫面。

2015/7/16

【治具】RS232 迴路測試每根Pin腳功能

RS232是個歷久不衰的訊號通訊協議,雖然在主流電腦上已經很難看見其蹤跡,但在伺服器或是嵌入式裝置乃至於近年很夯的物連網裝置都很容易見到,這篇文章主要記錄如何設計硬體治具並撰寫對應測試程式。

首先可以先參考RS232每根Pin腳的功能用途,網路上有大量文章介紹,就不再贅述,可以參考連結:Ethernut RS-232 Primer

先看做好的治具成品圖

治具硬體Rework
  1. 使用4.7kOhm電阻將TxD與RxD串接起來,如果只需要驗證資料傳輸只需做這部分重工即可,大部分情況下(未使用Hardware Flow Control)其他Pin腳都不會用到。
  2. 使用4.7kOhm電阻將DCD與DSR串接起來。
  3. 將DSR跟DTR直接短路串接。
  4. 使用4.7kOhm電阻將RI與CTS串接起來。
  5. 將CTS跟RTS直接短路串接。
測試概念
  1. 從TX發送資料,硬體TxD與RxD已經串接,因此會收到送出資料,確認收到資料並比對資料內容即可確認TxD與RxD腳位功能是否正常。
  2. 硬體RTS與CTS及RI串接,因此設置/重置RTS訊號,再讀取CTS與RI訊號即可確認這三根腳位功能是否正常。
  3. 硬體DTR與DSR及DCD串接,因此設置/重置DTR訊號,再讀取DSR與DCD訊號即可確認這三根腳位功能是否正常。
程式碼實做
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// File name: uart.c
// gcc -o uart uart.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>

int main (int argc, char *argv[])
{
 int ret = 0;
 int len;
 unsigned char buf[16] = {0xAA, 0x55, 0x00, 0xFF,
    0x5A, 0xA5, 0xF0, 0x0F,
    0x01, 0x02, 0x04, 0x08,
    0x10, 0x20, 0x40, 0x80};
 unsigned char buf_rev[16];
 int fd;
 FILE *fp = NULL;
 int status;
 struct termios tio;
 
 if (argc <= 1) {
  fprintf(stderr, "Usage: %s <dev>\n", argv[0]);
  ret = 255;
  goto end;
 }

 fp = fopen (argv[1], "w+");
 if (fp == NULL) {
  puts ("Fail to open device");
  ret = 255;
  goto end;
 }
 
 printf ("+ TX: ");
 fflush (fp);
 len = fwrite (buf, sizeof (char), 16, fp);
 fflush (fp);
 if (len < 16) {
  puts ("Fail to transfer data");
  ret = 255;
  goto clean;
 }
 puts ("Pass");

 printf ("+ RX: ");
 len = fread (buf_rev, sizeof (char), 16, fp);
 if (len < 16) {
  puts ("Fail to receive data");
  ret = 255;
  goto clean;
 } else if (memcmp (buf, buf_rev, 16) != 0) {
  puts ("Check data fail");
  ret = 255;
  goto clean;
 }
 puts ("Pass");
 fclose (fp);
 fp = NULL;

 if ( (fd = open (argv[1], O_RDWR)) < 0 ) {
  puts ("Fail to open device");
  ret = 255;
  goto end;
 }

 tcgetattr(fd, &tio);
 printf ("RTS -> CTS - RI: ");
 status |= TIOCM_RTS;
 ioctl(fd, TIOCMSET, &status);
 ioctl(fd, TIOCMGET, &status);
 ret = status & (TIOCM_CTS | TIOCM_RNG); // Should be 0xA0

 status &= ~TIOCM_RTS;
 ioctl(fd, TIOCMSET, &status);
 ioctl(fd, TIOCMGET, &status);
 if ( (status & (TIOCM_CTS | TIOCM_RNG)) || ret != 0xA0) { // Status should be 0x00, false
  puts ("FAIL");
  if (ret == 0x0)
   puts ("  --> Case1: RTS fail; Case2: CTR & RI fail");
  else if (ret == 0x80)
   puts ("  --> CTS fail");
  else if (ret == 0x20)
   puts ("  --> RI fail");
  else
   puts ("  -> RTS fail");
  ret = 6;
  goto clean;
 } else {
  puts ("PASS");
  ret = 0;
 }

 printf ("DTR -> DSR - DCD: ");
 status |= TIOCM_DTR;
 ioctl(fd, TIOCMSET, &status);
 ioctl(fd, TIOCMGET, &status);
 ret = status & (TIOCM_DSR | TIOCM_CAR); // Should be 0x140
 status &= ~TIOCM_DTR;
 ioctl(fd, TIOCMSET, &status);
 ioctl(fd, TIOCMGET, &status);
 if ( (status & (TIOCM_DSR | TIOCM_CAR)) || ret != 0x140) { // Status should be 0x00, false
  puts ("FAIL");
  if (ret == 0x0)
   puts ("  --> Case1: DTR fail; Case2: DSR & DCD fail");
  else if (ret == 0x100)
   puts ("  --> DCD fail");
  else if (ret == 0x40)
   puts ("  --> DSR fail");
  else
   puts ("  -> RTS fail");
  ret = 7;
  goto clean;
 } else {
  puts ("PASS");
  ret = 0;
 }

clean:
 if (fp)
  fclose (fp);
 if (fd > 0)
  close (fd);
end:
 printf("Return Code: %d\n", ret);
 return ret;
}

參考連結

2015/7/8

Trace shell script的小技巧

參考上圖,有三個script,先執行test1.sh,會帶起test2.sh;test2.sh會再帶起test3.sh,如果從test1.sh開始了解程式架構,很容易就可以得知彼此之間的執行關係;但有時候線頭只抓到test2.sh或是test3.sh時就麻煩了。
  在Linux下可以使用bash maintain的$PPID變數再搭配ps指令就可以慢慢推敲出script file的呼叫關係。

直接看範例:
#!/bin/sh
# file: test1.sh

echo $0
echo "Execute by `ps -o comm -h --pid $PPID`"
echo ===========
./test2.sh

#!/bin/sh
# file: test2.sh

echo $0
echo "Execute by `ps -o comm -h --pid $PPID`"
echo ===========
./test3.sh

#!/bin/sh
# file: test3.sh

echo $0
echo "Execute by `ps -o comm -h --pid $PPID`"
echo ===========

執行結果:
./test1.sh
Execute by bash
===========
./test2.sh
Execute by test1.sh
===========
./test3.sh
Execute by test2.sh
===========

2015/7/7

更改Shell輸出文字的顏色、底線、粗體等控制

要在Shell輸出文字中有顏色改變、底線與粗體效果,需要用到如下的控制碼:
printf "'\033[0;31m'Hello'\033[0m'"
會在螢幕上顯示紅色的Hello,但這樣要記住所有效果的代碼也不是辦法,可以將每種效果定義為一種變數,如此要調用就會簡單多了,如下可以達到相同效果:
Red='\033[0;31m'
NC='\033[0m'

printf "${Red}Hello${NC}"

完整的效果定義
#!/bin/bash
# File: color.sh

# Regular Colors
Black='\033[0;30m'
Red='\033[0;31m'
Green='\033[0;32m'
Yellow='\033[0;33m'
#Orange='\033[0;33m'
Blue='\033[0;34m'
Purple='\033[0;35m'
Cyan='\033[0;36m'
White='\033[0;37m'

# Bold
BBlack='\033[1;30m'
BRed='\033[1;31m'
BGreen='\033[1;32m'
BYellow='\033[1;33m'
BBlue='\033[1;34m'
BPurple='\033[1;35m'
BCyan='\033[1;36m'
BWhite='\033[1;37m'

# Underline
UBlack='\033[4;30m'
URed='\033[4;31m'
UGreen='\033[4;32m'
UYellow='\033[4;33m'
UBlue='\033[4;34m'
UPurple='\033[4;35m'
UCyan='\033[4;36m'
UWhite='\033[4;37m'

# Background
GBlack='\033[40m'
GRed='\033[41m'
GGreen='\033[42m'
GYellow='\033[43m'
GBlue='\033[44m'
GPurple='\033[45m'
GCyan='\033[46m'
GWhite='\033[47m'

# High Intensity
IBlack='\033[0;90m'
IRed='\033[0;91m'
IGreen='\033[0;92m'
IYellow='\033[0;93m'
IBlue='\033[0;94m'
IPurple='\033[0;95m'
ICyan='\033[0;96m'
IWhite='\033[0;97m'

# Bold High Intensity
BIBlack='\033[1;90m'
BIRed='\033[1;91m'
BIGreen='\033[1;92m'
BIYellow='\033[1;93m'
BIBlue='\033[1;94m'
BIPurple='\033[1;95m'
BICyan='\033[1;96m'
BIWhite='\033[1;97m'

# High Intensity Background
GIBlack='\033[0;100m'
GIRed='\033[0;101m'
GIGreen='\033[0;102m'
GIYellow='\033[0;103m'
GIBlue='\033[0;104m'
GIPurple='\033[0;105m'
GICyan='\033[0;106m'
GIWhite='\033[0;107m'

LightGray='\033[0;37m'
DarkGray='\033[1;30m'
LightRed='\033[1;31m'
LightGreen='\033[1;32m'
Yellow='\033[1;33m'
LightBlue='\033[1;34m'
LightPurple='\033[1;35'
LightCyan='\033[1;36'

NC='\033[0m'

效果Demo
#!/bin/bash
# File: color_demo.sh
. color.sh

printf "${Black}Black${NC}\n"
printf "${Red}Red${NC}\n"
printf "${Green}Green${NC}\n"
printf "${Yellow}Yellow${NC}\n"
printf "${Blue}Blue${NC}\n"
printf "${Purple}Purple${NC}\n"
printf "${Cyan}Cyan${NC}\n"
printf "${White}White${NC}\n"

printf "${BBlack}BBlack${NC}\n"
printf "${BRed}BRed${NC}\n"
printf "${BGreen}BGreen${NC}\n"
printf "${BYellow}BYellow${NC}\n"
printf "${BBlue}BBlue${NC}\n"
printf "${BPurple}BPurple${NC}\n"
printf "${BCyan}BCyan${NC}\n"
printf "${BWhite}BWhite${NC}\n"

printf "${UBlack}UBlack${NC}\n"
printf "${URed}URed${NC}\n"
printf "${UGreen}UGreen${NC}\n"
printf "${UYellow}UYellow${NC}\n"
printf "${UBlue}UBlue${NC}\n"
printf "${UPurple}UPurple${NC}\n"
printf "${UCyan}UCyan${NC}\n"
printf "${UWhite}UWhite${NC}\n"

printf "${GBlack}GBlack${NC}\n"
printf "${GRed}GRed${NC}\n"
printf "${GGreen}GGreen${NC}\n"
printf "${GYellow}GYellow${NC}\n"
printf "${GBlue}GBlue${NC}\n"
printf "${GPurple}GPurple${NC}\n"
printf "${GCyan}GCyan${NC}\n"
printf "${GWhite}GWhite${NC}\n"

printf "${IBlack}IBlack${NC}\n"
printf "${IRed}IRed${NC}\n"
printf "${IGreen}IGreen${NC}\n"
printf "${IYellow}IYellow${NC}\n"
printf "${IBlue}IBlue${NC}\n"
printf "${IPurple}IPurple${NC}\n"
printf "${ICyan}ICyan${NC}\n"
printf "${IWhite}IWhite${NC}\n"

printf "${BIBlack}BIBlack${NC}\n"
printf "${BIRed}BIRed${NC}\n"
printf "${BIGreen}BIGreen${NC}\n"
printf "${BIYellow}BIYellow${NC}\n"
printf "${BIBlue}BIBlue${NC}\n"
printf "${BIPurple}BIPurple${NC}\n"
printf "${BICyan}BICyan${NC}\n"
printf "${BIWhite}BIWhite${NC}\n"

printf "${GIBlack}GIBlack${NC}\n"
printf "${GIRed}GIRed${NC}\n"
printf "${GIGreen}GIGreen${NC}\n"
printf "${GIYellow}GIYellow${NC}\n"
printf "${GIBlue}GIBlue${NC}\n"
printf "${GIPurple}GIPurple${NC}\n"
printf "${GICyan}GICyan${NC}\n"
printf "${GIWhite}GIWhite${NC}\n"
呈現結果

讓ssh連線不用手動輸入密碼(自動登入)

最近專案有個應用:在客戶端透過ssh自動連線到伺服器並下達命令,卻遇到了需要手動輸入密碼的問題,發現ssh有提供公私鑰機制可以免除每次登入都需要輸入密碼,設定步驟也很簡單:
  1. 產生金鑰:在客戶端執行
    ssh-keygen -t rsa -b 2048
    
    過程中會出現Enter passphrase提示輸入訊息,直接按Enter跳過即可
  2. 將產生的公鑰內容上傳到伺服器的~/.ssh/authorized_keys檔案
    ssh-copy-id user_id@server_ip
    
只要完成上述兩個步驟就完成了,步驟2的user_id需替換成遠端連線的帳號、server_ip則是遠端連線的ip,底下稍微做一下說明:
  • 步驟1會產生一組本機的公鑰與私鑰,執行完後可以在~/.ssh目錄下看到兩個檔案
    • id_rsa:私鑰,之後連線會使用這私鑰進行演算後傳送到遠端進行驗證
    • id_rsa.pub:公鑰,內容會儲存在遠端的~/.ssh/authorized_keys檔案內,客戶端傳來的驗證資訊會以這資訊進行驗證
  • 步驟2的ssh-copy-id其實是一隻script(/usr/bin/ssh-copy-id),功能就是把id_rsa.pub內容幫忙存到遠端的~/.ssh/authorized_keys檔案內。