728x90

시스템프로그래밍 5주차에는 시스템 정보에 관하여 배운다.

 

MAC에서는 사용자 전환이 잘 안되어서... groom으로 진행하겠습니다.

 

  • 시스템 정보

시스템에 설치된 운영체제에 관한 정보, 호스트명 정보, 하드웨어 종류에 대한 정보 등을 얻는 방법을 알아보자.

 

uname

shell에 uname을 사용하면 시스템의 기본 정보를 출력한다.

system call로 알아보자

#include <sys/utsname.h>

int uname(struct utsname *buf);

-buf

읽은 정보를 저장할 utsname 구조체의 포인터

return: 0(success), -1(error)

 

여기에 들어가는 utsname 구조체에 대해 살펴보면

struct  utsname {
	char    sysname[_SYS_NAMELEN];  /* [XSI] Name of OS */
	char    nodename[_SYS_NAMELEN]; /* [XSI] Name of this network node */
	char    release[_SYS_NAMELEN];  /* [XSI] Release level */
	char    version[_SYS_NAMELEN];  /* [XSI] Version level */
	char    machine[_SYS_NAMELEN];  /* [XSI] Hardware type */
};

이고 이 구조체를 이용하여 시스템의 기본 정보를 가져오는 코드를 작성해보자.

#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.sysname);
	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;
}

sysinfo

sysinfo를 사용해서 다른 정보들을 가져올 수도 있다.

#include <sys/sysinfo.h>

int sysinfo(struct sysinfo *info);

-info

읽은 정보를 저장할 sysinfo 구조체의 포인터

return: 0(success), -1(error)

 

sysconf

#include <unistd.h>

long sysconf(int name);

-name

검색할 정보를 지칭하는 상수

return: 요청한 정보의 값, -1(error)

 

이번엔 리소스의 정보를 가져오는 system call이다.

 

상수의 예

상수 설명
_SC_ARG_MAX(1) argv[]와 envp[]를 합한 최대 크기로, 바이트 단위로 표시한다.
_SC_CHILD_MAX(2) 한 UID에 허용되는 최대 프로세스 개수를 나타낸다.
_SC_CLK_TCK(3) 초당 클록 틱 수를 나타낸다.
_SC_OPEN_MAX(5) 프로세스당 열 수 있는 최대 파일 개수를 나타낸다.
_SC_VERSION(8) 시스템이 지원하는 POSIX.1의 버전을 나타낸다.
_SC_PASS_MAX(9) 패스워드의 최대 길이를 나타낸다.
_SC_LOGNAME_MAX(10) 로그인명의 최대 길이를 나타낸다.
_SC_PAGESIZE(11) 시스템 메모리의 페이지 크기를 나타낸다.

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_LOGIN_NAME_MAX));
	
	return 0;
}

  • 사용자 정보

사용자를 추가하거나 권한을 관리하는 방법들이다.

우선 shell에서 사용자(seungkyu)를 추가해보자.

sudo adduser [사용자 이름]을 입력하면 된다.

일단 이렇게 모두 디폴트로 설정을 하면 된다.

 

해당 사용자로 접근을 해보자.

su [사용자 이름] 명령어를 사용하면 해당 사용자로 접근할 수 있다.

exit로 나갈 수 있다.

UID는 그 사용자에게 부여된 ID 번호이며, Login name은 문자 형태의 사용자 이름이다.

이렇게 id [사용자 이름]으로 확인 할 수 있다.

Process에 입장 할 때의 사용자에 대해 알아보자.

- Real user ID

최초에 Process를 실행한 user의 UID

- Effective user ID

현재 Process가 행사하는 UID

- Saved user ID

Process의 최초의 effective user ID

 

Effective User ID는 기본적으로는 Real UID와는 같다, 실행 파일의 setuid bit가 1인 경우 해당 파일 소유자의 UID가 effective UID가 된다.

 

Getting/Setting user IDs

#include <unistd.h>
#include <sys/types.h>

uid_t getuid(void);
uid_t geteuid(void);

return: 얻으려고 하는 uid

uid와 euid를 반환 받는 getuid와 geteuid 함수이다.

 

#include <sys/types.h>
#include <unistd.h>

int seteuid(uid_t uid);

Process의 EUID를 설정할 수 있는 seteuid 함수이다.

 

바로 실습으로 가보도록 하자.

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main(void){
	uid_t uid, euid;

	uid = getuid();
	euid = geteuid();
	printf("[Init] UId = %d, EUID = %d\n", (int)uid, (int)euid);

	seteuid(getuid());
	int cur_euid = (int)geteuid();
	printf("[seteuid(uid)] UID = %d, EUID = %d\n", (int)uid, (int)cur_euid);

	seteuid(euid);
	cur_euid = (int)geteuid();
	printf("[seteuid(euid)]UID = %d, EUID = %d\n", (int)uid, (int)cur_euid);

	return 0;
}

