2011. 9. 8. 05:37
Posted by devanix
2011. 9. 3. 22:35

재시작 라이브러리(restart library)는 순간적인 사건으로 요청한 작업을 완료하지 못했을 경우

스스로 재시작할 수 있는 함수들의 집합이다.

 

재시작 라이브러리는 시그널에 의한 중단과 불완전한 I/O 두 부분에 중점을 두고 있다.

예를 들어 read, write와 같은 라이브러리 함수들은 I/O 명령을 완전히 실행하기 전에

시그널에 의해 중단될 때 -1을 리턴하고, errno를 EINTR로 설정한다.

 

이러한 중단은 실제로 에러 상황이 아닌 프로그램이 블로킹 I/O를 사용할 때 시그널의 처리를 위한 자연스러운

사건이다. 함수가 -1을 리턴하고, errno가 EINTR로 설정된 경우 재시작 함수는 재시작 과정을 수행한다.

 

[ restart.c ]

/data/workspace/b-example/usp/appendixB/restart.c.html
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/wait.h>
#include "restart.h"
#define BLKSIZE PIPE_BUF
#define MILLION 1000000L
#define D_MILLION 1000000.0

/* Private functions */

static int gettimeout(struct timeval end,
                               struct timeval *timeoutp) {
   gettimeofday(timeoutp, NULL);
   timeoutp->tv_sec = end.tv_sec - timeoutp->tv_sec;
   timeoutp->tv_usec = end.tv_usec - timeoutp->tv_usec;
   if (timeoutp->tv_usec >= MILLION) {
      timeoutp->tv_sec++;
      timeoutp->tv_usec -= MILLION;
   }
   if (timeoutp->tv_usec < 0) {
      timeoutp->tv_sec--;
      timeoutp->tv_usec += MILLION;
   }
   if ((timeoutp->tv_sec < 0) ||
       ((timeoutp->tv_sec == 0) && (timeoutp->tv_usec == 0))) {
      errno = ETIME;
      return -1;
   }
   return 0;
}

/* Restart versions of traditional functions */

int r_close(int fildes) {
   int retval;
   while (retval = close(fildes), retval == -1 && errno == EINTR) ;
   return retval;
}

int r_dup2(int fildes, int fildes2) {
   int retval;
   while (retval = dup2(fildes, fildes2), retval == -1 && errno == EINTR) ;
   return retval;
}


int r_open2(const char *path, int oflag) {
   int retval;
   while (retval = open(path, oflag), retval == -1 && errno == EINTR) ;
   return retval;
}

int r_open3(const char *path, int oflag, mode_t mode) {
   int retval;
   while (retval = open(path, oflag, mode), retval == -1 && errno == EINTR) ;
   return retval;
}

ssize_t r_read(int fd, void *buf, size_t size) {
   ssize_t retval;
   while (retval = read(fd, buf, size), retval == -1 && errno == EINTR) ;
   return retval;
}

pid_t r_wait(int *stat_loc) {
   pid_t retval;
   while (((retval = wait(stat_loc)) == -1) && (errno == EINTR)) ;
   return retval;
}

pid_t r_waitpid(pid_t pid, int *stat_loc, int options) {
   pid_t retval;
   while (((retval = waitpid(pid, stat_loc, options)) == -1) &&
           (errno == EINTR)) ;
   return retval;
}

ssize_t r_write(int fd, void *buf, size_t size) {
   char *bufp;
   size_t bytestowrite;
   ssize_t byteswritten;
   size_t totalbytes;

   for (bufp = buf, bytestowrite = size, totalbytes = 0;
        bytestowrite > 0;
        bufp += byteswritten, bytestowrite -= byteswritten) {
      byteswritten = write(fd, bufp, bytestowrite);
      if ((byteswritten == -1) && (errno != EINTR))
         return -1;
      if (byteswritten == -1)
         byteswritten = 0;
      totalbytes += byteswritten;
   }
   return totalbytes;
}

/* Utility functions */

struct timeval add2currenttime(double seconds) {
   struct timeval newtime;

