Create TOC

2012년 11월 29일

Debian/wine으로 DirectX 쓰는 프로그램이 동작하지 않을 때

Debian amd64에서 wine으로 DirectX 사용하는 프로그램을 실행하면 항상 crash가 발생했다. 원인은 nvidia의 glx 드라이버의 32bit 버전 패키지가 변경Debian에서는 Multiarch 라는 개념이 도입되면서 amd64에서 i386 버전의 package를 설치하는 방식이 바뀌었다.되면서 발생한 문제이다.

아래와 같이 package를 다시 설치해준다.

$ sudo dpkg --add-architecture i386
$ sudo apt-get update
$ sudo apt-get install libgl1-nvidia-glx:i386

2012년 10월 16일

Debian/AirVideo Server 설치

이 문서는 Debian Sid AMD64에서 AirVideo Server를 설치하는 방법을 기술한다.

설치

Debian Multimedia 설정

$ sudo apt-get install deb-multimedia-keyring
$ sudo echo deb http://www.deb-multimedia.org sid main non-free >> /etc/apt/sources.list.d/debian-multimedia.list
$ sodo apt-get update
$ sudo apt-get upgrade

libav 빌드

$ sudo apt-get install autoconf build-essential checkinstall git libfaac-dev libgpac-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev librtmp-dev libtheora-dev libtool libvorbis-dev pkg-config texi2html yasm zlib1g-dev x264 libx264-dev
$ wget http://s3.amazonaws.com/AirVideo/Linux-2.4.6-beta3/libav.tar.bz2
$ tar -xjvf libav.tar.bz2
$ cd libav.tar.bz2
$ ./configure --enable-pthreads --disable-shared --enable-static --enable-gpl --enable-libx264 --enable-libmp3lame --enable-nonfree --enable-encoder=libfaac --disable-asm --prefix=<설치할 경로>
$ make -j3
$ make install

AirVideo 설치

아래 명령으로 jar 파일을 받아서 적당한 위치에 복사한다.

$ wget http://s3.amazonaws.com/AirVideo/Linux-2.4.6-beta3/AirVideoServerLinux.jar

설정

설정 파일 작성

네이버 사전체가 설치된 것을 전제로 설명한다.

아래와 같은 설정 파일을 만들고 적당히 저장한다.

path.ffmpeg = <libav 설치 경로>/bin/avconv
password = 1234
subtitles.encoding = cp949
subtitles.font = Naver Dictionary
folders = Movies:경로;TV:경로

Bonjour 등록

Bonjour에 등록하면 ip설정 없이 airvideo 서버에 접근할 수 있다.

아래 명령으로 avahi-daemon을 설치한다.

$ sudo apt-get install avahi-daemon

/etc/avahi/services/AirVideoServer.service파일을 만들고 아래와 같은 내용을 추가한다.

<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name replace-wildcards="yes">AirVideoServer on %h</name>
<service>
<type>_airvideoserver._tcp</type>
<port>45631</port>
</service>
</service-group>

avahi-daemon을 다시 시작한다.

$ sudo /etc/init.d/avahi-daemon restart

실행

주의할 점은 동영상의 소유주와 airvideo 를 실행하는 id 가 동일해야 한다.

$ java -jar <복사한 위치>/AirVideoServerLinux.jar <설정파일>

crontab 등록

매번 부팅시 자동 실행하려면 crontab -e을 이용해서 crontab에 등록한다.

@reboot java -jar <복사한 위치>/AirVideoServerLinux.jar <설정파일> 2&>1 /dev/null &

2012년 9월 1일

OS/X - Alfred를 이용해서 Evernote에 바로 글 적기

Alfred에 아래와 같은 applescript를 등록하면 "m 적을 내용" 이런 식으로 바로 Evernote에 메모를 추가할 수 있다.

on alfred_script(q)
  tell me
    do shell script "open /Applications/Evernote.app"
  end tell
  tell application "Evernote"
    set note1 to create note title q with text q notebook "노트를 추가할 노트북 이름"
    open note window with note1
    activate
  end tell
end alfred_script

2012년 8월 22일

Windows/디스크 정리 도구를 자동화

원문에서는 XP만 다루고 있지만 Windows 7에서도 잘 작동한다.

