리눅스에서 "아래아 한글(한/글)"은 불편하다. 정확히 말해서는 한/글보다는 hwp 파일 포맷이라고 해야 겠지만 hwp 포맷이 한/글의 기본 파일 포맷인데다 아직까지 이를 한/글만큼 완벽히 읽어내는 프로그램이 없으니 "hwp 포맷 == 한/글 사용"이라고 해도 큰 무리는 아닐 것이다. 하지만 아쉽게도--한글과 컴퓨터(한컴)에게는 아니겠지만-- 이놈의 hwp 포맷은 앞으로도 꽤 오랫동안 없어지지 않을 것 같다. 민간 업체에서는 그렇지 않다지만, 관공서 쪽에서는 거의 100% 한/글을 사용하고 있는 것 같고, 우리나라에서 관공서는 아직까지는 전통의 甲이라는 점을 고려하면 공무원뿐만 아니라 관공서 관련 업체에서도 한/글을 사용할 수 밖에 없다는 답이 나온다.
다행히 작년(2014년)에 한컴에서 다시 리눅스용 "한컴오피스 한/글 2014 뷰어"를 배포했다. 무료다. :-) 뷰어라서 수정은 안되지만 보는 것과 인쇄하는 것만큼은 깔끔하게 잘 된다. 그래도 이만하면 어딘가? 간단한 hwp 파일 확인하려고 wine이나 vmware를 실행시킬 일은 없어지는 셈이다. 사실 2001년 쯤에 리눅스용 한/글이 발매된 적이 있었고 2010년에는 한컴에서 윈도우즈용 한컴오피스 2008 버전을 리눅스용으로 포팅해서 판매하기도 했다. 하지만 많이 쓰이지는 않는 것 같다. 하긴 한/글의 주요 사용자인 관공서에서 사무용으로 리눅스를 쓸 일이 없으니... 오히려 나처럼 wine이나 vmware에 윈도우즈용 한/글을 깔아 쓰는 사람이 많았던 듯.
잡설이 길었다. 아래에 내 젠투 박스에 한글 2014 뷰어를 설치했던 과정을 적는다.
1. 설치
먼저 설치 파일을 구해야 한다. 한컴의 링크에 보면 H&Friends 홈페이지에서 다운을 받을 수 있다고 되어 있는데, 정작 H&Friends 홈페이지에 들어가도 다운 받을 수 있는 링크는 찾을 수 없다. 옛날에 내가 분명 다운을 받은 적이 있으니 그 이후에 지워진 듯 한데, 한컴에서 사용자들을 일부러 골탕 먹일려고 한 것은 아닐테고... 혹시 유료 서비스인 넷피스를 쓰게 하려고? 설마 국내 PC 사용자의 1%도 안되는 리눅스 사용자를 대상으로 그렇게나 치밀하고 미래발전적인 전략이... 내 생각엔 아마도 라이센스 문제 때문에 링크를 지운게 아닌가 생각된다. 리눅스에서 사용되는 대표적인 라이브러리인 glibc만 하더라도 라이센스가 LGPL로 되어 있지만 각각의 모듈 중에는 GPL이 적용되는 게 있어서 일괄적으로 LGPL이 적용된다고 하기에는 논란의 소지가 있다고 한다. 만약 부분적으로 GPL이 적용된다고 결론이 난다면 한컴은 해당 부분의 소스코드를 공개해야 하는 부담을 안게 된다. 기업의 존립을 흔들 수도 있는 부담! 이건 뭐... 그냥 내 혼자 생각이다.
설치 파일은 아래 구글 드라이브 링크에서 다운 받을 수 있다.
https://drive.google.com/file/d/0BxNTay729OWHTTl0QlRwN2I2LUE/view?pref=2&pli=1
다운 받은 HWP_Viewers_Linux.zip 파일의 압축을 풀면 32bit용 hwpviewer_9.20.0.346_i386.deb과 64bit용 hwpviewer_9.20.0.347_amd64.deb 파일이 보인다. 한/글 2014 뷰어는 Ubuntu 14.04 LTS 기반으로 제작되었기 때문에 deb 형식으로 패키징 되어 있다. 다운 받은 두 개 deb 파일을 /usr/portage/distfiles/로 복사 한다.
이제 진짜 설치를 해야 하는데, Ubuntu야 그냥 apt-get으로 설치하면 된다지만 Gentoo는 그렇게 안되니 ebuild 파일을 만들어야 한다. 그냥 수동으로 압축을 풀어 복사하거나 dpkg 패키지를 이용할 수도 있겠지만 그래도 커스텀 ebuild를 만들고 로컬 overlay에 설치해서 인스톨하는 방법이 가장 젠투스럽다.
참고로 아래는 내가 사용한 ebuild 파일. 오리지널은 인터넷에서 다운받아--원 저자에게는 죄송하지만 어디서 다운 받은 것인지 당최 찾을 수가 없다-- 순전히 나 혼자 쓰려고 몇 가지 수정을 한거라 공개하기에는 좀 거시기하지만 그럭저럭 설치하는데는 문제없다. 파일 첨부를 했으면 좋았겠지만 이 블로그는 파일 첨부가 안되서 참담함을 무릅쓰고...
바로 copy & paste 초식을 시전할 타이밍이다. 주욱~ 긁어서 적당한 ebuild 파일명으로, 예를 들어 /usr/local/portage/app-office/hwpviewer-bin/hwpviewer-bin-9.20.0.346.ebuild, 로컬 오버레이에 저장하면 되겠다. 그리고 드디어 emerge!
이런! emerge 전에 digest!!!
# Copyright 1999-2013 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ EAPI="4" inherit gnome2 DESCRIPTION="HWP document viewer" HOMEPAGE="http://www.hancom.com" SRC_URI="x86? ( hwpviewer_9.20.0.346_i386.deb ) amd64? ( hwpviewer_9.20.0.347_amd64.deb )" LICENSE="GPL-2" SLOT="0" KEYWORDS="amd64 x86" IUSE="" RESTRICT="fetch mirror strip" RDEPEND=" virtual/libc x11-libs/cairo:0 =media-libs/fontconfig-2* media-libs/freetype:2 x11-libs/gdk-pixbuf:2 =sys-libs/glibc-2* x11-libs/gtk+:3 net-libs/webkit-gtk:3 =virtual/libstdc++-3* >=x11-libs/libX11-1.6 dev-libs/libxml2:2 gnome-base/gvfs sys-libs/zlib gnome-base/gsettings-desktop-schemas:0 dev-util/desktop-file-utils:0 dev-util/gtk-update-icon-cache:0 " MY_P="data.tar.xz" src_unpack() { default # make ${S} directory. i.e., ${WORKDIR}/%{P} mkdir "${P}" mv ${MY_P} ${S} } src_prepare() { unpack ./${MY_P} } # dummy phase to use gnome2_pkg_* functions src_configure() { return } # same as above src_compile() { return } src_install() { # doins does NOT repect file permissions cp -R "${S}/"usr "${D}/" || die "Install failed!" } # for GSettings, Icons, desktop and mime database updates. pkg_preinst() { gnome2_pkg_preinst } pkg_postinst() { gnome2_pkg_postinst } pkg_postrm() { gnome2_pkg_postrm }※ 로컬 오버레이를 만드는 방법에 대해서는 젠투 사용자라면 대부분 알고 있을 테니 따로 적지 않는다. 혹시나 그렇지 않다면 언제나 그렇듯이 구글링!
2. 패치
이 글을 쓰게된 가장 큰 이유는 사실 지금부터다. 원래 패키징 기반인 우분투에서는 어떤지 모르겠지만, Gentoo에서는--아마 다른 배포판도 비슷할 것이다-- 위와 같이 설치를 해서 실행을 하면 segment fault를 내고 프로그램이 금방 죽어 버린다. 이상한 건 네트워크를 끊거나 su를 이용해서 root로 실행하면 정상적으로 실행이 된다는 거. 소스 코드가 공개되어 있지 않으니 정확한 원인은 알 수 없지만 에러 메세지로 보건대 프로그램 실행 초기에 업데이트를 체크하는 부분에서 메모리 해제 관련 에러가 있는 것으로 추정된다. 아래는 에러 메세지의 일부.
*** Error in `hwpviewer': munmap_chunk(): invalid pointer: 0xbfba13c0 *** ======= Backtrace: ========= /lib/libc.so.6(+0x6b3a6)[0xb46a13a6] /lib/libc.so.6(+0x71716)[0xb46a7716] /lib/libc.so.6(+0x717d0)[0xb46a77d0] /usr/lib/libglib-2.0.so.0(g_free+0x21)[0xb7682281] hwpviewer(_ZN10HwpUpdater10runCommandEPPc+0x3c)[0x890af9c] hwpviewer(_ZN10HwpUpdater23getDistributionSpecInfoEv+0x67)[0x890b047] hwpviewer(_ZN10HwpUpdater3runEv+0x123)[0x890b713] hwpviewer(_ZN10HwpUpdater8onUpdateEPv+0x2c)[0x890b9cc] hwpviewer(_ZN10HwpUpdater16onUpdateTaskDoneEPv+0x58)[0x890bac8] /usr/lib/libgdk-3.so.0(+0x15cfc)[0xb6daacfc] /usr/lib/libglib-2.0.so.0(+0x44ae0)[0xb7678ae0] /usr/lib/libglib-2.0.so.0(g_main_context_dispatch+0x162)[0xb767c562] /usr/lib/libglib-2.0.so.0(+0x48961)[0xb767c961] /usr/lib/libglib-2.0.so.0(g_main_loop_run+0xf1)[0xb767cd31] /usr/lib/libgtk-3.so.0(gtk_dialog_run+0x163)[0xb6fbbfa3] hwpviewer(_ZN8HwpFrame12onFileChangeEP10_GtkWidgetPv+0x25e)[0x88f2e2e] hwpviewer(_ZN8HwpFrame4openEPKc+0x3f)[0x88f302f] hwpviewer(_ZN6HwpApp11delayedOpenEPv+0x32)[0x88eab62] /usr/lib/libglib-2.0.so.0(+0x44ae0)[0xb7678ae0]원인이야 그렇다 치고 중요한 건 해결 방법이다. 결론부터 말하면 업데이트 서버 주소를 null로 변경해서 아에 업데이트를 위한 네트워크 접속 시도를 하지 않게 하는 것이다. 한/글 2014 뷰어는 "서버주소 != null" 체크 루틴이 들어가 있어 서버 주소가 null이면 업데이트 루틴이 시행되지 않게 프로그래밍된 듯하다. thanks! 이 방법은 kldp 게시판에서 어떤 귀인이--이름을 밝히지 않으셔서-- 알려 주셨는데 아래에 해당 kldp 게시물의 링크를 걸어 놓는 것으로 그 분과 kldp에 대한 고마움을 대신한다. 링크를 따라가는 수고를 조금한다면 Arch 리눅스의 설치 패키지를 득템할 가능성도 있다.
https://kldp.org/node/154351
물론 위의 방법이 정확한 해결 방법이라고는 할 수는 없다. 하지만 소스 코드가 없는 상황에서 바이너리 파일을 disassemble을 해서 어셈블리 코드와 한판 삽질을 벌이는 수고에 비하면 아무 것도 아니다. 더구나 몇 안되는 리눅스 사용자를 위해 한컴에서 지속적으로 업데이트를 제공해 줄 가능성은 현실적으로 낮아보인다. 실제로 업데이트 서버인 linuxupdate.hancom.com로 ping을 쏘아보면 아무 반응이 없고, 이 도메인에 사용된 ip가 CJ-HELLOVISION 꺼라고 whois에서 검색되기도 한다.
어찌 됐건, 업데이트 서버 주소를 null로 수정하는 것은 간단하다. 바이너리 에디터로 /usr/bin/hwpviewer 파일을 열어서 직접 써넣어도 되고, sed를 이용해도 되고, 아래처럼 dd를 이용해도 된다. 당근 이로 인해 초래되는 결과는 모두 자신 책임이다. 광고제거 패치는 보너스!
이 패치를 ebuild의 pkg_preinst()나 pkg_postinst()에 넣으면 깔끔하겠지만 부속 파일이나 문서 내용의 전부 또는 일부를 수정, 변형하려면 사전 서면 승인을 받아야 한다는 거룩한 한컴의 저작권을 존중해서 그러지 않았다. 깨갱~
BTW, 왜 Mac 버전 뷰어에는 광고를 넣지 않고 리눅스 버전에만 넣었지? Mac 유저가 더 많지 않나?
32bit(x86) 용 # 업데이트 접속 방지 sudo dd if=/dev/zero of=/usr/bin/hwpviewer bs=1 count=22 seek=$((0x1d02ffa)) conv=notrunc # 광고 제거 sudo dd if=/dev/zero of=/usr/bin/hwpviewer bs=1 count=45 seek=$((0x1d1a7e0)) conv=notrunc 64bit(amd64) 용, 써글! 그냥 sed로 했으면 이런 중복은 필요 없었을걸... # 업데이트 접속 방지 sudo dd if=/dev/zero of=/usr/bin/hwpviewer bs=1 count=22 seek=$((0x1bb9d07)) conv=notrunc # 광고 제거 sudo dd if=/dev/zero of=/usr/bin/hwpviewer bs=1 count=45 seek=$((0x1bb9e08)) conv=notrunc[추가]
hwpviwer는 처음 실행하면 첫 화면이 뜨기 까지 꽤 시간이 걸린다. 약 4~5초 정도. 이렇게 한 번 실행 시키고 나면 다음 번에는 금방 화면이 뜨기는 하지만, 혹시나 업데이트 때문에 처음 실행이 늦어지는게 아닌가 싶어서 디버거로 실행파일을 좀 디벼 봤다.
장님이 코끼리 다리를 만지듯이 hwpviewer의 실행과정을 따라가다 보면 대충 다음과 같은 그림이 그려진다.
①처음 main 함수가 실행되면 HwpApp 객체가 만들어 지고 ② HwpApp의 초기화(HwpApp.init)가 진행된다. ③초기화 과정 중에 업데이트 시작 함수(HwpApp.runUpdateTask)가 실행되는데 ④HwpApp.runUpdateTask 함수는 실제 업데이트를 진행할 HwpUpdater 객체와 thread를 생성하여 ⑤이후 업데이트 서버 체크와 저기 위에 에러 메세지에서 보이는 일련의 HwpUpdater의 이벤트 핸들러 메서드가 순차적으로 실행되는 것이다.
아래는 업데이트 시도를 아예 하지 않게 하는 막장 패치. 업데이트 시작 함수(HwpApp.runUpdateTask)를 호출하는 call 명령을 nop(0x90)으로 바꿔서 업데이트를 위한 이후의 프로세스들이 모두 실행되지 않게 한다. 따라서 이론적으로는 위의 업데이트 서버 주소를 null로 바꾸는 방법보다 실행속도가 조금이라도 빨라지는게 맞다. 하지만... 실제 체감속도는 별로 크게 달라지지 않았다는 거ㅠㅠ
32bit(x86) 용 echo "0x9090909090" | xxd -r -p | sudo dd of=/usr/bin/hwpviewer bs=1 count=5 seek=$((0x8a36af)) conv=notrunc 64bit(amd64) 용 echo "0x9090909090" | xxd -r -p | sudo dd of=/usr/bin/hwpviewer bs=1 count=5 seek=$((0x989b4f)) conv=notrunc※ 업데이트로 인한 세그먼트 폴트 에러를 해결하기 위해서라면 이 패치만 적용해도 되고, 저기~~ 위의 업데이트 서버 주소를 null로 만드는 패치와 이 패치를 둘다 적용해도 상관없다. 어차피 이 패치가 적용되면 업데이트 서버 체크하는 루틴은 실행되지도 않을 테지만...광고 제거 패치는 따로 해야 한다.
1 comment:
Newer Post
