<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>juni-test.log</title>
        <link>https://velog.io/</link>
        <description>인기는 없지만 그래도 임베디드를 사랑하는 한 개발자</description>
        <lastBuildDate>Wed, 20 Jan 2021 13:52:21 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>juni-test.log</title>
            <url>https://images.velog.io/images/juni-test/profile/bae753f4-7ffd-4ede-8369-1638c009932b/KakaoTalk_20200720_230102020_01.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. juni-test.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/juni-test" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Git Merge]]></title>
            <link>https://velog.io/@juni-test/Git-Merge</link>
            <guid>https://velog.io/@juni-test/Git-Merge</guid>
            <pubDate>Wed, 20 Jan 2021 13:52:21 GMT</pubDate>
            <description><![CDATA[<p>두 Branch 간 History 및 형상을 통합하는 기능이다.</p>
<h1 id="fast-forward-vs-no-ff">Fast Forward vs No-ff</h1>
<p><img src="https://images.velog.io/images/juni-test/post/4fcca282-69b9-4fc6-a60e-f8d001c3fd5b/image.png" alt="Fast"><em>Fast forward merge</em></p>
<p><img src="https://images.velog.io/images/juni-test/post/94282d9f-5838-4fa9-959d-fd9be81242cb/image.png" alt=""><em>No fast forward merge</em></p>
<p>Merge가 완료되면 두 브랜치의 형상 History가 통합되어 기록되는데, 이 때 기록 방법이 두 가지로 나뉜다.</p>
<p>하나는 Fast Forward(이하 ff) 이며 통합된 History를 한 가닥으로 기록한다. 반면 다른 하나인 No Fast Forward(이하 no-ff) 는 두 가닥으로 표현하여 기록한다.</p>
<p>FF는 Commit history를 단순화할 수 있다는 장점이 있지만, 개발 History를 파악하기 어렵다는 단점이 있다.</p>
<p>반면 No-FF는 개발 History를 파악하기 용이하다는 장점이 있지만, Commit history가 복잡해질 수도 있다는 단점이 있다.</p>
<p>하지만 형상 관리라는 것이 개발 과정을 기록하고 후에 파악하기 용이하기 위한 것이 그 목적이므로, 보통은 No-FF Merge를 사용하는 편이다.</p>
<h1 id="명령어">명령어</h1>
<pre><code class="language-bash"># Default : FF와 No-FF 중 git config에 설정된 방법으로 Merge
$ git merge &lt;target-branch-name&gt;

# Example
$ git merge Branch_B

# FF Merge
$ git merge --ff &lt;target-branch-name&gt;

# No-FF Merge
$ git merge --no-ff &lt;target-branch-name&gt;</code></pre>
<blockquote>
<p><strong>주의사항</strong>
두 Branch의 History를 통합하여 기록할 곳을 둘 중에서 선정해야 한다.
그리고 그 Branch로 Checkout한 후에 Merge를 실행해야 한다.</p>
</blockquote>
<p>Merge 이후 Target branch가 제거되는 것은 아니다.</p>
<p>Merge는 두 Branch를 합친다기보다는, 현재 HEAD가 위치한 Branch의 History 및 형상에다가 Target branch의 History 및 형상을 더한다는 의미가 더 가깝다.</p>
<p>추가로 특정 Commit 포인트와의 Merge도 가능하다.
그 때는 <target-branch-name> 대신 <target-commit-number>를 지정하면 된다.</p>
<h1 id="관련-설정">관련 설정</h1>
<pre><code class="language-bash"># Set ff as merge default
$ git config merge.ff true

# Set no-ff as merge default
$ git config merge.ff false</code></pre>
<h1 id="conflict">Conflict</h1>
<p>Merge를 하다보면 종종 Conflict가 발생하는 경우가 있다.</p>
<p>이는 두 Branch가 동일한 부모 branch로부터 파생되어 분리된 이후에, 동일한 위치의 코드가 각 Branch에서 수정이 발생했을 경우다.</p>
<p><img src="https://images.velog.io/images/juni-test/post/10fba285-ce37-4c8c-86d5-242f4cff6424/image.png" alt=""></p>
<p>Git은 동일한 위치의 두 가지 수정사항 중 어느 것이 올바른 것인지 스스로 판단하지 않고, 사용자에게 그 몫을 넘겨준다. 이것이 바로 Conflict다.</p>
<p>그리고 Conflict 발생 시, Git은 Confilict가 발생한 파일 목록을 출력하고, 파일의 해당 위치마다 다음과 같은 표식을 기록해둔다.</p>
<pre><code class="language-c">/* 
##### Format #####
&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
// Codes
======================
// Codes
&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; &lt;target-branch-name&gt; or &lt;target-branch-commit-number&gt;
*/

/* Example */
// ret = add(a, b);
&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
ret = sub(a, b);
// Modified by jgchoi 201220
======================
ret = mul(a, b);
// Modified by jhkim 201214
&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; Branch_B</code></pre>
<p>Conflict를 해결하는 방법은 Git이 기록해둔 두 개의 선택지(HEAD, Target-branch)에서 올바른 코드를 선택 또는 통합한 뒤 나머지는 지워주면 된다.</p>
<p>Conflict 수정이 모두 완료되면 다시 한 번 Commit을 실행한다. 그러면 Merge commit 포인트가 생성된다.</p>
<h1 id="왜-git-merge기능을-사용하여-코드를-통합해야-하는가">왜 Git merge기능을 사용하여 코드를 통합해야 하는가?</h1>
<p>Git merge 기능을 통해서 코드를 통합하지 않고, Beyond compare 등의 툴을 사용하여 직접 통합할 수도 있다. 하지만 후자의 방법은 치명적인 단점이 존재하는데 이는 Target branch의 History가 모두 휘발된다는 것이다.</p>
<p>형상을 관리하고 추적하기 위해서는 Target branch의 History 또한 통합해야 하는데, 직접 통합은 오직 코드만 통합이 가능하기 때문이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git Checkout]]></title>
            <link>https://velog.io/@juni-test/Git-Checkout</link>
            <guid>https://velog.io/@juni-test/Git-Checkout</guid>
            <pubDate>Wed, 20 Jan 2021 13:49:06 GMT</pubDate>
            <description><![CDATA[<p>특정 Commit 포인트 및 브랜치 간 이동을 할 수 있는 기능이다.</p>
<h1 id="head">HEAD</h1>
<p><code>Checkout</code> 기능으로 이곳저곳을 이동할 수 있는데, 현재 내가 위치한 형상을 <code>HEAD</code>라고 한다. </p>
<p>또한 현재 HEAD가 위치한 브랜치를 <code>HEAD Branch</code> 라고 한다.</p>
<p><img src="https://images.velog.io/images/juni-test/post/8d38a894-ecaa-4983-8718-235f1e909698/image.png" alt=""></p>
<p>또한 <code>$ git reflog</code> 명령어를 실행하면 HEAD의 발자취를 확인할 수 있다.</p>
<h1 id="명령어">명령어</h1>
<p><img src="https://images.velog.io/images/juni-test/post/c412f971-0e6a-4ff3-9b38-319dcd3c657a/image.png" alt=""></p>
<pre><code class="language-bash"># HEAD 이동
$ git checkout &lt;branch-name&gt;
$ git checkout &lt;commit-number&gt;
$ git checkout HEAD@{number}
$ git checkout &lt;tag-name&gt;

# Example
$ git branch
     master
   * Branch_A
     Branch_B
$ git checkout Branch_B
$ git branch
     master
     Branch_A
   * Branch_B

# 브랜치 생성 및 HEAD 이동
$ git checkout -b &lt;branch-name&gt;

# Example
$ git branch
     master
     Branch_A
   * Branch_B
$ git checkout -b Branch_C
$ git branch
     master
     Branch_A
     Branch_B
   * Branch_C</code></pre>
<p><branch-name> 으로 <code>Checkout</code> 하면 Branch 간 전환이 수행된다.</p>
<p>그외 인자로 <code>Checkout</code> 하면 별도의 임시 브랜치가 생성되어 전환된다.</p>
<blockquote>
<p><em>Branch로 <code>Checkout</code> 하는 것도 사실 해당 Branch의 최신 Commit 포인트로 이동하는 것이다.</em></p>
</blockquote>
<blockquote>
<p><strong>주의사항</strong>
현재 작업을 진행 중이라 Changes가 발생한 상황이라면, 
반드시 현재 Changes를 Commit 포인트로 기록한 후 Checkout을 해야 한다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git Branch]]></title>
            <link>https://velog.io/@juni-test/Git-Branch</link>
            <guid>https://velog.io/@juni-test/Git-Branch</guid>
            <pubDate>Wed, 20 Jan 2021 13:47:22 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/juni-test/post/7ac75b42-797d-448a-b945-bf6c3cd9f629/image.png" alt=""></p>
<p>Branch는 형상의 가닥을 잡아주는 가지와 같다.</p>
<p>나뭇가지들은 하나의 가지에서 파생되었지만 서로 다른 방향을 향한다.</p>
<p>이처럼, Git branch 기능을 사용하면 동일한 History에서 파생되었지만 이후 각기 다른 개발을 진행을 할 수 있을 뿐만 아니라 서로 영향을 주지 않고 각각 형상 관리를 할 수 있다.</p>
<h1 id="명령어">명령어</h1>
<h2 id="복제fork">복제(Fork)</h2>
<p><img src="https://images.velog.io/images/juni-test/post/cc18da67-e1a1-4c77-be43-2e3b23669b88/image.png" alt=""></p>
<pre><code class="language-bash"># Branch 확인
$ git branch
      master
    * Branch_A  # 현재 위치한 Branch

# Branch 복제(Fork)
$ git branch &lt;new-branch-name&gt;

# Example
$ git branch
      master
    * Branch_A 
$ git branch Branch_B
$ git branch
      master
    * Branch_A
      Branch_B</code></pre>
<blockquote>
<p>이 명령어는 현재 위치한 브랜치를 복제하여 새로 생성하므로, 실행 전 항상 현재 위치한 브랜치가 어디인지 확인해야 한다.</p>
</blockquote>
<h2 id="삭제">삭제</h2>
<p><img src="https://images.velog.io/images/juni-test/post/e3d72ee8-299d-4c08-a7de-d4749dc602b8/image.png" alt=""></p>
<pre><code class="language-bash"># Branch 삭제
$ git branch -D &lt;branch-name&gt;

# Example
$ git branch
      master
    * Branch_A
      Branch_B
