Page 1 of 2

Get full commandline parameters

Posted: Sat Oct 03, 2015 7:49 am
by Keya
Full support - Windows, Linux, Mac OSX, 32+64, Ascii+Unicode.

This gets the full commandline "as is", which can be helpful in times where you just want the commandline as a single string, or when you need to preserve space characters, or need to use speech characters which might otherwise throw off the parser, or dont want to require quotes encapsulation, etc.

The Windows version returns the full result from GetCommandLine(), which is in the form "Executable{space}Commandline", whereas the Linux + OSX versions just return "Commandline", however they also need to read the Executable part in order to get to the Commandline part, so it's very easy to change the result so that they all return "Executable{space}Commandline" (simply return sExePath+" "+sCmdline instead of just sCmdline)

Code: Select all

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
  Import ""
    GetCommandLineW()
  EndImport    
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS   
  ImportC ""
    _NSGetArgv()    ;http://www.opensource.apple.com/source/Libc/Libc-167/headers.subproj/crt_externs.h
  EndImport
CompilerEndIf


Procedure.s GetCmdLine()
  Protected sExePath.s, sCmdline.s, *cmdline
  CompilerIf #PB_Compiler_OS = #PB_OS_Windows
    *cmdline = GetCommandLineW()
    If *cmdline: sCmdline = PeekS(*cmdline,-1,#PB_Unicode): EndIf
  CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS   
    *cmdline = _NSGetArgv()
    If *cmdline
      *cmdline = PeekI(PeekI(*cmdline))      
      sExePath = PeekS(*cmdline,-1,#PB_UTF8)
      sCmdline = PeekS(*cmdline+Len(sExePath)+1,-1,#PB_UTF8)
    EndIf
  CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
    hFile = ReadFile(#PB_Any, "/proc/self/cmdline")
    If hFile
      sExePath = ReadString(hFile, #PB_UTF8)
      sCmdLine = ReadString(hFile, #PB_UTF8)
    EndIf
  CompilerEndIf
  ProcedureReturn sCmdline
EndProcedure


Debug("Full CmdLine=" + GetCmdLine())


; IDE Options = PureBasic 5.31 (MacOS X - x64)
; CommandLine = MY DUMMY CMDLINE

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 7:57 am
by GPI
When you need to pharse space characters, you should put your paras in quotes.

for example:

Code: Select all

dir "c:\program files\*"
instead of

Code: Select all

dir c:\program files\*

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 8:13 am
by Keya
yes but not all users of my program will read the helpfile or necessarily be that familiar with using parameters, and the type of parameter im using doesnt really warrant encapsulation in this case (just extra work for the user), and in not all situations do i want the commandline to be broken down into subparameters, and in some situations i also need the " character as a part of the parameter not acting as a control character, and calling CountProgramParameters() and looping through one-by-one to rebuild the original full string the recreation therefore isnt always character-accurate.

Consider also for example a utility app that just needs to show the commandline parameter of each process, it must get the raw commandline as-is, cannot rely on any user input, and has no need for parsing into subparams :)

That loop is of course all i use most of the time though lol, but yes for this app I need access to the full, raw commandline exactly as it is, so am just sharing in case anybody else might also find it useful.

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 9:00 am
by Vera
Hi Keya,

testing you routine on my Linux didn't output anything, but it created 28 empty files in /proc/self/ which I'm not allowed to remove even with admin-rights.

Why were they created? What are they? How can I remove them?

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 9:01 am
by wilbert
For OSX it would also be possible to access arguments and environment through NSProcessInfo.

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 1:42 pm
by Keya
Vera wrote:Hi Keya,
testing you routine on my Linux didn't output anything, but it created 28 empty files in /proc/self/ which I'm not allowed to remove even with admin-rights.
Why were they created? What are they? How can I remove them?
Well that's no good! It doesn't make the slightest bit of sense to me though ... i mean all it does is call ReadFile() (and ReadString if successful)!?! :| ... so im not sure how on earth a single ReadFile with ReadString is able to create files!?

Which Linux are you using? im using one of the latest Mints (Ubuntu) - if i recall you're using quite an old Linux? but no doubt it has another way to access cmdline! most of my googling seemed to suggest /proc/self/cmdline was the way to go though? perhaps im wrong there

When do you 'ls /proc/self/' from terminal do you not see 'cmdline' amongst a list of ~40 other files? (does '/proc/' even exist?)
And if it is there can you do a 'cat /proc/self/cmdline' ?
Any Linux people here know what on earth might be going on?!?

Anyway thankyou for reporting, this certainly needs to be addressed before any deployment!! but i apologise for the troubles :(

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 2:46 pm
by Oma
Hi Keya and Vera,

i don't know why the cmdline is empty or when is it filled, because i have no experience with it.

But the swarm of empty files are created in the moment in which you open the /proc/self/ - folder.
Defendant: I think you are acquitted as charged. :wink: (was the proper English?)

Bye, Charly

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 2:55 pm
by Keya
Oma so you're experiencing this on your Linux too? which Linux, and what can you do in regards to /proc/ from the terminal? (like my Q's to Vera above) thankyou for help debugging :)

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 3:05 pm
by Keya
wilbert wrote:For OSX it would also be possible to access arguments and environment through NSProcessInfo.
Excellent! thanks :) And just to add to the menu there is also a syscall from 10.6+ that ps etc uses, seems easy enough and can be pointed at any pid :) - https://gist.github.com/nonowarn/770696
but for getting from our own process im guessing _NSGetArgv is best?

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 3:20 pm
by wilbert
Keya wrote:but for getting from our own process im guessing _NSGetArgv is best?
I guess whatever you prefer. :wink:
Sysctl seems like a bit more work to me.

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 3:59 pm
by Oma
Hi Keya,

at the moment my time is very limited, sorry.

I tried it on Kubuntu64 & Xubuntu32 (14.04) & Mint 17.2.
The cmdline is always empty.
The reason is, that in all cases the /proc/self/ - folder is a link.
The links goes to a parallel-folder (1 of a lot folders with a number as name)
If i replace the path in your code with the link, it works. :) [edit]

Now my problem, that I noticed some time ago.
GetFileAttributes("/proc/self/cmdline") & #PB_FileSystem_Link [edit, see below]
should show it as link (4096), but does not. :?: (always 292, ReadUser, ReadGroup, ReadAll)
I don't know if it is a PB- or a Charly-Bug :?:
And i don't know how to follow a link with PB commands.

As quick-help i only have a link on GLib-Level but i'm sure there are simpler solutions (which i don't know at the moment).
http://www.chabba.de/Linux/Misc/File_GetSymLink.pb

