wifi_linux.go 18 KB

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