뭘 이런걸..

Posted
Filed under Tech/프로그래밍
정말 오랜만에 blog 에 posting 을 해 봅니다 :)

bash 에서 옵션 처리를 할 경우, bash 의 내장 함수인 getopts 또는 GNU getopt 를 사용하게 되는데, 필자의 경우에는 long option 을 제공하는 GNU getopt 를 더 선호하는 편입니다.

하지만 GNU getopt 를 사용할 경우 치명적인 문제가 하나 있는데, 바로 옵션 값에 공백 문자가 있을 경우, getopt -> set 을 하는 과정에서 옵션 값의 공백문자를 기준으로 분리가 되어 버리는 문제 입니다. (set 을 하는 이유는, 옵션과 인자값 순서를 섞어도 되게 하기 위해서 입니다.) 예를 들어

#!/bin/bash

opts="$( getopt -o h -u -l help -- $@ )"
set -- ${opts}
echo "$@"
echo "$3"
와 같이 코드를 만들고, 실행을 하면 다음과 같이 출력이 됩니다.
[user@host ~]$ bash test.sh -h "1 2 3"
-h -- 1 2 3
1
출력되는 $3 은 기대하는 "1 2 3" 이 아니라 "1" 이 됩니다.

그래서 이 문제는 해결하기 위해서는 다음과 같이 해 볼 수 있습니다.

#!/bin/bash

for i
do
[[ $i =~ [[:space:]] ]] && opt[n++]="\"${i}\"" || opt[n++]="${i}"
done
echo "input: ${opt[@]}"

opts="$( eval getopt -o ah: -l aa,hhh: -- ${opt[@]} )"
echo "opts -> ${opts}"
eval set -- ${opts}
for i
do
case "${i}" in
-a|--aa)
A=1
shift
;;
-h|--hhh)
H="${2}"
shift 2
;;
--)
shift;
break
esac
done

echo "$@"
echo "----"
echo "-h -> $H"
echo "\$1 -> $1"
echo "\$2 -> $2"
echo "\$3 -> $3"
echo "\$4 -> $4"
결과는
[user@host ~]$ bash test.sh "123 456" -h '\"abc def\"' 789
input: -h "\"abc def\"" "123 456" 789
opts -> -h '"abc def"' -- '123 456' '789'
123 456 789
----
-h -> "abc def"
$1 -> 123 456
$2 -> 789
$3 ->
$4 ->


--
코드를 조금 더 업데이트 해 보았습니다. 옵션값이 quote 를 사용할 떄 escape 를 해야 했는데 불편해서 하지 않아도 되도록 개선해 보았습니다. 이 이슈 때문에 getopt 를 eval 을 했었는데 굳이 하지 않아도 되었더군요. ㅠ

#!/bin/bash

echo "input: $@"

opts="$( getopt -o ah: -l aa,hhh: -- "$@" )"
echo "opts -> ${opts}"
eval set -- "${opts}"

echo "input -> ${opts}"

for i
do
case "${i}" in
-a|--aa)
A=1
shift
;;
-h|--hhh)
H="${2}"
shift 2
;;
--)
shift;
break
esac
done

echo "$@"
echo "----"
echo "-h -> $H"
echo "\$1 -> $1"
echo "\$2 -> $2"
echo "\$3 -> $3"
echo "\$4 -> $4"
이렇게 하면 옵션값에 quote  를 사용할 때 escape 를 하지 않아도 됩니다.
[user@host ~]$ bash test.sh 123\ 456 -h '"abc def"' 789
iinput: 123 456 -h "abc def" 789
opts -> -h '"abc def"' -- '123 456' '789'
input -> -h '"abc def"' -- '123 456' '789'
123 456 789
----
-h -> "abc def"
$1 -> 123 456
$2 -> 789
$3 ->
$4 ->
2023/01/06 13:22 2023/01/06 13:22
Posted
Filed under Tech/프로그래밍
디스크 크기나 네트워크 전송 대역폭 등을 단위대로 보기 좋게 하기 위한 코드를 살펴보겠습니다.
C나 여러 언어로 많이 있으나, bash 로는 딱히 마음에 드는 코드가 없어 만들어 보았습니다.

HUMANREADABLE_SIZE_SUFFIX=( "B" "KB" "MB" "GB" "TB" )
# HUMANREADABLE_SIZE req_size base_suffix
function HUMANREADABLE_SIZE {
local suffix=${2:-0}
local size=$1
local isize=${size}

while [ 1 ]
do
(( isize < 1024 )) && break
size="$( bc <<< "scale = 2; ${size} / 1024" )"
isize=${size%%.*}
let "suffix += 1"
done

echo "${size} ${HUMANREADABLE_SIZE_SUFFIX[suffix]}"
}


