사용하는 서버에 mysql이 설치되어 있다면 mysql
설치경로에서 mysql_setpermission 프로그램을 찾아보기 바란다.
이 프로그램은 다름 아닌 Perl로 만들어진 시스템 도구의 일종이다.
이 프로그램은 mysql을 사용함에 있어 번거로운 작업이 아닐 수
없는 database와 user의 생성 및 권한조정 등의 작업을 자동화한
도구이다. 뿐만 아니라 my sqlaccess, mysql_find_rows, mysql_zap
등의 프로그램도 마찬가지로 Perl로 만들어진 시스템 도구의 일종이다.
이렇듯 Perl을 이용해 시스템 도구를 만들어두면 빈번하게 발생하는
복잡한 작업들을 자동화할 수 있어 서버 운영자 및 시스템 사용자에게
편리함을 제공한다.
Perl 소스 프로그램을 시스템 도구로 직접 사용하기
위해서는 앞서 설명했듯이 실행권한(chmod +x)을 부여하고 소스
첫 번째 줄에 Perl의 위치를 지정해줘야 한다. 또한 Perl 소스 프로그램이
PATH에 걸려있지 않다면 ./program 과 같이 실행해야 한다는 점을
잊지 말자.
1. Perl 명령행 옵션
Perl을 명령행에서 실행할 경우 목적에 따라
다양한 옵션을 사용할 수 있다. Perl이 시스템 도구로 사용될 때
특히 옵션을 자주 사용하게 되는데, 주로 사용되는 명령행 옵션은
다음과 같다.
옵션 |
설명 |
e |
주어진 Perl 명령 실행 |
p |
지정한 파일을 대상으로
작업 |
i |
원본파일을 결과파일로
대체 |
c |
구문검사(문법에러
점검) |
v |
Perl 버전정보 |
V |
Perl 버전정보(상세) |
w |
경고 출력(개발과정에
주로 사용) |
U |
비안전모드, SUID 적용시
사용 |
2. 문자열 일괄 치환
회사명이나 도메인, 메일주소 등이 바뀌었을
때 수많은 문서파일에 적힌 내용을 모두 고치기란 쉬운 일이 아니다.
하지만 Perl을 이용하면 너무도 간단히 변경 내용을 반영할 수 있다.
아래 명령은 html 확장자를 지닌 문서파일에서 “우정”이라는 문자열을
찾아 “사랑”이라는 문자열로 모두 치환하는 명령(Perl 명령행
옵션)이다.
find 명령을 이용하면 하위 경로의 문서도 일괄적으로
치환할 수 있다.
3. 파일명 대소문자 일괄변경
파일명의 대소문자를 구분하지 않는 운영체제(윈도우즈
등)에서 생성된 파일명은 많은 문제를 야기하곤 한다. 특히 HTML
문서에서 링크오류를 유발하거나 파일명을 입력할 때 입력혼선을
가중시키기도 한다. 하지만 다음 도구(recase)를 이용하면 파일명을
소문자 또는 대문자로 일괄적으로 변경할 수 있다.
$ ls HOME.GIF
LIST.GIF NEXT.GIF $ recase * (또는 $ recase
-l *) $ ls home.gif list.gif next.gif
$ recase -u * $ ls HOME.GIF LIST.GIF NEXT.GIF |
File Name : recase |
#!/usr/bin/perl
# 사용법 : recase [옵션] [파일 리스트] # 옵션
: -l(소문자, 기본값), -u(대문자) # 옵션 점검(소문자화
또는 대문자화) if($ARGV[0] =~ /-L/i)
{ $method=”L”; shift; } elsif($ARGV[0] =~
/-U/i) { $method=”U”; shift; } else
{ $method = “L”; }
foreach $file (@ARGV) { #
디렉토리인 경우 처리하지 않음 next if -d $file;
($dir, $filename) = $file =~ /(.*[\/\\])(.*)$/;
$filename = $file if $file !~ /\//; # 변경이
필요한 파일명인지 확인 next if $method eq “L”
and $filename !~ /[A-Z]/; next
if $method eq “U” and $filename !~ /[a-z]/;
# 대소문자 변환 $filename =~ tr/A-Z/a-z/
if $method eq “L”; $filename =~ tr/a-z/A-Z/
if $method eq “U”; if(-f “$dir$filename”)
{ # 새로운 이름의 파일이 이미 존재하는 경우
print “Already exist! : $dir$filename\n”;
next; } # 파일명 변경 rename(“$file”,
“$dir$filename”); |
특정경로 이하의 모든 파일명을 소문자로 변경하려면
다음과 같이 사용하면 된다.
$ find way-cart
-type f -exec recase {} \; |
4. 문서형식 변환(UNIX ↔ DOS)
Perl이나 shell 스크립트 파일을 바이너리(Binary)
모드로 전송(FTP 등)하면 스크립트 실행시 에러가 발생하곤 한다.
이를 극복하기 위해서는 파일을 아스키(ASCII) 모드로 다시 전송하면
되지만, Perl을 이용해 간단히 해결할 수도 있다. 이는 앞서 설명한
‘문자열 치환’과 동일한 원리다.
# DOS → UNIX
문서형식으로 변환 $ perl -pi -e “s/\r//”
*.cgi
# UNIX → DOS 문서형식으로 변환
$ perl -pi -e “s/\n/\r\n/” *.txt |
명령(Perl 명령행 옵션)이 기억하기 쉽지만은
않을 테니 shell 스크립트로 한번 만들어 보자. 파일에 실행권한을
부여한 후 사용자들의 PATH에 포함되어있는 경로(/usr/local/bin
등)에 위치해두면 편리하게 사용할 수 있을 것이다.
File Name : dos2unix |
#!/bin/sh # DOS
→ UNIX 문서형식으로 변환 perl -pi -e “s/\r//”
$*
File Name : unix2dos #!/bin/sh
# UNIX → DOS 문서형식으로 변환 perl -pi -e
“s/\n/\r\n/” $* |
5. 파일 크기정보 출력 및 활용
다음은 지정한 파일의 크기를 출력하는 도구(sizeof)로서,
얻어진 정보는 다른 응용프로그램에서도 활용할 수 있다.
File Name : sizeof |
#!/usr/bin/perl
# 1. 파일테스트 연산자중 -s(Size) 옵션 이용
# 2. 하나의 파일만 확인할 때는 # 다른 응용프로그램에서
활용할 수 있도록 # 파일크기만 출력 if($#ARGV
eq 0) { print -s $ARGV[0]; exit; } foreach
(@ARGV) { print “$_ : “, -s $_, “\n”; } |
$ sizeof *.cgi
way-admin.cgi :
46031
way-board.cgi : 19065
way-notice.cgi : 6264
그런데 이런 도구는 언제 쓰일까?
필자는
매주 1G byte가 넘는 자료를 원격으로 백업 받는다. 그런데 백업파일이
저장될 컴퓨터를 항상 켜둘 수 없는 특수한 상황인지라 백업이 종료되면
자동으로 halt시켜야 한다.
문제는 정상적으로 백업이 이루어졌는지
알 수 없는 상태에서 무턱대고 halt시켜서는 안된다는 점이다. 그래서
생각해낸 것은(물론 다른 방법으로도 가능하다.) 수신된 백업파일
크기를 확인하여 원본파일과 동일한 크기일 경우만 halt명령을 실행하도록
하는 것이다.
File Name : remotebackup |
#!/bin/sh # 사용법 : remotebackup
[백업파일크기] # 파일 다운로드 ncftpget
-u way -p “********” \ “ftp://way.co.kr/backup/19991231.tar.gz”
# 외부명령인 Perl 프로그램을 실행하고 #
결과를 받아오기 위해 Perl에서와 마찬가지로
# shell 스크립트도 `(역따옴표)기호 사용
SIZE=`sizeof 19991231.tar.gz` # 입력한 파일크기와
백업 받은 파일크기 비교 if [ “X$1” = “X${SIZE}”
] # 일치(정상백업)할 경우 시스템 종료
then halt fi
|
6. 수치정보 컴마 표기
File Name : comma |
#!/usr/bin/perl
# 사용법 : comma [수치] 1 while $ARGV[0] =~
s/(\d+)(\d{3})/$1,$2/; print $ARGV[0]; |
이 도구는 또 언제 사용될까? 필자는 계정 사용자의
웹서버 로그파일을 이용해 일일 자료 전송량을 산출한다. 산출된
정보를 출력할 때 식별을 용이하게 하기 위해 이 도구를 이용해
3자리마다 컴마를 넣어 출력하고 있다.
$ comma 1234567890
1,234,567,890
앞서 소개한 remotebackup과 마찬가지로 shell
스크립트 등의 응용프로그램에서 외부명령으로 comma 명령을 사용하면
보기 좋게 수치정보를 표시할 수 있을 것이다.
파일 크기를 파악한 후 보기 좋게 출력해보자.
$ comma `sizeof way-board.cgi`
19,065
7. 파일 부분 출력
이제 소개할 도구는 특정 파일의 일부분을 출력하는
도구다. 예를 들어 tmp라는 파일의 5번째 줄부터 3줄을 출력하고자
한다면 다음과 같이 사용한다.
$ cat tmp
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line
9
Line 10
$ partprint 5 3 tmp
FILE
: tmp
LINE
: (from 5 to 7 / total 10)
Line 5
Line 6
Line 7
File Name : partprint |
#!/usr/bin/perl
# 사용법 : partprint [시작줄] [출력줄] [파일]
$start = shift; $end = shift; $filename
= shift; open(FILE, “$filename”) or die
“Error: $filename, $!”; @File = <FILE>;
close(FILE); $start --; $start = 0 if $start
< 0; $end = 0 if $end < 0; $end --;
$end = $start + $end; print “=” x 80, “\n”;
print “FILE : $filename\n”; print “LINE
: “; print “(from “, $start + 1, “ to “,
$end + 1, “ / total “, $#File+1, “)\n”;
print “=” x 80, “\n”; @File = @File[$start
.. $end]; foreach (@File) { print $_; } |
8. 웹호스팅 서버관리 시스템
이제 간단하면서도 종합적인 기능을 수행하는
시스템 도구를 만들어 보자. 이 도구는 세 곳의 웹호스팅 업체에서
10개월 전부터 유용하게 사용되고 있다. 지면으로 옮기기 어려운
일부 기능은 배제하였으며, 소스를 소개하고 각 부분의 기능을 설명함으로써
이해와 응용을 돕고자 한다.
실제 사용을 원한다면 임시 서버를
이용해 여러 차례 시험을 거친 후 사용하기를 권하며 super user
권한으로 실행되므로 세심한 주의를 요한다.
주요 기능은 다음과 같다.
가. 사용자 계정
관리
나. POP 계정 관리
다. 디스크 할당
라. 도메인
설정
마. 데몬(bind, sendmail, apache) 관리
#!/usr/bin/perl
#=====================================
config();
menu();
#=====================================
sub config {
# 이 루틴은 시스템에서 사용할
주요 설정을 선언하는
# 부분이다.
# 그룹 및 사용자 기본값으로서
# 이미 존재하는
그룹 및 사용자여야 한다.
# 계정 추가시 기본 그룹
$user_basegroup
= “user”;
# POP계정 추가시 기본 그룹
$pop_basegroup
= “pop”;
# 디스크 할당 표본 사용자
$disk_baseuser
= “way”;
# 사용자 계정 관리 등에서 조작이 허용되는
최소 UID
$min_uid = 500;
# 사용자에게 부여할 IP 주소를 기록한다.
# Name-based Virtual Host(apache)를 전제로 한다.
$ip_address
= “210.123.12.1”;
# 아래 경로들은 /etc/skel에 미리 생성되어
있어야 한다.
# $ mkdir /etc/skel/public_html /etc/skel/wwwlog
# 웹문서 경로
$webdir = “public_html”;
# 웹로그 경로
$logdir = “wwwlog”;
# 아래는 특수한 경우가 아닌 한 변경할 필요가
없다.
# shadow 시스템을 사용하더라도 변경할 필요가 없다.
# 비밀번호 파일
$pass_file = “/etc/passwd”;
# 그룹파일
$group_file = “/etc/group”;
# Message
$prog_msg = “[MSG] “;
}
#=====================================
sub menu {
# 이 루틴은 기본 메뉴화면을
출력하는 기능을 한다.
# 실행자가 super user가 아니면 종료한다.
chomp($run_id = `id -u`);
if($run_id ne “0”) {
print
“$prog_msg 실행권한이 없습니다.(UID:$run_id)\n”;
exit;
}
# get_date 함수를 통해 현재 시간정보를 얻는다.
$date_info = get_date(time);
$date_seri = “$date_info”
. “01”;
# 화면을 정리하고 출력한다.
system(“clear”);
print <<”__END__”;
웹호스팅
서버 관리 시스템
11. 계정 등록 26.
사용자 password 지정
12. 계정 삭제 27.
13. 계정 조회 28.
프로세서 조회
14. 전체 계정 조회 29.
데몬 관리
15. POP 계정 등록 30.
16. 31.
17. 디스크 할당 32.
18. 디스크 할당(수동) 33.
19. 디스크 할당 조회 34.
20. 35.
21. 도메인 등록 36.
22. 도메인 정보 갱신 37.
23. 도메인 정보 상세조회 38.
24. 39.
25. 40.
\\. EXIT
__END__
print “ 선택 : “;
$choice = <STDIN>;
chomp $choice;
print “-” x 80, “\n”;
# 입력한
메뉴번호에 따라 해당되는 기능을 수행한다.
if ($choice eq
11) { add_user(); }
elsif ($choice eq 12) { delete_user();
}
elsif ($choice eq 13) { query_user(); }
elsif ($choice
eq 14) { all_user_info(); }
elsif ($choice eq 15) { pop_add();
}
elsif ($choice eq 17) { disk_quota(); }
elsif ($choice
eq 18) { disk_quota_edit(); }
elsif ($choice eq 19) { disk_query();
}
elsif ($choice eq 21) { add_domain(); }
elsif ($choice
eq 22) { domain_apply(); }
elsif ($choice eq 23) { domain_display();
}
elsif ($choice eq 26) { pass_define(); }
elsif ($choice
eq 28) { ps_ax(); }
elsif ($choice eq 29) { demon(); }
elsif ($choice eq “\\”) { print “\nbye...\n\n”; exit;
}
else { menu(); }
}
#=====================================
# 여기서부터는 시스템에서 공통적으로 사용되는
# 함수들이다.
sub check {
# 명령의 실행을 최종적으로
확인하도록 하는 루틴
print “$prog_msg 확실합니까? [yes/No]
“;
$input = <STDIN>;
chomp $input;
if ($input =~ /yes/i) { return; }
else { print
“\n$prog_msg 실행을 취소합니다. [Enter] “;
$input = <STDIN>;
menu(); }
}
sub end {
# 실행결과를 출력하고 초기화하는
루틴
local ($end) = @_;
if ($end eq “”) { $end = “처리가
완료되었습니다.”; }
print “\n$prog_msg $end [Enter] “;
$input = <STDIN>;
exec(“$0”);
}
sub file_error {
# 파일 조작시 문제가
발생하면 에러사실을 경고하는 루틴local ($err) = @_;
if ($err
eq “”) { $err = “파일 저장 오류, $FILE”; }
print “=”
x 30 . “ 중대 오류 발생 “ . “=” x 30 . “\n”;
print “ 오류 내용 : $err \n”;
print “=” x 80;
print
“중대한 오류입니다.”;
print “ 해당 파일을 면밀히 검토하시기
바랍니다.\n”;
exit;
}
sub user_check {
# 넘겨받은 사용자 ID
등의 정보를 이용해 사용자 정보를
# 얻는 함수
local ($search_data,
$search_field) = @_;
$FILE = “$pass_file”;
open(FILE,
“$FILE”) || file_error(“파일 읽기 오류, $FILE”);
while($user_data
= <FILE>) {
chomp $user_data;
@ud = split(“:”,
$user_data);
$search_fld = $search_field -
1;
$search_fld_data = $ud[$search_fld];
if ($search_data
eq $search_fld_data) {
return $user_data; }
}
close(FILE);
return 0;
}
sub group_check {
# 넘겨받은 그룹 ID 등의
정보를 이용해 그룹 정보를
# 얻는 함수
local ($search_data,
$search_field) = @_;
$FILE = “$group_file”;
open(FILE,
“$FILE”) || file_error(“파일 읽기 오류, $FILE”);
while($group_data
= <FILE>) {
chomp $group_data;
@gd
= split(“:”, $group_data);
$search_fld = $search_field
- 1;
$search_fld_data = $gd[$search_fld];
if ($search_data
eq $search_fld_data) {
return $group_data; }
}
close(FILE);
return 0;
}
sub get_date {
# 시간정보를 얻는 함수
local ($data) = @_;
local ($second, $minute, $hour, $date,
$month,
$year, $weekday, $yearday, $Isdst) = localtime($data);
$month ++;
$year += 1900;
$month <
10 && ($month = “0$month”);
$date
< 10 && ($date = “0$date”);
$hour < 10 && ($hour = “0$hour”);
$minute < 10 && ($minute = “0$minute”);
$second < 10 && ($second = “0$second”);
return “$year$month$date”;
}
#=====================================
# 여기서부터는 메뉴에 나열된 실제 작업을 수행하는
# 루틴이다.
sub add_user {
# 11. 계정 등록
print
“$prog_msg 등록할 사용자 ID : “;
$id = <STDIN>;
chomp $id;
if ($id eq “”) { add_user(); }
if ($id
eq “\\”) { menu(); }
if (user_check($id, “1”)) {
end(“이미 등록되어있는 ID입니다.”); }
print “$prog_msg
등록할 사용자의 소속그룹”;
print “(default=$user_basegroup)
: “;
$grp = <STDIN>;
chomp $grp;
if ($grp eq “”) { $grp = $user_basegroup; }
if ($grp
eq “\\”) { menu(); }
if (!group_check($grp, “1”))
{
end(“등록되지 않은 GROUP입니다.”); }
check();
# adduser 명령에 -g 옵션을 사용해 그룹을 지정한다.
system(“/usr/sbin/useradd
$id -g $grp”);
# 웹로그 경로의 소유권을 super user로 바꾼다.
system(“/bin/chown 0.0 /home/$id/$logdir”);
end();
}
sub delete_user {
# 12. 계정 삭제
print “$prog_msg 삭제할 사용자 ID : “;
$id = <STDIN>;
chomp $id;
if ($id eq “”) { delete_user(); }
if ($id eq “\\”) { menu(); }
if (!($user_data
= user_check($id, “1”))) {
end(“등록되지 않은 ID입니다.”);
}
($ud1, $ud2, $ud3, $ud4, $ud5, $ud6, $ud7)
= split(“:”,
$user_data);
if ($ud3 < $min_uid) {
end(“해당
ID를 삭제할 수 없습니다.”); }
check();
# userdel 명령에
-r 옵션을 이용해 계정을 삭제한다.
# 자료보호를 위해 삭제할
계정의 홈경로가 /home 경로
# 하위에 위치하지 않으면 홈경로를
삭제하지 않는다.
if($ud6 =~ /^\/home/) { $home_del = “-r”;
}
system(“/usr/sbin/userdel $home_del $id”);
end();
}
sub query_user {
# 13. 계정 조회
#
지정한 사용자에 대해 다음과 같은 결과를 출력한다.
# [MSG]
조회할 사용자 ID : way
# [MSG] ID : way (539)
# [MSG]
GROUP : user (500)
# [MSG] HOME DIR : /home/way
# [MSG]
SHELL : /bin/bash
print “$prog_msg 조회할 사용자 ID : “;
$id = <STDIN>;
chomp $id;
if ($id
eq “”) { query_user(); }
if ($id eq “\\”) {
menu(); }
if (!($user_data = user_check($id, “1”)))
{
end(“등록되지 않은 ID입니다.”); }
($ud1, $ud2, $ud3,
$ud4, $ud5, $ud6, $ud7)
= split(“:”, $user_data);
$s_group = $ud4;
if (!($group_data = group_check($s_group,
“3”))) {
end(“등록되지 않은 GROUP입니다. (GID=$s_group)”);
}
($gd1, $gd2, $gd3, $gd4) = split(“:”, $group_data);
print “$prog_msg ID : $id ($ud3)\n”;
print “$prog_msg
GROUP : $gd1 ($s_group)\n”;
p
rint “$prog_msg HOME DIR : $ud6\n”;
print “$prog_msg SHELL : $ud7\n\n”;
end(“조회가 완료되었습니다.”);
}
sub all_user_info {
# 14. 전체 계정 조회
# 비밀번호 파일을 출력한다.
$FILE = “$pass_file”;
open(FILE, “$FILE”) || file_error(“파일 읽기 오류, $FILE”);
while($user_data = <FILE>) {
chomp $user_data;
@ud = split(“:”, $user_data);
$search_fld_data = $ud[2];
if ($search_fld_data > = $min_uid ) {
$print_data
.= “$user_data\n”; }
}
close(FILE);
print $print_data;
end(“조회가 완료되었습니다.”);
}
sub pop_add {
# 15. POP 계정 등록
print “$prog_msg 등록할 POP ID : “;
$id = <STDIN>;
chomp $id;
if ($id eq “”) { pop_add(); }
if
($id eq “\\”) { menu(); }
if (user_check($id,
“1”)) {
end(“이미 등록되어있는 ID입니다.”); }
print
“$prog_msg 등록할 사용자의 소속그룹”;
print “(default=$pop_basegroup)
: “;
$grp = <STDIN>;
chomp $grp;
if ($grp
eq “”) { $grp = $pop_basegroup; }
if ($grp eq “\\”)
{ menu(); }
if (!group_check($grp, “1”)) {
end(“등록되지
않은 GROUP입니다.”); }
check();
# POP 계정은 noshell이라는
간단한 쉘스크립트를
# 기본 shell로 지정한다.
File Name : /usr/local/bin/noshell
#!/bin/sh
echo
echo “ ============================= “
echo “
현재 접속하신 ID는”
echo “ TELNET, FTP 접속이 허용되지”
echo “ 않습니다.”
echo “ =============================
“
echo
system(“/usr/sbin/useradd $id -g $grp -M
\\
-s /usr/local/bin/noshell -d /”);
end();
}
sub disk_quota {
# 17. 디스크 할당
# quota 기능을 이용해 사용자의 디스크를 할당한다.
print
“$prog_msg 디스크를 할당할 사용자 ID : “;
$id =
<STDIN>;
chomp $id;
if ($id eq “”)
{ disk_quota(); }
if ($id eq “\\”) { menu(); }
if (!user_check($id, “1”)) {
end(“등록되지 않은
ID입니다.”); }
print “$prog_msg 표본 사용자 ID(default:$disk_baseuser)
: “;
$id_2 = <STDIN>;
chomp $id_2;
if ($id_2 eq “”) { $id_2 = $disk_baseuser; }
if
($id_2 eq “\\”) { menu(); }
if (!user_check($id_2,
“1”)) {
end(“등록되지 않은 ID입니다.”); }
check();
# edquota 명령에 -p 옵션을 이용해 새로 지정할
# 사용자에게
표본 사용자의 디스크 할당정보를
# 복사한다.(man edquota)
system(“/usr/sbin/edquota -p $id_2 $id”);
end();
}
sub disk_quota_edit {
# 18. 디스크 할당(수동)
print “$prog_msg 디스크를 할당할 사용자 ID : “;
$id =
<STDIN>;
chomp $id;
if ($id eq “”)
{ disk_quota_edit(); }
if ($id eq “\\”) { menu();
}
if (!user_check($id, “1”)) {
end(“등록되지
않은 ID입니다.”); }
check();
system(“/usr/sbin/edquota
-u $id”);
end();
}
sub disk_query {
# 19. 디스크 할당 조회
print “$prog_msg 디스크 사용상황을 조회할”;
print “ 사용자
ID(default:all) : “;
$id = <STDIN>;
chomp $id;
if ($id eq “”) { $id = “ALL”; }
if ($id eq “\\”) { menu(); }
if ( !user_check($id,
“1”) && ($id ne “ALL”) ) {
end(“등록되지 않은
ID입니다.”); }
# 전체 사용자의 디스크 정보는 repquota 명령
# (man repquota)을 이용하고, 개별 사용자는 quota 명령
#
(man quota)을 이용한다.
if($id eq “ALL”) { system(“/usr/sbin/repquota
-avug”); }
else { system(“/usr/bin/quota -u $id”); }
end(“조회가 완료되었습니다.”);
}
sub add_domain {
# 21. 도메인 등록
print “$prog_msg 도메인을 등록할 사용자 ID : “;
$id =
<STDIN>;
chomp $id;
if ($id eq “”)
{ add_domain(); }
if ($id eq “\\”) { menu(); }
if (!user_check($id, “1”)) {
end(“등록되지 않은
ID입니다.”); }
print “$prog_msg 등록할 도메인(ex. abcd.co.kr)
: “;
$domain = <STDIN>;
chomp $domain;
if ($domain eq “”) { add_domain(); }
if ($domain
eq “\\”) { menu(); }
$domain =~ tr/[A-Z]/[a-z]/;
$domain =~ s/^ +| + _$//g;
# 중복을 막기 위해
네임서버 zone 파일이
# 이미 존재하는지 점검한다.
if(-e
“/var/named/custom/$domain”) {
print “\n$prog_msg ERROR,
동일한 도메인이”;
print “ 이미 등록되어 있습니다. [Enter]
“;
$input = <STDIN>;
menu(); }
check();
# bind 8.x대에서 사용하는 /etc/named.conf에
# 추가할 정보를 생성한다.
$named_conf = <<”__END__”;
zone “$domain” {
type master;
file
“custom/$domain”;
};
__END__
# zone 파일(/var/named/custom/도메인명)에
# 기록할 정보를 생성한다.
# serial 부분의 $date_seri 값은
일자정보에
# 번호(01)를 조합한 값(1999123101)을 사용한다.
$named_zone = <<”__END__”;
@ IN SOA ns.way.co.kr
domain.way.co.kr.
(
$date_seri
; serial
8H
; refresh
2H
; retry
1W
; expiry
1D
) ; minimum
IN NS
ns.way.co.kr.
IN NS
dns.way.co.kr.
IN A
$ip_address
IN MX
10 mail.way.co.kr.
www IN A
$ip_address
IN MX
10 mail.way.co.kr.
__END__
# apache 설정파일(httpd.conf)의 VirtualHost
# 정보를 생성한다.
# httpd.conf 파일에 미리 NameVirtualHost
# 지시자를 선언해 두어야 한다.
# 추가할 모든 도메인이 동일한
IP를 사용하는
# Name-based Virtual Host 임을 전제로 한다.
$httpd_conf = <<”__END__”;
<VirtualHost
$ip_address>
ServerAdmin webmaster\@$domain
DocumentRoot
/home/$id/$webdir
ScriptAlias /cgi-bin/ /home/$id/$webdir/cgi-bin/
ServerName www.$domain
ServerAlias $domain www.$domain
TransferLog /home/$id/$logdir/today.log
ErrorLog /home/$id/$logdir/error.log
</VirtualHost>
__END__
# 생성한 named.conf 정보를 파일에 기록한다.
$FILE = “/etc/named.conf”;
open(FILE, “>>$FILE”)
|| file_error();
print FILE $named_conf;
close(FILE);
# 생성한 named zone 파일 정보를 기록한다.
$FILE = “/var/named/custom/$domain”;
open(FILE, “>$FILE”)
|| file_error();
print FILE $named_zone;
close(FILE);
# 추가한 도메인으로 도착한 메일을 수신할 수
있도록
# 설정한다.
$FILE = “/etc/sendmail.cw”;
open(FILE, “>>$FILE”) || file_error();
print FILE
“$domain\n”;
close(FILE);
# 도메인별로 가상 사용자 mail을 사용할 수
# 있도록 virtusertable을 설정(추가)한다.
# @way.co.kr way라고
지정하면 way.co.kr 도메인으로
# 수신되는 모든 메일은 way
계정으로 배달된다.
# sendmail.cf 파일에 virtusertable을
사용할 수 있는
# 설정이 되어있어야 한다.
$FILE = “/etc/mail/virtusertable”;
open(FILE, “>>$FILE”) || file_error();
print FILE
“\@$domain $id\n”;
close(FILE);
# 추가한 도메인의 VirtualHost정보를 httpd.conf
# 파일에 기록(추가)한다.
# apache를 RedHat rpm으로 설치한
경우에는
# /etc/httpd/conf/httpd.conf 파일에 반영해야한다.
$FILE = “/usr/local/apache/conf/httpd.conf”;
open(FILE,
“>>$FILE”) || file_error();
print FILE “$httpd_conf”;
close(FILE);
end();
}
sub domain_apply {
# 22. 도메인 정보 갱신
# “도메인 등록”후 등록내용을 반영하기 위해 실행한다.
#
apache를 RedHat rpm으로 설치한 경우에는
# /etc/rc.d/init.d/httpd
파일을 이용한다.
# restart를 이용할 수도 있지만 연속되는
실행에 약간의
# 여유를 두기 위해 1초 간격으로 stop과 start를
실행한다.
check();
system(“/usr/local/apache/bin/apachectl
stop”);
sleep 1;
system(“/usr/local/apache/bin/apachectl
start”);
sleep 1;
system(“/etc/rc.d/init.d/named stop”);
sleep 1;
system(“/etc/rc.d/init.d/named start”);
sleep
1;
system(“/etc/rc.d/init.d/sendmail stop”);
sleep
1;
system(“/etc/rc.d/init.d/sendmail start”);
sleep
1;
end();
}
sub domain_display {
# 23. 도메인 정보
상세조회
# 도메인의 등록내용(각 설정파일)을 조회한다.
# vi editor를 이용해 설정파일들을 조회하고
# 편집할 수 있다.
print “$prog_msg 조회할 도메인(ex. abcd.co.kr) : “;
$domain
= <STDIN>;
chomp $domain;
if ($domain
eq “”) { domain_display(); }
if ($domain eq “\\”)
{ menu(); }
$domain_file_list = “/etc/named.conf “;
$domain_file_list .= “/var/named/custom/$domain “;
$domain_file_list
.= “/etc/sendmail.cw “;
$domain_file_list .= “/etc/mail/virtusertable
“;
$domain_file_list .= “/usr/local/apache/conf/httpd.conf
“;
check();
system(“vi $domain_file_list”);
end();
}
sub pass_define {
# 26. 사용자 password
지정
print “$prog_msg password를 지정(변경)할 사용자 ID
: “;
$id = <STDIN>;
chomp $id;
if ($id eq “”) { pass_define(); }
if ($id
eq “\\”) { menu(); }
if (!($user_data = user_check($id,
“1”))) {
end(“등록되지 않은 ID입니다.”); }
($ud1,
$ud2, $ud3, $ud4, $ud5, $ud6, $ud7)
= split(“:”,
$user_data);
if ($ud3 < $min_uid) {
end(“해당
ID의 password를 지정(변경)할 수 없습니다.”); }
check();
system(“/usr/bin/passwd $id”);
end();
}
sub ps_ax {
# 28. 프로세서 조회
system(“/bin/ps
ax”);
end();
}
sub demon {
# 29. 데몬 관리
# “도메인
정보 갱신”과 “프로세서 조회”를 통해 데몬의
# 수동 조작(stop,
start, restart)이 필요한 경우 사용한다.
print “$prog_msg
{httpd,named,sendmail}”;
print “ {start,stop,restart}\n”;
print “$prog_msg # “;
$cmd = <STDIN>;
chomp $cmd;
if ($cmd eq “”) { demon(); }
if
($cmd eq “\\”) { menu(); }
($cmd, $act) = $cmd
=~ /^(.*) (.*)$/;
if($cmd =~ /^httpd/) {
$cmd = “/usr/local/apache/bin/apachectl”; }
elsif($cmd
=~ /^named/) {
$cmd = “/etc/rc.d/init.d/named”;
}
elsif($cmd =~ /^sendmail/) {
$cmd = “/etc/rc.d/init.d/sendmail”;
}
# 임의작동을 막기 위해 httpd, named, sendmail 이외의
# 데몬은 조작할 수 없도록 한다.
else { end(“허용되지 않는
명령입니다.”); }
system(“$cmd $act”);
demon();
end();
}
이번 “Perl 시스템 도구” 강좌를 끝으로 부족하나마
“Perl programming” 연재를 마친다.