접근

전형적인 BFS 문제였다. 가로 세로의 길이가 50 이하로, 모든 경우를 탐색한다 해도 2500번만 보면 된다. 모든 칸을 탐색하며 육지일 경우 bfs로 가장 긴 거리를 리턴하고, 그 중 가장 큰 수를 출력하면 된다.

개인적으로 하나로 연결된 육지를 계속해서 확인해봐야 한다는 점이 비효율적으로 느껴져 개선 방안을 찾아보고자 했지만.. 다른 사람들의 풀이를 참고해봐도 실행 시간이 비슷한 것으로 보아 특별한 해결책은 찾지 못했다. 

 

코드

import java.util.*;
import java.lang.*;
import java.io.*;

class Main {
    static int[] dx = {-1, 0, 1, 0};
    static int[] dy = {0, 1, 0, -1};
    static char[][] map;

    public static class Pos{
        int x;
        int y;
        int dist = 0;

        Pos(int x, int y, int d){
            this.x = x;
            this.y = y;
            this.dist = d;
        }
    }
    
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        // 입력값 저장
        int h = Integer.parseInt(st.nextToken());
        int w = Integer.parseInt(st.nextToken());
        map = new char[h][w];

        for(int i = 0; i < h;i++)
            map[i] = br.readLine().toCharArray();

        // 최단거리 계산
        int answer = solve(w, h);
        System.out.println(answer);
    }

    public static int solve(int w, int h){
        int res = 0;

        for(int i = 0;i < h;i++){
            for(int j = 0;j < w;j++){
                if(map[i][j] =='W') continue;
                int curMax = bfs(i, j, w, h);
                res = Math.max(res, curMax);
            }
        }
        
        return res;
    }

    public static int bfs(int x, int y, int w, int h){
        int maxDist = 0;
        
        boolean[][] visit = new boolean[h][w];
        for(int i = 0;i < h;i++)
            Arrays.fill(visit[i], false);

        Queue<Pos> q = new LinkedList();
        q.add(new Pos(x, y, 0));
        visit[x][y] = true;
        
        while(!q.isEmpty()){
            Pos cur = q.poll();
            maxDist = Math.max(maxDist, cur.dist);

            for(int d = 0;d < 4;d++){
                int nx = cur.x + dx[d];
                int ny = cur.y + dy[d];

                // 범위를 벗어남
                if(!inBound(nx, ny, w, h)) continue;
                // 바다이거나 이미 방문함
                if(map[nx][ny] == 'W' || visit[nx][ny]) continue;

                q.add(new Pos(nx, ny, cur.dist+1));
                visit[nx][ny] = true;
            }
        }

        return maxDist;
    }

    public static boolean inBound(int x, int y, int w, int h){
        return !(x < 0 || x >= h || y < 0 || y >= w);
    }
}

 

'Algorithm' 카테고리의 다른 글

[백준] 5430: AC JAVA  (0) 2025.05.18
[백준] 1092: 배 JAVA  (0) 2025.03.02
[백준] 1976: 여행 가자 JAVA  (0) 2025.03.01
[백준] 11403: 경로 찾기 JAVA  (0) 2025.02.28
[백준] 9084: 동전 JAVA  (0) 2025.02.14

접근

어렵진 않은데, 생각보다 푸는 데 되게 오래 걸렸던 문제다. 구현 문제는 알고리즘에 조금 소홀해지면 바로 표가 나는 것 같다. 

 

1. 우선 처음에는 'R' 명령어가 나올 때마다 배열을 reverse하는 단순한 방식으로 작성했고, 시간초과가 났다.

2. 그래서 R이 나올 때마다 flag값을 반전시켜 앞/뒤쪽 중 어디에서 아이템을 삭제할지 정하는 방식으로 수정했다. 

3. 이번엔 시간 초과는 안났는데, 틀렸다. 질문 게시판의 반례를 모두 입력해보아도 틀린 경우가 없었는데.. 

4. 이유가 다소 어이없었다ㅠ 내가 작성한 코드의 ArrayList.toString() 함수는 "[1, 2, 3]"과 같이 각 값 사이에 공백이 추가되어 나오는데, 문제의 테스트 케이스는 "[1,2,3]"과 같이 공백이 없는 값을 요구하고 있었다.. 그래서 replaceAll로 공백을 모두 없애주니 통과했다. 

 

다른 사람들의 코드와 비교해봤을 때 실행 시간이 다소 느린 것 같아서 그 이유를 고민해봤다. 로직은 동일한데, 자료구조의 문제였던 것 같다. 내가 사용한 ArrayList는, 만약 첫 번째 아이템을 remove한다면 뒤쪽의 아이템들을 모두 앞당기는 과정이 필요하다고 한다.(by gpt) 그런데 676ms가 나온 해당 코드를 보면 Deque를 사용하고 있다. 디큐도 잘 알고 있는 자료구조였지만, 알고리즘 문제를 풀며 자주 접하게 되지는 않다보니 이를 사용할 생각을 못한 것 같다. 

 

코드

import java.util.*;
import java.lang.*;
import java.io.*;

class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        
        int tc = Integer.parseInt(br.readLine());
        for(int t = 0;t < tc;t++){
            // 입력값 저장
            char[] p = br.readLine().toCharArray();
            int n = Integer.parseInt(br.readLine());
            String[] numStrArr = br.readLine().split(",|\\[|\\]");  // 양 끝에는 빈 리스트가 올 것
            
            // 숫자 배열 전처리
            ArrayList<Integer> numArr = new ArrayList();

            for(int i = 0;i < n;i++)
                numArr.add(Integer.parseInt(numStrArr[i+1]));

            String res = solve(p, numArr);
            sb.append(res).append("\n");
        }
        
        System.out.println(sb.toString());
    }

    public static String solve(char[] commandArr, ArrayList<Integer> numArr){
        // 첫 번째 코드(시간 초과)
        /**
        int commandCnt = commandArr.length;
        for(int i = 0;i < commandCnt;i++){
            char c = commandArr[i];
            if(c == 'R'){
                Collections.reverse(numArr);
            }
            else {  // c == 'D'
                if(numArr.size() == 0)
                    return "error";
                else
                    numArr.remove(0);
            }
        }

        return numArr.toString();
        **/

        int commandCnt = commandArr.length;
        boolean reverseFlag = false;
        
        for(int i = 0;i < commandCnt;i++){
            char c = commandArr[i];
            if(c == 'R'){
                reverseFlag = !reverseFlag;
            }
            else {  // c == 'D'
                if(numArr.size() == 0)
                    return "error";
                else{
                    if(reverseFlag)
                        numArr.remove(numArr.size()-1);
                    else
                        numArr.remove(0);
                }
            }
        }

        if(reverseFlag)
            Collections.reverse(numArr);

        return numArr.toString().replaceAll(" ", "");
    }
}