Good luck
Charly

PS:
Charly is the bug :lol:
You have to test the folder, not the file and the test works:
GetFileAttributes("/proc/self") & #PB_FileSystem_Link
But the fact remains that i don't know how to follow a link in PB.

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 4:57 pm
by Keya
Oma wrote:But the fact remains that i don't know how to follow a link in PB.
Hmm, LINKS! :) ... Im glad you brought that up (links could be the missing link here! :lol:) because when i was googling yesterday for info about /proc/self/ i came across this:

Code: Select all

lngBuffer = AllocateMemory(2048+1)
lngLen = Readlink_("/proc/" + Str(getpid_()) + "/exe", lngBuffer, 2048)
strOut = GetPathPart(PeekS(lngBuffer, lngLen))
but i figured ReadString was a bit easier, and it worked fine on my linux Mint so i figured it was ok :)

[edit] Well, readlink_() doesnt work on my Mint for "/cmdline", but it works fine for "/exe" like the above demo
So im wondering if you change "/exe" to "/cmdline" in the above does it work on your system??

On my system GetFileAttributes() & #PB_FileSystem_Link returns positive for "/proc/self/exe", and negative for "/proc/self/cmdline"

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 9:04 pm
by Vera
@Keya
- Which Linux are you using? - Suse 11.1
- When do you 'ls /proc/self/' from terminal do you not see 'cmdline' - yes, cmdline is listed (amongst 29 other files)
- does '/proc/' even exist? - sure
- And if it is there can you do a 'cat /proc/self/cmdline' ? - yes
Oma wrote:But the swarm of empty files are created in the moment in which you open the /proc/self/ - folder.
wow - that's nearly like Schrödingers Cat - If you look they are there and if you don't they might not exist.
But that relieves me and it somehow explains why they can't be removed (because they would reapear in the same instant as they vanish) 8)
i don't know why the cmdline is empty or when is it filled
I'm not sure if I understand your question, but I observed, that after I'd applied parameters to the compiler option / commandline parameter those parameters apeared in the debug output (but without showing the complete commandline)

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 9:11 pm
by Keya
yes it can only read the commandline if there is one! otherwise it returns empty string, as it should (although if you also want the executable file/path part thats very easy to get too - the code is already there you just need to return an additional string which im already filling in, see first post)

Oma is that the root of your problem too - not having a commandline set?

I included this in the first post, but maybe your IDE isnt picking it up because of the MacOS bit not being Linux:

Code: Select all

; IDE Options = PureBasic 5.31 (MacOS X - x64)
; CommandLine = MY DUMMY CMDLINE
Im very confused by both your comments and Oma's... you both seem to be suggesting that the call to /proc/self/ is creating those ~28 files
but in my Mint from the terminal i can go to any /proc/ ... say, /proc/13/ which is just one picked at random, type 'ls', and it too has all those files, like cmdline
and i'm only calling ReadFile and ReadString... how can that be creating files? so arent they always there? or does simply the act of opening the directory actually create them? and why cant all linux distros be the same? lol :D

Re: Get full commandline parameters

Posted: Sat Oct 03, 2015 9:33 pm
by Keya
I used this Linux PB code, with the string "MY DUMMY CMDLINE!" set as the commandline in Compiler Options to keep a process with cmdline alive:

Code: Select all

MessageRequester("PID", Str(getpid_()))
And it runs and i get pid 10237 or whatever, so then from my Mint x86 terminal:

Code: Select all

/ $ cd /proc/10237
/proc/10237 $ hexdump -c cmdline
0000000   /   t   m   p   /   p   u   r   e   b   a   s   i   c   _   c
0000010   o   m   p   i   l   a   t   i   o   n   2   .   o   u   t  \0
0000020   M   Y  \0   D   U   M   M   Y  \0   C   M   D   L   I   N   E
0000030   !   \0
Interesting how it has replace the spaces in my commandline with nulls because its not encapsulated