이렇게 프로세스 내에서의 userID 변동을 살펴 볼 수 있다.

 

User information

우선 /etc/passwd 라는 파일을 한 번 보도록 하자.

이렇게 사용자들의 정보가 쭉 나온다.

LoginID:PassWord:UID:GID:UserInfo:HomeDir의 정보로 출력이 된다.

 

당연히 시스템 콜에서도 사용자의 정보를 불러 올 수 있고, 사용자에 대한 구조체가 존재한다.

struct passwd {
	char	*pw_name;		/* user name */
	char	*pw_passwd;		/* encrypted password */
	uid_t	pw_uid;			/* user uid */
	gid_t	pw_gid;			/* user gid */
	char	*pw_gecos;		/* Honeywell login info */
	char	*pw_dir;		/* home directory */
	char	*pw_shell;		/* default shell */
};

이렇게 존재한다.

 

Reading the passwd file

#include <sys/types.h>
#include <pwd.h>

struct passwd *getpwnam(const char *name);
struct passwd *getpwuid(uid_t uid);

passwd 파일을 가져오는 함수들이다.

-name

passwd file에서 정보를 읽어올 사용자의 이름

-uid

passwd file에서 정보를 읽어올 사용자의 uid

return: 해당 사용자에 대한 passwd structure가 저장된 pointer, -1(NULL)

 

#include <sys/types.h>
#include <pwd.h>
#include <stdio.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;
}

uid로 사용자를 불러온 모습이다.

 

Reading the group file

#include <sys/types.h>
#include <grp.h>

struct group *getgrname(const char *name);
struct group *getgrgid(gid_t gid);

struct group *getgrent(void);
void setgrent(void);
void endgrent(void);

사용자 뿐만 아니라 그룹에 대한 정보도 가져올 수 있다.

위와 비슷하고 그룹이란 것만 변경이 되었기 때문에 바로 실습으로 가보도록 하겠다.

 

group의 구조체는 아래와 같다.

struct group {
	char	*gr_name;		/* [XBD] group name */
	char	*gr_passwd;		/* [???] group password */
	gid_t	gr_gid;			/* [XBD] group id */
	char	**gr_mem;		/* [XBD] group members */
};

 

그룹에 대한 정보를 읽어오는 프로그램을 만들어보자.

 

#include <stdio.h>
#include <stdlib.h>
#include <grp.h>

int main(void){
	struct group *grp;

	grp = getgrnam("root");
	printf("Group Name : %s\n", grp->gr_name);
	printf("GID : %d\n", (int)grp->gr_gid);


	return 0;
}

그룹의 이름을 이용해 정보를 가져왔다.

  • 시간 정보

리눅스의 시간은 1970년 1월 1일 0시 0분 0초를 기준으로 흘러가며 현재까지 경과한 시간을 초 단위로 저장한다.

 

Getting time

#include <sys/time.h>

time_t time(time_t *tloc);

-tloc

얻어올 초를 저장할 주소

return: 얻어온 초, -1(error)

 

하지만 이렇게 얻어온 시간은 흘러간 초로 표현이 되기 때문에 읽기가 매우 힘들다.

그래서 이 time_t를 우리가 보기 편한 시간으로 보여주는 함수가 있고 그 시간을 저장하는 구조체가 있다.

 

우선 해당 구조체부터 살펴보자면

struct tm {
	int	tm_sec;		/* seconds after the minute [0-60] */
	int	tm_min;		/* minutes after the hour [0-59] */
	int	tm_hour;	/* hours since midnight [0-23] */
	int	tm_mday;	/* day of the month [1-31] */
	int	tm_mon;		/* months since January [0-11] */
	int	tm_year;	/* years since 1900 */
	int	tm_wday;	/* days since Sunday [0-6] */
	int	tm_yday;	/* days since January 1 [0-365] */
	int	tm_isdst;	/* Daylight Savings Time flag */
};

이렇게 연부터 초들이 들어가게 되고

 

Seconds <-> tm struct

#include <time.h>

struct tm *gmtime(const time_t *timep);
struct tm *localtime(const time_t *timep);

time_t mktime(struct tm *tm);

-*timep

변환하려는 time_t 구조체

return: 변환된 tm 구조체

 

-tm

변환하려는 tm 구조체

return: 변환된 time_t 구조체

 

변환하여 출력해보자.

#include <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;
}

이렇게 tm과 time_t 간에 변환이 된 모습이다.

+ Recent posts