2011년 4월 28일 목요일

Garbage Collection

객체 생성/ 소멸

객체를 생성하게 되면 해당 객체는 메모리상의 Runtime Data AreaHeap Area에 자리를 잡음
자바에서는 사용자에게 직접적인 메모리 해제를 허락하고 있지 않음

Garbage Collection

Garbage Collection(가비지 컬렉션) : Garbage Collector heap영역에 할당 된 더 이상 사용되지 않는 메모리인 Garbage를 다른 객체가 사용할 수 있도록 정리하는 것
객체를 가리키는 참조변수가 null로 지정되거나 객체를 더 이상 참조하지 않게 되었을 때 가비지 컬렉션의 후보가 되면 이러한 객체들은 가비지 컬렉터에 의해 메모리를 반환
가비지 컬렉션은 프로그램을 수행하기 위한 여유 메모리가 부족하거나 사용자의 입력을 기다리고 있을 때처럼 프로그램이 활동하지 않을 때 메모리 반환작업을 수행

가비지 컬렉션의 특징
1. Automatic memory manager(자동 메모리 관리) 라고 부르기도 함.
2. 가비지 컬렉션은 프로그래머에 의해 구현 될 수 없음.
3. 가비지 컬렉션의 대상은 object(객체)이지 reference(참조)가 아니다.
4. 살아있는 스레드가 더 이상 참조되지 않은 객체는 가비지 컬렉션의 대상이 된다.
5. 다른 참조 변수도 참조하기 있는 객체는 가비지 컬렉션의 대상이 아니다.
6. 할당된 메모리를 명시적으로 해제할 수 없다.
7. 가비지 컬렉터가 객체를 어떠한 순서로 정리하는지는 알 수 없다.
8. 가비지 컬렉터가 언제 수행될지 정확히 알 수 없다.
9. 객체에 null이 할당되거나 객체를 더 이상 참조하지 않게 되었을 때 가비지 컬렉션의 대상이 됨

가비지 컬렉션 작업은 자바가상머신이 알아서 처리하지만 프로그래머가 직접 가비지 컬렉션 작업을 요청 할 수 있다.

가비지 컬렉션 요청 방법

System.gc()

Runtime.getRuntime().gc()

finalize() 메소드는 객체가 소멸될 때 자바가상머신에 의해 호출되므로 이 메소드 내에서 파일이 열려있는지를 확인하고 열렸을 경우에는 닫는 작업을 수행하면 된다. 이 메소드는 각 객체마다 정확히 한번만 수행된다. finalize() 메소드는 protected 제한자로 선언되어 있으며 Throwable 예외를 발생시킨다.

finalize() 메소드를 오버라이딩 하여 사용



-------------------------------------------------

인증서 오류는 결국 해결 못함.


서버 시간도 맞추어 보고, 인증서 관련 옵션도 바꾸어 보았지만.
회사 프락시를 거치기 때문에 해결될 수 없는 문제도 있는가 보다.
뭐, 돈 받고 일하니 회사가 스니핑 해도 할말은 없다만.

IT 엔지니어들이 서로가 서로를 지키지 못하고,
회사가 어려워지면 서로 자를 구실을 만들려고
관련 자료를 만드느라 분주한 모습이 안타까울 뿐이다.

2011년 4월 25일 월요일

android] 이미지 출력 메모리 부족

... 메모리 부족 때문에 지금껏 안되다가 이제 된다.

고친 부분은 여기.
 public View getView(int position, View convertView, ViewGroup parent) {
  ImageView imageView;
  if (convertView == null) {
   imageView = new ImageView(this.imageViewer.mContext);
   imageView.setLayoutParams(new GridView.LayoutParams(185, 185));                 
   imageView.setAdjustViewBounds(true);
   imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
   imageView.setPadding(2, 2, 2, 2); // Padding setting
  } else {
   imageView = (ImageView) convertView;
  }
  BitmapFactory.Options bo = new BitmapFactory.Options();
  bo.inSampleSize = 8;
  Log.i("DEbF", "in " + String.valueOf(System.currentTimeMillis()));
  Bitmap BM = BitmapFactory.decodeFile(thumbsDataList.get(position), bo);
       
  Matrix mat=new Matrix();                  mat.postScale(1,1); 

  BM = Bitmap.createBitmap(BM, 0, 0, BM.getWidth(), BM.getHeight(), mat, true);
  imageView.setImageBitmap(BM);
  return imageView;
 }

다른 건 변함없고.
inSampleSize를 8로 해서 decoding 정보를 1/8로 줄여서 되는 것 같다.
가상 머신서도 힙 없다고 뻗고 실재 폰에서도 뻗더니 이제 안 뻗고 실행은 된다 ㅋㅋ

android] dos for

adb push 계속 파일 집어 넣기

for %i in (*) do adb push %i /sdcard

다른 방법이 있을 것 같은디 ㅡㅡ;

android] avd sdcard

android virtual machine을 실행시키면 하나의 device로 잡힌다.

adb push로 파일을 넣을 수 있다.

avd 파일이 저장된 곳으로 가면

sdcard.img 파일이 있으니

고녀석을 컨트롤 하면 됨.

android sdk / tools 안에 sdcard용 유틸이 있음.

2011년 4월 24일 일요일

windows] win7와 win XP 간의 원격 데스크톱 연결

mstsc

정말 유용한 윈도우 기능이다. 랜선 하나만 있으면 컴퓨터를 편하게 연결해서 내것처럼 쓴다.
뭐 원래 내꺼지만. ㅋㅋ

그런데 widnws XP 쓰던거에 원격 데스트톱을 쓰니 마우스 포인터가 끊겨서 나왔는데.
win 7로 업그레이드 후에는 다른 윈도우 창을 하나 더 띄운 정도의 퍼포먼스가 나온다.

화면 제일 위에 IP표시가 없다면 다른 쪽 컴퓨터인지 구분이 안 갈 정도다.

win 7 물건이구먼.

life] 국민 주택 규모.

도대체 어떤 주택이 국민주택규모일까.

국민주택의 사전적 의미는 ‘국민주택기금으로부터 자금을 지원받아 건설 또는 개량한 25.7평 이하의 주택, 주택구입능력이 취약한 일반 서민을 대상으로 저렴한 가격으로 임대·분양하기 위해 정부가 정책적으로 건설하는 주택, 국민 일반대중에게 가장 보편적이고 표준적인 모델로 삼을 수 있는 동시에 국민이면 누구나 이 정도의 집은 가져야 한다는 지표를 제시하는 주택’등으로 돼 있고 담당자는 25.7평 이하면 국민주택기금 지원에 상관없이 모두 국민주택규모 주택이라 한다.

라고 실컷 알아봤더니 ㅡㅡ;

결국 연말 정산 때는 안되더라.

국세청에 젤 도둑이여.

lfie] 종교인이라고 또 아니라고 그 사람을 크게 판단하지는 말자.

살다보니 종교인들 중에 밉상인 사람이 있고.
종교인이 아니라도 매력적인 사람들이 많다.

난 종교가 있고 없고로 사람을 판단하지는 않는다.

좀 아쉬운 것은 밉상인 사람은 신이 마치 자기를 그렇게 만든것이 모든 계획인줄 알고
고치지도 않고 밉상으로 산다.
영원한 밉상에 대한 깊은 신념이라고 해야 하나...

하느님이 만드신 태양도 똑바로 못 쳐다 보는데.
어찌 그 가르침을 다 알리요.

배우려는 자세를 가진 사람이야 말로 진정한 종교인이다.

다만 생각을 조금 달리해서 세례는 받았으면 한다. 열심히 세상을 살고,
또 착하게 산다고만 좋은 것은 아니다.

사회의 냉정함을 보았다면 절차도 중요함을 알아야 하고.
착하게만 산다고 법을 피해갈수는 없듯이.
정해진 규율의 소중함도 알아야 한다.

그렇다고 내가 교회를 잘 나가는 것은 아니다.

내 자신이 여유가 없어서. 못가는 것은 아니고.
내 자신이 여유가 없어서. 안간다.

life] 세상은 여유로운 줄 알았다.

사실 내가 욕심이 많아서 여유롭지 않기도 하겠지만.

일반적인 사람들의 삶 자체가 그리 여유로운 것이 아니다.

대표적인 예로 일과 사랑중에 선택해야 할 때가 많다.

구하려고 하는 직장은 다른 지역에 있고 연인은 이동이 쉽지 않은 경우가

대표적일 것이다.

예전에는 그냥 같이 따라가서 가까운데 살면되지 하고 단순히 생각했겠지만.

지금은 정말 많이 고민해야 한다는 것을 안다.

물론, 정말 사랑하는 사이이고 많은 것을 포기할 준비가 되어 있다면 결정은 쉽겠지만.

나중에 다른 길을 선택하지 못한 것에 대한 아쉬움 또한 남을 것이다.

이 뿐만 아니라 부모, 자식 간. 좋아하던 친구들. 비단 사람 뿐만 아니라 살고 싶은 지역도

포함해서 세상은 여유롭지 못하다.

하지만 자신이 원하는 바를 단순히 하고 욕심을 줄인다면.

선택이 좀 더 쉬워지겠지.

어른이 되고 나니 확실하게 말하기가 두려워졌고 그러기도 힘들었졌다.

~같다. ~겠지. ~일 것이다. 라는 추측성이 언어를 종결짓는 대부분의 의미가 되어 버렸다.

그래서 사색의 시간이 많이 필요하다.

내가 확실히 좋아하는 것.

확실히 사랑하는 것.

확실히 원하는 것이 무엇인지 알고.

그것을 적고 그것을 되뇌어야 한다.

세상은 여유롭지 못하지만. 그래서 닿을 수는 없지만.

얼마든지 최선을 다해도 되는 세상이기에 재미가 있다.

준비되었는가?

여유롭고 공평하지 못한 세상이지만.

순응하고 적응하고 또 그게 안되면 어깨를 부딪혀서 바꾸려고 해 보자.

당신 뒤에는 부모님과 연인 친구들이 함께 할 것이다.

모두가 없다면 마음속의 하느님, 그리고 세상을 만드는 그분을 잊지 말자.

2011년 4월 23일 토요일

hack] about crackers

  Easy PC 
리눅스 산책
시스템 관리자에게 보내는 편지
리눅스 시스템의 해킹
글 | 오태호 ohhara@postech.edu
최근 들어서 해커들에 의한 시스템 침입 사고가 급속히 늘고 있다. 특히 리눅스를 대상으로 한 해킹이 급속도로 증가하고 있는 추세다. 내부 구조가 완전히 공개되어 있는 리눅스는 많은 사람에 의해 조직적으로 만들어져서 다른 운영체제에 비해 속도도 빠르고 견고하며, 버그도 상대적으로 적다. 하지만 역으로 누구나 내부 구조를 분석할 수 있기 때문에 실력 있는 이들이 운영체제를 분석해 버그를 찾아낼 가능성이 다른 운영체제에 비해서 높은 것도 사실이다. 여기서는 리눅스를 관리하는 관리자가 이런 해커들로부터의 공격을 어떻게 하면 효과적으로 막을 수 있는지에 대해 살펴보도록 한다.참고로, 이 글에서는 원래 컴퓨터 마니아를 뜻하는 '해커(hacker)'라는 용어의 범위를 시스템을 파괴하는 '크래커(cracker)'까지 포함한 의미로 사용하겠다. 현재는 크래커도 모두 편의상 해커라고 부르는 경우가 많기 때문이다.
무시무시한 해커들이 등장하는 영화를 본 일반인들은 해커가 다른 이의 시스템에 접근하는 이유를 대부분 '상대 기업이나 상대 국가에서 극비 자료를 가져오기 위해서'라고 상상하기 십상일 것이다. 물론 이런 행동은 바람직하지 않지만, 영화 속의 해커는 고민과 연구 끝에 결국 해킹에 성공하고야 말고, 이 모든 과정이 멋있고 근사하게 묘사되고 있다. 이러한 이유로 혈기 넘치는 많은 젊은이들이 해커를 동경하며 스스로 해커가 되고 싶어한다. 언론에서도 이러한 분위기에 편승하여 어떤 이가 해킹을 하다가 붙잡혔을 경우 천재적인 실력을 지닌 아까운 인재가 한 순간의 판단 착오로 감옥에 가게 되었다는 식으로 영웅 만들기에 급급하다. 이렇게 실력을 인정(?)받은 해커들이 감옥에서 나오자마자 수많은 대기업이나 정부에서 서로 '모셔가려는' 모습을 보는 것도 낯설지 않다.
하지만 해커의 모습은 이렇듯 일반인들이 상상하는 것과는 전혀 다른 경우가 대부분이다. 지금 활동하고 있는 해커들 중에 앞에서 열거했듯이 사람들의 부러움을 받을 만한 모습을 지닌 이는 전체의 10%도 되지 않을 것이다. 해커들 대부분은 다음과 같은 생활을 한다.
현재 대부분의 해커들의 모습이 바로 이렇다. 해커란 상당한 지식과 전문성을 지닌 사람으로 생각하기 쉽지만, 이러한 수준의 행동 정도는 인터넷을 사용할 줄만 안다면 중·고등학생이라거나 해킹에 대한 사전 지식이 전혀 없더라도 쉽게 할 수 있다. 그리고 해커의 대다수는 이러한 어린 학생들인 것이 사실이다. 검거되는 대부분의 해커가 10대이거나 20대 초반의 젊은 사람이라는 점이 이를 반증한다. 또한 이런 해커들은 보통 자신이 어떤 원리로 상대방의 서버 관리자 권한을 획득할 수 있었는지에 대해 제대로 알고 있지 못한 경우가 많다.
운영체제에 새로운 버그가 발견되지 않았는지 보안 사이트를 뒤지고 돌아다닌다.
보안상 중요한 버그가 발견되면 그에 대한 공격 코드를 누군가가 만들어놓지 않았을까 생각하며 그 공격 코드를 찾아 인터넷을 헤매고 돌아다닌다. 만약 지금까지 알려지지 않은 버그를 이용한 공격 코드가 발견되면 뛸 듯이 좋아한다.
이렇게 모은 수많은 공격 코드를 이용해 IP 주소 0.0.0.0부터 255.255.255.255 중에서 적당한 범위를 지정하고 차례차례 공격을 시도한다.
공격을 통해 시스템 접근에 성공하게 되면, 해당 서버에 침입한 후 또다시 적당한 범위를 지정하여 공격을 반복한다. 이런 식으로 하루에 수십 대에서 수백 대의 서버를 공격하고, 결국 해킹에 성공해 관리자(root) 권한을 획득한다. 획득한 서버의 관리자 권한은 나중에 자신의 위치를 속이기 위한 경유지로 쓰거나 불법 자료(상용 프로그램 따위)를 교환하는 장소로 사용한다.
인터넷 채팅인 irc에서 채팅을 하다가 자신에게 기분 나쁜 소리를 하는 이들을 만나게 되었을 경우 상대방한테 서비스 거부 공격(Denial of Service)을 가할 때도 해킹한 서버를 사용한다. 물론 이렇게 해서 확보한 서버들은 자신의 해킹 실력 과시용으로도 사용된다. "나는 하루에 수백 대의 서버를 해킹하는 천재 해커다."라는 말을 남기면서….