'Algorithm' 카테고리의 다른 글

[백준] 2589: 보물섬 JAVA  (0) 2025.05.20
[백준] 1092: 배 JAVA  (0) 2025.03.02
[백준] 1976: 여행 가자 JAVA  (0) 2025.03.01
[백준] 11403: 경로 찾기 JAVA  (0) 2025.02.28
[백준] 9084: 동전 JAVA  (0) 2025.02.14
Jasypt 활용 목적
우리 솔루션은 .env 파일에 변수를 따로 정리해 두고, docker-compose.yml 파일에서 참조하여 사용하고 있다. 이 .env 파일에 적혀있는 DB 패스워드값이 평문이기 때문에 이를 암호화하고자 한다. 임의의 secretKey를 지정하여 해당 패스워드를 암호화하고, 이를 .env파일에 넣으면 된다.

 

 

jasypt 설치

라이브러리 종류

나는 폐쇄망에서 개발 중이었기 때문에, 인터넷에서 jar 파일을 다운로드하여 반입해야 한다. 그 과정에서 jasypt 라이브러리의 타입이 다양해서 처음에는 무엇을 설치해야 할지 헷갈렸다.

우선 공식 git 레포지토리를 찾아보면 두 가지가 나온다. (jaspyt 깃허브 & jasypt spring boot 깃허브) 전자는 일반 jasypt 라이브러리에 대한 페이지이며 후자는 spring boot와의 통합을 위한 라이브러리에 해당한다. 즉 나는 스프링 코드에 사용할 것이기 때문에 후자를 다운로드 하면된다.

이제 jar 파일 다운로드를 위해 maven central repository “jasypt spring boot”를 검색했다. 그랬더니 일반 jasypt spring boot와 jasypt spring boot starter가 있었다. Jasypt Spring Boot는 asypt를 Spring Boot 애플리케이션에서 사용할 수 있게 해주는 기본 라이브러리이며, starter는 Jasypt Spring Boot를 Spring Boot 애플리케이션에 통합하기 쉽게 만든 스타터 라이브러리이다. pring Boot의 starter는 Spring Boot 애플리케이션에서 특정 라이브러리를 더 쉽게 사용할 수 있도록 도와주는 구성요소이다.

 


기본 설정 변경

gradle 설정

build.gradle 파일에서 해당 라이브러리를 사용하고자 하는 모듈에 아래와 같이 implementation 을 추가하고, gradle reload를 실행한다.

subprojects {
	dependencies {
		implementation 'com.github.ulsebocchio:jasypt-spring-boot-starter:3.0.5'
	}
}

 

Config 생성

@Configuration
@EnableEncrypableProperties
@ComponentScan("com.hanafn.ocr")

public class JasyptConfig {
	private static final String ALGORITHM = "PBEWithMD5AndDES";
	private String encryptKey = "test";  // secretKey에 해당
	
	@Bean("jasyptStringEncryptor")
	public StringEncryptor stringEncryptor(){
		PooledPBEStringEncryptor encryptor = new 	PooledPBEStringEncryptor();
		SimpleStringPBEConfig config = new SimpleStringPBEConfig();
		
		encryptor.setPassword(encrytKey);
		config.setAlgorithm(ALGORITHM);
		config.setKeyObtentionIterations("1000");
		config.setPoolSize("1");
		config.setSaltGeneratorClassName("org.jasypt.salt.RandomGenerator");
		config.setStringOutputType("base64");
		encryptor.setConfig(config);
		
		return encryptor;
	}
}

 

각 모듈 설정 파일 수정

jasypt:
	encryptor:
		bean: jasyptStringEncryptor

 

.env 파일 수정

다음과 같이 ENC() 로 감싼 암호화 텍스트로 패스워드 변수를 수정해준다.

db_password=ENC("암호화된 텍스트")
ex: ENC(xUtTur3ookt8ibe....)

 


로컬 테스트

패키지 설정

물론 스프링 애플리케이션에 암복호화를 하는 코드를 작성해서 테스트해봐도 되지만, 나는 그게 귀찮았다. 그래서 spring-boot-starter 패키지 외에도 별도로 일반 jasypt 패키지를 다운받아 윈도우 cmd 창에서 테스트를 진행했다. Github 레포지토리의 README에서 :Download distributable: jasypt 1.9.3 (binaries and javadocs)” 링크를 클릭해 다운받았다.

 

암복호화 로컬 테스트

다운받은 파일을 압축 해제하고, cmd 상에서 [압축 해제 경로]/bin으로 이동한 뒤 아래 명령을 실행하면 된다. 암호화 시 나오는 output은 실행할 때마다 달라지는 것이 정상이다. 여기서 입력되는 “password”값이 JasyptConfig의 “encryptKey” 값과 동일해야 한다.

# 암호화 테스트
encrypt.bat input="[암호화할 텍스트]" password="test" algorithm="PBEWithMD5AndDES"

# 복호화 테스트
decrypt.bat input="[암호화결과 output]" password="test" algorithm="PBEWithMD5AndDES"

 


테스트

컨테이너 실행

내 경우 mariaDB 컨테이너가 우선적으로 실행된 뒤 나머지 서버(config, discovery 등)이 실행되도록 되어있다. Jasypt는 자바 코드 기반으로 동작하는데, 가장 우선적으로 올라가야 할 mariaDB는 openJDK가 설치되어 있지 않기 때문에 해당 암복호화 기능을 사용할 수는 없다.

상사에게 문의해본 결과, 해당 부분이 문제가 되는 이유는 초기 솔루션 설치 시점이 아니라 운영 도중이라고 하며, 즉 처음에 컨테이너가 올라갈 때에는 .env 파일에 패스워드 평문을 쓰는 것은 아무런 상관이 없다는 답변을 받았다. 따라서 솔루션 설치 시에는 평문을 사용하여 DB만 컨테이너 이미지를 생성하고, 나머지는 암호화된 텍스트를 넣어 실행시키면 된다.

