pythonlinuxrootsu

linux directory permission check and/or dir exist or not


I have a script which is running as a ROOT on linux collecting data from different users. Given a nfs path for each individual user 1) verify the director does not exist 2) verify permission denied

verify_model_path_not_found = '/usr/bin/su ' + userID + ' -c \'/usr/bin/ls ' +  u_model_path + '  | /usr/bin/grep \"Permission denied\|No such file or directory\"\''
perm_denied_str = 'Permission denied'
no_file_dir_str =  'No such file or directory'

print("verify_model_path_not_found:", verify_model_path_not_found)

#Run as a root
try:
    verify_cmd_out = subprocess.check_output(verify_model_path_not_found, shell=True) 
    verify_cmd_out = str(verify_cmd_out)
    print("verify_cmd_out:", verify_cmd_out, "\n")

except subprocess.CalledProcessError as errorcatch:
    print(datetime.datetime.now(), " Error while executing ", verify_model_path_not_found)
    print("error code", errorcatch.returncode, errorcatch.output, "\n")
    continue 

#only add items that are not accessible (perm denied or no file found)
if  ((perm_denied_str in verify_cmd_out) or (no_file_dir_str in verify_cmd_out)):
    #remaining actions .... send an email to the user ...

Example output Error:

verify_model_path_not_found: /usr/bin/su xxxx  -c '/usr/bin/ls /nfs/x/y/z  | /usr/bin/grep "Permission denied\|No such file or directory"'
2021-08-10 17:00:31.827186  Error while executing  /usr/bin/su xxxx -c '/usr/bin/ls /nfs/x/y/z | /usr/bin/grep "Permission denied\|No such file or directory"'
error code 1 b''  #I know this dir does not exist or perm denied - still getting error 

given /nfs/x/y/z, if the user does not have a read access, I would like to get "Permission denied" using grep - "Permission denied" should be the value of verify_cmd_out

given /nfs/x/y/z, if the dir does not exist, I would like to get "No such file or directory" using grep - "No such file or directory" should be the value of verify_cmd_out

once perm denied or no such file is confirmed for the user, certain actions need to place.
The /usr/bin/su xxxx -c ... command is not properly working, any thought or idea how to resolve the issue?


Solution

  • You are examining standard output (file descriptor 1), but error messages (and progress and diagnostics in general) are posted on standard error (file descriptor 2).

    Your code is quite clunky anyway. Probably try something along the lines of

    import subprocess
    
    def assert_error_stderr(cmd, expected_stderr):
        """
        Accept a shell command; verify that it fails with error,
        and emits the expected message on standard error.
        """
        try:
            result = subprocess.run(cmd, check=True, text=True, capture_output=True)
            raise ValueError("%r did not raise an error" % cmd)
        except CalledProcessError:
            assert expected_stderr in result.stderr
    
    def assert_silent_failure(cmd):
        """
        Check that a command fails; verify that standard error is empty
        """
        try:
            result = subprocess.run(cmd, check=True, text=True, capture_output=True)
        except CalledProcessError:
            assert result.stderr == ''
        raise ValueError("%r did not fail", cmd)
    
    assert_silent_failure(['su', '-c' 'test -d ' + u_model_path])
    ...
    

    but of course using Python when you fundamentally want to test the shell might not make much sense.

    #!/bin/sh
    ! test -d "$1"
    

    Basically never use ls in scripts and generally probably don't rely on a particular error message (it could be localized, or change between versions).

    Also, in Python subprocess code, avoid shell=True whenever you can. See also Actual meaning of shell=True in subprocess