   gettimeofday(&newtime, NULL);
   newtime.tv_sec += (int)seconds;
   newtime.tv_usec += (int)((seconds - (int)seconds)*D_MILLION + 0.5);
   if (newtime.tv_usec >= MILLION) {
      newtime.tv_sec++;
      newtime.tv_usec -= MILLION;
   }
   return newtime;
}

int copyfile(int fromfd, int tofd) {
   int bytesread;
   int totalbytes = 0;

   while ((bytesread = readwrite(fromfd, tofd)) > 0)
      totalbytes += bytesread;
   return totalbytes;
}

ssize_t readblock(int fd, void *buf, size_t size) {
   char *bufp;
   ssize_t bytesread;
   size_t bytestoread;
   size_t totalbytes;

   for (bufp = buf, bytestoread = size, totalbytes = 0;
        bytestoread > 0;
        bufp += bytesread, bytestoread -= bytesread) {
      bytesread = read(fd, bufp, bytestoread);
      if ((bytesread == 0) && (totalbytes == 0))
         return 0;
      if (bytesread == 0) {
         errno = EINVAL;
         return -1;
      }
      if ((bytesread) == -1 && (errno != EINTR))
         return -1;
      if (bytesread == -1)
         bytesread = 0;
      totalbytes += bytesread;
   }
   return totalbytes;
}

int readline(int fd, char *buf, int nbytes) {
   int numread = 0;
   int returnval;

   while (numread < nbytes - 1) {
      returnval = read(fd, buf + numread, 1);
      if ((returnval == -1) && (errno == EINTR))
         continue;
      if ((returnval == 0) && (numread == 0))
         return 0;
      if (returnval == 0)
         break;
      if (returnval == -1)
         return -1;
      numread++;
      if (buf[numread-1] == '\n') {
         buf[numread] = '\0';
         return numread;
      }
   }
   errno = EINVAL;
   return -1;
}

ssize_t readtimed(int fd, void *buf, size_t nbyte, double seconds) {
   struct timeval timedone;

   timedone = add2currenttime(seconds);
   if (waitfdtimed(fd, timedone) == -1)
      return (ssize_t)(-1);
   return r_read(fd, buf, nbyte);
}

int readwrite(int fromfd, int tofd) {
   char buf[BLKSIZE];
   int bytesread;

   if ((bytesread = r_read(fromfd, buf, BLKSIZE)) < 0)
      return -1;
   if (bytesread == 0)
      return 0;
   if (r_write(tofd, buf, bytesread) < 0)
      return -1;
   return bytesread;
}

int readwriteblock(int fromfd, int tofd, char *buf, int size) {
   int bytesread;

   bytesread = readblock(fromfd, buf, size);
   if (bytesread != size)         /* can only be 0 or -1 */
      return bytesread;
   return r_write(tofd, buf, size);
}

int waitfdtimed(int fd, struct timeval end) {
   fd_set readset;
   int retval;
   struct timeval timeout;

   if ((fd < 0) || (fd >= FD_SETSIZE)) {
      errno = EINVAL;
      return -1;
   }
   FD_ZERO(&readset);
   FD_SET(fd, &readset);
   if (gettimeout(end, &timeout) == -1)
      return -1;
   while (((retval = select(fd+1, &readset, NULL, NULL, &timeout)) == -1)
           && (errno == EINTR)) {
      if (gettimeout(end, &timeout) == -1)
         return -1;
      FD_ZERO(&readset);
      FD_SET(fd, &readset);
   }
   if (retval == 0) {
      errno = ETIME;
      return -1;
   }
   if (retval == -1)
      return -1;
   return 0;
}

 

[ restart.h ]

/data/workspace/b-example/usp/appendixB/restart.h.html
#ifndef __RESTART_H_
#define __RESTART_H_

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

#ifndef ETIME
#define ETIME ETIMEDOUT
#endif

