linuxvcs.pp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. {$IFNDEF FPC_DOTTEDUNITS}
  2. unit linuxvcs;
  3. {$ENDIF FPC_DOTTEDUNITS}
  4. {*****************************************************************************}
  5. interface
  6. {*****************************************************************************}
  7. const vcs_device:shortint=-1;
  8. function try_grab_vcsa:boolean;
  9. {*****************************************************************************}
  10. implementation
  11. {*****************************************************************************}
  12. {$IFDEF FPC_DOTTEDUNITS}
  13. uses UnixApi.Base,System.Strings;
  14. {$ELSE FPC_DOTTEDUNITS}
  15. uses baseunix,strings;
  16. {$ENDIF FPC_DOTTEDUNITS}
  17. function try_grab_vcsa_in_path(path:PAnsiChar;len:cardinal):boolean;
  18. const grab_vcsa='/grab_vcsa';
  19. grab_vcsa_s:array[1..length(grab_vcsa)] of AnsiChar=grab_vcsa;
  20. var p:PAnsiChar;
  21. child:Tpid;
  22. status:cint;
  23. pstat:stat;
  24. begin
  25. getmem(p,len+length(grab_vcsa)+1);
  26. move(path^,p^,len);
  27. move(grab_vcsa_s,(p+len)^,length(grab_vcsa));
  28. (p+len+length(grab_vcsa))^:=#0;
  29. {Check if file exists.}
  30. if fpstat(p,pstat)<>0 then
  31. begin
  32. try_grab_vcsa_in_path:=false;
  33. exit;
  34. end;
  35. child:=fpfork;
  36. if child=0 then
  37. begin
  38. fpexecve(p,nil,nil);
  39. halt(255); {fpexec must have failed...}
  40. end;
  41. fpwaitpid(child,status,0);
  42. try_grab_vcsa_in_path:=status=0; {Return true if success.}
  43. freemem(p);
  44. end;
  45. function try_grab_vcsa:boolean;
  46. {If we cannot open /dev/vcsa0-31 it usually because we do not have
  47. permission. At login the owner of the tty you login is set to yourself.
  48. This is not done for vcsa, which is kinda strange as vcsa is revoke from
  49. you when you log out. We try to call a setuid root helper which chowns
  50. the vcsa device so we can get access to the screen buffer...}
  51. var path,p:PAnsiChar;
  52. begin
  53. try_grab_vcsa:=false;
  54. path:=fpgetenv('PATH');
  55. if path=nil then
  56. exit;
  57. p:=strscan(path,':');
  58. while p<>nil do
  59. begin
  60. if try_grab_vcsa_in_path(path,p-path) then
  61. begin
  62. try_grab_vcsa:=true;
  63. exit;
  64. end;
  65. path:=p+1;
  66. p:=strscan(path,':');
  67. end;
  68. if try_grab_vcsa_in_path(path,strlen(path)) then
  69. exit;
  70. end;
  71. procedure detect_linuxvcs;
  72. var f:text;
  73. fields:array [0..60] of int64;
  74. fieldct,i:integer;
  75. pid,ppid:longint;
  76. magnitude:int64;
  77. s:string[15];
  78. statln:ansistring;
  79. begin
  80. {Extremely aggressive VCSA detection. Works even through Midnight
  81. Commander. Idea from the C++ Turbo Vision project, credits go
  82. to Martynas Kunigelis <[email protected]>.}
  83. pid:=fpgetpid;
  84. repeat
  85. str(pid,s);
  86. assign(f, '/proc/'+s+'/stat');
  87. {$I-}
  88. reset(f);
  89. {$I+}
  90. if ioresult<>0 then
  91. break;
  92. readln(f, statln);
  93. close(f);
  94. magnitude := 1;
  95. fieldct := 0;
  96. fields[fieldct] := 0;
  97. for i := high(statln) downto low(statln) do
  98. begin
  99. {$push}{$R-} {$Q-}
  100. case statln[i] of
  101. '-': magnitude := -1;
  102. '0'..'9': begin
  103. fields[fieldct] := fields[fieldct]
  104. + (magnitude * (ord(statln[i]) - ord('0')));
  105. magnitude := magnitude * 10;
  106. end;
  107. {$pop}
  108. ' ': begin
  109. magnitude := 1;
  110. fieldct := fieldct + 1;
  111. fields[fieldct] := 0;
  112. end;
  113. else
  114. break;
  115. end;
  116. end;
  117. ppid := pid;
  118. pid := fields[fieldct - 1];
  119. if (fields[fieldct - 4] and $ffffffc0) = $00000400 then {/dev/tty*}
  120. begin
  121. vcs_device:=fields[fieldct - 4] and $3f;
  122. break;
  123. end;
  124. until (fields[fieldct - 4]=0) {Not attached to a terminal, i.e. an xterm.}
  125. or (pid=-1)
  126. or (ppid=pid);
  127. end;
  128. begin
  129. {Put in procedure because there are quite a bit of variables which are made
  130. temporary this way.}
  131. detect_linuxvcs;
  132. end.