Python 读取umask(线程安全)
我知道用Python读取umask的模式:Python 读取umask(线程安全),python,thread-safety,umask,Python,Thread Safety,Umask,我知道用Python读取umask的模式: current_umask = os.umask(0) # line1 os.umask(current_umask) # line2 return current_umask # line3 但这不是线程安全的 在第1行和第2行之间执行的线程将具有不同的umask 有没有线程安全的方法来读取Python中的umask 相关:如果您的系统在/proc/[pid]/status中有Umask字段,您可以从中读取: impor
current_umask = os.umask(0) # line1
os.umask(current_umask) # line2
return current_umask # line3
但这不是线程安全的
在第1行和第2行之间执行的线程将具有不同的umask
有没有线程安全的方法来读取Python中的umask
相关:如果您的系统在
/proc/[pid]/status
中有Umask
字段,您可以从中读取:
import os
def getumask():
pid = os.getpid()
with open(f'/proc/{pid}/status') as f:
for l in f:
if l.startswith('Umask'):
return int(l.split()[1], base=8)
return None
根据CentOS 7.5和Debian 9.6进行测试
或者,您可以添加线程锁:)子进程继承umask。您可以创建一个管道,派生一个子进程,在那里获取umask并将结果写入管道,以便父进程可以读取它 非常昂贵,但没有任何特殊要求,如
/proc
虚拟文件系统。下面是一个只有低级操作系统调用(所有异步安全)且没有错误检查的示例:
import os
import struct
def get_umask():
pipe = os.pipe()
pid = os.fork()
if pid == 0:
os.close(pipe[0])
umask = os.umask(0)
os.write(pipe[1], struct.pack('H', umask))
os.close(pipe[1])
os._exit(0)
else:
os.close(pipe[1])
value = os.read(pipe[0], 2)
os.close(pipe[0])
os.waitpid(pid, 0)
return struct.unpack('H', value)[0]
print("umask {:03o}".format(get_umask()))
可以通过创建临时文件并检查其权限来确定umask。这应适用于所有*nix系统:
def get_umask():
import os, os.path, random, tempfile
while True:
# Generate a random name
name = 'test'
for _ in range(8):
name += chr(random.randint(ord('a'), ord('z')))
path = os.path.join(tempfile.gettempdir(), name)
# Attempt to create a file with full permissions
try:
fd = os.open(path, os.O_RDONLY|os.O_CREAT|os.O_EXCL, 0o777)
except FileExistsError:
# File exists, try again
continue
try:
# Deduce umask from the file's permission bits
return 0o777 & ~os.stat(fd).st_mode
finally:
os.close(fd)
os.unlink(path)
我所知道的唯一真正、明确的线程安全方式是调用一个新进程
import subprocess
umask_cmd = ('python', '-c', 'import os; print(os.umask(0777))')
umask = int(subprocess.check_output(umask_cmd))
注意,如果您有bash或其他shell,也可以调用它。由于它可能在一个奇怪的系统上,我选择在
umask_cmd
中使用python子进程,因为您必须使用python。如果您使用的是非怪异的*nix系统,那么您可以使用sh或bash。首先为什么需要调用os.umask()
?您通常不需要知道当前的umask。(另外请注意:在线程化环境中使用os.umask(0)
不仅会带来竞争条件的风险,还会导致应用程序出现安全漏洞。您至少需要设置一个限制性掩码,如os.umask(0o777)
@MartijnPieters为什么我想知道umask?我想比较两个环境,并检查两者之间的区别。我想改进我的工具dumpenv:这是一个比大多数人更好的理由来检查当前umask!而不是使用os.getpid()
和插值,您只需从/proc/self/status
中读取即可。如果有人想知道如何测试this@MartijnPietersredhat将此功能后端口到其rhel7/centos7 3.10内核。/proc/self/status
中的umask是八进制的;此代码解析错误它是十进制的。使用int(…,base=8)
。很好的解决方案!我喜欢这个。这段代码不安全。从manfork(2)
:“在多线程程序中使用fork()
后,在调用execve(2)
之前,孩子只能安全地调用异步信号安全函数(请参见信号安全(7)
)问题是Python解释器本身不是异步信号安全的。特别是,几乎任何Python代码都可能导致解释器分配内存,而且大多数内存分配函数都不是异步信号安全的。因此,调用os.fork()永远都不安全
来自多线程程序。@abacabadabacaba我不确定。解释器自己的内存操作应该受到GIL的保护。@GIL的VPfB实现也不是异步信号安全的。3.Python试图使os.fork安全,甚至重新初始化子进程内的各种重要锁。这实际上可以为某些应用程序提供安全性pthread实现,例如glibc在Linux上使用的实现。但是,并非所有实现都能保证这一点,因为没有使用异步信号安全的函数保证fork之后是安全的。@MartijnPietersmkstemp
不允许您指定新文件的权限,因此它不起作用。请使用python库“tempfile”,而不是“TMPDIR=os.environ.get('TMPDIR','/tmp')”umask值通常由子级继承,除非由pythonrc设置。