struct timeval add2currenttime(double seconds);
int copyfile(int fromfd, int tofd);
int r_close(int fildes);
int r_dup2(int fildes, int fildes2);
int r_open2(const char *path, int oflag);
int r_open3(const char *path, int oflag, mode_t mode);
ssize_t r_read(int fd, void *buf, size_t size);
pid_t r_wait(int *stat_loc);
pid_t r_waitpid(pid_t pid, int *stat_loc, int options);
ssize_t r_write(int fd, void *buf, size_t size);
ssize_t readblock(int fd, void *buf, size_t size);
int readline(int fd, char *buf, int nbytes);
ssize_t readtimed(int fd, void *buf, size_t nbyte, double seconds);
int readwrite(int fromfd, int tofd);
int readwriteblock(int fromfd, int tofd, char *buf, int size);
int waitfdtimed(int fd, struct timeval end);

#endif /* __RESTART_H_ */

 

Posted by devanix
2011. 9. 3. 02:32

Catexit 함수는 사용자가 정의한 종료 핸들러를 등록한다.

종료 핸들러는 프로그램이 main 함수로부터 리턴 하거나 exit 함수를 호출하였을 때

마지막에 등록된 핸들러가 먼저 실행되는 순서로 실행. (여러 번 호출하여 핸들러 등록 가능)

 

 

showtimes 예제는 showtimes 함수를 exit 핸들러로 등록하여

프로그램과 그 자식들이 사용한 시간에 대한 통계를 표준 에러로 출력한다.

 

[ 예제 코드 : showtimes.c ]

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/times.h>
#include <sys/wait.h>

int wastetime(int maxus);

static void showtimes(void) {
   double ticks;
   struct tms tinfo;

   if ((ticks = (double) sysconf(_SC_CLK_TCK)) == -1)
      perror("Failed to determine clock ticks per second");
   else if (times(&tinfo) == (clock_t)-1)
      perror("Failed to get times information");
   else {
      fprintf(stderr, "User time:              %8.3f seconds\n",
         tinfo.tms_utime/ticks);
      fprintf(stderr, "System time:            %8.3f seconds\n",
         tinfo.tms_stime/ticks);
      fprintf(stderr, "Children's user time:   %8.3f seconds\n",
         tinfo.tms_cutime/ticks);
      fprintf(stderr, "Children's system time: %8.3f seconds\n",
         tinfo.tms_cstime/ticks);
   }
}
 
int main(void) {
   if (atexit(showtimes))  {
      fprintf(stderr, "Failed to install showtimes exit handler\n");
      return 1; 
   }
   if (fork())
      wastetime(2900000);
   else
      wastetime(5400000);
   if (wait(NULL) > 0)
      fprintf(stderr, "\nChild has exited, parent stats follow:\n");
   return 0;
}

times 함수는 시간 틱(tick) 수의 시간 정보를 나타낸다.

 

 

[ 예제 코드 : wastetime.c ]

#include <stdio.h>
#include <sys/time.h>
#define MILLION 1000000L

/* waste maxus microseconds of time */
int wastetime(int maxus) {
   long timedif;
   struct timeval tp1, tp2;

   if (gettimeofday(&tp1, NULL)) {
      fprintf(stderr, "Failed to get initial time\n");
      return 1;
   }
   timedif = 0;
   while (timedif < maxus) {
      if (gettimeofday(&tp2, NULL)) {
         fprintf(stderr, "Failed to get check time\n");
         return 1;
      }
      timedif = MILLION*(tp2.tv_sec - tp1.tv_sec) +
                   tp2.tv_usec - tp1.tv_usec;
      if (timedif < 0)
         break;
   }
   return 0;
}

 

▶ 사용 예:

$ ./showtimes

User time:                         1.270 seconds

System time:                    2.660 seconds

Children's user time:      0.000 seconds

Children's system time: 0.000 seconds

 

Child has exited, parent stats follow:

User time:                        0.460 seconds

System time:                    0.970 seconds

Children's user time:      1.270 seconds

Children's system time: 2.660 seconds

 

Posted by devanix
2011. 9. 2. 23:52

♧ 이 리스트 객체는 프로그램에 의해 실행된 명령어를 기록한다.

 

요구사항:

- 사용자가 한 번 입력한 자료는 수정하지 못하기 때문에,

원래의 문자열에 대한 포인터 대신 이 문자열의 사본(copy)을 가리키는 포인터를 리스트로 추가.

