* copy vendor drop to trunk
[lab.git] / Dev / utvpn / utvpn-unix-v101-7101-public / src / Mayaqua / Unix.c
1 // SoftEther UT-VPN SourceCode\r
2 // \r
3 // Copyright (C) 2004-2010 SoftEther Corporation.\r
4 // Copyright (C) 2004-2010 University of Tsukuba, Japan.\r
5 // Copyright (C) 2003-2010 Daiyuu Nobori.\r
6 // All Rights Reserved.\r
7 // \r
8 // http://utvpn.tsukuba.ac.jp/\r
9 // \r
10 // This program is free software; you can redistribute it and/or\r
11 // modify it under the terms of the GNU General Public License\r
12 // version 2 as published by the Free Software Foundation.\r
13 // \r
14 // This program is distributed in the hope that it will be useful,\r
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
17 // GNU General Public License for more details.\r
18 // \r
19 // You should have received a copy of the GNU General Public License version 2\r
20 // along with this program; if not, write to the Free Software\r
21 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
22 // \r
23 // このファイルは GPL バージョン 2 ライセンスで公開されています。\r
24 // 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布\r
25 // することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示\r
26 // を除去することはできません。改変した著作物を配布する場合は、改変実施者の\r
27 // 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。\r
28 // \r
29 // この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の\r
30 // ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )\r
31 // および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって\r
32 // ホストされています。\r
33 // 本プログラムの配布者は、本プログラムを、業としての利用以外のため、\r
34 // および、試験または研究のために利用が行われることを想定して配布\r
35 // しています。\r
36 // SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に\r
37 // あります。\r
38 // 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード\r
39 // の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して\r
40 // いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して\r
41 // ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース\r
42 // に組み込みさせていただきます。\r
43 // \r
44 // GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する\r
45 // 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。\r
46 // \r
47 // 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社\r
48 // (SoftEther Corporation) およびその他の著作権保持者が保有しています。\r
49 // ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの\r
50 // 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意\r
51 // ください。\r
52 // \r
53 // お願い: どのような通信ソフトウェアにも通常は必ず未発見の\r
54 // セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、\r
55 // UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの\r
56 // 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社\r
57 // および脆弱性情報の届出を受け付ける公的機関まで通報いただき、\r
58 // 公益保護にご協力いただきますようお願い申し上げます。\r
59 // \r
60 // ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を\r
61 // 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客\r
62 // を保護するための努力を行います。\r
63 // \r
64 // ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/\r
65 // 日本国内の脆弱性情報届出受付公的機関:\r
66 //         独立行政法人 情報処理推進機構\r
67 //         http://www.ipa.go.jp/security/vuln/report/\r
68 // \r
69 // 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。\r
70 // 連絡先: http://www.softether.co.jp/jp/contact/\r
71 \r
72 // -----------------------------------------------\r
73 // [ChangeLog]\r
74 // 2010.05.20\r
75 //  新規リリース by SoftEther\r
76 // -----------------------------------------------\r
77 \r
78 // Unix.c\r
79 // UNIX 依存コード\r
80 \r
81 #ifdef  UNIX\r
82 \r
83 #include <stdio.h>\r
84 #include <stdlib.h>\r
85 #include <string.h>\r
86 #include <wchar.h>\r
87 #include <stdarg.h>\r
88 #include <time.h>\r
89 #include <errno.h>\r
90 #include <Mayaqua/Mayaqua.h>\r
91 \r
92 // MacOS X 用の struct statfs\r
93 #ifdef  UNIX_MACOS\r
94 typedef struct fsid { int32_t val[2]; } fsid_t;\r
95 struct statfs {\r
96         short   f_otype;                /* TEMPORARY SHADOW COPY OF f_type */\r
97         short   f_oflags;               /* TEMPORARY SHADOW COPY OF f_flags */\r
98         long    f_bsize;                /* fundamental file system block size */\r
99         long    f_iosize;               /* optimal transfer block size */\r
100         long    f_blocks;               /* total data blocks in file system */\r
101         long    f_bfree;                /* free blocks in fs */\r
102         long    f_bavail;               /* free blocks avail to non-superuser */\r
103         long    f_files;                /* total file nodes in file system */\r
104         long    f_ffree;                /* free file nodes in fs */\r
105         fsid_t  f_fsid;                 /* file system id */\r
106         uid_t   f_owner;                /* user that mounted the filesystem */\r
107         short   f_reserved1;    /* spare for later */\r
108         short   f_type;                 /* type of filesystem */\r
109     long        f_flags;                /* copy of mount exported flags */\r
110         long    f_reserved2[2]; /* reserved for future use */\r
111         char    f_fstypename[15]; /* fs type name */\r
112         char    f_mntonname[90];  /* directory on which mounted */\r
113         char    f_mntfromname[90];/* mounted filesystem */\r
114 };\r
115 #endif  // UNIX_MACOS\r
116 \r
117 // Solaris 用の scandir() 関数\r
118 #ifdef  UNIX_SOLARIS\r
119 #define scandir local_scandir\r
120 #define alphasort local_alphasort\r
121 \r
122 /*******************************************\r
123  * Copyright Free の互換ルーチン (local_scandir)\r
124  * コピー元: http://www005.upp.so-net.ne.jp/yoga/compile.html\r
125  *******************************************/\r
126 \r
127 int local_scandir(const char *dir, struct dirent ***namelist,\r
128             int (*select)(const struct dirent *),\r
129             int (*compar)(const struct dirent **, const struct dirent **))\r
130 {\r
131   DIR *d;\r
132   struct dirent *entry;\r
133   register int i=0;\r
134   size_t entrysize;\r
135 \r
136   if ((d=opendir(dir)) == NULL)\r
137      return(-1);\r
138 \r
139   *namelist=NULL;\r
140   while ((entry=readdir(d)) != NULL)\r
141   {\r
142     if (select == NULL || (select != NULL && (*select)(entry)))\r
143     {\r
144       *namelist=(struct dirent **)realloc((void *)(*namelist),\r
145                  (size_t)((i+1)*sizeof(struct dirent *)));\r
146         if (*namelist == NULL) return(-1);\r
147         entrysize=sizeof(struct dirent)-sizeof(entry->d_name)+strlen(entry->d_name)+1;\r
148         (*namelist)[i]=(struct dirent *)malloc(entrysize);\r
149         if ((*namelist)[i] == NULL) return(-1);\r
150         memcpy((*namelist)[i], entry, entrysize);\r
151         i++;\r
152     }\r
153   }\r
154   if (closedir(d)) return(-1);\r
155   if (i == 0) return(-1);\r
156   if (compar != NULL)\r
157     qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), compar);\r
158     \r
159   return(i);\r
160 }\r
161 \r
162 int local_alphasort(const struct dirent **a, const struct dirent **b)\r
163 {\r
164   return(strcmp((*a)->d_name, (*b)->d_name));\r
165 }\r
166 \r
167 \r
168 #endif  // UNIX_SOLARIS\r
169 \r
170 // UNIX 用スレッドデータ\r
171 typedef struct UNIXTHREAD\r
172 {\r
173         pthread_t thread;\r
174         bool finished;\r
175 } UNIXTHREAD;\r
176 \r
177 // UNIX 用スレッド起動情報\r
178 typedef struct UNIXTHREADSTARTUPINFO\r
179 {\r
180         THREAD_PROC *thread_proc;\r
181         void *param;\r
182         THREAD *thread;\r
183 } UNIXTHREADSTARTUPINFO;\r
184 \r
185 // UNIX 用スレッド関数プロトタイプ\r
186 void *UnixDefaultThreadProc(void *param);\r
187 \r
188 // 現在のプロセス ID\r
189 static pid_t current_process_id = 0;\r
190 \r
191 // UNIX 用ファイル I/O データ\r
192 typedef struct UNIXIO\r
193 {\r
194         int fd;\r
195         bool write_mode;\r
196 } UNIXIO;\r
197 \r
198 // UNIX 用ロックファイルデータ\r
199 typedef struct UNIXLOCKFILE\r
200 {\r
201         char FileName[MAX_SIZE];\r
202         int fd;\r
203 } UNIXLOCKFILE;\r
204 \r
205 // UNIX 用イベントデータ\r
206 typedef struct UNIXEVENT\r
207 {\r
208         pthread_mutex_t mutex;\r
209         pthread_cond_t cond;\r
210         bool signal;\r
211 } UNIXEVENT;\r
212 \r
213 static pthread_mutex_t get_time_lock;\r
214 static pthread_mutex_t malloc_lock;\r
215 static bool high_process = false;\r
216 \r
217 static bool unix_svc_terminate = false;\r
218 static int solaris_sleep_p1 = -1, solaris_sleep_p2 = -1;\r
219 \r
220 // ディスパッチテーブルの作成\r
221 OS_DISPATCH_TABLE *UnixGetDispatchTable()\r
222 {\r
223         static OS_DISPATCH_TABLE t =\r
224         {\r
225                 UnixInit,\r
226                 UnixFree,\r
227                 UnixMemoryAlloc,\r
228                 UnixMemoryReAlloc,\r
229                 UnixMemoryFree,\r
230                 UnixGetTick,\r
231                 UnixGetSystemTime,\r
232                 UnixInc32,\r
233                 UnixDec32,\r
234                 UnixSleep,\r
235                 UnixNewLock,\r
236                 UnixLock,\r
237                 UnixUnlock,\r
238                 UnixDeleteLock,\r
239                 UnixInitEvent,\r
240                 UnixSetEvent,\r
241                 UnixResetEvent,\r
242                 UnixWaitEvent,\r
243                 UnixFreeEvent,\r
244                 UnixWaitThread,\r
245                 UnixFreeThread,\r
246                 UnixInitThread,\r
247                 UnixThreadId,\r
248                 UnixFileOpen,\r
249                 UnixFileOpenW,\r
250                 UnixFileCreate,\r
251                 UnixFileCreateW,\r
252                 UnixFileWrite,\r
253                 UnixFileRead,\r
254                 UnixFileClose,\r
255                 UnixFileFlush,\r
256                 UnixFileSize,\r
257                 UnixFileSeek,\r
258                 UnixFileDelete,\r
259                 UnixFileDeleteW,\r
260                 UnixMakeDir,\r
261                 UnixMakeDirW,\r
262                 UnixDeleteDir,\r
263                 UnixDeleteDirW,\r
264                 UnixGetCallStack,\r
265                 UnixGetCallStackSymbolInfo,\r
266                 UnixFileRename,\r
267                 UnixFileRenameW,\r
268                 UnixRun,\r
269                 UnixRunW,\r
270                 UnixIsSupportedOs,\r
271                 UnixGetOsInfo,\r
272                 UnixAlert,\r
273                 UnixAlertW,\r
274                 UnixGetProductId,\r
275                 UnixSetHighPriority,\r
276                 UnixRestorePriority,\r
277                 UnixNewSingleInstance,\r
278                 UnixFreeSingleInstance,\r
279                 UnixGetMemInfo,\r
280                 UnixYield,\r
281         };\r
282 \r
283         return &t;\r
284 }\r
285 \r
286 // Solaris 用 Sleep の初期化\r
287 void UnixInitSolarisSleep()\r
288 {\r
289         char tmp[MAX_SIZE];\r
290 \r
291         UnixNewPipe(&solaris_sleep_p1, &solaris_sleep_p2);\r
292         read(solaris_sleep_p1, tmp, sizeof(tmp));\r
293 }\r
294 \r
295 // Solaris 用 Sleep の解放\r
296 void UnixFreeSolarisSleep()\r
297 {\r
298         UnixDeletePipe(solaris_sleep_p1, solaris_sleep_p2);\r
299         solaris_sleep_p1 = -1;\r
300         solaris_sleep_p2 = -1;\r
301 }\r
302 \r
303 // Solaris 用 Sleep\r
304 void UnixSolarisSleep(UINT msec)\r
305 {\r
306         struct pollfd p;\r
307 \r
308         memset(&p, 0, sizeof(p));\r
309         p.fd = solaris_sleep_p1;\r
310         p.events = POLLIN;\r
311 \r
312         poll(&p, 1, msec == INFINITE ? -1 : (int)msec);\r
313 }\r
314 \r
315 // ディスクの空き容量を取得する\r
316 bool UnixGetDiskFreeW(wchar_t *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size)\r
317 {\r
318         char *path_a = CopyUniToStr(path);\r
319         bool ret;\r
320 \r
321         ret = UnixGetDiskFree(path_a, free_size, used_size, total_size);\r
322 \r
323         Free(path_a);\r
324 \r
325         return ret;\r
326 }\r
327 bool UnixGetDiskFree(char *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size)\r
328 {\r
329         char tmp[MAX_PATH];\r
330         bool ret = false;\r
331         // 引数チェック\r
332         if (path == NULL)\r
333         {\r
334                 return false;\r
335         }\r
336 \r
337         NormalizePath(tmp, sizeof(tmp), path);\r
338 \r
339         while ((ret = UnixGetDiskFreeMain(tmp, free_size, used_size, total_size)) == false)\r
340         {\r
341                 if (StrCmpi(tmp, "/") == 0)\r
342                 {\r
343                         break;\r
344                 }\r
345 \r
346                 GetDirNameFromFilePath(tmp, sizeof(tmp), tmp);\r
347         }\r
348 \r
349         return ret;\r
350 }\r
351 bool UnixGetDiskFreeMain(char *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size)\r
352 {\r
353 #ifndef USE_STATVFS\r
354         struct statfs st;\r
355         char tmp[MAX_PATH];\r
356         UINT64 v1 = 0, v2 = 0;\r
357         bool ret = false;\r
358         // 引数チェック\r
359         if (path == NULL)\r
360         {\r
361                 return false;\r
362         }\r
363 \r
364         NormalizePath(tmp, sizeof(tmp), path);\r
365 \r
366         Zero(&st, sizeof(st));\r
367         if (statfs(tmp, &st) == 0)\r
368         {\r
369                 v1 = (UINT64)st.f_bsize * (UINT64)st.f_bavail;\r
370                 v2 = (UINT64)st.f_bsize * (UINT64)st.f_blocks;\r
371                 ret = true;\r
372         }\r
373 \r
374         if (free_size != NULL)\r
375         {\r
376                 *free_size = v1;\r
377         }\r
378 \r
379         if (total_size != NULL)\r
380         {\r
381                 *total_size = v2;\r
382         }\r
383 \r
384         if (used_size != NULL)\r
385         {\r
386                 *used_size = v2 - v1;\r
387         }\r
388 \r
389         return ret;\r
390 #else   // USE_STATVFS\r
391         struct statvfs st;\r
392         char tmp[MAX_PATH];\r
393         UINT64 v1 = 0, v2 = 0;\r
394         bool ret = false;\r
395         // 引数チェック\r
396         if (path == NULL)\r
397         {\r
398                 return false;\r
399         }\r
400 \r
401         NormalizePath(tmp, sizeof(tmp), path);\r
402 \r
403         Zero(&st, sizeof(st));\r
404 \r
405         if (statvfs(tmp, &st) == 0)\r
406         {\r
407                 v1 = (UINT64)st.f_bsize * (UINT64)st.f_bavail;\r
408                 v2 = (UINT64)st.f_bsize * (UINT64)st.f_blocks;\r
409                 ret = true;\r
410         }\r
411 \r
412         if (free_size != NULL)\r
413         {\r
414                 *free_size = v1;\r
415         }\r
416 \r
417         if (total_size != NULL)\r
418         {\r
419                 *total_size = v2;\r
420         }\r
421 \r
422         if (used_size != NULL)\r
423         {\r
424                 *used_size = v2 - v1;\r
425         }\r
426 \r
427         return ret;\r
428 #endif  // USE_STATVFS\r
429 }\r
430 \r
431 // ディレクトリ列挙\r
432 DIRLIST *UnixEnumDirEx(char *dirname, COMPARE *compare)\r
433 {\r
434         char tmp[MAX_PATH];\r
435         DIRLIST *d;\r
436         int n;\r
437         struct dirent **e;\r
438         LIST *o;\r
439         // 引数チェック\r
440         if (dirname == NULL)\r
441         {\r
442                 return NULL;\r
443         }\r
444 \r
445         o = NewListFast(compare);\r
446 \r
447         NormalizePath(tmp, sizeof(tmp), dirname);\r
448 \r
449         if (StrLen(tmp) >= 1 && tmp[StrLen(tmp) - 1] != '/')\r
450         {\r
451                 StrCat(tmp, sizeof(tmp), "/");\r
452         }\r
453 \r
454         e = NULL;\r
455         n = scandir(tmp, &e, 0, alphasort);\r
456 \r
457         if (StrLen(tmp) >= 1 && tmp[StrLen(tmp) - 1] == '/')\r
458         {\r
459                 tmp[StrLen(tmp) - 1] = 0;\r
460         }\r
461 \r
462         if (n >= 0 && e != NULL)\r
463         {\r
464                 UINT i;\r
465 \r
466                 for (i = 0;i < (UINT)n;i++)\r
467                 {\r
468                         char *filename = e[i]->d_name;\r
469 \r
470                         if (filename != NULL)\r
471                         {\r
472                                 if (StrCmpi(filename, "..") != 0 && StrCmpi(filename, ".") != 0)\r
473                                 {\r
474                                         char fullpath[MAX_PATH];\r
475                                         struct stat st;\r
476                                         Format(fullpath, sizeof(fullpath), "%s/%s", tmp, filename);\r
477 \r
478                                         Zero(&st, sizeof(st));\r
479 \r
480                                         if (stat(fullpath, &st) == 0)\r
481                                         {\r
482                                                 DIRENT *f = ZeroMalloc(sizeof(DIRENT));\r
483                                                 SYSTEMTIME t;\r
484 \r
485                                                 f->Folder = S_ISDIR(st.st_mode) ? true : false;\r
486                                                 f->FileName = CopyStr(filename);\r
487                                                 f->FileNameW = CopyUtfToUni(f->FileName);\r
488 \r
489                                                 Zero(&t, sizeof(t));\r
490                                                 TimeToSystem(&t, st.st_ctime);\r
491                                                 f->CreateDate = LocalToSystem64(SystemToUINT64(&t));\r
492 \r
493                                                 Zero(&t, sizeof(t));\r
494                                                 TimeToSystem(&t, st.st_mtime);\r
495                                                 f->UpdateDate = LocalToSystem64(SystemToUINT64(&t));\r
496 \r
497                                                 if (f->Folder == false)\r
498                                                 {\r
499                                                         f->FileSize = st.st_size;\r
500                                                 }\r
501 \r
502                                                 Add(o, f);\r
503                                         }\r
504                                 }\r
505                         }\r
506 \r
507                         free(e[i]);\r
508                 }\r
509 \r
510                 free(e);\r
511         }\r
512 \r
513         Sort(o);\r
514 \r
515         d = ZeroMalloc(sizeof(DIRLIST));\r
516         d->NumFiles = LIST_NUM(o);\r
517         d->File = ToArray(o);\r
518 \r
519         ReleaseList(o);\r
520 \r
521         return d;\r
522 }\r
523 DIRLIST *UnixEnumDirExW(wchar_t *dirname, COMPARE *compare)\r
524 {\r
525         char *dirname_a = CopyUniToUtf(dirname);\r
526         DIRLIST *ret;\r
527 \r
528         ret = UnixEnumDirEx(dirname_a, compare);\r
529 \r
530         Free(dirname_a);\r
531 \r
532         return ret;\r
533 }\r
534 \r
535 // 指定したファイルの実行権限をチェックする\r
536 bool UnixCheckExecAccess(char *name)\r
537 {\r
538         // 引数チェック\r
539         if (name == NULL)\r
540         {\r
541                 return false;\r
542         }\r
543 \r
544         if (access(name, X_OK) == 0)\r
545         {\r
546                 return true;\r
547         }\r
548 \r
549         return false;\r
550 }\r
551 bool UnixCheckExecAccessW(wchar_t *name)\r
552 {\r
553         char *name_a;\r
554         bool ret;\r
555         // 引数チェック\r
556         if (name == NULL)\r
557         {\r
558                 return false;\r
559         }\r
560 \r
561         name_a = CopyUniToUtf(name);\r
562 \r
563         ret = UnixCheckExecAccess(name_a);\r
564 \r
565         Free(name_a);\r
566 \r
567         return ret;\r
568 }\r
569 \r
570 // スレッドの優先順位を最高にする\r
571 void UnixSetThreadPriorityRealtime()\r
572 {\r
573         struct sched_param p;\r
574         Zero(&p, sizeof(p));\r
575         p.sched_priority = 255;\r
576         pthread_setschedparam(pthread_self(), SCHED_RR, &p);\r
577 }\r
578 \r
579 // スレッドの優先順位を低くする\r
580 void UnixSetThreadPriorityLow()\r
581 {\r
582         struct sched_param p;\r
583         Zero(&p, sizeof(p));\r
584         p.sched_priority = 32;\r
585         pthread_setschedparam(pthread_self(), SCHED_OTHER, &p);\r
586 }\r
587 \r
588 // スレッドの優先順位を高くする\r
589 void UnixSetThreadPriorityHigh()\r
590 {\r
591         struct sched_param p;\r
592         Zero(&p, sizeof(p));\r
593         p.sched_priority = 127;\r
594         pthread_setschedparam(pthread_self(), SCHED_RR, &p);\r
595 }\r
596 \r
597 // スレッドの優先順位をアイドルにする\r
598 void UnixSetThreadPriorityIdle()\r
599 {\r
600         struct sched_param p;\r
601         Zero(&p, sizeof(p));\r
602         p.sched_priority = 1;\r
603         pthread_setschedparam(pthread_self(), SCHED_OTHER, &p);\r
604 }\r
605 \r
606 // スレッドの優先順位を標準に戻す\r
607 void UnixRestoreThreadPriority()\r
608 {\r
609         struct sched_param p;\r
610         Zero(&p, sizeof(p));\r
611         p.sched_priority = 64;\r
612         pthread_setschedparam(pthread_self(), SCHED_OTHER, &p);\r
613 }\r
614 \r
615 // 現在のディレクトリの取得\r
616 void UnixGetCurrentDir(char *dir, UINT size)\r
617 {\r
618         // 引数チェック\r
619         if (dir == NULL)\r
620         {\r
621                 return;\r
622         }\r
623 \r
624         getcwd(dir, size);\r
625 }\r
626 void UnixGetCurrentDirW(wchar_t *dir, UINT size)\r
627 {\r
628         char dir_a[MAX_PATH];\r
629 \r
630         UnixGetCurrentDir(dir_a, sizeof(dir_a));\r
631 \r
632         UtfToUni(dir, size, dir_a);\r
633 }\r
634 \r
635 // イールド\r
636 void UnixYield()\r
637 {\r
638 #ifdef UNIX_SOLARIS\r
639         UnixSolarisSleep(1);\r
640 #else\r
641         sleep(1);\r
642 #endif\r
643 }\r
644 \r
645 // メモリ情報の取得\r
646 void UnixGetMemInfo(MEMINFO *info)\r
647 {\r
648         // 引数チェック\r
649         if (info == NULL)\r
650         {\r
651                 return;\r
652         }\r
653 \r
654         // 知らん!!\r
655         Zero(info, sizeof(MEMINFO));\r
656 }\r
657 \r
658 // シングルインスタンスの解放\r
659 void UnixFreeSingleInstance(void *data)\r
660 {\r
661         UNIXLOCKFILE *o;\r
662         struct flock lock;\r
663         // 引数チェック\r
664         if (data == NULL)\r
665         {\r
666                 return;\r
667         }\r
668 \r
669         o = (UNIXLOCKFILE *)data;\r
670 \r
671         Zero(&lock, sizeof(lock));\r
672         lock.l_type = F_UNLCK;\r
673         lock.l_whence = SEEK_SET;\r
674 \r
675         fcntl(o->fd, F_SETLK, &lock);\r
676         close(o->fd);\r
677 \r
678         remove(o->FileName);\r
679 \r
680         Free(data);\r
681 }\r
682 \r
683 // シングルインスタンスの作成\r
684 void *UnixNewSingleInstance(char *instance_name)\r
685 {\r
686         UNIXLOCKFILE *ret;\r
687         char tmp[MAX_SIZE];\r
688         char name[MAX_SIZE];\r
689         char dir[MAX_PATH];\r
690         int fd;\r
691         struct flock lock;\r
692         // 引数チェック\r
693         if (instance_name == NULL)\r
694         {\r
695                 GetExeName(tmp, sizeof(tmp));\r
696                 HashInstanceName(tmp, sizeof(tmp), tmp);\r
697         }\r
698         else\r
699         {\r
700                 StrCpy(tmp, sizeof(tmp), instance_name);\r
701         }\r
702 \r
703         GetExeDir(dir, sizeof(dir));\r
704 \r
705         // ファイル名の生成\r
706         Format(name, sizeof(name), "%s/.%s", dir, tmp);\r
707 \r
708         fd = open(name, O_WRONLY);\r
709         if (fd == -1)\r
710         {\r
711                 fd = creat(name, 0600);\r
712         }\r
713         if (fd == -1)\r
714         {\r
715                 Format(tmp, sizeof(tmp), "Unable to create %s.", name);\r
716                 Alert(tmp, NULL);\r
717                 exit(0);\r
718                 return NULL;\r
719         }\r
720 \r
721         Zero(&lock, sizeof(lock));\r
722         lock.l_type = F_WRLCK;\r
723         lock.l_whence = SEEK_SET;\r
724 \r
725         if (fcntl(fd, F_SETLK, &lock) == -1)\r
726         {\r
727                 return NULL;\r
728         }\r
729         else\r
730         {\r
731                 ret = ZeroMalloc(sizeof(UNIXLOCKFILE));\r
732                 ret->fd = fd;\r
733                 StrCpy(ret->FileName, sizeof(ret->FileName), name);\r
734                 return (void *)ret;\r
735         }\r
736 }\r
737 \r
738 // プロセスの優先順位を上げる\r
739 void UnixSetHighPriority()\r
740 {\r
741         if (high_process == false)\r
742         {\r
743                 UINT pid = getpid();\r
744                 UINT pgid = getpgid(pid);\r
745 \r
746                 high_process = true;\r
747                 nice(-20);\r
748 \r
749                 setpriority(PRIO_PROCESS, pid, -20);\r
750                 setpriority(PRIO_PGRP, pgid, -20);\r
751         }\r
752 }\r
753 \r
754 // プロセスの優先順位を戻す\r
755 void UnixRestorePriority()\r
756 {\r
757         if (high_process != false)\r
758         {\r
759                 high_process = false;\r
760                 nice(20);\r
761         }\r
762 }\r
763 \r
764 // プロダクト ID を取得する\r
765 char *UnixGetProductId()\r
766 {\r
767         return CopyStr("--");\r
768 }\r
769 \r
770 // アラートを表示する\r
771 void UnixAlertW(wchar_t *msg, wchar_t *caption)\r
772 {\r
773         char *msg8 = CopyUniToUtf(msg);\r
774         char *caption8 = CopyUniToUtf(caption);\r
775 \r
776         UnixAlert(msg8, caption8);\r
777 \r
778         Free(msg8);\r
779         Free(caption8);\r
780 }\r
781 void UnixAlert(char *msg, char *caption)\r
782 {\r
783         char *tag =\r
784                 "-- Alert: %s --\n%s\n";\r
785         // 引数チェック\r
786         if (msg == NULL)\r
787         {\r
788                 msg = "Alert";\r
789         }\r
790         if (caption == NULL)\r
791         {\r
792                 caption = "SoftEther UT-VPN Kernel";\r
793         }\r
794 \r
795         printf(tag, caption, msg);\r
796 }\r
797 \r
798 // 現在の OS の情報を取得する\r
799 void UnixGetOsInfo(OS_INFO *info)\r
800 {\r
801         // 引数チェック\r
802         if (info == NULL)\r
803         {\r
804                 return;\r
805         }\r
806 \r
807         Zero(info, sizeof(OS_INFO));\r
808         info->OsType = OSTYPE_UNIX_UNKNOWN;\r
809 \r
810 #ifdef  UNIX_SOLARIS\r
811         info->OsType = OSTYPE_SOLARIS;\r
812 #endif  // UNIX_SOLARIS\r
813 \r
814 #ifdef  UNIX_CYGWIN\r
815         info->OsType = OSTYPE_CYGWIN;\r
816 #endif  // UNIX_CYGWIN\r
817 \r
818 #ifdef  UNIX_MACOS\r
819         info->OsType = OSTYPE_MACOS_X;\r
820 #endif  // UNIX_MACOS\r
821 \r
822 #ifdef  UNIX_BSD\r
823         info->OsType = OSTYPE_BSD;\r
824 #endif  // UNIX_BSD\r
825 \r
826 #ifdef  UNIX_LINUX\r
827         info->OsType = OSTYPE_LINUX;\r
828 #endif  // UNIX_LINUX\r
829 \r
830         info->OsServicePack = 0;\r
831 \r
832         if (info->OsType != OSTYPE_LINUX)\r
833         {\r
834                 info->OsSystemName = CopyStr("UNIX");\r
835                 info->OsProductName = CopyStr("UNIX");\r
836         }\r
837         else\r
838         {\r
839                 info->OsSystemName = CopyStr("Linux");\r
840                 info->OsProductName = CopyStr("Linux");\r
841         }\r
842 \r
843         if (info->OsType == OSTYPE_LINUX)\r
844         {\r
845                 // Linux の場合 ディストリビューション名を取得する\r
846                 BUF *b;\r
847                 b = ReadDump("/etc/redhat-release");\r
848                 if (b != NULL)\r
849                 {\r
850                         info->OsVersion = CfgReadNextLine(b);\r
851                         info->OsVendorName = CopyStr("Red Hat, Inc.");\r
852                         FreeBuf(b);\r
853                 }\r
854                 else\r
855                 {\r
856                         b = ReadDump("/etc/turbolinux-release");\r
857                         if (b != NULL)\r
858                         {\r
859                                 info->OsVersion = CfgReadNextLine(b);\r
860                                 info->OsVendorName = CopyStr("Turbolinux, Inc.");\r
861                                 FreeBuf(b);\r
862                         }\r
863                         else\r
864                         {\r
865                                 info->OsVersion = CopyStr("Unknown Liunx Version");\r
866                                 info->OsVendorName = CopyStr("Unknown Vendor");\r
867                         }\r
868                 }\r
869 \r
870                 info->KernelName = CopyStr("Linux Kernel");\r
871 \r
872                 b = ReadDump("/proc/sys/kernel/osrelease");\r
873                 if (b != NULL)\r
874                 {\r
875                         info->KernelVersion = CfgReadNextLine(b);\r
876                         FreeBuf(b);\r
877                 }\r
878                 else\r
879                 {\r
880                         info->KernelVersion = CopyStr("Unknown Version");\r
881                 }\r
882         }\r
883         else\r
884         {\r
885                 // その他の場合\r
886                 info->OsProductName = CopyStr(OsTypeToStr(info->OsType));\r
887                 info->OsVersion = CopyStr("Unknown Version");\r
888                 info->KernelName = CopyStr(OsTypeToStr(info->OsType));\r
889                 info->KernelVersion = CopyStr("Unknown Version");\r
890         }\r
891 }\r
892 \r
893 // 現在の OS が SoftEther UT-VPN Kernel によってサポートされているかどうか調べる\r
894 bool UnixIsSupportedOs()\r
895 {\r
896         // すべての起動可能な UNIX OS をサポートしている\r
897         return true;\r
898 }\r
899 \r
900 // 指定したコマンドを実行する\r
901 bool UnixRunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait)\r
902 {\r
903         char *filename8 = CopyUniToUtf(filename);\r
904         char *arg8 = CopyUniToUtf(arg);\r
905         bool ret = UnixRun(filename8, arg8, hide, wait);\r
906 \r
907         Free(filename8);\r
908         Free(arg8);\r
909 \r
910         return ret;\r
911 }\r
912 bool UnixRun(char *filename, char *arg, bool hide, bool wait)\r
913 {\r
914         TOKEN_LIST *t;\r
915         UINT ret;\r
916         // 引数チェック\r
917         if (filename == NULL)\r
918         {\r
919                 return false;\r
920         }\r
921         if (arg == NULL)\r
922         {\r
923                 arg = "";\r
924         }\r
925 \r
926         // 子プロセス作成\r
927         ret = fork();\r
928         if (ret == -1)\r
929         {\r
930                 // 子プロセス作成失敗\r
931                 return false;\r
932         }\r
933 \r
934         if (ret == 0)\r
935         {\r
936                 Print("", filename, arg);\r
937                 // 子プロセス\r
938                 if (hide)\r
939                 {\r
940                         // 標準入出力を閉じる\r
941                         UnixCloseIO();\r
942                 }\r
943 \r
944                 t = ParseToken(arg, " ");\r
945                 if (t == NULL)\r
946                 {\r
947                         AbortExit();\r
948                 }\r
949                 else\r
950                 {\r
951                         char **args;\r
952                         UINT num_args;\r
953                         UINT i;\r
954                         num_args = t->NumTokens + 2;\r
955                         args = ZeroMalloc(sizeof(char *) * num_args);\r
956                         args[0] = filename;\r
957                         for (i = 1;i < num_args - 1;i++)\r
958                         {\r
959                                 args[i] = t->Token[i - 1];\r
960                         }\r
961                         execvp(filename, args);\r
962                         AbortExit();\r
963                 }\r
964         }\r
965         else\r
966         {\r
967                 // 親プロセス\r
968                 pid_t pid = (pid_t)ret;\r
969 \r
970                 if (wait)\r
971                 {\r
972                         int status = 0;\r
973                         // 子プロセスの終了を待機する\r
974                         if (waitpid(pid, &status, 0) == -1)\r
975                         {\r
976                                 return false;\r
977                         }\r
978 \r
979                         if (WEXITSTATUS(status) == 0)\r
980                         {\r
981                                 return true;\r
982                         }\r
983                         else\r
984                         {\r
985                                 return false;\r
986                         }\r
987                 }\r
988 \r
989                 return true;\r
990         }\r
991 }\r
992 \r
993 // デーモンの初期化\r
994 void UnixDaemon(bool debug_mode)\r
995 {\r
996         UINT ret;\r
997 \r
998         if (debug_mode)\r
999         {\r
1000                 // デバッグモード\r
1001                 signal(SIGHUP, SIG_IGN);\r
1002                 return;\r
1003         }\r
1004 \r
1005         ret = fork();\r
1006 \r
1007         if (ret == -1)\r
1008         {\r
1009                 // エラー\r
1010                 return;\r
1011         }\r
1012         else if (ret == 0)\r
1013         {\r
1014                 // 子プロセス用に新しいセッションを作成する\r
1015                 setsid();\r
1016 \r
1017                 // 標準入出力をクローズする\r
1018                 UnixCloseIO();\r
1019 \r
1020                 // 不要なシグナルを停止する\r
1021                 signal(SIGHUP, SIG_IGN);\r
1022         }\r
1023         else\r
1024         {\r
1025                 // 親プロセスを終了する\r
1026                 exit(0);\r
1027         }\r
1028 }\r
1029 \r
1030 // 標準入出力をクローズする\r
1031 void UnixCloseIO()\r
1032 {\r
1033         static bool close_io_first = false;\r
1034 \r
1035         // 1 回しか実行できない\r
1036         if (close_io_first)\r
1037         {\r
1038                 return;\r
1039         }\r
1040         else\r
1041         {\r
1042                 close(0);\r
1043                 close(1);\r
1044                 close(2);\r
1045                 open("/dev/null", O_RDWR);\r
1046                 dup2(0, 1);\r
1047                 dup2(0, 2);\r
1048                 close_io_first = false;\r
1049         }\r
1050 }\r
1051 \r
1052 // ファイル名を変更する\r
1053 bool UnixFileRenameW(wchar_t *old_name, wchar_t *new_name)\r
1054 {\r
1055         char *old_name8 = CopyUniToUtf(old_name);\r
1056         char *new_name8 = CopyUniToUtf(new_name);\r
1057         bool ret = UnixFileRename(old_name8, new_name8);\r
1058 \r
1059         Free(old_name8);\r
1060         Free(new_name8);\r
1061 \r
1062         return ret;\r
1063 }\r
1064 bool UnixFileRename(char *old_name, char *new_name)\r
1065 {\r
1066         // 引数チェック\r
1067         if (old_name == NULL || new_name == NULL)\r
1068         {\r
1069                 return false;\r
1070         }\r
1071 \r
1072         if (rename(old_name, new_name) != 0)\r
1073         {\r
1074                 return false;\r
1075         }\r
1076 \r
1077         return true;\r
1078 }\r
1079 \r
1080 // コールスタックを取得する\r
1081 CALLSTACK_DATA *UnixGetCallStack()\r
1082 {\r
1083         // Win32 以外ではサポートされていない\r
1084         return NULL;\r
1085 }\r
1086 \r
1087 // コールスタックからシンボル情報を取得\r
1088 bool UnixGetCallStackSymbolInfo(CALLSTACK_DATA *s)\r
1089 {\r
1090         // Win32 以外ではサポートされていない\r
1091         return false;\r
1092 }\r
1093 \r
1094 // ディレクトリを削除する\r
1095 bool UnixDeleteDirW(wchar_t *name)\r
1096 {\r
1097         char *name8 = CopyUniToUtf(name);\r
1098         bool ret = UnixDeleteDir(name8);\r
1099 \r
1100         Free(name8);\r
1101 \r
1102         return ret;\r
1103 }\r
1104 bool UnixDeleteDir(char *name)\r
1105 {\r
1106         // 引数チェック\r
1107         if (name == NULL)\r
1108         {\r
1109                 return false;\r
1110         }\r
1111 \r
1112         if (rmdir(name) != 0)\r
1113         {\r
1114                 return false;\r
1115         }\r
1116 \r
1117         return true;\r
1118 }\r
1119 \r
1120 // ディレクトリを作成する\r
1121 bool UnixMakeDirW(wchar_t *name)\r
1122 {\r
1123         char *name8 = CopyUniToUtf(name);\r
1124         bool ret = UnixMakeDir(name8);\r
1125 \r
1126         Free(name8);\r
1127 \r
1128         return ret;\r
1129 }\r
1130 bool UnixMakeDir(char *name)\r
1131 {\r
1132         // 引数チェック\r
1133         if (name == NULL)\r
1134         {\r
1135                 return false;\r
1136         }\r
1137 \r
1138         if (mkdir(name, 0700) != 0)\r
1139         {\r
1140                 return false;\r
1141         }\r
1142 \r
1143         return true;\r
1144 }\r
1145 \r
1146 // ファイルを削除する\r
1147 bool UnixFileDeleteW(wchar_t *name)\r
1148 {\r
1149         bool ret;\r
1150         char *name8 = CopyUniToUtf(name);\r
1151 \r
1152         ret = UnixFileDelete(name8);\r
1153 \r
1154         Free(name8);\r
1155 \r
1156         return ret;\r
1157 }\r
1158 bool UnixFileDelete(char *name)\r
1159 {\r
1160         // 引数チェック\r
1161         if (name == NULL)\r
1162         {\r
1163                 return false;\r
1164         }\r
1165 \r
1166         if (remove(name) != 0)\r
1167         {\r
1168                 return false;\r
1169         }\r
1170 \r
1171         return true;\r
1172 }\r
1173 \r
1174 // ファイルをシークする\r
1175 bool UnixFileSeek(void *pData, UINT mode, int offset)\r
1176 {\r
1177         UNIXIO *p;\r
1178         UINT ret;\r
1179         // 引数チェック\r
1180         if (pData == NULL)\r
1181         {\r
1182                 return 0;\r
1183         }\r
1184         if (mode != FILE_BEGIN && mode != FILE_END && mode != FILE_CURRENT)\r
1185         {\r
1186                 return false;\r
1187         }\r
1188 \r
1189         p = (UNIXIO *)pData;\r
1190 \r
1191         ret = lseek(p->fd, offset, mode);\r
1192 \r
1193         if (ret == -1)\r
1194         {\r
1195                 return false;\r
1196         }\r
1197 \r
1198         return true;\r
1199 }\r
1200 \r
1201 // ファイルサイズを取得する\r
1202 UINT64 UnixFileSize(void *pData)\r
1203 {\r
1204         struct stat st;\r
1205         UNIXIO *p;\r
1206         // 引数チェック\r
1207         if (pData == NULL)\r
1208         {\r
1209                 return 0;\r
1210         }\r
1211 \r
1212         p = (UNIXIO *)pData;\r
1213 \r
1214         if (fstat(p->fd, &st) != 0)\r
1215         {\r
1216                 return 0;\r
1217         }\r
1218 \r
1219         return (UINT64)st.st_size;\r
1220 }\r
1221 \r
1222 // ファイルに書き込む\r
1223 bool UnixFileWrite(void *pData, void *buf, UINT size)\r
1224 {\r
1225         UNIXIO *p;\r
1226         UINT ret;\r
1227         // 引数チェック\r
1228         if (pData == NULL || buf == NULL || size == 0)\r
1229         {\r
1230                 return false;\r
1231         }\r
1232 \r
1233         p = (UNIXIO *)pData;\r
1234 \r
1235         ret = write(p->fd, buf, size);\r
1236         if (ret != size)\r
1237         {\r
1238                 return false;\r
1239         }\r
1240 \r
1241         return true;\r
1242 }\r
1243 \r
1244 // ファイルから読み込む\r
1245 bool UnixFileRead(void *pData, void *buf, UINT size)\r
1246 {\r
1247         UNIXIO *p;\r
1248         UINT ret;\r
1249         // 引数チェック\r
1250         if (pData == NULL || buf == NULL || size == 0)\r
1251         {\r
1252                 return false;\r
1253         }\r
1254 \r
1255         p = (UNIXIO *)pData;\r
1256 \r
1257         ret = read(p->fd, buf, size);\r
1258         if (ret != size)\r
1259         {\r
1260                 return false;\r
1261         }\r
1262 \r
1263         return true;\r
1264 }\r
1265 \r
1266 // ファイルをフラッシュする\r
1267 void UnixFileFlush(void *pData)\r
1268 {\r
1269         UNIXIO *p;\r
1270         bool write_mode;\r
1271         // 引数チェック\r
1272         if (pData == NULL)\r
1273         {\r
1274                 return;\r
1275         }\r
1276 \r
1277         p = (UNIXIO *)pData;\r
1278 \r
1279         write_mode = p->write_mode;\r
1280 \r
1281         if (write_mode)\r
1282         {\r
1283                 fsync(p->fd);\r
1284         }\r
1285 }\r
1286 \r
1287 // ファイルを閉じる\r
1288 void UnixFileClose(void *pData, bool no_flush)\r
1289 {\r
1290         UNIXIO *p;\r
1291         bool write_mode;\r
1292         // 引数チェック\r
1293         if (pData == NULL)\r
1294         {\r
1295                 return;\r
1296         }\r
1297 \r
1298         p = (UNIXIO *)pData;\r
1299 \r
1300         write_mode = p->write_mode;\r
1301 \r
1302         if (write_mode && no_flush == false)\r
1303         {\r
1304                 fsync(p->fd);\r
1305         }\r
1306 \r
1307         close(p->fd);\r
1308 \r
1309         UnixMemoryFree(p);\r
1310 \r
1311         if (write_mode)\r
1312         {\r
1313                 //sync();\r
1314         }\r
1315 }\r
1316 \r
1317 // ファイルを作成する\r
1318 void *UnixFileCreateW(wchar_t *name)\r
1319 {\r
1320         void *ret;\r
1321         char *name8 = CopyUniToUtf(name);\r
1322 \r
1323         ret = UnixFileCreate(name8);\r
1324 \r
1325         Free(name8);\r
1326 \r
1327         return ret;\r
1328 }\r
1329 void *UnixFileCreate(char *name)\r
1330 {\r
1331         UNIXIO *p;\r
1332         int fd;\r
1333         // 引数チェック\r
1334         if (name == NULL)\r
1335         {\r
1336                 return NULL;\r
1337         }\r
1338 \r
1339         fd = creat(name, 0600);\r
1340         if (fd == -1)\r
1341         {\r
1342                 return NULL;\r
1343         }\r
1344 \r
1345         // メモリ確保\r
1346         p = UnixMemoryAlloc(sizeof(UNIXIO));\r
1347         p->fd = fd;\r
1348         p->write_mode = true;\r
1349 \r
1350         return (void *)p;\r
1351 }\r
1352 \r
1353 // ファイルを開く\r
1354 void *UnixFileOpenW(wchar_t *name, bool write_mode, bool read_lock)\r
1355 {\r
1356         char *name8 = CopyUniToUtf(name);\r
1357         void *ret;\r
1358 \r
1359         ret = UnixFileOpen(name8, write_mode, read_lock);\r
1360 \r
1361         Free(name8);\r
1362 \r
1363         return ret;\r
1364 }\r
1365 void *UnixFileOpen(char *name, bool write_mode, bool read_lock)\r
1366 {\r
1367         UNIXIO *p;\r
1368         int fd;\r
1369         int mode;\r
1370         // 引数チェック\r
1371         if (name == NULL)\r
1372         {\r
1373                 return NULL;\r
1374         }\r
1375 \r
1376         if (write_mode == false)\r
1377         {\r
1378                 mode = O_RDONLY;\r
1379         }\r
1380         else\r
1381         {\r
1382                 mode = O_RDWR;\r
1383         }\r
1384 \r
1385         // ファイルを開く\r
1386         fd = open(name, mode);\r
1387         if (fd == -1)\r
1388         {\r
1389                 return NULL;\r
1390         }\r
1391 \r
1392         // メモリ確保\r
1393         p = UnixMemoryAlloc(sizeof(UNIXIO));\r
1394         p->fd = fd;\r
1395         p->write_mode = write_mode;\r
1396 \r
1397         return (void *)p;\r
1398 }\r
1399 \r
1400 // 現在のスレッド ID を返す\r
1401 UINT UnixThreadId()\r
1402 {\r
1403         UINT ret;\r
1404 \r
1405         ret = (UINT)pthread_self();\r
1406 \r
1407         return ret;\r
1408 }\r
1409 \r
1410 // スレッド関数\r
1411 void *UnixDefaultThreadProc(void *param)\r
1412 {\r
1413         UNIXTHREAD *ut;\r
1414         UNIXTHREADSTARTUPINFO *info = (UNIXTHREADSTARTUPINFO *)param;\r
1415         if (info == NULL)\r
1416         {\r
1417                 return 0;\r
1418         }\r
1419 \r
1420         ut = (UNIXTHREAD *)info->thread->pData;\r
1421 \r
1422         // スレッド関数の呼び出し\r
1423         info->thread_proc(info->thread, info->param);\r
1424 \r
1425         // 終了フラグを立てる\r
1426         ut->finished = true;\r
1427 \r
1428         // 参照の解放\r
1429         ReleaseThread(info->thread);\r
1430 \r
1431         UnixMemoryFree(info);\r
1432 \r
1433         FreeOpenSSLThreadState();\r
1434 \r
1435         return 0;\r
1436 }\r
1437 \r
1438 // スレッドの解放\r
1439 void UnixFreeThread(THREAD *t)\r
1440 {\r
1441         // 引数チェック\r
1442         if (t == NULL)\r
1443         {\r
1444                 return;\r
1445         }\r
1446 \r
1447         // メモリの解放\r
1448         UnixMemoryFree(t->pData);\r
1449 }\r
1450 \r
1451 // スレッドの終了を待機\r
1452 bool UnixWaitThread(THREAD *t)\r
1453 {\r
1454         UNIXTHREAD *ut;\r
1455         void *retcode = NULL;\r
1456         // 引数チェック\r
1457         if (t == NULL)\r
1458         {\r
1459                 return false;\r
1460         }\r
1461         ut = (UNIXTHREAD *)t->pData;\r
1462         if (ut == NULL)\r
1463         {\r
1464                 return false;\r
1465         }\r
1466 \r
1467         pthread_join(ut->thread, &retcode);\r
1468 \r
1469         return true;\r
1470 }\r
1471 \r
1472 // スレッドの初期化\r
1473 bool UnixInitThread(THREAD *t)\r
1474 {\r
1475         UNIXTHREAD *ut;\r
1476         UNIXTHREADSTARTUPINFO *info;\r
1477         pthread_attr_t attr;\r
1478         // 引数チェック\r
1479         if (t == NULL || t->thread_proc == NULL)\r
1480         {\r
1481                 return false;\r
1482         }\r
1483 \r
1484         // スレッドデータ作成\r
1485         ut = UnixMemoryAlloc(sizeof(UNIXTHREAD));\r
1486         Zero(ut, sizeof(UNIXTHREAD));\r
1487 \r
1488         // 起動情報作成\r
1489         info = UnixMemoryAlloc(sizeof(UNIXTHREADSTARTUPINFO));\r
1490         Zero(info, sizeof(UNIXTHREADSTARTUPINFO));\r
1491         info->param = t->param;\r
1492         info->thread_proc = t->thread_proc;\r
1493         info->thread = t;\r
1494         AddRef(t->ref);\r
1495 \r
1496         // スレッド作成\r
1497         pthread_attr_init(&attr);\r
1498         pthread_attr_setstacksize(&attr, UNIX_THREAD_STACK_SIZE);\r
1499 \r
1500         t->pData = (void *)ut;\r
1501 \r
1502         if (pthread_create(&ut->thread, &attr, UnixDefaultThreadProc, info) != 0)\r
1503         {\r
1504                 // エラー発生\r
1505                 t->pData = NULL;\r
1506                 Release(t->ref);\r
1507                 UnixMemoryFree(ut);\r
1508                 UnixMemoryFree(info);\r
1509                 pthread_attr_destroy(&attr);\r
1510                 return false;\r
1511         }\r
1512 \r
1513         pthread_attr_destroy(&attr);\r
1514 \r
1515         return true;\r
1516 }\r
1517 \r
1518 // イベントの解放\r
1519 void UnixFreeEvent(EVENT *event)\r
1520 {\r
1521         UNIXEVENT *ue = (UNIXEVENT *)event->pData;\r
1522         if (ue == NULL)\r
1523         {\r
1524                 return;\r
1525         }\r
1526 \r
1527         pthread_cond_destroy(&ue->cond);\r
1528         pthread_mutex_destroy(&ue->mutex);\r
1529 \r
1530         UnixMemoryFree(ue);\r
1531 }\r
1532 \r
1533 // イベントの待機\r
1534 bool UnixWaitEvent(EVENT *event, UINT timeout)\r
1535 {\r
1536         UNIXEVENT *ue = (UNIXEVENT *)event->pData;\r
1537         struct timeval now;\r
1538         struct timespec to;\r
1539         bool ret;\r
1540         if (ue == NULL)\r
1541         {\r
1542                 return false;\r
1543         }\r
1544 \r
1545         pthread_mutex_lock(&ue->mutex);\r
1546         gettimeofday(&now, NULL);\r
1547         to.tv_sec = now.tv_sec + timeout / 1000;\r
1548         to.tv_nsec = now.tv_usec * 1000 + (timeout % 1000) * 1000 * 1000;\r
1549         if ((to.tv_nsec / 1000000000) >= 1)\r
1550         {\r
1551                 to.tv_sec += to.tv_nsec / 1000000000;\r
1552                 to.tv_nsec = to.tv_nsec % 1000000000;\r
1553         }\r
1554 \r
1555         ret = true;\r
1556 \r
1557         while (ue->signal == false)\r
1558         {\r
1559                 if (timeout != INFINITE)\r
1560                 {\r
1561                         if (pthread_cond_timedwait(&ue->cond, &ue->mutex, &to))\r
1562                         {\r
1563                                 ret = false;\r
1564                                 break;\r
1565                         }\r
1566                 }\r
1567                 else\r
1568                 {\r
1569                         pthread_cond_wait(&ue->cond, &ue->mutex);\r
1570                 }\r
1571         }\r
1572         ue->signal = false;\r
1573 \r
1574         pthread_mutex_unlock(&ue->mutex);\r
1575 \r
1576         return ret;\r
1577 }\r
1578 \r
1579 // イベントのリセット\r
1580 void UnixResetEvent(EVENT *event)\r
1581 {\r
1582         UNIXEVENT *ue = (UNIXEVENT *)event->pData;\r
1583         if (ue == NULL)\r
1584         {\r
1585                 return;\r
1586         }\r
1587 \r
1588         pthread_mutex_lock(&ue->mutex);\r
1589         ue->signal = false;\r
1590         pthread_cond_signal(&ue->cond);\r
1591         pthread_mutex_unlock(&ue->mutex);\r
1592 }\r
1593 \r
1594 // イベントのセット\r
1595 void UnixSetEvent(EVENT *event)\r
1596 {\r
1597         UNIXEVENT *ue = (UNIXEVENT *)event->pData;\r
1598         if (ue == NULL)\r
1599         {\r
1600                 return;\r
1601         }\r
1602 \r
1603         pthread_mutex_lock(&ue->mutex);\r
1604         ue->signal = true;\r
1605         pthread_cond_signal(&ue->cond);\r
1606         pthread_mutex_unlock(&ue->mutex);\r
1607 }\r
1608 \r
1609 // イベントの初期化\r
1610 void UnixInitEvent(EVENT *event)\r
1611 {\r
1612         UNIXEVENT *ue = UnixMemoryAlloc(sizeof(UNIXEVENT));\r
1613 \r
1614         Zero(ue, sizeof(UNIXEVENT));\r
1615 \r
1616         pthread_cond_init(&ue->cond, NULL);\r
1617         pthread_mutex_init(&ue->mutex, NULL);\r
1618         ue->signal = false;\r
1619 \r
1620         event->pData = (void *)ue;\r
1621 }\r
1622 \r
1623 // ロックの削除\r
1624 void UnixDeleteLock(LOCK *lock)\r
1625 {\r
1626         pthread_mutex_t *mutex;\r
1627         // Ready フラグを安全に解除する\r
1628         UnixLock(lock);\r
1629         lock->Ready = false;\r
1630         UnixUnlockEx(lock, true);\r
1631 \r
1632         // mutex の削除\r
1633         mutex = (pthread_mutex_t *)lock->pData;\r
1634         pthread_mutex_destroy(mutex);\r
1635 \r
1636         // メモリ解放\r
1637         UnixMemoryFree(mutex);\r
1638         UnixMemoryFree(lock);\r
1639 }\r
1640 \r
1641 // ロック解除\r
1642 void UnixUnlock(LOCK *lock)\r
1643 {\r
1644         UnixUnlockEx(lock, false);\r
1645 }\r
1646 void UnixUnlockEx(LOCK *lock, bool inner)\r
1647 {\r
1648         pthread_mutex_t *mutex;\r
1649         if (lock->Ready == false && inner == false)\r
1650         {\r
1651                 // 状態が不正\r
1652                 return;\r
1653         }\r
1654         mutex = (pthread_mutex_t *)lock->pData;\r
1655 \r
1656         if ((--lock->locked_count) > 0)\r
1657         {\r
1658                 return;\r
1659         }\r
1660 \r
1661         lock->thread_id = INFINITE;\r
1662 \r
1663         pthread_mutex_unlock(mutex);\r
1664 \r
1665         return;\r
1666 }\r
1667 \r
1668 // ロック\r
1669 bool UnixLock(LOCK *lock)\r
1670 {\r
1671         pthread_mutex_t *mutex;\r
1672         UINT thread_id = UnixThreadId();\r
1673         if (lock->Ready == false)\r
1674         {\r
1675                 // 状態が不正\r
1676                 return false;\r
1677         }\r
1678 \r
1679         if (lock->thread_id == thread_id)\r
1680         {\r
1681                 lock->locked_count++;\r
1682                 return true;\r
1683         }\r
1684 \r
1685         mutex = (pthread_mutex_t *)lock->pData;\r
1686 \r
1687         pthread_mutex_lock(mutex);\r
1688 \r
1689         lock->thread_id = thread_id;\r
1690         lock->locked_count++;\r
1691 \r
1692         return true;\r
1693 }\r
1694 \r
1695 // 新しいロックの作成\r
1696 LOCK *UnixNewLock()\r
1697 {\r
1698         pthread_mutex_t *mutex;\r
1699         // メモリ確保\r
1700         LOCK *lock = UnixMemoryAlloc(sizeof(LOCK));\r
1701 \r
1702         // mutex 作成\r
1703         mutex = UnixMemoryAlloc(sizeof(pthread_mutex_t));\r
1704 \r
1705         // mutex 初期化\r
1706         pthread_mutex_init(mutex, NULL);\r
1707 \r
1708         lock->pData = (void *)mutex;\r
1709         lock->Ready = true;\r
1710 \r
1711         lock->thread_id = INFINITE;\r
1712         lock->locked_count = 0;\r
1713 \r
1714         return lock;\r
1715 }\r
1716 \r
1717 // スリープ\r
1718 void UnixSleep(UINT time)\r
1719 {\r
1720         UINT sec = 0, millisec = 0;\r
1721         // 引数チェック\r
1722         if (time == 0)\r
1723         {\r
1724                 return;\r
1725         }\r
1726 \r
1727         if (time == INFINITE)\r
1728         {\r
1729                 // 無限に待機する\r
1730                 while (true)\r
1731                 {\r
1732 #ifdef UNIX_SOLARIS\r
1733                         UnixSolarisSleep(time);\r
1734 #else\r
1735                         sleep(1000000);\r
1736 #endif\r
1737                 }\r
1738         }\r
1739 \r
1740 #ifdef UNIX_SOLARIS\r
1741         UnixSolarisSleep(time);\r
1742 #else\r
1743 \r
1744         // 桁あふれ防止\r
1745         sec = time / 1000;\r
1746         millisec = time % 1000;\r
1747 \r
1748         if (sec != 0)\r
1749         {\r
1750                 sleep(sec);\r
1751         }\r
1752         if (millisec != 0)\r
1753         {\r
1754                 usleep(millisec * 1000);\r
1755         }\r
1756 #endif\r
1757 }\r
1758 \r
1759 // デクリメント\r
1760 void UnixDec32(UINT *value)\r
1761 {\r
1762         if (value != NULL)\r
1763         {\r
1764                 (*value)--;\r
1765         }\r
1766 }\r
1767 \r
1768 // インクリメント\r
1769 void UnixInc32(UINT *value)\r
1770 {\r
1771         if (value != NULL)\r
1772         {\r
1773                 (*value)++;\r
1774         }\r
1775 }\r
1776 \r
1777 // システム時刻の取得\r
1778 void UnixGetSystemTime(SYSTEMTIME *system_time)\r
1779 {\r
1780         time_t now = 0;\r
1781         struct tm tm;\r
1782         struct timeval tv;\r
1783         struct timezone tz;\r
1784         // 引数チェック\r
1785         if (system_time == NULL)\r
1786         {\r
1787                 return;\r
1788         }\r
1789 \r
1790         pthread_mutex_lock(&get_time_lock);\r
1791 \r
1792         Zero(system_time, sizeof(SYSTEMTIME));\r
1793         Zero(&tv, sizeof(tv));\r
1794         Zero(&tz, sizeof(tz));\r
1795 \r
1796         time(&now);\r
1797 \r
1798         gmtime_r(&now, &tm);\r
1799 \r
1800         TmToSystem(system_time, &tm);\r
1801 \r
1802         gettimeofday(&tv, &tz);\r
1803 \r
1804         system_time->wMilliseconds = tv.tv_usec / 1000;\r
1805 \r
1806         pthread_mutex_unlock(&get_time_lock);\r
1807 }\r
1808 \r
1809 // システムタイマの取得 (64bit)\r
1810 UINT64 UnixGetTick64()\r
1811 {\r
1812 #if     defined(OS_WIN32) || defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) || defined(CLOCK_HIGHRES)\r
1813 \r
1814         struct timespec t;\r
1815         UINT64 ret;\r
1816         static bool akirame = false;\r
1817 \r
1818         if (akirame)\r
1819         {\r
1820                 return TickRealtimeManual();\r
1821         }\r
1822 \r
1823         Zero(&t, sizeof(t));\r
1824 \r
1825         // システムの起動時刻を取得する関数\r
1826         // システムによって実装が異なるので注意\r
1827 #ifdef  CLOCK_HIGHRES\r
1828         clock_gettime(CLOCK_HIGHRES, &t);\r
1829 #else   // CLOCK_HIGHRES\r
1830 #ifdef  CLOCK_MONOTONIC\r
1831         clock_gettime(CLOCK_MONOTONIC, &t);\r
1832 #else   // CLOCK_MONOTONIC\r
1833         clock_gettime(CLOCK_REALTIME, &t);\r
1834 #endif  // CLOCK_MONOTONIC\r
1835 #endif  // CLOCK_HIGHRES\r
1836 \r
1837         ret = (UINT64)t.tv_sec * 1000LL + (UINT64)t.tv_nsec / 1000000LL;\r
1838 \r
1839         if (akirame == false && ret == 0)\r
1840         {\r
1841                 ret = TickRealtimeManual();\r
1842                 akirame = true;\r
1843         }\r
1844 \r
1845         return ret;\r
1846 \r
1847 #else\r
1848 \r
1849         return TickRealtimeManual();\r
1850 \r
1851 #endif\r
1852 }\r
1853 \r
1854 // システムタイマの取得\r
1855 UINT UnixGetTick()\r
1856 {\r
1857         return (UINT)UnixGetTick64();\r
1858 }\r
1859 \r
1860 // メモリの確保\r
1861 void *UnixMemoryAlloc(UINT size)\r
1862 {\r
1863         void *r;\r
1864         pthread_mutex_lock(&malloc_lock);\r
1865         r = malloc(size);\r
1866         pthread_mutex_unlock(&malloc_lock);\r
1867         return r;\r
1868 }\r
1869 \r
1870 // メモリの再確保\r
1871 void *UnixMemoryReAlloc(void *addr, UINT size)\r
1872 {\r
1873         void *r;\r
1874         pthread_mutex_lock(&malloc_lock);\r
1875         r = realloc(addr, size);\r
1876         pthread_mutex_unlock(&malloc_lock);\r
1877         return r;\r
1878 }\r
1879 \r
1880 // メモリの解放\r
1881 void UnixMemoryFree(void *addr)\r
1882 {\r
1883         pthread_mutex_lock(&malloc_lock);\r
1884         free(addr);\r
1885         pthread_mutex_unlock(&malloc_lock);\r
1886 }\r
1887 \r
1888 // SIGCHLD ハンドラ\r
1889 void UnixSigChldHandler(int sig)\r
1890 {\r
1891         // ゾンビプロセスの回収\r
1892         while (waitpid(-1, NULL, WNOHANG) > 0);\r
1893         signal(SIGCHLD, UnixSigChldHandler);\r
1894 }\r
1895 \r
1896 // UNIX 用ライブラリの初期化\r
1897 void UnixInit()\r
1898 {\r
1899         UNIXIO *o;\r
1900 \r
1901         UnixInitSolarisSleep();\r
1902 \r
1903         // グローバルロック\r
1904         pthread_mutex_init(&get_time_lock, NULL);\r
1905         pthread_mutex_init(&malloc_lock, NULL);\r
1906 \r
1907         // プロセス ID の取得\r
1908         current_process_id = getpid();\r
1909 \r
1910 #ifdef  RLIMIT_CORE\r
1911         UnixSetResourceLimit(RLIMIT_CORE, UNIX_MAX_MEMORY);\r
1912 #endif  // RLIMIT_CORE\r
1913 \r
1914 #ifdef  RLIMIT_DATA\r
1915         UnixSetResourceLimit(RLIMIT_DATA, UNIX_MAX_MEMORY);\r
1916 #endif  // RLIMIT_DATA\r
1917 \r
1918 #ifdef  RLIMIT_NOFILE\r
1919         UnixSetResourceLimit(RLIMIT_NOFILE, UNIX_MAX_FD);\r
1920 #endif  // RLIMIT_NOFILE\r
1921 \r
1922 #ifdef  RLIMIT_STACK\r
1923 //      UnixSetResourceLimit(RLIMIT_STACK, UNIX_MAX_MEMORY);\r
1924 #endif  // RLIMIT_STACK\r
1925 \r
1926 #ifdef  RLIMIT_RSS\r
1927         UnixSetResourceLimit(RLIMIT_RSS, UNIX_MAX_MEMORY);\r
1928 #endif  // RLIMIT_RSS\r
1929 \r
1930 #ifdef  RLIMIT_LOCKS\r
1931         UnixSetResourceLimit(RLIMIT_LOCKS, UNIX_MAX_LOCKS);\r
1932 #endif  // RLIMIT_LOCKS\r
1933 \r
1934 #ifdef  RLIMIT_MEMLOCK\r
1935         UnixSetResourceLimit(RLIMIT_MEMLOCK, UNIX_MAX_MEMORY);\r
1936 #endif  // RLIMIT_MEMLOCK\r
1937 \r
1938 #ifdef  RLIMIT_NPROC\r
1939         UnixSetResourceLimit(RLIMIT_NPROC, UNIX_MAX_CHILD_PROCESSES);\r
1940 #endif  // RLIMIT_NPROC\r
1941 \r
1942         // proc ファイルシステムの threads-max に値を書き込む\r
1943         o = UnixFileCreate("/proc/sys/kernel/threads-max");\r
1944         if (o != NULL)\r
1945         {\r
1946                 char tmp[128];\r
1947                 sprintf(tmp, "%u\n", UNIX_LINUX_MAX_THREADS);\r
1948                 UnixFileWrite(o, tmp, strlen(tmp));\r
1949                 UnixFileClose(o, false);\r
1950         }\r
1951 \r
1952         // 無視するシグナルを設定\r
1953         signal(SIGPIPE, SIG_IGN);\r
1954         signal(SIGALRM, SIG_IGN);\r
1955 \r
1956 #ifdef  UNIX_BSD\r
1957         signal(64, SIG_IGN);\r
1958 #endif  // UNIX_BSD\r
1959 \r
1960 #ifdef  SIGXFSZ\r
1961         signal(SIGXFSZ, SIG_IGN);\r
1962 #endif  // SIGXFSZ\r
1963 \r
1964         // 子プロセス回収用シグナルハンドラの設定\r
1965         signal(SIGCHLD, UnixSigChldHandler);\r
1966 }\r
1967 \r
1968 // UNIX 用ライブラリの解放\r
1969 void UnixFree()\r
1970 {\r
1971         UnixFreeSolarisSleep();\r
1972 \r
1973         current_process_id = 0;\r
1974 \r
1975         pthread_mutex_destroy(&get_time_lock);\r
1976 }\r
1977 \r
1978 // 占有することができる資源の上限値を調整\r
1979 void UnixSetResourceLimit(UINT id, UINT value)\r
1980 {\r
1981         struct rlimit t;\r
1982         UINT hard_limit;\r
1983 \r
1984         Zero(&t, sizeof(t));\r
1985         getrlimit(id, &t);\r
1986 \r
1987         hard_limit = t.rlim_max;\r
1988 \r
1989         Zero(&t, sizeof(t));\r
1990         t.rlim_cur = MIN(value, hard_limit);\r
1991         t.rlim_max = hard_limit;\r
1992         setrlimit(id, &t);\r
1993 \r
1994         Zero(&t, sizeof(t));\r
1995         t.rlim_cur = value;\r
1996         t.rlim_max = value;\r
1997         setrlimit(id, &t);\r
1998 }\r
1999 \r
2000 // PID ファイル名を生成する\r
2001 void UnixGenPidFileName(char *name, UINT size)\r
2002 {\r
2003         char exe_name[MAX_PATH];\r
2004         UCHAR hash[MD5_SIZE];\r
2005         char tmp1[64];\r
2006         char dir[MAX_PATH];\r
2007         // 引数チェック\r
2008         if (name == NULL)\r
2009         {\r
2010                 return;\r
2011         }\r
2012 \r
2013         GetExeDir(dir, sizeof(dir));\r
2014 \r
2015         GetExeName(exe_name, sizeof(exe_name));\r
2016         StrCat(exe_name, sizeof(exe_name), ":pid_hash");\r
2017         StrUpper(exe_name);\r
2018 \r
2019         Hash(hash, exe_name, StrLen(exe_name), false);\r
2020         BinToStr(tmp1, sizeof(tmp1), hash, sizeof(hash));\r
2021 \r
2022         Format(name, size, "%s/.pid_%s", dir, tmp1);\r
2023 }\r
2024 \r
2025 // PID ファイルを削除する\r
2026 void UnixDeletePidFile()\r
2027 {\r
2028         char tmp[MAX_PATH];\r
2029 \r
2030         UnixGenPidFileName(tmp, sizeof(tmp));\r
2031 \r
2032         UnixFileDelete(tmp);\r
2033 }\r
2034 \r
2035 // PID ファイルに書き込む\r
2036 void UnixWritePidFile(UINT pid)\r
2037 {\r
2038         char tmp[MAX_PATH];\r
2039         char tmp2[64];\r
2040         IO *o;\r
2041 \r
2042         UnixGenPidFileName(tmp, sizeof(tmp));\r
2043         Format(tmp2, sizeof(tmp2), "%u\n", pid);\r
2044 \r
2045         o = FileCreate(tmp);\r
2046         if (o != NULL)\r
2047         {\r
2048                 FileWrite(o, tmp2, StrLen(tmp2));\r
2049                 FileClose(o);\r
2050         }\r
2051 }\r
2052 \r
2053 // PID ファイルを読み込む\r
2054 UINT UnixReadPidFile()\r
2055 {\r
2056         char tmp[MAX_PATH];\r
2057         BUF *buf;\r
2058 \r
2059         UnixGenPidFileName(tmp, sizeof(tmp));\r
2060 \r
2061         buf = ReadDump(tmp);\r
2062         if (buf == NULL)\r
2063         {\r
2064                 return 0;\r
2065         }\r
2066 \r
2067         Zero(tmp, sizeof(tmp));\r
2068         Copy(tmp, buf->Buf, MIN(buf->Size, sizeof(tmp)));\r
2069         FreeBuf(buf);\r
2070 \r
2071         return ToInt(tmp);\r
2072 }\r
2073 \r
2074 // サービスの開始\r
2075 void UnixStartService(char *name)\r
2076 {\r
2077         char *svc_name, *svc_title;\r
2078         char tmp[128];\r
2079         INSTANCE *inst;\r
2080         char exe[MAX_PATH];\r
2081         // 引数チェック\r
2082         if (name == NULL)\r
2083         {\r
2084                 return;\r
2085         }\r
2086 \r
2087         GetExeName(exe, sizeof(exe));\r
2088 \r
2089         Format(tmp, sizeof(tmp), SVC_NAME, name);\r
2090         svc_name = _SS(tmp);\r
2091         Format(tmp, sizeof(tmp), SVC_TITLE, name);\r
2092         svc_title = _SS(tmp);\r
2093 \r
2094         // すでにサービスが起動していないかどうか調べる\r
2095         inst = NewSingleInstance(NULL);\r
2096         if (inst == NULL)\r
2097         {\r
2098                 // すでにサービスが起動している\r
2099                 UniPrint(_UU("UNIX_SVC_ALREADY_START"), svc_title, svc_name);\r
2100         }\r
2101         else\r
2102         {\r
2103                 int pid;\r
2104                 // サービスの起動を開始する\r
2105                 UniPrint(_UU("UNIX_SVC_STARTED"), svc_title);\r
2106                 FreeSingleInstance(inst);\r
2107 \r
2108                 // 子プロセスを作成する\r
2109                 pid = fork();\r
2110                 if (pid == -1)\r
2111                 {\r
2112                         UniPrint(_UU("UNIX_SVC_ERROR_FORK"), svc_title);\r
2113                 }\r
2114                 else\r
2115                 {\r
2116                         if (pid == 0)\r
2117                         {\r
2118                                 // 子プロセス\r
2119                                 char *param = UNIX_SVC_ARG_EXEC_SVC;\r
2120                                 char **args;\r
2121 \r
2122                                 // デーモン化する\r
2123                                 setsid();\r
2124                                 UnixCloseIO();\r
2125                                 signal(SIGHUP, SIG_IGN);\r
2126 \r
2127                                 // 引数を準備\r
2128                                 args = ZeroMalloc(sizeof(char *) * 3);\r
2129                                 args[0] = exe;\r
2130                                 args[1] = param;\r
2131                                 args[2] = NULL;\r
2132 \r
2133                                 execvp(exe, args);\r
2134                                 AbortExit();\r
2135                         }\r
2136                         else\r
2137                         {\r
2138                                 // 子プロセス番号をファイルに書き込まない\r
2139 //                              UnixWritePidFile(pid);\r
2140                         }\r
2141                 }\r
2142         }\r
2143 }\r
2144 \r
2145 // サービスの停止\r
2146 void UnixStopService(char *name)\r
2147 {\r
2148         char *svc_name, *svc_title;\r
2149         char tmp[128];\r
2150         INSTANCE *inst;\r
2151         char exe[MAX_PATH];\r
2152         UINT pid;\r
2153         // 引数チェック\r
2154         if (name == NULL)\r
2155         {\r
2156                 return;\r
2157         }\r
2158 \r
2159         GetExeName(exe, sizeof(exe));\r
2160 \r
2161         Format(tmp, sizeof(tmp), SVC_NAME, name);\r
2162         svc_name = _SS(tmp);\r
2163         Format(tmp, sizeof(tmp), SVC_TITLE, name);\r
2164         svc_title = _SS(tmp);\r
2165 \r
2166         inst = NewSingleInstance(NULL);\r
2167         pid = UnixReadPidFile();\r
2168         if (inst != NULL || pid == 0)\r
2169         {\r
2170                 // まだサービスが起動していない\r
2171                 UniPrint(_UU("UNIX_SVC_NOT_STARTED"), svc_title, svc_name);\r
2172         }\r
2173         else\r
2174         {\r
2175                 int status;\r
2176 \r
2177                 // サービスを停止する\r
2178                 UniPrint(_UU("UNIX_SVC_STOPPING"), svc_title);\r
2179 \r
2180                 // プロセスを終了する\r
2181                 kill(pid, SIGTERM);\r
2182                 if (UnixWaitProcessEx(pid, UNIX_SERVICE_STOP_TIMEOUT_2))\r
2183                 {\r
2184                         UniPrint(_UU("UNIX_SVC_STOPPED"), svc_title);\r
2185                 }\r
2186                 else\r
2187                 {\r
2188                         UniPrint(_UU("UNIX_SVC_STOP_FAILED"), svc_title);\r
2189                 }\r
2190         }\r
2191 \r
2192         FreeSingleInstance(inst);\r
2193 }\r
2194 \r
2195 // プロセスへの停止シグナルのハンドラ\r
2196 void UnixSigTermHandler(int signum)\r
2197 {\r
2198         if (signum == SIGTERM)\r
2199         {\r
2200                 unix_svc_terminate = true;\r
2201         }\r
2202 }\r
2203 \r
2204 // サービス停止用スレッド\r
2205 void UnixStopThread(THREAD *t, void *param)\r
2206 {\r
2207         SERVICE_FUNCTION *stop = (SERVICE_FUNCTION *)param;\r
2208         // 引数チェック\r
2209         if (t == NULL || param == NULL)\r
2210         {\r
2211                 return;\r
2212         }\r
2213 \r
2214         stop();\r
2215 }\r
2216 \r
2217 // サービスの内容の実行\r
2218 void UnixExecService(char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop)\r
2219 {\r
2220         char *svc_name, *svc_title;\r
2221         char tmp[128];\r
2222         INSTANCE *inst;\r
2223         UINT yobi_size = 1024 * 128;\r
2224         void *yobi1, *yobi2;\r
2225         // 引数チェック\r
2226         if (start == NULL || stop == NULL || name == NULL)\r
2227         {\r
2228                 return;\r
2229         }\r
2230 \r
2231         Format(tmp, sizeof(tmp), SVC_NAME, name);\r
2232         svc_name = _SS(tmp);\r
2233         Format(tmp, sizeof(tmp), SVC_TITLE, name);\r
2234         svc_title = _SS(tmp);\r
2235 \r
2236         inst = NewSingleInstance(NULL);\r
2237         if (inst != NULL)\r
2238         {\r
2239                 THREAD *t;\r
2240 \r
2241                 yobi1 = ZeroMalloc(yobi_size);\r
2242                 yobi2 = ZeroMalloc(yobi_size);\r
2243 \r
2244                 // 起動\r
2245                 UnixWritePidFile(getpid());\r
2246 \r
2247                 start();\r
2248 \r
2249                 // 起動完了 別のプロセスから SIGTERM が送られてくるのを待つ\r
2250                 signal(SIGTERM, &UnixSigTermHandler);\r
2251                 while (unix_svc_terminate == false)\r
2252                 {\r
2253                         pause();\r
2254                 }\r
2255 \r
2256                 // 停止\r
2257                 Free(yobi1);\r
2258                 t = NewThread(UnixStopThread, stop);\r
2259                 if (t == NULL || (WaitThread(t, UNIX_SERVICE_STOP_TIMEOUT_1) == false))\r
2260                 {\r
2261                         // 停止用スレッドの作成に失敗したか、タイムアウトした場合は\r
2262                         // 強制終了する\r
2263                         Free(yobi2);\r
2264                         FreeSingleInstance(inst);\r
2265                         UnixDeletePidFile();\r
2266                         _exit(0);\r
2267                 }\r
2268                 ReleaseThread(t);\r
2269 \r
2270                 // PID ファイルを削除\r
2271                 UnixDeletePidFile();\r
2272 \r
2273                 FreeSingleInstance(inst);\r
2274 \r
2275                 Free(yobi2);\r
2276         }\r
2277 }\r
2278 \r
2279 // 指定した pid のプロセスが存在するかどうか取得する\r
2280 bool UnixIsProcess(UINT pid)\r
2281 {\r
2282         if (getsid((pid_t)pid) == -1)\r
2283         {\r
2284                 return false;\r
2285         }\r
2286 \r
2287         return true;\r
2288 }\r
2289 \r
2290 // 指定したプロセスの終了を待機する\r
2291 bool UnixWaitProcessEx(UINT pid,  UINT timeout)\r
2292 {\r
2293         UINT64 start_tick = Tick64();\r
2294         UINT64 end_tick = start_tick + (UINT64)timeout;\r
2295         if (timeout == INFINITE)\r
2296         {\r
2297                 end_tick = 0;\r
2298         }\r
2299         while (UnixIsProcess(pid))\r
2300         {\r
2301                 if (end_tick != 0)\r
2302                 {\r
2303                         if (end_tick < Tick64())\r
2304                         {\r
2305                                 return false;\r
2306                         }\r
2307                 }\r
2308                 SleepThread(100);\r
2309         }\r
2310         return true;\r
2311 }\r
2312 void UnixWaitProcess(UINT pid)\r
2313 {\r
2314         UnixWaitProcessEx(pid, INFINITE);\r
2315 }\r
2316 \r
2317 // 起動方法の説明\r
2318 void UnixUsage(char *name)\r
2319 {\r
2320         char *svc_name, *svc_title;\r
2321         char tmp[128];\r
2322         // 引数チェック\r
2323         if (name == NULL)\r
2324         {\r
2325                 return;\r
2326         }\r
2327 \r
2328         Format(tmp, sizeof(tmp), SVC_NAME, name);\r
2329         svc_name = _SS(tmp);\r
2330         Format(tmp, sizeof(tmp), SVC_TITLE, name);\r
2331         svc_title = _SS(tmp);\r
2332 \r
2333         UniPrint(_UU("UNIX_SVC_HELP"), svc_title, svc_name, svc_name, svc_title, svc_name, svc_title);\r
2334 }\r
2335 \r
2336 // UNIX サービスのメイン関数\r
2337 UINT UnixService(int argc, char *argv[], char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop)\r
2338 {\r
2339         // 引数チェック\r
2340         if (name == NULL || start == NULL || stop == NULL)\r
2341         {\r
2342                 return 0;\r
2343         }\r
2344 \r
2345         if (argc >= 2 && StrCmpi(argv[1], UNIX_SVC_ARG_EXEC_SVC) == 0)\r
2346         {\r
2347                 UINT pid;\r
2348                 // 子プロセスを生成して開始する\r
2349                 // もし子プロセスが正しく終了しなかった場合は再起動する\r
2350 \r
2351 RESTART_PROCESS:\r
2352                 pid = fork();\r
2353                 if ((int)pid != -1)\r
2354                 {\r
2355                         if (pid == 0)\r
2356                         {\r
2357                                 // メイン処理の実行\r
2358                                 UnixServiceMain(argc, argv, name, start, stop);\r
2359                         }\r
2360                         else\r
2361                         {\r
2362                                 int status = 0, ret;\r
2363 \r
2364                                 // 子プロセスの終了を待機する\r
2365                                 ret = waitpid(pid, &status, 0);\r
2366 \r
2367                                 if (WIFEXITED(status) == 0)\r
2368                                 {\r
2369                                         // 異常終了した\r
2370                                         UnixSleep(100);\r
2371                                         goto RESTART_PROCESS;\r
2372                                 }\r
2373                         }\r
2374                 }\r
2375         }\r
2376         else\r
2377         {\r
2378                 // 通常に開始する\r
2379                 UnixServiceMain(argc, argv, name, start, stop);\r
2380         }\r
2381 \r
2382         return 0;\r
2383 }\r
2384 void UnixServiceMain(int argc, char *argv[], char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop)\r
2385 {\r
2386         UINT mode = 0;\r
2387         // Mayaqua の開始\r
2388         InitMayaqua(false, false, argc, argv);\r
2389 \r
2390         if (argc >= 2)\r
2391         {\r
2392                 if (StrCmpi(argv[1], UNIX_SVC_ARG_START) == 0)\r
2393                 {\r
2394                         mode = UNIX_SVC_MODE_START;\r
2395                 }\r
2396                 if (StrCmpi(argv[1], UNIX_SVC_ARG_STOP) == 0)\r
2397                 {\r
2398                         mode = UNIX_SVC_MODE_STOP;\r
2399                 }\r
2400                 if (StrCmpi(argv[1], UNIX_SVC_ARG_EXEC_SVC) == 0)\r
2401                 {\r
2402                         mode = UNIX_SVC_MODE_EXEC_SVC;\r
2403                 }\r
2404                 if (StrCmpi(argv[1], UNIX_ARG_EXIT) == 0)\r
2405                 {\r
2406                         mode = UNIX_SVC_MODE_EXIT;\r
2407                 }\r
2408         }\r
2409 \r
2410         switch (mode)\r
2411         {\r
2412         case UNIX_SVC_MODE_EXIT:\r
2413                 break;\r
2414 \r
2415         case UNIX_SVC_MODE_START:\r
2416                 UnixStartService(name);\r
2417                 break;\r
2418 \r
2419         case UNIX_SVC_MODE_STOP:\r
2420                 UnixStopService(name);\r
2421                 break;\r
2422 \r
2423         case UNIX_SVC_MODE_EXEC_SVC:\r
2424                 UnixExecService(name, start, stop);\r
2425                 break;\r
2426 \r
2427         default:\r
2428                 UnixUsage(name);\r
2429                 break;\r
2430         }\r
2431 \r
2432         // Mayaquq の終了\r
2433         FreeMayaqua();\r
2434 \r
2435         return;\r
2436 }\r
2437 \r
2438 #endif  // UNIX\r