Skip to content

Commit

Permalink
Revert D66719226
Browse files Browse the repository at this point in the history
Summary:
This diff reverts D66719226
(The context such as a Sandcastle job, Task, SEV, etc. was not provided.)

Test Plan:
```
buck2 build mode/opt fbcode//tupperware/image/emulation:emulation.centos9.sendstream.v2 --show-full-output
```

Before and after revert

P1699485763

Reviewed By: jamiecahill

Differential Revision: D67380579

fbshipit-source-id: 194a1e1f99e5cb8c040932c7110c92529bfca62b
  • Loading branch information
generatedunixname89002005232357 authored and facebook-github-bot committed Dec 18, 2024
1 parent f40562b commit d62a4c9
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 364 deletions.
1 change: 0 additions & 1 deletion antlir/antlir2/antlir2_users/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ rust_library(
],
deps = [
"derive_more",
"maplit",
"nix",
"nom",
"serde",
Expand Down
79 changes: 27 additions & 52 deletions antlir/antlir2/antlir2_users/src/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,10 @@
//! under-construction image so that ownership is attributed properly.
use std::borrow::Cow;
use std::collections::btree_map;
use std::collections::btree_map::BTreeMap;
use std::collections::BTreeSet;
use std::fmt::Display;
use std::fmt::Formatter;
use std::str::FromStr;

use maplit::btreemap;
use nom::bytes::complete::take_until;
use nom::bytes::complete::take_until1;
use nom::character::complete::char;
Expand All @@ -39,25 +35,23 @@ use nom::IResult;
use crate::Error;
use crate::GroupId;
use crate::Id;
use crate::Password;
use crate::Result;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EtcGroup<'a> {
// BTreeMap is used to prevent duplicate entries
// with the same groupname.
records: BTreeMap<String, GroupRecord<'a>>,
records: Vec<GroupRecord<'a>>,
}

impl<'a> Default for EtcGroup<'a> {
fn default() -> Self {
Self {
records: btreemap! {
"root".into() => GroupRecord {
name: "root".into(),
gid: GroupId(0),
users: vec!["root".into()],
},
},
records: vec![GroupRecord {
name: "root".into(),
password: Password::Shadow,
gid: GroupId(0),
users: vec!["root".into()],
}],
}
}
}
Expand All @@ -71,15 +65,7 @@ impl<'a> EtcGroup<'a> {
separated_list0(newline, context("GroupRecord", GroupRecord::parse))(input)?;
// eat trailing newlines
let (input, _) = all_consuming(many0(newline))(input)?;
Ok((
input,
Self {
records: records
.into_iter()
.map(|r| (r.name.to_string(), r))
.collect(),
},
))
Ok((input, Self { records }))
}

pub fn parse(input: &'a str) -> Result<Self> {
Expand All @@ -94,26 +80,15 @@ impl<'a> EtcGroup<'a> {
}

pub fn records(&self) -> impl Iterator<Item = &GroupRecord<'a>> {
self.records.values()
self.records.iter()
}

pub fn into_records(self) -> impl Iterator<Item = GroupRecord<'a>> {
self.records.into_values()
self.records.into_iter()
}

pub fn push(&mut self, record: GroupRecord<'a>) -> Result<()> {
match self.records.entry(record.name.to_string()) {
btree_map::Entry::Vacant(e) => {
e.insert(record);
Ok(())
}
btree_map::Entry::Occupied(e) if e.get() == &record => Ok(()),
btree_map::Entry::Occupied(e) => Err(Error::Duplicate(
e.get().name.to_string(),
format!("{:?}", e.get()),
format!("{:?}", record),
)),
}
pub fn push(&mut self, record: GroupRecord<'a>) {
self.records.push(record)
}

pub fn len(&self) -> usize {
Expand All @@ -125,23 +100,23 @@ impl<'a> EtcGroup<'a> {
}

pub fn get_group_by_name(&self, name: &str) -> Option<&GroupRecord<'a>> {
self.records.get(name)
self.records.iter().find(|r| r.name == name)
}

pub fn get_group_by_name_mut(&mut self, name: &str) -> Option<&mut GroupRecord<'a>> {
self.records.get_mut(name)
self.records.iter_mut().find(|r| r.name == name)
}

pub fn get_group_by_id(&self, id: GroupId) -> Option<&GroupRecord<'a>> {
self.records.values().find(|r| r.gid == id)
self.records.iter().find(|r| r.gid == id)
}

pub fn into_owned(self) -> EtcGroup<'static> {
EtcGroup {
records: self
.records
.into_iter()
.map(|(name, record)| (name, record.into_owned()))
.map(GroupRecord::into_owned)
.collect(),
}
}
Expand All @@ -156,12 +131,9 @@ impl FromStr for EtcGroup<'static> {
}
}

