I'm not sure if using Spawn
directly is the best way forward here. I would choose one of the following three alternatives for achieving your goal:
1. Use GNAT.OS_Lib.Set_Executable
If all you want is to make the file executable, then use GNAT.OS_Lib.Set_Executable
:
main_v1.adb
with GNAT.OS_Lib; use GNAT.OS_Lib;
procedure Main_v1 is
Name : constant String := "mem.bat";
begin
Set_Executable (Name, Mode => S_Owner);
Set_Executable (Name, Mode => S_Group);
Set_Executable (Name, Mode => S_Others);
end Main_v1;
output
$ touch mem.bat; ll mem.bat
-rw-rw-r--. 1 deedee deedee 0 May 9 21:44 mem.bat
$ ./main_v1; ll mem.bat
-rwxrwxr-x. 1 deedee deedee 0 May 9 21:44 mem.bat
2. Use GNAT.Expect
GNAT.Expect
is included in the GNAT standard library. An example on its use was already shown in this SO answer. You can rework the example for your particular problem.
main_v2.adb
with Ada.Text_IO;
with GNAT.Expect;
procedure Main_v2 is
Command : constant String := "chmod";
Argument_1 : aliased String := "777";
Argument_2 : aliased String := "mem.bat";
Input : constant String := "";
Status : aliased Integer := 0;
-- Execute the command and retrieve the output.
Output : String :=
GNAT.Expect.Get_Command_Output
(Command => Command,
Arguments => (1 => Argument_1'Unchecked_Access,
2 => Argument_2'Unchecked_Access),
Input => Input,
Status => Status'Access,
Err_To_Out => True);
-- NOTE: Cheating with Unchecked_Access, OK for demo. You may want
-- to properly new and Free these strings (see Argument_List
-- type in package GNAT.OS_Lib).
begin
if Status /= 0 then
Ada.Text_IO.Put_Line ("chmod failed: " & Output);
end if;
end Main_v2;
output
$ touch mem.bat && ll mem.bat
-rw-rw-r--. 1 deedee deedee 0 May 9 21:15 mem.bat
$ ./main_v2 && ll mem.bat
-rwxrwxrwx. 1 deedee deedee 0 May 9 21:15 mem.bat
3. Use Florist
As chmod
is a POSIX function, you could also consider to use the Florist library. The Florist library is readily available in distributions like Debian (libflorist), in Alire (only when running on Debian or Ubuntu), or otherwise as source from this repository on GitHub provided by AdaCore.
main_v3.adb
with POSIX.Files;
with POSIX.Permissions;
procedure Main_v3 is
use POSIX.Permissions;
New_Permissions : constant POSIX.Permissions.Permission_Set :=
(Owner_Read => True,
Owner_Write => True,
Owner_Execute => True,
Group_Read => True,
Group_Write => True,
Group_Execute => True,
Others_Read => True,
Others_Write => True,
Others_Execute => True,
others => False);
begin
POSIX.Files.Change_Permissions
(Pathname => "mem.bat",
Permission => New_Permissions);
end Main_v3;
output
$ touch mem.bat && ll mem.bat
-rw-rw-r--. 1 deedee deedee 0 May 9 21:16 mem.bat
$ ./main_v3 && ll mem.bat
-rwxrwxrwx. 1 deedee deedee 0 May 9 21:16 mem.bat
4. Importing chmod
as system call
You can also just import the chmod
directly as a system call. See also man 3p chmod
(or here) for its C signature. Ada has excellent facilities to import C programs as shown in the example below.
main_v4.adb
with Ada.Text_IO;
with Interfaces.C;
with GNAT.OS_Lib;
procedure Main_v4 is
package C renames Interfaces.C;
use type C.int; -- Make operators of C.int (like "<") directly visible.
subtype mode_t is C.unsigned;
function chmod (path : C.char_array; mode : mode_t) return C.int
with Import, Convention => C;
path : aliased C.char_array := C.To_C ("mem.bat");
result : C.int;
begin
result := chmod (path, 8#777#); -- 777 as octal number (base-8)
if result < 0 then
Ada.Text_IO.Put_Line ("chmod failed: " & GNAT.OS_Lib.Errno_Message);
end if;
end Main_v4;
output
$ touch mem.bat && ll mem.bat
-rw-rw-r--. 1 deedee deedee 0 May 9 21:17 mem.bat
$ ./main_v4 && ll mem.bat
-rwxrwxrwx. 1 deedee deedee 0 May 9 21:17 mem.bat