# 평문이 저장된 .env 파일 사용
docker compose up -d mariadb_test
# 암호화된 텍스트가 저장된 .env 파일 사용
docker compose up -d --no-recreate

그래서 우선 DB 컨테이너만 명시해서 docker-compose up을 해준 뒤, 패스워드값을 변경하고 나머지 컨테이너를 생성해줬다. 이때, --no-recreate 옵션이 있어야 이전에 생성한 DB 컨테이너가 영향을 받지 않는다.

 

컨테이너 변수 확인

로그를 확인해보니 서버가 모두 실행되긴 했는데.. 정말 패스워드값이 서로 다르게 적용된 게 맞은걸까? 이를 확인하기 위해 docker inspect로 컨테이너에 적용된 환경변수 값을 조회해봤다. grep 시에는 “Env” 를 정확히 입력해야 한다. (대소문자를 구분하기 때문) DB 컨테이너와 일반 컨테이너 조회 결과 아래와 같이 출력되어, 정상적으로 적용되었음을 확인할 수 있었다.

docker inspect [컨테이너명] | grep "Env" -A 20

## DB 컨테이너 조회 결과 ## 
"Env": {
	"MYSQL_PASSWORD=[패스워드 평문]"
}

## 일반 컨테이너 조회 결과 ##
"Env": {
	"db.password=ENC([암호화된 텍스트])"
}

 


References

'Backend > spring' 카테고리의 다른 글

Spring Cloud란?(Eureka, zuul)  (0) 2025.03.27

배경

회사 폐쇄망에서 virtual box로 개발 환경을 설정해야 하는 일이 있었는데, rocky 8.4 OS 이미지만 주어진 상태였다. 그래서 docker 설치를 위해 패키지 rpm 파일을 반입해야 했다. 집에 있는 인터넷망에서 완전히 동일한 환경(virtual box)를 준비하고 그에 맞는 파일들을 다운받기로 했다. 

 

온라인 환경 설정

Virtual box 생성

우선 rocky OS 부터 다운받는다. 공식 사이트에서 "아카이브된 릴리즈 버전"을 선택하고, 원하는 환경에 맞는 폴더를 선택한다. 내 경우 https://dl.rockylinux.org/vault/rocky/8.4/Minimal/x86_64/iso/ 경로의 Rocky-8.4-x86_64-minimal.iso 파일을 받았다. 사실 나도 정확히 뭔지 모르고 일단 다운부터 받아봤는데, 다행히 잘 진행됐다. 

 

virtual box를 설치한 후 새로 만들기 버튼을 통해 위에서 받은 ISO 이미지를 선택해주면 된다. 

 

이제 해당 머신이 사용할 네트워크 설정이 필요한데, 네트워크 설정은 머신이 종료된 상태에서만 변경이 가능하다. 나는 NAT 네트워크로 설정해 주었다. 

 

참고로, NAT 네트워크 사용 시 네트워크 관리자 창에서 포트포워딩 등의 설정도 가능하다. 나는 인터넷망은 아니고, 회사의 폐쇄망에서 SSH 접속을 위해 게스트 IP와 port(22)를 입력하여 putty로 세션을 저장하여 사용했다. 

 

네트워크 설정

기본적인 설정이 완료한 후 머신을 시작하면 계정 생성 등의 절차를 진행한 뒤 터미널에 접속할 수 있게 된다. 이제 이 터미널에서 도커 설치에 필요한 파일들을 받기 위한 명령어를 실행하면 된다. 그런데 나는 호스트가 인터넷에 연결되어 있기 때문에 머신 내에서도 자연스럽게 사용할 수 있을 줄 알았는데, 내 경우에는 별도 설정이 필요했다, 

sudo nmcli connection show
sudo nmcli connection up enp0s3
ping 8.8.8.8 -c 4  # 정상 연결 테스트

 

nmcli를 통해 현재 커넥션을 조회해보니 enp0s3이 내려가 있어서, 연결 설정을 해준 뒤 ping을 통해 정상적으로 인터넷이 동작하는지 확인해줬다. 

 

폴더 마운트 설정

머신 내에서 도커 파일을 받고 나면 이를 외부(호스트)로 반출할 방법이 필요한데, 나는 호스트의 경로를 마운트하여 빼내기로 했다. USB를 연결하는 방법도 있는데, 왜인지 나는 계속 USB 인식이 안돼서 이 방법을 택했다. 우선 사진과 같이 마운트를 원하는 경로를 지정한다. 나는 호스트의 workspace/VM/share라는 폴더와, 머신 내부의 /home/share라는 폴더가 마운트되도록 설정했다. 

 

아래 명령어로 필수 패키지를 설치한 후, 메뉴 탭의 장치 > Guest Additions CD 이미지 삽입(게스트 확장 CD 이미지 삽입)을 선택한다. 

sudo dnf install -y epel release
sudo dnf groupinstall -y Development Tools"
sudo dnf install -y kernel-devel kernel-headers dkms gcc make perl bzip2

 

 

CD 이미지가 정상적으로 삽입이 됐다면 다음 명령어로 마운트 경로를 설정한다.  

sudo mount /dev/cdrom /mnt
cd /mnt
sudo ./VBoxLinuxAdditions.run
sudo reboot
lsmod | grep vboxguest

sudo mkdir -p /home/share
sudo mount -t vboxsf share
ls /home/share  # 마운트된 호스트 경로의 파일들이 보임

 

만약 패키지 버전과 OS 버전이 "정확하게" 일치하지 않는다면 위 과정에서 에러가 발생할 수 있다. 이 경우 다음 명령어를 실행한 후 위 작업을 다시 시도한다. 정상적으로 마운트가 완료되었다면, 호스트의 파일을 머신에서 볼 수 있고 머신의 파일을 호스트에서 볼 수 있게 된다. 

sudo dnf install -y kernel-devel-$(uanme -r) kernel-headers-$(uname -r)

docker 다운로드

rpm 파일 다운로드

