2014-07-17 3 views
1

내 C 지식은 매우입니다. 전달 된 인수를 execve에 사용하고 싶기 때문에 클라이언트에서 서버에 전달 된 String을 토큰 화하려고합니다. buffer을 통해 전달 된 인수는 *argv에 복사해야하고 buffer의 토큰에 argv[0], argv[1] 등으로 액세스 할 수 있도록 토큰 화되어야합니다. 분명히 잘못하고 있습니다. 위의 코드와 함께 인수 "/ 빈/날짜 -u"를 전달execve()에 char *로 전달할 문자열 토큰 화

n = read(sockfd, buffer, sizeof(buffer)); 
strcpy(*argv, buffer); 
printf("buffer:%s\n", buffer); 
printf("argv:%s\n", *argv); 
printf("argv[0]:%s\n", argv[0]); 
printf("argv[1]:%s\n", argv[1]); 
*argv = strtok_r(*argv, " ", argv); 
printf("argv:%s\n", *argv); 

i = fork(); 
if (i < 0) { 
    //Close socket on fork error. 
    perror("fork"); 
    exit(-1); 
} else if (i == 0) { 
    //execve on input args 
    execve(argv[0], &argv[0], 0); 
    exit(0); 
} else { 
    wait(&status); 
    //close(sockfd); 
} 

는의 출력을 제공합니다

buffer:/bin/date -u 

argv:/bin/date -u 

argv[0]:/bin/date -u 

argv[1]:(null) 

를 내가의 출력 무엇 :

buffer:/bin/date -u 

argv:/bin/date -u 

argv[0]:/bin/date 

argv[1]:-u 

I strtok_r()을 사용해 보았지만 의도 한대로 작동하지 않았습니다. 내가 삽입 한 스 니펫은 argv:/bin/date의 출력을내는 코드 :

*argv = strtok_r(*argv, " ", argv); 
printf("argv:%s\n", *argv); 

입니다.

감사합니다.

편집 : 위와 같이 명시 적으로 토큰화할 필요가 없습니다. buffer. 서버로 전달 된 클라이언트에서 인수를 얻는 방법은 아무 문제가 없습니다.

답변

3

글쎄, 몇 가지 문제가 있습니다. 첫 번째는 버퍼를 쓸 varable로 argv을 선택하는 것입니다. 단지 포인터의 배열 일 뿐이지 만, 에서으로 전달 된 인수를 보유하고있는 배열은 일반적으로 argv으로 간주하며 수정할 변수가 아닙니다. 그러나, 그것은 정말로 의미 론적이다. 내가 아는 바로는 그렇게하는 것이 금지되어 있지 않다. 그러나 *argv을 토큰화할 수는 있지만 *argv에 토큰을 할당하는 것은 strtok_r이 처리 중에 *argv을 수정하기 때문에 토큰을 할당 할 수 없습니다.

그 외에도 실제 문제는 strtok_r의 사용 인 것으로 보입니다. man strtok_r을 살펴보십시오. 문자열을 토큰 화하려면 모든 토큰을 추출하기 위해 번의 전화를 strtok_r 번으로 반복해야합니다. 첫 번째 인수 (* argv ...)를 사용하는 strtok_r에 대한 첫 번째 호출은 첫 번째 토큰 만 추출합니다. 추출을 완료하려면 모든 토큰이 추출 될 때까지 NULL을 첫 번째 인수로 전달해야합니다. 또한 토큰을 추출하는 문자열은 strtok_r에 대한 호출로 수정되므로 추출 후에 사용해서는 안됩니다. 일반적으로 나중에 필요할 경우 원본을 보존하기 위해 문자열 사본이 만들어집니다. 코드에서

만 예하면 strtok_r 전화 :

char *token = malloc (sizeof (token) * 128); // or something large enough to hold the tokens 

token = strtok_r(*argv, " ", argv); 
if (token) 
    printf (" token: %s\n", token); 

while ((token = strtok_r (NULL, " ", argv)) != NULL) 
{ 
    printf (" token: %s\n", token); 
} 

: 당신의 의도는 모든 문자열을 추출하는 경우

*argv = strtok_r(*argv, " ", argv); // extracts the first token and modifies *argv 

는 다음과 같은 strtok_r 뭔가 반복 호출을해야합니다 execve으로 전달하기 위해 원하는 개별 토큰을 캡처 할 수 있습니다.그러나, argv에 다시 쓰는 동안 argv에서 tokes를 제거 할 수는 없습니다. 위에 표시된대로 argv은 추출하는 동안 strtok_r으로 수정되므로 토큰을 보유하려면 별도의 배열이 필요합니다. 희망이 도움이됩니다.

0

strtok()strtok_r() 함수는 한 번에 하나의 토큰을 반환합니다. 그들은 호출간에 상태를 유지하고 문자열을 토큰으로 분할하기 위해 루프에서 호출해야합니다. 또한 첫 번째 인수로 전달 된 버퍼를 수정하여 복사해야합니다.

내가 당신에게 예를 보여 드리죠 :

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

#define MAX_CMD_SIZE 1024 
#define MAX_ARG_COUNT 10 

main() 
{ 
    const char *command = "/bin/test arg1 arg2 arg3 arg4 arg5"; 

    /* Allocate a buffer for tokenization. 
    * the strtok_r() function modifies this buffer in-place and return pointers 
    * to strings located inside this buffer. */ 
    char cmd_buf[MAX_CMD_SIZE] = { 0 }; 
    strncpy(cmd_buf, command, sizeof(cmd_buf)); 

    /* This strtok_r() call puts '\0' after the first token in the buffer, 
    * It saves the state to the strtok_state and subsequent calls resume from that point. */ 
    char *strtok_state = NULL; 
    char *filename = strtok_r(cmd_buf, " ", &strtok_state); 
    printf("filename = %s\n", filename); 

    /* Allocate an array of pointers. 
    * We will make them point to certain locations inside the cmd_buf. */ 
    char *args[MAX_ARG_COUNT] = { NULL }; 

    /* loop the strtok_r() call while there are tokens and free space in the array */ 
    size_t current_arg_idx; 
    for (current_arg_idx = 0; current_arg_idx < MAX_ARG_COUNT; ++current_arg_idx) { 
     /* Note that the first argument to strtok_r() is NULL. 
     * That means resume from a point saved in the strtok_state. */ 
     char *current_arg = strtok_r(NULL, " ", &strtok_state); 
     if (current_arg == NULL) { 
      break; 
     } 

     args[current_arg_idx] = current_arg; 
     printf("args[%d] = %s\n", current_arg_idx, args[current_arg_idx]); 
    } 
} 

예제의 출력은 위이다 : 나는 별도의 변수로 filenameargs을 넣어

filename = /bin/test 
args[0] = arg1 
args[1] = arg2 
args[2] = arg3 
args[3] = arg4 
args[4] = arg5 

주 최초의 사이의 차이를 설명하기 위해 통화 및 후속 통화 execve()의 경우 일반적으로 파일을 첫 번째 요소 인 argv으로 간주하기 때문에이 파일을 단일 배열에 넣고 execve(argv[0], argv, NULL);과 같이 호출해야합니다.