wifi_linux.go 19 KB

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