/volumes_linux.go

https://gitlab.com/rollbrettler/lachs · Go · 128 lines · 105 code · 19 blank · 4 comment · 26 complexity · a270f18b2dae2b5ae803b823ecc09594 MD5 · raw file

  1. package lachs
  2. import (
  3. "bufio"
  4. "bytes"
  5. "log"
  6. "os/exec"
  7. "regexp"
  8. )
  9. var execCommand = exec.Command
  10. var execLookPath = exec.LookPath
  11. var blockDeviceRegex = `(?P<path>.*):(\sSEC_TYPE=\"(.*)\")?(\sLABEL=\"(?P<label>.*)\")?\sUUID=\"(?P<uuid>.*)\"\sTYPE=\"(?P<type>\w*)\"(\sPARTUUID=\"(.*)\")?`
  12. // Volume represents an encrypted volume
  13. type Volume struct {
  14. Path string `json:"path"`
  15. UUID string `json:"uuid"`
  16. Type string `json:"type"`
  17. Unlocked bool `json:"unlocked"`
  18. }
  19. // Open opens the encrypted volume
  20. func (v *Volume) Open(password, mount string) error {
  21. cryptsetup, err := execLookPath("cryptsetup")
  22. if err != nil {
  23. return err
  24. }
  25. cmd := execCommand(cryptsetup, "luksOpen", v.Path, mount)
  26. var stdin bytes.Buffer
  27. stdin.Write([]byte(password))
  28. cmd.Stdin = &stdin
  29. output, err := cmd.Output()
  30. log.Printf("Luks output: %v\n", string(output))
  31. if err != nil {
  32. return err
  33. }
  34. return nil
  35. }
  36. func (v *Volume) isUnlocked() bool {
  37. lsblk, err := execLookPath("lsblk")
  38. if err != nil {
  39. return false
  40. }
  41. cmd := execCommand(lsblk, "-n", "-o", "TYPE", v.Path)
  42. var stderr bytes.Buffer
  43. stderr.Write([]byte(""))
  44. cmd.Stderr = &stderr
  45. out, err := cmd.Output()
  46. if err != nil {
  47. log.Printf("Error from lsblk command: %v | %v | %v\n", err, cmd.Stderr, out)
  48. return false
  49. }
  50. buffer := bytes.NewBuffer(out)
  51. if len(buffer.Bytes()) == 0 {
  52. return false
  53. }
  54. scanner := bufio.NewScanner(buffer)
  55. for scanner.Scan() {
  56. if scanner.Text() == "crypt" {
  57. return true
  58. }
  59. }
  60. return false
  61. }
  62. // Volumes holds all read volumes
  63. type Volumes struct {
  64. List []Volume
  65. }
  66. // Read reads volumes from the underlying system
  67. func (vs *Volumes) Read() error {
  68. blkidPath, err := execLookPath("blkid")
  69. if err != nil {
  70. log.Print("blkid cannot be found in $PATH")
  71. return err
  72. }
  73. out, err := execCommand(blkidPath, "-t", "TYPE=crypto_LUKS").Output()
  74. if err != nil {
  75. log.Printf("Error from blkid command: %v %v\n", err, out)
  76. return err
  77. }
  78. buffer := bytes.NewBuffer(out)
  79. if len(buffer.Bytes()) == 0 {
  80. return nil
  81. }
  82. scanner := bufio.NewScanner(buffer)
  83. for scanner.Scan() {
  84. blockDeviceRegexp, err := regexp.Compile(blockDeviceRegex)
  85. if err != nil {
  86. return err
  87. }
  88. match := blockDeviceRegexp.FindStringSubmatch(scanner.Text())
  89. v := Volume{}
  90. if match != nil {
  91. for i, name := range blockDeviceRegexp.SubexpNames() {
  92. switch name {
  93. case "uuid":
  94. v.UUID = match[i]
  95. case "type":
  96. v.Type = match[i]
  97. case "path":
  98. v.Path = match[i]
  99. }
  100. }
  101. v.Unlocked = v.isUnlocked()
  102. vs.append(v)
  103. }
  104. }
  105. return nil
  106. }
  107. func (vs *Volumes) append(v Volume) {
  108. vs.List = append(vs.List, v)
  109. }