Preventing buffer overflows with strncpy, strncat, and snprintf

Preventing Buffer overflows

흔히 버퍼 오퍼플로우를 막기 위해 쓰는 함수가, strncpy(3), strncat(3), snprintf(3)⁠입니다. 이들 함수는 버퍼의 크기를 미리 지정받아, 복사할 문자열의 길이가 버퍼의 크기보다 클 경우, 복사를 중지해서 버퍼를 벗어나는 복사를 막아줍니다. 하지만, 버퍼의 크기를 해석하는 방식이 약간씩 다르다는 것이 문제입니다.

버퍼의 크기가 M이고, 복사해 넣을 문자열의 길이가 N이라고 합시다. 이 때 두 가지 경우를 생각할 수 있습니다. 첫째, 버퍼의 길이가 충분히 클 때 (즉, M > N), 둘째 버퍼의 길이가 짧을 때 (즉 M < N).

이 함수들을 검사하기 위해, 먼저 주어진 버퍼의 내용을 그대로 출력해 주는 함수를 만들어 봅시다. 보통 C 언어가 제공하는 문자열 함수들은 '\0'을 만나면 출력을 멈추기 때문에, 버퍼의 내용 전체를 알아 보기에는 좋지 않습니다. 따라서 다음과 같이 버퍼의 내용을 전체 다 출력해 주는 함수를 만듭니다 (필요한 표준 헤더 파일은 생략합니다):

void
memdump(const void *s, size_t size)
{
  const char *p = (const char *)s;
  const char *end = p + size;

  while (p < end) {
    if (isprint((unsigned char)*p))
      putchar(*p);
    else
      putchar('.');
    p++;
  }
}

예를 들어 char buf[10]⁠에 "ABCDEFGHI"가 들어있다고 가정하면, memdump(buf, 10)⁠은 다음과 같이 출력합니다:

ABCDEFGHI.

이제, 각각의 함수가 앞에서 다룬 두 가지 경우에 어떤 식으로 동작하는지 살펴봅시다. 먼저 첫번째 경우 (버퍼가 충분히 클 경우)를 알아보는 코드는 다음과 같습니다 (BUF_MAX⁠는 매크로이며 10입니다):

memset(buf, '#', BUF_MAX);
strcpy(buf, "123");
memdump(buf, BUF_MAX);  putchar('\n');

memset(buf, '#', BUF_MAX);
strncpy(buf, "123", 5);
memdump(buf, BUF_MAX);  putchar('\n');

memset(buf, '#', BUF_MAX);
buf[0] = '\0';
strncat(buf, "123", 5);
memdump(buf, BUF_MAX);  putchar('\n');

memset(buf, '#', BUF_MAX);
snprintf(buf, "%s", "123", 5);
memdump(buf, BUF_MAX);  putchar('\n');

위 코드에서 문자열 "123"을 복사해 넣으면서, 버퍼의 길이는 5라고 치고 각 함수를 테스트합니다. 이 때, 출력은 다음과 같습니다:

123.######
123..#####
123.######
123.######

strncpy(3)⁠를 제외하고, 나머지 세 함수는 예상대로 동작합니다. 즉 문자 '1', '2', '3'을 복사해 넣고, 문자열 끝을 알리는 '\0'까지 복사합니다. 이 네 문자 모두 버퍼의 길이라고 지정한 5보다 작기 때문에 문제는 전혀 없습니다. 하지만, 두번째 줄인 strncpy(3)⁠는, 123을 복사해 넣고, 나머지 공간을 모두 '\0'으로 채운다는 것이 다릅니다! 즉, 버퍼가 충분히 클 경우에도, strcpy(3)⁠와 strncpy(3) 동작 방식은 서로 다릅니다!

두번째 경우, 즉 버퍼가 충분히 크지 못할 경우를 살펴 봅시다. 이제 strcpy(3)⁠의 경우, 테스트할 필요가 없으므로 뺐습니다:

memset(buf, '#', BUF_MAX);
strncpy(buf, "12345", 3);
memdump(buf, BUF_MAX);  putchar('\n');

memset(buf, '#', BUF_MAX);
buf[0] = '\0';
strncat(buf, "12345", 3);
memdump(buf, BUF_MAX);  putchar('\n');

memset(buf, '#', BUF_MAX);
snprintf(buf, 3, "%s", "12345");
memdump(buf, BUF_MAX);  putchar('\n');

이 경우, 다음과 같은 출력을 얻을 수 있습니다:

123#######
123.######
12.#######

세가지 함수 모두 다르게 동작한다는 것을 알 수 있습니다. 먼저 strncpy(3)⁠의 경우, 버퍼의 길이가 부족할 경우, 버퍼의 크기만큼 써 줍니다. 이 때 공간이 부족하더라도 '\0'을 써 주지 않습니다. 따라서 strncpy(3)⁠의 경우, 완전하지 못한 문자열을 얻을 수 있습니다.

strncat(3)⁠의 경우, 무조건 n개 문자를 복사합니다. 따라서 이 경우, 123을 복사한 다음 '\0'까지 써 줍니다. 사실 strncat(3)⁠의 경우, 버퍼의 길이를 지정하는 것이 아니라, '\0'을 제외한 실제 복사할 문자의 갯수를 지정하는 것입니다.