해킹에 성공한 후 해커들이 하는 행동은?
리눅스에서의 해킹에 대해 좀더 자세히 살펴보도록 하자. 우선 해커가 해킹에 성공한 후 침입한 시스템에서 하는 행동은 일반적으로 다음과 같다.
① rootkit을 설치한다 해킹에 성공한 후 해커들이 설치하는 트로이 목마 프로그램들을 흔히 rootkit이라 부른다. rootkit에 포함되어 있는 프로그램으로는 login, ps, pstree, top, ls, dir, vdir, chfn, chsh, du, ifconfig, in.rshd, netstat, syslogd, tcpd 등과 같은 시스템 프로그램들이 있다. 이런 프로그램들을 원래 있던 프로그램과 바꿔치기 해서 관리자가 시스템을 점검해도 별 이상이나 변화가 없는 것처럼 위장하게 만드는 것이다. 예를 들어, ls를 바꿔치기 해서 ls를 실행시켜도 해커가 만든 파일이 보이지 않도록 하며, ps를 바꿔치기 해서 ps를 실행시켜도 해커가 실행한 프로그램이 보이지 않게 할 수 있다. netstat를 바꿔치기 하면 외부에서 네트워크로 연결한 해커의 모습을 보이지 않게 할 수 있다. 또한 login 프로그램도 바꿔치기 해서 패스워드 파일(/etc/passwd)에는 없지만 root 권한을 가진 아이디로 로그인할 수 있도록 해놓을 수 있다. 문제는 이와 같은 프로그램들이 인터넷에 널리 퍼져 있어서 초보들도 손쉽게 사용할 수 있다는 점이다. 필자의 경험을 예로 들자면, /bin/login 프로그램을 strings를 사용해 분석해 보았지만 숨겨놓은 백도어(backdoor) 아이디와 비밀번호를 찾지 못했다. 하지만 objdump를 사용하여 disassemble로 숨겨놓은 아이디와 비밀번호를 찾을 수 있었다.
② 다른 해커는 들어오지 못하게 막는다 일단 시스템을 완전히 접수했다면, 다른 해커가 자신과 같은 방법으로 관리자 권한을 획득하는 것을 막기 위해 해당 서버에 있는 모든 버그를 패치해 놓는다. 대단한 독점욕이라 아니 할 수 없다.
③ eggdrop, bnc 등 irc 관련 프로그램을 설치한다 관리자들은 누군가가 자신의 서버에 침입해서 eggdrop과 bnc와 같은 프로그램을 설치해 놓은 것을 보고 이러한 프로그램들을 해킹 프로그램인 것으로 짐작하여 겁을 먹는 경우가 있다. 하지만 이들은 그리 위험한 프로그램은 아니다. eggdrop은 irc에서 가장 많이 사용되는 irc bot 프로그램이고, bnc는 irc에서 자신의 위치를 숨기기 위해 사용되는 irc proxy이다.
④ scan류의 프로그램을 설치해서 실행시킨다 mscan이나 sscan과 같은 여러 가지 보안 버그를 알려주는 프로그램을 설치해 광범위하게 스캔(scan, 대상 서버에서 어떠한 보안 버그가 있는지 분석해서 정리해 주는 행위)을 해서 기록한다. 예를 들어 .ac.kr에 있는 모든 서버를 대상으로 스캔을 한다. 이와 같은 일을 해커가 하게 되면, 시간이 조금 흐른 후에 스캔을 당한 서버 관리자의 항의가 올 것이다. 침입을 당한 컴퓨터에서는 영문도 모른 채 엄청난 항의를 받게 된다. 최근 mscan이나 sscan과 같은 프로그램으로 국내 서버에 대한 공격이 아주 유행하고 있다. 이러한 프로그램의 사용법 예제로 .ac.kr의 모든 서버를 대상으로 스캔을 하는 방법이 나와 있기 때문이다. 이로 인해 국내의 많은 대학 서버들이 피해를 보았다.
⑤ 서비스 거부(Denial of Service) 공격 프로그램을 설치한다 자신에게 기분 나쁜 소리를 하는 사람의 머신을 사용 불능 상태에 빠뜨리기 위해 서비스 거부 공격 프로그램을 설치해 놓고 필요할 때 사용한다. 서비스 거부 공격 기법은 상상하기 힘들 정도로 다양하다. 상대 서버에 순간적으로 패킷을 엄청나게 많이 보내서 네트워크 사용이 불가능하게 만들기도 하고, 서버 운영체제의 구조적인 버그를 이용해 서버를 다운시키기도 한다. 이런 류의 프로그램은 인터넷에서 쉽게 찾을 수 있다.
⑥ chattr 명령어를 사용해서 파일의 변경을 불가능하게 만든다 리눅스에는 ext2 파일 시스템을 직접 건드리는 chattr라는 명령어가 있다. 이 명령어를 사용하면 특정 파일에 대해 관리자라 할지라도 지우거나 변경하지 못하게 만들 수 있다. 이 프로그램을 사용해 자신이 설치한 프로그램들을 관리자가 건드리지 못하게 만든 다음 chattr 명령어를 삭제한다. 리눅스 시스템에 대해 잘 모르는 관리자의 경우 root 계정으로도 변경할 수 없는 파일이 있다는 사실에 당황하게 마련이고, 속수무책으로 해커에게 당하게 된다.
어딘가 어설픈 초보 해커들
최근 일고 있는 리눅스와 해킹에 대한 관심으로 수많은 초보 해커들이 등장하고 있다. 이들 초보 해커들은 나름대로 실력과 철학을 가진 이전 해커들과 구별되는 몇 가지 특징을 가지고 있다. 여러분들 스스로 해커라 자부하지만 다음에 해당하지는 않는지?
① 접속 기록을 지우지 않는다 외부에서 시스템에 접속한 기록은 모두 로그 파일로 남게 마련이고, 이는 추적의 열쇠가 되는 중요한 근거인데도 로그 파일을 지우지 않는다. 행여 지운다 하더라도 인터넷에 있는 공개 프로그램을 단순히 사용하는 수준이기 때문에 관리자가 해킹 사고가 나기 전에 약간의 조작만 해준다면 기록을 모두 살릴 수 있다.
② history를 지우지 않는다 셸에서 실행한 여러 가지 명령어는 접속한 계정의 홈 디렉터리에 history 파일로 남게 되는데, 이것도 지우지 않는 경우를 흔히 볼 수 있다.
③ 관리자에게 들키는 것을 겁내지 않는다 관리자가 해커를 발견해서 talk(유닉스의 터미널에서 사용할 수 있는 1:1 채팅 프로그램)를 요청하면 이를 받아주기도 하고, 한술 더 떠 "자신에게 서버를 관리할 권한을 주면 안전하게 해주겠다."는 말도 서슴지 않고 한다. 뿐만 아니라 해커가 공격한 흔적을 관리자가 발견해서 연결을 강제로 끊어도(이 때 해커는 관리자에게 자신이 들켰음을 알게 됨) 해커는 계속 연결을 시도한다. 자기가 하고 있는 일이 일종의 범죄임을 전혀 인식하지 못하는 것이다. 무식하면 용감하다?
④ 전혀 잡히지 않는다는 확신을 가지고 있다 해커는 일반적으로 전화선을 사용한다. 전화선을 사용하게 되면 추적이 힘든 것이 사실이고, 이 때문에 해커는 아무런 거리낌없이 자신은 잡히지 않는다는 확신을 가지고 행동한다. 그러나 세상에 완벽한 범죄란 없다.
⑤ 리눅스에 대해 전혀 모르는 경우가 많다 이러한 초보 해커들이 운 좋게 시스템에 접근하더라도 하는 행동을 가만히 살펴보면 리눅스 시스템에 대해 아는 게 전혀 없다고 느껴지는 경우가 많이 있다. 심지어 리눅스에서 도스 명령어를 실행하려는 경우도 많이 볼 수 있다.
리눅스 시스템의 보안을 위해 신경 써야 할 것들
앞에서 소개한 종류의 초보 해커를 비롯한 대부분의 해커들은 관리자가 약간만 주의를 기울이면 어렵지 않게 막을 수 있다. 아래 열거한 모든 사항을 다 해주면 좋겠지만, 그렇게 하기가 힘들다면 ①∼③번 정도는 반드시 해주도록 한다.
① 데몬은 필요한 것만 띄우고 나머지는 모두 죽인다 최근 버전의 리눅스는 linuxconf 명령어를 사용해 사용하고자 하는 데몬만 쉽게 띄울 수 있도록 되어 있다. linuxconf가 설치되어 있지 않다면 다음과 같은 방법으로 원하는 데몬의 동작 여부를 결정한다. 예를 들어, nfs 데몬을 실행시키고 싶다면 '/etc/rc.d/init.d/nfs start'와 같이 하고, 죽이고 싶으면 '/etc/rc.d/init.d/nfs stop'처럼 하면 된다. 부팅시 nfs 데몬을 실행시키고 싶지 않다면 'chmod a-x /etc/rc.d/init.d/nfs'와 같이 실행시키면 된다. 필자의 경우 안전을 요하는 서버를 세팅할 때는 inetd(인터넷 데몬)도 죽여서 telnet, ftp 등도 사용할 수 없게 만든다.
② 리눅스에 대한 버그 패치가 새롭게 발표되면 즉시 받아서 설치한다 참고로, 가장 많이 사용하는 레드햇 리눅스의 버그 패치는 레드햇사의 홈페이지 'http://www.redhat.com/corp/support/errata/index.html'에서 구할 수 있으며, 설치는 'rpm -Uvh packagename.rpm'과 같은 형식으로 간단히 설치할 수 있다.
③ tcpwrapper와 같은 프로그램을 사용해 접근할 수 있는 대상을 최대한 줄인다 tcpwrapper를 사용하면 inetd를 통해서 접근하는 데몬에 한해 접근을 제한할 수 있다. 이와 같이 하면 보안성을 다소 높일 수 있다. 하지만 모든 데몬이 inetd를 통하는 것은 아니기 때문에 완전히 안심할 수는 없다는 것을 명심하자. tcpwrapper를 사용할 때는 모든 데몬에 대한 접근을 막고 필요한 것만 하나하나 여는 것이 안전하다. 우선 root 계정으로 로그인해 '/etc/hosts.deny' 파일을 다음과 같이 설정하면 모든 데몬에 대한 접근을 막을 수 있다. 이렇게 해놓으면 누군가가 데몬에 접근하다가 tcpwrapper에 의해 거부되면 상대방 서버에 finger를 해서 접근을 시도한 사람의 정보를 알아낸 후, 그 결과를 root에게 E-mail로 보낸다. '/etc/hosts.deny' 파일이 접근 제한에 대한 설정을 하는 것이라면 '/etc/hosts.allow' 파일을 통해서는 원하는 데몬에 대해 원하는 곳(IP 주소 입력)에서만 접근할 수 있도록 설정할 수 있다.
④ 방화벽 프로그램을 사용해 패킷을 걸러낸다 ipfwadm(kernel 2.0.x), ipchains(kernel 2.2.x)와 같은 방화벽(firewall) 프로그램을 사용하면 패킷이 오갈 때 이를 어떻게 처리할 것인지에 대해 자세히 설정할 수 있다. 하지만 이를 설정할 때는 네트워크 프로토콜에 대한 심도 있는 이해가 요구되므로 사전 지식이 필요하며, 신중히 사용해야 된다. 만약에 141.223. 영역에 있는 IP하고만 TCP 연결을 하고 나머지 모든 곳은 거부하고 싶으면 아래와 같이 하면 된다. 필자의 loghost를 ipchains로 패킷 필터링을 했더니 외부에서는 이 loghost가 존재하는지도 확인할 수 없었다.
⑤ sniff 방지를 위해 스위칭 허브를 사용한다 네트워크 환경에서 사용되는 일반적인 허브는 broadcasting(데이터 패킷을 연결된 모든 서버에 전달하는 것)을 한다. 그래서 근처의 한 서버가 해커에 의해 해킹을 당하면 근처의 모든 서버에 송수신되는 모든 데이터를 볼 수가 있다(이런 행동을 흔히 sniff라 부른다). 하지만 스위칭 허브를 사용하면 근처의 다른 서버의 데이터는 볼 수가 없게 되므로 보안성을 다소 높일 수 있다.
⑥ 중요한 데이터를 교환할 때는 암호화한다 ssh(secure shell), pgp(pretty good privacy)와 같은 프로그램을 사용해서 중요한 데이터는 암호화를 한 후에 송수신하도록 한다. 인터넷에서는 빠른 데이터 교환을 위해 기본적으로 암호화를 전혀 하지 않는다. 이로 인해 데이터를 중간에 가로채는 사고가 흔히 발생하기 때문에 보호가 필요한 중요한 데이터에 대해서는 암호화를 하는 것이 필수적이다.
다음으로 해킹을 당했을 때를 대비해 주기적으로 해주어야 할 것들에 대해 살펴보자. 앞의 사항과 마찬가지로 모두 다 해주면 좋겠지만, 여의치 않을 경우 ①번은 반드시 해주도록 한다.
① 백업을 생활화한다 백업의 중요성은 아무리 강조해도 지나치지 않다. 해커가 자신의 컴퓨터에 침입해서 자료를 파괴할 것이 걱정된다면, 백업을 '여러 곳에, 자주' 하면 된다. 또한 해커가 침입해서 순간적으로나마 관리자 권한을 획득한 흔적이 발견되었다면, 즉시 최근 백업해 둔 파일로 시스템을 복구해야 안전하다. 어느 곳에 어떤 뒷문(backdoor)을 숨겨놓았을지 알 수 없기 때문이다. 만약에 최근에 백업해 둔 파일이 없어 눈에 보이는 문제만 해결하고 넘어간다면, 나중에 다시 그 해커가 들어올 가능성이 얼마든지 있다.
② loghost를 별도로 지정한다 시스템에 대한 내용을 기록하는 syslogd는 일반적으로 자신의 호스트에서 발생하는 여러 가지 문제에 대한 것만 기록하도록 되어 있다. 하지만 이렇게 했을 경우, 만약에 해당 호스트가 해킹을 당해서 기록 파일이 해커에 의해 조작되어 버리면 이 기록은 믿을 수가 없게 된다. 이러한 이유로 기록 파일을 저장하는 서버(이를 loghost라 한다)를 하나 따로 만들고, 그 쪽에 기록을 보내는 것이 좋다. loghost를 설정하는 방법은 다음과 같다. syslogd를 실행시킬 때 -r 옵션을 주면 외부 호스트로부터의 기록도 받을 수 있도록 syslogd가 실행되어 loghost를 만들 수 있게 된다. loghost에 기록을 보내려면 해당 서버의 '/etc/syslog.conf' 파일 안에 다음과 같은 내용을 추가하고 'killall -HUP syslogd' 명령을 실행시켜 주면 된다(141.223.123.45은 loghost의 IP이다). 필자의 경우는 loghost를 여러 곳에 지정하여 자신의 접근 기록을 지우기 위해서는 여러 곳을 해킹해야만 하도록 만들어놓았다.
③ loghost의 내용을 주기적으로 프린트해서 안전한 장소에 보관한다 loghost는 당연히 해커의 침입이 거의 불가능할 정도로 안전하게 관리하는 것이 좋다. 만약에 loghost도 해킹당할 우려가 있다면, loghost의 기록을 주기적으로 프린트해서 안전한 장소에 따로 보관하도록 한다.
보안에 대한 자신감은 금물!
해커들로부터 반감을 살 만한 일은 하지 않는 것이 좋다. 보안에 대한 쓸데없는 자신감 등이 이에 해당할 것이다. 뛰어난 해커 몇 명이 특정 서버를 목표로 여러 가지 방법을 동원해 해킹을 시도한다면 살아남을 수 있는 서버는 거의 없다 해도 무방하다. 보안 버그 패치를 1주일에 한 번씩 하기 때문에 안전하다고 말하는 사람도 있지만, 보안 버그가 발표되고 1주일 안에 공격 코드를 만들어서 공격하면 해킹에 성공할 수 있기 때문에 완벽한 방법은 아니다. 또한 알려진 모든 버그를 빠른 속도로 패치한다고 하더라도, 지금까지 알려지지 않은 버그를 찾아서 공격해 들어올 경우에는 속수무책으로 당할 수밖에 없다.
해킹을 통해 서버의 내용을 바꾸는 것이 불가능하다고 하더라도, 목표 서버에 과부하를 줘서 서비스가 불가능하게 만드는 것은 얼마든지 가능한 일이다. 이러한 이유에서 고급 해커들로부터 공격을 받지 않으려면 해커들로부터 반감을 살 만한 행동을 되도록 하지 않는 것이 좋다. 필자 역시 해커를 뒤쫓다가 해커로부터 역공을 당해서 고생했던 쓰라린 경험을 가지고 있다.
마지막으로 해커가 되고자 하는 이들에게 당부할 것이 있다. 인터넷이 발달하고 해킹 도구가 발달하면서 해커가 되고자 하는 사람이 많아졌다. 컴퓨터에 대해서 아무것도 몰라도 조금만 공부하면 해커가 될 수 있을 정도다. 윈도의 백오리피스와 같은 도구들은 누구나 쉽게 사용할 수 있지 않은가? 이렇듯 아무것도 모르면서 상대방 시스템의 자료를 훔치고 파괴하는 것은 꼬마들도 할 수 있는 일이다. 이렇게 해커가 된다는 것이 쉬운 일인데, 그러한 평범한 해커가 되려는 것이 과연 의미 있는 일일까? 전혀 의미가 없다고 확언한다.
만약에 그래도 해커가 되고 싶다면, 해커란 말의 원래 의미를 살려 진정한 해커가 되어보자. 운영체제나 네트워크, 컴퓨터 시스템의 구조를 꼼꼼히 살펴보고, 구조적인 문제나 개선점은 없는지 끊임없이 연구하고 고민하는 그런 모습 말이다. 만약 문제가 있을 때는 세상에 알리고, 또 스스로 고쳐나가는 이야말로 진정 해커라 불릴 자격이 있을 것이다.
해커즈 랩 : 국내의 보안 기술 전문 업체인 시큐어소프트사에서 만든 해커들의 자유 지대로, 해커들의 두뇌 체육관이라는 별명을 가지고 있다. 음지에서 범죄자 취급을 받고 있는 해커들의 전문적인 컴퓨터 사용 기술을 양지로 끌어내 국가 경쟁력을 배가하자는 취지로 만들어진 해커즈 랩의 URL은 http://www.hackerslab.com/ 이며, 현재 13단계의 해킹 코스가 마련되어 있는 해커 자유 지대 서비스를 하고 있다.
백오리피스 : 지난해 7월 처음 공개된 '백 오리피스(Back Orifice)'는 윈도 운영체제를 사용하고 있는 시스템의 뒷구멍을 공략하는 해킹 도구이다. 'cDc(Cult of Dead Cow, 죽은 소 숭배)'라는 해커 그룹이 개발한 백 오리피스는 마이크로소프트 '백 오피스(Back Office)'의 패러디로 얼마전 백 오리피스 2000 버전이 발표되었다.
브로드캐스트 : 네트워크에 연결된 모든 호스트에 전달되는 신호를 일컫는 말로, C 클래스를 사용하고 있는 도메인(예. AAA.BBB.CCC.0)에서는 IP 주소 AAA.BBB.CCC.255가 브로드캐스팅을 위해 사용된다.


▶ 목차로

linux] shell 명령어

[펌] ★bourne shell☆ linux
2004/11/23 13:49 수정 삭제
출처 ★~º-상상 예찬-º~☆ | ㄱ깍쟁이
원문 http://blog.naver.com/violet6157/40007945392
1. 변수
  . 쉘변수는 처음 사용될때 만들어진다. 즉 미리 선언할 필요가 없다.
  . 쉘변수는 유닉스 명령과 마찬가지로 대소문자에 구별이 있다.
  . 쉘변수는 기본적으로 데이터를 문자열로 저장한다. 수치를 대입해도 실제 수치
    가 아닌 문자열이 저장된다. 계산이 필요할 경우는 자동으로 수치로 변환하여 
    계산후 다시 문자열로저장된다.
  . 쉘변수의 값을 사용할 때는 변수명앞에 "$" 를 붙여서 사용한다.
  . 쉘변수에 값을 대입할때는 "$"를 사용하지 않는다.
  . 쉘변수는 타입이 없다. 즉 아무 값이나 다 넣을 수 있다.
 
1.1 환경변수
  쉘을 기동하고나면 기본적으로 셋팅되어있는 변수들이다. 유닉스/리눅스에는 많은
  환경변수들이 있고 필요한경우 이 변수들을 마치 일반변수처럼 값을 얻어오거나 셋
  팅할 수 있다. 여기서는 쉘과 직접적인 관련이 있는것만 설명한다. 
  
  $0 - 실행된 쉘 스크립트 이름
  $# - 스크립트에 넘겨진 인자의 갯수
  $$ - 쉘 스크립트의 프로세스 ID
  
1.2 인자 변수
  쉘스크립트에 인자를 넘겨줄때 그 인자들에 대한 정보를 가지고 있는 변수들.
  
  $1~ $nnn  : 넘겨진 인자들
  $*        : 스크립트에 전달된 인자들을 모아놓은 문자열. 하나의 변수에 저장되며
              IFS 환경변수의 첫번째 문자로 구분된다.
  $@        : $*과 같다. 다만 구분자가 IFS변수의 영향을 받지 않는다.
 
1.3 일반변수
  일반변수에 특별한 제약은 없다. 단 대소문자 구분만 정확하게 해주면 된다.

  예제 )

  #!/bin/sh
  echo "This Script Executable File : $0"
  echo "Argument Count : $#"
  echo "Process ID : $$"
  echo "Argument List \$* : $*"
  echo "Argument List \$@ : $@"
  echo "Argument 1 : $1"
  echo "Argument 2 : $2"
  echo "Argument 3 : $3"
  echo "Argument 4 : $4" 
   
  실행 )
  $chmod 755 test1
  $./test1 a1 a2 a3 a4
  This Script Executable File : ./test1
  Argument Count : 4
  Process ID : 905
  Argument List $* : a1 a2 a3 a4
  Argument List $@ : a1 a2 a3 a4
  Argument 1 : a1
  Argument 2 : a2
  Argument 3 : a3
  Argument 4 : a4
 
1.4 연산
  변수의 산술연산은 생각하는것 처럼 쉽지않다. 위에서 언급했듯이 변수에는 모든것
  이 문자열로 저장되기 때문에 연산이 불가능하다. 연산을 위해서는 좀 복잡한 절차
  를 거쳐야 한다.

  변수 = $((산술식))
 
  이것이 가장 단순한 연산 규칙이다. 산술식내에는 변수( $1, $a 와 같은 ) 도 들어
  갈 수 있다. 산술식 내에 숫자가 아닌 문자열, 또는 문자열이 담겨있는 변수가 들어
  가면 그것들은 계산에서 제외된다.
  (정확히 말하면 0 으로 간주되어 연산이 이루어 지지 않는다.)
 