$ git branch -D Branch_B
$ git branch
      master
    * Branch_A</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git Reset]]></title>
            <link>https://velog.io/@juni-test/Git-Reset</link>
            <guid>https://velog.io/@juni-test/Git-Reset</guid>
            <pubDate>Wed, 20 Jan 2021 13:45:27 GMT</pubDate>
            <description><![CDATA[<p>이름 그대로 특정 Commit 포인트로 되돌릴 수 있다.</p>
<p>그 결과 형상의 복원/삭제가 가능하다.</p>
<p>그리고 옵션에 따라 두 가지 동작을 한다.</p>
<h2 id="1-현재--특정-포인트까지의-commit-취소">1. 현재 ~ 특정 포인트까지의 Commit 취소</h2>
<p><img src="https://images.velog.io/images/juni-test/post/40522cfc-6bed-4789-ad84-30c8d547107c/image.png" alt=""></p>
<pre><code class="language-bash"># Format
$ git reset &lt;commit-number&gt;

# Example
$ git reset 51d547f9816a95fbd87dec2f7a1370fbb0b1ff96</code></pre>
<p>실행하면 현재 ~ 특정 포인트까지의 Commit들을 취소한다. </p>
<p>그 결과 취소된 Commit들의 형상들이 Unstaged된다.</p>
<h2 id="2-특정-포인트로-roll-back">2. 특정 포인트로 Roll back</h2>
<p><img src="https://images.velog.io/images/juni-test/post/a1d1cb71-83dc-445a-aea0-bef3a2072e1c/image.png" alt=""></p>
<pre><code class="language-bash">$ git reset --hard &lt;commit-number&gt;</code></pre>
<p>실행하면 특정 포인트로 Roll back하면서 현재 ~ 특정포인트까지의 Commit들을 삭제한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git Commit]]></title>
            <link>https://velog.io/@juni-test/Git-Commit</link>
            <guid>https://velog.io/@juni-test/Git-Commit</guid>
            <pubDate>Wed, 20 Jan 2021 13:42:13 GMT</pubDate>
            <description><![CDATA[<p>Commit이란 어떠한 포인트에서 형상을 기록하는 것</p>
<p>그래서 Commit을 실행하기 전에, 어떠한 코드, 어떠한 파일들을 형상으로 기록할 지 선별하는 작업을 수행해야 한다.</p>
<blockquote>
<p>SVN의 <code>Commit</code> 과는 전혀 다른 기능이다.
SVN의 <code>Revision</code> 이라고 생각하면 된다.</p>
</blockquote>
<h2 id="선별-작업">선별 작업</h2>
<h3 id="tracked-changes">Tracked Changes</h3>
<ul>
<li>어떠한 파일(디렉터리)가 형상으로 등록되면, 그 이후부터 Git에서는 해당 파일(디렉터리)을 Tracking하기 시작한다.</li>
<li>이렇게 Tracking 하고 있는 파일(디렉터리) 중에서 수정사항이 발생한 목록을 의미한다.</li>
<li>보통은 파일(디렉터리) 수정/이동/삭제된 경우에 해당</li>
</ul>
<h3 id="untracked-list">Untracked List</h3>
<ul>
<li>형상 등록이 되지 않은 파일(디렉터리) 목록</li>
<li>보통은 파일(디렉터리) 추가된 경우에 해당</li>
</ul>
<h3 id="stage">Stage</h3>
<ul>
<li><code>Commit</code> 수행 시 형상으로 기록할 파일이나 코드 등의 리스트</li>
<li>Tracked changes, untracked list에서 형상으로 기록할 것들을 선별하여 Stage로 이동시킴</li>
</ul>
<h2 id="관련-명령어">관련 명령어</h2>
<ul>
<li>add</li>
<li>del</li>
<li>commit</li>
<li>rm</li>
<li>status</li>
<li>tag</li>
</ul>
<h3 id="add">add</h3>
<p><img src="https://images.velog.io/images/juni-test/post/d058b31d-0713-4f71-bf61-015dd3767760/image.png" alt=""></p>
<pre><code class="language-bash">### Add to stage ###
# Tracked changes와 Untracked list의 특정 파일(디렉터리)를 Stage에 추가
$ git add [files or dirs]

# Tracked changes와 Untracked list의 모든 파일(디렉터리)를 Stage에 추가
$ git add -A</code></pre>
<h3 id="del">del</h3>
<p><img src="https://images.velog.io/images/juni-test/post/fb4402ce-61f9-4516-8f75-11a1b785ecfd/image.png" alt=""></p>
<pre><code class="language-bash">### Delete from stage ###
# Stage에 있는 특정 파일(디렉터리)를 Stage에서 제외
$ git del [files or dirs]

# Stage에 있는 모든 파일(디렉터리)를 Stage에서 제외
$ git del -A</code></pre>
<h3 id="commmit">commmit</h3>
<p><img src="https://images.velog.io/images/juni-test/post/0b820ec0-74e8-4d66-9493-831855604d31/image.png" alt=""></p>
<pre><code class="language-bash">### Restore stage ###
$ git commit</code></pre>
<p>커맨드를 실행하면, 에디터가 실행되면서 Commit 메세지를 작성하는 화면으로 자동 전환됩니다.</p>
<blockquote>
<p><em>이 때 실행되는 에디터는 Repo config의 core.editor에 설정된 에디터임</em></p>
</blockquote>
<p>메시지를 모두 작성한 후, 에디터를 종료하면 Commit 완료</p>
<p>Commit 메세지를 작성하는 방법은 뒤에서 다룰 예정.</p>
<p><img src="https://images.velog.io/images/juni-test/post/3ae9234c-a3f1-4cca-958e-1f05c0804323/image.png" alt=""></p>
<p>Commit이 완료되면 History가 기록되는데, <code>$ git log</code> 커맨드로 확인할 수 있다.</p>
<p>또한 각 Commit마다 Commit number가 부여되는데 이 또한 log 커맨드로 확인할 수 있다(빨간색 화살표).</p>
<h3 id="rm">rm</h3>
<p><img src="https://images.velog.io/images/juni-test/post/a63e8e4e-c1f5-4229-8646-6c3a4950a728/image.png" alt=""></p>
<pre><code class="language-bash">### Remove from tracked list
# 특정 파일(디렉터리)를 Tracked list에서 제외시킴과 동시에 삭제
$ git rm [files or dirs]

# 특정 파일(디렉터리)를 Tracked list에서 제외만 시키고 삭제는 하지 않음
$ git rm --cached [files or dirs]</code></pre>
<h3 id="status">status</h3>
<pre><code class="language-bash">### Check unstaged list ###
$ git status
# Staged files
Changes to be committed:
            deleted:    file_a

# Tracked changes
Changes not staged for commit:
            modified:   file_b

# Untracked list
Untracked files:
            file_c
            file_d</code></pre>
<h3 id="tag">tag</h3>
<pre><code class="language-bash"># Register tag
$ git tag &lt;tag-name&gt;

# Example
$ git tag v0.0.0

# Check tags
$ git tag</code></pre>
<p>특정 Commit 포인트에서 Tag를 남길 수 있다.</p>
<p>보통은 버전명을 기록할 때 사용된다.</p>
<h1 id="commit-rule">Commit Rule</h1>
<p><code>$ git commit</code> 을 실행하면, Commit 메세지를 작성해야 한다.</p>
<p>각자 환경에 맞게 작성하면 되지만, 일단 먼저 Global conventional commit rule을 소개하고자 한다.</p>
<h2 id="global-conventional-commit-rule">Global conventional commit rule</h2>
<p>기본 틀은 다음과 같다.</p>
<pre><code>type : title

body(생략 가능)

footer(생략 가능)</code></pre><ul>
<li><p>type</p>
<p>  Commit의 타입을 정의한다. 이 커밋룰에서 정의한 목록은 다음과 같다.</p>
<ul>
<li>feat : 새로운 기능에 대한 커밋</li>
<li>fix : 버그 수정에 대한 커밋</li>
<li>build : 빌드 관련 파일 수정에 대한 커밋</li>
<li>chore : 그 외 자잘한 수정에 대한 커밋</li>
<li>ci : CI 관련 설정 수정에 대한 커밋</li>
<li>docs : 문서 수정에 대한 커밋</li>
<li>style : 코드 스타일 또는 포맷 등에 대한 커밋</li>
<li>refactor : 코드 리팩토링에 대한 커밋</li>
<li>test : 테스트 코드 수정에 대한 커밋</li>
</ul>
</li>
<li><p>title</p>
<p>  Commit의 제목을 정의한다.</p>
</li>
<li><p>body</p>
<p>  필요 시 본문 및 세부 내용을 명시한다.</p>
<p>  또한 생략 가능하다.</p>
</li>
<li><p>footer</p>
<p>  사족을 남긴다.</p>
<p>  생략도 가능하다.</p>
<p>  하지만 보통 해당 Commit과 연관된 Issue tracker ID를 명시한다.</p>
<ul>
<li><p>close #<issue-tracker-id></p>
<p>  일감이 완료되었음을 나타냄</p>
</li>
<li><p>resolved #<issue-tracker-id></p>
<p>  이슈가 해결되었음을 나타냄</p>
</li>
<li><p>refs #<issue-tracker-id></p>
<p>  현재 진행 중인 일감(or 이슈)를 나타냄</p>
</li>
<li><p>related to #<issue-tracker-id> #<issue-tracker-id> #<issue-tracker-id>...</p>
<p>  관련 일감들을 나타냄(복수 지정 가능)</p>
</li>
</ul>
</li>
</ul>
<p>이 Rule에서 정의하는 7가지 규칙은 다음과 같다.</p>
<ul>
<li><code>title</code> 과 <code>body</code> 는 빈 행으로 구분한다.</li>
<li><code>title</code> 은 50자 이내로 제한한다.</li>
<li><code>title</code> 첫 글자는 대문자로 작성한다.</li>
<li><code>title</code> 끝에 마침표를 넣지 않는다.</li>
<li><code>title</code> 은 명령문으로 사용하며 과거형을 사용하지 않는다.</li>
<li><code>body</code> 의 각 행은 72글자 내로 제한한다.</li>
<li>어떻게 보다는 무엇과 왜를 설명한다.</li>
</ul>
<p>예시는 다음과 같다.</p>
<pre><code>fix : Segmentation fault 현상 해결

For문에서 배열의 최대 인덱스를 초과하여 접근했던 것을 수정
   - main.c 723줄 참고

resolved #4431</code></pre><h1 id="ignore-file">Ignore File</h1>
<p>이름 그대로 Git에서 아예 신경을 쓰지 않아도 될 파일 목록을 명시할 수 있다. 이 파일에 명시된 파일들은 <code>$ git status</code> 명령어를 실행되면 출력되는 Untracked files 에도 제외된다.</p>
<p>Ignore file은 Git repo에서 <code>.gitignore</code> 파일을 생성하고, 무시할 파일(디렉터리) 리스트를 파일에 작성하면 된다. 각각 개행으로 구분해준다.</p>
<p>표준양식으로 Glob 패턴을 사용한다.</p>
<p>리스트 중에 무시를 취소하고 싶은 게 있다면, 삭제하거나 맨 앞에 #을 추가해준다.</p>
<h2 id="github-standard">Github standard</h2>
<p>C, Jave 등 각 코드 포맷마다 컴파일 등 작업 시 생성되는 부산물들(바이너리 등)이 존재한다. 하지만, 형상관리는 코드 관리를 주로 하기 때문에 이러한 부산물들은 필요없는 존재이다.</p>
<p>그래서 Github에서는 각 코드 포맷 별 Ignore file을 정의하여 제공한다. 그래서 보통 여기서 제공하는 Ignore file을 바탕으로 각자의 환경에 맞게 커스텀하여 사용한다.</p>
<p>Github 양식을 사용하려면 다운로드 받아서 이름을 <code>.gitignore</code> 로 변경하면 된다.</p>
<p><a href="https://github.com/github/gitignore">github/gitignore</a></p>
<h3 id="cgitignore">C.gitignore</h3>
<pre><code class="language-bash"># Prerequisites
*.d

# Object files
*.o
*.ko
*.obj
*.elf

# Linker output
*.ilk
*.map
*.exp

# Precompiled Headers
*.gch
*.pch

# Libraries
*.lib
*.a
*.la
*.lo

# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib

# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex

# Debug files
*.dSYM/
*.su
*.idb
*.pdb

# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git Local Repo Settings]]></title>
            <link>https://velog.io/@juni-test/Git-Local-Repo-Settings</link>
            <guid>https://velog.io/@juni-test/Git-Local-Repo-Settings</guid>
            <pubDate>Wed, 20 Jan 2021 13:36:29 GMT</pubDate>
            <description><![CDATA[<h1 id="시작">시작</h1>
<h2 id="설치">설치</h2>
<pre><code class="language-bash">$ cd &lt;dir-for-git&gt;
$ git init</code></pre>
<p>아무 디렉터리에서 Git을 사용할 수 있는 것이 아니다.</p>
<p>특정 디렉터리를 Git repo로 설정해야 한다.</p>
<p>Repo 설정은 Git repo로 사용할 디렉터리에 위치한 후  <code>$ git init</code> 커맨드를 실행하면 된다.</p>
<h2 id="기본-설정">기본 설정</h2>
<pre><code class="language-bash"># Profile
$ git config user.name &quot;juni&quot;
$ git config user.email &quot;jgchoi91@outlook.com&quot;

# Default editor
## 기본 Editor를 vim으로 설정
$ git config core.editor vim

## 기본 Editor를 VSCode로 설정
$ git config core.editor &quot;code --wait&quot;

# Repo config check
$ git config --list</code></pre>
<ul>
<li><p>Repo 설정의 기본 커맨드는 <code>$ git config</code> 이다.</p>
</li>
<li><p>Scope</p>
<ul>
<li><p>Git 툴이 설치된 PC 전체에 설정하려면 <code>--system</code> 옵션을 지정한다.
해당 설정은 <code>/etc/gitconfig</code> 에 저장된다.</p>
</li>
<li><p>PC에 접속한 계정에 한해서 설정하려면 <code>--global</code> 옵션을 지정한다.
해당 설정은 <code>~/.gitconfig</code> 또는 <code>~/.config/git/config</code> 에 저장된다.</p>
</li>
<li><p>현재 위치한 Local repo에만 국한된 설정을 하려면 아무런 옵션을 주지 않거나 <code>--local</code> 옵션을 지정하여 커맨드를 실행한다.
해당 설정은 <code>.git/config</code> 에 저장된다.</p>
<blockquote>
<p>SW팀은 개발 서버에 모두 동일한 계정으로 접속하여 사용하므로 Global 옵션은 사용을 지양한다.</p>
</blockquote>
</li>
<li><p>Local repo에 적용되는 설정 우선 순위는 Local → Global → System 순이다.</p>
</li>
</ul>
</li>
</ul>
<h1 id="개행문자-설정">개행문자 설정</h1>
<pre><code class="language-bash"># Windows 플랫폼
# 커밋 코드(LF) &lt;-&gt; 작업 코드(CRLF)
juni@Windows_or_WSL:~$ git config --system core.autocrlf true

# Linux 플랫폼
# 커밋 코드(CRLF) ---&gt; 작업 코드(LF)
juni@Linux:~$ git config --system core.autocrlf input</code></pre>
<p>Windows 플랫폼에서는 개행문자가 <code>CRLF</code> 이고 Linux 플랫폼에서는 <code>LF</code> 이다.</p>
<p>하지만 Linux 플랫폼에 적재되어 실행될 스크립트 등이 Windows에서 개행문자가 <code>CRLF</code> 인 채로 작성된다면, 나중에 Linux에서 실행할 때 문제를 야기할 수 있다.</p>
<p>이러한 상황을 방지하기 위해서, Git에서는 저장하는 코드의 개행문자 표준을 설정하는 기능을 제공하고 있다.</p>
<p>예를 들어, Windows에서 작성한 코드는 개행문자가 <code>CRLF</code> 로 입력되지만, Git commit으로 저장되는 코드는 개행문자가 <code>LF</code> 로 전환되어 저장된다.</p>
<blockquote>
<p>Autocrlf 설정은 Git 이 설치된 플랫폼(PC) 환경에 종속적이기 때문에 <code>--system</code> 옵션으로 설정하는 것이 좋다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[프롤로그]]></title>
            <link>https://velog.io/@juni-test/%ED%94%84%EB%A1%A4%EB%A1%9C%EA%B7%B8</link>
            <guid>https://velog.io/@juni-test/%ED%94%84%EB%A1%A4%EB%A1%9C%EA%B7%B8</guid>
            <pubDate>Wed, 20 Jan 2021 13:33:18 GMT</pubDate>
            <description><![CDATA[<p>얼마 전, 회사 팀장님의 지시로 개발팀을 대상으로 한 Git 세미나를 2회에 걸쳐 총 4시간 진행했었다. </p>
<p>세미나 진행을 위해 제작한 자료를 내 블로그로 공유하려고 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[파일 블로킹/논블로킹]]></title>
            <link>https://velog.io/@juni-test/%ED%8C%8C%EC%9D%BC-%EB%B8%94%EB%A1%9C%ED%82%B9%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9</link>
            <guid>https://velog.io/@juni-test/%ED%8C%8C%EC%9D%BC-%EB%B8%94%EB%A1%9C%ED%82%B9%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9</guid>
            <pubDate>Wed, 26 Aug 2020 15:07:37 GMT</pubDate>
            <description><![CDATA[<h1 id="설명">설명</h1>
<h3 id="blocking">Blocking</h3>
<p>어떠한 자원에 접근했을 때, 현재 접근은 불가하지만 반드시 획득해야 할 때 가능해질 때까지 Holding되는 것</p>
<h3 id="non-blocking">Non-blocking</h3>
<p>어떠한 자원에 접근했을 때, 현재 접근이 불가하지만 굳히 당장 획득할 필요가 없을 때 Holding을 하지 않고 다음을 진행하는 것</p>
<br>

<h1 id="설정-방법">설정 방법</h1>
<ol>
<li>open() 실행 시, O_NONBLOCK 플래그 지정/미지정</li>
<li>open() 이후, fcntl() 함수를 사용하여 O_NONBLOCK를 설정/해제</li>
</ol>
<h2 id="함수">함수</h2>
<pre><code class="language-c">#include &lt;unistd.h&gt;
#include &lt;fcntl.h&gt;

int fcntl(int fd, int cmd, ... /* arg */);</code></pre>
<h3 id="인자">인자</h3>
<h4 id="fd">fd</h4>
<p>파일 디스크립터</p>
<h4 id="cmd">cmd</h4>
<p>파일 제어 커맨드</p>
<ul>
<li>F_GETFL : File open flags를 얻어옴</li>
<li>F_SETFL : File open flags를 재설정</li>
<li>그 외 커맨드는 man 페이지 참조</li>
</ul>
<h4 id="">...</h4>
<p>제어 커맨드에 따라 필요한 가변 인자</p>
<h3 id="반환값">반환값</h3>
<h4 id="성공-시">성공 시</h4>
<p>커맨드에 따른 반환값</p>
<h4 id="실패-시">실패 시</h4>
<p>-1</p>
<br>

<h2 id="example">Example</h2>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;stdbool.h&gt;

#include &lt;errno.h&gt;

#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;unistd.h&gt;


static void dump_stdin(void)
{
    char buf[128];
    int fd = STDIN_FILENO,
        cnt, flags,
        MAX_BUF_IDX = (sizeof(buf) / sizeof(char)) - 1;

    printf(&quot;Trying to read...\n&quot;);
    cnt = read(fd, buf, MAX_BUF_IDX);
    if(cnt &gt;= 0){
        buf[cnt] = 0;
        printf(&quot;Read : %s\n&quot;, buf);
    }
    else {
        fprintf(stderr, &quot;read() FAIL : %s\n&quot;, strerror(errno));
    }


    flags = fcntl(fd, F_GETFL);
    if(flags &lt; 0){
        fprintf(stderr, &quot;fcntl(F_GETFL) FAIL : %s\n&quot;, strerror(errno));
        goto EXCEPTION;
    }

    if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) &lt; 0){
        fprintf(stderr, &quot;fcntl(F_SETFL) FAIL : %s\n&quot;, strerror(errno));
        goto EXCEPTION;
    }

    printf(&quot;Trying to read...\n&quot;);
    cnt = read(fd, buf, MAX_BUF_IDX);
    if(cnt &gt;= 0){
        buf[cnt] = 0;
        printf(&quot;Read : %s\n&quot;, buf);
    }
    else {
        fprintf(stderr, &quot;read() again FAIL : %s\n&quot;, strerror(errno));
    }

    if(fcntl(fd, F_SETFL, flags) &lt; 0){
        fprintf(stderr, &quot;&lt;&lt;WARNING&gt;&gt; fcntl(F_SETFL) again FAIL : %s\n&quot;, strerror(errno));
    }

    return;

EXCEPTION:
    return;
}

int main(int argc, char **argv)
{
    dump_stdin();

    return 0;
}

</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[파일을 이용한 동기화]]></title>
            <link>https://velog.io/@juni-test/%ED%8C%8C%EC%9D%BC%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%8F%99%EA%B8%B0%ED%99%94</link>
            <guid>https://velog.io/@juni-test/%ED%8C%8C%EC%9D%BC%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%8F%99%EA%B8%B0%ED%99%94</guid>
            <pubDate>Wed, 26 Aug 2020 06:15:57 GMT</pubDate>
            <description><![CDATA[<h1 id="동기화-용어">동기화 용어</h1>
<h3 id="race-condition경쟁-상태">Race Condition(경쟁 상태)</h3>
<p>둘 이상의 프로세스/스레드가 동시에 실행되고 있을 때, 타이밍 등에 의해서 의도치 않은 결과를 야기할 수 있는 상태를 의미</p>
<h3 id="critical-section임계-영역">Critical Section(임계 영역)</h3>
<p>둘 이상의 프로세스/스레드가 동시에 접근하면 안되는 Resource가 존재하는 코드 영역을 의미</p>
<br>

<h1 id="file-lock">File Lock</h1>
<pre><code class="language-c">#include &lt;sys/file.h&gt;

int flock(int fd, int operation);</code></pre>
<h3 id="인자">인자</h3>
<h4 id="fd">fd</h4>
<p>파일 디스크립터</p>
<h4 id="operation">operation</h4>
<p>Lock 설정</p>
<ul>
<li><p>LOCK_SH
공유 Lock 시도</p>
</li>
<li><p>LOCK_EX
상호배제 Lock 시도</p>
</li>
<li><p>LOCK_UN
점유Lock 해제</p>
</li>
<li><p>LOCK_NB
Non-block(Lock될 때까지 대기하지 않음)</p>
</li>
</ul>
<h3 id="반환값">반환값</h3>
<h4 id="성공-시">성공 시</h4>
<p>0</p>
<h4 id="실패-시">실패 시</h4>
<p>-1(LOCK_NB가 Set되어 있을 때만 실패반환이 발생할 수 있음)</p>
<br>

<h1 id="example">Example</h1>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;stdbool.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/mman.h&gt;
#include &lt;errno.h&gt;
#include &lt;sys/file.h&gt;



#define TARGET_FILE &quot;file&quot;
#define isNonBlock(x) ( strcmp(x, &quot;nb&quot;) == 0)
#define isSameStr(x, y) ( strcmp(x,y) == 0 )
#define isFdOpened(x) ( (fd &gt;= 0) &amp;&amp; (fd != fileno(stdin)) &amp;&amp; (fd != fileno(stdout)) &amp;&amp; (fd != fileno(stderr)) )

static void write_file(bool isNonBlock)
{
    int fd = -1, operation;
    char *str = &quot;Hello, World~!\n&quot;;

    fd = open(TARGET_FILE, O_WRONLY | O_CREAT | O_APPEND, 0644);
    if(fd &lt; 0){
        perror(&quot;open() FAIL\n&quot;);
        goto EXCEPTION;
    }

    (isNonBlock) ? (operation = LOCK_EX | LOCK_NB) 
                : (operation = LOCK_EX);

    if(flock(fd, operation) &lt; 0){
        fprintf(stderr, &quot;flock(%d) FAIL : %s\n&quot;, operation, strerror(errno));
        goto EXCEPTION;
    }

    printf(&quot;Press enter!\n&quot;);
    getc(stdin);    

    write(fd, str, strlen(str));

    if(flock(fd, LOCK_UN) &lt; 0){
        perror(&quot;&lt;&lt;WARNING&gt;&gt; flock(LOCK_UN) FAIL\n&quot;);
    }

    close(fd);
    return;

EXCEPTION:
    if(isFdOpened(fd)) close(fd);
    return;
}

static void dump_file(bool isNonBlock)
{
    #define MAX_STR_LEN 128
    int fd = -1, operation, maxStrIdx = MAX_STR_LEN - 1, cnt;
    char buf[MAX_STR_LEN];

    fd = open(TARGET_FILE, O_RDONLY | O_CREAT, 0644);
    if(fd &lt; 0){
        perror(&quot;open() FAIL\n&quot;); 
        goto EXCEPTION;
    }

    (isNonBlock) ? (operation = LOCK_SH | LOCK_NB)
                : (operation = LOCK_SH);

    if(flock(fd, operation) &lt; 0){
        fprintf(stderr, &quot;flock(%d) FAIL : %s\n&quot;, operation, strerror(errno));
        goto EXCEPTION;
    }

    printf(&quot;Press enter!\n&quot;);
    getc(stdin);

    cnt = read(fd, buf, maxStrIdx);
    buf[cnt] = 0;

    if(flock(fd, LOCK_UN) &lt; 0){
        perror(&quot;flock(LOCK_UN) FAIL\n&quot;);
        goto EXCEPTION;
    }

    puts(buf);

    close(fd);
    return;

EXCEPTION:
    if(isFdOpened(fd)) close(fd);
    return;
}

static void diplay_usage(const char * const binName)
{
    printf(&quot;Usage: %s w|r [nb]\n&quot;, binName);
}

int main(int argc, char **argv)
{
    if( (argc &lt; 2) || (3 &lt; argc) ){
        diplay_usage(argv[0]);
        goto EXCEPTION;
    }

    bool nb = false;

    if(argc == 3) nb = isNonBlock(argv[2]);

    if(isSameStr(argv[1], &quot;w&quot;)){
        write_file(nb);
    }
    else if(isSameStr(argv[1], &quot;r&quot;)){
        dump_file(nb);
    }
    else {
        diplay_usage(argv[0]);
        goto EXCEPTION;
    }

    return 0;

EXCEPTION:
    return -1;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[파일 메모리 매핑]]></title>
            <link>https://velog.io/@juni-test/%ED%8C%8C%EC%9D%BC-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%A7%A4%ED%95%91</link>
            <guid>https://velog.io/@juni-test/%ED%8C%8C%EC%9D%BC-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%A7%A4%ED%95%91</guid>
            <pubDate>Tue, 25 Aug 2020 01:52:39 GMT</pubDate>
            <description><![CDATA[<h1 id="매핑-요청">매핑 요청</h1>
<pre><code class="language-c">#include &lt;sys/mman.h&gt;

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);</code></pre>
<h3 id="인자">인자</h3>
<h4 id="addr">addr</h4>
<p>매핑되어 반환될 주소값을 직접 지정하여 요청
요청이 가능하면, 지정한 주소값으로 반환하고 불가능하면 커널이 임의의 주소값으로 반환함.</p>
<p>단, flags에 MAP_FIXED가 Set되어 있으면 요청 불가능할 경우에 실패값을 반환</p>
<h4 id="length">length</h4>
<p>매핑할 Byte수</p>
<h4 id="prot">prot</h4>
<p>제어 권한</p>
<ul>
<li>PROT_EXEC
실행 권한</li>
<li>PROT_READ
읽기 권한</li>
<li>PROT_WRITE
쓰기 권한</li>
<li>PROT_NONE</li>
</ul>
<h4 id="flags">flags</h4>
<p>매핑 설정</p>
<ul>
<li>프로세스 간 파일 공유 설정<ul>
<li>MAP_SHARED
공유 OK</li>
<li>MAP_PRIVATE
공유 NO</li>
</ul>
</li>
<li>MAP_FIXED
&quot;인자 addr로 지정한 주소값 아니면 매핑 안하겠다.&quot;라는 의미</li>
</ul>
<h4 id="fd">fd</h4>
<p>파일 디스크립터</p>
<h4 id="offset">offset</h4>
<p>오프셋값</p>
<h3 id="반환값">반환값</h3>
<h4 id="성공-시">성공 시</h4>
<p>매핑된 주소값</p>
<h4 id="실패-시">실패 시</h4>
<p>MAP_FAILED</p>
<br>

<h1 id="매핑-해제">매핑 해제</h1>
<pre><code class="language-c">#include &lt;sys/mman.h&gt;

int munmap(void *addr, size_t length);</code></pre>
<h3 id="인자-1">인자</h3>
<h4 id="addr-1">addr</h4>
<p>해제할 매핑주소값</p>
<h4 id="length-1">length</h4>
<p>매핑을 해제할 Byte수</p>
<h3 id="반환값-1">반환값</h3>
<h4 id="성공-시-1">성공 시</h4>
<p>0</p>
<h4 id="실패-시-1">실패 시</h4>
<p>-1</p>
<br>

<h1 id="예제">예제</h1>
<pre><code class="language-c">struct info_t {
   char name[64];
   int age;
};

static void display_info(void)
{
   int fd = -1, totalCount;
   struct info_t *pInfo;
   struct stat statBuf;

   fd = open(&quot;file&quot;, O_RDONLY);
   if(fd &lt; 0){
      perror(&quot;open() FAIL\n&quot;);
      goto EXCEPTION;
   }

   if(fstat(fd, &amp;statBuf) &lt; 0){
      perror(&quot;fstat() FAIL\n&quot;);
      goto EXCEPTION;
   }

   pInfo = (struct info_t *)
         (mmap(NULL, statBuf.st_size, PROT_READ, MAP_SHARED, fd, 0));
   if(pInfo == MAP_FAILED){
      perror(&quot;mmap() FAIL\n&quot;);
      goto EXCEPTION;
   }

   totalCount = statBuf.st_size / sizeof(struct info_t);
   for(register int idx = 0; idx &lt; totalCount; idx++){
      printf(&quot;[%d] Name(%s), Age(%d)\n&quot;, idx, pInfo[idx].name, pInfo[idx].age);
   }

   if(munmap(fd, statBuf.st_size) &lt; 0){
     perror(&quot;munmap FAIL\n&quot;); 
   }

   close(fd);

   return;

EXCEPTION:
   if(fd &gt;= 3)   close(fd);
   return;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[디렉터리 함수]]></title>
            <link>https://velog.io/@juni-test/%EB%94%94%EB%A0%89%ED%84%B0%EB%A6%AC-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@juni-test/%EB%94%94%EB%A0%89%ED%84%B0%EB%A6%AC-%ED%95%A8%EC%88%98</guid>
            <pubDate>Mon, 24 Aug 2020 01:48:15 GMT</pubDate>
            <description><![CDATA[<h2 id="열기">열기</h2>
<pre><code class="language-c">#include &lt;sys/types.h&gt;
#include &lt;dirent.h&gt;

DIR *opendir(const char *name);
DIR *fdopendir(int fd);</code></pre>
<h4 id="인자">인자</h4>
<p>name : 디렉터리 경로
fd : 파일 디스크립터</p>
<h4 id="반환값">반환값</h4>
<p>성공 시 : 디렉터리 스트림 포인터
실패 시 : NULL</p>
<br>

<h2 id="탐색">탐색</h2>
<h3 id="entry-구조체">Entry 구조체</h3>
<pre><code class="language-c">struct dirent {
    ino_t          d_ino;       /* Inode number */
    off_t          d_off;       /* Not an offset; see below */
    unsigned short d_reclen;    /* Length of this record */
    unsigned char  d_type;      /* Type of file; not supported
                                   by all filesystem types */
    char           d_name[256]; /* Null-terminated filename */
};
</code></pre>
<h4 id="d_type-값">d_type 값</h4>
<ul>
<li><p>DT_BLK
A block device.</p>
</li>
<li><p>DT_CHR
A character device.</p>
</li>
<li><p>DT_DIR
A directory.</p>
</li>
<li><p>DT_FIFO
A named pipe (FIFO).</p>
</li>
<li><p>DT_LNK
A symbolic link.</p>
</li>
<li><p>DT_REG
A regular file.</p>
</li>
<li><p>DT_SOCK
A UNIX domain socket.</p>
</li>
<li><p>DT_UNKNOWN
The file type could not be determined.</p>
</li>
</ul>
<h3 id="함수-정의">함수 정의</h3>
<pre><code class="language-c">#include &lt;dirent.h&gt;

struct dirent *readdir(DIR *dirp);</code></pre>
<h4 id="인자-1">인자</h4>
<p>dirp : 디렉터리 스트림 포인터</p>
<h4 id="반환값-1">반환값</h4>
<p>성공 시 : 디렉터리 엔트리 포인터
실패 시 : NULL</p>
<h4 id="사용법">사용법</h4>
<p>함수를 호출할 때마다 디렉터리 하위 파일들을 차례로 반환한다.
더 이상 반환할 파일들이 없을 때 NULL을 반환한다.</p>
<br>

<h2 id="닫기">닫기</h2>
<pre><code class="language-c">#include &lt;sys/types.h&gt;
#include &lt;dirent.h&gt;

int closedir(DIR *dirp);</code></pre>
<h4 id="인자-2">인자</h4>
<p>dirp : 디렉터리 스트림 포인터</p>
<h4 id="반환값-2">반환값</h4>
<p>성공 시 : 0
실패 시 : -1</p>
<br>

<h2 id="example">Example</h2>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;stdbool.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;unistd.h&gt;
#include &lt;dirent.h&gt;

#define TYPE2STR(x) \
    (x == DT_BLK)  ? &quot;Block device&quot; :\
    (x == DT_CHR)  ? &quot;Charcter device&quot;:\
    (x == DT_DIR)  ? &quot;Directory&quot;:\
    (x == DT_FIFO) ? &quot;FIFO&quot;:\
    (x == DT_LNK)  ? &quot;Symbolic link&quot;:\
    (x == DT_REG)  ? &quot;Regular file&quot;:\
    (x == DT_SOCK) ? &quot;Socket&quot;:\
                     &quot;Unknown&quot;

static void browse_dir(void)
{
    DIR *dp = NULL;
    struct dirent *entry;

    dp = opendir(&quot;.&quot;);
    if(dp == NULL){
        perror(&quot;opendir() FAIL\n&quot;);
        goto EXCEPTION;
    }

    while(true){
        entry = readdir(dp);
        if(entry == NULL){
            break;
        }

        printf(&quot;%s: %s\n&quot;, entry-&gt;d_name, TYPE2STR(entry-&gt;d_type));
    }

    closedir(dp);

    return;

EXCEPTION:
    if(dp)  closedir(dp);
    return;
}

int main(int argc, char **argv)
{
    browse_dir();

    return 0;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Petalinux Boot RC에 Init script 추가하는 방법]]></title>
            <link>https://velog.io/@juni-test/Petalinux-Boot-RC%EC%97%90-Init-script-%EC%B6%94%EA%B0%80%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@juni-test/Petalinux-Boot-RC%EC%97%90-Init-script-%EC%B6%94%EA%B0%80%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sun, 23 Aug 2020 08:06:54 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>Boot RC에 Init script를 추가하는 방법을 설명하고자 한다.</p>
<h2 id="순서">순서</h2>
<h4 id="1-페타리눅스-프로젝트-디렉터리로-이동한다">1. 페타리눅스 프로젝트 디렉터리로 이동한다.</h4>
<p><code>$cd /home/juni/work/bsp-zcu106-2019.2/xilinx-zcu106-2019.2</code></p>
<h4 id="2-스크립트-프로젝트를-생성한다">2. 스크립트 프로젝트를 생성한다.</h4>
<p><code>$petalinux-create -t apps --template install -n bootscript --enable</code></p>
<h4 id="3-생성한-프로젝트의-디렉터리로-이동하여-스크립트를-작성한다">3. 생성한 프로젝트의 디렉터리로 이동하여 스크립트를 작성한다.</h4>
<p><code>$cd project-spec/meta-user/recipes-apps/bootscript/files</code>
<code>$vim bootscript</code></p>
<h4 id="4-프로젝트의-bitbake를-수정한다">4. 프로젝트의 Bitbake를 수정한다.</h4>
<p><code>$ cd ..</code>
<code>$ vim bootscript.bb</code></p>
<h4 id="5-init-script용-bitbake로-수정하는-방법은-다음과-같다">5. Init script용 Bitbake로 수정하는 방법은 다음과 같다.</h4>
<blockquote>
<p>+는 추가한 것, -는 삭제 또는 비활성화한 것</p>
</blockquote>
<pre><code class="language-bb">S = &quot;${WORKDIR}&quot;

+inherit update-rc.d

+INITSCRIPT_NAME = &quot;bootscript&quot;
+INITSCRIPT_PARAMS = &quot;start 99 5 2 . stop 20 0 1 6 .&quot;
#start 99 5 2 : rc2, rc5에 S99bootscript를 생성하겠다.
#stop 20 0 1 6 : rc0, rc1, rc6에 K20bootscript를 생성하겠다.

do_install(){
-    install -d ${D}/${bindir}
-    install -m 0755 ${S}/bootscript ${D}/${bindir}
+    install -d ${D}${sysconfdir}/init.d
+    install -m 0755 ${S}/bootscript ${D}${sysconfdir}/init.d/bootscript
}
+FILES_${PN} += &quot;${sysconfdir}/*&quot;</code></pre>
<h4 id="6-이미지를-빌드한다">6. 이미지를 빌드한다.</h4>
<p><code>$petalinux-build -c bootscript -x do_install -f</code>
<code>$petalinux-build -c rootfs</code>
<code>$petalinux-build</code></p>
<h4 id="7-타겟보드에-로드하여-확인한다">7. 타겟보드에 로드하여 확인한다.</h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[Petalinux Default IP 설정 방법]]></title>
            <link>https://velog.io/@juni-test/Petalinux-Default-IP-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@juni-test/Petalinux-Default-IP-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sun, 23 Aug 2020 07:20:55 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>Petalinux image의 Default IP를 설정하는 방법을 설명하고자 한다.</p>
<h2 id="순서">순서</h2>
<h4 id="1-petalinux-설정을-실행한다">1. Petalinux 설정을 실행한다.</h4>
<p><code>Ex) $petalinux-config</code></p>
<h4 id="2-subsystem-auto-hardware-settings---ethernet-settings-선택">2. Subsystem AUTO Hardware Settings - Ethernet Settings 선택</h4>
<h4 id="3-obtain-ip-address-automatically-항목-선택해제">3. Obtain IP address automatically 항목 선택해제</h4>
<h4 id="4-선택해제-후-하단에-추가되는-static-ip-설정을-입력">4. 선택해제 후 하단에 추가되는 Static IP 설정을 입력</h4>
<h4 id="5-save---exit">5. Save - Exit</h4>
<h4 id="6-petalinux-image를-빌드하고-타겟보드에-로드하여-확인한다">6. Petalinux image를 빌드하고 타겟보드에 로드하여 확인한다.</h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[Petalinux RootFS을 NFS로 설정하는 방법]]></title>
            <link>https://velog.io/@juni-test/Petalinux-NFS-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@juni-test/Petalinux-NFS-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sun, 23 Aug 2020 07:08:52 GMT</pubDate>
            <description><![CDATA[<h2 id="rootnfs-설정-방법">RootNFS 설정 방법</h2>
<blockquote>
<p>NFS 관련한 패키지가 모두 설치된 것을 기반으로 작성하였음</p>
</blockquote>
<blockquote>
<p><strong>문제가 있다.</strong>
NFS부팅까지는 문제가 없으나, 로그인 후 명령어를 1회 실행한 이후로 계속 &#39;Command not found&#39; 에러가 발생한다.
아직 해결하지 못했으니, 아래 내용은 참고만 하기 바람.</p>
</blockquote>
<h4 id="1-nfs-server-전용-디렉터리-생성">1. NFS Server 전용 디렉터리 생성</h4>
<p><code>$mkdir /home/juni/work/bsp-zcu106-2019.2/rootnfs</code></p>
<h4 id="2-petalinux-config-에서-nfs-설정">2. petalinux-config 에서 NFS 설정</h4>
<ol>
<li><p>nfs 설정</p>
<ul>
<li>Image Packaging Configuration  Root File System Type 
: NFS 선택</li>
<li>Location of NFS root directory 
: NFS Server 전용 디렉터리 경로 입력</li>
</ul>
</li>
<li><p>dts 설정</p>
<ul>
<li><p>DTG Settings -&gt; Kernel Bootargs 
: generate boot args automatically 해제</p>
</li>
<li><p>해제 후 하단에 생성되는 입력 칸에 Bootargs 직접 입력 </p>
<pre><code>Format) earlycon console=ttyPS0,115200 clk_ignore_unused root=/dev/nfs nfsroot=&lt;nfs-server-ip&gt;:&lt;nfs-server-dir-path&gt;,nfsvers=3,tcp ip=&lt;nfs-client-ip&gt;:&lt;nfs-server-ip&gt; rw</code></pre><pre><code>Ex) earlycon console=ttyPS0,115200 clk_ignore_unused root=/dev/nfs nfsroot=192.168.20.105:/home/juni/work/bsp-zcu106-2019.2/rootnfs,nfsvers=3,tcp ip=192.168.20.106:192.168.20.105 rw</code></pre></li>
</ul>
</li>
</ol>
<h4 id="3-petalinux-config--c-kernel-에서-nfs-설정">3. petalinux-config -c kernel 에서 NFS 설정</h4>
<ol>
<li><p>ip 설정
: Networking support -&gt; Networking options -&gt; TCP/IP networking 선택 -&gt; IP : kernel level autoconfiguration 선택 -&gt; IP: DHCP Support, BOOTP support, RARP support 모두 선택</p>
</li>
<li><p>nfs 설정
: File systems -&gt; Network file systems -&gt; Root file system on NFS 선택</p>
</li>
</ol>
<h4 id="4-project-build">4. Project build</h4>
<ol>
<li><p><code>petalinux-build -c device-tree -x cleansstate &amp;&amp; petalinux-build -c device-tree</code> </p>
<blockquote>
<p>2번 단계를 하지 않았다면 스킵</p>
</blockquote>
</li>
<li><p><code>petalinux-build -c kernel</code></p>
<blockquote>
<p>3번 단계를 하지 않았다면 스킵</p>
</blockquote>
</li>
<li><p><code>petalinux-build -x distclean &amp;&amp; petalinux-build</code></p>
</li>
</ol>
<h4 id="5-bootbin-and-boot-image-build">5. BOOT.BIN and boot image build</h4>
<ol>
<li><p>Image 디렉터리로 이동
<code>$cd &lt;plnx-proj-root&gt;/images/linux</code></p>
</li>
<li><p>BOOT.BIN Build</p>
<pre><code>Ex) $petalinux-package --boot --format BIN --fsbl zynqmp_fsbl.elf --u-boot u-boot.elf --pmwfw.elf --fpga *.bit --force</code></pre></li>
<li><p>Boot image build</p>
<pre><code>Ex) $tar czf 2019.2-zcu106-rootnfs.tar.gz BOOT.BIN image.ub *.bit system.dtb zynqmp_fsbl.elf bl31.elf pmufw.elf u-boot.elf</code></pre></li>
</ol>
<h4 id="6-nfs-server-directory-setup">6. NFS Server directory setup</h4>
<ol>
<li>빌드로 생성된 rootfs 압축파일 사용하기<pre><code>$tar xzf &lt;plnx-proj-root&gt;/images/linux/rootfs.tar.gz -C &lt;nfs-server-dir-path&gt;</code></pre></li>
</ol>
<h4 id="7-etcexports-편집하기">7. /etc/exports 편집하기</h4>
<ol>
<li><p>Root 계정 로그인
<code>$su -</code></p>
</li>
<li><p>export 편집하기
<code>$vim /etc/exports</code></p>
</li>
<li><p>NFS 설정 추가하고 종료하기</p>
<pre><code>Format) &lt;nfs-server-dir-path&gt; &lt;ip-to-allow&gt;(rw,no_root_squash)</code></pre><pre><code>Ex) $/home/juni/work/bsp-zcu106-2019.2/rootnfs 192.168.20.*(rw,no_root_squash)</code></pre></li>
<li><p>Export 설정 반영하기
<code>$service nfs restart</code>
<code>$exportfs -r</code></p>
</li>
</ol>
<h4 id="8-빌드한-boot-image-압축파일을-sd카드에-압축해제한-후-타겟보드-부팅-rootnfs로-부팅하는-지-확인">8. 빌드한 Boot image 압축파일을 SD카드에 압축해제한 후 타겟보드 부팅. RootNFS로 부팅하는 지 확인</h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[Petalinux SSH 활성화 방법]]></title>
            <link>https://velog.io/@juni-test/Petalinux-SSH-%ED%99%9C%EC%84%B1%ED%99%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@juni-test/Petalinux-SSH-%ED%99%9C%EC%84%B1%ED%99%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sun, 23 Aug 2020 06:45:54 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>Petalinux의 SSH 기능 설정은 OpenSSH, DropBear 두 가지가 있다.
OpenSSH는 일반 PC환경 같은 여유로운 자원이 뒷받침되는 플랫폼을 위한 것이고, DropBear는 임베디드 같이 자원이 한정된 플랫폼을 위한 것이다.</p>
<p>이 두 가지에 대해서 각각 Kernel config 방법에 대해서 기술하려고 한다.</p>
<h2 id="openssh">OpenSSH</h2>
<ol>
<li><code>$petalinux-config -c rootfs</code> </li>
<li>Filesystem Packages - console - network - openssh - openssh
: Y 선택</li>
<li>Filesystem Packages - console - network - openssh - openssh-* 
: 취향 껏 Y 선택</li>
<li>Image Features - &quot;imagefeature-ssh-server-openssh&quot;
: Y 선택</li>
<li>Filesystem Packages - console - network - dropbear
: <strong>N 선택</strong></li>
<li>Image Features - &quot;imagefeature-ssh-server-dropbear&quot;
: <strong>N 선택</strong></li>
<li>Filesystem Packages - misc - &quot;packagegroup-core-ssh-dropbear&quot; - &quot;packagegroup-core-ssh-dropbear&quot;
: <strong>N 선택</strong></li>
<li>Save - Exit</li>
<li>Boot image Re-build</li>
<li>New boot image load on target board</li>
<li>IP 설정</li>
<li>SSH 접속 시도</li>
</ol>
<h2 id="dropbear">DropBear</h2>
<blockquote>
<p>사실 OpenSSH 설정과 정반대로 하면 된다.</p>
</blockquote>
<ol>
<li><code>$petalinux-config -c rootfs</code></li>
<li>Filesystem Packages - console - network - dropbear 
: Y 선택</li>
<li>Image Features - imagefeature-ssh-server-dropbear 
: Y 선택</li>
<li>Filesystem Packages - misc - packagegroup-core-ssh-dropbear - packagegroup-core-ssh-dropbear 
: Y 선택</li>
<li>Filesystem Packages - console - network - openssh - openssh 
: <strong>N 선택</strong></li>
<li>Filesystem Packages - console - network - openssh - openssh-* 
: <strong>모두 N 선택</strong></li>
<li>Image Features - imagefeature-ssh-server-openssh 
: <strong>N 선택</strong></li>
<li>Save - Exit</li>
<li>Boot image Re-build</li>
<li>New boot image load on target board</li>
<li>IP 설정</li>
<li>SSH 접속 시도</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[파일 속성 조회]]></title>
            <link>https://velog.io/@juni-test/%ED%8C%8C%EC%9D%BC-%EC%86%8D%EC%84%B1-%EC%A1%B0%ED%9A%8C</link>
            <guid>https://velog.io/@juni-test/%ED%8C%8C%EC%9D%BC-%EC%86%8D%EC%84%B1-%EC%A1%B0%ED%9A%8C</guid>
            <pubDate>Fri, 21 Aug 2020 02:45:17 GMT</pubDate>
            <description><![CDATA[<h2 id="파일-속성-구조체">파일 속성 구조체</h2>
<pre><code class="language-c"> struct stat {
    dev_t     st_dev;         /* ID of device containing file */
    ino_t     st_ino;         /* Inode number */
    mode_t    st_mode;        /* File type and mode */
    nlink_t   st_nlink;       /* Number of hard links */
    uid_t     st_uid;         /* User ID of owner */
    gid_t     st_gid;         /* Group ID of owner */
    dev_t     st_rdev;        /* Device ID (if special file) */
    off_t     st_size;        /* Total size, in bytes */
    blksize_t st_blksize;     /* Block size for filesystem I/O */
    blkcnt_t  st_blocks;      /* Number of 512B blocks allocated */

    /* Since Linux 2.6, the kernel supports nanosecond
    precision for the following timestamp fields.
    For the details before Linux 2.6, see NOTES. */

    struct timespec st_atim;  /* Time of last access */
    struct timespec st_mtim;  /* Time of last modification */
    struct timespec st_ctim;  /* Time of last status change */

    #define st_atime st_atim.tv_sec      /* Backward compatibility */
    #define st_mtime st_mtim.tv_sec
    #define st_ctime st_ctim.tv_sec
};</code></pre>
<br>

<h2 id="속성-조회-함수">속성 조회 함수</h2>
<pre><code class="language-c">#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;unistd.h&gt;

int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);</code></pre>
<h4 id="인자">인자</h4>
<p>pathname : 파일 경로
fd : File descriptor
statbuf : 파일 속성을 저장할 구조체</p>
<h4 id="반환값">반환값</h4>
<p>성공 시 : 0
실패 시 : -1</p>
<br>

<h2 id="매크로">매크로</h2>
<h4 id="description">Description</h4>
<pre><code class="language-c">S_ISREG(statbuf.st_mode) //Regular file?
S_ISDIR(statbuf.st_mode) //Directory?
S_ISCHR(statbuf.st_mode) //Character device?
S_ISBLK(statbuf.st_mode) //Block device?
S_ISFIFO(statbuf.st_mode) //FIFO?
S_ISLNK(statbuf.st_mode) //Symbolic link?
S_ISSOCK(statbuf.st_mode) //Socket?</code></pre>
<h4 id="example">Example</h4>
<pre><code class="language-c">static void show_file_info(const char * const file)
{
    struct stat statbuf;

    if(stat(file, &amp;statbuf) &lt; 0){
        perror(&quot;stat() FAIL\n&quot;);
        return;
    }

    printf(&quot;Name : %s\n&quot;, file);
    printf(&quot;Type : &quot;);
    if(S_ISREG(statbuf.st_mode)){
        printf(&quot;Regular file&quot;);
    }
    else if(S_ISDIR(statbuf.st_mode)){
        printf(&quot;Directory&quot;);
    }
    else {
        printf(&quot;The others&quot;);
    }
    printf(&quot;\n&quot;);
    printf(&quot;Size : %ld\n&quot;, statbuf.st_size);
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[저수준 파일 입출력 함수]]></title>
            <link>https://velog.io/@juni-test/%EC%A0%80%EC%88%98%EC%A4%80-%ED%8C%8C%EC%9D%BC-%EC%9E%85%EC%B6%9C%EB%A0%A5-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@juni-test/%EC%A0%80%EC%88%98%EC%A4%80-%ED%8C%8C%EC%9D%BC-%EC%9E%85%EC%B6%9C%EB%A0%A5-%ED%95%A8%EC%88%98</guid>
            <pubDate>Fri, 21 Aug 2020 02:28:29 GMT</pubDate>
            <description><![CDATA[<h2 id="파일-쓰기-함수">파일 쓰기 함수</h2>
<h3 id="dprintf">dprintf</h3>
<pre><code class="language-c">#include &lt;stdio.h&gt;

int dprintf(int fd, const char *format, ...);</code></pre>
<h4 id="인자">인자</h4>
<p>fd : File descriptor
format : 포맷 스트링을 포함한 문자열 버퍼
... : 가변 인자</p>
<h4 id="반환값">반환값</h4>
<p>성공 시 : 저장한 Byte수
실패 시 : -1</p>
<h3 id="write-pwrite">write, pwrite</h3>
<pre><code class="language-c">#include &lt;unistd.h&gt;

ssize_t write(int fd, const void *buf, size_t count);
sszie_t pwrite(int fd, const void *buf, size_t count, off_t offset);</code></pre>
<h4 id="인자-1">인자</h4>
<p>fd : File descriptor
buf : 저장할 버퍼
count : 저장할 Byte수
offset : 저장의 기준 오프셋(파일 시작점으로 부터)</p>
<h4 id="반환값-1">반환값</h4>
<p>성공 시 : 저장한 Byte수(단, count보다 작을 수 있음)
실패 시 : -1</p>
<br>

<h2 id="파일-읽기-함수">파일 읽기 함수</h2>
<pre><code class="language-c">#include &lt;unistd.h&gt;

ssize_t read(int fd, const void *buf, size_t count);
ssize_t pread(int fd, const void *buf, size_t count, off_t offset);</code></pre>
<h4 id="인자-2">인자</h4>
<p>fd : File descriptor
buf : 읽어온 데이터를 저장할 버퍼
count : 읽어올 Byte수
offset : 읽기의 기준 오프셋(파일의 시작점으로부터)</p>
<h4 id="반환값-2">반환값</h4>
<p>성공 시 : </p>
<ul>
<li>읽어온 Byte수(단, count보다 작을 수 있음)</li>
<li>다 읽었을 땐, 0을 반환</li>
</ul>
<p>실패 시 : -1</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[저수준 파일 열기/닫기 함수]]></title>
            <link>https://velog.io/@juni-test/%EC%A0%80%EC%88%98%EC%A4%80-%ED%8C%8C%EC%9D%BC-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@juni-test/%EC%A0%80%EC%88%98%EC%A4%80-%ED%8C%8C%EC%9D%BC-%ED%95%A8%EC%88%98</guid>
            <pubDate>Thu, 20 Aug 2020 02:37:23 GMT</pubDate>
            <description><![CDATA[<h2 id="파일-열기">파일 열기</h2>
<pre><code class="language-c">#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;

int open(const char * file, int flags);
int open(const char * file, int flags, int mode);</code></pre>
<h4 id="인자">인자</h4>
<p>file : 작업을 할 대상 파일</p>
<p>flags : 파일을 열 때 취할 옵션</p>
<ul>
<li>O_RDONLY</li>
<li>*[필수]** Read only용으로 Open</li>
<li>O_WRONLY</li>
<li>*[필수]** Write only용으로 Open</li>
<li>O_RDWR</li>
<li>*[필수]** Read&amp;Write 용으로 Open</li>
<li>O_CREAT
대상 파일이 존재하지 않을 시, 파일 생성</li>
<li>O_NOFOLLOW
대상 파일이 Symbolic link 파일일 때, Open하지 않음</li>
<li>O_TRUNC
대상 파일이 존재할 시, 덮어씀</li>
<li>O_APPEND
파일을 열 때, 파일 오프셋을 파일 가장 마지막에 위치시킴</li>
</ul>
<p>mode: 파일의 권한 설정</p>
<ul>
<li>0644 이런 식으로 지정할 수 있음</li>
<li>아니면 Pre-defined 문자열로 지정할 수도 있음. 리스트는 다음과 같음<ul>
<li>S_IRWXU : 0700</li>
<li>S_IRUSR : 0400</li>
<li>S_IWUSR : 0200</li>
<li>S_IXUSR : 0100</li>
<li>S_IRWXG : 0070</li>
<li>S_IRGRP : 0040</li>
<li>S_IWGRP : 0020</li>
<li>S_IXGRP : 0010</li>
<li>S_IRWXO : 0007</li>
<li>S_IROTH : 0004</li>
<li>S_IWOTH : 0002</li>
<li>S_IXOTH : 0001</li>
</ul>
</li>
</ul>
<h4 id="반환값">반환값</h4>
<p>성공 시 : File descriptor값
실패 시 : -1</p>
<br>

<h2 id="파일-닫기">파일 닫기</h2>
<pre><code class="language-c">#include &lt;unistd.h&gt;

int close(int fd);</code></pre>
<h4 id="인자-1">인자</h4>
<p>fd : File descriptor</p>
<h4 id="반환값-1">반환값</h4>
<p>성공 시 : 0
실패 시 : -1</p>
<br>

<h2 id="offset-설정">Offset 설정</h2>
<pre><code class="language-c">#include &lt;sys/types.h&gt;
#include &lt;unistd.h&gt;

off_t lseek(int fd, off_t offset, int whence);</code></pre>
<h4 id="인자-2">인자</h4>
<p>fd : File descriptor
offset : Offset 값(양음수 가능)
whence : Offset의 기준</p>
<ul>
<li>SEEK_SET
파일의 처음</li>
<li>SEEK_END
파일의 끝</li>
<li>SEEK_CUR
파일의 현재 커서 위치</li>
</ul>
<h4 id="반환값-2">반환값</h4>
<p>성공 시 : 파일의 처음부터 이동한 커서 위치까지의 Byte수
실패 시 : -1</p>
<br>

<h2 id="파일-디스크립터---포인터-변환-함수">파일 디스크립터 - 포인터 변환 함수</h2>
<h3 id="fdopen">fdopen</h3>
<pre><code class="language-c">#include &lt;stdio.h&gt;

FILE *fdopen(int fd, const char *mode);</code></pre>
<h4 id="인자-3">인자</h4>
<p>fd : File descriptor
mode : fopen()의 mode와 동일(Ex: &quot;r&quot;, &quot;w+&quot;, ...)</p>
<h4 id="반환값-3">반환값</h4>
<p>성공 시 : File pointer
실패 시 : NULL</p>
<h4 id="주의점">주의점</h4>
<p><img src="https://images.velog.io/images/juni-test/post/12b4d686-59d8-4311-abac-5f37838d730e/2.jpg" alt="">
파일포인터를 다 사용한 후, 반드시 fclose()로 해제해야 함.</p>
<h3 id="fileno">fileno</h3>
<pre><code class="language-c">#include &lt;stdio.h&gt;

int fileno(FILE *fp);</code></pre>
<h4 id="인자-4">인자</h4>
<p>fp : File pointer</p>
<h4 id="반환값-4">반환값</h4>
<p>성공 시 : File descriptor
실패 시 : -1</p>
<h4 id="주의점-1">주의점</h4>
<p><img src="https://images.velog.io/images/juni-test/post/e554adee-33ee-4c81-8f8a-018186576f53/1.jpg" alt="">
fdopen()함수와는 다르게 디스크립터를 해제하지 않아도 됨.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[백만장자의 시크릿]]></title>
            <link>https://velog.io/@juni-test/%EB%B0%B1%EB%A7%8C%EC%9E%A5%EC%9E%90%EC%9D%98-%EC%8B%9C%ED%81%AC%EB%A6%BF</link>
            <guid>https://velog.io/@juni-test/%EB%B0%B1%EB%A7%8C%EC%9E%A5%EC%9E%90%EC%9D%98-%EC%8B%9C%ED%81%AC%EB%A6%BF</guid>
            <pubDate>Mon, 10 Aug 2020 15:04:59 GMT</pubDate>
            <description><![CDATA[<h1 id="후기">후기</h1>
<p>　나는 돈 관리가 어려웠다.</p>
<p>　나름의 가계부도 쓰고 해봤지만 돈이 잘 모이지도 않았다. 부 소득으로 주식 같은 걸 해보려고 생각은 했지만, 내 딴엔 여윳돈이 없어서 실행에 옮기진 못했다. </p>
<p>　그러던 중 어느새 서른이 되었다.</p>
<p>　예전에 부모님께 서른이 되면 집을 사드리겠다고 호언장담을 했는데... 는 무슨 지금 당장 전세집 재계약이 가능할까로 맘졸이고 있는 상태고, 여자친구와도 결혼이 하고 싶지만 목돈이 그리 많지 않다는 것도 걱정이다.</p>
<p>　책을 평소에도 읽긴 하지만, 경제 책은 읽은 적이 없었다. 그렇다보니 경제적인 지식이 너무나 전무했다. 지금 현실이 왜 이런지 어느 정도 납득이 갔다.</p>
<p>　그래서 부자들은 어떻게 행동하는 지 알고 싶어서 유명한 책인 백만장자의 시크릿을 당장 구매를 하여 읽기 시작했다.</p>
<p>　내용은 의외로 특별하진 않았다. 누구나 알 법은 하지만, 행동은 하지 않는 그런 것들.</p>
<p>　하지만 행동으로 옮겼는 지에 대한 여부가 결국 현재를 판가름했을 것이다.</p>
<p>　맞다. 저자가 말한 것처럼 생각이 중요한 게 아니라, 행동이 더 중요하다. &#39;콜롬버스의 달걀&#39;처럼!</p>
<p>　그리고 읽으면서 느낀 건 저자가 강조하는 마음가짐과 내 평소 마음가짐이 같다는 것이다. 하지만, 나의 경우는 경제 분야가 아니라 삶의 방식이나 커리어에만 적용하고 있었다는 점이 다르다.</p>
<p>　예를 들면, 저자는 &#39;내 인생의 부는 내가 만든다&#39; 같은 자기 주체적인 마인드를 계속 강조한다. 나도  주체적인 삶을 살기 위해 부모님으로부터 독립을 하고, 문제가 생기면 자기성찰을 하고, 난관에 부딪히면 어떻게 극복할 수 있는가를 생각한다.</p>
<p>　지난 4월에 이직할 곳을 구해두지 않은 상태로 회사를 그만두었을 때도, 주변에서는 엄청난 우려와 걱정을 표했다. 그 때는 코로나라 한창일 때라, 다들 강제퇴사를 당하고 있는 실정이었기 때문에 나도 한편으로 걱정이 되긴 했다.</p>
<p>　하지만, 나의 신념에 따라 퇴사를 결심하였고, 결심을 당장 행동으로 옮기지 않으면 백년이 흘러도 변하는 건 없을 것이란 걸 알았기 때문에 한 치 앞도 안보이긴 했지만 리스크를 감수하기로 다짐했었다.</p>
<p>　리스크가 상당해 보였지만, 나는 그 리스크보다 큰 사람이고, 잘안되어도 상황을 다시 좋게 만들 자신감이 있었다. 퇴사 후 취업 기간 중 연구소장님이나 다른 사람들이 퇴사를 후회하지 않냐는 질문을 많이 했는데, 나는 그 때마다 &quot;일 년을 백수로 지내야 할지라도 퇴사한 것을 후회하지 않는다.&quot;라고 답변했다.</p>
<p>　이미 내 자신이 결정을 했었고, 그로 인해 발생하는 리스크는 당연히 내가 감수해야 하는 거고, 또 그럴 자신감이 있으니까.</p>
<p>　그래서 지금은 이전 직장보다 더 많은 돈을 받고, 더 좋은 곳에서 일하고, 더 좋은 대접을 받고, 더 좋은 근무환경에서 일을 하고 있다. 하지만 이전 직장에서 회사를 욕하면서 정작 행동을 하지 않던 나머지 동료분들은 상황이 나아지기는 커녕 오히려 점점 악화되어 가고 있다고 한다.</p>
<p>　어쨋든 이런 마인드로 살아가고 있는 나였기에 저자의 주장에 동감이 많이 되었다. 그러면서 나의 마인드를 왜 경제 분야에는 적용시키지 못했는지 꽤나 아쉬운 마음이 들었다.</p>
<p>　그래서 나는 아직 서른 밖에 안됐고, 지금부터 시작해보려고 한다. 책을 읽고 HOW TO를 알았다고 하지만 지금 당장에 다이나믹한 변화를 일으킬 수는 없다. 당장 저자가 강조하는 돈 관리도 아직도 너무 어려우니 말이다.</p>
<p>　하지만, 가계부도 저자가 추천하는 방식으로 양식을 변경했고, 차근차근 해보고 있다. 이러한 작은 변화들이 모여, 결국 나를 성장시킬 것이라고 믿는다.</p>
<p>　그리고 사람들이 이 책 다음으로 추천하는 &#39;부의 추월차선&#39;도 이제 읽기 시작했다. 그 다음은 &#39;시작의 기술&#39;을 읽을 계획이다.</p>
<p>　이렇게 서른 다섯에는 정말로 부모님 집을 사드릴 것이다.</p>
<p>　마지막으로 저자의 가르침을 다시 한 번 되새길 것이다.</p>
<blockquote>
<p>나는 백만장자의 마인드를 가졌다!!!</p>
</blockquote>
<br>
<br>
<br>

<h1 id="요약">요약</h1>
<blockquote>
<p>나는 백만장자 마인드를 가졌다!!!</p>
</blockquote>
<h2 id="17가지-시크릿">17가지 시크릿</h2>
<h3 id="1-내-인생의-부는-내가-만든다">1. 내 인생의 부는 내가 만든다.</h3>
<blockquote>
<p>부자는 &#39;내 인생은 내가 만든다&#39;고 믿는다.
가난한 사람은 &#39;인생은 우연이 만든다&#39;고 믿는다.</p>
</blockquote>
<h4 id="선언">선언</h4>
<p>&quot;나의 경제적인 성공은 내가 만든다!&quot;</p>
<h4 id="행동지침">행동지침</h4>
<ul>
<li><p>비난하고 합리화하고 불평하는 자신을 깨달을 때마다 집게손가락으로 목에 선을 그어라. 경제적인 목을 자르고 있다는 사실을 자신에게 일깨워 주는 행동이다.
이 동작이 조금 천박하게 느껴지더라도 비난이나 합리화나 불평으로 자신에게 저지르고 있는 짓보다는 훨씬 덜 천박하다. 이런 행동이 마침내 파멸을 부르는 습관을 떨쳐내게 해줄 것이다.</p>
</li>
<li><p>&#39;보고&#39;를 하라. 하루를 마무리할 때, 잘한 일 하나와 잘못한 일 하나를 적어라. 그 다음에 &#39;내가 어떻게 이런 상황을 만들었는가?&#39; 생각해보라. 다른 사람이 관여된 일이라면 &#39;그 상황에서 내가 어떤 역할을 했는가?&#39; 자문해 보고 그에 대한 대답을 써라.
이런 연습으로 자신의 인생을 책임질 수 있으며, 효과적인 전략과 비효과적인 전략을 파악할 수 있을 것이다.</p>
</li>
</ul>
<br>

<h3 id="2-부자는-부를-목표로-한다">2. 부자는 부를 목표로 한다.</h3>
<blockquote>
<p>부자는 돈을 벌려고 머니게임을 한다.
가난한 사람은 손해를 보지 않으려고 머니 게임을 한다.</p>
</blockquote>
<h4 id="선언-1">선언</h4>
<p>&quot;내 목표는 백만장자가 되는 것이다!&quot;</p>
<h4 id="행동지침-1">행동지침</h4>
<ul>
<li><p>평범한 정도를 넘어 부자가 되겠다는 의지가 드러나도록 경제적 목표를 적어라.
아래 나오는 2가지의 달성 목표를 적어라.
그리고 이 목표를 성취할 수 있도록 현실성 있는 계획을 세워라. 그와 동시에 &quot;별을 쏘아야 한다.&quot;는 점도 명심하라.</p>
<ul>
<li>연소득 <strong><strong><strong><strong><strong><strong><strong>__</strong></strong></strong></strong></strong></strong></strong></li>
<li>순자산 <strong><strong><strong><strong><strong><strong><strong>__</strong></strong></strong></strong></strong></strong></strong></li>
</ul>
</li>
<li><p>고급 레스토랑에 가서 가격을 묻지 말고 &#39;시가&#39;라고 쓰여 있는 음식을 주문하라. (가진 돈이 부족하면 한 그릇을 나눠 먹어도 된다.)</p>
</li>
</ul>
<br>

<h3 id="3-부를-꿈꾸고-헌신하는-사람만이-부자가-된다">3. 부를 꿈꾸고 헌신하는 사람만이 부자가 된다.</h3>
<blockquote>
<p>부자는 부자가 되기 위해 집중하고 헌신한다.
가난한 사람은 부자가 되기를 바라기만 한다.</p>
</blockquote>
<h4 id="선언-2">선언</h4>
<p>&quot;부자가 되기 위해 헌신하겠다.&quot;</p>
<h4 id="행동지침-2">행동지침</h4>
<ul>
<li>부자가 되어야 하는 이유를 짧은 문장으로 적어라. 구체적이어야 한다.</li>
<li>힘이 되어줄 친구나 가족을 만나라. 큰 성공을 이뤄내기 위해 헌신의 힘을 불러내고 싶다고 말하라. 가슴에 손을 얹고 그 사람의 눈을 쳐다보며 이렇게 말하라.
&quot;나, _<em>는 지금부터 _</em>(날짜)까지 백만장자가 되기 위해 헌신하겠습니다.&quot;
그 사람에게 이 말을 해달라고 하라. &quot;널 믿는다&quot;
그 후에 당신이 대답하라. &quot;고마워&quot;
헌신하겠다고 선언하기 전과 후의 느낌이 어떻게 다른가? 자유가 느껴진다면 제 길에 들어섰다. 약간 두렵다면 그것도 제 길에 들어선 셈이다. 그런 행동을 하는 게 귀찮다면 아직 &#39;무슨 일이든 다하겠다는 의지가 없는&#39; 상태이거나 &#39;그렇게 이상한 걸 왜 해야 하나.&#39;라고 회의하는 상태일 것이다. 다시 말하지만 당신의 그 방식이 지금 그 자리에 당신을 데려다 놓았다.</li>
</ul>
<br>

<h3 id="4-크게-생각하는-사람이-크게-이룬다">4. 크게 생각하는 사람이 크게 이룬다.</h3>
<blockquote>
<p>부자는 크게 생각한다.
가난한 사람을 작게 생각한다.</p>
</blockquote>
<h4 id="선언-3">선언</h4>
<p>&quot;크게 생각하자! 수천, 수만 명에게 기여하는 사람이 되겠다!&quot;</p>
<h4 id="행동지침-3">행동지침</h4>
<ul>
<li><p>자신의 &#39;타고난 재능&#39;을 생각해서 적어라.
어려서부터 늘 잘했던 일들이 그 예가 될것이다.
이 재능을 당신의 인생과 직업에 적극적으로 활용할 수 있는 방법과 분야를 적어라.</p>
</li>
<li><p>지금 하는 일이나 사업상 관련된 사람보다 열 배 많은 사람들을 끌어들일 수 있는 방법을 적어라.
그 방법은 다른 사람들과 상의하라.
최소한 3가지 전략을 짜라. 지렛대 원리도 생각해 보라.</p>
</li>
</ul>
<br>

<h3 id="5-행동하는-것이-행동하지-않는-것보다-낫다">5. 행동하는 것이 행동하지 않는 것보다 낫다.</h3>
<blockquote>
<p>부자는 기회에 집중한다.
가난한 사람은 장애물에 집중한다.</p>
</blockquote>
<h4 id="선언-4">선언</h4>
<p>&quot;장애물보다 기회에 집중하겠다.&quot;
&quot;준비하고, 발사하고, 조준하겠다!&quot;</p>
<h4 id="행동지침-4">행동지침</h4>
<ul>
<li><p>게임에 돌입하라.
당신이 시작하고 싶은 프로젝트나 상황을 생각하라. 기다리는 건 잊어버려라.
지금 있는 곳에서, 지금 가지고 있는 것으로, 지금 시작하라. 가능하면 처음에는 다른 사람 밑에서 일하거나 다른 사람과 같이 일하면서 요령을 배우는 편이 낫다. 이미 배웠다면 다른 핑계는 없다. 
추진하라!</p>
</li>
<li><p>낙관적인 자세를 연습하라.
장애물이나 문젯거리를 언급하는 사람이 있으면 그것을 기회나 가능성으로 바꿔 말하라. 부정적인 사람들에게는 속 터질 노릇이겠지만 달라질 게 뭐가 있겠나? 어차피 그들은 끝없이 자기 속을 긁어대고 있다!</p>
</li>
<li><p>갖지 못한 것 말고, 갖고 있는 것을 생각하라.
당신의 삶에 감사할 일을 10가지 적어 큰 소리로 읽어보자. 앞으로 한 달 동안 아침마다 그것을 읽어라. 지금 가진 것에 감사하지 않으면 더 많이 갖지 못하게 되고 그것은 더 필요하지 않다는 뜻이다.</p>
</li>
</ul>
<br>

<h3 id="6-부를-부자를-긍정하라">6. 부를, 부자를 긍정하라</h3>
<blockquote>
<p>부자는 성공한 부자들에게 감탄한다.
가난한 사람은 성공한 부자들을 욕한다.</p>
</blockquote>
<h4 id="선언-5">선언</h4>
<p>&quot;나는 부자들에게 감탄한다!&quot;
&quot;나는 부자들을 축복한다!&quot;
&quot;나는 부자들을 사랑한다!&quot;
&quot;나는 그런 부자가 될 것이다!&quot;</p>
<h4 id="행동지침-5">행동지침</h4>
<ul>
<li><p>&quot;네가 원하는 것을 축복하라.&quot;는 후나 철학을 연습하라.
돌아다니면서 아름다운 집이나 비까번쩍한 차들을 보아라.
성공한 사업에 대한 이야기를 읽어라.
마음에 드는 게 있거든 그것과 그 주인과 거기에 관련된 사람들을 축복하라.</p>
</li>
<li><p>어느 분야에서 대단히 성공한 사람에게 편지나 이메일을 보내라.
그들의 성취에 대한 감탄과 존경이 담긴 내용으로.</p>
</li>
</ul>
<br>

<h3 id="7-긍정-에너지를-가진-사람들을-가까이-하라">7. 긍정 에너지를 가진 사람들을 가까이 하라.</h3>
<blockquote>
<p>부자들을 긍정적이고 성공한 사람들과 사귄다.
가난한 사람은 부정적이고 성공하지 못한 사람들과 사귄다.</p>
</blockquote>
<h4 id="선언-6">선언</h4>
<p>&quot;성공한 부자들을 본받겠다.&quot;
&quot;성공한 부자들과 어울리겠다.&quot;
&quot;그들이 할 수 있다면 나도 할 수 있다!&quot;</p>
<h4 id="행동지침-6">행동지침</h4>
<ul>
<li><p>도서관, 서점, 인터넷, 어디든 들어가서 세계적으로 성공한 부자의 이야기를 읽어라.
앤드류 카네기, 존 D.록펠러, 메어리 케이, 도널드 트럼프, 워렌 버핏, 잭 웰치, 빌 게이츠, 테드 터너... 이런 사람들을 선택하면 된다. 그들의 성공담에서 영감을 얻고 특별한 성공 전략을 알아내고, 가장 중요한 그들의 마인드를 습득하라.</p>
</li>
<li><p>테니스, 헬스, 골프, 비즈니스 클럽, 기타 고급 클럽에 다녀라.
부유한 사람들 틈에 섞여라. 고급스런 클럽에 갈 형편이 안 되면 근사한 호텔에서 커피나 차를 마셔라. 이런 분위기에 편안해져라.
거기에 드나드는 손님들을 지켜보며 당신과 똑같은 사람이라는 것을 알라.</p>
</li>
<li><p>당신의 삶을 퇴보시키는 상황이나 사람들에게서 떨어져라.
그것이 가족이라면 되도록 덜 붙어 있어라.</p>
</li>
<li><p>쓸데 없는 텔레비전 프로그램이나 스트레스를 유발하는 뉴스를 멀리하라.</p>
</li>
</ul>
<br>

<h3 id="8-자신과-자신의-가치를-알려야-한다">8. 자신과 자신의 가치를 알려야 한다.</h3>
<blockquote>
<p>부자는 자신을 알리고 자신의 가치를 높이려고 한다.
가난한 사람은 판매와 홍보를 부정적으로 생각한다.</p>
</blockquote>
<h4 id="선언-7">선언</h4>
<p>&quot;정열적으로 열렬하게 나의 가치를 다른 사람들에게 알리겠다.&quot;</p>
<h4 id="행동지침-7">행동지침</h4>
<ul>
<li><p>당신이 지금 제공하고 있는(혹은 계획하고 있는) 상품이나 서비스가 얼마나 가치 있다고 믿는가?
1부터 10까지 등급을 매겨보라. 
7에서 9의 결과가 나왔다면 가치를 높이기 위해 상품이나 서비스를 개조하라.
6 이하의 결과가 나왔다면 그 상품이나 서비스 제공을 중지하고 확실히 가치 있다고 믿는 다른 것을 선택하라.</p>
</li>
<li><p>마케팅과 판매에 관한 책을 읽고 영상을 보고 강의를 들어라.
당신의 가치를 100퍼센트 홍보할 수 있을 정도로 해당 분야의 전문가가 되어라.</p>
</li>
</ul>
<br>

<h3 id="9-어떤-어려움이-닥쳐도-그보다-강해져라">9. 어떤 어려움이 닥쳐도 그보다 강해져라.</h3>
<blockquote>
<p>부자는 그들의 문제보다 크다.
가난한 사람은 그들의 문제보다 작다.</p>
</blockquote>
<h4 id="선언-8">선언</h4>
<p>&quot;나는 어떤 어려움보다도 크다!&quot;
&quot;나는 어떤 문제도 처리할 수 있다!&quot;</p>
<h4 id="행동지침-8">행동지침</h4>
<ul>
<li><p>커다란 문제가 생겼다고 느껴질 때마다 자신에게 손가락질하며
&quot;내가 작아서, 내가 작아서 그렇다!&quot;라고 소리쳐라.
그 다음에 깊이 숨을 들이쉬고 말하라.
&quot;나는 이 문제를 처리할 수 있다. 난 어떤 문제보다도 크다.&quot;</p>
</li>
<li><p>지금 문제가 되는 사항을 하나 적어라. 문제를 해결하거나 적어도 이 상황을 개선할 수 있는 방안 10가지를 구체적으로 적어라.
이 행동으로 당신의 생각은 문제에서 해결책으로 옮겨갈 것이다.
그러면 2가지 이점이 생긴다.
첫째, 문제를 해결할 가능성이 커진다. 둘째, 기분이 한결 좋아진다.</p>
</li>
</ul>
<br>

<h3 id="10-나는-충분히-받을만큼-가치있는-사람이다">10. 나는 충분히 받을만큼 가치있는 사람이다.</h3>
<blockquote>
<p>부자는 잘 받는다.
 가난한 사람을 잘 받지 못한다.</p>
</blockquote>
<h4 id="선언-9">선언</h4>
<p> &quot;나는 잘 받는 사람이다. 나는 인생에 들어오는 어마어마한 돈을 얼마든지 받아들일 것이다.&quot;</p>
<h4 id="행동지침-9">행동지침</h4>
<ul>
<li><p>잘 받는 사람이 되도록 연습하라.
칭찬을 들을 때마다 &quot;고마워요.&quot;라고 말하자.
그 사람을 똑같이 칭찬해 주려고 하지 말라. 상대의 칭찬을 &#39;빗나가게&#39; 하기 때문이다.
그 칭찬을 충분히 받아들이고 소유하라.</p>
</li>
<li><p>&#39;어떤&#39; 돈이든 찾거나 받을 때 열렬하게 기뻐하라.
나가서 소리쳐라. &quot;난 돈이 붙는 자석이다. 고맙다. 고마워&quot; 주운 돈, 선물로 받은 돈, 정부에서 받은 돈, 월급으로 받은 돈, 사업으로 번 돈, 모두 다 해당된다.
우주는 당신의 믿음을 지원해 주려고 한다. 당신이 돈이 붙는 자석이라고 계속 소리치면, 그리고 그 증거가 있으면 우주도 더 많이 보내줄 것이다.</p>
</li>
<li><p>자신의 응석을 받아주어라.
최소한 한 달에 한 번, 당신의 몸과 마음에 새 힘을 불어넣을 수 있는 일을 하라. 마사지, 매니큐어, 페디큐어를 받아라. 근사한 점심이나 저녁 식사를 즐겨라.
부자가 된 기분을 느낄 수 있는, 부자가 될 자격이 있다고 느낄 수 있는 일들을 하라.
이런 일을 하는 동안 당신은 &quot;나는 풍요롭게 산다.&quot;는 메세지를 우주에 보낼 것이고, 그러면 우주는 &quot;알았다.&quot;고 답하며 자기 할 일을 부지런히 할 것이다. 그런 기회를 당신에게 더 많이 제공할 것이다.</p>
</li>
</ul>
<br>

<h3 id="11-시간이-아닌-결과에-따라-보상받아라">11. 시간이 아닌 결과에 따라 보상받아라</h3>
<blockquote>
<p>부자는 결과에 따라 보상받는 것을 선택한다.
가난한 사람은 시간에 따라 보상받는 것을 선택한다.</p>
</blockquote>
<h4 id="선언-10">선언</h4>
<p>&quot;내가 일한 결과로 보상받겠다.&quot;</p>
<h4 id="행동지침-10">행동지침</h4>
<ul>
<li><p>현재 주급이나 월급 받는 일을 하고 있다면 부분적으로라도 회사의 수익과 당신이 산출한 결과로 보상받을 수 있는 보상 체계를 만들어 사장에게 제시하라.
자기 사업을 한다면 직원이나 중요한 공급업체들이 산출한 결과와 당신 회사의 결과에 따라, 보다 융통성 있게 움직일 수 있는 보상 체계를 만들어라.
이 계획을 즉시 실천에 옮겨라.</p>
</li>
<li><p>당신이 만들어내는 결과와 가치에 상응하는 보상을 받지 못하고 있다면 당장 자기 사업을 시작하라.
처음에는 파트타임으로 시작할 수 있다. 네트워크 마케팅 회사에 합류하거나, 당신이 아는 지식을 가르치는 강사가 되거나, 당신이 일하던 회사와 독립된 사업자로 계약을 체결할 수 있다. 하지만 이번에는 시간 당이 아니라 실적과 결과로 보상받아라.</p>
</li>
</ul>
<br>

<h3 id="12-둘-다-가질-수-있다">12. 둘 다 가질 수 있다.</h3>
<blockquote>
<p>부자는 &#39;둘 다&#39; 생각한다.
가난한 사람은 &#39;하나&#39;만 생각한다.</p>
</blockquote>
<h4 id="선언-11">선언</h4>
<p>&quot;나는 &#39;둘 다&#39; 생각하겠다.&quot;</p>
<h4 id="행동지침-11">행동지침</h4>
<ul>
<li><p>&#39;둘 다&#39; 가질 수 있는 창의적인 방법을 꾸준히 생각하고 훈련하라.
선택의 갈림길에 놓일 때마다 자신에게 물어라.
&quot;둘 다 가지려면 어떻게 해야 할까?&quot;</p>
</li>
<li><p>돈이 돌고 돌아 모든 사람에게 풍요가 더해질 수 있다고 강력히 생각하라. 돈을 쓸 때마다 이런 식으로 생각할 수 있다.
&#39;이 돈이 수백 명의 손을 거쳐 그들 모두에게 가치를 창출할 것이다.&#39;</p>
</li>
<li><p>&#39;친절하고 관대하고 다정한 성품을 지닌 데다 돈까지 많은 부자&#39;의 모습을 당신이 보여주겠다고 결심하라.</p>
</li>
</ul>
<br>

<h3 id="13-진정한-부의-척도는-순자산이다">13. 진정한 부의 척도는 순자산이다.</h3>
<blockquote>
<p>부자는 순자산을 계산한다.
가난한 사람은 근로소득을 계산한다.</p>
</blockquote>
<h4 id="선언-12">선언</h4>
<p>&quot;나는 순자산을 늘리는 데 집중하겠다!&quot;</p>
<h4 id="행동지침-12">행동지침</h4>
<ul>
<li><p>순자산의 4가지 요소인 소득, 저축, 투자, 간소화를 모두 고려하라.
소득을 높이고, 저축을 늘리고, 투자를 늘리고, 생활방식의 간소화 방식을 찾아라.</p>
</li>
<li><p>순자산을 계산하고 정기적으로 추적하라.
지금 소유하고 있는 자산의 현금 가치를 모두 합하고 거기서 부채를 빼라. 3개월에 한 번씩 순자산 기록용지를 수정하고 관찰하라. 집중하는 곳이 커지는 법칙에 따라 당신이 추구하고 있는 순자산이 늘어날 것이다.</p>
</li>
<li><p>성공한 금융 전문가를 찾아라.
실적과 평판이 좋은 회사에서 일하는 사람을 찾아라. 친구와 동료들에게 유능한 전문가를 소개해 달라고 한다.</p>
</li>
</ul>
<br>

<h3 id="14-적은-돈부터-관리하고-투자하는-습관을-들여라">14. 적은 돈부터 관리하고 투자하는 습관을 들여라.</h3>
<blockquote>
<p>부자는 돈 관리를 잘한다.
가난한 사람은 돈 관리를 못한다.</p>
</blockquote>
<ul>
<li><p>&#39;경제적 자유 통장&#39;을 개설하라.
소득의 10퍼센트를 이 통장에 넣어라.
이 돈은 소비할 돈이 아니라, 비활동 소득을 위해 투자해야 하는 돈이다.</p>
</li>
<li><p>집에 &#39;경제적 자유 저금통&#39;을 만들어 매일 돈을 넣어라.
10달러도 좋고 5달러, 1달러, 1센트 동전 하나도 좋다. 주머니에 있는 잔돈도 좋다.
이것은 경제적인 자유에 관심을 기울이는 훈련이 된다. 관심을 기울이는 곳에 결과가 나타날 것이다.</p>
</li>
<li><p>목적에 따라 5개의 통장을 만들어 소득을 관리하라.
먼저 놀이 통장을 개설하거나 집에 놀이 저금통을 만들어 소득의 10퍼센트를 저축하라. 그 외에 4개의 통장을 더 만들어 각각 다음의 비율로 저금하라.</p>
<ul>
<li>놀이 통장에 10퍼센트</li>
<li>장기적 소비 통장에 10퍼센트</li>
<li>교육 통장에 10퍼센트</li>
<li>생활비 통장에 50퍼센트</li>
<li>나눔 통장에 10퍼센트</li>
</ul>
</li>
<li><p>수중에 돈이 얼마 있는지와 상관없이 당장 돈 관리를 시작하라.
내일로 미루지 마라.
1달러 밖에 없더라도 그 돈을 관리하라.
10센트를 경제적 자유 저금통에 넣고, 다른 10센트를 놀이 저금통에 넣어라.
이 행동만으로도 당신이 더 많은 돈을 받을 준비가 되었다는 메시지를 우주에 보낼 수 있다.</p>
</li>
</ul>
<br>

<h3 id="15-돈이-나를-위해-일하게-하라">15. 돈이 나를 위해 일하게 하라.</h3>
<blockquote>
<p>부자는 돈이 자신을 위해 일하도록 한다.
가난한 사람은 돈을 위해 일한다.</p>
</blockquote>
<h4 id="선언-13">선언</h4>
<p>&quot;내 돈은 날 위해 일한다. 더 많은 돈을 벌어다 준다.&quot;</p>
<h4 id="행동지침-13">행동지침</h4>
<ul>
<li><p>배워야 한다.
투자 강연회에 다니고 한 달에 적어도 한 권씩 투자 관련 책을 읽어라. 경제 신문과 경제 잡지를 탐독하라.
그들이 말하는 대로 따라하라는 게 아니라 돈의 흐름과 기회를 알아보라는 것이다. 
한 분야의 전문가가 될 만큼 연구한 다음에 그 분야에 투자를 시작하라.</p>
</li>
<li><p>활동적인 소득에서 비활동 소득으로 초점을 바꿔라.
투자나 사업적 측면에서 일하지 않고 벌어들일 수 있는 전략 3가지를 구체적으로 작성하라. 다시 조사해 보고 이 전략에 따라 행동하라.</p>
</li>
<li><p>부동산을 사려고 기다리지 말라. 부동산을 사고 나서 기다려라.</p>
</li>
</ul>
<br>

<h3 id="16-두려움에도-불구하고-행동을-시작하라">16. 두려움에도 불구하고 행동을 시작하라.</h3>
<blockquote>
<p>부자는 두려워도 행동한다.
가난한 사람은 두려워서 행동하지 않는다.</p>
</blockquote>
<h4 id="선언-14">선언</h4>
<p>&quot;두려워도 행동하겠다.&quot;
&quot;의심스러워도 행동하겠다.&quot;
&quot;불안해도 행동하겠다.&quot;
&quot;불편해도 행동하겠다.&quot;
&quot;힘들어도 행동하겠다.&quot;
&quot;하기 싫어도 행동하겠다.&quot;</p>
<h4 id="행동지침-14">행동지침</h4>
<ul>
<li><p>돈에 관해서 제일 크게 느끼는 두려움이나 근심이나 불안감을 적어보라.
거기에 도전하라.
그 두려움이나 불안이 실제 상황이 될 경우에 어떻게 할 것인지 적어라.
그 후에도 살아 있을까? 회복할 수 있을까? 대개는 &#39;그렇다&#39;는 대답이 나올 것이다.
이제 걱정은 그만하고 부자가 되어라!</p>
</li>
<li><p>편안한 지대에서 빠져나오는 연습을 하라.
스스로 불편할 법한 결정을 내려라.
사람들에게 평소에 하지 않는 말을 하거나, 승진을 요구하거나, 가게 물건 값을 올리거나, 매일 한 시간 일찍 일어나거나, 밤에 숲 속을 걸어라.
그런 훈련으로 당신은 그 무엇으로도 막을 수 없는 인물이 될 것이다.</p>
</li>
<li><p>힘 있는 사고를 하라.
자신을 관찰하고 생각이 흐르는 패턴을 살펴라.
&quot;그건 못해&quot;, &quot;하기 싫어&quot;, &quot;안 되겠어&quot;, 머릿 속의 이런 작은 목소리에 도전하라.
두려움에 묶인, 편안함에 묶인 목소리에 조종당하지 말라. 그 목소리가 성공에 필요한 일을 못 하게 할 때에도 그 일을 하라.
마음이 아니라 당신이 주인이라는 점을 보여주어라. 영향력을 상실한 그 목소리는 결국 잠잠해질 것이다.</p>
</li>
</ul>
<br>

<h3 id="17-최고의-보상을-받으려면-최고가-되어라">17. 최고의 보상을 받으려면 최고가 되어라.</h3>
<blockquote>
<p>부자는 계속 배우고 발전한다.
가난한 사람은 이미 안다고 생각한다.</p>
</blockquote>
<h4 id="선언-15">선언</h4>
<p>&quot;계속 배우고 성장하겠다.&quot;</p>
<h4 id="행동지침-15">행동지침</h4>
<ul>
<li><p>성장하기 위해 노력하라.
적어도 한 달에 한 권, 책을 읽어라. 돈, 사업, 자기 계발에 관한 영상을 보거나 세미나에 참가하라.
당신의 지식과 자신감과 성공이 날아오를 것이다!</p>
</li>
<li><p>조언해 줄 전문가를 구하는 방법도 생각해 보라.
그 사람이 당신의 진전 상태를 확인해줄 수 있다.</p>
</li>
<li><p>백만장자 마인드 세미나 등 교육 프로그램에 등록하라.
그런 프로그램을 계기로 수백만 명의 삶이 달라졌다.
당신의 삶도 달라질 것이다!</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[시리얼 터미널 접속]]></title>
            <link>https://velog.io/@juni-test/%EC%8B%9C%EB%A6%AC%EC%96%BC-%ED%84%B0%EB%AF%B8%EB%84%90-%EC%A0%91%EC%86%8D</link>
            <guid>https://velog.io/@juni-test/%EC%8B%9C%EB%A6%AC%EC%96%BC-%ED%84%B0%EB%AF%B8%EB%84%90-%EC%A0%91%EC%86%8D</guid>
            <pubDate>Mon, 10 Aug 2020 02:04:01 GMT</pubDate>
            <description><![CDATA[<h2 id="initial">INITIAL</h2>
<h3 id="필요-스킬">필요 스킬</h3>
<ul>
<li>시리얼 장치를 Open한 후 R/W</li>
<li>시리얼 장치로부터 데이터를 수신하고 그 데이터를 처리할 로직</li>
<li>키보드로부터 키 입력을 받아 시리얼 장치로 데이터를 송신하는 로직</li>
</ul>
<h3 id="시리얼-함수">시리얼 함수</h3>
<pre><code class="language-c">#define TRANSFER_SPECIAL_CHARACTER

static int fd = -1;
static struct termios oldTio, newTio;
static bool initialized = false;

#define isInitialized() (initialized);
#define set_initialized(x) (initialized = x);

static int get_serial_fd(void)
{
    return fd;
}

static int open_serial(const char * const dev)
{
    fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
    return (fd &gt;= 0);
}

static void term_serial(void)
{
    if(isInitialized() == true)    tcsetattr(fd, TCSANOW, &amp;oldTio);
    if(fd &gt;= 0)    close(fd);
}

static void init_serial(void)
{
    tcgetattr(fd, &amp;oldTio);

    newTio.c_flag = B115200 | CS8 | CLOCAL | CREAD;
    newTio.c_iflag = 0;
    newTio.c_oflag = 0;
    newTio.c_lflag = 0;
    newTio.c_cc[VTIME] = 0;
    newTio.c_cc[VMIN] = 0;

    tcflush(fd, TCIFLUSH);
    tcsetattr(fd, TCSANOW, &amp;newTio);

    set_initialized(true);
}

static void write_serial(const char* const pBuf, const int len)
{
    int cnt;
    cnt = write(fd, pBuf, len);
}

static int read_serial(char* const pBuf, const int len)
{
    int cnt, totalCnt, freeSize;
    char buf[len];

    freeSize = len;
    pBuf[0];

    while(freeSize &gt; 0){
        cnt = read(fd, buf, freeSize);
        if(cnt &lt; 0)    break;

        buf[cnt] = 0;
        strcat(pBuf, buf);
        freeSize -= cnt;
    }

    totalCnt = len - freeSize;

    return totalCnt;
}</code></pre>
<h3 id="poll-이벤트-함수">POLL 이벤트 함수</h3>
<pre><code class="language-c">static int pollState;
static struct pollfd pollEvents;
static pthread_t thread;

static void init_poll(const int fd)
{
    pollEvents.fd = fd;
    pollEvents.events = POLLIN | POLLERR;
    pollEvents.revents = 0;
}

void* start_poll_routine(void *arg)
{
    int cnt, len;
    char rBuf[MAX_BUF_SIZE] = {0,};

    while(true){
        pollState = poll(&amp;pollEvents, 1, -1);
        if(pollState &gt; 0){
            if(pollEvents.revents &amp; POLLIN){
                cnt = read_serial(rBuf, MAX_STR_LEN);
                fputs(rBuf, stdout);
                fflush(stdout);
            }

            if(pollEvents.revents &amp; POLLERR){
                eprint(&quot;ERROR on COM Line&quot;);
            }

            pollEvents.revents = 0;
        }
    }
}

static void start_poll(void)
{
    pthread_create(&amp;thread, NULL, start_poll_routine, NULL);
}

static void stop_poll(void)
{
    pthread_cancel(thread);
    pthread_join(thread, NULL);
}</code></pre>
<h3 id="키-입력-함수">키 입력 함수</h3>
<pre><code class="language-c">static incline char getch(void)
{
    static char c;
    static struct termios save, now;

    tcgetattr(0, &amp;save);
    memcpy(&amp;now, &amp;save, sizeof(struct termios));
    #ifdef TRANSFER_SPECIAL_CHARACTER
    now.c_iflag |= IGNBRK;
    now.c_iflag &amp;= ~(INLCR | ICRNL | IXON | IXOFF);
    now.c_lflag &amp;= ~(ICANON | ECHO | ECHOK | ECHOE | ECHONL | ISIG | IEXTEN);
    now.c_cc[VMIN] = 1;
    now.c_cc[VTIME] = 0;

    #else /*TRANSFER_SPECIAL_CHARACTER*/
    now.c_lflag &amp;= ~(ICANON | ECHO);
    now.c_cc[VMIN] = 1;
    now.c_cc[VTIME] = 0;
    #endif /*TRANSFER_SPECIAL_CHARACTER*/

    tcsetattr(0, TCSAFLUSH, &amp;now);
    c = getchar();
    tcsetattr(0, TCSAFLUSH, &amp;save);

    return c;
}</code></pre>
<ul>
<li>키 하나하나씩 입력될 때마다 값을 받아오려면, l_flag에서 ICANON, ECHO 비트만 Clear하면 된다.</li>
<li>하지만, Ctrl+C 같이 커널의 특정 기능을 수행하는 특수한 문자들까지 직접 키 값으로 받아오려면 추가 설정을 해줘야 한다.<ul>
<li>Ctrl+C 같이 시그널을 발생시키는 키 값을 가져오려면, ISIG 플래그를 Clear한다.</li>
<li>Ctrl+Q, S의 키 값을 가져오려면, IXON, IXOFF 플래그를 Clear한다.</li>
<li>기타 특수키 값을 가져오려면, IEXTEN 플래그를 Clear한다.</li>
</ul>
</li>
</ul>
<br>

<h2 id="절차">절차</h2>
<ol>
<li>시리얼 장치 Open</li>
<li>시리얼 설정</li>
<li>수신 데이터 처리 설정</li>
<li>수신 데이터 처리 로직 시작</li>
<li>키 입력 및 데이터 송신 시작</li>
<li>수신 데이터 처리 로직 종료</li>
<li>시리얼 장치 Term</li>
</ol>
<h3 id="시리얼-장치-open">시리얼 장치 OPEN</h3>
<pre><code class="language-c">static int open_serial(const char * const dev)
{
    fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
    return (fd &gt;= 0);
}</code></pre>
<h3 id="시리얼-설정">시리얼 설정</h3>
<pre><code class="language-c">static void init_serial(void)
{
    tcgetattr(fd, &amp;oldTio);

    newTio.c_flag = B115200 | CS8 | CLOCAL | CREAD;
    newTio.c_iflag = 0;
    newTio.c_oflag = 0;
    newTio.c_lflag = 0;
    newTio.c_cc[VTIME] = 0;
    newTio.c_cc[VMIN] = 0;

    tcflush(fd, TCIFLUSH);
    tcsetattr(fd, TCSANOW, &amp;newTio);

    set_initialized(true);
}</code></pre>
<h3 id="수신-데이터-처리-설정">수신 데이터 처리 설정</h3>
<pre><code class="language-c">static void init_poll(const int fd)
{
    pollEvents.fd = fd;
    pollEvents.events = POLLIN | POLLERR;
    pollEvents.revents = 0;
}</code></pre>
<h3 id="수신-데이터-처리-로직-시작">수신 데이터 처리 로직 시작</h3>
<pre><code class="language-c">static void start_poll(void)
{
    pthread_create(&amp;thread, NULL, start_poll_routine, NULL);
}</code></pre>
<h3 id="키-입력-및-데이터-송신-시작">키 입력 및 데이터 송신 시작</h3>
<pre><code class="language-c">static void start_keyin(void)
{
    char c;

    while(true){
        c = getchar();
        write_serial(&amp;c, 1);
    }
}</code></pre>
<h3 id="수신-데이터-처리-로직-종료">수신 데이터 처리 로직 종료</h3>
<pre><code class="language-c">static void stop_poll(void)
{
    pthread_cancel(thread);
    pthread_join(thread, NULL);
}</code></pre>
<h3 id="시리얼-termination">시리얼 TERMINATION</h3>
<pre><code class="language-c">static void term_serial(void)
{
    if(isInitialized() == true)    tcsetattr(fd, TCSANOW, &amp;oldTio);
    if(fd &gt;= 0)    close(fd);
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>