우선 아래 명령으로 자동으로 청소할 항목을 선택한다.

cleanmgr /SAGESET:1

여기서 1은 원하는 숫자를 사용하면 된다. 청소할 항목을 지정했으면, 아래 명령으로 지정한 항목을 청소시킬 수 있다.

cleanmgr /SAGERUN:1

Linux/awk를 사용해서 숫자들의 합 세기

아래와 같은 csv 파일이 있다고 가정한다.

a,1
b,2
c,3
d,4
e,5

위 파일에서 두 번째 열의 숫자를 모두 합하고 싶다면 아래와 같이 하면 된다.

cat test.csv | awk -F "," '{sum += $2} END {print sum}'

Linux/특정 확장자를 가진 파일의 line 수 세기

findwc를 사용하면 된다.

wc --lines `find ./ -type f \( -name "*.c" -or -name "*.cpp" -or -name "*.asm" -name "*.h" \)`

2012년 8월 14일

Windows8/제품 키를 변경해서 인증 받기

이미 등록된 제품 번호를 변경하고 다시 인증을 받는 방법을 설명한다.

관리자 권한으로 cmd 창을 열고 아래 명령을 차례대로 입력한다.

cscript %windir%\system32\slmgr.vbs /upk
cscript %windir%\system32\slmgr.vbs /ipk 제품번호
cscript %windir%\system32\slmgr.vbs /ato
제품 번호는 XXXXX-XXXXX-XXXXX-XXXXX-XXXXX 형식을 사용하면 된다.

2012년 8월 13일

Python/ctypes in Win32

ctypes를 이용해 Win32 환경에서 작업하는 예제 기록.

자료구조

ctypes vs Win32

ctypes.wintypes를 참고한다.

배열

WCHAR [1000]의 배열을 선언한다고하면

FileNameType = c_wchar * 1000
a = FileNameType()

익명 구조체/공용체 선언

SYSTEM_INFO 구조체는 아래와 같이 역명 구조체와 공용체를 가지고 있다.

typedef struct _SYSTEM_INFO {
	union {
		DWORD  dwOemId;
		struct {
			WORD wProcessorArchitecture;
			WORD wReserved;
		};
	};
	DWORD     dwPageSize;
	LPVOID    lpMinimumApplicationAddress;
	LPVOID    lpMaximumApplicationAddress;
	DWORD_PTR dwActiveProcessorMask;
	DWORD     dwNumberOfProcessors;
	DWORD     dwProcessorType;
	DWORD     dwAllocationGranularity;
	WORD      wProcessorLevel;
	WORD      wProcessorRevision;
} SYSTEM_INFO;

이 구조체를 ctypes로 표시하면 아래와 같다.

class _Noname1(ctypes.Structure):
    _fields_ = [("wProcessorArchitecture", ctypes.c_ushort),
                ("wReserved", ctypes.c_short)]


class _Noname2(ctypes.Union):
    _anonymous_ = ("s",)
    _fields_ = [('dwOemId', ctypes.c_ulong),
                ('s', _Noname1)]


class SYSTEM_INFO(ctypes.Structure):
    _anonymous_ = ("u",)
    _fields_ = [("u", _Noname2),
                ("dwPageSize", ctypes.c_ulong),
                ("lpMinimumApplicationAddress", ctypes.c_void_p),
                ("lpMaximumApplicationAddress", ctypes.c_void_p),
                ("dwActiveProcessorMask", ctypes.c_ulong),  # 64 bit에서는 c_longlong이 되어야 한다.
                ("dwNumberOfProcessors", ctypes.c_ulong),
                ("dwProcessorType", ctypes.c_ulong),
                ("dwAllocationGranularity", ctypes.c_ulong),
                ("wProcessorLevel", ctypes.c_ushort),
                ("wProcessorRevision", ctypes.c_ushort)]

pointer type 선언

위에서 선언한 SYSTEM_INFO에 대한 pointer type으로 LPSYSTEM_INFO을 선언한다고 하면

LPSYSTEM_INFO = ctypes.POINTER(SYSTEM_INFO)

ctypes.LP_c_char를 문자열로 변환

ctypes.LP_c_charctypes.c_char_p로 형변환하면 된다.

ctypes.cast(ctypes.LP_c_char 객체, ctypes.c_char_p).value

함수 호출