- 리스트에서 자료를 가져올 때, 구현은 실제 데이터에 대한 포인터를 리턴하지 않고 사본의 포인터를 리턴.

사본(copy)에 대한 포인터를 리턴받은 경우, 호출자는 사본에 대한 메모리 해제.

- 탐색하는 동안, 리스트는 다음요청의 시작점을 알기 위해 현재의 위치를 기억해야만 한다.

자료 탐색 시에 사용되는 키(key) 값을 호출자에게 제공함으로써 리스트 객체는 키를 통해

- 인덱싱되는 리스트 내의원소에 대한 포인터의 배열을 유지하고 있다.

 

[ 예제 코드 : listlib.h ]

#ifndef __LISTLIB_H_
#define __LISTLIB_H_

#include <time.h>

typedef struct data_struct {
    time_t   time;
    char    *string;
} data_t;

int accessdata(void);
int adddata(data_t data);
int getdata(int key, data_t *datap);
int freekey(int key);

#endif /* __LISTLIB_H_ */

☞ adddata() : 내부 리스트 구조에 data의 사본을 가지는 노드를 추가.

☞ accessdata() : 리스트를 탐색하기 위한 키를 리턴.

☞ getdata() : 탐색되는 자료를 사용자가 제공한 data_t 형의 버퍼에 사본을 복사. (호출자가 메모리 해제)

☞ freekey() : 키 값이 더 이상 필요하지 않다면 키를 해제.

 

 

[ 예제 코드 : listlib.c ]

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "listlib.h"

#define TRAV_INIT_SIZE	8

typedef struct list_struct {
    data_t item;
    struct list_struct *next;
} list_t;

static list_t   endlist;
static list_t  *headptr  = NULL;
static list_t  *tailptr  = NULL;
static list_t **travptrs = NULL;
static int travptrs_size = 0;

/* return a nonnegative key if successful */
int accessdata(void) {
    int i;
    list_t **newptrs;

    /* can't access a completely emptry list */
    if (headptr == NULL) {
	errno = EINVAL;
	return -1;	
    }

    if (travptrs_size == 0) { /* first traversal */
	travptrs = (list_t **) calloc(TRAV_INIT_SIZE, sizeof(list_t *));
	if (travptrs == NULL) /* douldn't allocate space or traversal keys */
	    return -1;
	travptrs[0]   = headptr;
	travptrs_size = TRAV_INIT_SIZE;
	return 0;
    }
    
    /* look for an emptr slot for key */
    for (i=0; i<travptrs_size; i++) {
	if (travptrs[i] == NULL) {
	    travptrs[i] = headptr;
	    return i;
	}
    }    

    newptrs = realloc(travptrs, 2 * travptrs_size * sizeof(list_t *));
    if (newptrs == NULL)    /* couldn't expand the array of traversal keys */
	return -1;
    travptrs = newptrs;
    travptrs[travptrs_size] = headptr;
    travptrs_size *= 2;
    return travptrs_size/2;
}

/* allocate node for data and add to end of list */
int adddata(data_t data) {
    list_t *newnode;
    int	    nodesize;

    nodesize = sizeof(list_t) + strlen(data.string) + 1;
    /* couldn't add node */
    if ((newnode = (list_t *) (malloc(nodesize))) == NULL)
	return -1;
    newnode->item.time   = data.time;
    newnode->item.string = (char *)newnode + sizeof(list_t);
    strcpy(newnode->item.string, data.string);
    newnode->next = NULL;

    if (headptr == NULL)
	headptr = newnode;
    else
	tailptr->next = newnode;
    tailptr = newnode;

    return 0;
}

/* copy next item and set datap->string */
int getdata(int key, data_t *datap) {
    list_t *t;

    if( (key < 0) || (key >= travptrs_size) || (travptrs[key] == NULL)) {
	errno = EINVAL;
	return -1;
    }
    
    /* end of list, set datap->string to NULL */
    if (travptrs[key] == &endlist) {
	datap->string = NULL;
	travptrs[key] = NULL;
	return 0;   /* reaching end of list natural condition, not an error */
    }

    t = travptrs[key];
    datap->string = (char *)malloc(strlen(t->item.string) + 1);
    /* couldn't allocate space for returning string */
    if (datap->string == NULL)
	return -1;
    datap->time = t->item.time;
    strcpy(datap->string, t->item.string);

    if (t->next == NULL)
	travptrs[key] = &endlist;
    else
	travptrs[key] = t->next;

    return 0;
}