snprintf(3)⁠의 경우, strncat(3)⁠과 다르게, 버퍼의 크기를 지정합니다. 따라서 버퍼의 길이가 짧을 경우, 그 버퍼의 길이 - 1개의 문자를 복사하고, '\0'을 써 줍니다. 즉, strncpy(3)⁠와 다르게, 어떤 경우에도 '\0'으로 끝나는 올바른 문자열을 만들어 줍니다.

이제 이 차이를 알았으면, 실제 코드에서 어떤 식으로 써야 하는지 알아봅시다. 먼저 사용자가 입력한 문자열 somestring이 있다고 가정하고, 다음 코드를 보기 바랍니다:

char buf[LEN];
strncpy(buf, some_string, LEN);

자, 위 코드는 잘못된 코드입니다. 왜냐하면 somestring의 길이가 LEN보다 클 경우, buf에 들어가는 문자열이 '\0'으로 끝나지 않을 수 있기 때문입니다. 따라서 다음과 같이 써 주어야 합니다:

char buf[LEN];
strncpy(buf, some_string, LEN - 1);
buf[LEN - 1] = '\0';

다음 코드는 안전할까요?

char buf[LEN];
buf[0] = '\0';
strncat(buf, some_string, LEN);

아닙니다. strncat(3)⁠은, 버퍼의 크기가 아니라, 복사할 문자열의 길이를 지정하는 것이므로, 마찬가지로 '\0'으로 끝나지 않은 문자열을 만들 가능성이 있습니다. 이것도 다음과 같이 써야 합니다:

char buf[LEN];
buf[0] = '\0';
strncat(buf, some_string, LEN - 1);
buf[LEN - 1] = '\0';

그럼 snprintf(3)⁠를 쓴 코드를 봅시다:

char buf[LEN];
snprintf(buf, LEN, "%s", some_string);

위 코드는 안전할까요? 예. 그렇습니다. 안전합니다. snprintf(3)⁠는 버퍼의 길이를 받아서 어떤 상황에서도 '\0'으로 끝나는 완전한 문자열을 만들어 줍니다.

안전한 프로그램, buffer overflow에 항상 신경써야 하는 코드를 작성한다면, 이와 같은 사항은 꼭 기억해 두어야 합니다. 그럼 이만.

Best buffer size to store pathnames, PATH_MAX

Buffer size to store pathnames

보통 filename (또는 file name)이라고 하면 어떤 파일 이름 그 자체를 나타냅니다 (예: "hello.c" 또는 "src") 그리고 pathname이라고 하면 filename 또는 이 파일의 위치 정보까지 포함된 문자열을 뜻합니다. (예: "/usr/bin", "./a.out", "/home/cinsk/.emacs" 등) 이 때 pathname은 보통 root 디렉토리에서 시작하느냐의 여부에 따라 absolute pathname (절대경로) 또는 relative pathname (상대 경로)로 나타냅니다. Absolute pathname의 경우, "/"로 시작하는 pathname입니다.

파일 또는 디렉토리를 다루는 프로그램을 작성하다보면, filename이나 pathname을 취급할 경우가 많은데, 이 때 주어진 pathname을 저장하기 위해, 흔히 적당히 큰 문자 배열을 준비하고 쓰는 경우가 많습니다. 이런 식으로 작성한 프로그램은 적당히 크다고 생각한 값이 별로 크지 않을 경우, 버그가 발생할 수도 있으며, 나중에 수정하기도 꽤 어렵습니다. 따라서 이 경우에는 POSIX가 정의하고 있는 PATH_MAX⁠란 상수를 쓰는 것이 바람직합니다.

PATH_MAX⁠는 패스 이름이 가질 수 있는 최대 글자 수를 나타냅니다. 패스 이름이란 디렉토리 이름을 포함한 파일 이름을 뜻합니다. (예: "/usr/bin/ls", "/opt/share/info"). 문자열의 끝을 나타내는 '\0'도 포함입니다. 따라서 정확히 파일이 가질 수 있는 글자 수의 총 길이는 PATH_MAX - 1⁠이 됩니다.

따라서 파일 이름을 처리하거나 저장할 경우, PATH_MAX⁠ 크기의 메모리 공간을 준비해 놓고 작업하면 됩니다. 예를 들면 다음과 같습니다:

void foo(const char *pathname)
{
  char buf[PATH_MAX];
  buf[0] = '\0';     
  strncpy(buf, pathname, PATH_MAX - 1);

  ...
}

인생이 이렇게 단순했으면 얼마나 좋겠습니까만… 사실 이게 전부가 아닙니다.

먼저, POSIX 호환 시스템이라 하더라도 PATH_MAX⁠가 정의되어 있지 않은 경우가 있습니다. 왜 정의가 되어 있지 않냐면, 파일 이름의 길이 제한이 파일 시스템마다 달라질 수 있기 때문입니다. 예를 들어 무조건 한 파일 시스템만 사용하는 OS나, 여러 파일 시스템을 지원하더라도 파일 길이 제한의 값이 같은 OS라면 PATH_MAX⁠가 정의되어 있습니다. 하지만, 만약 여러 파일 시스템을 지원하고, 또 각 파일 시스템마다 지원하는 최대 파일 이름 길이가 다르다면, 단순히 한 상수로 최대 파일 이름 길이를 나타낼 수 없습니다.