Win32 API 호출

ctypes.windll뒤에 원하는 dll 모듈과 함수를 사용하면 된다. 예를 들어 kernel32GetsystemInfo함수를 호출한다면 아래와 같이 호출할 수 있다.

ctypes.windll.kernel32.GetsystemInfo( ... )

DLL 함수 호출

test1.dllvoid __cdecl testfunction1() 함수를 호출한다고 하면

test1 = ctypes.CDLL('test1.dll')
if test1:
	test1.testfunction1()

함수 인자로 pointer 전달

si = SYSTEM_INFO()
ctypes.windll.kernel32.GetSystemInfo(ctypes.byref(si))

함수 인자로 string buffer 전달

buf = ctypes.create_unicode_buffer(4096)
r = ctypes.windll.kernel32.GetWindowsDirectoryW(buf, 4096)
if r > 0:
	print buf.value

함수 반환값 검사

함수 객체의 errcheck를 지정하면 함수의 반환값 검사를 모아서 할 수 있다. 예를 들어 test2.dllBOOL __cdecl testfunction2() 함수에 대해서 코드를 작성해보면 아래와 같다.

>def checkBOOL(result, function, args):
    if result == 0:
		raise ctypes.WinError()
	return args

test2 = ctypes.CDLL('test2.dll')
test2.testfunction2.errcheck = checkBOOL

test2.testfunction2()  # 함수 호출이 끝나면 바로 checkBOOL 함수가 호출되서 반환값 검사를 할 수 있다.

명시적인 함수 인자 지정

함수 객체의 argtypes를 이용해서 함수의 인자를 명시적으로 지정할 수 있다. 예를 들어 test3.dllBOOL __cdecl testfunction3(LPCWSTR, LPBOOL)에 대해서 코드를 작성해보면 아래와 같다.

test3 = ctypes.CDLL('test3.dll')
test3.testfunction3.argtypes = [ctypes.c_wchar_p, ctypes.POINTER(ctypes.c_long)]

b = ctypes.c_long()
r = test3.testfunction3(u"hello, world!", ctype.byref(b))

명시적인 함수 반환형 지정

함수 객체의 restype을 시용해서 함수의 반환형을 명시적으로 지정할 수 있다(함수 반환형이 void라면 None을 사용한다). 예를 들어 test4.dllHANDLE __cdecl testfunction4()에 대해서 코드를 작성해보면 아래와 같다.

test4 = ctypes.CDLL('test4.dll')
test4.testfunction4.restype = ctypes.c_void_p

h = test4.testfunction4()

callback 함수

callback 함수 형식에 따라 ctypes.CFUNCTYPE 또는 ctypes.WINFUNCTYPE을 사용해서 callback 함수 형을 만들면 된다.

CFUNCTYPE

python 문서에 나온 예제를 Win32에 맞게 변형했다.

CMPFUNC = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))


def py_cmp_func(a, b):
    print 'py_cmp_func', a[0], b[0]
    return 0

cmp_func = CMPFUNC(py_cmp_func)

IntArray5 = ctypes.c_int * 5
ia = IntArray5(5, 1, 7, 33, 99)
qsort = ctypes.windll.msvcrt.qsort
qsort.restype = None
qsort(ia, len(ia), ctypes.sizeof(ctypes.c_int), cmp_func)

WINFUNCTYPE

LF_FACESIZE = 32
LF_FULLFACESIZE = 64


class LOGFONT(ctypes.Structure):
    _fields_ = [
        ('lfHeight', ctypes.c_long),
        ('lfWidth', ctypes.c_long),
        ('lfEscapement', ctypes.c_long),
        ('lfOrientation', ctypes.c_long),
        ('lfWeight', ctypes.c_long),
        ('lfItalic', ctypes.c_byte),
        ('lfUnderline', ctypes.c_byte),
        ('lfStrikeOut', ctypes.c_byte),
        ('lfCharSet', ctypes.c_byte),
        ('lfOutPrecision', ctypes.c_byte),
        ('lfClipPrecision', ctypes.c_byte),
        ('lfQuality', ctypes.c_byte),
        ('lfPitchAndFamily', ctypes.c_byte),
        ('lfFaceName', ctypes.c_wchar * LF_FACESIZE)]
