diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index c529c6b847..e10d0b6093 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -309,27 +309,65 @@ impl ProcScheme { } OpenTy::Auth => { extern "C" fn ret() {} - let context = match operation_str.ok_or(Error::new(ENOENT))? { - "new-context" => { - let id = NonZeroUsize::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)) - .ok_or(Error::new(EMFILE))?; - let context = context::spawn(true, Some(id), ret, token)?; - { - let parent_groups = - context::current().read(token.token()).groups.clone(); - context.write(token.token()).groups = parent_groups; - } - HANDLES.write(token.token()).insert( - id.get(), - Handle { - context, - kind: ContextHandle::OpenViaDup, - }, - ); - return Ok((id.get(), InternalFlags::empty())); + let operation_str = operation_str.ok_or(Error::new(ENOENT))?; + // The relibc fork's pthread_setname_np / getname_np / + // setaffinity_np / getaffinity_np all use the path + // format "proc:{thread_fd}/" via a single + // Sys::open() call. To support this, we need to parse + // the leading numeric prefix as a context id and the + // remaining suffix as the sub-handle path. The + // existing "new-context" and "cur-context" arms are + // kept for the "literal" paths that don't have a + // numeric prefix. + let context = if operation_str == "new-context" { + let id = NonZeroUsize::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)) + .ok_or(Error::new(EMFILE))?; + let context = context::spawn(true, Some(id), ret, token)?; + { + let parent_groups = + context::current().read(token.token()).groups.clone(); + context.write(token.token()).groups = parent_groups; } - "cur-context" => context::current(), - _ => return Err(Error::new(ENOENT)), + HANDLES.write(token.token()).insert( + id.get(), + Handle { + context: context.clone(), + kind: ContextHandle::OpenViaDup, + }, + ); + return Ok((id.get(), InternalFlags::empty())); + } else if operation_str == "cur-context" { + context::current() + } else if let Some(slash) = operation_str.find('/') { + // Path format "/" used by + // relibc's pthread_setname_np / getname_np / + // setaffinity_np / getaffinity_np. Split on the + // first '/' to get the numeric context id and + // the sub-handle name. Look up the context by id + // in the HANDLES map. + let id_str = &operation_str[..slash]; + let sub_path = &operation_str[slash + 1..]; + let id = id_str.parse::().map_err(|_| Error::new(EINVAL))?; + let context = { + let handles = HANDLES.read(token.token()); + let handle = handles.get(&id).ok_or(Error::new(ENOENT))?; + if !matches!( + handle.kind, + ContextHandle::OpenViaDup | ContextHandle::Authority + ) { + return Err(Error::new(ENOENT)); + } + handle.context.clone() + }; + // Re-call openat_context with the sub-path. This + // is a recursive open_inner which works because + // openat_context doesn't depend on the open + // path's Authority state. + return self + .open_inner(OpenTy::Ctxt(context), Some(sub_path), _flags, token) + .map(|(id, flags)| (id, flags)); + } else { + return Err(Error::new(ENOENT)); }; (