처음에는 docker 엔진 설치 문서를 참고했는데, 이렇게 진행할 경우 5~8개? 정도의 패키지에 대한 설치 파일만 저장된다. 그런데 내 경우에는 회사에서 사용 중인 OS 이미지가 정말 필수 패키지만 존재하는 상태였기 때문에, 그에 따른 의존성 패키지들도 모두 다운로드할 필요가 있었다. 그래서 repotrack 명령어를 통해 rpm 파일들을 다운받았고, 약 190여 개의 파일들이 저장되었다. 

docker dnf install yum-utils-y
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
repotrack docker-ce docker-ce-cli containerd.io docker-compose-plugin

 

rpm 설치 테스트

회사에 반입하여 테스트하기 전에, 해당 파일들로 docker가 제대로 설치되는지 사전 테스트를 진행해보았다. 우선 rpm 파일은 서로 의존성을 갖고 있어서, 우선적으로 설치되어야 하는 패키지나 버전이 존재한다. 하지만 내가 받은 파일은 모두 190여개에 달했고, 이 파일들의 관계를 모두 파악하기란 현실적으로 불가능하다. 어차피 인터넷망을 통해 필요한 모든 파일들을 받은 것이고, 버전도 그에 맞게 레포지토리에서 가져온 것이므로 문제가 없을 것이라 기대하고 무작정 설치를 진행했다. 

 

우선 그 전에, 최대한 폐쇄망과 동일한 환경을 구성하기 위해 (혹시 몰라) 처음에 설정했던 네트워크 설정을 다시 꺼줬다. 

sudo nmcli connection show
sudo nmcli connection down enp0s3
ping 8.8.8.8 -c 4  # 안되는 것 확인

 

이후 rpm 파일을 모두 설치하는 쉘 파일을 작성했다. 

  • --force: 기존에 설치된 패키지여도 강제로 설치
  • --nodeps: 의존성 무시하고 설치
  • -U: i면 install, u면 update
#!bin/bash

cd "test/docker/rpms" || exit 1

for rpm in *.rpm; do
	rpm -Uvh --nosignature --force --nodeps "$rpm"
done


설치가 완료되면 도커가 정상적으로 실행되는지 확인한다. 

docker -v  # docker-ce-cli 정상 설치 시 표시됨
systemctl start docker  # 이걸 실행해야 엔진이 실행됨
systemctl status docker  # docker-ce, 도커 엔진 정상 설치 시 표시됨
docker ps

 

그런데 사실, 집에서 해봤을 때는 문제가 없었는데, 회사에서 동일한 파일로 테스트했을 때에는 rpm 설치 도중 core dump 에러가 발생했다. 정확히 에러가 발생하는 패키지 대상을 확인했고, rpm 관련 3개 파일에서 문제가 생기는 것을 발견했다. (rpm, rpm-libs, rpm-plugin-selinux) 버전만 조금 상이할 뿐 이미 설치되어 있는 패키지였기 때문에 이 3개를 제외하고 설치를 진행했고, 이후 docker rootless 모드 설정까지 문제없이 모두 진행되어 큰 문제는 없어보였다. 

프린터 인쇄 시스템

LPRng(Line Printer next gegeration)

  • 리눅스 초기에 많이 사용됨
  • 라인 프린터 데몬 프로토콜을 이용해서 프린터 스풀링과 네트워크 프린터 서버를 지원
  • 설정 파일: /etc/printcap

 

CUPS(Common Unix Printing System)

  • 애플이 개발한 오픈 소스 프린팅 시스템
  • HTTP 기반 IPP(Internet Printing Procotol) → 인터넷을 통해 프린터를 지원
  • 사용자 및 호스트 기반의 인증 제공
  • 데몬 이름: cupsd
  • 설정 파일 디렉터리: /etc/cups

 

 

프린터 설정

  • 로컬 접속과 네트워크 프린터 설정 2가지 방법 존재
  • 네트워크 프린터 설정 방법

 


사운드 카드 시스템

OSS(Open Sound System)

  • 리눅스 및 유닉스 계열에서 사운드를 만들고 캡쳐하는 인터페이스
  • 표준 유닉스 장치 시스템 콜(POSIX read, write, ioctl 등) 기반
  • 현재는 OSS보다 ALSA로 대체

 

ALSA(Advanced Linux Sound Architecture)

  • 사운드 장치 드라이버 제공을 위한 리눅스 커널 요소
  • 사운드 카드를 자동으로 구성하고, 다수의 장치를 관리하는 것이 목적
  • OSS를 기반으로 하여 하드웨어 기반 미디어 합성, 다중 채널 하드웨어 믹싱, 전이중 통신 등의 기능 제공
  • 환경 설정 파일: /etc/asound.state

 

SANE(Scanner Access Now Easy)

  • 스캐너, 비디오 캠 등 이미지 관련 하드웨어를 제어하는 API
  • 멀티 OS 지원
  • SCSI 스캐너: /dev/sg0, /dev/scanner
  • USB 스캐너: /dev/usb/scanner, /dev/usbscanner

 

XSANE(X based Interface for the SANE)

  • SANE 스캐너 기반의 X-윈도우 기반 스캔/이미지 수정 프로그램
  • 스캔 작업 뿐 아니라 캡쳐한 이미지 수정 작업도 가능
  • gpl 라이센스, 멀티 OS 지원

 


장치 활용 명령어

프린트 명령어

  • lpr <옵션> [파일명]: 프린터 작업 요청

  • lpq <옵션>: 프린터 큐의 작업 목록 출력

  • lprm <옵션>: 큐에 대기 중인 작업 삭제

  • lpc: 라인 프린터 컨트롤 프로그램
    • 프린터 상태 확인
    • 큐 활성화/비활성화
    • 큐의 작업 순서 변경

 

System V 계열 프린트 명령어

  • lp <옵션> [파일명]: 프린터 작업 요청

  • cancal [ReqID]: 프린터 작업 취소
    • -a: 모든 작업 취소
  • lpstat <옵션>: 프린터 큐 상태 확인옵션 기능

 

사운드 카드 명령어

  • alsactl <옵션> [명령]: ALSA 사운드 카드 제어

 

  • alsamixer: ncurses 라이브러리 기반 오디오 프로그램
  • cdparanoia <옵션>: 오디오 CD 음악 추출

 

 