1.5 매개변수 확장
  매개변수 확장이란 변수의 값을 문자열등으로 대체하는 것을 말한다. 단순한 대체뿐
  아니라 변수내의 문자열을 조작하여 원하는 문자열만을 추출할 수도 있다.

  형식
  ${parm:-default} : parm이 존재하지 않으면 default로 대체된다.
  ${#parm}          : parm의 길이를 참조한다.(가져온다)
  ${parm%word}      : 끝에서부터 word와 일치하는 parm의 최소부분(첫번째 일치) 을
                      제거하고 나머지를 반환한다.
  ${parm%%word}     : 끝에서부터 word와 일치하는 parm의 최대부분(마지막 일치) 을
                      제거하고 나머지를 반환한다.
  ${parm#word}      : 처음부터 word와 맞는 parm의 최소부분(첫번째 일치)을 제거하
                      고 나머지 부분을 반환한다.
  ${parm##word}     : 처음부터 word와 맞는 parm의 최대부분(마지막 일치)을 제거하
                      고 나머지를 반환한다.
  
  * word에는 와일드 카드를 사용할 수 있다.
  
  예를 보자.
    
  1 #!/bin/sh
  2
  3 p="/usr/X11R6/bin/startx"
  4
  5 unset p
  6 a=${p:-"Variable p Not found"}
  7 echo $a
  8
  9 p="/usr/X11R6/bin/startx"
  10 a=${p:-"Variable parm Not found"}
  11 echo $a
  12
  13 a=${#p}
  14 echo $a
  15
  16 a=${p%/*}
  17 echo $a
  18
  19 a=${p%%/*}
  20 echo $a
  21
  22 a=${p#*/}
  23 echo $a
  24
  25 a=${p##*/}
  26 echo $a
  27                    
  
  위 스크립트의 결과는 다음과 같다.
  ---------------------------------
  Variable p Not found
  /usr/X11R6/bin/startx
  21
  /usr/X11R6/bin
  
  usr/X11R6/bin/startx
  startx              
  ----------------------------------
   6행 : 변수 p 가 제거 되었으므로 "Variable p Not found" 가 a에 들어간다.
  10행 : 변수 p 가 있으므로 그대로 a에 들어간다.
  13행 : a에는 변수 p의 길이가 들어간다.
  16행 : p 에서 가장 오른쪽의 "/"부터 끝까지 지우고 나머지를 a에 넣는다.
  19행 : p 에서 가장 왼쪽의 "/" 부터 끝까지 지우고 나머지를 a에 넣는다.
         (아무것도 없다)
  22행 : p 의 처음부터 가장왼쪽의 "/" 까지 지우고 나머지를 a에 넣는다.
  25행 : p 의 처음부터 가장 오른쪽의 "/"까지 지우고 나머지를 a에 넣는다.
2. 조건 판단
  쉘 스크립트에서 조건판단은 if 와 test 명령을 혼합하여 사용한다.
  일반적인 예는 다음과 같다.
 
  if test -f test1
  then
   ...
  fi
  
  -f 는 주어진 인자가 일반파일 일때 참이된다.
  
  
  test 명령은  [] 로 대체될 수 있다.
  
  if [ -f test1 ]
  then
   ...
  fi
  
  -----------------------------
  
  if [ -f test1 ]; then
   ...
  fi
 
  2.1 test 명령
  
  test 명령의 조건은 다음과 같이 세 부류로 나누어진다.
 
  문자열비교
    [ string ]             : string이 빈 문자열이 아니라면 참
    [ string1 = string2 ]  : 두 문자열이 같다면 참
    [ string1 != string2 ] : 두 문자열이 다르면 참
    [ -n string ]          : 문자열이 null(빈 문자열) 이 아니라면 참
    [ -z string ]          : 문자열이 null(빈 문자열) 이라면 참
  
  산술비교
    [ expr1 -eq expr2 ] : 두 표현식 값이 같다면 참 ( EQual )
    [ expr1 -ne expr2 ] : 두 표현식 갑이 같지 않다면 참 ( Not Equal )
    [ expr1 -gt expr2 ] : expr1 > expr2 이면 참 ( Greater Then )
    [ expr1 -ge expr2 ] : expr1 >= expr2 이면 참 ( Greater Equal )
    [ expr1 -lt expr2 ] : expr1 < expr2 이면 참 ( Less Then )
    [ expr1 -le expr2 ] : expr1 <= expr2 이면 참 ( Less Equal )
    [ ! expr ]          : expr 이 참이면 거짓, 거짓이면 참
    [ expr1 -a expr2 ]  : expr1 AND expr2 의 결과 ( 둘다 참이면 참 )
    [ expr1 -o expr2 ]  : expr1 OR expr2 의 결과 ( 둘중 하나만 참이면 참 )
  
  파일조건

    [ -b FILE ]           : FILE 이 블럭 디바이스 이면 참
    [ -c FILE ]           : FILE 이 문자 디바이스 이면 참.
    [ -d FILE ]           : FILE 이 디렉토리이면 참
    [ -e FILE ]           : FILE 이 존재하면 참
    [ -f FILE ]           : FILE 이 존재하고 정규파일이면 참
    [ -g FILE ]           : FILE 이 set-group-id 파일이면 참
    [ -h FILE ]           : FILE 이 심볼릭 링크이면 참
    [ -L FILE ]           : FILE 이 심볼릭 링크이면 참
    [ -k FILE ]           : FILE 이 Sticky bit 가 셋팅되어 있으면 참
    [ -p FILE ]           : True if file is a named pipe.
    [ -r FILE ]           : 현재 사용자가 읽을 수 있는 파일이면 참
    [ -s FILE ]           : 파일이 비어있지 않으면 참
    [ -S FILE ]           : 소켓 디바이스이면 참
    [ -t FD   ]           : FD 가 열려진 터미널이면 참
    [ -u FILE ]           : FILE 이 set-user-id 파일이면 참
    [ -w FILE ]           : 현재 사용자가 쓸 수 있는 파일(writable file) 이면 참
    [ -x FILE ]           : 현재사용자가 실행할 수 있는 파일(Executable file) 이면 참
    [ -O FILE ]           : FILE 의 소유자가 현재 사용자이면 참
    [ -G FILE ]           : FILE 의 그룹이 현재 사용자의 그룹과 같으면 참
    [ FILE1 -nt FILE2 ]   : FILE1이 FILE2 보다 새로운 파일이면 ( 최근파일이면 ) 참
    [ FILE1 -ot FILE2 ]   : FILE1이 FILE2 보다 오래된 파일이면 참
    [ FILE1 -ef FILE2 ]   : FILE1 이 FILE2의 하드링크 파일이면 참
  
  2.2 if 구문
    if 문은 조건을 판단하여 주어진 문장을 수행한다.
  
    1. 형식 1  ( 단일 if 문 )
    형식 :
      if [ 조건 ]
      then
        문장1
        문장2
      fi
    
    2. 형식 2  ( if~else 문 )
    형식 :
      if [ 조건 ]
      then
        문장3
        문장4
      fi
    
    3. 형식 3  ( if~elif 문 )
    형식 :
      if [ 조건 ]
      then
        문장1
        문장2
      elif
        문장3
        문장4
      else
        문장5
        문장6
      fi
    
  2.3 case 구문
  ※ 패턴에는 * 문자, 즉 와일드카드를 사용할 수 있다.
  형식 :
      case 변수 in
        패턴 [ | 패턴 ] ... ) 문장 ;;
        패턴 [ | 패턴 ] ... ) 문장 ;;
        ....
        * ) 문장 ;;
      easc
  
  2.4 목록
    여려명령을 실행할때 앞의 명령의 결과에 의해서 다음행동이 결정되어야 할 경우
    가 있다. 이런경우에 AND나 OR조건을 사용해서 한번에 처리할 수 있다. 이것은 쉘
    스크립트 뿐 아니라 명령행에서도 사용 가능하다. 물론 if 문을 이용해서 반환값
    을 검사하여 처리할 수 있지만 문장이 길어지고 복잡해진다.
  
    AND 목록
 
        statment1 && statment2 && statmentN && .....

        위의 명령들은 각 명령이 거짓이 될 때 까지 명령을 수행해 나간다. 수행도중
        결과가 거짓이 되면 그이후의 명령은 수행되지 않는다.
 
    OR  목록
 
        statment1 || statment2 || statmentN || .....
 
        위의 명령들은 각 명령이 거짓이 나오는 동안 계속된다. 즉 참이 나오면 실행
        을 멈춘다.
 
    AND와 OR목록은 혼용이 가능하다.
 
        [ 조건 ] && 문장1 || 문장2

        위의 예는 조건이 참이면 문장1을 수행하고 거짓이면 문장2를 수행한다.

        또한 위의 문장1이나 문장2에서 여러개의 문장을 수행 하고 싶을 때는 {}를
        사용하면 된다.

        [조건] && {
                    문장1
                    문장2
                    문장3
                          } || {
                                 문장4
                                 문장5
                                 문장6
                               }
 
3. 제어문
  3.1 for
  for 문은 지정된 범위안에서 루프를 수행한다. 범위는 어떤 집합도 가능하다.
  형식 :
         for 변수 in 값1, 값2, ...
         do
             문장
         done

  매 루프를 돌때마다 변수의 값은 in 이후의 값으로 대체된다.
  예)
      for str in "test1", "test2", "test3", "test4"
      do
         echo @str
      done

  출력 )

      test1
      test2
      test3
      test4
  
  값에는 와일드 카드 확장을 사용할 수 있다.

    for file in $(ls -a | grep "^.")
    do
      echo "$file is Hidden File"
    done

  위 예의 출력 결과는 현재디렉토리에서 처음이 "." 으로시작하는 파일(히든파일) 만
  을 출력한다.

  for file in $(ls chap[345].txt); do
      echo "--- $file ---" >> Books.txt
      cat $file >> Books.txt
  done

  위의예는 chap3.txt, chap4.txt, chap5.txt 파일을 Books.txt 라는 파일에 붙여 넣
  는다.

  다음의 예를 보고 결과를 예측해보자

  echo "\$* output"

  for fvar in $*
  do
    echo $fvar
  done

  echo "\$@ output"
  for fvar in $@
  do
    echo $fvar
  done
    
  3.2 while
    for 명령의 경우는 횟수를 지정해서 루프를 수행하는데는 문제가 있다.
    while 문은 실행횟수가 지정되지 않았을때 편리하다.
  
    형식 :
           while 조건문
           do
                문장
           done
   
    예제를 보자. 패스워드를 입력받고 맞는지 확인하는 프로그램이다.

    echo "Enter Password : "
    read password1

    echo "Retype Password : "
    read password2

    while [ "$password1" != "$password2" ]
    do
         echo "Password miss match Try again "

         echo "Retype Password : "
         read password2
    done

    echo "OK Password Match complete"
  


    어떻게 동작하는가 ?
    
  3.3 until
    until은 while문과 동일한 효과를 내지만 조건이 반대이다. 즉, while문은 조건이
    참 일동안 루프를 수행하지만 until은 조건이 거짓일 동안 루프를 수행한다.
    
    형식 :
      until 조건문
      do
       문장
      done
    
    다음 예를 보자. 이 예는 지정한 유저가 로그인 하면 알려준다.
    
    #!/bin/sh
    
    until who | grep "$1" > /dev/null
    do
        sleep 10
    done
    
    echo "User $1 just logged in ^_^"
  
 3.4 select
    select 문은 원하는 리스트를 출력하고 그중 선택된것을 돌려주는 구문이다. 주의
    할점은 select의 루프내에서는 자동적으로 루프를 벗어날 수 없다. 반드시 break
    문을 사용해서 루프를 벗어나야 한다.
  
    예) 간단한 퀴즈 ^_^

      #!/bin/sh
      
      echo "다음중 스크립트언어 프로그래밍에 속하는 것은 ?"
      select var in "쉘 프로그래밍" "C 프로그래밍" "자바 프로그래밍" "Exit"
      do
          if [ "$var" = "쉘 프로그래밍" ]
          then
                  echo "정답입니다."
                  exit 0
          elif [ "$var" = "Exit" ]
          then
                  echo "종료합니다."
                  exit 1
          else
                  echo "$var 을 선택하셨습니다. 오답입니다."
                  echo "다음중 스크립트언어 프로그래밍에 속하는 것은 ?"
          fi
      done

4. 함수
  쉘 스크립트 내부에 또는 다른 스크립트파일에 함수를 정의해 놓고 사용할 수 있다.
  함수를 사용하면 코드를 최적화 할 수 있고, 코딩이 간결해지며,재사용이 가능하다.
  그러나 다른 스크립트 파일을 호출해서 함수를 실행할 경우, 가능은 하지만 스크립
  트의 실행시간이 길어지고, 함수의 결과를 전달하는 것이 까다롭기 때문에 가급적이
  면 외부파일의 함수는 안쓰는 것이 좋다.
 
  형식 :
    정의 - 
    함수명 ()
    {
     문장
     return 값
    }
    
    사용
    
    함수명 인자1, 인자2, ...
    
    
    함수는 독립적으로 $#, $*, $0 등의 인자변수를 사용한다. 즉 함수내의 $#과 본체
    의 $#은 다를 수 있다는 것이다.
    
    다음의 예를 보자
    
    #!/bin/sh
  
    func()
    {
      echo ------ this is func --------
      echo "This Script Executable File : $0"
      echo "Argument Count : $#"
      echo "Process ID : $$"
      echo "Argument List \$* : $*"
      echo "Argument List \$@ : $@"
      echo "Argument 1 : $1"
      echo "Argument 2 : $2"
      echo "Argument 3 : $3"
    }
  
    echo ------ this is main --------
    echo "This Script Executable File : $0"
    echo "Argument Count : $#"
    echo "Process ID : $$"
    echo "Argument List \$* : $*"
    echo "Argument List \$@ : $@"
    echo "Argument 1 : $1"
    echo "Argument 2 : $2"
    echo "Argument 3 : $3"
    echo "Argument 4 : $4"
    func aa bb cc 


    본체와 함수에서 동일한 변수를 보여주지만 값은 틀린다는것을 알 수 있다.
    
    함수에서 값을 반환하기 - 함수에서 반환값은 반드시 정수값만을 반환할 수 있다.
    이 값을 if등으로 조건을 판단해서 사용할 수 있다. 반환값중 0은 참으로 나머지 
    숫자는 거짓으로 판별된다.
  
5. 명령어
  쉘에서 쓸 수 있는 명령어는 두가지로 나누어진다. 명프롬프트 상에서 실행 시킬 수
  있는 외부 명령어와 쉘 내부 명령이다. 내부명령은 보통 쉘 내부나 쉘 구문상에서
  쓰인다. 외부명령은 쉘에 관계없이 사용이 가능하다.
 
  break
    제어문이나 조건문의 루프를 빠져나갈때 사용한다.
    예)
     while [ $a -eq 10 ]
     do
      if [ $a -eq 5 ]; then
       break
      fi
     done
 
  :명령
    의미없는 명령. 논리값 true를 대신해 쓰기도 한다.
  
  continue
    제어문이나 조건문의 처음으로 돌아가서 다시수행한다.
    예)
     while [ $a -eq 10 ]
     do
         if [ $a -eq 5 ]; then
               continue
            fi
     done
  
  . 명령
    . 명령을 사용하면 현재 쉘에서 명령을 실행시킨다 그러므로 실행된 명령의 결과
    를 본 프로그램에서 사용할 수 있다.
    
    예를 들면 A 라는 스크립트에서 B라는 스크립트를 그냥 실행할 경우 B에서의 변화
    (환경변수 등)는 A에게 아무런 영향도 미치지 않는다. 그러나 . 명령을 사용해서 
    실행하면 B에서의 변화가 A에도 영향을 미친다.
  
  echo
    문장을 출력한다. 자동으로 개행문자가 삽입된다. ( 다음줄로 넘어간다 )
 
  eval
    인자의 실제 값을 구하는데 사용한다.
  
    foo=10
    x=foo
    y='$'$x
    echo $y
  
    이 예를 실행해 보면 $foo가 출력된다
  
    foo=10
    x=foo
    eval y='$'$x
    echo $y
  
    이 예에서는 $foo의 값 즉 10 이 출력된다. eval명령은 원하는 문자열들을 조합해
    서 변수를 액세스 할 수 있다.
 
  exec
    현재쉘을 다른 프로그램으로 대체한다.
  
    예 ) exec csh
 
  exit n
    현재 쉘을 종료한다. 종료시 n 값을 리턴한다.
 
  export
    해당 쉘에서 파생된 자식 프로세스에서 export한 환경변수는 본래 쉘에서 관리한
    다.
 
  expr
    표현식의 값을 구한다.    ( x=`expr 1 + 2` )
    요즘은 expr보다는 $((계산식)) 구문을 많이 사용한다.
 
  printf
    C 언어의 printf명령과 흡사하다.
    
    형식 :  printf "Format String" arg1 arg2 arg3 ...
  
  return
    쉘함수에서 값을 반환 할 때 쓰인다.
    0은 성공을 1~125까지는 쉘 에러코드를 나타낸다.
 
  set
    쉘 내부에서 매개 인자를 설정한다.
    set의 인자로 쓰인 문자열은 공백에 의해 $1 부터 차례대로 대입된다.
    
    예)
    
    #!/bin/sh
    echo $#
    set $(ls)
    echo $# 
    
    결과는 
    
    0
    22
    
    이다..( 22는 필자의 ls 결과의 갯수이다. ). 첫번째 0는 이 스크립트에 인수가
    없으므로 0이고 set $(ls) 에 의해서 인수의 갯수가 22개로 늘었다.
 
  shift
    쉘의 인자를 한자리씩 아래로( n -> 1 로 ) 이동시킨다.
    
    예)
    #!/bin/sh
    
    echo $1
    shift
    echo $1
    shift 5
    echo $1
    
    #./myscript 1 2 3 4 5 6 7 8 9 0
    1
    2
    7
 
 trap
    쉘의 실행도중 시그널을 처리하는 시그널 처리기를 만드는 역할을 한다.
    
    형식 : trap command signal
    
    쉘 스크립트는 위에서 아래로 실행되므로 보호하려는 부분 이전에 trap명령을 사
    용해야 한다. trap조건을 기본으로 사용하려면 명령에 - 를 넣으면 된다.
    신호를 무시하려면 '' 빈 문자열을 준다.
 
  unset
   변수나 함수를 제거한다.

6. 명령실행
  외부명령의 실행 결과를 변수에 집어넣어 변수의 값으로 사용할 수 있다.
  
  형식 : x = $(명령)
  
  이렇게 변수에 결과를 넣은 후에는 이 변수를 일반문자열로 생각하고 원하는 가공을
  해서 결과를 얻어낼 수 있다.
  위에서 보았던 매개변수 확장이나 set명령을 이용해서 원하는 부분을 추출해 내면
  그만이다.

7. 쉘 스크립트 내부에서 명령에 입력 전달하기 ( Here Documents )
  이 기능은 쉘 내부에서 명령어에 입력을 전달하는 방법이다. 전달된 입력은 마치 키
  보드에서 눌려진 것 처럼 반응한다.
  
  형식 :  명령 << 종료문자열
    입력값.....
    종료문자열
  예제 ) 자동으로 메일을 보내는 스크립트
  
  #!/bin/sh
  
  mail $1 << myscript
  This is Header
  This is Body
  .
  
  myscript

linux] iptalbes

[펌] Iptables로 기본적인 firewall 구축하기  linux  2005/01/05 11:13  수정  삭제
 http://blog.naver.com/wiggyz/80009098607


 푸른하늘 | 푸른하늘
 http://blog.naver.com/sung3ne/100009045197
1 장 : IP 주소 막기

이번시간에는 Iptables사용법과 기본적인 firewall구성법에 대해서 알아보도록 하겠다.
Iptables에 대해 배워보기에 앞서서 여기서 테스트한 환경은 다음과 같다.

CPU : AMD Duron 800Mhz
OS : RedHat Linux 7.1 (Kernel 2.4.x)
HDD : 13G
RAM : 128M


이제 Iptables를 사용하기 위한 기본적인 설정에 대해서 알아보자. Iptables는 Kernel 2.4.x 기반의 리눅스 설치시에 기본으로 설치되어있고 /sbin 디렉토리 아래에 있다. 그리고 iptables와 ipchains는 동시에 사용할 수 없으므로 우선 ipchains의 모듈을 내려줘야 한다.
아래의 그림처럼 lsmod를 해보고 만약 ipchains 모듈이 올라와 있다면 rmmod ipchains 명령으로 모듈을 내려줘야 iptables 사용이 가능하다.


이제 Iptables에 대해서 본격적으로 알아보도록 하자.
기본적으로 Iptables에는 세가지 chain이 있고 모든 패킷은 이 세가지 chain중 하나를 통과하게 된다. 이 세가지 chain은 INPUT, OUTPUT, FORWARD chain인데 우선 여러분의 컴퓨터로 들어가는 모든 패킷은 INPUT chain을 통과한다. 그리고 여러분의 컴퓨터에서 나가는 모든 패킷은 OUTPUT chain을 통과한다. 그리고 하나의 네트워크에서 다른 곳으로 보내는 모든 패킷은 FORWARD chain을 통과한다.

Iptables가 작동하는 방식은 이들 각각의 INPUT, OUTPUT, FORWARD chain에 당신이 어떠한 rule을 세우는 지에 따라 달라진다.
예를 들어 당신이 HTML 페이지를 요청하기 위해 http://www.yahoo.com/에 패킷을 보낸다면 이 패킷은 우선 당신 컴퓨터의 OUTPUT chain을 통과하게 된다.
그러면 kernel에서 OUTPUT chain의 rule을 확인하고 rule과 match가 되는지 확인을 하게된다. rule중에서 최초로 match되는 것에 의해 당신이 보낸 패킷의 운명이 결정되는 것이다.
만약 어떤 rule과도 match되지 않는다면 전체 chain의 정책이 ACCEPT냐 DROP이냐에 따라 패킷의 운명이 결정될 것이다. 그러고 나서 Yahoo! 에서 응답하는 패킷은 당신의 INPUT chain을 통과하게 될 것이다.
IP 주소 막기
이제 기초적인 개념에 대해서 알아봤으니 실제로 사용해 보도록 하겠다.
Iptable을 사용할 때에는 기억해야 할 많은 옵션들이 있으므로 man 페이지(man iptables)를 잘 활용하는 것이 중요하다. 이제 특정 IP를 조종하는 법에 대해서 알아보자. 우선 당신이 200.200.200.1 이라는 IP로부터 오는 모든 패킷을 막고 싶어한다고 가정하자. 우선 -s 옵션이 사용되는데 여기에서 source IP나 DNS name을 지칭할 수 있다. 그러므로 다음과 같이 함으로써 이 IP를 지칭할 수 있다.

./iptables -s 200.200.200.1


하지만 위처럼만 명령을 내리면 kernel은 위의 주소에서 오는 패킷을 어떻게 처리해야 할 지를 알 수가 없다. 그러므로 -j 옵션으로 그 패킷을 어떻게 처리해야 하는지 결정해야 한다. 일반적으로 3가지 옵션이 있는데 ACCEPT, DENY, DROP이다.
ACCEPT는 대충 예상할 수 있듯이 패킷을 허용하는 옵션이다. DENY 옵션은 컴퓨터가 연결을 허용하지 않는다고 메시지를 돌려 보내는 옵션이다. 그리고 DROP 옵션은 패킷을 완전히 무시해 버린다. 만약 우리가 이 IP에 대해 확실히 의심이 간다면 우리는 DENY 대신에 DROP을 사용해야 할 것이다.
그러므로 결과적으론 다음과같이 옵션을 주면 된다.

