4.시스템 정보
4-1.개요
유닉스 시스템의 기본 환경 정보를 검색할 수 있는 함수들은 기본 환경과 관련된 구조체나 상수를 사용해 정보를 검색한다. 주요 대상 정보는 하드웨어와 운영체제의 종류 관련 정보와 메모리 페이지의 크기나 최대 패스워드 길이등 시스템 환경 설정에 관한 정보다.
<시스템 정보 검색 및 설정 함수>
기능 | 함수원형 |
---|---|
시스템기본정보검색 | int name(struct utsname *name) |
시스템 정보 검색과 설정 | long sysinfo(int command, char *buf, long count); |
시스템 자원 정보 검색 | long sysconf(int name) |
파일과 디렉토리 관련 자원 검색 | long pathconf(const char *path, int name); long fpathconf(int fildes, int name); |
sysinfo함수는 정보 검색 뿐 아니라 호스트명같은 일부 환경 정보를 설정할 수도 있다.
유닉스 시스템의 사용자 관련 정보로는 사용자 계정정보, 그룹 정보, 로그인 기록 정보가 있다.
사용자 계정검색 관련 함수는 로그인명, UID, 패스워드 정보와 같은 개별 정보검색을 수행하는 함수와 패스워드 파일(/etc/passwd)이나 쉐도우파일(/etc/shadow)에서 사용자 정보를 읽어오는 함수로 구성되어 있다. 그룹 정보 관련 함수도 GID 검색과 그룹 파일에서(/etc/group)에서 그룹 정보를 읽어오는 함수로 구성되어 있다. 로그인 기록 정보관련 함수는 /var/adm/utmpx파일에서 로그인 기록을 읽어온다.
<사용자 정보 관련 함수>
기능 | 함수원형 |
---|---|
로그인명 검색 | char getlogin(void); char cuserid(char *s); |
UID 검색 | uid_t getuid(void); uid_t geteuid(void); |
패스워드 검색 | struct passwd getpwuid(uid_t uid); struct passwd getpwnam(const char *name); |
패스워드 파일 검색 | struct passwd getpwent(void); void setpwent(void); void endpwent(void); struct passwd fgetpwent(FILE *fp); |
섀도우 정보 검색 | struct spwd getspnam(const char name); |
섀도우 파일 검색 | struct spwd getspent(void); void setspent(void); void endspent(void); struct spwd fgetspent(FILE *fp); |
그룹 정보 검색 | gid_t getgid(void); gid_t getegid(void); |
그룹 파일 검색 | struct group getgrnam(const char name); struct group getgrgid(gid_t gid); strcut group getgrent(void); void setgrent(void); void endgrent(void); struct group fgetgrent(FILE fp); |
로그인 기록 검색 | struct utmpx getutxent(void); void setutxent(void); void endutxent(void); int utmpxname(const char file); |
유닉스 시스템에서 파일이나 디렉토리의 생성, 사용자 정보 변경 등 다양한 부분에서 시간 정보가 필요하다. 유닉스에서는 시간 정보 관련 함수로 현재 시간 정보를 검색하는 함수, 시간대를 설정하는 함수, 시간정보를 분해해 구조체로 리턴하는 함수, 시간정보의 출력 형식을 지정할 수 있는 함수를 제공한다.
기능 | 함수원형 |
---|---|
현재 시간 정보 검색 | time_t time(time_t *tloc); int gettimeofday(struct timeval *tp, void *tzp); |
시간대 설정 | void tzset(void); |
시간 정보 분해 | struct tm *localtime(const time_t *clock); struct tm *gmtime(const time_t *clock); |
초 단위 시간 생성 | time_t maktime(struct tm *timeptr); |
형식 지정 시간 출력 | char *ctime(const time_t *clock); char *asctime(const struct tm *tm); size_t strftime(char *restrict s, size_t maxsize, const char * restrict format, const struct tm *restrict timeptr); |
4-2.시스템 관련 정보 검색과 설정
유닉스 시스템 관련 정보에는 시스템에 설치된 운영체제에 대한 정보, 호스트명 정보, 하드웨어 종류에 대한 정보가 있다. 유닉스 시스템은 하드웨어에 따라 사용할 수 있는 자원의 최댓값을 설정해놓았는데, 함수를 사용해 자원값을 검색하거나 수정할 수 있다.이러한 자원값으로는 최대 프로세스 개수 프로세스 하나가 열수 있는 최대 파일 개수, 메모리 페이지 크기 등이 있다.
유닉스 시스템에서는 시스템의 기본 환경을 검색하고 설정하는데 사용하는 다양한 구조체와 매개변수를 제공한다. 적절한 매개변수와 함수를 활용해 시스템의 기본환경에 관한 정보를 검색하고, 커널의 설정을 변경하거나 시스템의 자원을 적절히 제한할 수 있다.
4-2-1.운영체제 기본 정보 검색
시스템에 설치된 운영체제의 이름과 버전, 호스트명, 하드웨어 종류 등을 검색하려면 uname명령을 사용한다. uname명령에 -a 옵션을 지정하면 현재 시스템에 설치되어 있는 운영체제에 관한 정보가 출력된다.
#uname -a
SunOS jihoo 5.10 Generic_118855-33 i86pc i386 i86pc
운영체제명 호스트명 릴리즈레벨 버전번호 하드웨어형식명 cpu명 플랫폼명
위의 결과는 시스템이 인텔PC이고 솔라리스 10 운영체제가 설치되어있음을 알 수 있다.
위의 uname 명령과 이름이 동일한 uname함수가 있다. 이 함수도 마찬가지로 운영체제의 정보를 검색할 수 있다.
- 운영체제 정보 검색: uname(2)
#include <sys/utsname.h>
int uname(struct utsname *name);
* name : utsname 구조체 주소
* return 값 성공: 음수가 아닌 값 / 실패 : -1 / 전역번수 errno에 오류 코드 지정
uname함수는 운영체제 정보를 검색해 utsname구조체에 저장한다.
struct utsname {
char sysname[_SYS_NMLN];
char nodename[_SYS_NMLN];
char release[_SYS_NMLN];
char version[_SYS_NMLN];
char machine[_SYS_NMLN];
}
utsname구조체의 각 항목은 문자열 배열이며, 각 값은 널 종료 문자열 (null terminated string)로 저장된다. 항목을 구성하는 각 배열의 크기인 상수 _SYS_NMLN은 257로 정의되어 있다.
항목 | 설명 |
---|---|
sysname | 현재 운영체제 이름을 저장한다 |
nodename | 네트워크를 통해 통신할 때 사용하는 시스템의 이름을 저장한다 |
release | 운영체제의 릴리즈 번호를 저장한다 |
version | 운영체제의 버전 번호를 저장한다 |
machine | 운영체제가 동작하는 하드웨어의 표준 이름(아키텍처)를 저장한다 |
- uname함수 사용하기
#include <sys/utsname.h>
#include <stdlib.h>
#include <stdio.h>
int main(void){
struct utsname uts;
if(uname(&uts) == -1){
perror("uname");
exit(1);
}
printf("OSname : %s\n" , uts.sysanme);
printf("Nodename : %s\n", uts.nodename);
printf("Release : %s\n", uts.release);
printf("Version: %s\n", uts.version);
printf("Machine: %s\n", uts.machine);
return 0;
}
4-2-2.시스템정보의 검색과 설정
SVR4에서는 uname과 비슷한 기능을 수행하는 시스템 호출인 sysinfo 함수를 제공한다.
sysinfo함수는 uname함수보다 다양한 정보를 검색할 수 있고, 시스템 정보를 설정할 수 있다.
- 시스템 정보 검색과 설정 : sysinfo(2)
#include <sys/systeminfo.h>
long sysinfo(int command, char *buf, long count);
*command : 검색 또는 설정할 명령
*buf : 버퍼 주소
*count : 버퍼 길이
sysinfo함수는 command에 지정한 검색 또는 설정 명령에 따른 값을 buf에 저장한다.
buf의 길이는 count값으로 설정하며 최댓값은 257이다.
command에 올 수 있는 값은 sys/systeminfo.h 파일에 상수로 정의되어 있다.
상수값은 크게 네 범주로 구분된다.
상수범위 | 예약용도 |
---|---|
1~256 | 유닉스 표준에서 정의한 함수 정보를 검색(get)하는데 사용하기 위해 예약된 번호 |
257~512 | 유닉스 표준에서 정의한 함수정보를 정의(set)할 때 사용하는 예약번호 |
검색번호+256으로 번호 할당|
|513~768|솔라리스에서 추가로 정의한 상수정보검색(get)|
|769~1024|솔라리스에서 추가로 정의한 상수정보정의(set) 검색번호+256 으로 번호 할당|
<유닉스 표준에서 정의한 정보 검색용 명령>
상수 | 설명 |
---|---|
SI_SYSNAME(1) | 운영체제명을 리턴한다. uname함수의 sysname항목과 같은 값 |
SI_HOSTNAME(2) | uname함수의 nodename 항목과 같은 값. 현재 시스템의 호스트명을 리턴함 |
SI_VERSION(4) | uname함수의 version항목과 같은 값 리턴 |
SI_MASHINE(5) | 하드웨어 형식 값을 리턴한다. uname함수의 machine항목과 같은 값 |
SI_ARCHITECTURE(6) | 하드웨어의 명령어 집합 아키텍처(ISA, Instruction Set Architecture) 정보를 리턴. sparc, mc68030, i386) |
SI_HW_SERIAL(7) | 하드웨어 장비의 일련번호를 리턴한다. 이 일련번호는 중복되지 않는다. SI_HW_PROVIDER값과 함께 사용하면 모든 SVR4 업체의 제품을 구별하는 유일한 번호가 된다. |
SI_HW_PROVIDER(8) | 하드웨어 제조사 정보 리턴 |
SI_SRPC_DOMAIN(9) | Secure RPC(Remote Procedure Call)도메인명 리턴 |
<유닉스 표준에서 정의한 정보 설정용 명령>
상수 | 설명 |
---|---|
SI_SET_HOSTNAME(258) | 호스트명 설정. 이 명령은 root사용자만 사용가능함 |
SI_SET_SPRC_DOMAIN(265) | secure RPC 도메인을 설정한다. |
<솔라리스에서 정의한 정보 검색용 명령>
상수 | 설명 |
---|---|
SI_PLATFORM(513) | 하드웨어 플랫폼 모델명을 리턴한다. |
SI_ISALIST(514) | 현지시스템에서 실행 가능한 하드웨어 명령어 집합 아키텍처 정보의 목록을 리턴한다. |
SI_DHCP_CACHE(515) | 부팅시 DHCP서버에서 DHCPACK 응답으로 받은 값을 리턴한다. |
SI_ARCHITECTURE_32(516) SI_ARCHITECTURE_64(517) SI_ARCHITECTURE_K(518) SI_ARCHITECTURE_NATIVE(519) | 32비트 또는 64비트 하드웨어의 명령어 집합 아키텍처 정보를 리턴한다. |
솔라리스에서 정의한 정보 설정용 상수값은 아직 없다. sysinfo함수가 성공하면 결과값은 두번째 인자에 저장된다.
결과값이 두번째 인자의 길이보다 길면 buf 길이 -1 만큼만 저장된다.
오류 발생시 -1 리턴
- sysinfo함수로 검색하는 예제
#include <sys/systeminfo.h>
#include <stdlib.h>
#include <stdio.h>
int main(void){
char buf[257];
if(sysinfo(SI_HW_SERIAL, buf, 257) == -1){
perror("sysinfo");
exit(1);
}
printf("HW Serial : %s\n", buf);
if(sysinfo(SI_ISALIST, buf, 257) == -1){
perror("sysinfo");
exit(1);
}
printf("ISA list : %s\n", buf);
return 0;
}
- sysinfo 함수로 시스템 이름 변경하는 예제
#include <sys/systeminfo.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void){
char buf[257];
if(sysinfo(SI_HOSTNAME, buf, 257) == -1){
perror("sysinfo");
exit(1);
}
printf("Before Host name : %s\n", buf);
strcpy(buf, "hbooks");
if(sysinfo(SI_SET_HOSTNAME, buf, 257) == -1) {
perror("sysinfo");
exit(1);
}
if(sysinfo(SI_HOSTNAME, buf, 257) == -1){
perror("sysinfo");
exit(1);
}
printf("After Hostname : %s\n", buf);
return 0;
}
- BSD계열 유닉스 호스트명 관련 함수
#include <unistd.h>
int gethostname(char *name, int namelen);
int sethostname(char *name, int namelen);
gethostname함수는 현재 시스템에 설정된 호스트명을 검색해 name에 저장한다.
sethostname함수는 새로 설정할 호스트명을 name에 저장한다. namelen은 name의 길이이다.
4-2-3.시스템 자원 정보 검색
유닉스 시스템에서는 하드웨어에 따라 사용할 수 있는 자원들의 최대값을 설정해놓았다.
제한된 값은 POSIX표준에 따라
- 시스템 자원 정보 검색 : sysconf(3)
#include<unistd.h>
long sysconf(int name);
* name : 검색할 정보를 나타내는 상수
*return : 현재 설정된 시스템 자원값, 옵션값 리턴 / 오류 발생시 -1
sysconf 함수로 지정할 수 있는 상수는 sys/unistd.h 파일에 정의되어 있다. 상수값의 설명은 man sysconf명령으로 확인할 수 있다.
- POSIX.1에서 정의한 상수
상수 | 설명 |
---|---|
_SC_ARG_MAX(1) | arg[]와 envp[]를 합한 최대 크기로 바이트 단위로 표시한다. |
_SC_CHILD_MAX(2) | 한 UID에 허용되는 최대 프로세스 개수 |
_SC_CLK_TCK(3) | 초당 클록 틱수 |
_SC_OPEN_MAX(5) | 프로세스당 열수 있는 최대 파일개수 |
_SC_VERSION(8) | 시스템이 지원하는 POSIX.1의 버전 |
- SVR4에서 정의한 상수
상수 | 설명 |
---|---|
_SC_PASS_MAX(9) | 패스워드의 최대값 |
_SC_LONGNAME_MAX(10) | 로그인명의 최대 길이 |
_SC_PAGESIZE(11) | 시스템 메모리의 페이지 크기 |
- POSIX.4에서 정의한 상수
상수 | 설명 |
---|---|
_SC_MEMLOCK(25) | 프로세스의 메모리 잠금 기능을 제공하는지 여부 |
_SC_MQ_OPEN_MAX(29) | 한 프로세스가 열수 있는 최대 메시지 큐 개수 |
_SC_SEMAPHORES(35) | 시스템에서 세마포어를 지원하는지 여부 |
- XPG.4에서 정의한 상수
상수 | 설명 |
---|---|
_SC_2_C_BIND(45) | C언어의 바인딩 옵션을 지원하는지 여부 |
_SC_2_C_VERSION(47) | ISO POSIX-2표준의 버전 |
- sysconf 함수로 클록 틱 수와 한 프로세스가 최대로 열수 있는 파일 개수, 로그인명의 최대 길이를 검색하는 예제
#include <unistd.h>
#include <stdio.h>
int main(void){
//초당 클록 틱
printf("Clock Tick : %ld\n", sysconf(_SC_CLK_TCK));
//열 수 있는 최대 파일 개수
printf("Max Open File : %ld\n", sysconf(_SC_OPEN_MAX));
//로그인명 최대 바이트 길이
printf("Max Login Name Length : %ld\n", sysconf(_SC_LOGNAME_MAX));
return 0;
}
- 파일과 디렉토리 관련 자원 검색 : fpathconf(3), pathconf(3)
#include <unistd.h>
long pathconf(const char *path, int name);
long fpathconf(int fildes, int name);
*path: 파일이나 디렉토리 경로
*name: 검색할 정보를 지정하는 상수
*filedes: 파일 기술자
pathconf 함수는 path에 지정한 파일이나 디렉토리와 관련해 설정된 자원값이나 옵션값을 리턴한다. fpathconf함수는 파일기술자를 이용해 검색한다.
name상수는 sys/unistd.h 파일에 정의되어 있다.
상수 | 설명 |
---|---|
_PC_LINK_MAX(1) | 디렉토리 혹은 파일 하나에 가능한 최대 링크수를 나타냄 |
_PC_NAME_MAX(4) | 파일명의 최대 길이를 바이트 크기로 나타냄 |
_PC_PATH_MAX(5) | 경로명의 최대 길이를 바이트 크기로 나타냄 |
- pathconf함수로 현재 디렉토리 최대 링크수와 디렉토리명의 최대길이, 경로의 최대 길이를 검색할 수 있다.
#include <unistd.h>
#include <stdio.h>
int main(void){
printf("Link Max : %ld/n", pathconf(".", _PC_LINK_MAX));
printf("Name Max : %ld/n", pathconf(".", _PC_NAME_MAX));
printf("Path Max : %ld/n", pathconf(".", _PC_PATH_MAX));
return 0;
}
4-3. 사용자관련 정보 검색
유닉스 시스템에서 사용자 관련정보로는 각 사용자에 대한 정보, 그룹에 대한 정보, 로그인 기록정보가 있다.
패스워드 파일(/etc/passwd)와 섀도우 파일(/etc/shadow), 그룹파일(/etc/group), 로그인 기록 파일(/var/adm/utmpx)이다.
4-3-1. 로그인명과 UID검색
사용자 관련 정보중 가장 기본적인 것이 로그인명이다. 로그인명마다 지정되는 사용자아이디또한 기본정보이다. 사용자 계정 등록시 로그인명과 사용자 아이디(UID, User ID)가 지정된다.
- 로그인명 검색: getlogin(3)
#include <unistd.h>
char *getlogin(void);
getlogin 함수는 /var/adm/utmpx 파일을 검색해 현재 프로세스를 실행한 사용자의 로그인명을 찾아 리턴한다.
void는 인자로 아무것도 지정하지 않음을 의미한다.
만약 프로세스를 실행한 사용자가 로그아웃하거나 rsh(remote shell) 등으로 원격에서 실행한 프로세스에서getlogin 함수를 호출하면 사용자명을 찾지 못하고 널 포인터를 리턴하므로 주의해야한다.
- 로그인 명 검색 : cuserid(3)
#include <stdio.h>
char *cuserid(char *s);
*s 검색한 로그인명을 저장할 주소
cuserid 함수는 현재 프로세스의 소유자 정보로 로그인명을 찾아 리턴한다.
인자로 지정한 s가 널 포인터이면 메모리를 내부적으로 할당해서 로그인명을 저장하고 그 주소를 리턴한다.
사용자 명을 찾지 못하면 널 포인터를 리턴한다.
- uid 검색: getuid(2), geteuid(2)
#include <sys/type.h>
#include <unistd.h>
uid_t getuid(void);
uid_t geteuid(void);
getuid는 현재 프로세스의 실제 사용자 id, geteuid는 유효 사용자id를 리턴한다.
두 함수 모두 인자를 받지 않는다.
유닉스 시스템에서 프로세스 관련 UID는 두가지 이다.
Real User ID : 로그인할 때 사용한 로그인명에 대응하는 UID이다. 프로그램을 실행하는 사용자
Effective ID : 프로세스에 대한 접근 권한을 부여할 때 사용한다. 처음 로그인할 때는 실제 사용자 ID와 유효사용자ID가 같지만, setuid가 설정된 프로그램을 실행하거나 다른 사용자ID 로 변경할 경우 유효 사용자 ID는 달라진다.
- getuid, geteuid 함수를 사용해 로그인명, UID, EUID를 검색하고, getlogin, cuserid로 로그인명을 검색해 출력하는 예제
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(void){
uid_t uid, euid;
char *name, *cname;
uid = getuid();
euid = geteuid();
name = getlogin();
cname = cuserid(NULL);
printf("Login Name = %s, %s UID = %d, EUID= %d\n", name, cname, (int)uid, (int)euid);
return 0;
}
* 실행시 결과값으로 UID와 EUID가 모두 0으로 나온다.
사용자를 변경하지 않았으므로 UID와 EUID가 모두 같다.
만약 이 실행파일에 setuid가 설정되어 있고, 일반 사용자가 실행한다면 결과는 달라질 것이다.
<실행 파일에 setuid를 설정하기>
#chmod 4755 ex4_6.out
*일반 사용자로 로그인하여 실행파일을 실행하면, UID는 프로그램을 실행한 일반 사용자의 ID를 출력하고, EUID는 setuid가 설정되어 있으므로, root의 UID인 0으로 나온다.
4-3-2. 패스워드 파일 검색
/etc/passwd 파일에는 로그인명, UID, GID, 사용자 홈디렉토리, 로그인 쉘 등의 사용자에 대한 기본적인 정보가 있다. 이들 정보를 검색하려면 /etc/passwd파일 관련 구조체와 함수를 알아야한다.
- /etc/passwd 파일의 구조
이 파일은 사용자 정보를 각 행에 저장하며, 각 행에는 콜론(:)으로 구분된 정보가 있다.
사용자 정보의 종류는 다음과 같다.
- 로그인 ID
- 패스워드
- UID
- GID
- 설명
- 홈디렉토리
- 로그인쉘
그룹ID의 상세정보는 /etc/group 파일을 보면 알 수 있다.
로그인 쉘이 '/bin/ksh'인 경우 콘쉘로 지정되어있음을 알 수 있다.
- passwd 구조체
/etc/passwd 파일의 정보를 읽어오려면 해당 구조체를 이용해야한다.
이 구조체는 pwd.h 파일에 정의되어있고, 각항목은 /etc/passwd 파일의 내용에 대응한다.
struct passwd{
char *pw_name; //로그인명
char *pw_passwd; //암호 (최근의 unix에서는 암호를 별도의 파일인 /etc/shadow 에 저장하므로 의미 없는 항목이다.
uid_t pw_uid; //UID
gid_t pw_gid; //기본 그룹 GID
char *pw_age; //사용안함
char *pw_comment; //사용안함
char *pw_gecos; // 사용자의 실명이나 기타 정보 저장
char *pw_dir; // 홈디렉토리 저장
char *pw_shell; // 로그인 쉘 저장
}
- UID로 passwd 파일 읽기 : getpwuid(3)
#include <pwd.h>
sturct passwd *getpwuid(uid_t uid);
*uid : 검색할 UID
이함수는 /etc/passwd 파일에서 uid를 찾아서 passwd 구조체에 결과를 저장하고 주소를 리턴한다.
만약에 uid에 해당하는 사용자를 찾지 못하면 널 포인터를 리턴한다.
- 현재 프로세스를 실행한 사용자의 UID를 검색하고, 이 UID를 사용해서 패스워드 파일에서 정보를 검색하기
#include <unistd.h>
#include <pwd.h>
int main(void){
struct passwd *pw;
pw = getpwuid(getuid());
printf("UID : %d\n", (int)pw->pw_uid);
printf("Login name : %s\n", pw->pw_name);
return 0;
}
- 이름으로 passwd 파일 읽기 : getpwnam(3)
#include <pwd.h>
struct passwd *getpwnam(const char *name);
*name: 로그인명
이 함수는 로그인명을 받아 /etc/passwd 파일에서 사용자 정보를 검색한다.
- /ect/passwd 파일을 순차적으로 읽기
#include <pwd.h>
struct passwd *getpwent(void); // /etc/passwd파일에서 사용자 정보를 순차적으로 읽어온다. 파일의 끝을 만나면 널포인터를 리턴한다.
void setpwent(void); // /etc/passwd 파일의 오프셋을 파일의 처음에 놓는다.
void endpwent(void); // /etc/passwd 파일을 닫는다.
struct passwd *fgetpwent(FILE *fp); // 파일 포인터가 가리키는 파일에서 사용자 정보를 읽어온다. 그 파일의 내부구조는 /etc/passwd파일과 동일해야한다.
* fp : 파일 포인터
- getpwent 함수로 /etc/passwd 파일에서 사용자 정보 3개를 읽어 출력하는 예제
#include <pwd.h>
int main(void){
struct passwd *pw;
int n;
for(n=0;n<3;n++){
pw = getpwent();
printf("UID: %d, LoginName: %s\n", (int)pw->pw_uid, pw->pw_name); }
return 0;
}
* 만약 읽어온 사용자 정보를 저장하고 다른 처리를 하려면 passwd 구조체 변수를 별도로 선언하고 복사해야한다.
4-3-3. 섀도우 파일 검색
초기 유닉스 시스템은 사용자 계정의 패스워드 정보를 /etc/passwd 파일에 저장했다. 그러나 누구나 그 파일을 읽을 수 있으므로 보안문제가 발생할 수 있어 대부분의 유닉스 시스템은 /etc/shadow 파일에 사용자 패스워드 정보를 저장하고 있다. 이 정보를 검색하는 함수는 root 사용자만 실행할 수 있다.
- /etc/shadow 파일의 구조
이 파일은 사용자의 패스워드 정보를 각 행에 저장하며, 각행의 정보는 (:)으로 구분되어 있다.
shadow 사용자 정보의 종류
- 로그인ID
- 패스워드
- 최종 변경일
- min
- max
- warning
- inactive
- expire
- flag
- spwd 구조체
/etc/shadow 파일은 사용자 패스워드 정보와 패스워드의 주기 정보를 저장한다.
사용자 계정별로 한 행씩 저장하며 각 행은 (:)으로 구분된 정보가 있다.
이를 읽어오려면 spwd 구조체를 이용해야한다.
이 구조체는 shadow.h 파일에 있다.
sturct spwd {
char *sp_namp; //로그인명 저장
char *sp_pwdp; //사용자 계정의 패스워드를 13개 문자로 암호화해 저장한다.
int sp_lstchg; //패스워드를 변경한 날짜 정보이다. 1970년 1월 1일부터 일 수로 계산해 저장한다.
int sp_min; //변경된 패스워드를 사용해야하는 최소 일수.
int sp_max; //현재 패스워드를 사용할 수 있는 최대 일수
int sp_warn; //패스워드를 변경할 날이 되기 전에 경고를 시작하는 일수.
int sp_inact; //사용자 계정으로 로그인할 수 없는 일수
int sp_expire; //사용자 계정이 만료되는 날짜 정보. 1970년 1월 1일부터 일 수로 표시한다.
unsigned int sp_flag; //현재는 사용안함.
};
spwd 구조체의 각 항목은 /etc/shadow 파일의 내용에 대응한다.
- /etc/shadow 파일 검색 : getspnam(3)
#include <shadow.h>
struct spwd * getspnam(const char *name);
getspnam 함수는 인자로 지정한 사용자의 패스워드와 관련된 정보를 읽어온다.
- /etc/shadow 파일 순차적으로 읽기
#include <shadow.h>
struct spwd * getspent(void); // /etc/shadow 파일에서 패스워드 정보를 순차적으로 읽어온다.
void setspent(void); // /etc/shadow 파일의 오프셋을 파일의 처음으로 위치시킨다.
void endspent(void); // /etc/shadow 파일을 만든다.
struct spwd *fgetspent(FILE *fp); // 파일포인터로 지정한 다른 파일에서 패스워드 정보를 읽는다.
4-3-4. 그룹 정보 검색
유닉스 시스템에서는 하나이상의 그룹에 속한다. 그룹도 사용자와 마찬가지로 그룹명, 그룹ID(GID)가 있다. GID를 검색하는 함수로는 getgid와 getegid가 있다.
#include <sys/types.h>
#include <unistd.h>
gid_t getgid(void); //실제 그룹ID 반환
gid_t getegid(void); //유효 그룹 ID
실제 그룹ID (RGID, Real group ID)는 로그인할 때 사용한 사용자 계정의 기본 그룹이다.
유효 그룹ID (EGID, Effective Group ID)는 프로세스에 대한 접근권한을 부여할 때 사용한다.
4-3-5. 그룹 파일 검색
유닉스에서는 그룹의 정보를 /etc/group 파일에 별도로 저장한다. 사용자가 속한 그룹중 /etc/passwd파일의 GID 항목에 지정된 그룹이 기본 그룹이며 2차 그룹은 /etc/group 파일에서 지정한다.
- group 구조체
/etc/group 파일에 저장된 그룹 정보를 읽어오려면 group 구조체를 사용해야 한다.
이 구조체는
struct group{
char *gr_name; //그룹명
char *gr_passwd; //그룹 패스워드. 보통은 공백이다. 만약 패스워드를 지정하면 사용자 패스워드처럼 암호화된 문자가 저장된다. 그룹 패스워드를 설정하는 명령은 없으므로 사용자 패스워드 파일에서 복사해서 삽입해야한다. 만약 그룹 패스워드가 지정되어있으면 사용자가 newgrp 명령을 사용해 다른 그룹으로 변경할 때 이 패스워드를 입력해야한다.
gid_t gr_gid; // 그룹ID 번호를 저장한다.
char **gr_mem; //그룹의 멤버인 로그인명을 저장한다. 문자열을 가리키는 포인터이다.
}
- /etc/group 파일 검색
#include <grp.h>
struct group *getgrnam(const char *name); //검색하려는 그룹명을 읽어온다.
struct group *getgrgid(git_t gid); // 검색하려는 그룹의 ID를 읽어온다.
*name : 검색하려는 그룹명
*gid: 검색하려는 그룹의 ID
*검색한 그룹 정보는 group구조체에 저장하고 주소를 리턴한다.
- /etc/group 파일을 순차적으로 읽기
#include <grp.h>
struct group *getgrent(void); // /etc/group파일에서 그룹정보를 순차적으로 읽어온다.
void setgrent(void); // /etc/group 파일의 오프셋을 파일의 처음으로 위치시킨다.
void endgrent(void); // /etc/group 파일을 닫는다.
struct group *fgetgrent(FILE *fp); // 파일포인터로 지정한 다른 파일에서 그룹 정보를 읽어온다.
*fp:파일 포인터
4-3-6. 로그인 기록 검색
who 명령으로 현재 시스템에 로그인한 사용자에 대한 정보를 검색할 수 있다.
last 명령은 시스템의 부팅시각정보와 시스템 로그인 기록을 검색할 수 있다.
이러한 정보는 /var/adm/utmpx , /var/adm/wtmpx 파일에 저장된다.
솔라리스의 경우는 2.8부터는 utmpx, wtmpx 파일만 사용한다.
이 두 파일은 바이너리 형태로 되어있어서 vi같은 편집기로 확인이 안된다.
이들 파일에서 정보를 읽어올려면 파일의 구조와 관련된 구조체와 함수가 필요하다.
- utmpx 구조체
utmpx와wtmpx 파일은 구조가 동일하다. 이 두파일을 읽으려면 utmpx구조체를 사용한다.
이 구조체는
struct utmpx {
char ut_user[32]; //사용자명
char ut_id[4]; // /etc/inittab 파일에서 읽어온 ID
char ut_line[32]; // 사용자가 로그인한 장치명
pid_t ut_pid; //현재 실행 중인 프로세스의 ID
short ut_type; // 현재 읽어온 항목에 저장된 데이터의 형식. ut_type에 올 수 있는 값은 <utmp.h>에 상수로 정의되어 있다.
struct exit_status ut_exit; // 정보의 종류가 DEAD_PROCESS(종료한 프로세스)인 경우 프로세스의 종료상태를 저장한다. exit_status 구조체는 <utmp.h>에 정의되어 있다
struct timeval ut_tv; //해당 정보를 마지막으로 변경한 시각
int ut_session; //해당 번호의 세션 번호
int pad[5]; //추후 사용을 위해 예약해놓은 부분
short ut_syslen; //ut_host의 길이
char ut_host[257]; //원격 접속한 경우 원격 호스트명 저장
};
- /var/adm/utmpx 파일 순차적으로 읽기
#include <utmpx.c>
struct utmpx *getutxent(void); // /var/adm/utmpx파일에서 로그인 정보를 순차적으로 읽어온다.
void setutxent(void); // 해당 파일의 오프셋을 파일의 시작에 위치시킨다.
void endutxent(void); // 해당 파일을 닫는다 .
int utmpxname(const char *file); // 로그인 정보 파일을 file 파라미터로 지정한 다른 파일로 변경한다. 예를 들어 last 명령에서 사용하는 /var/adm/wtmpx 파일로 변경할 때 사용한다.
* file: 교체할 파일명
- getutxent 함수를 사용해 /var/adm/utmpx파일을 읽고 로그인명과 터미널 정보를 출력하는 예제
#include <sys/types.h>
#include <utmpx.h>
#include <stdio.h>
int main(void){
struct utmpx *utx;
printf("LoginName line\n");
printf("---------------\n");
while((utx=getutxent()) != NULL){
if(utx->ut_type != USER_PROCESS)
continue;
printf("%s %s\n", utx->ut_user, utx_ut_line);
}
return 0;
}
4-4. 시간 관리 함수
유닉스 시스템은 1970년 1월 1일 00:00:00(그리니치 표준시, UTC시간대)부터 현재까지 경과한 시간을 초단위로 저장하고 이를 기준으로 시간 정보를 관리한다.
이렇게 초단위로 저장된 시간을 그대로 활용하기도 하지만, 사람이 보기 편한 형태로 바꿔야할 때도 있다.
유닉스는 시간을 관리하는 다양한 함수를 제공한다.
4-4-1. 기본 시간 정보 확인
유닉스에서 현재 시간 정보를 구하는 기본 함수는 time이다. BSD에서 도입한 gettimeofday함수도 시간을 초단위로 알려준다.
- 초단위로 현재 시간 정보 얻기 : time(2)
#include <sys/types.h>
#include <time.h>
time_t time(time_t *tloc);
*tloc : 검색한 시간 정보를 저장할 주소
time함수는 1970년 1월 1일(UTC)부터 현재까지 경과한 시간을 초단위로 알려준다.
tloc가 널이 아니면 tloc가 가리키는 주소에 시간 정보를 저장하고 널이면 시간 정보를 리턴한다.
time함수는 실패하면 -1을 리턴한다.
- 마이크로 초단위로 시간 정보 얻기 : gettimeofday(3)
#include <sys/time.h>
int gettimeofday(struct timeval *tp, void *tzp);
int settimeofday(struct timeval *tp, void *tzp);
* tp: 시간 정보 구조체 주소
* tzp: 시간대
BSC 계열 유닉스에서 도입한 gettimeofday 함수는 시간 정보를 timeval구조체에 저장해 리턴한다.
tzp는 시간대를 나타내는 값으로 무시한다.
- timeval 구조체는 다음과 같이 초와 마이크로단위로 시간정보를 알려준다.
struct timeval {
time_t tv_sec; //초
suseconds_t tv_usec; //마이크로초
}
tp가 널이면 시간 정보를 읽어올 수 없다.
gettimeofday함수는 성공하면 0, 실패하면 -1을 리턴한다.
settimeofday 함수는 시간을 설정하는 함수이며, root권한으로 실행해야 한다.
- gettimeofday 함수를 사용해 시간 정보 읽기 예제
#include <sys/time.h>
#include <stdio.h>
int main(void){
struct timeval tv;
//두번째 인자는 NULL로 지정
gettimeofday(&tv, NULL);
printf("Time(sec) : %d\n", (int)tv.tv_sec);
//마이크로초단위로 출력
printf("Time(micro-sec) : %d\n", (int)tv.tv_usec);
return 0;
}
4-4-2. 시간대 정보
전세계 사람이 동일한 시간대를 사용하지 않는다. 영국의 그리니치 표준시를 기준으로 각 지역의 시차가 정해진다.
우리나라는 UTC보다 9시간 빠른 시간을 사용한다. SVR4 계열의 유닉스는 기본 시간대 정보를 환경변수 TZ에 설정한다.
시스템의 기본 시간대 정보는 /etc/default/init 파일에 'TZ=ROK'와 같은 형태로 지정되어 있다.
유닉스에서는 현재 지역의 시간대를 설정할 수 있는 함수를 제공한다.
- 시간대 설정 : tzset(3)
#include <time.h>
void tzset(void);
* 결과값이 저장되는 전역변수 4개
extern time_t timezone, altzone; // timezone은 UTC와지역시간대의 시차를 초단위로 저장한다. altzone은 UTC와 일광 절약제(DST, Daylight saving time) 등으로 보정된 지역 시간대와의 시차를 초단위로 저장한다.
extern int daylight; // 일광 절약제를 시행하면 0이 아니고, 그렇지 않으면 0이다.
extern char *tzname[2]; // 지역 시간대와 보정된 시간대를 약어로 저장한다.
이 함수는 현재 지역의 시간대로 시간대를 설정한다. 이함수를 호출하면 전역변수 4개에 정보가 설정된다.
- tzset함수 사용하기
#include <time.h>
#include <stdio.h>
int main(void){
//시간대를 현재 지역 시간대로 설정한다.
tzset();
//전역변수에 설정된 시간대 정보를 출력한다.
printf("Timezone : %d\n", (int)timezone);
printf("Altzone : %d\n", (int)altzone);
printf("Daylight : %d\n, daylight);
printf("TZname[0] : %s\n", tzname[0]);
printf("TZname[1] : %s\n", tzname[1]);
return 0;
}
* 실행결과를 보면 우리나라의 표준시는 UTC와 32,499초(9시간)차이가 난다.
`987년과 1988년에 1시간 일광절약제를 실행한적이 있어 일광 절약제를 실시할 경우 UTC와 1시간 더 차이가 난다. 표준 시간대의 이름은 KST이다.
4-4-3. 시간의 형태 변환
초단위 시간을 사람이 이해할 수 있게 변환해주는 함수가 있다.
- 시간 정보 분해 : tm 구조체
초단위 시간을 년, 월, 일로 분해해 저장할 때 tm 구조체를 사용한다. 이 구조체는 iso/time_iso.h 에 정의되어있다.
sturct tm {
int tm_sec //초
int tm_min;
int tm_hour;
int tm_mday // 일
int tm_mon //월(0~11) 0은 1월 11은 12월이다.
int tm_year; //년도 - 1900 값을 리턴하므로 1900값을 리턴값에 더해야 실제 년도를 출력할 수 있다.
int tm_wday; //요일(0~6)
int tm_yday; //일수 (0~365)
int isdst; //일광절약제 시행여부, 1이면 일광절약제 실시중임을 의미한다.
}
- 초단위 시간 정보 분해
include <time.h>
struct tm *localtime(const time_t *clock);
struct tm *gmtime(const time_t *clock);
* clock : 초 단위 시간 정보를 저장한 주소
이 함수들은 모두 초 단위 시간 정보를 인자로 받아 tm구조체 형태로 리턴한다.
gmtime 함수는 UTC 시간대를 기준으로 시간을 분해한다.
localtime 함수는 gmtime과 같은 결과를 산출하지만, UTC 대신 지역 시간대를 기준으로 시간을 처리한다.
- time함수로 초 단위 시간을 구한 후 이를 gmtime, localtime함수로 분해해 출력하는 예제.
#inlcude <time.h>
#include <stdio.h>
int main(void){
struct tm *tm;
time_t t;
time(&t);
printf("Time(sec) : %d\n", (int)t);
tm = gmtime(&t);
printf("GMTIME = Y:%d ", tm->tm_year);
printf("M:%d ", tm->tm_mon);
printf("D:%d ", tm->tm_mday);
printf("H:%d ", tm->tm_hour);
printf("M:%d ", tm->tm_min);
printf("S:%d\n", tm->tm_sec);
tm = localtime(&t);
printf("LOCALTIME=Y:%d ", tm->tm_year);
printf("M:%d ", tm->tm_mon);
printf("D:%d ", tm->tm_mday);
printf("H:%d ", tm->tm_hour);
printf("M:%d ", tm->tm_min);
printf("S:%d\n", tm->tm_sec);
return 0;
}
* 실행결과를 보면 년도(Y)가 109이므로 1900+109= 2009년임을 알 수 있다.
월(M)이 0이면 1월을 의미한다.
시간을 보면 gmtime의 결과는 2, localtime의 결과는 11로 9시간 차이나는 것을 알 수 있다.
- 초단위 시간으로 역산 : mktime(3)
#include <time.h>
time_t mktime(struct tm *timeptr);
*timeptr : 시간 정보를 저장한 tm 구조체 주소
이 함수는 gmtime이나localtime함수와 반대 역할을 수행한다. tm구조체형태의 시간을 인자로 받아 1970년 1월 1일(UTC)로부터 얼마나 시간이 지났는지 초단위로 계산해 리턴한다.
4-4-4.형식 지정 시간 출력
time함수로 구한 초단위 시간 정보나 gmtime, localtime함수로 구한 tm구조체 시간정보를 사람이 알아보기 쉬운 형태로 변환해주는 함수
- 초단위 시간을 변환해 출력하기 : ctime
#include <time.h>
char * ctime(const time_t *clock);
* clock : 초단위 시간 정보를 저장한 주소
* return : 요일 월 일 시:분:초 년도
이 함수는 초단위 시간을 인자로 받아 사람이 보기 편한 형태로 변환해 문자열로 리턴한다.
- tm 구조체 시간을 변환해 출력하기 : asctime(3)
#include <time.h>
char *asctime(const struct tm *tm);
* tm : 시간정보를 저장한 tm 구조체 주소
asctime함수는 tm구조체로 분해된 시간을 인자로 받고, 사람이 보기 편한 형태로 변경해 문자열로 리턴한다. 출력되는 형태는 ctime의 출력형태와 동일하다.
- 출력 형식 기호를 사용해 출력하기 : strftime(3)
printf처럼 형식을 지정해서 시간 정보를 출력할 수 있다.
#inculde <time.h>
size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr);
* s : 출력할 시간 정보를 저장할 배열 주소
* maxsize : s의 크기
* format : 출력형식을 저장할 문자열
* timeptr : 출력할 시간 정보를 저장한 구조체 주소
timeptr이 가리키는 tm구조체에 저장된 시간정보를 format에 지정한 출력 형식에 따라 변환해 s가 가리키는 배열에 저장한다. maxsize는 배열 s의 크기다.
- strftime 함수로 시간의 출력형식 지정
#include <time.h>
#include <stdio.h>
char *output[]={
"%x %X",
"%G년, %m월 %d일%U주 %H:%M",
"%r"
};
int main(void){
struct tm *tm;
int n;
time_t t;
char buf[257];
time(&t);
tm = localtime(&t);
//미리 정의된 출력 형식 지정자에 따라 buf에 문자열을 생성하고 출력한다.
for(n=0; n<3; n++){
strftime(buf, sizeof(buf), output[n], tm);
printf("%s = %s\n", output[n], buf);
}
return 0;
}
* 실행결과를 보면 출력 형식 지정자별로 어떻게 출력했는지 알 수 있다.
output 배열의 두번째 형식 지정자에서 기호에 해당하지 않는 문자는 문자 그대로 출력된다.