또한, 드물지만, 파일 이름 길이에 제한이 없다면, PATH_MAX⁠가 정의되어 있지 않습니다.

둘째, PATH_MAX⁠가 정의되어 있다 하더라도, 이 매크로가 배열의 크기로 쓰기에는 너무나 큰 상수일 가능성이 있습니다. 따라서 다음과 같이, 배열의 크기를 지정하는 목적으로 PATH_MAX⁠를 쓰는 것은 별로 바람직한 방법은 아닙니다. (저도 여유가 없으면 자주 쓰는 방식이긴 하지만.. -_-;;)

char buf[PATH_MAX];

세째, PATH_MAX⁠의 정확한 뜻에 관한 것입니다. PATH_MAX⁠는 임의의 한 pathname이 가질 수 있는 최대 값을 나타내는 것이 아닙니다. 다시 말해, PATH_MAX⁠보다 큰 pathname이 존재할 수도 있습니다. 여기에 관한 것은 바로 뒤에 pathconf(3)를 설명할 때 다루겠습니다.

그럼 PATH_MAX⁠가 정의되어 있지 않다면 어떻게 pathname의 최대값을 얻을 수 있느냐? 답은 pathconf(3)나 fpathconf(3)를 쓰는 것입니다.

#include <unistd.h>

long fpathconf(itn filedes, int name);
long pathconf(const char *path, int name);

두 함수 모두, pathname에 관련된 정보를 얻는 목적으로 쓰이며, fpathconf()는 이미 열려있는 file descriptor를, pathconf()는 파일/디렉토리 이름을 첫 인자로 받습니다. PATH_MAX⁠의 값을 얻으려면 두 함수 모두 두번째 인자에 _PC_PATH_MAX⁠를 주면 됩니다.

왜 file descriptor나 파일/디렉토리 이름이 필요한지 궁금해 하는 분도 있을 것입니다. 그 이유는, 앞에서 잠깐 말했듯이, pathname의 최대값은 현재 파일 시스템에 따라 달라질 수 있기 때문에, 기준이 되는 파일/디렉토리 이름이 필요하기 때문입니다.

이 두 함수 모두, 다른 정보를 얻기 위해 사용되기도 합니다. 예를 들어, 단순한 파일 이름의 최대값을 얻으려면 위 함수의 두번째 인자로 _PC_NAME_MAX⁠를 사용합니다. 또 주어진 파일이 pipe (또는 FIFO)인 경우, 파이프 버퍼의 크기를 얻기 위해 _PC_PIPE_BUF⁠를 쓸 수도 있습니다.

한가지 주의할 것은 이 때 얻은 PATH_MAX⁠ 값의 정확한 뜻입니다. 두 번째 인자로 _PC_PATH_MAX⁠를 쓸 경우, 첫 번째 인자로 전달한 파일 이름이나 file descriptor는 반드시 디렉토리에 대한 이름 또는 file descriptor이어야 합니다. 첫 번째 인자가 디렉토리를 가르킬 경우, 이 때 리턴한 값은 주어진 디렉토리를 기준으로한 상대 경로가 가질 수 있는 최대 길이를 뜻합니다. 만약 첫번째 인자가 디렉토리를 가리키지 않는다면, 리턴 값과 주어진 파일과 어떤 관계가 있다는 것을 보장할 수 없습니다. 또한 pathname의 길이에 대한 제한이 없는 경우, 이 두 함수는 -1을 리턴하고 errno를 설정하지 않습니다.

추가적으로, POSIX는 _POSIX_PATH_MAX⁠란 매크로를 256으로 정의하고 있습니다. 그리고 PATH_MAX⁠는 적어도 _POSIX_PATH_MAX⁠와 같거나 큰 값을 가져야한다고 정의합니다. 또 오래된 유닉스 시스템은 전통적으로 MAXPATHLEN이란 매크로를 쓰는 경우가 많습니다. (주의, 필자는 MAXPATHLEN의 정확한 뜻이나 유래에 대해 잘 모릅니다. 아시는 분은 제게 알려주시면 고맙겠습니다.)

또, ISO C 표준은 파일 이름을 저장하기 위한 배열의 크기를 지정할 목적으로 FILENAME_MAX⁠란 매크로를 <stdio.h>⁠에 정의하고 있습니다. 이 매크로는 배열을 선언할 때 쓸 목적으로 만든 것이기 때문에 다음과 같이 쓰는 것이 가능합니다:

char buf[FILENAME_MAX];

하지만, 사용가능한 파일의 최대 길이가 제한이 없는 경우라면, 문자 배열의 크기로 쓸만한 값을 FILENAME_MAX⁠로 정의한다고 나와 있습니다. 따라서 파일의 최대 길이가 제한이 없는 경우라면 pathconf()나 fpathconf()를 써야만 알 수 있습니다. (errno 변경없이 -1을 리턴)

따라서 이식성이 뛰어난 프로그램을 만들고 싶다면 다음과 같은 코드를 헤더 파일에 포함시키는 것도 좋을 것입니다:

#include <unistd.h>
#include <limits.h>

#ifndef _POSIX_PATH_MAX
#define _POSIX_PATH_MAX    256
#endif

#if !defined =PATH_MAX=  && defined _PC_PATH_MAX
# define PATH_MAX    (pathconf("/", _PC_PATH_MAX) < 1 ? 1024 \
		      : pathconf("/", _PC_PATH_MAX))