스캐너 관련 명령어

  • sane-find-scanner <옵션> [장치명]: SCSI 스캐너와 USB 스캐너 관련 장치 파일을 찾음

  • scanimage <옵션>: 이미지 스캔

  • scanadf <옵션>: 자동 문서 공급 장치가 장착된 스캐너에서 여러 개의 사진을 스캔

  • xcom: GUI 기반으로 평판 스캐너나 카메라로부터 이미지를 스캔

 


X-윈도우 개요

개념

  • 리눅스 환경의 각종 애플리케이션과 유틸리티에 대해 GUI를 제공
  • 플랫폼과 독립적으로 작동하는 그래픽 시스템
  • x-윈도우는 X11, X, X 윈도우 시스템이라고도 부름
  • 오픈 데스크톱 환경: KDE, GNOME, XFCE

 

특징

  • 네트워크 기반의 그래픽 환경을 지원
  • 이기종 시스템 사이에서도 사용 가능
  • 스크롤바, 아이콘, 색상 등 그래픽 환경 자원들이 통일되어 있지 않음
  • 디스플레이 장치에 의존적이지 않으며 원하는 인터페이스 설정 가능

 

네트워크 기반 클라이언트/서버 시스템

  • 서버: 클라이언트의 디스플레이 접근 제어, 클라이언트 간 자원 공유, 메세지 전달, 클라이언트와 입출력 장치의 중계
  • 클라이언트: 어플리케이션을 이용하여 X 서버의 기능 이용

 

구성요소의 종류

- windows manager: 창 크기나 색상 조절 등 GUI 관련 처리 담당
- display server ↔ client libraries: 통신 데이터는 display server protocol로 제어
- client libraries는 다양한 toolkit을 활용해서 작업을 처리함

 

  • Xfree86
    • display 서버를 지원해주는 라이브러리/프로토콜의 일종
    • X86 계열의 X서버 프로그램. 무료
  • XF86Config
    • XFree86 설정 파일 담당
    • 폰트, 키보드, 마우스, 비디오 카드 등의 색상 정보를 설정 가능
  • Xlib
    • 저수준 클라이언트 라이브러리
    • 윈도우 생성, 이벤트 처리, 창 조회, 키보드 처리 등의 기능 제공
  • XCB: Xlib보다 향상된 쓰레드, 확장성 제공
  • X 프로토콜: Xlib, Xtoolkit 인터페이스 사용
  • Xtoolkit: 고급 레벨의 GUI 생성 가능, Widget과 Intrinsic 지원

 

X-윈도우의 설정과 실행

  1. 윈도우 설정
    • init 프로세스 시 /etc/inittab 파일을 읽어 리눅스 환경 환경을 초기화함
    • 파일 시스템 점검, 서비스 프로세스 관리, 가상 콘솔 관리, 런 레벨 관리
  2. 윈도우 실행(startx -- [인자값])
    • 터미널 윈도우로 로그인하고 그래픽 환경으로 전환하고자 하는 경우 실행
    • 인자값 입력 시 여러 개의 x윈도우 프로그램 구동 가능
    • startx는 x윈도우를 실행하는 스크립트로, 시스템 환경을 초기화하고 xinit을 호출함
  3. DISPLAY 환경 변수
    • X 윈도우의 display 위치 지정
    • export DISPLAY=[IP]:[DISPLAY 번호],[스크린번호]

 


X-윈도우 매니저

x 윈도우 운영 시에는 다양한 관리자 프로그램들이 필요하다. 일반적으로 윈도우 매니저, 데스크톱 매니저, 디스플레이 매니저로 구분된다. 가장 핵심은 데스크톱 매니저이며, 데스크톱 매니저를 기반으로 윈도우와 디스플레이 매니저가 활성화되어 사용된다.

 

윈도우 매니저

  • 창의 배치와 표현을 담당하는 프로그램
  • XLib와 XCB 라이브러리를 사용
  • 리눅스에서 사용 가능한 윈도우 매니저는 다양함
  • 대표적인 윈도우 매니저
    • Enlinghtment: GNOME의 기본 윈도우 매니저
    • kwm: KDE v1.x의 기본 윈도우 매니저
    • etc: fvwm, twm, mw, windowmaker, AfterStep

 

데스크톱 매니저

  • Desktop Manager 또는 Desktop Environment
  • GUI 사용자에게 제공하는 인터페이스 스타일
  • 윈도우 매니저, 파일 관리자, 도움말, 제어판 등 다양한 도구를 제공하는 패키지 형태의 프로그램
  • 드래그 앤 드롭으로 프로세스 간의 통보 기능 지원
  • 대표적인 데스크톱 환경
    • KDE(Kool Desktop Environment): QT 툴 기반(그래픽 라이브러리), FreeBSD
    • GNOME(GNU Network Object Model Environment): QTK+이용, BSD 등에 포함
    • LXDE: Raspbian, GTK2 사용, 가벼운 모델
    • XFCE: GTK+2 사용, Xfwm 윈도우 매니저, 가벼운 모델

 

디스플레이 매니저

  • X-윈도우 상에서 작동하는 프로그램
  • X서버 접속 및 사용자 로그인 시 세션을 시작하기까지의 과정을 담당
  • 대표적인 디스플레이 매니저
    • kdm: KDE의 디스플레이 매니저
    • gdm: GNOME의 디스플레이 매니저. GTK, GNU GPK
    • etc: xdm, dtlogin

 


X-윈도우 활용 명령어

xhost

  • X 서버에 접속할 수 있는 클라이언트 지정 혹은 해제
  • 서버로의 요청 허용 여부를 호스트 단위로 제어
  • xhost [+|-] [IP|도메인명]
xhost +  # 모든 클라이언트 접속 허용
xhost + [IP]  # 해당 IP로부터 접속 허용

 

xauth

  • MMC 방식의 인증을 사용하기 위한 유틸리티
  • x윈도우 실행 시 생성되는 키를 기반으로 인증을 진행함
  • 쿠키 값으로 인증을 진행하기 때문에 xhost보다 더 강화됐다고 볼 수 있음
  • .Xauthority 파일에 해당 쿠키(magic cookie) 내용을 추가, 삭제, 리스트를 출력함
  • 당연히 $HOME/.Xauthority 파일에 대한 읽기/쓰기 권한 필요
  • xauth <옵션>
    • list: 모든 쿠키값 리스트 조회

 

X-윈도우 프로그램

 

 


References

에디터 활용

