Unix Shell: punkty montowania i urządzenia

Opublikował siefca n 02 lis 2008 16:40:06 GMT

Jakiś czas temu opublikowałem prostą funkcję używającą narzędzia awk, której możesz użyć, aby poznać, jaki jest punkt montowania dla podanego urządzenia. Dzisiaj zamierzam podzielić się zestawem podobnych funkcji, które są nieco ulepszone. Pozwalają one określić punkt montowania dla podanego pliku specjalnego odwołującego się do urządzenia lub zwykłego pliku. Ostatnia z funkcji jest wrapperem, który używa poprzednich, aby uczynić mechanizm prostym w użyciu, gdy dane pochodzą z zewnątrz.

Funkcja getmnt_bydev()

Funkcja zwraca nazwę katalogu będącego punktem zamontowania systemu plików dla wprowadzonego pliku specjalnego reprezentującego urządzenie.

Składnia C

  int getmnt_bydev(char *urządzenie, char *pliki_tablic);
  char *mntpt;

Opis

Na podstawie podanej nazwy pliku urządzenia funkcja getmnt_bydev() tworzy dwa łańcuchy znaków. Jeden jest kopią wprowadzonej nazwy ścieżkowej wiodącej do pliku specjalnego skojarzonego z urządzeniem, a drugi jego przekształceniem do postaci kanonicznej. W tym ostatnim przypadku funkcja używa polecenia readlink, aby uzyskać uproszczoną nazwę, na przykład oczyszczoną ze zbędnych dowiązań symbolicznych i odniesień do katalogu nadrzędnego lub bieżącego. Następnie funkcja wczytuje zawartość plików określonych w zmiennej pliki_tablic (zwyczajowo: /etc/fstab, /etc/mtab i /proc/mounts). Ścieżki te powinny być oddzielone znakiem spacji. Dla każdego rekordu pochodzącego z tych plików pobierane są informacje o urządzeniu i jego punkcie zamontowania. Również w tym przypadku tworzone są dwa warianty informacji: nieprzetworzona i zamieniona na postać kanoniczną. Dla każdej znalezionej w ten sposób nazwy urządzenia dokonywane jest porównanie z dwoma wariantami podanej w argumencie ścieżki. W sumie dla każdego rekordu znalezionego w wymienionych plikach wykonywane są cztery instrukcje warunkowe testujące, czy podana ścieżka pliku urządzenia pasuje do ścieżki znalezionej w zbiorach.

Zwracana wartość

W przypadku znalezienia punktu montowania dla podanego urządzenia w zmiennej o nazwie mntpt zachowywana jest jego ścieżka, a funkcja zwraca 0. Gdy katalog montowania nie został znaleziony zmienna mntpt zawiera łańcuch o zerowej długości, a funkcja zwraca 1.

Kod funkcji