PLOGFONT = ctypes.POINTER(LOGFONT)


class ENUMLOGFONT(ctypes.Structure):
    _fields_ = [
        ('elfLogFont', LOGFONT),
        ('elfFullName', ctypes.c_wchar * LF_FULLFACESIZE),
        ('elfStyle', ctypes.c_wchar * LF_FACESIZE)]
PENUMLOGFONT = ctypes.POINTER(ENUMLOGFONT)


if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
    LPARAM = ctypes.c_long
elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
    LPARAM = ctypes.c_longlong

#int CALLBACK EnumFontFamProc(ENUMLOGFONT *lpelf,__in  NEWTEXTMETRIC *lpntm, DWORD FontType, LPARAM lParam;
EnumFontFamProc = ctypes.WINFUNCTYPE(ctypes.c_int, PENUMLOGFONT, ctypes.c_void_p, ctypes.c_long, LPARAM)


def py_enum_font_fam_proc(lpelf, lpntm, FontType, lparam):
    print 'py_enum_font_fam_proc', lpelf.contents.elfFullName
    return 1

enum_font_proc = EnumFontFamProc(py_enum_font_fam_proc)

EnumFontFamilies = ctypes.windll.gdi32.EnumFontFamiliesW
hdc = ctypes.windll.user32.GetDC(0)
EnumFontFamilies(hdc, 0, enum_font_proc, 0)
ctypes.windll.user32.ReleaseDC(hdc)

2012년 8월 11일

cygwin/Windows 개발을 위한 Makefile template

cygwin에서 Windows 프로그램 개발을 위한 Makefile template.

BASECFLAGS = -DUNICODE -D_UNICODE -DWIN32 -D_WIN32 -Wall -Wextra -ffunction-sections -fdata-sections
CXXFLAGS = -fno-rtti -fno-exceptions

ifdef debug
	OPTFLAGS = -g -DDEBUG -Wall -Wextra -Wfloat-equal -Wunreachable-code
else
	OPTFLAGS = -Os -s -DNDEBUG
endif

ifdef x64
	MINGWPREFIX = x86_64-w64-mingw32
	CFLAGS = $(BASECFLAGS) $(OPTFLAGS) -DWIN64 -D_WIN64
else
	MINGWPREFIX = i686-pc-mingw32
	CFLAGS = $(BASECFLAGS) $(OPTFLAGS)
endif
LDFLAGS = -Wl,--gc-sections -mwindows -mno-cygwin

CC = $(MINGWPREFIX)-gcc
CXX = $(MINGWPREFIX)-g++
RES = $(MINGWPREFIX)-windres

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

%.o: %.cpp
	$(CXX) $(CFLAGS) $(CXXFLAGS) -c $< -o $@

%.res.o: %.rc
	$(RES) -i $< -o $@

Makefile은 아래와 같이 사용할 수 있다.

디버그 빌드시

$ make debug=1

x64 빌드시

$ make x64=1

2012년 7월 12일

VIM/'unable to open swap file for "[No Name", recovery impossible' 오류 수정

Windows에서 VIM을 쓰다보면 unable to open swap file for "[No Name", recovery impossible 오류가 나는 경우가 있다. 임시 파일 생성 경로에 권한이 없는 경우 발생하는데, %USERPROFILE%/_vimrc 파일에 아래와 같이 임시파일 생성 경로를 지정해주면 된다.

if has ('win32')
	set directory=.,$TEMP
endif

2012년 7월 9일

Debian/SSD 최적화

SSD 최적화 방법을 기술한다. 최적화의 대부분은 i/o를 줄이는데 있다. 편의상 ssd 장치는 /dev/sd?으로 표시한다. 그리고 파일 시스템은 ext4를 사용하는 것을 가정한다.

파일 시스템 설정

Journal 끄기

아래와 같은 명령으로 journal 기능을 끈다. 주의할 점은 mount 된 장치에는 쓸 수 없기 때문에 usb등으로 부팅한 후 수정해야 한다.

$ tune2fs -O ^has_journal /dev/sd?1

no access time

access time을 기록하지 않도록 /etc/fstab 수정해서 noattime옵션을 추가한다.

/dev/sd?1	/	ext4	noatime,discard,defaults

Trim 지원