#endif

#if !defined PATH_MAX && defined MAXPATHLEN
# define PATH_MAX MAXPATHLEN
#endif

#if !defined PATH_MAX && defined FILENAME_MAX
# define PATH_MAX FILENAME_MAX
#endif

#ifndef PATH_MAX
# define PATH_MAX _POSIX_PATH_MAX
#endif

물론 완벽한 것은 아닙니다. 사실 위 코드는 gnulib 패키지의 <pathmax.h>를 조금 손본 것이며, pathname 길이에 제한이 없는 경우는 고려하지 않았습니다.

Summary

지금까지 내용을 요약해 보면,

  1. pathname을 저장하기 위해, PATH_MAX⁠를 쓰는 것은 바람직하나, PATH_MAX⁠보다 큰 pathname이 존재할 수도 있다는 것.
  2. PATH_MAX⁠를 쓸 경우, 동적으로 메모리를 할당하는 방식 (예: malloc() 함수)을 쓰는 것이 바람직하다는 것.
  3. PATH_MAX⁠는 마지막 '\0'도 포함한다는 것. 즉 PATH_MAX⁠ + 1과 같은 형태로 쓸 필요가 없다는 것.
  4. PATH_MAX⁠가 정의되어 있지 않을 경우, pathconf(3) 또는 fpathconf(3)를 써서 PATH_MAX⁠의 값을 얻을 수 있다는 것.
  5. 세번째 목적으로 pathconf(3)나 fpatconf(3)를 쓸 때, 첫번째 인자는 디렉토리를 가리키고 있어야 한다는 것입니다.

마지막으로, FILENAME_MAX⁠를 제외한 모든 매크로, 함수는 SUS 표준 (POSIX)이며, ISO C 표준에는 나와 있지 않다는 것을 말해 둡니다.

Parallel commands execution using GNU screen

I have been working on to develop large-scale web application, which deals with a lot of image files. To test the application, we need a huge number of large (the resolution should be higher than 640x480) images. Since we didn't have lots of samples, I decided to grab from http://images.google.com/. For my own execuse, the testing will be done in private network, which makes me less obligation for the copyright issue.

The image archiving job was simple. I create a small shell script that extracts actual image URL from the saved Google images result, and saved that file as images.lst. Each line of that file contains image URL. Then I create another script that reads URL one by one, and wget the image to the local storage, and produce several thumbnails using ImageMagick. So the whole process can be describe as:

$ cat images.lst | ./image-downloader.sh

I intended to download around 1000 images, and since it uses just one thread of execution, it will takes for a while. At that time, I was beginning to wonder, "It would be great if there is an utility that automatically divide the input data file into specified number of pieces, then execute the command that I specified for each piece."

I instantly remembered that there is a tool called parallel, but I decided to make my own. There is a reason to build from scratch:

The work job program, which will deal with dividened piece, is not matured program mostly. This means that I need to watch the progress of each job process output, and I need to fix it in quick-and-dirty way. Similar to previous reason, sometimes, I need to analyze the output of the process at the run-time. Needs a 'detatched from tty' feature, so that I can launch the whole process in remote and can forget it for a while. All the reasons makes me to think, it would be great if I can create a script (I named it, screen-parallel.sh) to use GNU screen to do the parallel jobs. For example, if I specified the concurrency level to 10, then screen-parallel.sh will divide the input into 10 pieces, and will create 10 screen windows, and execute the command that I specified per piece.

For example, in the beginning of the article, I used "cat images.lst | ./image-downloader.sh". To do that job in 10 workers,

$ screen-parallel.sh -h
Parallel execution of a command using GNU screen(1)
Usage: screen-parallel.sh [OPTION...] COMMAND [ARG...]

    -c CONCURRENCY           set concurrency level (default: 3)

    -i INPUT                 specify input data file
    -p                       send input to STDIN of COMMAND

    -d                       leave screen(1) in detached state.

    -v                       verbose mode

If no input file specified, this program will create CONCURRENCY
windows, then each window will execute COMMAND with ARGs.

Otherwise, input file will be splitted in CONCURRENCY parts, and
COMMAND will be executed per part.  If any of ARG is "{}", then it
will be substituted to the pathname of the part.  If there is none,
the pathname of the part will be appended to ARGs.

Example:

    # Split 'input.txt into 5 parts,
    # and execute "./process.sh -i PART-PATHNAME -v".
    screen-parallel.sh -i input.txt -c 5 ./process.sh -i {} -v

    # Run 3 instances of "standalone.sh -p"
    screen-parallel.sh -c 3 ./standalone.sh -p

$ screen-parallel.sh -c 10 -i images.lst -p ./image-downloader.sh

Option -c 10 means to specify the concurrency level to 10, and option -i images.lst means to use the input file, images.lst, and option -p indicates that the each divided piece will be provides via STDIN to the command process.

The whole source code is provided in the GitHub repository. Feel free to leave an issue there if you have any comment or suggestion. Thanks.

A tool for registering CouchDB design documents, couch-register-design

Whenever I experiment CouchDB, especially design documents, always I feel unhandy to upload the document.

For simple experiments, Futon (CouchDB web interface) is the easiest solution. However, if you want to keep the changes systemically, or if you want to use any version control system, you're on your own.