# obtain mount point for a given device file
#
function getmnt_bydev()
{
  local deviceorig="$1"
  local tabfiles="$2"
  local device=$(readlink -m "${deviceorig}" 2>/dev/null \
                || readlink -f "${deviceorig}" 2>/dev/null)

  if [ -z "${tabfiles}" ]; then
      mntpt=""
      return 0
  fi

  mntpt=$(cat ${tabfiles} | \
      awk -v "device=${device}" -v "deviceorig=${deviceorig}" \
              '!/^[[:space:]]*#/ \
         {
           gsub(/#.*/,"");
           tabdevorig=$1; tabmnt=$2;
           if (tabdevorig == "" || tabdevorig == "none" ||
               tabmnt == "none" || tabmnt == "shm") next;
           if (tabdevorig == deviceorig || tabdevorig == device)
               { print tabmnt; exit; }
           command = ("readlink -m " tabdevorig " 2>/dev/null \
                       || readlink -f " tabdevorig " 2>/dev/null");
           (command | getline tabdev);
           close(command);
           if (tabdev == deviceorig || tabdev == device)
              { print tabmnt; exit; }
       }')

  if [ -z "$mntpt" ]; then
      return 1
  else
      return 0
  fi
}

Funkcja getdev_byfile()

Zwraca plik urządzenia, na którym znajduje się plik lub katalog.

Składnia C

  int getdev_byfile(char *ścieżka);
  char *devpt;

Opis

Na podstawie ścieżki funkcja getdev_byfile() tworzy nowy łańcuch znaków. Jest on podaną ścieżką przekształconą do postaci kanonicznej. Funkcja używa w tym celu polecenia readlink, aby uzyskać uproszczoną nazwę, na przykład oczyszczoną ze zbędnych dowiązań symbolicznych i odniesień do katalogu nadrzędnego lub bieżącego. Następnie funkcja rekurencyjnie skraca podaną ścieżkę korzystając z narzędzi dirname i awk, a dla każdej uzyskanej w ten sposób nazwy wywołuje polecenie df. Funkcja próbuje w ten sposób odnaleźć plik specjalny reprezentujący urządzenie, na którym znajduje się podany plik lub katalog. Funkcja sprawdza tylko zamontowane systemy plików, ponieważ tylko je może zbadać używane polecenie df. W większości systemów polecenie df nie wymaga dokładnej ścieżki, więc skracanie nie będzie używane.

Zwracana wartość

W zmiennej o nazwie devpt zawarta jest nazwa pliku specjalnego wskazującego na znalezione urządzenie, a funkcja zwraca 0. Gdy urządzenie nie zostanie znalezione lub wystąpi inny błąd zmienna devpt zawiera łańcuch o zerowej długości, a funkcja zwraca 1. W większości przypadków funkcja zwróci nazwę urządzenia odpowiadającego głównemu systemowi plików, ponieważ dla każdego pliku, dla którego nie znaleziono innego niż główny systemu plików, skracanie ścieżki doprowadzi w końcu do powstania łańcucha /.

Kod funkcji

# obtain filesystem's device file for a given file or a directory
#
function getdev_byfile()
{
  local filenameorig="$1"
  local filename=$(readlink -m "${filenameorig}" 2>/dev/null \
                   || readlink -f "${filenameorig}" 2>/dev/null)

  devpt=$(df -P "${filename}" 2>/dev/null \
                  | awk 'NR==2 && $1~/\// { print $1 }' )
  if [ $? -ne 0 -o -z "${devpt}" ]; then
      dir=$(dirname "${filename}")
      until df -P "${dir}" >/dev/null 2>&1
      do
          dir=$(dirname "${dir}")
      done
      devpt=$(df -P "${dir}" 2>/dev/null \
                      | awk 'NR==2 && $1~/\// { print $1 }' )
      if [ $? -ne 0 ]; then
          devpt=""
      fi
  fi

  if [ -z "$devpt" ]; then
      return 1
  else
      return 0
  fi
}

Funkcja getmnt_byfile()

Zwraca punkt zamontowania dla podanego pliku lub katalogu (skraca ścieżkę do chwili, gdy będzie ona odzwierciedlała punkt zamontowania).

Składnia C

  int getmnt_byfile(char *ścieżka);
  char *mntpt;

Opis

Na podstawie ścieżki funkcja getmnt_byfile() tworzy nowy łańcuch znaków. Jest on podaną ścieżką przekształconą do postaci kanonicznej. Funkcja używa w tym celu polecenia readlink, aby uzyskać uproszczoną nazwę, na przykład oczyszczoną ze zbędnych dowiązań symbolicznych i odniesień do katalogu nadrzędnego lub bieżącego. Następnie funkcja rekurencyjnie skraca podaną ścieżkę korzystając z narzędzi dirname i awk, a dla każdej uzyskanej w ten sposób nazwy wywołuje polecenie df. Funkcja próbuje w ten sposób odnaleźć plik specjalny reprezentujący urządzenie, na którym znajduje się podany plik lub katalog. Funkcja sprawdza tylko zamontowane systemy plików, ponieważ tylko je może zbadać używane polecenie df. W większości systemów polecenie df nie wymaga dokładnej ścieżki, więc skracanie nie będzie używane. Gdy urządzenie zostanie znalezione zwracana jest skojarzony z nim punkt zamontowania.

Zwracana wartość

W zmiennej o nazwie mntpt zawarta jest nazwa katalogu będącego punktem zamontowania dla podanego pliku lub katalogu, a funkcja zwraca 0. Gdy urządzenie odpowiadające plikowi lub katalogowi nie zostanie znalezione lub wystąpi inny błąd zmienna mntpt zawiera łańcuch o zerowej długości, a funkcja zwraca 1. W większości przypadków funkcja zwróci nazwę głównego systemu plików (/), ponieważ dla każdego pliku, dla którego nie znaleziono innego niż główny systemu plików, skracanie ścieżki doprowadzi w końcu do powstania łańcucha /.

Kod funkcji

# obtain filesystem's mount point for a given file or a directory
#
function getmnt_byfile()
{
  local filenameorig="$1"
  local filename=$(readlink -m "${filenameorig}" 2>/dev/null \
            || readlink -f "${filenameorig}" 2>/dev/null)

  mntpt=$(df -P "${filename}" 2>/dev/null \
                  | awk 'NR==2 && $NF~/\// { print $NF }' )
  if [ $? -ne 0 -o -z "${mntpt}" ]; then
      dir=$(dirname "${filename}")
      until df -P "${dir}" >/dev/null 2>&1
      do
          dir=$(dirname "${dir}")
      done
      mntpt=$(df -P "${dir}" 2>/dev/null \
                      | awk 'NR==2 && $NF~/\// { print $NF }' )
      if [ $? -ne 0 ]; then
          mntpt=""
      fi
  fi

  if [ -z "$mntpt" ]; then
      return 1
  else
      return 0
  fi
}

Funkcja getmnt_byfile_off()

Zwraca katalog będący punktem zamontowania dla podanego pliku lub katalogu. Używa pomocniczych plików tablic w formacie fstab.

Składnia C

  int getmnt_byfile_off(char *ścieżka, char *pliki_tablic);
  char *mntpt;

Opis

Na podstawie podanej ścieżki funkcja getmnt_byfile_off() tworzy łańcuch znaków, który jest przekształceniem jej nazwy do postaci kanonicznej. Funkcja używa polecenia readlink, aby uzyskać uproszczoną nazwę, na przykład oczyszczoną ze zbędnych dowiązań symbolicznych i odniesień do katalogu nadrzędnego lub bieżącego. Następnie funkcja wczytuje zawartość plików określonych w zmiennej pliki_tablic (zwyczajowo: /etc/fstab i /etc/mtab). Ścieżki te powinny być oddzielone znakiem spacji. Dla każdego rekordu pochodzącego z tych plików pobierane są informacje o urządzeniu reprezentującym partycję zawierającą system plików i jej punkcie zamontowania. Również w tym przypadku tworzone są dwa warianty informacji: nieprzetworzona i zamieniona na postać kanoniczną. Dla każdej znalezionej w ten sposób nazwy urządzenia dokonywane jest porównanie ze ścieżką. W sumie dla każdego rekordu znalezionego w wymienionych plikach wykonywane są dwie instrukcje warunkowe testujące, czy podana ścieżka pliku urządzenia pasuje do ścieżki znalezionej w zbiorach. Jeśli ścieżka nie została znaleziona cały proces odbywa się jeszcze raz, ale nazwa ścieżki jest skracana o jeden poziom zagłębienia w strukturze katalogów.

Zwracana wartość

W przypadku znalezienia punktu zamontowania dla podanej ścieżki w zmiennej o nazwie mntpt zachowywana jest nazwa odpowiedniego katalogu, a funkcja zwraca 0. Gdy katalog zamontowania nie został znaleziony zmienna mntpt zawiera łańcuch o zerowej długości, a funkcja zwraca 1. W większości przypadków funkcja zwróci nazwę głównego systemu plików (/), ponieważ dla każdego pliku, dla którego nie znaleziono innego niż główny systemu plików, skracanie ścieżki doprowadzi w końcu do powstania łańcucha /.

Kod funkcji

# obtain filesystem's mount point for a given file or a directory
# (semi-offline)
#
function getmnt_byfile_off()
{
  local filenameorig="$1"
  local tabfiles="$2"
  local filename=$(readlink -m "${filenameorig}" 2>/dev/null \
      || readlink -f "${filenameorig}" 2>/dev/null)

  if [ -z "${tabfiles}" ]; then
      mntpt=""
      return 0
  fi

  mntpt=$(awk -v "thefile=${filename}" \
              -v "tabfiles=${tabfiles}" \
  '
  function dirname(dir) {
    arylen=split(dir, ary, /\/+/);
    if (ary[arylen] == "") arylen--;
    if (arylen <= 2) {
      if (ary[1] == "") return "/";
        else return ".";
    }
    name = "";
    for (i=1; i <= arylen-1; i++)
      name = name (i==1?"":"/") ary[i];
      return name;
  }
   
  function examine(mfile,infiles,infileslen) {
    for (x=1; x<=infileslen; x++) {
      if (mfile=="") return "";
      while (getline line < infiles[x]) {
        if (line ~ /^[[:space:]]*#/) continue;
        gsub(/#.*/, "", line);
        if (split(line, tabf, /[[:space:]]+/) < 2) continue;
        tabdev = tabf[1];
        tabmntorig = tabf[2];
        if (tabdev == "" || tabdev == "none" ||
            tabdev == "shm" || tabf[3] == "swap" ||
            tabmntorig == "" ) continue;
        if (tabmntorig == mfile) {
          close(infiles[x]);
          return tabmntorig;
        }
        command = ("readlink -m " tabmntorig " 2>/dev/null \
                                || readlink -f " tabmntorig " 2>/dev/null");
        (command | getline tabmnt);
        close(command);
        if (tabmnt == mfile) {
          close(infiles[x]);
          return tabmnt;
        }
      }
      close(infiles[x]);
    }
    return "";
  }
  BEGIN {
    r="";
    infileslen = split(tabfiles, infiles, " ");
    r = examine(thefile, infiles, infileslen);
    if (r == "") {
      safety=0
      while (thefile != "." && thefile != "/" && safety < 4096) {
        thefile = dirname(thefile);
        r = examine(thefile, infiles, infileslen);
        if (r != "") break;
        safety++;
      }
    }
    print r;
  }')

  if [ -z "$mntpt" ]; then
      return 1
  else
      return 0
  fi
}

Funkcja getmount()

Funkcja zwraca punkt zamontowania dla podanego pliku lub katalogu. Jeśli plik jest plikiem specjalnym reprezentującym urządzenie lub znajduje się w katalogu /dev to poszukiwane jest odwzorowanie w podanych plikach tablic. Dla zwykłych plików lub katalogów skraca ścieżkę do chwili, gdy będzie ona odzwierciedlała punkt zamontowania.

Składnia

  int getmount(char *ścieżka, char *tab_online, char *tab_offline);
  char *mntpt;

Opis

Jest to funkcja opakowująca (ang. wrapper), która wywołuje kilka z wcześniej zaprezentowanych funkcji. Jeśli podana ścieżka jest nazwą pliku specjalnego reprezentującego urządzenie lub prowadzi do zbioru w katalogu /dev to wywoływana jest funkcja getmnt_bydev(), której przekazane zostaną pliki tablic zawarte w zmiennej tab_online (pliki używane przez system, w tym pliki które zawierają informację o zamontowanych zasobach, np. /proc/mounts). Jeśli do czynienia mamy ze zwykłym plikiem to wywoływana jest funkcja getmnt_byfile(). Jeśli zwróci ona łańcuch pusty lub katalog o nazwie / lub ., to wywoływana jest dodatkowo funkcja getmnt_byfile_off(). Przekazana zostaje jej zmienna tab_offline, która powinna zawierać nazwy plików będących tablicami odzwierciedlającymi punkty zamontowania systemów plików (np. /etc/fstab). Jeśli ta wywołana funkcja nie zwróci żadnego rezultatu, to przyjmowany jest wynik poprzednio wywołanej getmnt_byfile() nawet, jeśli było to wskazanie na główny system plików lub katalog bieżący.

Zwracana wartość

W przypadku znalezienia punktu zamontowania dla podanej ścieżki w zmiennej o nazwie mntpt zachowywana jest nazwa odpowiedniego katalogu, a funkcja zwraca 0. Gdy katalog zamontowania nie został znaleziony zmienna mntpt zawiera łańcuch o zerowej długości, a funkcja zwraca 1. W większości przypadków funkcja zwróci nazwę głównego systemu plików (/), ponieważ dla każdego pliku, dla którego nie znaleziono innego niż główny systemu plików, skracanie ścieżki doprowadzi w końcu do powstania łańcucha /.

Kod funkcji

function getmount()
{
    local filename="$1"
    local tabs_on="$2"
    local tabs_off="$3"

    mntpt=""
    if [ -z "${tabs_on}" ]; then
        tabs_on="/etc/fstab /etc/mtab /proc/mounts"
    fi
    if [ -z "${tabs_off}" ]; then
        tabs_off="/etc/fstab /etc/mtab"
    fi

    local devc=$(readlink -m "${filename}" 2>/dev/null \
                 || readlink -f "${filename}" 2>/dev/null)
    local isdev=$(echo "${devc}" | cut -b1-5)
    if [ -b "${filename}" -o -c "${filename}" -o \
            "${isdev}" == "/dev/" -o \
            -b "${devc}" -o -c "${devc}" ]; then
        getmnt_bydev "${filename}" "${tabs_on}"
        return $?
    elif [ ! -e "${filename}" -o -d "${filename}" -o \
             -f "${filename}" -o -L "${filename}" ]; then
        first=""
        getmnt_byfile "${filename}"
        err=$?
        first="${mntpt}"
        if [ $err -ne 0 -o -z "${mntpt}" -o \
             "${mntpt}" = "/" -o "${mntpt}" = "." ]; then
            getmnt_byfile_off "${filename}" "${tabs_off}"
            err=$?
            if [ -z "${mntpt}" -a -n "${first}" ]; then
                mntpt="${first}"
                return 0
            fi
        fi
        return $err
    fi

    return 1
}

Funkcja getdev()

Funkcja zwraca nazwę pliku urządzenia odpowiadającego systemowi plików, na którym znajduje się podany plik lub katalog. Jeśli plik jest plikiem specjalnym lub znajduje się w katalogu /dev, zwracana jest jego niezmieniona nazwa.

Składnia

  int getdev(char *ścieżka);
  char *devpt;

Opis

Jest to funkcja opakowująca (ang. wrapper), która wywołuje kilka z wcześniej zaprezentowanych funkcji. Jeśli podana ścieżka jest nazwą pliku specjalnego reprezentującego urządzenie lub prowadzi do zbioru w katalogu /dev to zwracana jest jej niezmieniona wartość. W przeciwnym wypadku wywoływana jest funkcja getdev_byfile().

Raczej nie zechcesz używać tej funkcji tylko do „oczyszczania” wprowadzonej nazwy ścieżki, ponieważ może ona zwrócić łańcuch / w przypadku braku dopasowania nazwy pliku do któregoś z punktów zamontowania.

Zwracana wartość

W zmiennej o nazwie devpt zawarta jest nazwa pliku specjalnego wskazującego na znalezione urządzenie, a funkcja zwraca 0. Gdy urządzenie nie zostanie znalezione lub wystąpi inny błąd zmienna devpt zawiera łańcuch o zerowej długości, a funkcja zwraca 1. W większości przypadków funkcja zwróci nazwę urządzenia odpowiadającego głównemu systemowi plików, ponieważ dla każdego pliku, dla którego nie znaleziono innego niż główny systemu plików, skracanie ścieżki doprowadzi w końcu do powstania łańcucha /.

Kod funkcji

# obtain device file for a given path
#
function getdev()
{
    local device="$1"

    devpt=""
    local devc=$(readlink -m "${device}" 2>/dev/null \
                || readlink -f "${device}" 2>/dev/null)
    local isdev=$(echo "${isdev}" | cut -b1-5)

    if [ -b "${device}" -o -c "${device}" -o \
           "${isdev}" == "/dev/" -o \
           -b "${devc}" -o -c "${devc}" ]; then
        devpt="${device}"
        ret=0
    else
        getdev_byfile "${device}"
        ret=$?
    fi

    return ${ret}
}

Przykłady użycia

#!/bin/sh

getmnt_bydev "/dev/md0" "/etc/fstab /etc/mtab /proc/mounts"
[ $? = 0 ] && echo "mount point: ${mntpt}"

getdev_byfile "/home/user"
[ $? = 0 ] && echo "device: ${devpt}"

getmnt_byfile "/home/user"
[ $? = 0 ] && echo "mount point: ${mntpt}"

getmnt_byfile_off "/home/user" "/etc/fstab /etc/mtab"
[ $? = 0 ] && echo "mount point: ${mntpt}"

# wrappers
getmount "/dev/md0" "/etc/fstab /etc/mtab /proc/mounts" "/etc/fstab /etc/mtab"
[ $? = 0 ] && echo "mount point: ${mntpt}"
getmount "/home/user" "/etc/fstab /etc/mtab /proc/mounts" "/etc/fstab /etc/mtab"
[ $? = 0 ] && echo "mount point: ${mntpt}"

getdev "/home/user"
[ $? = 0 ] && echo "device: ${devpt}"
getdev "/dev/md0"
[ $? = 0 ] && echo "device: ${devpt}"

Licencja

Copyright © 2008 by Paweł Wilk.

Powyższy program jest rozpowszechniany w nadziei, że będzie przydatny, ale bez żadnych gwarancji – wyrażonych wprost lub domyślnie – w tym bez gwarancji użyteczności lub przydatności do konkretnych celów. Używasz go na własne ryzyko i na własną odpowiedzialność.

Używając zamieszczonego powyżej programu, dystrybuując go, modyfikując lub zapisując go na nośniku służącym do przechowywania informacji, oświadczasz, że posługujesz się językiem angielskim i akceptujesz spisane w tym języku umowne regulacje określające warunki korzystania z programu zwane Licencją. Nazwa tej Licencji to GNU Lesser General Public License w wersji 3, a jej zasady zostały wyłożone w dokumencie dostępnym pod adresem http://www.fsf.org/licensing/licenses/lgpl-3.0.html. Nieoficjalne tłumaczenie Licencji możesz znaleźć na stronie Konrada Stobieckiego . Jeśli nie możesz połączyć się z witryną, na której przedstawiona jest treść Licencji, to aby ją uzyskać napisz pod adres:

Free Software Foundation
51 Franklin Street, Fifth Floor
Boston, MA 02110-1301
USA


This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see http://www.gnu.org/licenses/

Podziel się

Trackbacki

Użyj następującego trackbacka na swojej stronie:

http://randomseed.pl/trackbacks?article_id=unix-shell-punkty-montowania-i-urz%C4%85dzenia&day=02&month=11&year=2008

Komentarze

(leave url/email »)

   Pomoc języka formatowania Obejrzyj komentarz