./iptables -s 200.200.200.1 -j DROP


하지만 이 명령만으로는 아직 컴퓨터가 명령을 이해할 수가 없다. 우리는 한가지를 더 추가해야 되는데 바로 어떤 chain의 rule로 적용시킬지 결정해야 하는 것이다.
여러분은 -A 옵션을 사용해서 이를 결정할 수 있다. 즉 아까 위에서 본 INPUT, OUTPUT, FORWARD 옵션 중에서 하나를 선택해야 하는 것이다. 이 옵션을 줌으로써 당신이 선택한 chain의 맨 아래부분에 새로운 rule이 추가될 것이다.
따라서 우리는 우리에게 들어오는 패킷을 차단하고 싶으므로 INPUT 옵션을 주면 되는 것이다. 그러므로 전체 명령은 다음과 같다.

./iptables -A INPUT -s 200.200.200.1 -j DROP


이 한 줄의 명령으로 200.200.200.1로부터 오는 모든 패킷을 무시할 수 있다. 옵션의 순서는 바뀌어도 상관이 없다. 즉 -j DROP이 -s 200.200.200.1 보다 앞에 가도 상관이 없다. 만약 그 반대로 200.200.200.1로 패킷이 못가도록 하려면 INPUT 대신에 OUTPUT을, -s 대신에 -d(destination) 옵션을 주면된다.

2 장 : Service 차단하기

만약 우리가 해당 컴퓨터로부터 telnet 요청만 무시하고싶다면 어떻게 해야 하는가? 이것도 그다지 어렵지 않다. 일단 큰 범주로 나누어 봤을 때 적어도 3가지의 프로토콜 - TCP, UDP, ICMP - 가 있다. 다른 대부분의 서비스와 마찬가지로 telnet은 TCP 프로토콜로 작동한다. -p 옵션으로 우리는 프로토콜을 결정할 수 있다. 하지만 TCP라고만 옵션을 줘서는 컴퓨터가 인식하지를 못한다. telnet은 TCP프로토콜로 작동하는 특정 서비스에 불과하기 때문이다. 우선 우리가 프로토콜을 TCP로 설정한 다음에는 --destination-port 옵션으로 해당하는 port를 설정해 줘야한다.
우선 telnet의 포트번호는 23번이다. 포트번호 대신에 telnet이라 써도 상관없다.
여기서 source port 와 destination port를 혼동하면 안된다. 즉 클라이언트는 어떤 포트로도 작동할 수 있는 반면에 서버는 23번 포트로 작동하기 때문이다. 즉 특정 서비스를 차단하기 위해서는 -destination-port를 이용하면 되고, 그 반대는 -source-port를 이용하면 된다. 이제 이들 옵션을 합쳐서 아래와 같이 명령을 주면 된다.
./iptables –A INPUT –s 200.200.200.1 –p tcp --destination-port telnet –j DROP


그리고 IP의 영역을 선택하고 싶다면 200.200.200.0/24 와 같이 설정하면 된다. 이것은 200.200.200.* 에 해당하는 모든 IP를 선택하는 것과 같다.
선택적인 차단
이제 좀더 심화된 내용에 대해서 알아보자. 우선 여러분의 컴퓨터가 local area network(LAN)에 있고, Internet에 접속 가능하다고 가정한다. 알다시피 LAN은 eth0으로 Internet 연결은 ppp0으로 구분할 수 있다. 이제 다시 다음과 같이 가정해 보자. 우리는 telnet 서비스를 LAN상의 컴퓨터에게는 서비스하고 보안상 Internet상에서는 접근하지 못하도록 하고 싶다. 이것 역시 쉽게 구성할 수 있다. 우리는 input interface에 대해서는 -i 옵션을 output interface에 대해서는 -o 옵션을 사용할 수 있다. 즉 다음처럼 명령을 주면 된다.
./iptables –A INPUT –p tcp --destination-port telnet –i ppp0 –j DROP


이렇게 함으로써 우리는 LAN상의 사용자는 telnet을 사용하고 그밖에 Internet상의 사용자는 telnet 을 사용하지 못하도록 할 수 있다.
Rule 순서에 관하여
이제 다음 단계로 들어가기에 앞서서 rule을 조종하는 다른 방법에 대해서 간단히 알아보자.
Iptables의 chain에서는 먼저 등록 된 rule이 효력을 발생하기때문에 등록을 하는 순서가 중요하다. 모든 것을 거부하는 설정이 먼저오게 되면 그 이후에 포트를 열어주는 설정이 와도 효과가 없다. 그러므로 허용하는 정책이 먼저오고 나서 거부하는 정책이 와야한다.
–A 옵션을 줌으로써 우리는 새로운 규칙을 chain의 맨 아래에 추가하게 된다. 즉 chain상의 상위 rule이 먼저 작동하기 때문에, 만일 새로 추가하는 rule을 먼저 작동시키기 위해서는 -I 옵션을 줌으로써 새로운 rule을 원하는 위치에 놓을 수 있다. 예를 들어 INPUT chain의 가장 위에 어떤 rule을 놓고 싶다면 “-I INPUT 1” 이라 명령하면 된다. 그리고 다른 위치로 놓고 싶다면 1을 다른 숫자로 바꿔주면 된다.
그리고 이미 위치된 rule을 다른 위치로 바꾸고 싶다면 -R 옵션을 주면 된다. -I 옵션을 주는 것과 마찬가지로 사용할 수 있는데 다만 -I옵션을 사용해서 1의 위치에 놓으면 다른 rule들이 밑으로 한칸씩 내려가는 반면 -R옵션을 사용해서 1의 위치에 놓으면 그 위치의 rule은 삭제된다.
그리고 끝으로 rule을 삭제하고 싶다면 -D옵션과 숫자를 사용하면 되고, -L 옵션을 사용하면 작성된 모든 rule의 목록을 보여주고, -F 옵션을 주면 해당 chain의 모든 rule을 삭제한다. 그리고 만약 chain을 명시하지 않았다면 모든 것을 flush할 것이다.


3 장 : SYN Packets

좀더 심화된 내용에 대해서 알아보자. 우선 패킷들은 특정 프로토콜을 사용한다. 그리고 프로토콜이 TCP라면 역시 특정 port를 사용한다. 그러므로 여러분 컴퓨터의 모든 포트를 막음으로써 보안을 할 수 있을 것이다.
하지만 당신이 다른 컴퓨터에 패킷을 보내면 그 컴퓨터는 당신에게 다시 응답을 해야한다. 그러므로 만약 당신에게 들어오는 모든 포트를 막아버린다면 당신에게 응답하는 패킷도 결국 못 들어오므로 connection을 하는 의미가 없을 것이다.
하지만 다른 방법이 있다. 두 컴퓨터가 TCP connection으로 패킷을 주고 받는다면 그 connection은 우선 초기화가 되어야 한다.
이것은 바로 SYN packet이 담당한다. SYN packet은 단순히 다른 컴퓨터에게 주고 받을 준비가 되었다는 것만 알려주는 초기화 기능만을 한다. 이제 서비스를 요청하는 컴퓨터는 우선적으로 SYN packet을 보낸다는 것을 알게 되었다. 그러므로 들어오는 SYN packet만 막기만 하면 다른 컴퓨터가 당신 컴퓨터의 서비스를 이용하지 못하게 할 수 있고, 하지만 당신은 그들과 통신할 수 있는 것이다.
즉 이와 같이 하면 당신이 먼저 패킷을 보내서 요청이 들어오는 것이 아니면 모두 무시해 버리게 된다.
이 옵션을 사용하기 위해서는 선택한 프로토콜 뒤에 --syn이라고 명령을 넣으면 된다. 이제 인터넷으로부터 오는 모든 연결을 막기위해서는 다음과 같이 rule을 정하면 된다.
./iptables –A INPUT –i ppp0 –p tcp --syn –j DROP


당신이 만약 웹 서비스를 운영하는 것이 아니라면 이것은 유용한 rule이 될 것이다.
만약 당신이 웹서비스를 위해 하나의 포트(예를들어 80번-HTTP)만 열어두고 싶다면 역시 한가지 방법이 있다.
바로 “!” 마크를 사용하면 되는데 많은 프로그래밍 언어에서처럼 “!”은 “not”을 의미한다.
예를들어 80번 포트만 제외하고 모든 SYN packet들을 막고싶다면 다음과 같이 하면 된다.

./iptables –A INPUT –i ppp0 –p tcp --syn --destination-port ! 80 –j DROP


다소 복잡한듯해도 간단한 rule이다.
Chain 정책
마지막으로 한가지 남은 것이 있다. 이것은 chain의 정책을 바꾸는 것으로 INPUT과 OUTPUT chain은 디폴트로 ACCEPT로 정해져 있고, FORWARD chain은 DENY로 정해져 있다.
만약 당신의 컴퓨터를 라우터로 사용하려면 당신은 FORWARD chain의 정책을 ACCEPT로 설정하고 싶을 것이다.
이럴때 어떻게 해야하는가? 이것은 매우 간단하다. -P 옵션을 사용하면 된다. 즉 FORWARD chain을 ACCEPT로 정하기 위해선 다음과 같이 명령을 내리면 된다.

./iptables -P FORWARD ACCEPT




4 장 : iptables, 스크립트로 만들어 사용하기

이번에는 iptable 명령어를 편리하게 스크립트로 만들어서 사용해 보자
일단 iptables라는 파일을 다음처럼 작성해 보자. 파일의 위치는 /etc/sysconfig/ 아래에 두도록 하겠다.


--begin script--
#!/bin/sh
# 우선 모든 Rule을 정리한다.
/sbin/iptables -F
# 다음으로 각각에 대한 정책을 세운다.
/sbin/iptables -P INPUT DROP
/sbin/iptables -P OUTPUT ACCEPT
/sbin/iptables -P FORWARD DROP
# localhost에서의 traffic을 받아들인다.
/sbin/iptables -A INPUT -i lo -j ACCEPT
# 확립된 연결에 대한 Packet을 받아들인다.
/sbin/iptables -A INPUT -i eth0 -p tcp ! --syn -j ACCEPT
# DNS 응답을 받아들인다.
/sbin/iptables -A INPUT -i eth0 -p tcp --source-port 53 -j ACCEPT
/sbin/iptables -A INPUT -i eth0 -p udp --source-port 53 -j ACCEPT
# 인증 연결을 거부한다(그렇지 않을 경우 메일서버가 오랫동안 타임아웃 상태가 될 것이다.)
/sbin/iptables -A INPUT -i eth0 -p tcp --destination-port 113 -j REJECT
# echo나 목적지에 도착 못하거나 시간 초과된 icmp packet들을 받아들인다.
/sbin/iptables -A INPUT -i eth0 -p icmp --icmp-type 0 -j ACCEPT
/sbin/iptables -A INPUT -i eth0 -p icmp --icmp-type 3 -j ACCEPT
/sbin/iptables -A INPUT -i eth0 -p icmp --icmp-type 11 -j ACCEPT
--end script—


위의 스크립트는 하나의 예에 불과하고 기타 ssh나 ftp, samba등을 이용하기 위한 설정사항을 직접 작성해야 한다.
파일 작성이 끝났으면 파일에 실행권한을 줘야한다. 보안상 root만 실행할 수 있도록 권한을 변경한 후 위의 스크립트를 실행하면 된다.
확인을 하려면 /sbin/iptables –L 이라고 하면 방금 실행시킨 스크립트가 나올 것이다.
그리고 부팅시마다 실행을 시키려면 /etc/rc.d/rc.local 파일 맨 아래 부분에 다음처럼 넣으면 된다.
if [ -f /etc/sysconfig/iptables ]; then
/etc/sysconfig/iptables
fi
이번 시간에는 Iptables의 기초만을 알아보았다. 여기 있는 정보를 통해서 당신은 기본적인 firewall을 설정할 수 있을 것이다. 하지만 아직 많은 것들이 남아있다. 더 많은 옵션에 대해서 알아보기 위해서 man 페이지를 활용하기 바라고 Iptables에 관련된 심화된 문서들을 참고하기 바란다.
Reference Site
http://kldp.org/Translations/html/Packet_Filtering-KLDP/Packet_Filtering-KLDP-7.html
http://linux.com/enhance/newsitem.phtml?sid=125&aid=12431
http://chongnux.klug.or.kr/board/read.php?table=tip1&no=326
http://linux.co.kr/tips/se.html?keyword=iptables


출처 : linux.co.kr (http://www.linux.co.kr/theme/pageview.html?ca=200108&pageid=40&aaa=138&casub=iptables&st=Iptables로%20기본적인%20firewall%20구축하기)

linux] devfs 설명

Linux Devfs (Device File System) FAQ
Richard Gooch
2-FEB-2002
번역:최종필(viatoris@nownuri.net, viatoris@viatoris.homeip.net)
(4-FEB-2002)
Document languages:  
--------------------------------------------------------------------------------
NOTE: 이 문서의 원본은 http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html 에서 찾을수 있고, 커널소스와 함께 제공되는 텍스트 문서보다 보기에 더 편하다. 미러사이트는 http://www.ras.ucalgary.ca/~rgooch/linux/docs/devfs.html 에 있다.
또한 devfs와 같이 사용되는 데몬이 있는데,http://www.atnf.csiro.au/~rgooch/linux/ 에서 더 많은 정보를 얻을수 있다.
당신이 신청할 경우 메일링 리스트의 사용이 가능하다. mailto:majordomo@oss.sgi.com로 메일 본문에
subscribe devfs
과 같은 내용을 포함하여 메일을 보내라. 신청취소는
unsubscribe devfs
을 포함한 메일을 보내면 된다. 이 리스트는 http://oss.sgi.com/projects/devfs/archive/ 에 보관된다.

--------------------------------------------------------------------------------
2002. 02. 04 홈페이지 이전에 따른 링크 수정. 오타 수정.
2002. 01. 24 현재 번역 완료. 잔손질. 버전 ver 0.1 :-p
2002. 01. 16 현재 번역중입니다. 최대한 빨리 번역하도록 하겠습니다.
--------------------------------------------------------------------------------
목차
이것은 무엇인가?
왜 이것을 하는가?
누가 이일을 하는가?
동작원리
조작상의 문제 (꼭 읽어보시오)
개론 또는 또는 참을성이 부족한 사람
리붓후의 퍼미션 유지
devfs의 지원없이 드라이버 취급하기
Devfs의 모든 방법
다른 문제점
커널의 네이밍 스키마
Devfsd 네이밍 스키마
옛방식과의 호환
SCSI Host의 탐색에 있어서의 문제
현재까지 만들어진 디바이스 드라이버
디바이스 번호의 할당
질문과 답변
Making things work
devfs의 대안들
devfs에 대해 좋아하지 않는 것
버그리포트의 방법
생소한 커널메세지
devfsd의 문제점들
다른 참고문서
이 문서의 번역물
--------------------------------------------------------------------------------
이것은 무엇인가?
Devfs는 루트 파일시스템에서 "실제" 캐릭터 및 특수 블럭디바이스를 취급하는 것에 대한 다른 방법이다. 커널 디바이스 드라이버는 메이저/마이너 번호에 의해 등록되는 것보다 더 나은 이름으로 디바이스를 등록할수 있다. 이 디바이스들은 그 드라이버에 지정된 소유권과 보호권한을 가진체 자동적으로 devfs에 나타날 것이다. 데몬(devfsd)은 이러한 기본값을 덮어써서 사용할 수 있다. Devfs는 커널 2.3.46 이후버전부터 사용할수 있다.
NOTE devfs는 옵션이라는 것을 명심하자. 만약 예전방식의 disc-based 디바이스 노드를 선호한다면, 간단하게 CONFIG_DEVFS_FS=n (기본값)라고 두면 된다. 이 경우에, 아무것도 바뀌지 않는다. 또한 devfs를 활성화시켰다면 기본값은 예전의 디바이스 이름과 완벽하게 호환되도록 관리된다는 것을 기억하라.
devfs를 바라보는데에 두가지 관점이 있다.: 하나는 디바이스 네임스페이스가 단지 마운트된 파일시스템처럼 네임스페이스라는 것에 기초한 것이다. 다른 하나는 그 디바이스 네임스페이스의 관점을 제공하는 파일시스템의 코드에 대한 관점이다. 내(원저자)가 이런 구분을 만든 이유는 devfs는 각 마운트마다 같은 디바이스 네임스페이스를 보여주면서 여러번 마운트 될수 있기 때문이다.
devfs에 대한 댓가는 커널코드의 크기와 메모리 사용량에 대한 소량의 증가이다. 약 7페이지의 코드(__init 섹션에서)와 그 네임스페이스에서 각 개체에 대하여 72바이트의 메모리가 필요하다. 보통의 시스템은 수백개의 디바이스 개체를 가지며, 이것은 좀더 많은 페이지를 필요로 한다. ramdisc에 /dev를 넣는 방법과 이것을 비교해 보라.
일반적인 머신에서, 그 댓가는 0.2 퍼센트 이하이다. 64메가의 램을 가지는 보통의 시스템에서는 0.1 퍼센트 이하이다. devfs 에 대해 "bloatware"라는 비난은 정당성이 없다.