The difficulty come from the format of the design document; CouchDB wants you to specify javascript functions in JSON string. If you decided not to use Futon, you'll escape your function in JSON string by yourself.

Worse, if your function is not valid, you'll realize after the design document is uploaded.

Precisely, I want a tool that:

  • can add/update the design document from the sources that I provided,
  • can verify all javascript functions before uploading,
  • can upload attachment files.

First, I tried to use CouchApp, but lack of the detailed guide makes me gave up. Sorry CouchApp folks. :(

Second, I wrote simple bash shell scripts to interact with CouchDB with curl(1), to upload the document after escaping the function to build JSON document. It was not simple to implement all the features that I need, so I stopped.

Third, I try to write the tool in Ruby, and try to use httpclient, but I couldn't make httpclient works for HTTP client features like multipart/form-data. (Mayhaps I didn't know how to use httpclient fluently.) So I stopped again.

Fourth, I realized that I spent too much time to write this script. I don't want to dig the source of the httpclient, so I just write small Ruby wrapper of curl(1), and made the tool, finally.

If you have interest, visit couch-register-design and experiment.

$ ./register-designs.rb -h
Usage: register-designs.rb [OPTION...] DIRECTORY

    -d, --database [URL]             CouchDB endpoint URL
				     (default: "http://localhost:5984/sedis")

    -j, --jspath [JS-PATH]           Javascript interpreter
    -v, --verbose                    Verbose output

    -h, --help                       Show this message
    -V, --version                    Show version and exit