/* free list entry corresponding to key */
int freekey(int key) {
    /* key out of range */
    if ( (key < 0) || (key >= travptrs_size) ) {
	errno = EINVAL;
	return -1;
    }
    travptrs[key] = NULL;
    return 0;
}

 

 

[ 예제 코드 : keeplog.c ]

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef MAX_CANON
#define MAX_CANON   8192
#endif

extern int  runproc(char *cmd);
extern void showhistory(FILE *f);

int main(int argc, char *argv[]) {
    char cmd[MAX_CANON];
    int	 history = 1;

    if (argc == 1) {
	history = 0;
    } else if ((argc > 2) || strcmp(argv[1], "history")) {
	fprintf(stderr, "Usage: %s [history]\n", argv[0]);
	return 1;
    }

    while(fgets(cmd, MAX_CANON, stdin) != NULL) {
	if( cmd[strlen(cmd) - 1] == '\n')
	    cmd[strlen(cmd) - 1] = 0;

	if( history && !strcmp(cmd, "history")) {
	    showhistory(stdout);
	} else if (runproc(cmd)) {
	    perror("Failed to execute command");
	    break;
	}
    }
    printf("\n\n>>>>>>The list of commands executed is:\n");
    showhistory(stdout);

    return 0;
}

 

 

[ 예제 코드 : keeploglib.c ]

#include <stdio.h>
#include <stdlib.h>
#include "listlib.h"

/* execute cmd; store cmd and time in history list */
int runproc(char *cmd) {
    data_t execute;

    if (time(&(execute.time)) == (time_t)-1)
	return -1;
    execute.string = cmd;
    /* command could not be executed at all */
    if (system(cmd) == -1)
	return -1;    
    return adddata(execute);
}

/* output the history list of the file f */
void showhistory(FILE *f) {
    data_t  data;
    int	    key;

    key = accessdata();
    if (key == -1) {
	fprintf(f, "No history\n");
	return;
    }

    while (!getdata(key, &data) && (data.string != NULL)) {
	fprintf(f, "Command: %s\nTime: %s\n", data.string, ctime(&(data.time)));
	free(data.string);
    }
}

☞ runproc() : 성공적으로 명령어를 실행하면, adddata()를 호출하여 기록 리스트에 추가.

☞ showhistory() : accessdata() 호출하여 key값을 받아 getdata() 로 데이터 사본을 받아 히스토리 출력.

 

▶ 사용 예:

$ ./keeplog history

ls

Makefile argtest.c keeplog.c listlib.c makeargv.c wordaverage.c

argtest keeplog keeploglib.c listlib.h wordaverage wordaveragetest.c

date

2011. 09. 02. (금) 23:54:27 KST

history

Command: ls

Time: Fri Sep 2 23:54:27 2011

 

Command: date

Time: Fri Sep 2 23:54:27 2011

 

 

>>>>>>The list of commands executed is:

Command: ls

Time: Fri Sep 2 23:54:27 2011

 

Command: date

Time: Fri Sep 2 23:54:27 2011

☞ 프로그램은 "history"라는 커맨드라인 인자를 선택적으로 입력 받는다.

☞ "history"인자가 선택되고 표준 입력에서 "history"를 읽을 때마다 프로그램은 이제까지 실행한 명령어의 기록을 출력.

Posted by devanix
2011. 9. 2. 20:38

♧ strtok_r 함수를 이용해서 한 줄의 평균 단어 수를 구한다.

원형

double wordaverage(char *s);

인수

const char *s : 문자열 버퍼를 가리키는 포인터.

반환

double - 평균 단어 수.

 

strtok함수는 하나의 지역 변수만을 사용하기 때문에 여러 번에 걸쳐 호출하게 된다면

 문자열의 파싱은 서로 방해 받고 말 것이다.