--------------------------------------------------------------------------------
왜 이것을 하는가?
devfs를 필요로 하는 여러 문제점이 있다. 이들 문제들 중에 어떤 것들은 (당신의 관점에 따라서) 매우 심각하고, 어떤 것들은 devfs 없이 해결할 수 있다. 그러나, 전체적인 면에서 보면 이 문제들은 devfs를 필요로 한다.
선택할 수 있는 것은 복잡하고 헛점투성이인 필요없는 사용자 공간에서의 해결 패치를 내놓거나, 간단하고 튼튼하며 효과적인 devfs를 사용하는 것 중에 하나이다.
devfs에 대한 많은 반론이 있고, 모두다 devfs를 구현하지 않으면 얻어지는 이익들을 포함하고 있다. 하지만, 지금까지는 코드가 없거나, devfs가 제공하는 모든 기능들을 제공할수 있는 어떤 대안도 없다. 게다가, 제안된 대안들은 사용자 공간에서 더 복잡하다(그리고 devfs보다 기능적으로 모자란체로 제공한다). 어떤 사람들은 "커널 크기"의 감소를 과제로 삼지만 사용자 공간에 미치는 영향은 고려하지 않는다.
좋은 해결책은 커널공간과 사용자 공간의 전체적인 복잡함을 제한하는 것이다.
메이저&마이너 할당
현존하는 스키마는 각각의 디바이스 마다 메이저/마이너 디바이스 번호의 할당을 요구한다. 이것은 유일성을 보존하기 위하여 (당신이 "개인적"인 디바이스 드라이버를 개발하지 않는한) 이들 디바이스 번호들을 처리하기 위하여 중앙집중적인 권한이 요구된다는 것을 의미한다. Devfs는 네임스페이스에 대한 부하를 덜어준다. 이것은 크게 부하를 덜어주는 것처럼 보이지 않지만, 실제로는 엄청난 효과를 낸다. 드라이버 관리자들은 자연적으로 그 디바이스의 기능을 반영하는 디바이스 이름을 선택하므로, 네임스페이스의 충돌에 대한 잠재적 위험은 적다. 이것을 해결하기 위해서는 커널의 변경이 필요하다.
/dev 관리
현재 디바이스스 노드를 통하여 디바이스에 접근하기 때문에, 시스템 관리자에 의해 만들어져야만 한다. 표준 디바이스에 대하여 당신은 모든 (수백개의!)노드를 만들어내는 MAKEDEV라는 프로그램을 찾을 수 있다. 이것은 커널에서의 변화는 MAKEDEV 프로그램에서 반영되어야 하거나, 시스템 관리자가 수동으로 디바이스 노드를 만들어야 한다는 것을 의미한다.
기본적인 문제는 메이저 번호와 마이너 번호를 구분하는 두개의 데이터베이스가 존재한다는 것이다. 하나는 커널에 있고, 나머지는 /dev에 있다(또는 만약 당신이 그런 방법으로 보기 원한다면 MAKEDEV 프로그램에 있다.). 이것은 실용적이지 못한 정보의 중복이다. 이 문제를 해결하기 위해서는 커널의 변경이 필요하다.
/dev 의 증가
전형적인 /dev에는 1200개 이상의노드가 있다! 이 디바이스들의 대부분은 하드웨어가 없기 때문에 존재하지 않는다. 이 거대한 /dev 는 디바이스 접근 시간을 증가시킨다(나는 단지 dentry 탐색 시간과 존재하지 않는 디스크의 inode를 읽는데 걸리는 시간만을 참조한 것이다: 다음 항목에서는 좀더 끔찍한 예를 보여준다).
다음의 예는 SCSI 디바이스를 고려한다면 /dev 가 얼마나 커질수 있는 가를 보여준다.
host           6  bits  (say up to 64 hosts on a really big machine)
channel        4  bits  (say up to 16 SCSI buses per host)
id             4  bits
lun            3  bits
partition      6  bits
TOTAL          23 bits
가능한 모든 디바이스 노드를 저정하기 원한다면 8메가(1024*1024)의 inode를 필요로 한다. 만약 id, partion을 제외하고 SCSI 타겟(id)당 하나의 SCSI 버스와 하나의 논리적 유닛을 가지는 호스트 어뎁터로 가정한다 할지라도, 여전히 10bits 또는 1024개의 노드가 남는다. 각 VFS inode는 대략 256 bytes를 차지하므로(kernel 2.1.78), 디스크(실제 inode 역시 VFS inode와 유사한 양의 공간을 차지한다고 가정하면) 디스크상에 256kBytes의 inode 저장공간이 필요하다. 오늘날 디스크는 저렴하므로, 나쁘지는 않다. 임베디드 시스템은 /dev inode의 256kBytes에 대해 주의해야 하지만 임베디드 시스템은 /dev 디렉토리를 수동으로 조정할 수 있다. 나 자신의 임베디드 시스템에서는 그렇게 해야겠지만, devfs를 사용하는 방법을 택할 것이다.
다른 문제는 최초로 참조될때 inode 를 탐색하는데 걸리는 시간이다. 메모리상의 리스트를 통하여 탐색하는데 걸리는 시간 뿐만 아니라, 디스크에서 inode를 읽는데 걸리는 시간도 있다. 이 문제는 커널로그를 분석하여 필요하지 않으면 /dev 개체를 삭제하고 필요할때 생성하는 프로그램을 사용하여 사용자 공간상에서 해결할 수 있다. 이 프로그램은 새로운 모듈이 로드될때마다 실행될 것이고, 많은 부분 느려지게 될 것이다.
SCSI 디바이스에 대하여 디바이스 노드를 자동으로 만드는 scsidev라 불리는 프로그램이 있다. 이 프로그램은 /proc/scsi에서 파일을 탐색하는 방법으로 작동한다. 불행히도, 다른 디바이스 노드에 대해 이 개념을 확장하는 것은 현존하는 드라이버들을 많은 부분 수정하는 것이 필요하다(/proc에 정보를 제공해야 하기 때문에). 이것은 간단한 변경이 아니다(나는 devfs가 유사한 일을 한다는 것을 알고 있다). 당신이 이러한 모든 노력을 하더라도, (이 정보를 제공하고 있는) devfs를 사용하는 것이 나을 것이다. 따라서, 다른 드라이버들이 다른 방법으로 각각의 정보를 제공하는 것처럼, 시스템은 각각의 특성에 맞게 구현되어야 한다. 특수한 경우에 구현되는 시스템처럼
Devfs는 (자연스럽게) 디바이스 노드 스스로 정보를 제공하는 일정한 메커니즘을 가지고 있으므로 더 명확하다.
드라이버 file_operations 변환에 대한 노드
disc-based 방법으로 연결하는 캐릭터/블럭 노드들과 devfs 개체들이 /dev 의 개체와 실제 디바이스 노드들 사이에 연결하는 것에는 매우 중요한 차이점이 있다.
8비트의 메이저/마이너 번호를 가지고 disc-based c&b 노드들과 메이저번호당 드라이버의 사이를 연결하는 하는 것은 고정된 128 개의 엔트리 테이블을 통하여 이루어진다. 다양한 파일시스템은 디바이스가 열리면 그 드라이버 file_operations을 빠르게 indirection 함으로써 {chr,blk}dev_inode_operations에서 c&b 노드를 통하여 inode operation을 설정한다.
다른 miscellaneous 디바이스들 때문에 두번째 단계가 필요하다: 그 파일이 열렸을때 같은 마이너 번호를 가진 드라이버 엔트리를 탐색하고, 적당한 마이너 오픈 메쏘드를 호출한다. 이 탬색은 디바이스 노드를 열때 *항상* 수행된다. 어쩌면, 오픈 메쏘드를 찾기 전에 수십개의 misc. 개체를 탐색할 것이다. 많은 어버헤드를 일으키지는 않는다 하더라도, 필요없는 작업으로 보인다.
리눅스는 때때로 8비트의 메이저/마이너 경계를 *넘어서야만* 한다. 만약 16비트로 각각을 증가시킨다면, 메이저 테이블은(캐릭터 및 블럭 디바이스에 대해 하나의) 64k 엔트리가 필요하기 때문에 (x86 에서는 512kBytes, 64 비트 시스템에서는1 메가바이트), 그 메이저 드라이버를 사용하는 인덱싱 스키마는 사용할 수 없게 된다. 따라서 miscellaneous 캐릭터 디바이스를 사용하는 것처럼 스키마를 사용해야만 한다. 이것은 탐색시간은 당신의 시스템에서 메이저 디바이스 드라이버의 평균 수에 따라 선형적으로 증감한다는 것을 나타낸다. 모든 "디바이스"가 하드웨어는 아니다. 어떤 것은 KGI처럼 좀더 고수준의 드라이버들이다. 따라서 당신은 하드웨어의 증가 없이 더 많은 "디바이스"들을 얻을 수 있다. 당신은 질서정연한(균형잡힌:-) 바이너리 구조를 생성함으로써 이것을 향상 시킬수 있고, 이 경우에 탐색시간은 log(N)으로 된다. 다른 방법으로는, 탐색시간을 향상시키기 위해 해싱(hashing)을 사용할 수 있다. 그러나 꼭 해야만 하는 것이 아니라면 왜 모두를 탐색하려 하는가? 다시 한번, 이것은 필요없는 것처럼 보인다.
devfs는 메이저&마이너 시스템을 사용하지 않는 다는 것을 기억하라. devfs 엔트리에 대한 연결은 /dev 개체를 탐색했을때 일어난다. devfs_register()이 호출되면, 내부의 테이블은 그 엔트리 이름과 file_operations을 추가한다. 그 dentry 캐시가 미리 /dev 엔트리를 가지고 있지 않다면, 이 내부의 테이블은 file_operations를 얻기 위하여 탐색되고, inode는 생성된다. 만약 dentry 캐쉬가 이미 그 엔트리를 가지고 있다면, 탐색시간은 *필요없다*(other than the dentry scan itself, but we can't avoid that anyway, and besides Linux dentries cream other OS's which don't have them:-). 또한, devfs에 노드 엔트리의 수는 사용가능한 디바이스 엔트리의 수와 같다. 즉, "상상할 수 있는" 수가 아니다. disc-based /dev에서 필용벗는 엔트리를 지운다 하더라도, 공간을 절약하기 위하여 스스로 제한하더라도 상상할 수 있는 엔트리의 수는 여전히 같은 체로 남아있다.
Devfs는 VFS 노드와 디바이스 드라이버 사이의 빠른 연결을 제공한다.
시스템 관리 도구로서의 /dev
/dev는 내가 가지고 있지 않는 대부분의 디바이스를 포함하여 가능한 모든 디바이스의 노드를 포함한다. Devfs는 단지 시스템에서 사용가능한 디바이스만 보여준다. 이것은 /dev의 목록을 만든다는 사용가능한 디바이스를 편리한 방법으로 체크한다는 것을 의미한다.
메이저&마이너 크기
현재 메이저/마이너 번호들은 각각 8비트로 제한되어 있다. 이것은 하나의 메이저 넘버를 소비하는 SCSI 디스크 드라이버와 같은 드라이버에서는 한계요인이 된다. 16개의 디스크만 지원되고 각 디스크는 15개의 파티션을 가질 수 있다. 아마 이것은 당신에게는 문제가 아닐지 모르나, 디스크 어레이를 사용하여 큰 리눅스 시스템을 만드는 이에게는 큰 문제가 된다. Devfs에서 임의의 포인터는 32비트 디바이스 구분자(i.e. 32비트 마이너 넘버를 가지는 것처럼 보이는)를 사용할 수 있는 각각의 디바이스 엔트리로 연결시킬수 있다. 이것은 커널에만 관련된 것이므로, 메이저/마이너 번호를 크기를 증가시키는 것에 대하여 C 라이브러리와의 호환에 대한 논란은 필요없다. 사용자 공간에서 호환성을 유지하는 것에 대한 세부사항은 "디바이스 번호의 할당"에 대한 섹션을 보라.
이 문제를 해결하는데는 커널의 변경이 필요하다.
이것을 작성함으로써, 커널은 SCSI 디스크 드라이버가 더 많은 메이저 번호를 할당받고, 128 디스크 이상을 지원하도록 수정되었다. 이들 메이저 번호들이 비연속적(무계획적인 확장의 결과로 인해)이므로, 그것의 구현은 처음보다 더 상가신 일이 되었다.
주소공간에서 절박한 제한을 수정하기 위해여 IPv4 를 변경하는 것처럼, 사람들은 그 제한을 둘러갈 방법을 찾느다. 그러나 오랜 시간이 흐른다면 IPv6 또는 devfs와 같은 해결책은 영원히 지속되지 못한다.
읽기전용 루트 파일시스템
루트 파일시스템에 디바이스 노드를 가진다는 것은, 읽기전용 루트 파일시스템에서는 원하는데로 작동하지 못한다는 것을 의미한다. 그것은 tty 디바이스의 소유권과 보호권에 변경하기를 원하는 것이기 때문이다. 이런 방법은 당신이 루트 파일시스템 디바이스로서 CD-ROM을 사용하는 것을 막는다. 확실히, 당신은 CD-ROM을 이용하여 부팅을 할수는 있으나, tty의 소유권을 변경하지는 못한다. 따라서 그 방법은 인스톨할때나 좋은 방법이다.
또한, 디스크가 없는(discless) 리눅스 머신(보통 /dev 에서 변경된 tty 소유권을 가지는 것은 좋지 못하다)의 클러스터에 NFS 루트 파일시스템을 공유할 수 없다.또한 ROM-FS에서 당신의 루트 파일시스템을 포함시킬수도 없다.
당신은 부팅시에 RAMDISC를 만들고, 그것에 ext2 파일시스템을 만든후, 그것을 어떤 장소에 마운트하고 /dev의 목록을 그것에 복사한 후, 마운팅을 해제하고 /dev에 그것을 다시 마운팅 하는 방법으로 피해갈 수 있다.
Devfs는 이 문제를 해결하는데 있어 좀더 명확한 방법이 있다.
Non-Unix 루트 파일시스템
Non-Unix 파일시스템(NTFS와 같은)은 그것들이 다양한 캐릭터/블럭 스페설 파일 또는 심볼릭 링크들을 지원하지 않기 때문에 루트 파일시스템으로 사용할 수 없다. 당신은 마운트 하기 전에 디바이스 노드를 필요로 하기 때문에 /dev 에 마운트된 파일시스템이 disc-based 인지 RAMDISC-based 인지 구분할 수 없다. Devfs는 디바이스 노드 필요없이 마운트 할 수 있다. Devlink는 심링크(symlink)의 지원이 안되기 때문에 작동하지 않을 것이다. 다른 해결책은 RAMDISC 초기 루트 파일시스템(소수의 선택된 디바이스 노드를 포함하는)을 마운트 하기 위하여 initrd를 사용하고, 다른 RAMDISC에 새로운 /dev를 만든 후, 마지막으로 non-Unix 루트 파일시스템으로 바꾸는 것이다 이것은 영리한 부트스크립트와 헛점이 많고 복잡한 부트 과정이 필요하다.
Devfs는 튼튼하고 개념적으로 간단한 방법으로 이 것을 해결한다.
PTY 보안
현재의 pseudo-tty(pty)는 루트가 소유권자이고, 모든 사용자에게 읽고 쓰기가 가능하다. pty-pair의 사용자는 suid-root 없이는 소유권/보호권을 바꿀수 없다.
이 문제는 루트로 수행되고 실제 pty-pairs를 만들어 내는 보안 사용자공간 데몬을 사용함으로써 해결될 수 있다. 이 같은 데몬은 이런 새로운 매커니즘을 사용하고자 하는 "모든" 프로그램에 수정을 요한다. 또한 pty-pairs를 생성하는데도 속도저하가 일어난다.
다른 해결책은 사용자공간의 데몬과 많은 부분 같은 일을 하는 새로운 open_pty() 시스템콜을 만드는 것이다. 다시 한번 말하지만, 이것은 pty 핸들링 프로그램들의 수정을 요구한다.
devfs 의 해결책은 열려있지 않은 디바이스가 열렸을때 디바이스 드라이버가 어떤 디바이스 파일을 "tag"하도록 허용하고, 소유권은 열린 프로세스의 현재 euid와 egid로 변화되고, 보호권은 그 드라이버에 의해 등록된 기본값으로 변경된다. 그 디바이스가 닫히면, 소유권은 루트로 돌아가고 보호권은 모든 이에게 읽고쓰기 가능으로 바뀐다. 어떤 프로그램도 수정될 필요가 없다. devpts 파일시스템은 Unix98 ptys에 대하여 이러한 자동-소유권의 기능을 제공한다. 이것은 옛방식의 pty 디바이스는 지원하지 않고, devfs가 제공하는 다른 기능들을 모두 제공하지 않는다.
Intelligent device 유지
Devfs는 사용자 공간에서 디바이스 관리 데몬(devfsd)와 통신을 위하여 간단하지만 강력한 프로토콜을 구현한다. 이것은 디바이싀 엔트리의 등록/등록해제, 디바이스의 열림/닫기, inode의 탬색 디렉토리와 다른 것들의 탐색 등과 같은 어떤 이벤트가 일어나면 (동기 또는 비동기적으로) devfsd에 메세지를 보내는 것이 가능하다. 이것은 많은 잠재성을 가지게 된다. 그 잠재성 중의 어떤 것은 이미 구현되어 있다. http://www.atnf.csiro.au/~rgooch/linux/을 살펴보라
디바이스 엔트리의 등록이벤트는 새롭게 생성되는 디바이스 노드의 퍼미션을 변경할때 devfsd에 의해 사용될 수 있다. 이것은 디바이스의 퍼미션을 제어하기 위한 하나의 매커니즘이다.
디바이스 엔트리의 등록/등록해제 이벤트는 프로그램이나 스크립트를 구동시키는데 사용된다. 이것은 새로운 블럭 디바이스 미디어에 드라이버가 추가되었을때 파일시스템의 자동적인 마운트를 제공하는데 사용될 수 있다.
비동기 디바이스의 열림/닫힘 이벤트는 퍼미션 관리를 구현하는데 사용될 수 있다. 예를 들어, /dev/dsp에 대한 기본 퍼미션은 모든 사용자가 그 디바이스를 읽는 것을 허용하지 않는다. 이것은 당신의 콘솔에 얘기하는 것을 원격 사용자가 녹음하는 것을 원하지 않을 것이기 때문에 합당한 일이다. 그러나, 콘솔 사용자 역시 녹음하는 것이 막혀있다. 이것은 바람직한 것이 아니다. 비동기 디바이스에 열림/닫힘 이벤트를 이용하여 당신은 콘솔디바이스가 *다른* 디바이스노드(예를 들어 /dev/dsp)에 대한 소유권을 변경하기 위해 열렸을때, devfsd가 어떤 프로그램이나 스크립트를 수행하도록 할 수 있다. 마지막으로, 당신은 다른 스크립트를 이용하여 퍼미션을 복구 할 수 있다. C 라이브러리의 tty 핸들링의 수정이 필요없는 이런 설계의 이득은 당신의 프로그램이 충돌이 일어나더라도 (당신은 존재하지 않은 로긴을 위하여 지체되는 엔트리를 가지는 utmp 데이터 베이스를 수없이 보아오지 않았는가?) 작동한다는 것이다.
동기 디바이스의 열기 이벤트는 디바이스가 접근권한을 설정하는데 사용될 수 있다. 디바이스 드라이브의 open() 메소드가 호출되기 전에, 데몬은 외부 프로그램이나 스크립트를 실행시킴으로써 처음으로 열기시도를 확인할 것이다. 이것은 그에 대한 접근 자체가 UID와 GID 대신에 다른 시스템의 상태에 기초하여 결정되기 때문에 제어리시트를 사용하는 것보다 훨씬 더 유연하다.
Inode 탐색 이벤트는 모듈의 자동로드 요청을 인증하는데 사용될 수 있다. kmod를 직접적으로 사용하는 대신에, 이 이벤트는 모듈 스스로가 적재되기 전에 임의적으로 인증을 구현할수 있는 devfsd에 보내진다.
Inode 탐색 이벤트는 존재하지 않는 디바이스에 대하여 심링크로 devfs를 위치시키기 위해 복구하지 않고도 임시로 네임스페이스를 구성하는데 역시 쓰일수 있다.
이론적인 디바이스 탐색
모듈이 올라와 있던 아니던 시스템에 있는 모든(SCSI, IDE 및 다른 타입들) CD-ROM 디바이스를 찾기 위한(cdparanoia와 같은) 어플리케이션을 고려해보자. 이론적으로 어플리케이션은 해당 모듈이 적재되어 있는지 확인하기 위해서는 디바이스 노드를(SCSI CD-ROM의 경우 /dev/sr0) 열어야만 한다. 표준 디바이스 네이밍 스키마(최근에 레드햇은 이것을 다르게 구현한 것을 확인했다)를 따르는 모든 리눅스 배포판은 이러한 작업을 필요로 한다. Devfs는 그러한 네이밍 문제를 해결한다.
그와 같은 어플리케이션은 또 시스템에 실제 사용가능한 디바이스를 찾기를 원할 수도 있다. 현존하는 시스템으로 이같은 일은 /dev 디렉토리를 읽고, 그 디바이스가 존재하는지 안하는지를 결정하기 위해서는 각 /dev/sr* 디바이스들을 열어봐야 한다. 큰 /dev를 가지는 시스템에서, 그 시스템이 특히 많은 수의 /dev/sr* 노드를 가지고 있다면, 이것은 비효율적인 작업이다. scsidev와 같은 해결책은 /dev/sr* 엔트리의 수를 줄여줄수 있다(그러나 역시 불필요한 디렉토리 탐색은 필요하다).
Devfs를 사용하면, 그 어플리케이션은 /dev/sr 디렉토리(필요하다면 모듈의 자동적재를 유도해내는)를 읽을수 있고, /dev/sr를 읽기 위하여 계속 진행된다. 오직 사용가능한 디바이스들만이 엔트리를 가지므로, 불필요한 디렉토리 탐색이나, 디바이스의 오프닝은 필요없다.

--------------------------------------------------------------------------------
누가 이 일을 하는가?
FreeBSD는 devfs를 구현한다. 솔라리스와 AIX 역시 pseudo-devfs(scsi와는 비슷하지만 비명시적인 커널 지원과 함께 모든 디바이스를 지원하는)를 가지고 있다. BeOS, Plan9와 QNX 역시 이것을 가지고 있다. SGI의 IRIX 6.4 이상의 것 역시 디바이스 파일시스템을 가지고 있다.
우리는 다른 사람들이 하기 때문에 자동적으로(의무적으로) 이것을 할 필요는 없지만, 다른 사람의 작업을 무시해서도 안된다. FreeBSD 는 이 작업을 하는데 있어 수많은 개발자를 소유하고 있고, 따라서 그들의 의견은 간단하게 무시되어서는 안된다.

--------------------------------------------------------------------------------
어떻게 작동하나?
디바이스 엔트리를 등록하기
devfs에 기초한 /dev 안에서 각 엔트리(디바이스노드)에 대해 드라이버는 devfs_register()를 호출해야만 한다. 이것은 내부 테이블에 디바이스 엠트리의 이름과 file_operation structure 포인터와 약간의 다른 것들을 추가한다. 디바이스 엔트리는 어떤 때라도 추가되거나 제거될 수 있을 것이다. 디바이스 엔트리가 등록되면, devfs가 마운트된 곳에 자동으로 나타난다.
Inode 탐색
엔트리에 대한 탐색이 수행되고 만약 그 엔트리에 대한 어떠한 드라이버 정보도 없을때 devfs는 devfsd의 호출을 시도한다. 만약 어떠한 정보도 찾아지지 않는다면, negative dentry가 얻어지고, 다음 단계의 수행은 VFS(create() 또는 mknod() inode 메쏘드 와 같은)에 의해 호출될 것이다. 드라이버의 정보가 찾아지면 inode는 생성될 것이고(미리 존재하는 것이 없다면) 그것으로 잘 될 것이다.
직접 device노드를 만들기
mknod() 메쏘드는 사용자에게 devfs 안에 고유하게 이름붙여진 파이프를 만들도록 허용하거나, 이미 존재하지 않는다면 블럭 스페셜 inode를 만들수 있도록 허용한다. 사용자는 사용자 스스로 퍼미션과 소유권을 설정할 수 있는 캐릭터나 블럭 스페셜 inode를 생성하기를 원할 수도 있다. 나중에, 만약 디바이스 드라이버가 같은 이름으로 엔트리를 등록한다면, 그 퍼미션과 소유권과 시간은 계속 유지된다. 이것은 그 드라이버가 적재되기 전이라도 디바이스에 대한 보호권을 설정할 수 있도록 한다. 한번이라도 inode를 만들었다면 디렉토리에 나타난다.
다비이스 엔트리의 등록해제
디바이스 드라이버는 엔트리를 등록해제하기 위해서 devfs_unregister()를 호출한다.
Chroot()의 제한들
2.2.x대의 커널들
inode 생성의 의미는 devfs가 "특별한" 옵션과 함께 마운트 되었을때는 다르다. 지금, 디바이스 엔트리가 등록되었을때, 그 디바시으를 생성하기 위해 mknod()를 사용하기 전까지는 나타나지 않을 것이다. mknod()가 devfs_register()를 사용하여 그 디바이스가 되기 전이던 중요하지 않다. 이런 작업의 목적은 당신이 그 제한안에 최소한의 devfs를 마운트 하기 원하는 곳에서 chroot(2)의 제한을 지원하는 것이다. 단지 당신이 특별히 사용가능하도록 설정하는(당신만의 mknod() 설정을 통하여) 디바이스만이 접근 가능하게 될 것이다.
2.4.x 대의 커널들
현재의 2.3.99 커널은 VFS가 전체 파일시스템의 네임스페이스의 한 부분을 그 네임스페이스의 다른 부분으로 리바인드 시킬수 있다. 이것은 심지어 leaf-node 레벨에서도 작동하며, 각각의 파일들과 디바이스 노드가 그 네임스페이스의 다른 부분으로 바인드 될수 있다는 것을 의미한다. 이것은 링크를 만드는 것과 유사하지만, 파일시스템(하드 링크와는 다른)과 chroot() 의 제한(심볼릭 링크와 다른)을 통하여 작동하기 때문에 더 낫다.
VFS에서의 이런 향상 덕분에, devfs에서 다중 마운트에 대한 기능은 더이상 필요하지 않다. 관리자는 VFS 바인딩을 사용하여 chroot(2) 제한 안에 최소한의 디바이스 트리를 만들게 된다. 이것은 devfs의 다중마운트 능력이 가진 대부분의 기능을 제공하기 때문에, 나는(저자는) 다중 마운트 코드를 (RFC 에서의 논의 후에) 빼버렸다. 이것은 코드크기의 감소와 간소함을 가져다 주었다.
만약 최소한의 chroot() 제한을 만들기 원한다면, 다음의 명령어를 치면 된다.
mount --bind /dev/null /gaol/dev/null
보여주기 원하는 다른 디바이스 노드에도 반복하라. 간단하다!
--------------------------------------------------------------------------------
운영상의 문제점
참을성 없는 이들을 위한 소개
문서읽기를 좋아하는 사람은 없다. 사람들은 바로 얻고 수행하기를 원한다. 따라서 이번 부분에서는 빠르게 /dev 상에 devfs를 마운트 하여 수행하는데 있어 필요한 단계 를 설명할 것이다. 이번 단계를 건너뛰어라. 그러면 당신은 거의 부팅할수 없는 시스템을 가진채 끝날 것이다. 아래의 부분들은 좀더 자세한 부분에 대해 설명하고 있고, 필수적이지 않은 설정옵션에 대해 논의할 것이다.
Devfsd
OK, 당신이 이부분을 읽고 있다면, 나는 당신이 devfs를 사용하기를 원한다고 생각할 것이다. 첫번째로 당신은 /usr/src/linux에 최신의 커널소스를 포함하고 있는지 확실하게 해야한다. 그리고 디바이스 관리 데몬인 devfsd를 컴파일 할 필요가 있다. 이것은 http://www.atnf.csiro.au/~rgooch/linux/ 에서 얻을수 있다. 그 커널은 옛 버전의 네이밍 스키마와는 상당히 다른 네이밍 스키마를 가지기 때문에 예전의 네이밍 스키마가 깨지지 않고 계속 사용할 수 있도록하는 소프트웨어와 설정파일인 devfsd를 설치할 필요가 있다.
devfsd를 컴파일 하고 설치하라. 당신은 예전 네이밍 스키마에 대하여 호환성을 가지는 심링크를 제공하는 기본 설정파일인 /etc/devfsd.conf를 제공받을 것이다. 충분한 지식을 얻기 전까지 이 파일을 수정하지 말라. 충분한 지식을 가지고 있다고 생각한다 할지라도, 아래에서 부팅된 devfs가 가능한 시스템과 이것이 제대로 작동하는지에 대해 검증이 끝날때까지 수정하지 말라.
이제 devfsd가 가장 처음(파일시스템의 체크가 일어나기 전에)에 시작되도록 메인 시스템의 부트 스크립트를 수정해야 한다. 가금 /etc/rc.d/rc.sysinit이 SysV 형식의 부트 스크립트와 함께 시스템에서 메인 부트 스크립트로 사용된다. BSD 형식의 부트 스크립트를 가지는 시스템에서는 /etc/rc 도 사용된다. /sbin/rc도 체크해보라.
Note 부트 스크립트에 넣어야 될 줄은 정확하게 다음과 같아야 함을 명심하라
/sbin/devfsd /devDO NOT 어떠한 데몬 실행 프로그램도 사용하지 말라. 그렇지 않으면 부트스크립트는 devfsd가 초기화하는 것을 기다려주지 않는다.
시스템 라이브러리들
잘못된 소프트웨어가 디바이스 네임에 대해 가정하기 때문에 일어나는 문제점들이 있다. 자세하게 말하면, 어떤 소프트웨어는 심볼릭 링크로 된 디바이스를 사용하지 못한다. 만약 libc5 를 사용하는 시스템을 사용하고 있다면, libc5.4.44를 설치해라(만약 libc5.4.46을 사용하고 있다면 올바르게 작동하는 libc5.4.44로 다운그레이드하라). 만약 glibc에 기초한 시스템을 사용한다면 glibc 2.1.3 이상인지 확인해야 한다.
/etc/securetty
PAM(Pluggable Authentication Modules)은 더 나은 사용자 인증과 서비스를 제공하기 때문에 유연한 메커니즘으로 평가받고 있다. 불행하게도, 그것은 깨지기 쉽고, 복잡하고 문서화 되어 있지 않다(레드햇 6.1과 다른 배포판을 확인해보라). PAM은 심볼릭링크와는 문제를 일으킨다. 다음의 줄을 /etc/securetty 파일에 추가시켜라.
vc/1
vc/2
vc/3
vc/4
vc/5
vc/6
vc/7
vc/8
이것은 보안을 약화시키지 않을 것이다. 만약 2.10.h 이전의 util-linux 버전을 사용하고 있다면 그 이후의 버전으로 업그레이를 하기 바란다. 만약 업그레이드 할 수 없다면, 다음의 줄을 /etc/securetty 파일에 추가하라.
1
2
3
4
5
6
7
8
이것은 네트워크를 통한 루트의 로그인을 허용하기 때문에(패스워드는 요구된다) 보안을 약화시킨다. 그러나, 심링크를 취급하는데 있어서 문제가 있기 때문에, 나는 어떤 경우에라도 제공되는 보안레벨에 의심을 가지고 있다.(역자 주:PAM이 심링크에 문제점을 보이기 때문에, 어차피 보안에는 문제점이 있다는 말.)
Xfree86
필수적이지는 않지만, 좀더 devfs에 밀접하도록 하는 패치의 일환으로 XFree86 4.0으로 업그레이드 하는 것은 좋은 생각이다. 만약 그렇게 하지 않는다면, 일반 사용자가 startx를 할수 있도록 /etc/security/console.perms에 다음의 패치를 적용해야 할 것이다. 모든 배포판이 이 파일을 가지고 있는 것은 아니므로(e.g. 데비안) 이것이 존재하지 않는다고 해도 걱정할 필요는 없다.
--- /etc/security/console.perms.orig    Sat Apr 17 16:26:47 1999
+++ /etc/security/console.perms Fri Feb 25 23:53:55 2000
@@ -14,7 +14,7 @@
# man 5 console.perms
# file classes -- 이것은 정규표현식이다.
-<console>=tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9]
+<console>=tty[0-9][0-9]* vc/[0-9][0-9]* :[0-9]\.[0-9] :[0-9]
# device classes -- these are shell-style globs
<floppy>=/dev/fd[0-1]*
만약 패치가 적용되지 않는다면, 다음과 같이 변경하라.:
<console>=tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9]을
<console>=tty[0-9][0-9]* vc/[0-9][0-9]* :[0-9]\.[0-9] :[0-9] 으로 수정하라.
devpts를 중지시키기
나는 /dev/pts에 마운트된 devpts가 제대로 작동하지 않는다는 보고를 받았다. devfs는 /dev/pts를 관리하므로, 더 이상 devpts를 마운트할 필요는 없다. /etc/fstab파일을 수정해서 마운트되지 않도록 하거나, 커널 설정에서 devpts를 사용하지 않도록 하라.
지원되지 않는 드라이버
모든 드라이버가 devfs를 지원하지는 않는다. 만약 이러한 드라이버 중에 하나를 가지고 있다면, 적당한 때에 디바이스 노드를 생성하도록 부팅시에 사용할 수 있는 스크립트나 tarfile를 작성하는 것이 필요할 것이다. section 는 이부분을 설명하고 있다.section 는 devfs를 지원하는 드라이버들의 목록이다.
/dev/mouse
많은 배포판들이 XFree86과 GPM의 마우스 디바이스를 /dev/mouse로 설정한다. 나는 이것을 원래와 다르게 우회해서 추가하기 때문에 좋지 못한 생각이라고 생각한다. 만약 당신이 설정파일에서 살펴볼 때, /dev/mouse를 보게 된다면 마우스가 참조된 곳이 어디인지 궁금하게 여길 것이다. 따라서 나는 /etcX11/XF86Cnfig파일(그리고 GPM 설정 파일)에 실제 마우스 디바이스(예를 들어,/dev/psaux와 같은)를 기입하는 것을 추천한다.
다른 방법으로는 위에 설명된 지원되지 않는 드라이버를 위한 테크닉을 사용해도 된다.
커널
마지막으로, devfs가 커널에에서 컴파일 되도록 해야 한다. 가장 좋아하는 커널 설정툴(예를 들면, make config 또는 make xconfig)을 사용하여 CONFIG_EXPERIMENTAL=y, CONFIG_DEVFS_FS=y 그리고 CONFIG_DEVFS_MOUNT=y 로 설정하고 make dep;make clean 하고 커널과 모듈을 재컴파일 하라. 부팅시에 devfs가 /dev 에 마운트 될 것이다.
만약 부팅시에 문제(예를 들어, 설정 단계를 잊었다던지 하는)가 발생한다면, 커널 부트 커맨드 라인에 devfs=nomount를 넣고 통과할 수 있다. 이것은 커널이 부팅시에 devfs를 /dev에 마운팅 하는 것을 막아준다. /proc/partitions, irrespective of whether devfs is mounted.
일반적으로 CONFIG_DEVFS_FS=y로했지만 /dev에 마운트되지 않도록 만들어진 커널은 안전하다, 또한 설정의 변경도 필요없다. 주의를 기울여야 할 한가지 예외는 LABEL= 지시자가 /etc/fstab에 사용되었을 때이다. 이런 경우에는 정상적으로 부팅할 수 없을 것이다. 이것은 mount(8) 프로그램이 그 볼륨 레이블을 찾는 과정의 일부분으로 /proc/partitions를 사용하고, 찾은 디바이스 이름이 CONFIG_DEVFS_FS=y로 설정하는 것이 /proc/partitions에서 그 이름을 변경시키고, devfs가 마운트 되었는지 상관하지 않기 때문에 사용불가능하게 되기 때문이다.
이제 필요한 모든 단계를 끝냈다. 이제 당신의 빛나는:-) 새로운 커널을 부팅할 준비가 되었다. 즐겨보라.
설정파일 변경하기
OK, 이제 devfs가 사용가능한 시스템을 부팅시켰고, 모든 것이 제대로 작동한다. 이제 설정파일을 변경시킬 필요를 느낄 것이다(일반적으로 설정대상은 /etc/fstab와 /etc/devfsd.conf이다). 제대로 작동하는 시스템을 갖고 있기 때문에, 설정을 변경하고나서 제대로 작동하지 않더라도, 디폴트로 설정파일을 복구하면 잘 작동한다는 것을 알 수 있다.
리부팅 후의 퍼미션 유지
만약 디바이스 파일을 생성하기 위하여 mknod(2)를 사용하지 않고 소유권/퍼미션을 변경하기 위해 chmod(2) 또는 chown(2)을 사용하지 않는다면 inode의 ctime는 0(12 am, 1-JAN-1970, GMT)으로 남겨질 것이다. 이후의 ctime을 가지는 것들은 소유권/퍼미션의 변화가 있을 것이다. 따라서, 간단한 스크립트 또는 프로그램을 사용하여 셧다운하기 전에 모든 변경된 inode들을 묶는데 사용한다. 효과적이긴 하지만 이것을 적용하기 위해서는 많은 고려사항이 있다.
더 나은 접근방법은 퍼미션을 저장하고 북구하는데 devfsd를 사용하는 것이다. 이것은 퍼미션에서의 변경을 기록하기 위해서 설정되고, 데이타베이스(실제로는 디렉토리 트리)에 저장하고, 부팅시에 복구할 것이다. 이것은 현재의 퍼미션을 저장하는데 있어서 효율적인 방법이며 효과적인 결과를 보여준다(알수 없는 미래의 시간에 퍼미션을 저장하는 tar 의 접근과는 다르게)
devsd에 제공되는 기본설정파일은 지속적인 관리가 가능하도록 하기 위해 주석이 달아진 설정부분을 가지고 있다.
만약 어떤 방법으로던 tar 접근을 사용하기로 결정했다면, tar은 새로운 디바이스 노드를 생성하기 전에 먼저 inode를 unlink(2)할 것이라는 것을 주의하라. unlink(2)는 devfs 엔트리와 디바이스 드라이버 사이의 연결을 끊어버리는 효과를 가진다. 만약 부팅 옵션에서 "devfs=only"를 사용하고 있다면, 모듈을 적재하기 위해 필요한 디바이스 드라이버에 대한 통로를 잃게 된다. 나는 이것을 tar의 버그라고 생각하고 있다(실제로 tar가 inode를 먼저 unlink(2)할 필요는 없다)
다른 방법으로는, 디바이스의 좀더 철학적인 퍼미션 관리를 제공하기 위하여 devfsd를 사용할 수도 있다. 당신은 디바이스당 하나의 엔트리를 할당하는 진부한 방법보다, 하나의 설정을 통하여 모든 디바이스 그룹에 대하여 퍼미션을 저장할 수 있다.
/dev에 마운트된 퍼미션 데이타베이스의 저장
만약 devfs가 /dev에 마운트 된채로 disc-baed /dev에 디바이스의 퍼미션을 저장하거나 복구하기를 원한다면 그렇게 할 수도 있다. 이것은 2.4.x 커널(실제로는, 2.3.99 이후)의 VFS 바인딩 기능을 필요로 한다. 이 기능을 설정하기 위해서는 아래와 같이 하라:
부팅시에 devfs가 마운트 되지 않도록하라
/dev-state디렉토리를 만들어라
부트 스크립트의 앞부분에 다음의 줄을 추가하라
mount --bind /dev /dev-state
mount -t devfs none /dev
devfsd /dev
/etc/devfsd.conf에 다음을 추가하라:
REGISTER ^pt[sy]/.* IGNORE
CHANGE  ^pt[sy]/.* IGNORE
REGISTER .*  COPY /dev-state/$devname $devpath
CHANGE  .*  COPY $devpath /dev-state/$devname
CREATE  .*  COPY $devpath /dev-state/$devname
리붓.
일반 디렉토리에 퍼미션 데이트베이스 복구하기
만약 VFS 바인딩을 지원하지 않는 오래된 커널을 사용중이라면, /dev에 마운트되어 있는 퍼미션 데이타베이스를 가져올 수 없을 것이다. 그러나 그 데이타베이스를 복구하기 위하여 일반 디렉토리를 만들 수 있다. 위의 /etc/devfsd.conf파일은 여전히 사용가능 할 것이다. 당신은 devfsd를 인스톨 하기에 앞서 /dev-state디렉토리를 만들어야 한다. 만약 /dev에 예전의 퍼미션을 가지고 있다면, 새로운 디렉토리에 디바이스 노드들을 카피(또는 move)하면 된다.
더 나은 방법
가장 좋은 방법은 /dev에 마운트되어 있는 퍼미션의 데이터베이스를 가져오는 것이다. 그 이유는 디바이스 노드드를 /dev-state에 복사할 필요가 없고, /dev-state(devfs를 위한) 과 /dev/(devfs를 사용하지 않을 경우에) 사이에 퍼미션을 복사할 필요가 없이 devfs와 devfs를 사용하지 않는 커널을 바꿀 수 있기 때문이다.
devfs의 지원없이 드라이버를 취급하기
현재, 커널에서 모든 드라이버들이 devfs를 사용하도록 수정되지는 않았다. 여전히 devfs가 지원되지 않는 디바이스 드라이버들은 자동으로 devfs에 나타나지 않을 것이다. 이러한 드라이버들에 대한 디바이스를 생성하는 가장 간단한 방법은 필요한 디바이스 노드들을 포함하고 있는 tarfile을 푸는 것이다. 이것을 부트 스크립트에 넣어도 된다. 이제 당신의 모든 드라이버들은 전처럼 작동할 것이다.
고무적이게도 대부분의 사람들에게 devfs는 대부분의 기능을 잃지 않고(예를 들어 다양한 디바이스에 대한 접근 상실) /dev 위에 devfs디렉토리를 마운트 할 수 있는 충분한 지원을 한다. 22-JAN-1998 이후(devfs 패치 버전 10)부터 나는(저자는) 이 방법(devfs)를 운영하고 있다. 내가 가지고 있는 모든 디바이스들은 devfs에 나타나므로 나는 아무것도 잃은 것이 없다.
경고: 만약 당신의 설정이 예전방식의 디바이스 이름(예를 들어 /dev/hda1, /dev/sda1)을 필요로 한다면, 호환엔트리를 유지하도록 devfsd를 설치하고 설정해야 한다. 당신이 이것을 필요로 할 것이라는 것은 거의 확실하다. 커널이 루트 디바이스에 대해 호환항목을 생성하기 때문에 initrd를 필요로 하지 않는다는 것을 기억하라.
만약 Unix98 PTYs를 사용하기 있다면 devfs 가 /dev/pts를 관리할 수 있기 때문에 더 이상 devpts를 마운트할 필요가 없다는 것을 기억하라. 이것은 devpts를 컴파일 하고 설치할 필요가 없기 때문에, 약간의 램을 절약한다. glibc의 어떤 버전은 devfs 시스템에서 Unix98 pty를 취급하는데 버그를 가지고 있다는 것을 명심하라. 수정을 위해서는 glibc 메인테이너와 연락하라. Glibc 2.1.3 은 수정되었다.
만약 devfsd를 설치하지 않았다면 /etc/fstab를 수정하는 것에서부터 다른 것들도 수정해야 한다는 것을 명심하라. (X 서버와 같은) 어떤 소프트웨어는 그 소스에 디바이스 이름을 고정시켜 놓는다. 실제로 호환 엔트리를 생성하는데 devfsd를 사용하는 것이 훨씬 쉽다. 당신은 당신의 시스템을 devfsd가 호환항목을 생성하도록 제한하면서 서서히 새로운 디바이스 이름(예를 들어, /etc/fstab부터 시작하여)을 사용하도록 할수 있다.
DEVFS가 가능한 커널을 부팅하기 전에 DEVFSD를 설치하였는지 확인하라!!
devfs가 2.3.46 커널에 들어갔을 당시, 나는 수많은 보고를 받았다. 대부분의 보고들은 사람들이 devfsd 없이 운영했기 때문이었고, 그 중에 어떤 것들이 깨졌다(사용할 수 없는 시스템이 되었다). 나는 순간적인 설정잘못으로 인한 버그보다 실제 버그에 전념하기를 원한다. 만약 다른 코드(예를 들어 glibc, X server)에서 버그/오류를 수정해야 한다고 느낀다면, 그 메인테이너들에게 확인하라. 그들은 (나보다) 훌륭하게 해결할 것이다.
Devfs 의 방법
devfs의 커널패치는 합리적인 디바이스 트리를 생성한다. 위에 기술된대로, 만약 예전 방식의 /dev 네이밍 스키마를 유지하기 원한다면, 적당하게(맨 페이지에서 보는대로) devfsd를 설정하면 된다. 예전 방식을 선호하는 사람들은 이번 섹션을 건너뛰어라. 체계화된 이름과 명확한 /dev를 좋아하는 사람들은 읽어보길 바란다.
만약 devfsd를 실행하지 않았다면, 호환 엔트리의 관리를 할수 없고, 새로운 이름을 사용하기 위해서는 당신의 시스템을 설정해야 할 것이다. 예를 들어, 새로운 디스크의 네이밍 스키마를 사용하기 위해서 /etc/fstab를 수정해야 할 것이다. 만약 devfs를 사용하지 않는 커널을 부팅하시기 원한다면, devfs없이 커널을 부팅했을때를 위하여 예전 방식의 이름으로 돌아갈 disc-based /dev에 기초한 호환 심링크가 필요할 것이다.
당신은 호환엔트리를 유지할 디바이스를 선택할 수 있다. 예를 들어, BSD pseudo-terminal 디바이스에 대한 호환 엔트리를 원할 수도 있다(그렇지 않으면 C 라이브러리를 패치하거나, 대신에 Unix98 ptys를 사용해야 할 것이다). 이것은 /dev/devfsd.conf에 정확한 정규표현식을 넣으면 되는 일이다.
당신이 선호하는 다른 네이밍 스키마를 선택할 수 있다. 예를 들어, 나는 너무 수직적이기 때문에 커널 제공 이름를 사용하지 않는다. 일반적인 잘못된 생각은 커널이 제공하는 이름들은 설정파일에 직접적으로 사용되어야 한다 것이다. 이것은 그런게 아니다. 그것들은 장착된 디바이스들의 래이아웃을 반영하고 쉽게 분류하기 위하여 디자인된 것이다.
만약 커널이 제공하는 이름을 좋아한다면, 그것으로 좋다. 만약 그렇지 않다면, 당신이 좀더 선호하는 네임스페이스를 생성하기 위하여 devfsd를 사용해야 할 것이다. Devfsd는 논리적이고 관리하기 쉽도록 하는 네임스페이스를 생성하기 위한 코드를 포함하고 있다. 근본적으로는 , 커널이 제공하는 네임스페이스의 생략형을 생성한다.
당신은 자신만의 네임스페이스를 만들기 위한 과정에 있다. Devfsd는 당신이 이일을 쉽게 하도록 하는데 필요한 모든 기반을 가지고 있다. 필요한 일은 스크립트를 만드는 것이다. 심지어 C코드를 작성할 수도 있으며 devfsd는 호출가능한 확장으로 그 공유 오브젝트를 적재할 수 있다.
다른 논점
init 프로그램
저의를 기울여야 할 다른 점은 init프로그램이 /dev/telinit 유닉스 소켓을 생성하는지에 대한 것이다. init의 어떤 버전은 /dev/telinit를 생성하고 telinit프로그램은 init 프로세스와 통신한다. 만약 이런 시스템을 가지고 있다면, init 가 시작되기 *전에* devfs가 /dev에 마운트되도록 해야 한다. 다른 말로 하면, init후에 수행되는 /etc/rc에는 devfs를 마운트 하도록 넣어서는 안된다.init의 다른 버전들은 init가 시작하기 *전에* 존재해야만 하는 named pipe /dev/initctl가 필요하다. 다시말하지만 init가 시작되기 *전에* 그 named pipe를 생성하고 devfs를 마운트해야 한다.
기본적인 행동은 2.3.x 이후의 커널이 부팅할때에는 /dev에 devfs를 마운트 하지 않는 것이다. 이것은 부팅 옵션에 "devfs=mount"를 넣음으로써 고칠 수 있다. 이 문제는 init의 문제를 해결하고, 다음의 끔찍한 상황(
Cannot open initial console메세지)을 막아준다. devfs 패치가 적용되어야 하는 2.2.x의 커널에서는 기본적으로 마운트 한다.
만약 /dev에 devfs를 자동으로 마운트한다면, 부트 스크립트에서 /dev/initctl를 생성하도록 해야 한다. 다음의 줄을 추가하라:
mknod /dev/initctl p
kill -SIGUSR1 1  # /dev/initctl이 현재 존재하는지를 init에 알려줌
다른 방법으로는, 커널이 /dev에 devfs를 마운트 하기를 원치 않는다면, /dev/initctl문제를 해결하기 위하여 다음의 프로시져를 사용할 수 수 있다:
# cd /sbin
# mv init init.real
# cat > init
#! /bin/sh
mount -n -t devfs none /dev
mknod /dev/initctl p
exec /sbin/init.real $*
[control-D]
# chmod a+x init
init의 최신 버전은 /dev/initctl를 자동으로 생성하므로, 이것에 대해서 걱정할 필요가 없다는 것을 기억하라.
모듈 자동로딩
모듈의 자동로딩을 하기 위해서는 devfsd를 설정할 필요가 있다. 다음의 줄을 /etc/devfsd.conf파일에 추가시켜라:
LOOKUP .* MODLOAD
devfsd-v1.3.10 이후로, MODLOAD에 의해 사용되는 포괄적인 /etc/modules.devfs 설정 파일이 설치된다. 이것은 대부분의 설정들에 대해 충분하다. 만약 설정이 더 필요하다면, /etc/modules.conf파일을 수정하라. devfs가 모듈의 자동로딩을 하는 방법은 :
프로세스가 디바이스 노드의 탐색시도를 한다(e.g. /dev/fred)
만약 디바이스 노드가 존재하지 않으면, 전체경로가 문자열로 devfsd에 넘겨진다.
devfsd는 modprobe 프로그램(위에서 보여진 설정 라인이 존재하는)에 그 문자열을 전해주고, 그 설정파일인 /etc/modules.devfs에 명시한다.
/etc/modules.devfs는 로컬 설정에 접근하기 위해 /etc/modules.conf을 포함한다.
modprobe는 그 경로를 모듈이름으로 변환하는 앨리어스를 탐색함으로써 그것의 설정파일을 찾을 것이다.
변환된 경로는 그 모듈을 로딩하는데 사용된다.
만약 mymod모듈을 로딩하기 위하여 /dev/fred를 탐색하기 원한다면, /etc/modules.conf에 다음의 줄을 추가하라:
alias /dev/fred mymod
그 /etc/modules.devfs 서정 파일은 표준 디바이스 이름에 대해서 각각의 앨리어스를 제공한다. 만약 이 파일을 자세하게 찾는다면, 어떤 모듈은 여러개의 앨리어스 설정 줄이 필요하다는 것을 알것이다. 그것은 엣 방시과 새로운 방식의 디바이스 이름에 대해 모듈 자동로딩을 지원하기 위해 필요하다.
devfs 디바이스에 root를 마운트하기
만약 "devfs=only" 부트 옵션을 설정했을때 devfs 디바이스가 root를 마운트 하기를 원한다면, 부팅시 커널옵션에 "root=<device>" 옵션을 넣어야 한다. LILO를 사용한다면, lilo.conf에 이것을 가지고 있어야만 한다:
append = "root=>device>"
놀라운가? 옙, 나 역시 그렇다. 다음의 줄을 당신이 가지고 있다면(대부분의 사람들이 그런 것처럼) 해결한다:
root = <device>
LILO는 <device>의 디바이스 번호를 결정할 것이고, 그커널을 시작하게 전에 커널 이미지의 특정 부분에 그 번호를 기록할 것이며, 그 커널은 루트 파일시스템을 마운트 하기 위하여 그 디바이스 번호를 사용할 것이다. 그래서, "append" 변수를 사용하는 것은 LILO가 그 루트 파일시스템을 devfs가 사용할 수 있는 문자열로 넘겨 주도록 확실히 하는 것이다.
만약 "devfs=only"를 사용하지 않는다면 신경쓸 것 없다.
TTY 문제
C 라이브러리의 어떤 버전에서는 ttyname(3)가 심볼릭 링크인 디바이스 엔트리에 대해서는 오류를 만들어낸다. tty(1) 프로그램은 이 함수에 의존한다. 나는 이것을 수정하기 위하여 libc 5.4.43에 패치를 만들었다. 이것은 libc 5.4.44에 포함되어 있고 비슷핸 패치가 glibc 2.1.4에 있다.
커널 네이밍 스키마
커널은 기본 네이밍 스키마를 제공한다. 이 스키마는 특정한 디바이스나 디바이스 형태에 따라 검색하고, 사용가능한 디바이스를 찾아보는데 쉽도록 디자인 된다. 어떤 디바이스 형태(하드 디스크 같은)는 그런 부류의 디바이스가 사용가능한가를 알아보기 쉽게 하기 위해 그 항목의 디렉토리를 가지고 있다. 종종, 그 항목들은 사용가능한 디바이스의 구조를 반영하기 위한 디렉토리 트리에 심볼릭 링크로 되어 있다. 기하학적인 트리는 당신의 디바이스가 어떻게 배열되어 있는지 보는데 유용하다.
아래는 대부분의 일반적인 드라이버들에 대한 네이밍 스키마의 목록이다. 예약된 디바이스 이름들의 목록은 참고가 가능하다. 그 목록에 추가되기 원한다면 rgooch@atnf.csiro.au에 메일을 보내라. 다른 이름들도 그 메인테이너의 판단에 따라 요청된 이름대신 할당될 수 있다.
디스크 디바이스들
SCSI, IDE 또는 무엇이라도, 모든 디스크는 /dev/discs 아래에 위차한다.
 /dev/discs/disc0 first disc
 /dev/discs/disc1 second disc
