sound_card_init: change config path to /etc/sound_card_init/${sound-card-init-conf}.yaml

To allow using different config files for different projects, this CL:
1. Reads config file path from required command line option
    `--config` in sound_card_init.
2. Passes --config \
    CONFIG=$(cros_config /audio/main sound-card-init-conf) from
    sound_card_init upstart config.

BUG=b:181828415
TEST=/sbin/initctl start sound_card_init SOUND_CARD_ID=sofrt5682

Cq-Depend: chromium:2734495
Cq-Depend: chromium:2733853
Change-Id: I80abbebbc15304bf1a4990a8836d2a6035880006
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/adhd/+/2733862
Tested-by: Judy Hsiao <judyhsiao@chromium.org>
Reviewed-by: Cheng Yueh <cyueh@chromium.org>
Commit-Queue: Judy Hsiao <judyhsiao@chromium.org>
diff --git a/sound_card_init/amp/src/lib.rs b/sound_card_init/amp/src/lib.rs
index 7486ff0..7114233 100644
--- a/sound_card_init/amp/src/lib.rs
+++ b/sound_card_init/amp/src/lib.rs
@@ -7,6 +7,7 @@
 
 mod max98373d;
 mod max98390d;
+use std::path::PathBuf;
 
 use dsm::Error;
 
@@ -19,19 +20,32 @@
 /// It creates `Amp` object based on the sound card name.
 pub struct AmpBuilder<'a> {
     sound_card_id: &'a str,
