wifi_linux.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. // +build linux
  2. package wifi
  3. import (
  4. "errors"
  5. "io/ioutil"
  6. "log"
  7. "os"
  8. "os/exec"
  9. "path/filepath"
  10. "sort"
  11. "strconv"
  12. "strings"
  13. "time"
  14. "github.com/valyala/fasttemplate"
  15. )
  16. //Toggle WiFi On Off. Only allow on sudo mode
  17. func (w *WiFiManager) SetInterfacePower(wlanInterface string, on bool) error {
  18. status := "up"
  19. if on == false {
  20. status = "down"
  21. }
  22. cmd := exec.Command("ifconfig", wlanInterface, status)
  23. out, err := cmd.CombinedOutput()
  24. if err != nil {
  25. log.Println("*WiFi* WiFi toggle failed: ", string(out))
  26. return err
  27. }
  28. //OK
  29. return nil
  30. }
  31. func (w *WiFiManager) GetInterfacePowerStatuts(wlanInterface string) (bool, error) {
  32. //Check if interface is in list
  33. interfaceList, err := w.GetWirelessInterfaces()
  34. if err != nil {
  35. return false, err
  36. }
  37. interfaceExists := false
  38. for _, localInterface := range interfaceList {
  39. if localInterface == wlanInterface {
  40. interfaceExists = true
  41. }
  42. }
  43. if !interfaceExists {
  44. return false, errors.New("wlan Interface not exists")
  45. }
  46. //Check if the interface appears in ifconfig. If yes, this interface is online
  47. cmd := exec.Command("bash", "-c", "ifconfig | grep "+wlanInterface)
  48. out, err := cmd.CombinedOutput()
  49. if err != nil {
  50. return false, errors.New(string(out))
  51. }
  52. if strings.TrimSpace(string(out)) != "" {
  53. //Interface exists in ifconfig. Report it as powered on
  54. return true, nil
  55. } else {
  56. return false, nil
  57. }
  58. }
  59. //Scan Nearby WiFi
  60. func (w *WiFiManager) ScanNearbyWiFi(interfaceName string) ([]WiFiInfo, error) {
  61. rcmd := `iwlist ` + interfaceName + ` scan`
  62. if w.sudo_mode {
  63. rcmd = "sudo " + rcmd
  64. }
  65. cmd := exec.Command("bash", "-c", rcmd)
  66. out, err := cmd.CombinedOutput()
  67. if err != nil {
  68. //Scan failed, the following code is used to handle edge case on some SBC that only nmcli works but not iwlist
  69. /*
  70. If the interface is not supported, something like this will show up:
  71. wlan0 Interface doesn't support scanning.
  72. */
  73. if strings.Contains(string(out), "Interface doesn't support scanning") {
  74. //Try nmcli instead if exists
  75. if pkg_exists("nmcli") {
  76. log.Println("*WiFi* Running WiFi scan in nmcli compatibility mode")
  77. cmd := exec.Command("bash", "-c", "nmcli d wifi list")
  78. out, err := cmd.CombinedOutput()
  79. if err != nil {
  80. return []WiFiInfo{}, err
  81. }
  82. //Parse the nmcli output
  83. lines := strings.Split(string(out), "\n")
  84. if len(lines) > 1 {
  85. //Remove the header
  86. lines = lines[1:]
  87. }
  88. results := []WiFiInfo{}
  89. //Prase the wifi information
  90. for _, line := range lines {
  91. //Replace all double space as split sign
  92. line = strings.TrimSpace(line)
  93. for strings.Contains(line, " ") {
  94. line = strings.ReplaceAll(line, " ", "$")
  95. }
  96. for strings.Contains(line, "$$") {
  97. line = strings.ReplaceAll(line, "$$", "$")
  98. }
  99. //Process the wifi info chunk
  100. wifiInfoSlice := strings.Split(line, "$")
  101. thisWifiInfo := new(WiFiInfo)
  102. if len(wifiInfoSlice) == 7 {
  103. //This is a valid entry
  104. thisWifiInfo.ESSID = strings.TrimSpace(wifiInfoSlice[0])
  105. thisWifiInfo.Quality = wifiInfoSlice[4] + "/100"
  106. thisWifiInfo.Frequency = wifiInfoSlice[3]
  107. channel, _ := strconv.Atoi(wifiInfoSlice[2])
  108. thisWifiInfo.Channel = channel
  109. thisWifiInfo.SignalLevel = w.getSignalLevelEstimation(wifiInfoSlice[5])
  110. //Check connect before
  111. if w.database.KeyExists("wifi", thisWifiInfo.ESSID) {
  112. thisWifiInfo.ConnectedBefore = true
  113. } else {
  114. thisWifiInfo.ConnectedBefore = false
  115. }
  116. } else if len(wifiInfoSlice) == 8 {
  117. //Entry with inuse * at front
  118. thisWifiInfo.ESSID = strings.TrimSpace(wifiInfoSlice[1])
  119. thisWifiInfo.Quality = wifiInfoSlice[5] + "/100"
  120. thisWifiInfo.Frequency = wifiInfoSlice[4]
  121. channel, _ := strconv.Atoi(wifiInfoSlice[2])
  122. thisWifiInfo.Channel = channel
  123. thisWifiInfo.SignalLevel = w.getSignalLevelEstimation(wifiInfoSlice[6])
  124. thisWifiInfo.ConnectedBefore = true //It is connected
  125. } else {
  126. //Line not valid. Skip this line
  127. continue
  128. }
  129. results = append(results, *thisWifiInfo)
  130. }
  131. return results, nil
  132. } else {
  133. log.Println("*WiFi* Scan Failed: ", err.Error())
  134. return []WiFiInfo{}, errors.New("Interface doesn't support scanning")
  135. }
  136. }
  137. return []WiFiInfo{}, err
  138. }
  139. //parse the output of the WiFi Scan
  140. lines := strings.Split(strings.TrimSpace(string(out)), "\n")
  141. for i, thisline := range lines {
  142. lines[i] = strings.TrimSpace(thisline)
  143. }
  144. //Ignore first line if it contains "Scan completed"
  145. if strings.Contains(lines[0], "Scan completed") {
  146. lines = lines[1:]
  147. }
  148. var results = []WiFiInfo{}
  149. //Loop through each line and construct the WiFi Info slice
  150. processingWiFiNode := new(WiFiInfo)
  151. for _, line := range lines {
  152. if strings.Contains(line, "Address: ") {
  153. //Push the previous results into results and create a new Node
  154. if processingWiFiNode.Address != "" {
  155. //Check if the ESSID already exists
  156. if pkg_exists("nmcli") {
  157. //Make use of nmcli storage
  158. if w.database.KeyExists("wifi", processingWiFiNode.ESSID) {
  159. processingWiFiNode.ConnectedBefore = true
  160. } else {
  161. processingWiFiNode.ConnectedBefore = false
  162. }
  163. } else {
  164. //Direct access to wpa_supplicant
  165. if fileExists("./system/network/wifi/ap/" + processingWiFiNode.ESSID + ".config") {
  166. processingWiFiNode.ConnectedBefore = true
  167. } else {
  168. processingWiFiNode.ConnectedBefore = false
  169. }
  170. }
  171. results = append(results, *processingWiFiNode)
  172. processingWiFiNode = new(WiFiInfo)
  173. }
  174. //Analysis this node
  175. datachunk := strings.Split(line, " ")
  176. if len(datachunk) > 0 {
  177. processingWiFiNode.Address = datachunk[len(datachunk)-1]
  178. }
  179. } else if strings.Contains(line, "Channel") && strings.Contains(line, "Frequency") == false {
  180. datachunk := strings.Split(line, ":")
  181. if len(datachunk) > 0 {
  182. channel, err := strconv.Atoi(datachunk[len(datachunk)-1])
  183. if err != nil {
  184. channel = -1
  185. }
  186. processingWiFiNode.Channel = channel
  187. }
  188. } else if strings.Contains(line, "Frequency") {
  189. tmp := strings.Split(line, ":")
  190. if len(tmp) > 0 {
  191. frequencyData := tmp[len(tmp)-1]
  192. frequencyDataChunk := strings.Split(frequencyData, " ")
  193. if len(frequencyDataChunk) > 1 {
  194. frequencyString := frequencyDataChunk[:2]
  195. processingWiFiNode.Frequency = strings.Join(frequencyString, " ")
  196. }
  197. }
  198. } else if strings.Contains(line, "Quality=") {
  199. //Need to seperate quality data from signal level. Example source: Quality=70/70 Signal level=-40 dBm
  200. analysisItem := strings.Split(line, " ")
  201. if len(analysisItem) == 2 {
  202. //Get the quality of connections
  203. processingWiFiNode.Quality = analysisItem[0][8:]
  204. //Get the signal level of the connections
  205. processingWiFiNode.SignalLevel = analysisItem[1][13:]
  206. }
  207. } else if strings.Contains(line, "Encryption key") {
  208. ek := strings.Split(line, ":")
  209. if len(ek) > 0 {
  210. status := ek[1]
  211. if status == "on" {
  212. processingWiFiNode.EncryptionKey = true
  213. } else {
  214. processingWiFiNode.EncryptionKey = false
  215. }
  216. }
  217. } else if strings.Contains(line, "ESSID") {
  218. iddata := strings.Split(line, ":")
  219. if len(iddata) > 0 {
  220. ESSID := iddata[1]
  221. ESSID = strings.ReplaceAll(ESSID, "\"", "")
  222. if ESSID == "" {
  223. ESSID = "Hidden Network"
  224. }
  225. processingWiFiNode.ESSID = ESSID
  226. }
  227. }
  228. }
  229. return results, nil
  230. }
  231. //Hack the signal level out of the nmcli bars
  232. func (w *WiFiManager) getSignalLevelEstimation(bar string) string {
  233. bar = strings.TrimSpace(bar)
  234. if bar == "▂▄▆█" {
  235. return "-45 dBm[Estimated]"
  236. } else if bar == "▂▄▆_" {
  237. return "-55 dBm[Estimated]"
  238. } else if bar == "▂▄__" {
  239. return "-75 dBm[Estimated]"
  240. } else if bar == "▂___" {
  241. return "-85 dBm[Estimated]"
  242. } else {
  243. return "-95 dBm[Estimated]"
  244. }
  245. }
  246. //Get all the network interfaces
  247. func (w *WiFiManager) GetWirelessInterfaces() ([]string, error) {
  248. rcmd := `iw dev | awk '$1=="Interface"{print $2}'`
  249. cmd := exec.Command("bash", "-c", rcmd)
  250. out, err := cmd.CombinedOutput()
  251. if err != nil {
  252. return []string{}, errors.New(string(out))
  253. }
  254. interfaces := strings.Split(strings.TrimSpace(string(out)), "\n")
  255. //sort.Strings(interfaces)
  256. sort.Sort(sort.StringSlice(interfaces))
  257. return interfaces, nil
  258. }
  259. func (w *WiFiManager) ConnectWiFi(ssid string, password string, connType string, identity string) (*WiFiConnectionResult, error) {
  260. //Build the network config file
  261. //Updates 21-10-2020, use nmcli if exists
  262. if pkg_exists("nmcli") {
  263. oldSSID, _, _ := w.GetConnectedWiFi()
  264. if ssid != "" {
  265. //There is an existing connection to another wifi AP. Disconnect it
  266. cmd := exec.Command("nmcli", "con", "down", oldSSID)
  267. out, err := cmd.CombinedOutput()
  268. if err != nil {
  269. log.Println("*WiFi* Connecting previous SSID failed: " + string(out))
  270. log.Println("*WiFi* Trying to connect new AP anyway")
  271. }
  272. }
  273. if connType == "switch" {
  274. //Load ssid and password from database
  275. w.database.Write("wifi", ssid, &password)
  276. }
  277. //Try to connect the new AP
  278. cmd := exec.Command("nmcli", "device", "wifi", "connect", ssid, "password", password)
  279. out, err := cmd.CombinedOutput()
  280. if err != nil {
  281. log.Println("*WiFi* Connecting to SSID " + ssid + " failed: " + string(out))
  282. return &WiFiConnectionResult{Success: false}, errors.New(string(out))
  283. }
  284. if connType != "switch" {
  285. //Save the ssid and password to database
  286. w.database.Write("wifi", ssid, password)
  287. }
  288. log.Println(string(out))
  289. //Check and return the current connection ssid
  290. //Wait until the WiFi is conencted
  291. rescanCount := 0
  292. connectedSSID, _, _ := w.GetConnectedWiFi()
  293. //Wait for 30 seconds
  294. for rescanCount < 10 && connectedSSID == "" {
  295. connectedSSID, _, _ = w.GetConnectedWiFi()
  296. log.Println(connectedSSID)
  297. rescanCount = rescanCount + 1
  298. log.Println("*WiFi* Waiting WiFi Connection (Retry " + strconv.Itoa(rescanCount) + "/10)")
  299. time.Sleep(3 * time.Second)
  300. }
  301. return &WiFiConnectionResult{
  302. ConnectedSSID: connectedSSID,
  303. Success: true,
  304. }, nil
  305. }
  306. //DO NOT TOUCH THE INDENTATION!! THEY MUST BE KEEP LIKE THIS
  307. writeToConfig := true
  308. networkConfigFile := ""
  309. if connType == "" {
  310. //Home use network / WPA2
  311. if password == "" {
  312. //No need password
  313. networkConfigFile = `network={
  314. ssid="` + ssid + `"
  315. key_mgmt=NONE
  316. priority={{priority}}
  317. }`
  318. } else {
  319. networkConfigFile = `network={
  320. ssid="` + ssid + `"
  321. psk="` + password + `"
  322. priority={{priority}}
  323. }`
  324. }
  325. } else if connType == "WPA-EAP" {
  326. if identity == "" {
  327. return &WiFiConnectionResult{Success: false}, errors.New("Identify not defined")
  328. }
  329. networkConfigFile = `network={
  330. ssid="` + ssid + `"
  331. key_mgmt=WPA-EAP
  332. identity="` + identity + `"
  333. password="` + password + `"
  334. }`
  335. } else if connType == "switch" {
  336. //Special case, for handling WiFi Switching without retyping the password
  337. writeToConfig = false
  338. } else {
  339. log.Println("*WiFi* Unsupported connection type")
  340. return &WiFiConnectionResult{Success: false}, errors.New("Unsupported Connection Type")
  341. }
  342. //Generate new wpa_supplicant_conf from file
  343. if !fileExists("./system/network/wifi/ap") {
  344. os.MkdirAll("./system/network/wifi/ap", 0755)
  345. }
  346. if writeToConfig == true {
  347. log.Println("*WiFi* WiFi Config Generated. Writing to file...")
  348. //Write config file to disk
  349. err := ioutil.WriteFile("./system/network/wifi/ap/"+ssid+".config", []byte(networkConfigFile), 0755)
  350. if err != nil {
  351. log.Println(err.Error())
  352. return &WiFiConnectionResult{Success: false}, err
  353. }
  354. } else {
  355. log.Println("*WiFi* Switching WiFi AP...")
  356. }
  357. //Start creating the new wpa_supplicant file
  358. //Get header
  359. configHeader, err := ioutil.ReadFile("./system/network/wifi/wpa_supplicant.conf_template.config")
  360. if err != nil {
  361. //Template header not found. Use default one from Raspberry Pi
  362. log.Println("*WiFi* Warning! wpa_supplicant template file not found. Using default template.")
  363. configHeader = []byte(`ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
  364. update_config=1
  365. {{networks}}
  366. `)
  367. }
  368. //Build network informations
  369. networksConfigs, err := filepath.Glob("./system/network/wifi/ap/*.config")
  370. if err != nil {
  371. log.Println(err.Error())
  372. return &WiFiConnectionResult{Success: false}, err
  373. }
  374. //Read each of the network and append it into a string slice
  375. networks := []string{}
  376. for _, configFile := range networksConfigs {
  377. thisNetworkConfig, err := ioutil.ReadFile(configFile)
  378. if err != nil {
  379. log.Println("*WiFi* Failed to read Network Config File: " + configFile)
  380. continue
  381. }
  382. if strings.TrimSuffix(filepath.Base(configFile), filepath.Ext(configFile)) == ssid {
  383. //The new SSID. Set this to higher priority
  384. networks = append(networks, template_apply(string(thisNetworkConfig), map[string]interface{}{
  385. "priority": strconv.Itoa(1),
  386. }))
  387. } else {
  388. //Old SSID. Use default priority
  389. networks = append(networks, template_apply(string(thisNetworkConfig), map[string]interface{}{
  390. "priority": strconv.Itoa(0),
  391. }))
  392. }
  393. }
  394. //Subsitute the results into the template
  395. networksConfigString := strings.Join(networks, "\n")
  396. newconfig := template_apply(string(configHeader), map[string]interface{}{
  397. "networks": networksConfigString,
  398. })
  399. //Try to write the new config to wpa_supplicant
  400. err = ioutil.WriteFile(w.wpa_supplicant_path, []byte(newconfig), 0777)
  401. if err != nil {
  402. log.Println("*WiFi* Failed to update wpa_supplicant config, are you sure you have access permission to that file?")
  403. return &WiFiConnectionResult{Success: false}, err
  404. }
  405. log.Println("*WiFi* WiFi Config Updated. Restarting Wireless Interfaces...")
  406. //Restart network services
  407. cmd := exec.Command("wpa_cli", "-i", w.wan_interface_name, "reconfigure")
  408. out, err := cmd.CombinedOutput()
  409. if err != nil {
  410. //Maybe the user forgot to set the flag. Try auto detect.
  411. autoDetectedWIface, err := w.GetWirelessInterfaces();
  412. if err != nil || len(autoDetectedWIface) == 0{
  413. log.Println("failed to restart network: " + string(out))
  414. return &WiFiConnectionResult{Success: false}, err
  415. }
  416. firstWlanInterface := autoDetectedWIface[0]
  417. cmd := exec.Command("wpa_cli", "-i", firstWlanInterface, "reconfigure")
  418. out, err := cmd.CombinedOutput()
  419. if err != nil {
  420. //Really failed.
  421. log.Println("failed to restart network: " + string(out))
  422. return &WiFiConnectionResult{Success: false}, err
  423. }
  424. }
  425. log.Println("*WiFi* Trying to connect new AP")
  426. //Wait until the WiFi is conencted
  427. rescanCount := 0
  428. connectedSSID, _, _ := w.GetConnectedWiFi()
  429. //Wait for 30 seconds
  430. for rescanCount < 10 && connectedSSID == "" {
  431. connectedSSID, _, _ = w.GetConnectedWiFi()
  432. log.Println(connectedSSID)
  433. rescanCount = rescanCount + 1
  434. log.Println("*WiFi* Waiting WiFi Connection (Retry " + strconv.Itoa(rescanCount) + "/10)")
  435. time.Sleep(3 * time.Second)
  436. }
  437. result := new(WiFiConnectionResult)
  438. if (rescanCount) >= 10 {
  439. result.Success = false
  440. } else {
  441. result.ConnectedSSID = connectedSSID
  442. result.Success = true
  443. }
  444. return result, nil
  445. }
  446. //Get the current connected wifi, return ESSID, wifi interface name and error if any
  447. //Return ESSID, interface and error
  448. func (w *WiFiManager) GetConnectedWiFi() (string, string, error) {
  449. cmd := exec.Command("iwgetid")
  450. out, err := cmd.CombinedOutput()
  451. if err != nil {
  452. //Check nmcli working or not
  453. if pkg_exists("nmcli") {
  454. //Try nmcli method instead
  455. cmd := exec.Command("nmcli", "-t", "-f", "NAME,DEVICE", "connection", "show", "--active")
  456. out, err := cmd.CombinedOutput()
  457. if err != nil {
  458. return "", "", errors.New(string(out))
  459. }
  460. //nmcli return something. Use the first one
  461. outString := strings.TrimSpace(string(out))
  462. currentSSIDInfo := ""
  463. if strings.Contains(outString, "\n") {
  464. connectedIds := strings.Split(outString, "\n")
  465. for _, conn := range connectedIds {
  466. if !strings.Contains(conn, "Wired") {
  467. //The first connection that is not wired
  468. currentSSIDInfo = conn
  469. break
  470. }
  471. }
  472. } else {
  473. currentSSIDInfo = outString
  474. }
  475. if strings.Contains(currentSSIDInfo, "Wired") {
  476. //This is an ethernet port?
  477. //Nothing connected
  478. return "OFFLINE", "N/A", nil
  479. }
  480. if currentSSIDInfo == "" {
  481. //No connection to any interface, which is strange?
  482. return "", "", errors.New("No established connection")
  483. }
  484. //Split the information
  485. SSIDinfoChunk := strings.Split(currentSSIDInfo, ":")
  486. currentSSID := SSIDinfoChunk[0]
  487. interfaceName := SSIDinfoChunk[1]
  488. return currentSSID, interfaceName, nil
  489. } else {
  490. return "", "", errors.New(string(out))
  491. }
  492. return "", "", errors.New(string(out))
  493. }
  494. if len(string(out)) == 0 {
  495. return "OFFLINE", "N/A", nil
  496. }
  497. //Try to parse the data
  498. trimmedData := string(out)
  499. for strings.Contains(trimmedData, " ") {
  500. trimmedData = strings.ReplaceAll(trimmedData, " ", " ")
  501. }
  502. dc := strings.Split(trimmedData, " ")
  503. if len(dc) == 0 {
  504. return "", "", errors.New("No valid wlan Interface Found")
  505. }
  506. wlanInterface := dc[0]
  507. ESSID := strings.Join(dc[1:], " ")[7:]
  508. ESSID = strings.TrimSpace(ESSID)
  509. ESSID = ESSID[:len(ESSID)-1]
  510. if strings.TrimSpace(ESSID) == "\"" {
  511. ESSID = ""
  512. }
  513. return ESSID, wlanInterface, nil
  514. }
  515. func (w *WiFiManager) CheckInterfaceIsAP(wlanInterfaceName string) (bool, error) {
  516. cmd := exec.Command("bash", "-c", "iwconfig wlan1 | grep Mode")
  517. out, err := cmd.CombinedOutput()
  518. if err != nil {
  519. return false, err
  520. }
  521. if len(string(out)) == 0 {
  522. return false, errors.New("Missing iwconfig package")
  523. }
  524. //Check if the output contains Mode:Master
  525. if strings.Contains(string(out), "Mode:Master") {
  526. return true, nil
  527. } else {
  528. return false, nil
  529. }
  530. }
  531. func (w *WiFiManager) RemoveWifi(ssid string) error {
  532. if pkg_exists("nmcli") {
  533. //Make use of nmcli storage
  534. if w.database.KeyExists("wifi", ssid) {
  535. w.database.Delete("wifi", ssid)
  536. }
  537. } else {
  538. //Fall back to systemctl
  539. if !fileInDir("./system/network/wifi/ap/"+ssid+".config", "./system/network/wifi/ap/") {
  540. return errors.New("Invalid SSID")
  541. }
  542. if fileExists("./system/network/wifi/ap/" + ssid + ".config") {
  543. os.Remove("./system/network/wifi/ap/" + ssid + ".config")
  544. } else {
  545. return errors.New("Record not found")
  546. }
  547. }
  548. return nil
  549. }
  550. //Helper functions
  551. func fileInDir(filesourcepath string, directory string) bool {
  552. filepathAbs, err := filepath.Abs(filesourcepath)
  553. if err != nil {
  554. return false
  555. }
  556. directoryAbs, err := filepath.Abs(directory)
  557. if err != nil {
  558. return false
  559. }
  560. //Check if the filepathabs contain directoryAbs
  561. if strings.Contains(filepathAbs, directoryAbs) {
  562. return true
  563. } else {
  564. return false
  565. }
  566. }
  567. func fileExists(filename string) bool {
  568. _, err := os.Stat(filename)
  569. if os.IsNotExist(err) {
  570. return false
  571. }
  572. return true
  573. }
  574. func template_apply(templateString string, replacement map[string]interface{}) string {
  575. t := fasttemplate.New(templateString, "{{", "}}")
  576. s := t.ExecuteString(replacement)
  577. return string(s)
  578. }
  579. func pkg_exists(pkgname string) bool {
  580. cmd := exec.Command("which", pkgname)
  581. out, _ := cmd.CombinedOutput()
  582. if len(string(out)) > 1 {
  583. return true
  584. } else {
  585. return false
  586. }
  587. }