사용법은 간단합니다.

HUMANREADABLE_SIZE 입력_숫자 입력단위(0-B,1-KB,2-MB,3-GB)


[root@host ~]# # convert 1024 B
[root@host ~]# HUMANREADABLE_SIZE 1024
1KB
[root@host ~]# # convert 1024 KB
[root@host ~]# HUMANREADABLE_SIZE 1024 1
1MB
[root@host ~]# # convert 1024 MB
[root@host ~]# HUMANREADABLE_SIZE 1024 2
1GB
[root@host ~]# # convert 1024 GB
[root@host ~]# HUMANREADABLE_SIZE 1024 3
1TB


변환 값을 변수로 받고 싶다면 다음과 같이 할 수 있습니다.


[root@host ~]# SIZE=$( HUMANREADABLE_SIZE 1024 3 )
[root@host ~]# echo -n ${SIZE} # newline 이 없어야 할 경우..
2021/01/13 11:45 2021/01/13 11:45
Posted
Filed under Tech/프로그래밍
만들 때 마다 헷갈리고 까먹어서 기록해 놓아야 겠다.

# USAGE: compare_version OLD NEW
# RETURN:
# (OLD == NEW) return 0
# (OLD < NEW) return 1
# (OLD > NEW ) return 2
function compare_version {
local opt
[[ $1 == $2 ]] && return 0

# -V option 이 지원되지 않을 경우, 숫자 이외의 문자가 들어간 버전 비교가
# 정확하지 않을 수 있다. 예) 2.1.9-3el6_7.2
sort -V >& /dev/null <<< "aa"
[[ $? == 0 ]] && opt="V"

test "$(printf '%s\n' "$@" | sort -r${opt} | head -n 1)" != "$1";
res=$?
[[ $res == 0 ]] && return 1 || return 2
}


결과

[root@host ~]# source version_comapre.sh
[root@host ~]# compare_version 3 3
0
[root@host ~]# compare_version 3 4
1
[root@host ~]# compare_version 4 3
2
[root@host ~]#
2020/06/08 16:41 2020/06/08 16:41
Posted
Filed under Tech/프로그래밍
서버를 관리하다 보면 legacy OS 까지 고려하면서 코드를 작성해야 할 경우가 종종 있습니다.

스크립팅을 하다 보면 sort -V 옵션을 종종 사용해야 할 경우가 있습니다. 그런데 old OS 에 있는 sort 는 -V 옵션이 없는 경우가 있을 수 있습니다.

[root@host ~]# sort --help | grep -- "-V"
-V, --version-sort natural sort of (version) numbers within text
[root@host ~]#

sort -V 옵션이 필요한 경우는 대부분 다음과 같습니다.

cat << EOL | sort
1
2
10
20
EOL

위의 코드의 결과로는 보통은 1.. 2.. 10 .. 20 의 순서대로 나오기를 기대하게 됩니다. 하지만 위의 코드 결과는 실제

1
10
2
20

과 같이 의도하지 않는 출력이 되게 됩니다. 그러다 보니 어쩔수 없이 sort -V 를 구현을 해야 하게 됩니다.

아래 코드는 sort -V 옵션을 bash function 으로 만든 것입니다. license 는 BSD 2 clause 로 사용해 주시면 됩니다.