+    config_path: PathBuf,
 }
 
 impl<'a> AmpBuilder<'a> {
     /// Creates an `AmpBuilder`.
-    pub fn new(sound_card_id: &'a str) -> Self {
-        AmpBuilder { sound_card_id }
+    /// # Arguments
+    ///
+    /// * `card_name` - card name.
+    /// * `conf_file` - config file name.
+    pub fn new(sound_card_id: &'a str, conf_file: &'a str) -> Self {
+        let config_path = PathBuf::from(CONF_DIR).join(conf_file);
+        AmpBuilder {
+            sound_card_id,
+            config_path,
+        }
     }
 
     /// Creates an `Amp` based on the sound card name.
     pub fn build(&self) -> Result<Box<dyn Amp>> {
         match self.sound_card_id {
-            "sofcmlmax98390d" => Ok(Box::new(Max98390::new(self.sound_card_id)?) as Box<dyn Amp>),
-            "sofrt5682" => Ok(Box::new(Max98373::new(self.sound_card_id)?) as Box<dyn Amp>),
+            "sofcmlmax98390d" => {
+                Ok(Box::new(Max98390::new(self.sound_card_id, &self.config_path)?) as Box<dyn Amp>)
+            }
+            "sofrt5682" => {
+                Ok(Box::new(Max98373::new(self.sound_card_id, &self.config_path)?) as Box<dyn Amp>)
+            }
             _ => Err(Error::UnsupportedSoundCard(self.sound_card_id.to_owned())),
         }
     }
diff --git a/sound_card_init/amp/src/max98373d/mod.rs b/sound_card_init/amp/src/max98373d/mod.rs
index 647d22f..1ee29ce 100644
--- a/sound_card_init/amp/src/max98373d/mod.rs
+++ b/sound_card_init/amp/src/max98373d/mod.rs
@@ -8,7 +8,7 @@
 mod dsm_param;
 mod settings;
 
-use std::path::{Path, PathBuf};
+use std::path::Path;
 use std::time::Duration;
 use std::{fs, thread};
 
@@ -16,7 +16,7 @@
 use dsm::{CalibData, Error, Result, SpeakerStatus, ZeroPlayer, DSM};
 use sys_util::info;
 
-use crate::{Amp, CONF_DIR};
+use crate::Amp;
 use dsm_param::*;
 use settings::{AmpCalibSettings, DeviceSettings};
 
@@ -89,6 +89,7 @@
     /// # Arguments
     ///
     /// * `card_name` - card_name.
+    /// * `config_path` - config file path.
     ///
     /// # Results
     ///
@@ -97,12 +98,9 @@
     /// # Errors
     ///
     /// * If `Card` creation from sound card name fails.
-    pub fn new(card_name: &str) -> Result<Self> {
-        let config_path = PathBuf::from(CONF_DIR)
-            .join(card_name)
-            .with_extension("yaml");
-        let conf =
-            fs::read_to_string(&config_path).map_err(|e| Error::FileIOFailed(config_path, e))?;
+    pub fn new(card_name: &str, config_path: &Path) -> Result<Self> {
+        let conf = fs::read_to_string(config_path)
+            .map_err(|e| Error::FileIOFailed(config_path.to_path_buf(), e))?;
         let settings = DeviceSettings::from_yaml_str(&conf)?;
         Ok(Self {
             card: Card::new(card_name)?,
diff --git a/sound_card_init/amp/src/max98390d/mod.rs b/sound_card_init/amp/src/max98390d/mod.rs
index f989255..601165e 100644
--- a/sound_card_init/amp/src/max98390d/mod.rs
+++ b/sound_card_init/amp/src/max98390d/mod.rs
@@ -8,15 +8,12 @@
 mod settings;
 
 use std::time::Duration;
-use std::{
-    fs,
-    path::{Path, PathBuf},
-};
+use std::{fs, path::Path};
 
 use cros_alsa::{Card, IntControl, SwitchControl};
 use dsm::{CalibData, Error, Result, SpeakerStatus, TempConverter, ZeroPlayer, DSM};
 
-use crate::{Amp, CONF_DIR};
+use crate::Amp;
 use settings::{AmpCalibSettings, DeviceSettings};
 
 /// Amp volume mode emulation used by set_volume().
@@ -85,6 +82,7 @@
     /// # Arguments
     ///
     /// * `card_name` - card name.
+    /// * `config_path` - config file path.
     ///
     /// # Results
     ///
@@ -93,12 +91,9 @@
     /// # Errors
     ///
     /// * If `Card` creation from sound card name fails.
-    pub fn new(card_name: &str) -> Result<Self> {
-        let config_path = PathBuf::from(CONF_DIR)
-            .join(card_name)
-            .with_extension("yaml");
-        let conf =
-            fs::read_to_string(&config_path).map_err(|e| Error::FileIOFailed(config_path, e))?;
+    pub fn new(card_name: &str, config_path: &Path) -> Result<Self> {
+        let conf = fs::read_to_string(config_path)
+            .map_err(|e| Error::FileIOFailed(config_path.to_path_buf(), e))?;
         let settings = DeviceSettings::from_yaml_str(&conf)?;
         Ok(Self {
             card: Card::new(card_name)?,
diff --git a/sound_card_init/sound_card_init.conf b/sound_card_init/sound_card_init.conf
index 15c4db8..40bc88f 100644
--- a/sound_card_init/sound_card_init.conf
+++ b/sound_card_init/sound_card_init.conf
@@ -31,42 +31,50 @@
   fi
 end script
 
-# Here (in order) are a list of the args added:
-# --uts: Create and enter new UTS namespace (hostname/NIS domain name).
-# -e: doesn't need network access.
-# -l: process doesn't use SysV shared memory or IPC.
-# -N: doesn't need to modify control groups settings.
-# -v: run inside a new VFS namespace.
-# -p -r: process doesn't need to access other processes in the system.
-# -n: process doesn't need new privileges.
-# -P: set /mnt/empty as the root fs.
-# -b: bind /
-# -k: Get a writeable and empty /run tmpfs path.
-# -b: need /run/cras to connect cras.
-# -b: need /dev to send ioctls to the system's block devices.
-# -k: empty /sys tmpfs path.
-# -b: need /sys/firmware/vpd/ro/ access to read the default calibration value in vpd.
-# -k: get a writeable and empty /var tmpfs path.
-# -b: need /var/lib/sound_card_init/$SOUND_CARD_ID writable access for datastore update.
-# -b: need /var/lib/cras readable
-exec minijail0 \
-    --uts \
-    -e \
-    -l \
-    -N \
-    -v \
-    -p -r \
-    -n \
-    -P /mnt/empty \
-    -b / \
-    -k 'tmpfs,/run,tmpfs,MS_NODEV|MS_NOEXEC|MS_NOSUID,mode=755,size=10M' \
-    -b /run/cras \
-    -b /dev \
-    -k 'tmpfs,/sys,tmpfs,MS_NODEV|MS_NOEXEC|MS_NOSUID,mode=755,size=10M' \
-    -b /sys/firmware/vpd/ro/ \
-    -k 'tmpfs,/var,tmpfs,MS_NODEV|MS_NOEXEC|MS_NOSUID,mode=755,size=10M' \
-    -b /var/lib/sound_card_init/"${SOUND_CARD_ID}"/,,1 \
-    -b /var/lib/cras/ \
-    -u sound_card_init -g sound_card_init -G \
-    -S /usr/share/policy/sound_card_init-seccomp.policy \
-    /usr/bin/sound_card_init "--id=${SOUND_CARD_ID}"
+
+script
+  CONFIG="$(cros_config /audio/main sound-card-init-conf)"
+  if [ -f /etc/sound_card_init/"${CONFIG}" ]; then
+    # Here (in order) are a list of the args added:
+    # --uts: Create and enter new UTS namespace (hostname/NIS domain name).
+    # -e: doesn't need network access.
+    # -l: process doesn't use SysV shared memory or IPC.
+    # -N: doesn't need to modify control groups settings.
+    # -v: run inside a new VFS namespace.
+    # -p -r: process doesn't need to access other processes in the system.
+    # -n: process doesn't need new privileges.
+    # -P: set /mnt/empty as the root fs.
+    # -b: bind /
+    # -k: Get a writeable and empty /run tmpfs path.
+    # -b: need /run/cras to connect cras.
+    # -b: need /dev to send ioctls to the system's block devices.
+    # -k: empty /sys tmpfs path.
+    # -b: need /sys/firmware/vpd/ro/ access to read the default calibration
+    #     value in vpd.
+    # -k: get a writeable and empty /var tmpfs path.
+    # -b: need /var/lib/sound_card_init/$SOUND_CARD_ID writable access for
+    #     datastore update.
+    # -b: need /var/lib/cras readable
+    exec minijail0 \
+        --uts \
+        -e \
+        -l \
+        -N \
+        -v \
+        -p -r \
+        -n \
+        -P /mnt/empty \
+        -b / \
+        -k 'tmpfs,/run,tmpfs,MS_NODEV|MS_NOEXEC|MS_NOSUID,mode=755,size=10M' \
+        -b /run/cras \
+        -b /dev \
+        -k 'tmpfs,/sys,tmpfs,MS_NODEV|MS_NOEXEC|MS_NOSUID,mode=755,size=10M' \
+        -b /sys/firmware/vpd/ro/ \
+        -k 'tmpfs,/var,tmpfs,MS_NODEV|MS_NOEXEC|MS_NOSUID,mode=755,size=10M' \
+        -b /var/lib/sound_card_init/"${SOUND_CARD_ID}"/,,1 \
+        -b /var/lib/cras/ \
+        -u sound_card_init -g sound_card_init -G \
+        -S /usr/share/policy/sound_card_init-seccomp.policy \
+        /usr/bin/sound_card_init "--id=${SOUND_CARD_ID}" "--conf=${CONFIG}"
+  fi
+end script
\ No newline at end of file
diff --git a/sound_card_init/src/main.rs b/sound_card_init/src/main.rs
index 7d6bcc3..806b7d5 100644
--- a/sound_card_init/src/main.rs
+++ b/sound_card_init/src/main.rs
@@ -29,6 +29,7 @@
 #[derive(Default)]
 struct Args {
     pub sound_card_id: String,
+    pub conf: String,
 }
 
 #[sorted]
@@ -58,6 +59,12 @@
 fn parse_args() -> Result<Args> {
     let mut opts = Options::new();
     opts.optopt("", "id", "sound card id", "ID");
+    opts.optopt(
+        "",
+        "conf",
+        "the config file name. It should be $(cros_config /audio/main sound-card-init-conf)",
+        "CONFIG_NAME",
+    );
     opts.optflag("h", "help", "print help menu");
     let matches = opts
         .parse(&env::args().collect::<Vec<_>>()[1..])
@@ -79,13 +86,24 @@
             e
         })?;
 
-    Ok(Args { sound_card_id })
+    let conf = matches
+        .opt_str("conf")
+        .ok_or_else(|| Error::MissingOption("conf".to_owned()))
+        .map_err(|e| {
+            print_usage(&opts);
+            e
+        })?;
+
+    Ok(Args {
+        sound_card_id,
+        conf,
+    })
 }
 
-/// Parses the CONF_DIR/<sound_card_id>.yaml and starts boot time calibration.
+/// Parses the CONF_DIR/${args.conf}.yaml and starts the boot time calibration.
 fn sound_card_init(args: &Args) -> std::result::Result<(), Box<dyn error::Error>> {
-    info!("sound_card_id: {}", args.sound_card_id);
-    AmpBuilder::new(&args.sound_card_id)
+    info!("sound_card_id: {}, conf:{}", args.sound_card_id, args.conf);
+    AmpBuilder::new(&args.sound_card_id, &args.conf)
         .build()?
         .boot_time_calibration()?;