개요

  • 리눅스에서 지원하는 편집기로는 vi, emacs, pico, gedit, xedit 등이 있음
  • 버퍼 기반 편집기 방식의 장단점
    • 장점: 사용자가 잘못 편집 시 해당 편집을 중지하여 원본 파일 보존 가능
    • 단점: 외부적인 원인으로 갑자기 편집기가 종료되었을 경우 수정 내용 손실

 

pico

pico <옵션> [파일명]

  • 워싱턴 대학에서 개발된 유닉스 기반의 텍스트 에디터
  • 메뉴 선택 방식의 편집기로, 원도우의 메모장과 유사
  • 자유 소프트웨어 라이센스가 아니기 때문에 소스 수정이 불가능함
  • 기능이 부족하고 업데이트가 잘 되지 않음
  • 복제 버전인 nano 편집기가 존재

 

emacs

  • 리차드 스톨만이 개발, 이후 제임스 고슬링이 LISP 언어로 기능 추가 개발
  • 매크로 기능이 존재
  • 단순 편집기를 넘어 소스 코드 작성 모드에 특화된 통합 개발 환경을 제공

 

vi

  • 리눅스 배포판과 유닉스에 기본적으로 포함되어 있음
  • mode형 편집기(명령, 입력, 편집)

 

vim

  • vi 편집기와 호환되며 다양한 기능을 추가함
  • 디양한 색상을 사용해 가시성을 높이고, ex모드에서 히스토리 기능을 제공함
  • 확장된 정규 표현식 문법, 다중 되돌리기, 문법 검사 기능 지원

 

gedit

  • 자유 소프트웨어 편집기로, 마이크로소프트, 윈도우, 맥OS X에서 사용 가능
  • GNOME(GUI) 데스크톱 환경에서 사용 가능하며 UTF-8과 호환됨
  • 그래픽 기반이기 때문에 CLI에서 사용 불가

 

nano

  • 단축키 기반의 메뉴(편집기 하단에 표시)

 


프로그램 설치

리눅스 소프트웨어 설치

  • 설치 방법
    • 배포판에서 제공하고 있는 패키지 매니저 혹은 레퍼지토리를 활용해 설치
    • 오픈소스 코드를 직접 컴파일하여 사용
  • 패키지 관리 프로그램


패키지 매니저를 활용한 설치

rpm(Redhat Package Manager)

  • 패키지 확장명: .rpm
  • 프로그램 패키지 파일 형식: 패키지명-버전(주버전.부버전.패치번호)-릴리즈번호.페도라버전.아키텍처
    (EX: sendmail-8.12.3.-5.fc11.i586.rpm)
  • 커널 패키지 파일 형식: 패키지명-버전(주버전.부버전.패치번호)-릴리즈번호.CentOS버전.아키텍처
    (EX: kernel-3.5.0-327.el7.x76_x64.rpm)
  • 패키지 관리 명령: rpm <옵션> 패키지명

 

yum(Yellowdog Updater Mofiied)

  • 레포지토리에 접속하여 패키지 관리. 즉, 인터넷 기반으로 설치하므로 네트워크 필요
  • RPM 의존성 문제를 해결하기 위한 유틸리티
  • 페도라 22 이후 yum 문제점을 보완한 dnf로 전환되고 있음
  • 패키지 관리 명령: yum <옵션> [패키지명]

 

dpkd

  • 데비안의 low level 패키지 관리 도구
  • 패키지 설치 및 제거 시 rpm과 같은 의존성 문제 발생할 수 있음
  • deb 패키지 형식: 패키지이름_버전-릴리즈버전-리버전_아키텍처.deb
  • dpkg <옵션> [패키지명.deb]

 

apt-get(Advanced Package tool Get)

  • 데비안 계열 리눅스의 패키지 관리 도구
  • dpkg의 의존성 문제를 해결(/etc/apt/source.list 파일 참조)
    • 패키지 유형(바이너리, 소스), 저장소 주소(URL), 우분투 버전 정보, 카테고리로 구성

 

aptitude

  • 우분투의 패키지 관리 유틸리티
  • API처럼 패키지 관리를 자동화함
  • aptitude 서브명령

 


소스 파일을 이용한 설치

파일 아카이브

  • 아카이브는 다수 개의 파일이나 디렉터리를 하나의 파일로 묶는 것
  • 백업, 배포에 활용
  • 대표적인 파일 압축은 compress, gzip, bzip2, xz가 존재
  • 압축률이 가장 낮은 것은 compress, 높은 것이 xz

 

tar

  • tar <옵션> [파일명]

 

소스 코드 설치

  • 소스 코드를 압축 해제 후 컴파일 순서에 따라 프로그램을 설치함
  • “./”에서 알 수 있듯, 현재 폴더에서 실행하는 것
  • configure 결과로 makefile(컴파일 시 참고 정보)이 생성됨
  • cmake(Cross Platform Make): OS별 makefile 생성. 의존 관계 분석, 다양한 개발 환경 지원, 타임스탬프(변화 확인)

 


References

리눅스 Shell의 개요

개념

  • 명령어 해석기(commend interpreter) 역할(사용자 명령어 ↔ 커널)
  • 로그인할 때 실행되어 사용자 별로 다른 사용 환경을 설정함
  • 강력한 스크립트 언어
  • 리다이렉션, 파이프, 쉘 스크립트, 포그라운드/백그라운드 프로세스 실행

 

분류

대부분은 본쉘 계열의 기능을 포함하여 확대 발전한 형태

  • 본쉘(Bourne shell) 계열
    • ‘$’ 프롬프트
    • bash shell(리눅스 표준)
    • z shell(확장 기능 제공)
  • C쉘 계열
    • ‘%’ 프롬프트
    • 본쉘의 모든 기능과 명령어 히스토리, 별명, 작업 제어 기능을 추가로 가짐

 

로그인 쉘 확인

  • /etc/shells: 사용 가능한 쉘 목록
  • /etc/passwd의 마지막 필드: 계정마다 할당된 쉘
  • echo $SHELL: 현재 로그인한 사용자가 사용하고 있는 쉘

 


환경 변수

환경 변수와 쉘 변수

 

  • 주요 환경 변수
  • PATH(사용자가 입력한 명령어를 찾아 실행하기 위해 방문하기 위한 경로 정보), HOME, HOSTNAME, USER, PS1, SHELL, TMOUT, MAIL
  • 환경 변수 설정과 해제
    • 설정: export [변수명]=[값]
    • 해제: unset [변수명]

 