fstab을 수정해서 trim지원을 적용하는 방법과 하루 한번 정리하는 방법이 있다. 구글 검색을 해보면 하루 한번 정리하는 것을 권장한다.

fstab를 수정하는 방법

아래 명령으로 지원 상황 확인한다.

$ hdparam -I /dev/sd? | grep TRIM
	   *	Data Set Management TRIM supported (limit 8 blocks)

지원되는 것이 확인되면 /etc/fstab 수정해서 discard 옵션을 추가한다.

/dev/sd?1	/	ext4	discard,defaults

crontab을 이용해 하루 한번 정리하는 방법

아래와 같은 내용의 /etc/cron.daily/trim파일을 만든다.

#!/bin/sh
LOG=/var/log/trim.log
echo "*** $(date -R) ***" >> $LOG
fstrim -v / >> $LOG
fstrim -v /home >> $LOG

파일 생성 후 실행 권한을 준다.

$ sudo chmod +x /etc/cron.daily/trim

/tmp를 tmpfs로 변경

/etc/default/tmpfs 수정한다.

다른 리눅스 시스템에서는 직접 /etc/fstab 수정한다.
tmpfs	/tmp	tmpfs	defaults,noatime,mode=1777	0	0
RAMTMP=yes

I/O Scheduler 변경

I/O Scheduler를 noopdeadline으로 변경한다.

noop 스케줄러를 사용

/etc/rc.local에 아래 명령을 추가한다.

echo noop > /sys/block/sd?/queue/scheduler

/etc/default/grub에 아래처럼 기본 옵션을 설정한다.

GRUB_CMDLINE_LINUX_DEFAULT="elevator=noop"

설정 후 update-grub 명령으로 grub 설정을 변경한다.

deadline 스케줄러를 사용

/etc/rc.local에 아래 명령을 추가한다.

echo deadline > /sys/block/sd?/queue/scheduler
echo 1 > /sys/block/sd?/queue/iosched/fifo_batch

/etc/default/grub에 아래처럼 기본 옵션을 설정한다.

GRUB_CMDLINE_LINUX_DEFAULT="elevator=deadline"

설정 후 update-grub 명령으로 grub 설정을 변경한다.

swap 최적화

swap partition이 SSD에 있다면 /etc/sysctl.d/swap.conf파일을 만들고 아래와 같은 내용을 적는다.

# swap을 최소로 사용.
vm.swappiness=0

기타

home디렉토리가 SSD에 있다면 firefox등의 프로그램에서 사용하는 cache 디렉토리를 /tmp로 지정하거나 /etc/fstab에 아래와 같이 ramdisk를 만들어서 ramdisk로 지정한다.

tmpfs	/media/ramdisk	tmpfs	size=64M,nr_inodes=10k,mode=777	0	0

2012년 4월 22일

AppleTV/XBMC를 바로 시작하기

원문

AppleTV에서 XBMC를 바로 시작하기 위해서는 ssh으로 접속한 후 root권한으로 아래 명령을 실행해서 org.tomcool.xbmc-booter패키지를 설치한다..

apt-get install org.tomcool.xbmc-booter

기능을 끄기 위해서는 org.tomcool.xbmc-booter을 삭제하면 된다.

apt-get remove org.tomcool.xbmc-booter

2012년 4월 21일

AppleTV/sudo 설치

AppleTV에서 sudo를 사용하기 위한 방법을 기술한다.

우선 root계정으로 AppleTV에 접속한다.

$ ssh root@<apple tv ip>

접속 후 필요한 패키지를 설치한다.

$ apt-get install sudo nano

nano를 이용해서 /etc/sudoers파일을 열고 아래 설정을 추가한다.

mobile	ALL=(ALL)	ALL

이후 부터는 mobile계정으로 접속한 후 sudo를 이용해서 root권한의 작업을 할 수 있게 된다.

2012년 4월 5일

OSX - AppleScript를 이용해서 Finder 열기

아래와 같은 스크립트를 이용해서 새 Finder 창을 열 수 있다.

activate application "Finder" --gives Finder focus
tell application "Finder"
	set new_finder to make new Finder window to alias ":"
	set the current view of new_finder to column view
	set the target of new_finder to the home
end tell

2012년 3월 21일

NFC와 NFD 서로 변환하기