이들 각 항목들마다 그 디바이스에 대하여 디렉토리에 심볼릭 링크가 걸려있다. 디바이스 디렉토리는 다음을 포함한다.
 disc 전체 디스크에 대하여
 part* 각각의 파티션에 대하여
CD-ROM Devices
SCSI, IDE 또는 어떤 CD-ROM이던지간에 모든 CD-ROM들은 /dev/cdroms 계열아래 존재한다.:
 /dev/cdroms/cdrom0 first CD-ROM
 /dev/cdroms/cdrom1 second CD-ROM
이들 항목 각각은 그 디바이스에 대한 실제 디바이스 항목에 대한 심볼릭 링크이다.
Tape Devices
SCSI, IDE 를 막론하고 모든 테잎 장치들은 /dev/tapes계열아래에 위치한다.
 /dev/tapes/tape0 first tape
 /dev/tapes/tape1 second tape
이들 항목 각각은 그 디바이스에 대한 디렉토리의 심볼릭 링크이다.
 mt   for mode 0
 mtl   for mode 1
 mtm   for mode 2
 mta   for mode 3
 mtn   for mode 0, no rewind
 mtln   for mode 1, no rewind
 mtmn   for mode 2, no rewind
 mtan   for mode 3, no rewind
SCSI Devices
어떤 SCSI 디바이스를 유일하게 판별하기 위해서는 다음의 정보가 필요하다:
  controller (host adapter)
       bus  (SCSI channel)
       target (SCSI ID)
       unit  (Logical Unit Number)