☞ 그래서 멀티스레드 프로그램에서의 안전성을 위하여 strtok대신 strtok_r 함수를 사용.

strtok_r 에서 "_r" 표시는 재진입(reentrant)를 뜻하며,

 함수가 그 전의 호출이 끝나기 전에 재진입(재호출)될 수 있다는 것을 의미.

 

 

[ 예제 코드 : wordaveragetest.c ]

#include <stdio.h>
#include <unistd.h>

#define BUFSIZE	1024

extern double wordaverage(char *s);

int main() {
    char    buf[BUFSIZE];
    int	    size = 0;
    int	    num;
    double  ave;

    while (size < BUFSIZE-1) {
	num = read(0, buf+size, BUFSIZE-size-1);
	if (num == 0) break;
	if (num < 0) {
	    fprintf(stderr, "Error reading from standard input!\n");
	    return 1;
	}
	fprintf(stderr, "%d bytes read\n", num);
	size += num;
    }
    buf[size] = 0;
    fprintf(stderr, "Total number of bytes read = %d\n", size);
    ave = wordaverage(buf);
    fprintf(stderr, "The average number of word is %f\n", ave);

    return 0;
}

 

[ 예제 코드 : wordaverage.c ]

#include <string.h>
#define LINE_DELIMITERS	"\n"
#define WORD_DELIMITERS	" "

static int wordcount(char *s) {
    int   count = 1;
    char *lasts;

    if (strtok_r(s, WORD_DELIMITERS, &lasts) == NULL)
	return 0;
    while (strtok_r(NULL, WORD_DELIMITERS, &lasts) != NULL)
	count++;

    return count;
}

/* return average size of words in s */
double wordaverage(char *s) {
    char *lasts;
    char *nextline;
    int	  words;
    int   linecount = 1;

    nextline = strtok_r(s, LINE_DELIMITERS, &lasts);
    if (nextline == NULL)
	return 0.0;
    words = wordcount(nextline);
    while ((nextline = strtok_r(NULL, LINE_DELIMITERS, &lasts)) != NULL) {
	words += wordcount(nextline);
	linecount++;
    }
    return (double)words/linecount;
}

 

▶ 사용 예:

$ ./wordaverage

word1 word2 word3

18 bytes read

word4 word5

12 bytes read

word6 word7 word8 word9 word10

31 bytes read

Total number of bytes read = 61

The average number of word is 3.333333

 

Posted by devanix
2011. 9. 2. 19:02

▣ 설명 : 하나의 커맨드라인 인자를 가지고 makeargv() 호출하여 인자 배열을 만든다.

원형

int makeargv(const char *s, const char *delimiters, char ***argvp);

인수

const char *s : 문자열

const char *delimiters : 구분자

char ***argvp : 인자 배열을 가리키는 포인터.

반환

성공 : 토큰 수

실패 : -1리턴, errno 설정.

makeargv 함수는 delimiter를 구분자로 가지고, 문자열 s로부터 argvp가 가리키는 곳에 인자 배열을 만든다.

 

[ 예제코드 : argtest.c ]

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

extern int makeargv(const char *s, const char *delimiters, char ***argvp);
extern void freemakeargv(char **argv);

int main(int argc, char *argv[]) {
    char delim[] = " \t";
    int i;
    char **myargv;
    int numtokens;

    if (argc != 2) {
	fprintf(stderr, "Usage: %s string\n", argv[0]);
	return 1;
    }

    if ((numtokens = makeargv(argv[1], delim, &myargv)) == -1) {
	fprintf(stderr, "Failed to construct an argument array for %s\n",
	    argv[1]);
	return 1;
    }
    fputs("The argument array contains:\n", stdout);
    for (i=0; i<numtokens; i++)
	printf("%d: %s\n", i, myargv[i]);

    freemakeargv(myargv);
    return 0;
}

 

[ 예제코드 : makeargv.c ]

#include <errno.h>
#include <stdlib.h>
#include <string.h>