Register design documents from DIRECTORY where it contains
files for the document.

  DIRECTORY/views/VIEW-NAME/*.js  (e.g. map.js or reduce.js)
  DIRECTORY/shows/*.js            (e.g. print.js or others)
  DIRECTORY/*.js                  (e.g. validate_doc_update.js)
  DIRCETORY/_attachments/*        (automatically uploaded)

Report bugs to <cinsky at gmail.com> or post bugs to
  <https://github.com/cinsk/couch-register-design/issues>

Emacs Mail Address Completion

I don't use Emacs for reading mails. All of my mail servers uses IMAP, and for productivity, Emacs as a mail client is too slow. It's kind of sad. However, sending e-mail in Emacs (M-x mail) speed up my daily work greatly. Normally, I discuss some code within Emacs, and for the reference, I send the code fragment or org file to the discussioners. ('discussioner' is not an English word. I don't know any word for it.)

The problem is, I usually don't remember mail address for people. Had I used graphical mail agent such as thunderbird or outlook, I would be pleased to see the auto-completion feature of them. But no such luck in Emacs. (Yes I know there are couple of Emacs packages that analyze mail boxes to extract the mail addresses, but none makes me comfortable enough. Those who want it anyway, see BBDB)

All I want is, to use my gmail contacts as address completing candidates.

So I wrote very simple Ruby script, to extract the contact information from my gmail account, and save it as contacts.el using following command:

$ cd $HOME/.emacs.d
$ ./gcontact.el MY-GMAIL-ACCOUNT@gmail.com
password: ********
$ _

Then add following code to your init script:

(defun complete-contact-address-internal ()
  (let ((name (completing-read "address: "
			       my-google-contacts
			       nil 'confirm)))
    (if (string-match "@" name)
	name
      (let ((found (assoc name my-google-contacts))
	    (nam (if (string-match "\\(.*?\\) *([^)]*) *$" name)
		     (match-string 1 name)
		   name)))
	(format "%s <%s>" nam (cdr found))))))

(defun complete-contact-address (&optional arg)
  (interactive "P")
  (let ((address (complete-contact-address-internal))
	(pos (point)))
    (save-restriction
      (save-match-data
	(goto-char (point-min))
	(re-search-forward (regexp-quote mail-header-separator)
			   (point-max) t)
	(beginning-of-line)
	(let ((header-sep (point)))
	  (if (>= pos header-sep)
	      (progn
		(goto-char (point-min))
		(re-search-forward "^To:" header-sep t))
	    (goto-char pos))
	  (beginning-of-line)
	  (if (or (re-search-forward "^[^[:blank:]][^:]*:[[:blank:]]*$"
				     (line-end-position) t)
		  (re-search-forward "^[[:blank:]]+$" (line-end-position) t))
	      (insert address)
	    (beginning-of-line)
	    (re-search-forward "[,[:blank:]]*$" (line-end-position) t)
	    (replace-match (format ", %s" address))))))))

(eval-after-load "sendmail"
  '(progn
     (define-key mail-mode-map [(meta return)] 'complete-contact-address)

     (let ((contacts (concat (file-name-as-directory user-emacs-directory)
			     "contacts.el")))
       (when (file-exists-p contacts)
	 (load-file contacts)))))    

When writing e-mail in Emacs using M-x mail, press M-RET to auto-completing mail address.

Emacs mail address completion

Listing of gcontract.rb:

Wait until TCP port opened using bash and nc

Recently, I wrote a shell script which interacts with a TCP server. Since the script took charge of launching the server, sometimes my script fails because the server did not open the socket yet.

To come up with this problem, I used to wait certain amount of time using sleep(1) like this:

# launch the server which automatically daemonizes itself.
start-server 

# one second is enough for my system.
sleep 1

client do something

It was fine for my system, until I realized this method would not work on slow machine. Worse, when my system in a heavy-load, my system also failed to run above script successfully.

I would solve this problem by raising the amount of seconds sleeping, but I do not want to wait more on my relatively fast system.

Then I realized that netcat (a.k.a. nc) provides such feature with the "-z" option.

To test whether www.cinsk.org (TCP port 80) is opened, I can launch

# In BSD-like (MacOS) system
$ nc -z www.cinsk.org 80
Connection to www.cinsk.org 80 port [tcp/http] succeeded!
$ _

# On my Linux system, no message but just return zero on success
$ nc -z www.cinsk.org 80
$ _

Then I found another problem. Suppose that the firewall drops all packets for that port. Since by default, netcat(nc) will wait permanently until the port is open, the script that uses netcat(nc) will not return.

Thanks to the rich interface of netcat, it provides another option "-w" to specify the amount of time it will wait. The problem is, MacOS nc (BSD) does not work with "-w" option if the firewall drops all packets. Installing GNU version will solve this problem. (by the command "brew install netcat")

Finally, I wrote wait4tcp.sh to lessen the burden for others.

# Wait until port 80 8080 5984 are opened
$ ./wait4tcp.sh HOSTNAME 80 8080 5984

# The same as above, except it will retry only 10 times per each port.
$ ./wait4tcp.sh -w 10 HOSTNAME 80 8080 5984

# Wait until port 80 is closed
$ ./wait4tcp.sh -c HOSTNAME 80

# The same as above, except it will retry permanently.
$ ./wait4tcp.sh -w -1 -c HOSTNAME 80

# With the bash brace expansion, wait for port range 6379..6383 are opened
$ ./wait4tcp.sh HOSTNAME {6379..6383}

By default, wait4tcp.sh will retry 100 times per each port. Retrying 100 times is done less than 1 second in my system. Using "-w -1" option will retry permanently.

Updated

Recently, I read valuable article from TCP Port Scanner in Bash, and found that bash provides special filenames for redirections.

As Peteris suggested, I changed to bash special filenames and timeout(1) so that there is no dependency to netcat(nc).

Here is the full source code for wait4tcp.sh:

<script src="https://gist.github.com/3769111.js"> </script>

Emacs ruby-mode and RVM propmt

On emacs ruby-mode, if you do M-x run-ruby (or C-c C-s), the inferior ruby interpreter is provided in the "*ruby*" buffer so that you can evaluate lots of ruby statements or expressions.

When you press M-p (M-x comint-previous-input), Emacs will cycle to the previous input histrory saving input, so that you can easily re-evaulate of your previous input.

It works like other inferior interpreter provided by python-mode, slime, and so on.

What makes me frustrated is, it works for the ruby 1.8 installed in my gentoo system, but it does not work for the ruby 1.9.3 installed via RVM. The minibuffer shows sulpurous error:

Search failed: "^irb(.*)[0-9:]+0> *"

Looking at the ruby-mode's source, I found that string is the value of 'inferior-ruby-first-prompt-pattern' in inf-ruby.el. It looks like that ruby-mode uses inferior-ruby-first-prompt-pattern and inferior-ruby-prompt-pattern for the ruby's prompt pattern.

Another notable different from the start between two rubies (v1.8 system versus v1.9 RVM) are their prompt patterns:

# ruby 1.8 (system)
irb(main):001:0> _

# ruby 1.9.3 (RVM)
ruby-1.9.2-p180 :001 > _

Now it's clear who is the culprit. Due to the difference of the prompt pattern, ruby-mode could not provide me M-p or M-n working.

So I modified two variables in inf-ruby.el and reports a bug to the Ruby issue tracking system and got a quick response.

It turns out that it's not the fault of ruby-mode, but it's the fault of RVM. (Actually, it's not a defect. It just not right for my purpose.)

By default, RVM uses different prompt from the native ruby. To solve this, you can force RVM ruby (irb) to use the native prompt pattern. It's simple: modify $HOME/.irbrc to include following:

IRB.conf[:PROMPT_MODE] = :DEFAULT

I feel embbarassed that I blamed ruby-mode when I found something is wrong :(

OS X Emacs 24.1 Fontset revised

Whenever I installed new Emacs version, the init script for fontset turned out not working. It is sad that even now Emacs fontset related API is somewhat unstable. I cannot blame Emacs developers for this. Part of the reason is there are so many bad font (esp. Korean font) which works very poorly on non-Windows machines.

Anyway, the script in my previous post does not work with the stable 24.1 binary from EmacsForMacOsX.

Here are working version of Emacs snippet that uses different font for multiple charset:

(when (eq system-type 'darwin)
  ;; These configuration seems to work in
  ;; GNU Emacs 24.1.1 (x86_64-apple-darwin, NS apple-appkit-1038.36)
  ;; of 2012-06-11 on bob.porkrind.org

  ;; default font family
  (set-face-attribute 'default nil :family "Consolas")

  ;; default font size
  ;;
  ;; WARNING: depending on the default font, some height value may
  ;; cause a broken frame display; that is, the beginning of the 
  ;; buffer is not visible.
  (set-face-attribute 'default nil :height 165)

  ;; You may add :size POINT in below font-spec if you want to use
  ;; specific size of Hangul font regardless of default font size
  (set-fontset-font t 'hangul
		    (font-spec :name "NanumGothicCoding")))

Height 165 seems to work well with "Consolas" font.

Yes! The height is 165 (about 16 pt). As I'm growing old, I cannot use smaller font size any more. It sucks! Anyway, here is the screenshot with the above setting:

[[nil]

I tried with several fonts such as Monaco, Andale Mono, and so on but I found Consolas is superior among others (this is my biased opinion, of course.)

Smart ediff widen frame on Emacs

One of the reason that I love Emacs is the ediff package, which provides nice diff interface that I cannot find similar feature in other editors. Here are some screenshots of sample ediff session:

Ediff Example 1Ediff Example 2

The first one (on left-side) uses the default split, called vertical split, and the second one (on the right-side) is called horizontal split. You can switch back and force using | or M-x ediff-toggle-split command in the ediff control buffer. As you can see here, the horizontal split looks much more readable. One problem, though. Normally, I uses 80 character width for a emacs frame. If I choose to use the horizontal split, it automatically split the windows in the 80-char-width frame, so that each window will have about 40 characters. (Actually, depending on the width of the scroll bar and the internal borders, it will be smaller than 40 characters).

Around a couple of years ago, I wrote custom hook function to automatically widen the frame on the "horizontal split" and restore to the original frame width when ediff session finished. What makes me to feel stupid is, Ediff has already provided that feature years ago. If you use m or M-x ediff-toggle-wide-display on the ediff control buffer, the frame width will span to that of the display.

One problem is, I use two LCD minitor, combined into one X display (using nvidia's TwinView feature). Each monitor supports 1920x1080, so my X window system provides 3840x1080 display. That means, if I call ediff-toggle-wide-display, the screen will look like:

Ediff Wide Display

As you can see, this is unacceptable. So, again, I need to modify the configuration little bit, so that it will widen the frame in a reasonable amount.

Let's find out which code should be modified. On the ediff control buffer, C-h k m shows that the m command is binded to ediff-toggle-wide-display in ediff-util.el. After reading the function code, ediff-toggle-wide-display will call the function in the value of ediff-make-wide-display-function, which is set to ediff-make-wide-display by default. This means that, if I write my own function that does the job of ediff-make-wide-display, problem will be solved! Yeah~

But what makes me troubled is, it is not straight-forward to determine the 'reasonable amount of frame width. Several ideas come up to my mind:

  • Normally, most people prefer 80 character width for a window. What about 80 * 2 = 160 for the widened frame? — No, using hard-coded value is always a bad choice.
  • Each buffer can have its own fill-column value, which is 70 by default. What about to use fill-column * 2? — No, probably using the previous width of the windows is the better.
  • Ediff provides 2 way diff or 3 way diff job. Merely doubling the width is not good. Depending 2-way-diff or 3-way-diff, I might need to multiply by two or by three.
  • In any case, user might want to use specific width. It will be handy, if m command can have prefix value for the exact width of the window. For example, 160m will set window width to 160, so that total frame width will be 160 * 2 = 320 character width.

To provide the prefix value, I need to wrap the ediff-toggle-wide-display with my own advice function:

(defadvice ediff-toggle-wide-display (around cinsk/ad-ediff-toggle-wide-display
					     ())
  (interactive)
  (let ((w (prefix-numeric-value current-prefix-arg))
	(min-width (cond ((window-live-p ediff-window-A)
			  (if (eq ediff-split-window-function 
				  'split-window-vertically)
			      ;; ediff windows splitted like A/B
			      (window-width ediff-window-A)
			    ;; ediff windows splitted like A|B
			    (frame-width (window-frame ediff-window-A))))
			 ((buffer-live-p ediff-buffer-A)
			  (buffer-local-value 'fill-column
					      ediff-buffer-A))
			 (t (max fill-column 70)))))
    (setq w (max min-width w))
    (message "width: %S" w)

    (let ((cinsk/ediff-wide-window-width w))
      ad-do-it)))

(ad-activate 'ediff-toggle-wide-display)

Since advice function cannot change the function interface of the advised function, I'm not sure if I can use current-prefix-arg in the advice function like above. One more bad design is, above code relies on the dynamic binding of the local variable, cinsk/ediff-wide-window-width. Anyway it works as I expected. :)

For the ediff-make-wide-display-function, I'll use following function instead of genuine one:

(defun cinsk/ediff-make-wide-display ()
  "Construct an alist of parameters for the wide display.
Saves the old frame parameters in `ediff-wide-display-orig-parameters'.
The frame to be resized is kept in `ediff-wide-display-frame'.
This function modifies only the left margin and the width of the display.
It assumes that it is called from within the control buffer."
  (if (not (fboundp 'ediff-display-pixel-width))
      (error "Can't determine display width"))
  (let* ((frame-A (window-frame ediff-window-A))
  (frame-A-params (frame-parameters frame-A))
	 (fw (frame-width frame-A))
	 (fpw (frame-pixel-width frame-A))
  (cw (ediff-frame-char-width frame-A))
	 (febw cw)                      ; frame external border width
	 (fibw (- fpw (* fw cw)))       ; frame internal border width
	 desired-fw desired-fpw desired-left)

    (setq ediff-wide-display-orig-parameters
   (list (cons 'left (max 0 (eval (cdr (assoc 'left frame-A-params)))))
  (cons 'width (cdr (assoc 'width frame-A-params))))
   ediff-wide-display-frame frame-A)

    (setq desired-fw (* cinsk/ediff-wide-window-width
			(if (and (boundp 'ediff-3way-job) ediff-3way-job)
			    3 2)))

    ;; ensure that DESIRED-FW is smaller than the screen size
    (if (> (+ (* desired-fw cw) febw fibw) (ediff-display-pixel-width))
	(setq desired-fw (/ (- (ediff-display-pixel-width) fibw febw) cw)))

    ;;(setq desired-fpw (+ (* desired-fw cw) fbw))
    (setq desired-fpw (* desired-fw cw))
    (let ((left (eval (cdr (assoc 'left frame-A-params)))))
      (cond ((eq cinsk/ediff-wide-display-policy 'left)
	     (setq desired-left (- left (* (- desired-fw fw) cw))))

	    ((eq cinsk/ediff-wide-display-policy 'right)
	     (setq desired-left left))

	    (t                          ; center
	     (setq desired-left (- left (/ (* (- desired-fw fw) cw) 2)))))

      ;; ensure that the frame will be inside of the display border.
      (if (< (- desired-left (/ febw 2)) 0)
	  (setq desired-left (/ febw 2)))

      (if (> (+ desired-left (+ (* desired-fw cw) fibw (/ febw 2)))
	     (ediff-display-pixel-width))
	  (setq desired-left (- (ediff-display-pixel-width) 
				(+ (* desired-fw cw) fibw (/ febw 2))))))

    ;; (message "resizing WIDTH to %S where LEFT to %S" desired-fw desired-left)

    (modify-frame-parameters
     frame-A `((left . ,desired-left) (width . ,desired-fw)
	       (user-position . t)))))

Of course, I need to set ediff-make-wide-display-function before loading ediff module, so put below line in front of the init file:

(setq ediff-make-wide-display-function 'cinsk/ediff-make-wide-display)
(require 'ediff)

And if you want to restore to the previous frame configuration on ediff exit, add following code:

(add-hook 'ediff-quit-hook
	      (lambda ()
		(if ediff-wide-display-p
		    'ediff-toggle-wide-display)))

You may also want to register above function (lambda () ...) in ediff-suspend-hook if you want to restore the frame on ediff suspension.

If you want full source, check out my github repository.

Emacs, Mac, Fontset, Font and X resources

Recently, I bought a macbook pro for my personal use. As soon as it is delivered to my home, I installed Emacs 24.x, from EmacsForMacOsX. Normally, in my other computers, I use the version 23.x. The reason that I installed unstable 24.x is, that I want to use the package system (package.el) in my macbook. It would be very boring and tedious if I need to install all the packages that I want to use like in my other Gentoo linux.

For my Linux systems, I uses Korean and English fonts using Emacs's X resource configuration. For example,

Emacs*Fontset-0:-*-DejaVu Sans Mono-*-*-*-*-14-*-*-*-*-*-fontset-dejavu14,\
	  latin:-*-DejaVu Sans Mono-*-*-*-*-14-*-*-*-*-*-*,\
	hangul:-*-NanumGothic_Coding-*-*-*-*-*-*-*-*-*-*-*
Emacs.Font: fontset-dejavu14

But in my macbook, it didn't work. The reason is, in Mac, the X window system is not running by default. It seems that MacOS delays loading X window system until the first X application starts. And it takes a couple of seconds, which I don't like it. Of course, I could force to load the X resource, by using xrdb -merge MY_EMACS_X_RESOURCE_FILE in my .bash_profile but as I said before, it took several seconds to load the X system.

So, I want to set my fontset configuration in the startup lisp code instead X resource file. With a few experiments, here are the working version:

(set-fontset-font "fontset-standard" 'unicode 
		  (font-spec :name "Consolas"
			     :weight 'normal
			     :slant 'normal
			     :size 16)); nil 'prepend)
(set-fontset-font "fontset-standard" 'hangul
		  (font-spec :name "NanumGothicCoding"))

(set-face-font 'default "fontset-standard")

In addition to fontset configuration, there are a few more configuration for Mac.

  1. I want to use Command key as a meta key, since it's where the Meta key should be.
  2. I want to use Command-C to work as "copy the content to the clipboard". Since the Command key is meta key now, I want to bind M-c to something that works like "copy the selection to the clipboard for other application.".
  3. I want to make Fn-Delete key as to delete right character.
  4. I want to maintain one startup lisp code for all my Linux machines and Macbook.

With some help, here's the complete lisp code for Mac:

(when (eq system-type 'darwin)
  (setq mac-option-modifier nil)
  (setq mac-command-modifier 'meta)
  ;; sets fn-delete to be right-delete
  (global-set-key [kp-delete] 'delete-char)

  (set-fontset-font "fontset-standard" 'unicode 
		    (font-spec :name "Consolas"
			       :weight 'normal
			       :slant 'normal
			       :size 16)); nil 'prepend)
  (set-fontset-font "fontset-standard" 'hangul
		    (font-spec :name "NanumGothicCoding"))

  (set-face-font 'default "fontset-standard")

  (when (display-graphic-p)
    (global-set-key [(meta ?c)] 'ns-copy-including-secondary)))

Finally! I can use Emacs with my custom preferences like in my Linux machines. :)

Note that this configuration worked on Emacs pretest binary 24.x EmacsForMacOsX. As 24.1 is turned to the stable release, it suddenly turned out not working! :( Read on more here.