// When printing the file, we want to use Ord implementation of GroupRecord.
// This way, the file will resemble a file created the regular way (adduser/addgroup).
impl<'a> Display for EtcGroup<'a> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
let records = self.records.values().collect::<BTreeSet<_>>();
for record in records {
for record in &self.records {
writeln!(f, "{}", record)?;
}
Ok(())
Expand All @@ -170,9 +142,9 @@ impl<'a> Display for EtcGroup<'a> {

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct GroupRecord<'a> {
// Keep as the first field so we sort by it.
pub gid: GroupId,
pub name: Cow<'a, str>,
pub password: Password,
pub gid: GroupId,
pub users: Vec<Cow<'a, str>>,
}

Expand All @@ -182,11 +154,10 @@ impl<'a> GroupRecord<'a> {
E: ParseError<&'a str> + ContextError<&'a str>,
{
let colon = char(':');
let (input, (name, _, _, _, gid, _)) = tuple((
let (input, (name, _, password, _, gid, _)) = tuple((
context("groupname", take_until1(":")),
&colon,
// On modern Unix systems, password field is always "x".
char('x'),
Password::parse,
&colon,
context("gid", nom::character::complete::u32),
&colon,
Expand All @@ -201,6 +172,7 @@ impl<'a> GroupRecord<'a> {
input,
Self {
name: Cow::Borrowed(name),
password,
gid: gid.into(),
users: users.into_iter().map(Cow::Borrowed).collect(),
},
Expand All @@ -210,6 +182,7 @@ impl<'a> GroupRecord<'a> {
pub fn into_owned(self) -> GroupRecord<'static> {
GroupRecord {
name: Cow::Owned(self.name.into_owned()),
password: self.password,
gid: self.gid,
users: self
.users
Expand All @@ -223,7 +196,7 @@ impl<'a> GroupRecord<'a> {

impl<'a> Display for GroupRecord<'a> {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "{}:x:{}:", self.name, self.gid.as_raw())?;
write!(f, "{}:{}:{}:", self.name, self.password, self.gid.as_raw())?;
for (i, u) in self.users.iter().enumerate() {
write!(f, "{u}")?;
if i < self.users.len() - 1 {
Expand Down Expand Up @@ -254,6 +227,7 @@ systemd-journal:x:190:systemd-journald
assert_eq!(
Some(&GroupRecord {
name: "bin".into(),
password: Password::Shadow,
gid: 1.into(),
users: vec!["root".into(), "daemon".into()],
}),
Expand All @@ -268,6 +242,7 @@ systemd-journal:x:190:systemd-journald
assert_eq!(
Some(&GroupRecord {
name: "root".into(),
password: Password::Shadow,
gid: 0.into(),
users: Vec::new()
}),
Expand Down
68 changes: 65 additions & 3 deletions antlir/antlir2/antlir2_users/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
* LICENSE file in the root directory of this source tree.
*/

use std::fmt::Display;
use std::fmt::Formatter;

pub mod group;
pub mod passwd;
pub mod shadow;
Expand All @@ -16,11 +19,9 @@ pub enum Error {
Io(String),
#[error("parse error: {0}")]
Parse(String),
#[error("{0} defined twice, first as {1} and then as {2}")]
Duplicate(String, String, String),
}

pub type Result<T, E = Error> = std::result::Result<T, E>;
pub type Result<T> = std::result::Result<T, Error>;

pub trait Id: Copy + std::fmt::Debug {
fn from_raw(id: u32) -> Self
Expand Down Expand Up @@ -83,3 +84,64 @@ macro_rules! id_type {

id_type!(UserId, nix::unistd::Uid);
id_type!(GroupId, nix::unistd::Gid);

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Password {
Shadow,
Locked,
/// Empty string, login is allowed without a password at all
Empty,
}

impl Password {
pub(crate) fn parse<'a, E>(input: &'a str) -> nom::IResult<&'a str, Self, E>
where
E: nom::error::ParseError<&'a str> + nom::error::ContextError<&'a str>,
{
let (input, txt) = nom::error::context(
"password",
nom::branch::alt((
nom::bytes::complete::tag("x"),
nom::bytes::complete::tag("!"),
nom::bytes::complete::tag(""),
)),
)(input)?;
Ok((
input,
match txt {
"x" => Self::Shadow,
"!" => Self::Locked,
"" => Self::Empty,
_ => unreachable!("parser would have failed"),
},
))
}
}

impl Display for Password {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
Self::Shadow => write!(f, "x"),
Self::Locked => write!(f, "!"),
Self::Empty => write!(f, ""),
}
}
}

#[cfg(test)]
mod tests {
use nom::error::VerboseError;
use rstest::rstest;

use super::*;

#[rstest]
#[case::shadow("x", Password::Shadow)]
#[case::shadow("!", Password::Locked)]
#[case::shadow("", Password::Empty)]
fn test_parse_password(#[case] input: &str, #[case] expected: Password) {
let (rest, pw) = Password::parse::<VerboseError<&str>>(input).expect("failed to parse");
assert_eq!(pw, expected);
assert_eq!(rest, "", "all input should have been consumed");
}
}
Loading

0 comments on commit d62a4c9

Please sign in to comment.