function sortv {
local var
local i

if [[ $# == 0 ]]; then
i=0
while read var_t
do
var[i++]="${var_t}"
done < /dev/stdin
else
var=( $* )
fi

(
for i in ${var[@]}
do
printf "ibase=2; %07d\n" "$(bc <<< "obase=2; ${i}")"
done
) | sort | bc
}

sort -V 2> /dev/null <<< "1"
[ $? -eq 0 ] && sort="sort -V" || sort="sortv"

cat <<EOL | ${sort}
1
10
2
20
EOL

출력 결과는

1
2
10
20


P.S.
기존의 sortv 함수가 문자열이나 공백이 들어갈 경우 문제가 되어 개선을 해 보았습니다.

function sortv {
local var
local i
if [[ $# == 0 ]]; then
i=0
while read var_t
do
var[i++]="${var_t}"
done < /dev/stdin
else
var=( $* )
fi

(
for i in "${var[@]}"
do
perl -p -e 's/([0-9]{4})/$1#~~#/g; s/([0-9]+)/`bc <<< "obase=2; $1" | xargs printf "%020d~~"`/eg' <<< "${i}"
done
) | sort | perl -pe 's/([0-9]{20})~~/`bc <<< "ibase=2; $1" | xargs printf "%s"`/eg; s/[0-9]{4}#~~#/$1/g'
}

sort -V 2> /dev/null <<< "1"
[ $? -eq 0 ] && sort="sort -V" || sort="sortv"

cat <<EOL | ${sort}
/home/0 asdfdsakf298u098uop;
/home/2 asdfdsakf298u097uop;
/home/5 asdfdsakf298u098uop;
/home/4 asdfdsakf298u098uop;
/home/11 asdfdsakf298u098uop;
/home/3 asdfdsakf298u028uop;
/home/1
EOL

출력 결과는 

/home/0  asdfdsakf298u98uop;
/home/1
/home/2 asdfdsakf298u97uop;
/home/3 asdfdsakf298u28uop;
/home/4 asdfdsakf298u98uop;
/home/5 asdfdsakf298u98uop;
/home/11 asdfdsakf298u98uop;
2020/01/16 18:47 2020/01/16 18:47
Posted
Filed under Tech/프로그래밍
3/17 에 putty 0.71 이 release 가 되었네요. iPuTTY 0.71 release 를 시작 해야겠습니다.

0.70 에서 0.71 release 되기 까지 꽤 오랜 시간이 되었고, commit 양도 어마어마하네요. iPuTTY 에 반영한 변경 사항이 잘 merge가 될지 모르겠습니다. 좀 자주 release 해 주는게 merge 하는데는 더 편할 수도 있을 것 같네요.
2019/03/24 04:20 2019/03/24 04:20
김정균

설정 파일 저장하는 부분의 api declare 가 완전히 변경이 되어 시간이 소요되고 있습니다. iPuTTy에서 설정파일을 파일로 저장하는 기능이 있는데, 이 부분을 완전히 새로 작성해야 할 것 같네요.

Posted
Filed under Tech/프로그래밍
현재 접속해 있는 host가 vm guest 인지 아닌지 여부를 확인 하는 방법은 보통 다음과 같다.

1. dmidecode 에서 Xen 또는 VMware 가 있는지 찾기
2. Xen guest의 CentOS 6 이하는 dmidecode를 제대로 지원하지 않는 경우가 많은데, 이 경우에는 ps 명령에서 xenbus 를 찾는 방법이 있다.

여기서 논하는 방법은 CPU ID를 확인하는 방법인데, VMWare 문서에 의하면 다음과 같이 소개하고 있다.

Intel 및 AMD의 CPU는 CPUID 리프 0x1의 ECX의 비트 31을 하이퍼 바이저 존재 비트로 예약하고 있습니다. 이 비트에 의해 하이퍼 바이저는 게스트 OS에 그 존재를 나타낼 수 있습니다. 하이퍼 바이저는이 비트를설정하여 실제 CPU (모든 기존 CPU와 장래의 CPU)는이 비트를 0으로 설정합니다. 게스트 OS는 31 비트를테스트하여 그 하이퍼 바이저가 가상 머신 내에서 실행되고 있는지를 확인할 수 있습니다.

Intel 및 AMD는 소프트웨어에서 사용할 수 있도록 CPUID 리프 0x40000000 ~ 0x400000FF도 예약하고 있습니다. 하이퍼 바이저는 이러한 리프를 사용하여 하이퍼 바이저에서 가상 머신 내에서 실행되는 게스트 OS에 정보를 전달하기위한 인터페이스를 제공 할 수 있습니다. 하이퍼 바이저 비트는 하이퍼 바이저가 존재하는 것을 의미하며 이러한 추가 소프트웨어 리프를 테스트하는 것이 안전하다는 것을 보여줍니다. VMware는 0x40000000 리프를 하이퍼 바이저 CPUID 정보 리프로 정의합니다. VMware 하이퍼 바이저 코드를 실행함으로써 하이퍼바이저 서명이 있는지 CPUID 정보 리프를 테스트 할 수 있습니다. VMware는 CPUID 리프 0x40000000의 EBX, ECX, EDX에 "VMwareVMware"라는 문자열을 저장합니다.

이 내용을 C code 로 만들면 다음과 같다.


#include <stdio.h>
#include <string.h>

// https://stackoverflow.com/questions/6491566/getting-the-machine-serial-number-and-cpu-id-using-c-c-in-linux
static inline void cpuid (unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
{
/* ecx is often an input as well as an output. */
asm volatile (
"cpuid"
: "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
: "0" (*eax), "2" (*ecx)
);
}

// https://kb.vmware.com/s/article/1009458
int cpuid_check (void) {
unsigned int eax, ebx, ecx, edx;
char hyper_vendor_id[13];
//cpuid(0x1, &eax, &ebx, &ecx, &edx);
eax = 0x1;
cpuid (&eax, &ebx, &ecx, &edx);

// bit 31 of ecx is set
// 0x8000000 10000 0000 0000 0000 0000 0000 0000 0000
if ( ecx >= 0x80000000 ) {
//cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
eax = 0x40000000;
cpuid (&eax, &ebx, &ecx, &edx);
memcpy (hyper_vendor_id + 0, &ebx, 4);
memcpy (hyper_vendor_id + 4, &ecx, 4);
memcpy (hyper_vendor_id + 8, &edx, 4);
hyper_vendor_id[12] = '\0';

//printf ("This is GuesVM %s\n");
//printf ("##################### %s\n", hyper_vendor_id);

// VMwareVMware
if ( ! strncmp (hyper_vendor_id, "VMware", 6) )
return 0; // Success - running under VMware
// XenVMMXenVMM
else if ( ! strncmp (hyper_vendor_id, "XenVM", 5) )
return 0; // Success - running under Xen
}

return 1;
}

int main (void) {
// if guest vm return 0 and case others, return 1
return cpuid_check ();
}


이 코드는 VMWare EX 5.1 이상에서 정상 동작 함을 확인 했고, Xen server의 경우 7 에서 정상 동작하며, Xen server 6.5의 경우 CentOS 6.x 이하에서는 CPU  id 에서 해당 영역값을 읽어오지 못한다. 즉, legacy system에서는 동작하지 않을 수 있다.
2019/01/30 13:30 2019/01/30 13:30
Posted
Filed under Tech/프로그래밍
iPuTTY 0.70.2 release 소식 입니다.

왠만하면 PuTTY 0.71 을 기다리려고 하고 있는데, release 될 생각이 없는 듯 싶네요.  뭐 PuTTY 가 거의 보안버그 나올 경우만 업데이트 되는 경향이 강해서.. 0.61 출시 때 처럼 몇년이 걸릴지 모르겠습니다.

그래서 일단, iPuTTY의 기능에 대한 업데이트로 release 를 합니다.
0.70.2 의 주요 내용은, ZMODEM 기능 개선이며, 드디어 Drag & Drop 으로 ZMODEM 파일 전송이 가능해졌습니다.

ZMODEM 사용법에 대해서는 https://github.com/iPuTTY/iPuTTY/wiki 의 ZMODEM 항목을 참고 하세요.

Download: https://github.com/iPuTTY/iPuTTY/releases/tag/l0.70.2i

Changes:

  • ZMODEM Drag & Drop 지원 (#41)
  • ZMODEM 의 sz 파일 경로 체크 오류 수정 (#40)
2018/10/07 21:54 2018/10/07 21:54
Posted
Filed under Tech/프로그래밍
0.70.1 release 소식 입니다.

0.70.1 은 iPuTTY 수정 사항에 대한 bug 나 신 기능에 대한 업데이트 입니다.

Download: https://github.com/iPuTTY/iPuTTY/releases/tag/l0.70.1i

Changes:


  • Vista 이후 사용되지 않는 ONTHESPOT 패치 코드 제거 (#20)
  • OTP와 같은 2 단계 인증 시에 저장되어 있는 암호가 잘못 입력 되는 문제 수정 (#31)
  • 명령행으로 실행 시에, 파일 세션을 불러오지 못하는 문제 수정 (#33)
  • 명령행으로 실행 시에, ssh:putty: 지원 (#35)
  • ZMODEM 단축키 지원 (#36) - 받기 F11 / 보내기 F12
  • MacOS의 SSH server로 로그인 시에, NFC 문제로 한글이 깨져 보이는 문제 수정 (#38)
  • 암호 저장시에, 암호 길이가 3의 배수일 경우 로그인 실패하는 문제 수정 (#39)



2018/04/29 22:23 2018/04/29 22:23
Posted
Filed under Tech/프로그래밍
0.70 release  소식 입니다.

iPuTTY 업데이트 사항:
  • fixed #27 wrong translattion
  • fixed #28 Fixedsys 폰트의 사용 on windows 10
  • fixed #30 add Hanterm key map
  • pscp의 기본 문자셋을 cp949에서 utf-8로 변경 (1e68e28)
PuTTY 업데이트 사항:
  • Security fix: the Windows PuTTY binaries should no longer be vulnerable to hijacking by specially named DLLs in the same directory, even a name we missed when we thought we'd fixed this in 0.69. See vuln-indirect-dll-hijack-3.
  • Windows PuTTY should be able to print again, after our DLL hijacking defences broke that functionality.
  • Windows PuTTY should be able to accept keyboard input outside the current code page, after our DLL hijacking defences broke that too.

릴리즈 패키지는 https://github.com/iPuTTY/iPuTTY/releases/tag/l0.70i 에서 제공 합니다.
2017/07/25 00:12 2017/07/25 00:12