int makeargv(const char *s, const char *delimiters, char ***argvp) {
    int error;
    int i;
    int numtokens;
    const char *snew;
    char *t;

    if ((s == NULL) || (delimiters == NULL) || (argvp == NULL)) {
	errno = EINVAL;
	return -1;
    }
    *argvp = NULL;

    /* snew is real start of string */
    snew = s + strspn(s, delimiters);	
    if ((t = malloc(strlen(snew) + 1)) == NULL)
	return -1;
    strcpy(t, snew);

    numtokens=0;
    /* count the number of tokens in s */
    if (strtok(t, delimiters) != NULL)
	for (numtokens=1; strtok(NULL, delimiters) != NULL; numtokens++) ;

    /* create argument array for ptrs to the tokens */
    if ((*argvp = malloc((numtokens + 1) * sizeof(char *))) == NULL) {
	error = errno;
	free(t);
	errno = error;
	return -1;
    }

    /* insert pointers to tokens into the argument array */
    if (numtokens == 0) {
	free(t);
    } else {
	strcpy(t, snew);
	**argvp = strtok(t, delimiters);
	for(i=1; i<numtokens; i++)
	    *((*argvp)+i) = strtok(NULL, delimiters);
    }
    /* put in final NULL pointer */
    *((*argvp)+numtokens) = NULL;    
    return numtokens;
}

void freemakeargv(char **argv) {
    if (argv == NULL)
	return;
    if (*argv != NULL)
	free(*argv);
    free(argv);
    argv=NULL;
}

 

▣ 사용 예: 하나의 커맨드라인 인자("큰따옴표"로 묶는다)를 받아 인자 배열로 만듬.

$ ./argtest

Usage: ./argtest string

 

$ ./argtest "mine -c 10 2.0"

The argument array contains:

0: mine

1: -c

2: 10

3: 2.0

 

전반적인 구현 순서 :

1. 문자열 분석을 위한 버퍼 tmalloc로 할당한다.

버퍼 t는 문자열 s와 종료문자 '\0'을 담을 수 있을 만큼 충분한 크기를 가져야 한다.

2. st에 복사 (문자열 : "mine -c 10 2.0")

3. 문자열 t를 매개변수로 strtok 함수를 호출하여 토큰의 수를 계산.

4. 토큰의 수(numtokens)를 이용하여 argv 배열의 크기를 할당.

5. st에 다시 복사.

6. strtok를 사용하여 각각의 토큰에 대한 포인터를 만들고, t를 분석하기 좋은 형태로 수정.

 

Posted by devanix
2011. 9. 2. 17:07

 

[ 책소개 ]

이 책은 이전 판(기존 제목은 "Practical UNIX Programming")을 완전히 새롭게 구성하였으며,

복잡한 소프트웨어를 설계하는 방법을 설명함으로써 UNIX 운영체제의 대부분을 이해할 수 있게 도와 준다.

UNIX Systems Programming은 UNIX 프로그래밍의 필수적인 지식들을 명확하고도 이해하기 쉽게 설명하고 있다.

두 명의 저자들은 독자들의 실력을 넓혀 주기 위해, 독자들이 시스템 콜을 사용하는 방법을 설명하는 짤막한

코드에서부터 시작하여 곧바로 직접 참여할 수 있는 프로젝트를 접해볼 수 있도록 책을 구성하였다.

 

수많은 연습문제와 예제, 프로젝트를 통해 UNIX의 이론을 체험하자!!!

220여 개의 예제, 400여 개의 연습문제, 7개의 대형 프로젝트 수록

 

이 책을 통해 여러분은 Linux, Solaris, MacOS X 등의 POSIX 기반 시스템에서 신뢰성 있는 UNIX 소프트웨어를

설계하고 구현하는 방법을 배울 수 있다.

 

[ 목차 ]

PART 1 기초

Chapter 1 프로그램에 끼친 기술의 영향

Chapter 2 프로그램, 프로세스, 쓰레드

Chapter 3 UNIX의 프로세스

Chapter 4 UNIX I/O

Chapter 5 파일과 디렉토리

Chapter 6 UNIX 특수 파일

Chapter 7 프로젝트 : 토큰 링(Token Ring)

 