OS/X는 NFD복잡한 설명을 생략하고 "한글.txt"가 실제로는 "ㅎㅏㄴㄱㅡㄹ.txt"로 풀어써진다고 보면 된다. 자세한 내용은 유니코드 정규화를 참고한다. 형식으로 파일 이름을 저장한다. 이 파일을 다른 OS로 복사했을 때 해당 OS에서 NF이를 NFC로 바꾸기 위해서는 convmv을 사용하면 된다.

설치

OS/X 에서는 brew을 이용해서 설치하는 것이 편하다.

$ brew install convmv

Debian/Linux 에서는 아래 명령으로 간단하게 설치할 수 있다.

$ sudo apt-get install convmv

사용법

NFD를 NFC로

대상 파일 시스템이 utf-8를 쓴다고 가정하면

$ convmv -f utf-8 -t utf-8 --nfc -notest 파일명

NFC를 NFD로

원본 파일 시스템이 utf-8을 쓴다고 가정하면

$ convmv -f utf-8 -t utf-8 --nfd -notest 파일명

2012년 3월 18일

OS/X - tab 키로 모든 컨트롤 이동하기

OS/X 는 Windows 와 달리 tab 키로 모든 컨트롤을 이동할 수 없다. 그렇지만 설정 - 키보드 - 키보드 단축키 설정을 아래와 같이 변경하면 Windows 처럼 tab 키로 모든 컨트롤을 이동할 수 있다.


2012년 2월 26일

Debian/Gnome Shell이 검색할 때마다 죽을 때

최근 사용한 파일 목록이 엉키면 Gnome Shell이 검색할 때 마다 죽게 된다. 최근 사용한 파일 목록을 초기화 시키면 된다.

  1. 아래 명령을 이용해서 최근 사용한 파일 목록을 삭제한다.
  2. $ rm ~/.local/share/recently-used.xbel
  3. Gnome-Shell을 재시작한다.

2012년 2월 17일

OS/X - Xcode 삭제하기

Xcode 4.3 for Lion과 함께 Command Line Tools for Xcode, Graphics Tools for Xcode, Hardware IO Tools for Xcode, Dashcode for Xcode, Auxiliary Tools for Xcode, Audio Tools for Xcode, Accessibility Tools for Xcode 가 발표되었다.

gcc와 Dashcode 만 사용하면 Xcoee 4.3 for Lion 대신 Command Line Tools for Xcode와 Dashcode for Xcode 만 설치하면 된다.

Command Line Tools 와 Dashcode를 설치하기 전에 더 이상 사용하지 않을 Xcode를 삭제해야 하는데, 삭제하는 방법은 아래와 같다. 원문

$ sudo <Xcode>/Library/uninstall-devtools

<Xcode>는 Xcode 설치 경로이며 기본값으로 설치시 /Developer이다. 그리고 원문에는 --mode=all 옵션을 사용하도록 설명하는데, Xcode 4.2 기준으로 uninstall-devtools의 기본값이 --mode=all이다.

2012년 2월 13일

OS/X - 기본 입력기 전환 키를 Shift-Space로 변경하기.

원문

~/Library/Preferecnes/com.apple.symbolichotkeys.plist파일을 xcode로 열어서 편집한다.

파일을 열고 AppleSymbolicHotkeys>61>value>parapeters>item2를 131072로 변경하고 저장한다.

저장 후 재부팅 (또는 로그 아웃 후 로그인) 하면 변경된 키 설정을 확인할 수 있다.

2012년 1월 3일

OS/X - 부팅이 느려졌을 때

마이그레이션을 한 뒤나 부팅이 느려졌다면 아래와 같이 조치를 해보는 것이 좋다.

Repair permissions

아래와 같은 순서로 권한 복구를 한다.

  1. 디스크 유틸리티를 실행
  2. 부팅 파티션 선택
  3. 디스크 권한 복구버튼 클릭

또는 터미널에서 아래 명령을 통해서 권한 복구를 할 수도 있다

$ diskutil repairPermissions /

Rebuild kernel extension cache

터미널에서 아래 명령을 순서대로 입력한다.원문

$ sudo chown root:admin /
$ sudo kextcache -system-prelinked-kernel
$ sudo kextcache -system-caches

재부팅

위의 모든 작업이 끝나면 재부팅 한다.