create dir
This commit is contained in:
@@ -26,6 +26,7 @@ The program:
|
|||||||
- Offers to create missing local accounts with `useradd -M -s /usr/sbin/nologin <user>`.
|
- Offers to create missing local accounts with `useradd -M -s /usr/sbin/nologin <user>`.
|
||||||
- If user creation fails because admin rights are needed, explains the issue and offers to retry with `sudo`.
|
- If user creation fails because admin rights are needed, explains the issue and offers to retry with `sudo`.
|
||||||
- After creating a user, offers to launch `smbpasswd -a <user>` immediately so the Samba password can be set right away.
|
- After creating a user, offers to launch `smbpasswd -a <user>` immediately so the Samba password can be set right away.
|
||||||
|
- Before saving, checks whether each share folder exists and offers to create missing directories.
|
||||||
- If saving the Samba config or its backup needs admin rights, explains the issue and offers to retry with `sudo`.
|
- If saving the Samba config or its backup needs admin rights, explains the issue and offers to retry with `sudo`.
|
||||||
- Writes a timestamped backup before saving changes.
|
- Writes a timestamped backup before saving changes.
|
||||||
|
|
||||||
|
|||||||
85
app.go
85
app.go
@@ -237,6 +237,10 @@ func (a *App) deleteShare(doc *Document) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) writeConfig(doc *Document) error {
|
func (a *App) writeConfig(doc *Document) error {
|
||||||
|
if err := a.ensureShareDirectories(doc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
backup := fmt.Sprintf("%s.bak.%s", a.configPath, time.Now().UTC().Format("20060102T150405Z"))
|
backup := fmt.Sprintf("%s.bak.%s", a.configPath, time.Now().UTC().Format("20060102T150405Z"))
|
||||||
serialized := doc.Serialize()
|
serialized := doc.Serialize()
|
||||||
|
|
||||||
@@ -259,6 +263,49 @@ func (a *App) writeConfig(doc *Document) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) ensureShareDirectories(doc *Document) error {
|
||||||
|
for _, section := range doc.ShareSections() {
|
||||||
|
cfg := ShareFromSection(section)
|
||||||
|
if strings.TrimSpace(cfg.Path) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(cfg.Path)
|
||||||
|
if err == nil {
|
||||||
|
if info.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return fmt.Errorf("share %q path exists but is not a directory: %s", cfg.Name, cfg.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("check share %q path %s: %w", cfg.Name, cfg.Path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
a.println("")
|
||||||
|
a.printf("The folder for share %q does not exist yet.\n", cfg.Name)
|
||||||
|
a.printf("Missing folder: %s\n", cfg.Path)
|
||||||
|
a.println("I can create it now so the share is ready to use.")
|
||||||
|
a.flush()
|
||||||
|
|
||||||
|
create, promptErr := a.confirm("Create this folder now", true)
|
||||||
|
if promptErr != nil {
|
||||||
|
return promptErr
|
||||||
|
}
|
||||||
|
if !create {
|
||||||
|
return fmt.Errorf("share %q needs an existing folder before saving", cfg.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.createDirectory(cfg.Path); err != nil {
|
||||||
|
return fmt.Errorf("create folder for share %q: %w", cfg.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
a.printf("Created folder %s\n", cfg.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) selectShare(doc *Document) (*Section, error) {
|
func (a *App) selectShare(doc *Document) (*Section, error) {
|
||||||
shares := doc.ShareSections()
|
shares := doc.ShareSections()
|
||||||
if len(shares) == 0 {
|
if len(shares) == 0 {
|
||||||
@@ -608,6 +655,44 @@ func (a *App) writeTempConfig(serialized string) (string, error) {
|
|||||||
return file.Name(), nil
|
return file.Name(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) createDirectory(path string) error {
|
||||||
|
if err := os.MkdirAll(path, 0o755); err == nil {
|
||||||
|
return nil
|
||||||
|
} else if shouldOfferPrivilegeRetry(err) {
|
||||||
|
a.println("")
|
||||||
|
a.println("Creating that folder needs administrator permission.")
|
||||||
|
a.println("I can try again using sudo so you can enter your admin password.")
|
||||||
|
a.flush()
|
||||||
|
|
||||||
|
canUseSudo := false
|
||||||
|
if a.lookPath != nil {
|
||||||
|
_, sudoErr := a.lookPath("sudo")
|
||||||
|
canUseSudo = sudoErr == nil
|
||||||
|
}
|
||||||
|
if !canUseSudo {
|
||||||
|
return fmt.Errorf("create folder %s: %w", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
retry, promptErr := a.confirm("Retry folder creation with sudo", true)
|
||||||
|
if promptErr != nil {
|
||||||
|
return promptErr
|
||||||
|
}
|
||||||
|
if !retry {
|
||||||
|
return fmt.Errorf("create folder %s: %w", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sudoErr := a.runner.Run("sudo", "mkdir", "-p", path); sudoErr != nil {
|
||||||
|
return fmt.Errorf("create folder %s with sudo: %w", path, sudoErr)
|
||||||
|
}
|
||||||
|
if sudoErr := a.runner.Run("sudo", "chmod", "755", path); sudoErr != nil {
|
||||||
|
return fmt.Errorf("set permissions on folder %s with sudo: %w", path, sudoErr)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("create folder %s: %w", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func friendlyWriteError(action, path string, err error) error {
|
func friendlyWriteError(action, path string, err error) error {
|
||||||
if errors.Is(err, os.ErrPermission) || strings.Contains(strings.ToLower(err.Error()), "permission denied") {
|
if errors.Is(err, os.ErrPermission) || strings.Contains(strings.ToLower(err.Error()), "permission denied") {
|
||||||
return fmt.Errorf("%s %s: administrator permission is needed", action, path)
|
return fmt.Errorf("%s %s: administrator permission is needed", action, path)
|
||||||
|
|||||||
BIN
samba-configer
BIN
samba-configer
Binary file not shown.
Reference in New Issue
Block a user