PART 2 비동기 이벤트

Chapter 8 시그널

Chapter 9 시간과 타이머

Chapter 10 프로젝트 : 가상 타이머

Chapter 11 프로젝트 : 쉘 만들기

 

PART 3 병행성

Chapter 12 POSIX 쓰레드

Chapter 13 쓰레드 동기화

Chapter 14 크리티컬 섹션과 세마포어

Chapter 15 POSIX IPC

Chapter 16 프로젝트 : 생산자 소비자 동기화

Chapter 17 프로젝트 : NTPVM(Not Too Parallel Virtual Machine)

 

PART 4 통신

Chapter 18 연결 지향 통신

Chapter 19 프로젝트 : WWW 재지향

Chapter 20 비연결형 통신과 멀티캐스트

Chapter 21 프로젝트 : 인터넷 라디오

Chapter 22 프로젝트 : 서버의 성능

 

PART 5 부록

Appendix A UNIX 기초

Appendix B 재시작 라이브러리

Appendix C UICI의 구현

Appendix D 로깅 함수

 

예제 소스 : 


참조사이트 : 
http://usp.cs.utsa.edu/usp/

'컴퓨터 문서 모음 > 시스템 프로그래밍' 카테고리의 다른 글

Advanced Linux Programming  (1) 2011.08.12
Posted by devanix
2011. 8. 20. 08:38

♧ 대부분의 리눅스 시스템은 시스템에서 발생하는 많은 활동의 로그를 구성한다.

/var/log 디렉토리 혹은 서브 디렉토리에 위치한 로그파일에 쓴다.

이 로긴은 Syslog를 통해 이루어진다.

우분투는 sysklogd 그리고 klogd 패키지에서 시스템 로깅을 관리하는

syslogd(시스템 로그 데몬) 및 klogd(커널 로그 데몬)를 사용한다.

이러한 데몬은 syslog init 스크립트(/etc/init.d/sysklogd)에서 자동적으로 시작한다.

시스템에 대한 활동 정보는 /etc/syslog.conf 설정을 기반으로

message, secure, cron 그리고 boot.log 같은 것으로 /var/log 디렉토리 안의 파일에 다이렉트 한다.

 

자동 로그 회전은 /etc/logrotate.conf 파일 그리고 /etc/logrotate.d 디렉토리 설정을 기반으로

logrotate를 다룬다. /etc/cron.daily/logrotate 크론잡(cronjob)은 매일 로그 회전을 맡는다.

 

vi 혹은 좋아하는 텍스트 편집을 사용하여 로그 파일은 수동으로 언제든지 확인할 수 있다.

그러나 만약 logwatch 패키지를 설치했다면, 로그 파일의 하이라이트는 매일 root 사용자의

사서함에 자동적으로 우송된다. /etc/cron.daily/0logwatch파일을 편집하여 메일의

받는주소와 보내는 주소를 변경할 수 있다.

이메일 루프를 방지하려면, 수신자가 로컬 머신에 없을 때 실제 이메일 주소를 보내는 주소로 변경해야 한다.

수신자를 변경하는 또 다른 방법은 /etc/aliases 편집하여 root의 이메일 주소를 다른 주소로 포워드한다.

그리고 newaliases를 실행하여 변화를 제정한다.

그렇지 않으면, logwatch이메일 메시지를 읽을 때 root로 로그인하고 메일 클라이언트를 사용한다.

 

logger 명령어를 사용하여 syslogd 로깅으로 자신의 메시지를 보낼 수 있다.

 

$ logger Added new video card

$ logger -p info -t CARD -f /tmp/my.txt

메시지를 메시지 파일에 추가

우선순위, 태크, 메시지 파일

 

첫 번째 예는, Added new video card 문장을 메시지 파일에 보낸다.

두 번째 예는, 메시지의 우선순위가 정보로 설정되어 있고 CARD의 태크가 메시지 각 라인에 추가하였다.

텍스트 메시지는 /tmp/my.txt 파일에서 가지고 온 것이다.

실시간으로 로그 항목을 보려면 tail -f 혹은 less를 사용하라.

 

Posted by devanix