모든 SCSI 디바이스는 /dev/scsi(devfs가 /dev에 마운트 되었다는 전제하에) 아래 위치한다. 그러므로, 다음 파라미터:c=1, b=2, t=3, u=4 를 가지는 SCSI 디바이스는 다음과 같이 나타날 것이다.
/dev/scsi/host1/bus2/target3/lun4 device directory
이 디렉토리 안에서 SCSI 디바이스 타잎 드라이버가 인스톨된 것에 의존하여 디바이스 항목 번호가 만들어질 것이다.
SCSI 디스크 드라이버가 만드는 항목을 알기위해서는 디스크 네이밍 체계에 대한 섹션을 보라.
SCSI 테잎 드라이버 항목이 만들어지는 것에 대해 알고 싶으면 테잎 네이밍 쳬게에 대한 섹션을 보라.
SCSI CD-ROm 드라이버는 다음을 만든다:
 cd
SCSI generic 드라이버는 다음을 만든다:
 generic
IDE Devices
IDE 디바이스를 유일하게 지정하기 위해서는 다음의 정보가 필요하다:
  controller
  bus  (aka. primary/secondary)
  target (aka. master/slave)
  unit
모든 IDE 디바이스들은 /dev/ide아레 위치하고, SCSI 서브시스템과 비슷한 네이밍 체계를 사용한다.
XT Hard Discs
모든 XT 디스크들은 /dev/xd아래 위치한다. 첫번째 XT 디스크는 /dev/xd/disc0디렉토리를 가진다.
TTY devices
tty 디바이스들은 다음과 같이 나타난다.
             New name                   Old-name                   Device Type
             ---------                   --------                     -----------
 /dev/tts/{0,1,...}         /dev/ttyS{0,1,...}          Serial ports
 /dev/cua/{0,1,...}      /dev/cua{0,1,...}          Call out devices
 /dev/vc/0                  /dev/tty                         Current virtual console
 /dev/vc/{1,2,...}       /dev/tty{1...63}              Virtual consoles
 /dev/vcc/{0,1,...}     /dev/vcs{1...63}            Virtual consoles
 /dev/pty/m{0,1,...}   /dev/ptyp??                   PTY masters
 /dev/pty/s{0,1,...}    /dev/ttyp??                    PTY slaves
RAMDISCS
RAMDISC들은 그들 자신의 디렉토리에 위치하며, 다음과 같은 이름을 가진다:
  /dev/rd/{0,1,2,...}
Meta Devices
meta 디바이스들은 그들 자신의 디렉토리에 위치하며, 다음과 같다:
  /dev/md/{0,1,2,...}
Floppy discs
플로피 디스크들은 /dev/floppy디렉토리에 위치한다.
Loop devices
Loop 디바이스들은 /dev/loop디렉토리에 위치한다.
Sound devices
Sound 디바이스들은 /dev/sound디렉토리에 위치한다.(audio, sequencer,...).
Devfsd 네이밍 스키마
Devfsd는 커널제공 네임스페이스 의 편리한 축약형인 네이밍 스키마를 제공한다. 어떤 경우에는, 커널이 제공하는 네이밍 스키마는 매우 편리고, 따라서 devfsd는 다른 네이밍 스미마를 제공하지 않는다. devfsd가 만드는 편리한 이름은 실제로 오리지날 devfs 커널 패치가 만드는 이름과 동일하다(리누즈가 Big Name Change를 지시하기 전까지). 이것들은 "새로운 호환 엔트리"로서 참고된다.
이들 편리한 이름을 생성하기 위해 devfsd를 설정하기 위하여, 다음의 줄이 /etc/devfsd.conf에 추가되어야 한다:
REGISTER        .*         MKNEWCOMPAT
UNREGISTER      .*         RMNEWCOMPAT
이것은 커널이 제공하는 이름을 지정하기 위하여 devfsd가 심볼릭 링크를 만들(없앨)도록 한다.
SCSI 하드 디스크들
모든 SCSI 디스크들은 /dev/sd아래에 위치한다(devfs는 /dev에 마운트되었다고 가정하면). 그러므로, 다음의 파라미터:c=1,b=2,t=3,u=4를 가지는 SCSI 디스크들은
 /dev/sd/c1b2t3u4 for the whole disc
 /dev/sd/c1b2t3u4p5 for the 5th partition
 /dev/sd/c1b2t3u4p5s6 for the 6th slice in the 5th partition
에 나타난다.
SCSI Tapes
모든 SCSI 테입들은 /dev/st아래 위치한다. SCSI 디스크들과 유사한 네이밍 체계가 사용된다. 다음과 같은 파라미터 : c=1, b=2, t=3, u=4 를 가지는 SCSI 테잎들은 다음과 같이 나타난다:
 /dev/st/c1b2t3u4m0 for mode 0
 /dev/st/c1b2t3u4m1 for mode 1
 /dev/st/c1b2t3u4m2 for mode 2
 /dev/st/c1b2t3u4m3 for mode 3
 /dev/st/c1b2t3u4m0n for mode 0, no rewind
 /dev/st/c1b2t3u4m1n for mode 1, no rewind
 /dev/st/c1b2t3u4m2n for mode 2, no rewind
 /dev/st/c1b2t3u4m3n for mode 3, no rewind
SCSI CD-ROMs
모든 SCSI CD-ROM들은 /dev/sr아래 위치한다. SCSI 디스크들과 비슷한 네이밍 체계를 사용한다. 다음과 같은 파라미터: c=1, b=2, t=3, u=4 를 가지는 SCSI CD-ROM은 다음과 같이 나타난다:
 /dev/sr/c1b2t3u4
SCSI Generic Devices
모든 SCSI CD-ROM들은 /dev/sg아래 위치한다. SCSI 디스크와 비슷한 네이밍 체계를 사용한다. 다음과 같은 파라미터: c=1, b=2, t=3, u=4 를 가지는 SCSI generic 디바이스는 다음과 같이 나타난다:
 /dev/sg/c1b2t3u4
IDE Hard Discs
모든 IDE 디스크들은 SCSI 디스크들과 비슷한 방법을 사용하여, /dev/ide/hd아래 위치한다. 다음의 맵핑이 새로운 이름과 예전 이름 사이에 존재한다.
 /dev/hda /dev/ide/hd/c0b0t0u0
 /dev/hdb /dev/ide/hd/c0b0t1u0
 /dev/hdc /dev/ide/hd/c0b1t0u0
 /dev/hdd /dev/ide/hd/c0b1t1u0
IDE Tapes
IDE 디스크들과 유사한 네이밍 체계가 사용된다. 그 항목은 /dev/ide/mt디렉토리 안에서 나타날 것이다.
IDE CD-ROM
IDE 디스크와 비슷한 네이밍 체계가 사용된다. 각 항목은 /dev/ide/cd디렉토리 안에서 나타날 것이다.
IDE Floppies
IDE 디스크와 비슷한 네이밍 체계를 사용한다. 각 항목은 /dev/ide/fd디렉토리 안에서 나타날 것이다.
XT Hard Discs
모든 XT 디스크들은 /dev/xd아래에 위치한다. 첫번째 XT 디스크는 /dev/xd/c0t0처럼 나타날 것이다.
옛 방식의 호환 이름
에전의 호환이름들은 /dev/hda, /dev/sda, /dev/rtc 등등의 예전부터 유지되어온 디바이스 이름을 사용한다. Devfsd는 오래된 이름을 계속 사용할 수 있도록 호환 심링크를 생성하도록 설정파일에 설정될 수 있고, 따라서 오래된 응용프로그램들은 계속하여 잘 작동하게 될 것이다.
devfsd가 이런 예전의 이름을 생성하도록 설정하기 위해서 다음의 줄이 /etc/devfsd.conf에 추가되어야 한다
REGISTER .*  MKOLDCOMPAT
UNREGISTER .*  RMOLDCOMPAT
이것은 devfsd가 커널이 제공하는 이름을 지정하도록 하는 심볼릭 링크를 만들(없애)도록 한다.
SCSI 호스트 Probing Issues
Devfs는 SCSI 호스트 번호에 대해 기초한 SCSI 디스크를 식별하도록 허용한다. 만약 당신의 컴퓨터에 오직 하나의 SCSI 호스트(card)가 있다면, 호스트 번호는 0을 받게 될 것이다. 당신이 여러개의 SCSI 호스트를 가지고 있다면 그다지 쉽지 않다. 불행하게도, 때때로 SCSI 호스트의 번호를 얻기 원하는 것을 추측하는데 어려움이 있을 수 있다. 이것을 쉽게 하기 위해서, "scsihosts"라 불리는 커널 부트 파라미터가 있다. 이것은 SCSI 호스트들의 다른 타입에 대해 순서를 결정하도록 해준다. 이 파라미터의 문법은:
scsihosts=<name_1>:<name_2>:<name_3>:...:<name_n>
이다. 여기서 <name_1>,<name_2>,...,<name_n> 들은 /proc 파일시스템에서 사용된 드라이버들의 이름들이다. 예를 들어:
    scsihosts=aha1542:ppa:aha1542::ncr53c7xx