환경 설정 파일

  • 쉘 시작 시 자동으로 실행되는 고유의 파일이 있음
  • 이 파일은 사용자 운영 환경을 설정함
  • 공통 설정: /etc/profile, /etc/bashrc
  • 사용자 설정
    • ~/.bash_profile: 로그인 시 실행됨
    • .~/.bash_history: 명령어를 기록하여 재사용 가능하도록 지원
    • ~/.bashrc: alias와 자동 실행을 지정
    • ~/.bash_logout: 로그아웃 직전에 실행됨
  • /etc/profile.d: 특정 응용 프로그램 시작 시 자동 실행할 스크립트 경로 저장

 


bash shell의 주요 기능

history 기능

  • 일정 개수(기본 천개) 이상 사용했던 명령어를 저장했다가 다시 불러 사용
  • .bash_history에 저장된 명령어를 재사용
  • 해당 파일은 개별 사용자들의 홈 디렉터리에 위치

 

alias 기능

  • 자주 사용하는 명령어를 별칭으로 지정하여 간편하게 사용

 


프로세스

개념

  • 프로세스: CPU와 메모리를 할당받아 프로그램이 실행된 상태. 즉, CPU/메모리 등 자원을 할당받아 실행된 상태
  • 프로세스마다 고유의 PID를 가짐
  • 최초 실행 프로세스는 원래 init으로, PID 1을 가짐. 단 CentOS 7부터는 systemd가 최초 실행되면서 1이 됨

 

프로세스 관련 용어

데몬의 종류
1. Stand Alone(ex: httpd)
  - 독립적으로 운영되는 데몬
  - 사용자 요청 시 즉시 응답 가능
2. inetd 데몬(ex: telnet, FTP)
  - 슈퍼 데몬이라고도 부름
  - 하위에 종속된 모든 데몬이 함께 실행됨
  - 사용자 요청 시 해당되는 서비스를 구동하여 응답하여 속도는 느리나 메모리 효율성
  • fork: 기본 프로세스를 복제하여 실행 → 부모/자식 관계
  • exec: 새로운 프로세스로 변경되어 실행 → 하나의 프로세스만 남게 됨
  • 데몬: 부팅 시 자동으로 실행되는 백그라운드 프로세스
    • 메모리에 상주하며 사용자의 특정 요청을 즉시 처리하는 대기 서버 프로세스
    • CentOS7부터는 systemd에 의해 관리되며 일부 바뀐 부분 존재
  • 시그널: 프로세스에게 전달할 수 있는 이벤트(신호)
    • kill -l로 가능한 시그널 목록 확인

 


프로세스 관련 명령어

ps(process status)

좀비 프로세스
좀비 프로세스는 KILL 시그널을 받아도 종료되지 않음. 이 프로세스는 이미 현재 프로세스에 대한 모든 정보가 메모리에서 사라졌지만 부모 프로세스가 정상적인 종료 처리를 하지 못해 발생함

 

  • 실행 중인 프로세스의 목록/상태 정보를 표시
  • CPU 사용도가 낮은 순으로 출력됨
  • 옵션 없이 요청할 경우 현재 터미널에서 실행되고 있는 프로세스 관련 정보만 표시
  • ps <옵션>

 

pstree

  • 실행 중인 프로세스의 목록을 트리 형식으로 표시
  • pstree <옵션>

 

jobs

  • 작업 프로세스의 동작 상태 표시(중지, 진행 중, 변경되었지만 보고되지 않음)
  • jobs <옵션> [작업번호]

 

bg/fg

  • 백그라운드 ↔ 포그라운드로 작업 전환
  • bg <작업번호> | fg <작업번호>
# ping 8.8.8.8 > NULL &
- '>' NULL을 통해 화면에 출력하지 않도록 함
- '&'를 통해 리눅스 명령어를 백그라운드 실행

 

kill

  • 프로세스 종료
  • kill <옵션> [시그널 번호 | PID | %작업번호]

 

killall

  • 동일한 데몬의 여러 프로세스를 한번에 종료
  • 프로세스명으로 연관된 모든 프로세스를 종료함
  • killall <옵션> [프로세스명]

 

nice

프로세스 우선 순위
프로세스의 우선 순위가 높다는 것은 다른 프로세스보다 시스템 자원이 더 많이 할당되는 것을 의미함. 즉 실행 속도가 빨라지게 됨
  • 프로세스의 우선 순위를 확인하고 변경
  • NI값을 조정(-20 ~19 범위)
  • 값이 작을수록 우선 순위가 높음
  • 일반 사용자는 NI값 증가만 가능
  • nice <옵션> [프로세스명]

 

renice

NICE vs RENICE
-  nice: 우선순위를 변경하며 프로그램을 재시작(옵션값의 숫자를 더함)
- renice: 현재 실행 중인 프로그램의 우선순위를 변경(설정한 값 자체로 변경됨)
  • 실행 중인 프로세스의 우선순위 변경
  • renice <옵션> <NI값> [PID]

 

top

  • 시스템 운영 상태 혹은 프로세스 상태 확인
  • top <옵션> [PID]
  • -d: 실시간 화면 출력 시간 지정(기본 5초)
    -p: PID 지정

 

nohup

  • 프로세스 중단 없이 백그라운드로 작업 실행
  • 로그아웃 되어도 계속 실행됨
  • 백그라운드로 실행될 수 있도록 명령어 뒤에 ‘&’를 명시
  • 표준 출력 내용을 nohup.out에 기록

 

cron

  • 주기적으로 반복되는 일을 자동으로 실행할 수 있도록 설정
  • crond: 스케쥴링 데몬
  • /etc/crontab: 설정 파일
  • crontab <옵션> [파일명]

 

 


References

리눅스의 파일 권한

일반 파일 권한

  • 모든 파일과 디렉터리는 접근 권한과 소유권이 부여됨
  • 사용자별 권한은 기호 모드(symbloic)와 8진수 숫자 모드(numeric)로 표시
  • ls -al 결과 표시 내용: 파일 유형 + 접근 권한, 물리적 파일 연결개수(하드링크), 소유자, 소유 그룹, 크기, 마지막 변경 날짜+시간, 파일명
  • 디렉토리의 x 권한: 해당 디렉터리 안에서 작업이 가능하다는 의미

 

