#include <unistd.h>
char *getcwd(char *buf, size_t bufsize);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
int main(int argc, char *argv[]){
char buf[PATH_MAX];
// getcwd() 함수로 현재 작업 디렉터리의 경로 가져옴
if (!getcwd(buf, PATH_MAX)){ // 성공 시 0 반환
perror("getcwd");
exit(1);
}
puts(buf); // buf에 저장된 문자열을 출력
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define INIT_BUFSIZE 1024
char* my_getcwd(void){
char *buf, *tmp;
size_t size = INIT_BUFSIZE;
buf = malloc(size);
if (!buf) return NULL;
for (;;) {
errno = 0;
if (getcwd(buf, size))
return buf;
if (errno != ERANGE) break;
size *= 2;
tmp = realloc(buf, size);
if (!tmp) break;
buf = tmp;
}
free(buf);
return NULL;
}
int main(int argc, char *argv[]){
char *path;
path = my_getcwd();
if (!path){
perror("getcwd");
exit(1);
}
puts(path);
free(path);
exit(0);
}
#include <unistd.h>
int chdir(const char *path);
/proc/[PID]/cwd
을 사용하는 방법이 있다.#include <stdio.h>
#include <stdlib.h>
extern char **environ; // 환경 변수를 가리키는 전역 변수
int main(int argc, char *argv[]){
char **p;
for (p = environ; *p; p++){
// environ은 문자열 포인터 배열이고 끝은 널 포인터
printf("%s\n", *p);
}
exit(0);
}
#include <stdlib.h>
char *getenv(const char *name);
#include <stdlib.h>
int putenv(char *string);
이름=값
의 형식이어야 한다.passwd 명령어와 같이 특정 사용자의 권한으로 실행하고 싶은 경우가 있다.
그러나 암호를 변경하기 위해 모든 사용자에게 쓰기 권한을 부여할 수는 없다.
따라서 특정 프로그램에 set-uid 비트를 설정하여 실행한 사용자와 관계없이 프로그램 파일의 소유자 권한으로만 실행되도록 한다.
passwd 명령어를 ls -l 하여 소유자의 권한을 살펴보자.
$ ls -l /usr/bin/passwd
수행 결과는 다음과 같다.
rwx
에서 x
가 s
로 바뀌어 있다. 이것이 set-uid 비트가 설정되었다는 표시다.#include <unistd.h>
#include <sys/types.h>
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);
#include <unistd.h>
#include <sys/types.h>
int getgroups(int bufsize, gid_t *buf);
#include <unistd.h>
#include <sys/types.h>
int setuid(uid_t id);
int setgid(gid_t id);
#define _BSD_SOURCE
#include <grp.h>
#include <sys/types.h>
int initgroups(const char *user, gid_t group);
- 슈퍼 사용자, root로서 프로그램을 시작한다.
- 원하는 사용자의 사용자명과 ID, 그룹 ID를 얻는다.
- setgid([변경할 그룹 ID])
- initgroups([변경할 사용자명], [그룹 ID])
- setuid([변경할 사용자 ID])
#include <pwd.h>
#include <sys/types.h>
struct passwd *getpwuid(uid_t id);
struct passwd *getpwnam(const char *name);
struct passwd{
char *pw_name; /* 사용자 이름 */
char *pw_passwd; /* 패스워드 */
uid_t pw_uid; /* 사용자 ID */
gid_t pw_gid; /* 그룹 ID */
char *pw_gecos; /* 본명 */
char *pw_dir; /* 홈 드렉터리 */
char *pw_shell; /* 셸 */
};
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
int main(int argc, char *argv[]){
// argv: 명령 인자로 사용자 이름을 받음
struct passwd *pw;
if (argc < 2){
fprintf(stderr, "no argument\n");
exit(1);
}
// 사용자 이름이 argv인 사용자 정보를 얻음
pw = getpwnam(argv[1]);
if (!pw){
perror(argv[1]);
exit(1);
}
// 반환한 사용자 정보 구조체에서 uid를 출력
printf("id=%d\n", pw->pw_uid);
exit(0);
}
#include <grp.h>
#include <sys/types.h>
struct group *getgrgid(gid_t id);
struct group *getgrnam(const char *name);
struct group{
char *gr_name; /* 그룹명 */
char *gr_passwd; /* 그룹 패스워드 */
gid_t gr_gid; /* 그룹 ID */
char **gr_mem; /* 그룹에 속하는 멤버(사용자명 리트스) */
};
#include <sys/time.h>
#include <sys/resource.h>
int getrusage(int who, struct rusage *usage);
getrusage()는 프로세스의 리소스 사용량을 usage에 저장한다.
who가 RUSAGE_SELF
인 경우 현재 프로세스의 리소스 사용량을 기록하고 RUSAGE_CHILDREN
이라면 자식 프로세스의 리소스 사용량을 기록한다.
이 때 자식 프로세스는 현재 프로세스에서 fork()한 모든 자식 프로세스 중에서 wait() 중인 것을 의미한다.
struct rusage는 많은 멤버 필드가 있는데 다음과 같다.
#include <time.h>
time_t time(time_t *tptr);
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
struct timeval{
time_t tv_sec; /* 초 */
suseconds_t tv_usec; /* 마이크로초 */
};
#include <time.h>
struct tm *localtime(const time_t *timep);
struct tm *gmtime(const time_t *timep);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <locale.h>
int main(int argc, char *argv[]){
time_t t;
struct tm *tm;
struct timeval tv;
setlocale(LC_TIME, "");
/* time(2), ctime(3), gettimeofday(2) */
time(&t);
gettimeofday(&tv, NULL);
printf("time = %ld\n", (long)t);
printf("ctime = %s", ctime(&t));
printf("tv.tv_sec = %ld\n", (long)tv.tv_sec);
printf("tv.tv_usec = %ld\n", (long)tv.tv_usec);
printf("ctime(tv) = %s", ctime(&tv.tv_sec));
/* gmtime(3), localtime(3) */
tm = gmtime(&t);
printf("asctime(UTC) = %s", asctime(tm));
printf("mktime(UTC) = %ld\n", (long)t);
tm = localtime(&t);
printf("asctime(LOC) = %s", asctime(tm));
printf("mktime(LOC) = %ld\n", (long)t);
exit(0);
}
#include <time.h>
time_t mktime(struct tm *tm);
#include <time.h>
char *asctime(const struct tm *tm);
char *ctime(const time_t *timep);
Sat Sep 25 00:43:37 2017\n
과 같은 형식의 문자열로 변환하여 반환한다.#include <time.h>
size_t strftime(char *buf, size_t bufsize, const char *fmt, const stuct tm *tm);
strftime()은 tm으로 지정한 시간을 fmt에 따라 포맷하고 buf에 저장한다.
fmt는 printf()와 비슷하게 구성하여 출력하고 싶은 시간의 요소를 ['%'+1 문자]로 지정한다.
사용할 수 있는 형식 지정 문자 중 중요한 것은 다음과 같다.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <locale.h>
#include <string.h>
int main(int argc, char *argv[]){
time_t t;
struct tm *tm;
char *fmtchars = "aAbBcCdDeFgGhHIjklmMnOpPrRsStTuUVwWxXyYzZ+";
char *p;
char *opt_E = "cCxXyY";
char *opt_O = "deHImMSuUvwWy";
setlocale(LC_ALL, "");
time(&t);
tm = localtime(&t);
for (p = fmtchars; *p; p++){
char fmt[16];
char buf[256];
printf("%%%c=", *p);
fmt[0] = '"';
fmt[1] = '%';
fmt[2] = *p;
fmt[3] = '"';
fmt[4] = '\0';
if (strftime(buf, sizeof buf, fmt, tm) == 0)
puts("FAILED");
else
puts(buf);
if (strchr(opt_E, *p)){
printf("%%E%c=", *p);
fmt[0] = '"';
fmt[1] = '%';
fmt[2] = 'E';
fmt[3] = *p;
fmt[4] = '"';
fmt[5] = '\0';
if (strftime(buf, sizeof buf, fmt, tm) == 0)
puts("FAILED");
else
puts(buf);
}
if (strchr(opt_O, *p)){
printf("%%O%c=", *p);
fmt[0] = '"';
fmt[1] = '%';
fmt[2] = 'O';
fmt[3] = *p;
fmt[4] = '"';
fmt[5] = '\0';
if (strftime(buf, sizeof buf, fmt, tm) == 0)
puts("FAILED");
else
puts(buf);
}
}
exit(0);
}
2017-08-09T14:45:31+09:00
- 연도는 항상 4자리
- 월, 일, 시, 분, 초는 항상 0을 채움으로 2자리
- 연월일의 구분 문자는
/
가 아닌-
- 날짜와 시간 사이는
T
가 들어감- 시는 항상 24시간제
- UTC와의 시차를
+09:00
과 같은 형식으로 추가
:
을 추가하면 된다.
- systemd 또는 init이 단말 수만큼 getty 명령어를 기동
- getty 명령어는 단말로부터 사용자 이름을 입력하는 것을 기다려, login 명령어를 시작
- login 명령어가 사용자를 인증
- 셸을 시작
/etc/passwd
이다./etc/passwd
에 직접 쓰지 않고 /etc/shadow
로 분리하는 섀도 패스워드가 도입되어 있다.
- 패스워드 종류, 문자 수 제한, 암호화 방법
- 로그인할 수 있는 날짜나 시간의 제한
- 로그인 할 수 있는 사용자 제한
/etc/login.defs
에서 설정하게 되어있다.execl("/bin/sh", "-sh", ...);
/var/run/utmp
에 있다. 명령어 수행 결과는 다음과 같다./var/log/wtmp
에 있다./var/log/lastlog
도 있다.