- 첫번째 aha1542 컨트롤러   - /dev/scsi/host0/bus#/target#/lun# 일 것이다.
- 첫번째 병렬포트 ZIP       - /dev/scsi/host1/bus#/target#/lun# 일 것이다.
- 두번째 aha1542 컨트롤러   - /dev/scsi/host2/bus#/target#/lun# 일 것이다.
- 첫번째 NCR53C7xx 컨트롤러 - /dev/scsi/host4/bus#/target#/lun# 일 것이다.
- 나머지 컨트롤러           - /dev/scsi/host5/bus#/target#/lun#,
                                  /dev/scsi/host6/bus#/target#/lun# 등등 일 것이다.
- 만약 위의 어떤 컨트롤러도 발견되지 않았다면 - 그 예약된 이름들이 다른 디바이스에 의해
                                                사용되지 않는다는 것이다.
- /dev/scsi/host3/bus#/target#/lun# 는 절대로 사용되지 않는다.
에 연결된 디바이스를 의미한다. 원한다면 분리자로 ':' 대신에 ','를 사용할 수 있다. 나는 여기서 devfsd 네이밍 스키마 을 사용한다.
만약 같은 타입으로 여러개의 카드(NCR53c8xx와 같은)를 가지고 있다면, 이 스키마가 SCSI 호스트를 지정하지는 못한다. 이런 경우에 당신은 이것을 제어하기 위해서 드라이버를 지정하는 부트 파라미터를 사용할 필요가 있다.

--------------------------------------------------------------------------------
현재 포팅된 디바이스 드라이버들
-모든 miscellaneous 캐릭터 디바이스들은 devfs를 지원한다
 (이것은 misc_register()를 통하여 투명하게 이루어 진다)
- SCSI 디스크와 일반 하드 디스크들
- 캐릭터 메모리 디바이스들(null, zero, full, 기타등등)
  C. Scott Ananian <cananian@alumni.princeton.edu>에게 감사하다.
 
- 루프 디바이스들(/dev/loop?)
- TTY 디바이스들 (콘솔, 시리얼 포트, 터미널과 pseudo 터미널들)
  C. Scott Ananian <cananian@alumni.princeton.edu> 에 감사한다.
 
- SCSI 테입장치(/dev/scsi 와 /dev/tapes)
- SCSI CD-ROM(/dev/scsi와 /dev/cdroms)
- SCSI 일반 디바이스들(/dev/scsi)
- RAMDISCS (/dev/ram?)
- 메타 디바이스들 (/dev/md*)
- 병렬포트 프린터 (/dev/printers)
- 사운드 디바이스 (/dev/sound)
  C. Scott Ananian <cananian@alumni.princeton.edu> 와 Eric Dumas <dumas@linux.eu.org> 에
  감사한다.
 
- 조이스틱(/dev/joysticks)
- Sparc 키보드 (/dev/kbd)
- DSP56001 디비털 시그널 프로세서 (/dev/dsp56k)
- 애플 데스크탑 버스 (/dev/adb)
- Coda 네트웍 파일시스템 (/dev/cfs*)
- 버츄얼 콘솔 캡쳐 디바이스 (/dev/vcc)
  Dennis Hou <smilax@mindmeld.yi.org> 에 감사한다.
 
- 프레임 버퍼 디바이스 (/dev/fb)
- 비디오 캡쳐 디바이스 (/dev/v41)
--------------------------------------------------------------------------------
디바이스 번호의 할당
Devfs는 커널 내부의 오퍼레이션에 대해 디바이스 번호(메이저&마이너 번호)를 할당할 필요가 없는 드라이버들을 작성할 수 있도록 허용한다. 그러나, 디바이스에 대해 유일하게 조정가능한 것으로써 그 디바이스를 사용하는 사용자 공간 프로그램들의 번호가 있다. 그 중에 한 예가 inode가 다른 inode와 다른 파일시스템에 있는지 구분하기 위하여 다비이스 번호를 사용하는 find 프로그램이다. 그 사용된 디바이스 번호는 파일시스템이 사용하고 있는 블럭 디바이스를 위한 것이다. 사용자 공간 프로그램들고 호환성을유지하기 위하여 devfs를 사용하는 블럭 디바이스들은 유일한 디바이스 번호를 할당받을 필요가 있다. 또한, POSIX는 디바이스 번호들을 명시하고 디바이스 번호중 일부분은 사용자 공간에 보여줄 필요가 있다.
가장 간단한 옵션(특히 devfs에 포팅된 드라이버일때)은 예전의 메이저/마이너 번호들을 계속 사용하는 것이다. Devfs는 메이저&마이너 번호에 주어진 값이 무엇이던간에 사용자 공간에 보낼 것이다.
다른 방법으로는, devfs가 유일한 디바이스 번호를 선택하도록 할 수 있다. devfs_register를 사용하여 캐릭터나 블럭 디바이스를 등록하였을때, 자동적으로 고유한 디바이스 번호를 하당하는(그 할당은 캐릭터와 블럭디바이스를 구분한다) DEVFS_FL_AUTO_DEVNUM 플래그를 사용할 수 있다.
이 디바이스 번호는 16 bit 번호이며, 따라서 많은 수의 디스크와 파티션에 대해 충분한 공간을 마련해준다. 이 스키마는 또한 현재 256 pseudo-ttys로 제한된(이 제한은 xterms 과 원격 로긴의 총 동시 접속자 수이다) tty 디바이스들과 같은 캐릭터 디바이스에도 적용된다. 디바이스 번호는 현존하는 공식적인 할당과의 가능한 충돌을 피하기 위하여 36864-61439(메이저 144-239)의 범위로 제한되어 있다는 것을 명심하라.
동적으로 할당된 블럭 디바이스 번호들은 원격 마운트의 활성 시간동안 계속해서 주어지는 디바이스에 대해 dev_t를 기다리는 NFS 데몬과는 작동하지 않는다(사용자와 커널 모드 다)는 것을 명심하라.
이 스키마에서 마지막으로 명심할 것은: 이것이 디바이스 번호의 크기를 증가시키지 않기 때문에 사용자 공간에서의 호환과는 문제가 없다는 것을 명심하라.

--------------------------------------------------------------------------------
질문과 답변
Making things work
devfs의 대안
내가 devfs에 대해 좋아하지 않는것
버그를 보고하는 방법
이상한 커널 메세지
devfsd의 컴파일 문제
Making things work
여기에는 통상적인 질문과 답변이 있다.
Devfsd가 모든 퍼미션을 관리하지 않는다
당신이 적당한 이벤트를 캡쳐하고 있는지 확인하라. 예를 들어,커널이 만든 디바이스 엔트리는 REGISTER이벤트를 발생시키지만, devfsd가 생성한 것들은 CREATE이벤트를 발생한다.
Devfsd는 모든 REGISTER이벤트를 캡쳐하지 않는다.
앞의 항목을 보라: 당신은 CREATE이벤트를 캡쳐할 필요가 있다.
X가 시작하지 않는다.
devfs의 대안
나는 모든 devfs를 반대한 제안들과 대조해 보았고, 그것들의 한계를 설명했다. 공사중
왜 데몬에서 create/remove 이벤트를 보내지 않는가?
여기에서 그러한 제안은 디바이스들이 create/remove 이벤트들을 등록할 수 있고, 데몬은 그 이벤트들을 들을 수 있는 커널의 API를 개발하자는 것이다. 그 데몬은 (디스크상의 한부분인)/dev를 생성/해제 할 것이다.
이것은 여러가지 제한을 가지고 있다:
그것은 오직 커널이 부팅을 끝낸후에 모듈을 올리거나 제거하는(또는 디바이스를 추가하거나 제거하는) 것에 대한 작업이다. 이벤트의 데이터베이스 없이는 데몬이 완전한 /dev를 만들 수 있는 방법은 없다.
만약 이 스키마에 대한 데이터베이스를 추가한다면, 문제점은 사용자 공간에서 그 데이터베이스를 보여주는 방법이다. 만약 데몬에서 파이프를 통해 통과되는 이벤트 코드들의 문자열 리스트를 만든다면, 오직 데몬만이 사용할 수 있다. 나는 이 데이터를 보여주기 위한 장연적은 방법으로 devfs와 같은 파일시스템 비슷한 것을 설명할 것이다. 파일시스템으로써 그 데이터를 보여주는 것은 사용자가 사용가능한 것을 알아보기 쉽게 하고 또한 그 "데이터베이스"를 탐색하기 쉽도록 하는 스크립트를 작성하기 쉽게 한다.
디바이스 노드와 드라이버 사이의 빡빡한 바인딩이 더 이상 가능하지 않다.(requiring the otherwise perfectly avoidable 테이블 검색)
/dev에서 모듈의 자동로딩은 생성된 디바이스 노드를 필요로 하기에 inode 탐색 이벤트를 잡을 수 없다. 이것은 커다란 셋으로부터 생성된 매우 적은수의 inode들의 드라이버에 대한 문제이다.
이 기법은 root 파일시스템이 읽기 전용으로 마운트 되었을때는 사용할 수 없다.
scsidev에 대한 더 나은 구현
이 제안은 scsidev 프로그램을 포함시켜서 그것을 SCSI 디바이스 뿐만 아니라, 모든 디바이스를 탐색하는데에도 확장하자는 것이다. scsidev 프로그램은 /proc/scsi를 탐색하는 방법으로 작동한다.
문제점:
커널은 현재 사용가능한 모든 디바이스들의 목록을 제공하지 않는다. 모든 드라이브들이 커널 메세지를 생성하거나 /proc에 엔트리를 등록하지는 않는다.
devfs API와는 다르게 디바이스를 등록시키는 일정한 메커니즘이 없다.
그와 같은 API를 구현하는 것은 proposal above과 같다.
램 디스크에 /dev를 넣는 것
이 제안은 램디스크를 생성하고 디바이스 노드들을 거기에 둔 후 /dev에 그것을 마운트 하자는 것이다.
문제점:

이것은 루트 파일시스템을 마운트 하기 위해서는 여전히 디바이스 노드가 필요하므로 루트 파일시스템을 마운트 할때는 도움이 되지 못한다.
만약 루트 디바이스 노드에도 이 기법을 사용하기 원한다면, initrd를 사용하여야 한다. 이것은 부팅 과정을 복잡하게 하고, 관리자와 설정하는 것을 더 어렵게 한다. initrd 는 쉬운 시스템 관리를 앗아감으로써 본질적으로 불투명하다.
정확하게 램디스크를 위치시키기 위한 정보가 불충분하다. 그래서 우리는 그 문제를 해결하기 위해서 proposal above로 돌아간다.
ramdisc-based 해결책은 각 항목마다 일반 VFS inode와 덴트리에 대해서 284 바이트와 112 바이트의 기본적인 저장공간이 필요하므로, 더 많은 커널 메모리가 필요하다. devfs가 72 바이트를 요구하는 것과 비교해보라.
아무것도 하지 않는다: 아무런 문제가 없다
때때로 사람들은 현재의 스키마가 좋다라는 주장을 듣곤 한다. 이것은 그들이 무시하는 것에 대한 것이다.
디바이스 번호의 크기(메이저/마이너 번호 당 8비트)은 실제 제한사항이고, 어떤 방식으로던 수정되어야만 한다. 예를 들어 큰 SCSI 디바이스 번호를 가지는 시스템에서는 할당되지 않은 메이저 번호들을 계속 사용할 것이다. USB는 8비트의 마이너 번호 제한을 넘을 필요가 있다.
단순히 디바이스 번호를 증가시키는 것만으로는 불충분하다. 많은 노력을 필요로 하는 것과는 달리, 수천개 이상의 디바이스 노드를 가지는 /dev를 관리하는 문제를 해결하지는 못한다.
거대한 /dev의 문제를 무시하는 것은 동적인 /dev를 원하는 많은 수의 합리적인 주장을 철회하거나 오래가지 못할 것이다.
표준 응답:"디바이스 관리 데몬을 작성하라" 이것은 우리가 proposal above로 돌아가게 한다.
devfs에 대해 좋아하지 않는것
여기 devfs에 대한 불평불만이 있고, 어떤 제안과 해결책은 좀더 당신의 마음에 들것이다. 나는 모든 사람을 기쁘게 할 수 없지만, 노력하겠다 :-)
나는 그 네이밍 스키마가 싫다
첫번째로, 모든 사람을 기쁘게 해 줄수 있는 네이밍 스키마는 없다는 것을 기억하라. 당신이 그 스키마가 싫어도, 다른 사람은 좋아한다. 누가 옳고 그름을 말할수 있는가? 궁극적으로, 코드를 작성하는 사람은 선택을 하고, 현재 남아있는 것은 devfs 저자와 커널 관리자(Linus)에 의해 만들어진 것의 조합하는 것이다.
그러나, 모든 것을 잃지는 않는다. 만약 자신만의 네이밍 스키마를 만들고 싶다면, 독립적인 스크립트를 작성하거나, devfsd를 핵 하거나, devfsd에 의해 호출되는 스크립트를 작성하는 등의 간단한 일을 하면된다. 당신이 좋아하는 네이밍 스키마가 무엇이던지 간에 만들 수 있다.
또한, /dev로부터 devfs 네이밍 스키마의 모든 것을 제거하기를 원한다면, devfs를 아무곳이나(/devfs등의)마운트하고, /devfs에 /dev를 링크하여 만들 수 있다. 그것은 원한다면 devfsd를 사용함으로써 자동적으로 해결될 수도 있다.
심지어 심볼릭 링크를 사용하기보다 VFS 바인딩 키능이 링크를 만들도록 사용할 수도 있다. 이 방법은, 이 심볼릭 링크들의 "목적지"가 어디인지 알 필요가 없다.
커널에서 Devfs 정책
이미 커널안에서의 정책이 있다. 디바이스 번호는 실제로 정책에 의한 것이다(왜 내가 사용하는 디바이스 번호가 무엇인지를 커널이 지시해야만 하는가?). 이것에 대해, 커널에는 어떤 정책이 있다. 정책으로써의 디바이스 이름과 정책으로서의 디바이스 번호의 실제 차이점은 디바이스 번호는 사람에게는 의미없는 숫자이고 너무 조잡스럽기 때문에 누구도 직접적으로 사용하지 않는다는 것이다. 최소한 devfs 디바이스 이름에서는, (자신만의 네이밍 스키마를 더 할 수 있다 하더라도) 어떤 사람들은 devfs가 제공하는 이름을 직접적으로 사용할 서이다. 이것은 어떤 사람들에게는 기분 나쁜 일이다 :-)
Devfs는 블로트웨어이다
앞에서 보여진 것처럼, 이것은 전혀 진실이 아니다. 코드와 데이터 크기 모두 매우 적은 양이다.
버그 리포트 방법
만약 devfs에 대한 버그를 알고 있다면(또는 알고 있다고 생각한다면), 다음의 단계대로 행하라:
최신의 devfs 패치를 적용했는지 확인해보라. 최신의 커널버전에 최신의 devfs 패치가 적용되지 않았을 수도 있다(Linus는 매우 바쁘다)
당신의 버그 리포트에 완전한 커널 로그(dmesg를 사용하여)를 저장하여 포함하라. 모든 부트 메세지를 잡아내기 위한 내부버퍼의 크기를 증가시키기 위해 -s를 사용할 필요가 있을 것이다.
커널 부트 커맨드 라인에 devfs=dall를 넣고 부팅해보고(부트로더에서 이것을 사용하는 방법은 문서를 읽도록 하라), 그 결과를 파일로 저장하라. 이것은 매우 장황스러운 일이고, 메제시 버퍼를 넘어설 수도 있지만, 할수만 있다면 더 많은 것을 잡아내도록 노력해달라.
당신의 devfsd 설정파일을 복사해 보내달라.
나에게 먼저 버그 리포트를 보내라. 당신이 리눅스 커널 메일링 리스트에 버그를 리포트 한다고 해서 내가 알 것이라고 기대하지는 말라. 위에 나열된 모든 정보를 포함하고, 그외 관련이 있다고 생각하는 것을 추가시켜도 좋다. 제목에 devfs를 넣어서, 나의 메일 필터가 긴급한 상황임을 알수 있게 하라.
여기, 답장받을 기회를 향상시켜주는 질문하는 방법: http://www.tuxedo.org/~esr/faqs/smart-questions.html 만약 버그보고를 하고 싶다면, http://www.chiark.greenend.org.uk/~sgtatham/bugs.html 를 읽을 필요가 있을 것이다.
이상한 커널 메세지
당신의 커널로그에서 devfs와 관련된 메세지를 볼 수 있을 것이다. 아래는 그 메세지들의 의미를 나열했다(그리고 가능하다면 그 메세지에 관해서 해야 할 것들이다.)
devfs_register(fred):could not append to parent, err: -17
당신은 그 에러코드가 의미하는 바를 확인할 필요가 있지만, 보통 17은 EEXIST를 의미한다. 이것은 드라이버가 디렉토리에 fred 항목을 생성하려고 했지만, 같은 이름의 항목이 이미 존재한다는 것을 나타낸다. 이것은 종종 퍼미션을 복구하기 위한 수단으로 /dev에 inode들을 풀어놓으려는 스크립트가 잘못되었을때 일어난다. 이 메세지는 그 디바이스 노드가 여전히 그 드라이버에 접근하도록 허용하기 때문에 (온 정성을 다하여:-) devfs=only부트 옵션을 사용하더라도) 위험하다. 이러한 불필요한 메세지를 제거하기 원한다면, devfsd-v1.3.20으로 업그레ㅣ드 하고, 퍼미션을 저장하기 위하여 추천된 RESTORE 지시자를 사용하라.
devfs_mk_dir(bill): using old entry in dir: c1808724 ""
이것은 드라이버가 부모디렉토리가 같은 이름을 가지는 bill이라 불리는 디렉토리를 생성하려고 한다는 것을 제외하고위의 메세지와 유사하다. 이 경우에, 드라이버가 작동을 올바르게 계속하기 위해서, 옛 항목이 그 드라이버에 주어지고 재사용된다. 2.5 커널에서는, 그 드라이버는 NULL 항목이 주어지고, 따라서, 어떤 환경에서는 요청된 디바이스 노드를 생성하지 못할 것이다. 이것의 해결책은 위와 같다
devfsd의 컴파일 문제
보통, devfsd컴파일은 단지 소스 디렉토리에서 make를 친 후, make install (루트로)을 치는 것으로 된다. 가끔은, 잘못된 설정으로 인해 문제가 일어날 수도 있다.
DEVFSD_NOTIFY_DELETE에 관련된 에러메세지
이것은 /usr/include/linux나 /usr/src/linux에 예전의 커널 헤더를 가지고 있기 때문에 일어난다. KERNEL_DIR변수를(만약 /usr/src/linux에 새 커널소스를 설치하지 않았다면) make에 전달하거나, /usr/include/linux에 커널 소스에 있는 devfs_fs.h를 복사하면 된다.
--------------------------------------------------------------------------------
다른 참고문서
Douglas Gilbert는 SCSI 서브 시스템을 탐색하고 devfs 와 같이 사용할 수 있게 하는 유용한 문서를http://www.torque.net/sg/devfs_scsi.html 에 작성해두었다.
Douglas Gilbert는 scsihosts=부트 옵션에 대해 논하는 또다른 좋은 문서를 http://www.torque.net/scsi/scsihosts.html 에 작성했다.
Douglas Gilbert는 2.4에서 리눅스 SCSI 서브시스템에 대해 논한 문서를 http://www.torque.net/scsi/SCSI-2.4-HOWTO/ 에 작성했다.
Johannes Erdfelt는 그 요구사항이 납득할만한 해결책인지와 어떻게 왜 devfs+devfsd를 사용할지 등에 대해 기술한 인지 리눅스와 hot-swap 디바이스에 관해 기술한 페이지를 만들었다. 이것은 초안임을 기억하고, 그 plain-text 폼으로 작성되었다.: http://johannes.erdfelt.com/hotswap.txt. Johannes 는 HTML 버전을 만들겠다고 약속했다.
나는 2000년 10월 미국 플로리다 마이에미에서 개최된 2nd Annual Storage Management Workshop에 초청된 논문을 발표했다.
--------------------------------------------------------------------------------
이 문서의 번역본
이 문서는 다른 언어로 번역되어 있다.
rgooch@atnf.csiro.au에 의해 주 문서(영어로 된)는 http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html에 있다.
viatoris@nownuri.net가 번역한 한국어 문서는 http://your.destiny.pe.kr/devfs/devfs.html에 있다.
--------------------------------------------------------------------------------
Most flags courtesy of ITA's Flags of All Countries used with permission.

bootcamp 지우기

맥북 프로 레티나 터치바 diskutility 에서 bootcamp 파티션 삭제하면 검은색에서 회색으로 바뀐다(APFS로 지정) 파틴션 아이콘 클릭하여 - 버튼을 이용하여 삭제하면 끝.