리눅스 파일의 특수 권한

  • 프로세스가 실행되는 동안 해당 프로세스의 root 권한을 임시로 가져오는 기능
  • 프로세스가 사용자보다 높은 수준의 접근을 요구할 때 접근 제한 때문에 원활한 기능을 제공할 수 없기 때문에 이를 해결하기 위함
  • SetUID: 사용자가 소유할 때만 소유자 권한으로 파일을 실행 시킴
  • SetGID: 소유자 그룹 권한으로 실행
  • s(실행파일), S(일반 파일)
  • 예시: 일반 계정의 비밀번호를 변경할 경우, root 권한으로 /etc/passwd 파일 접근

 

Sticky Bit

  • 주로 공용 디렉터리를 사용할 때 사용
  • 폴더에 대하여 소유자 혹은 root만 파일을 수정하거나 삭제 가능
chmod +t tmp
ls -al
> drwxrwxr-t root root 4096 tmp

 

디스크 쿼터(Disk Quota)

  • 파일 시스템마다 사용자나 그룹이 생성할 수 있는 파일의 용량 및 개수를 제한하는 것
  • 주로 block 단위의 용량 제한과 inode의 개수를 제한함
  • 쿼터는 사용자별, 파일 시스템별로 동작함
  • 디스크 쿼터 설정 파일 및 관련 명령어
    • quotaoff: 쿼터 서비스 비활성화
    • qoutaon: 활성화
    • quotacheck: 파일시스템의 디스크 사용 상태 점검
    • edquota: 편집기를 이용한 사용자/그룹 쿼터 설정
    • setquota: 명령어를 이용한 사용자/그룹 쿼터 설정

 


권한 및 그룹 설정 명령어

chown

  • 사용자(그룹) 소유권 변경
  • -R 옵션: 하위 디렉터리도 동일하게 변경(소유권의 상속)
chown root:root test.txt
chown root  test.txt  # 소유자
chown :root test.txt  # 소유 그룹

 

chgrp

  • 소유 그룹 변경
  • chgrp <옵션> [그룹명] [파일명]
  • -R: 하위 디렉터리 포함

 

chmod

  • 접근 권한 변경
  • chmod <옵션> [권한] [파일명]
  • -R: 하위 디렉터리 포함
chmod +x file  # 모든 유저에게 실행 권한 추가
chmod -x file
chmod u+x file  # 소유자에게 실행 권한 추가
chmod g=rx file  # 그룹에 read, write권한 추가
chmod o-x file  # 기타 다른 사람들은 실행할 수 없도록 설정
chmod a+r file
chmod 766 file  # rwx를 이진수로 계산한 것

 

unmask

  • 파일/디렉터리 생성 시 기본으로 적용할 접근 권한을 지정
  • 파일은 (666 - umask값), 디렉터리는 (777 - umask) 값으로 설정됨
  • umask <옵션>[설정값]
  • -S: 문자로 표시
umask  # 기존값 조회
umask 002  # umask값 설정

 


파일 시스템의 관리

파일 시스템의 개요

  • 파일 시스템이란? 스토리지 장치(디스크) 상에 파일을 관리할 수 있도록 만들어 놓은 구조 혹은 관리 방식
  • 최근에는 서버 파일과 가상 파일까지 접근할 수 있도록 개념이 확대됨

  • 슈퍼 블록: 파일 시스템 관련 정보(블록 크기 및 개수, inode 개수)
  • Group Descriptor: 각 블록 그룹을 관리하는 정보를 저장
  • Block Bitmap: 블록의 사용 상태를 나타냄
  • inode: 파일 이름을 제외한 정보(고유 번호, 파일 형태, 크기, 위치, 소유자 등)
    • inode bitmap: inode의 상태 정보
    • inode table: 각 inode에 대한 정보를 나타내는 descriptor로 구성

 

파일 시스템의 종류

저널링이란?
- 로그와 유사한 개념
- 특정 정보 관리를 통해 파일 시스템에 문제가 생길 경우 복구 진행

1. 저널링 파일 시스템

2. 네트워크 파일 시스템

 

3. 지원 가능한 기타 파일 시스템

 


파일 시스템 관련 명령어

/etc/fstab 파일
- 파일 시스템 정보 저장 및 관리하는 설정 파일
- 부팅 시 마운트 정보 포함

mount

  • 스토리지 장치를 연결하여 디렉토리처럼 사용
  • 설정 파일: /etc/fstab(부팅 시 참조하여 마운트), /etc/mtab(마운트된 블록 시스템 정보)
  • mount <옵션> [장치명] [디렉터리명]

 

unmount

  • 마운트 해제
  • unmount <옵션> [장치명] [디렉터리명]

 

eject

  • 미디어 장치를 해제하고 장치를 제거
  • eject <옵션> [디바이스명]

 

fdisk

  • 새로운 파티션의 생성, 기존 파티션의 삭제, 파티션의 타입 결정
  • 한 번에 한 디스크에 대해서만 작업을 수행
  • fdisk <옵션> [디바이스명]
  • fdisk를 실행하기 위해서는 어떤 디스크의 파티션을 나눌 것인지 지정 필요

 

mkfs

  • 파일 시스템 생성
  • 파티션 생성 뒤 원하는 파일 시스템 구축 필요
  • mkfs <옵션> [디바이스명]

 

mkfs2

  • ext2, 3, 4 리눅스 파일 시스템 생성
  • mkfs2 <옵션> [디바이스명]

 

 

fsck

  • 파일 시스템 점검 및 복구
  • /lost+found 디렉터리에 손상된 파일 관리 → 정상 복구된 후 삭제됨
  • fsck <옵션> [디바이스명]

 

 

e2fsck

  • ext2, 3, 4 리눅스 파일 시스템 점검 및 복구
  • e2fsck <옵션> [디바이스명]

 

du(disk use)

  • 디렉터리 별 디스크 사용량 확인
  • du <옵션> [디바이스명]

 

df

  • 시스템에 마운트된 하드 디스크의 남은 용량을 확인
  • 파티션 단위로 사용량 확인
  • 기본 1024bte 블록 단위로 출력
  • df <옵션> [디바이스명]

 


References

+ Recent posts