diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,12 @@
 # dnf-repo releases
 
+## 0.5.6 (2024-04-18)
+- --add-copr now supports non-fedora copr's and downloads .repo with curl
+- with --add-copr can override --osname OS and --releasever VERSION
+- use dnf5 if available
+- --expire now enables the repo for the invocation
+- --add-koji now uses rpm system arch
+
 ## 0.5.5 (2023-07-02)
 - for dnf5 test for dnf-3 (for config-manager) and also dnf
 - YumRepoFile: fix parsing of "enable = 1" (for UBI)
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -15,15 +15,16 @@
 It is also possible to expire repo caches individually.
 
 There are also smart options to enable/disable testing/modular repos
-(and even source/debuginfo repos),
-and also to create a repo file for a Copr or Koji repo.
+(and even source/debuginfo repos), and also to a Copr repo or Koji repo file.
 
 ## Help
 
-```shellsession
-$ dnf-repo --version
-0.5.5
-$ dnf-repo --help
+`$ dnf-repo --version`
+```
+0.5.6
+```
+`$ dnf-repo --help`
+```
 DNF wrapper repo tool
 
 Usage: dnf-repo [--version] [-n|--dryrun] [-q|--quiet] [-D|--debug] [-l|--list]
@@ -34,8 +35,9 @@
                   (-T|--disable-testing) | (-m|--enable-modular) |
                   (-M|--disable-modular) | --enable-debuginfo |
                   --disable-debuginfo | --enable-source | --disable-source |
-                  (-c|--add-copr COPR) | (-k|--add-koji REPO) |
-                  (-u|--repourl URL)] [DNFARGS]
+                  (-c|--add-copr COPR) [--osname OSNAME]
+                  [--releasever RELEASEVER] |
+                  (-k|--add-koji REPO) | (-u|--repourl URL)] [DNFARGS]
 
   see https://github.com/juhp/dnf-repo#readme
 
@@ -65,7 +67,9 @@
   --enable-source          Enable source repos
   --disable-source         Disable source repos
   -c,--add-copr COPR       Create repo file for copr repo
-  -k,--add-koji REPO       Create repo file for koji repo (f38-build, rawhide,
+  --osname OSNAME          Specify OS Name to override (eg epel)
+  --releasever RELEASEVER  Specify OS Release Version to override (eg rawhide)
+  -k,--add-koji REPO       Create repo file for koji repo (f40-build, rawhide,
                            epel9-build, etc)
   -u,--repourl URL         Use temporary repo from a baseurl
 ```
@@ -122,9 +126,9 @@
 ```
 
 ### Switch system from rawhide
-Switch a system from Rawhide to F38:
+Switch a system from Rawhide to F40:
 ```shellsession
-$ dnf-repo -d rawhide -e fedora distrosync --releasever 38 fedora-\*
+$ dnf-repo -d rawhide -e fedora distrosync --releasever 40 fedora-\*
 with disabled 'rawhide'
 with enabled 'fedora'
 
diff --git a/data/copr.fedorainfracloud.orgCOLONOWNERCOLONREPO.repo b/data/copr.fedorainfracloud.orgCOLONOWNERCOLONREPO.repo
deleted file mode 100644
--- a/data/copr.fedorainfracloud.orgCOLONOWNERCOLONREPO.repo
+++ /dev/null
@@ -1,10 +0,0 @@
-[copr:copr.fedorainfracloud.org:@COPR_OWNER@:@COPR_REPO@]
-name=Copr repo for @COPR_REPO@ owned by @COPR_OWNER@
-baseurl=https://download.copr.fedorainfracloud.org/results/@COPR_OWNER@/@COPR_REPO@/@DISTRO@-$releasever-$basearch/
-type=rpm-md
-skip_if_unavailable=True
-gpgcheck=1
-gpgkey=https://download.copr.fedorainfracloud.org/results/@COPR_OWNER@/@COPR_REPO@/pubkey.gpg
-repo_gpgcheck=0
-enabled=0
-enabled_metadata=1
diff --git a/dnf-repo.cabal b/dnf-repo.cabal
--- a/dnf-repo.cabal
+++ b/dnf-repo.cabal
@@ -1,5 +1,5 @@
 name:                dnf-repo
-version:             0.5.5
+version:             0.5.6
 synopsis:            DNF wrapper tool to control repos
 description:
         A command-line wrapper of the dnf package manager to
@@ -8,7 +8,7 @@
 license-file:        LICENSE
 author:              Jens Petersen <juhpetersen@gmail.com>
 maintainer:          Jens Petersen <juhpetersen@gmail.com>
-copyright:           2022-2023  Jens Petersen <juhpetersen@gmail.com>
+copyright:           2022-2024  Jens Petersen <juhpetersen@gmail.com>
 category:            Utility
 homepage:            https://github.com/juhp/dnf-repo
 bug-reports:         https://github.com/juhp/dnf-repo/issues
@@ -23,8 +23,7 @@
                      ||  == 9.2.7
                      ||  == 9.4.5
 data-dir:            data
-data-files:          copr.fedorainfracloud.orgCOLONOWNERCOLONREPO.repo
-                     koji-REPO.repo
+data-files:          koji-REPO.repo
 
 source-repository head
   type:                git
@@ -39,12 +38,13 @@
   autogen-modules:     Paths_dnf_repo
   hs-source-dirs:      src
   build-depends:       base < 5,
+                       curl,
                        directory,
                        extra,
                        filepath,
                        Glob,
                        http-directory >= 0.1.9,
-                       simple-cmd,
+                       simple-cmd >= 0.2.2,
                        simple-cmd-args >= 0.1.8,
                        simple-prompt >= 0.2
   default-language:    Haskell2010
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -9,6 +9,7 @@
 import Data.Char (isDigit)
 import Data.List.Extra
 import Data.Maybe (isJust, mapMaybe, maybeToList)
+import Network.Curl
 import Network.HTTP.Directory (httpExists', (+/+))
 import SimpleCmd
 import SimpleCmdArgs
@@ -51,7 +52,7 @@
       (fmap . fmap . fmap . fmap) cleanupReponame . strOptionWith
       where
         cleanupReponame =
-          dropWhileEnd (== ':') . replace "/" ":" . dropWhile (== '/')
+          dropWhileEnd (== '/') . dropWhile (== '/') . replace ":" "/"
 
     modeOpt =
       DisableRepo <$> repoOptionWith 'd' "disable" "REPOPAT" "Disable repos" <|>
@@ -67,12 +68,15 @@
       flagLongWith' (Specific DisableDebuginfo) "disable-debuginfo" "Disable debuginfo repos" <|>
       flagLongWith' (Specific EnableSource) "enable-source" "Enable source repos" <|>
       flagLongWith' (Specific DisableSource) "disable-source" "Disable source repos" <|>
-      AddCopr <$> repoOptionWith 'c' "add-copr" "COPR" "Create repo file for copr repo" <|>
-      AddKoji <$> repoOptionWith 'k' "add-koji" "REPO" "Create repo file for koji repo (f38-build, rawhide, epel9-build, etc)" <|>
+      AddCopr
+      <$> repoOptionWith 'c' "add-copr" "COPR" "Create repo file for copr repo"
+      <*> optional (strOptionLongWith "osname" "OSNAME" "Specify OS Name to override (eg epel)")
+      <*> optional (strOptionLongWith "releasever" "RELEASEVER" "Specify OS Release Version to override (eg rawhide)") <|>
+      AddKoji <$> repoOptionWith 'k' "add-koji" "REPO" "Create repo file for koji repo (f40-build, rawhide, epel9-build, etc)" <|>
       RepoURL <$> strOptionWith 'u' "repourl" "URL" "Use temporary repo from a baseurl"
 
-coprRepoTemplate :: FilePath
-coprRepoTemplate = "copr.fedorainfracloud.orgCOLONOWNERCOLONREPO.repo"
+fedoraCopr :: String
+fedoraCopr = "copr.fedorainfracloud.org"
 
 kojiRepoTemplate :: FilePath
 kojiRepoTemplate = "koji-REPO.repo"
@@ -88,7 +92,7 @@
   withCurrentDirectory "/etc/yum.repos.d" $ do
     forM_ modes $
       \case
-        AddCopr copr -> addCoprRepo dryrun debug copr
+        AddCopr copr mosname mrelease -> addCoprRepo dryrun debug mosname mrelease copr
         AddKoji repo -> addKojiRepo dryrun debug repo
         _ -> return ()
     repofiles <- filesWithExtension "." "repo"
@@ -103,7 +107,7 @@
     outputs <-
       forM actions $
       \case
-        Expire repo -> do
+        Expire repo _ -> do
           expireRepo dryrun debug repo
           return True
         UnExpire -> do
@@ -137,7 +141,11 @@
       else do
       sleep 1
       when save $ putStrLn ""
-      mdnf <- findExecutable "dnf"
+      mdnf <- do
+        mdnf5 <- findExecutable "dnf5"
+        case mdnf5 of
+          Just dnf5 -> return $ Just dnf5
+          Nothing -> findExecutable "dnf"
       case mdnf of
         Just dnf -> do
           when debug $ putStrLn dnf
@@ -145,40 +153,59 @@
               weakdeps = maybe [] (\w -> ["--setopt=install_weak_deps=" ++ show w]) mweakdeps
               quietopt = if quiet then ("-q" :) else id
               cachedir = ["--setopt=cachedir=/var/cache/dnf" </> relver | relver <- maybeToList (maybeReleaseVer args)]
-            in doSudo dryrun debug dnf $ quietopt repoargs ++ cachedir ++ weakdeps ++ args
+            in doSudo dryrun debug dnf $ quietopt repoargs ++ cachedir ++ weakdeps ++ map mungeArg args
         -- FIXME rpm-ostree install supports --enablerepo
         Nothing -> error' "rpm-ostree not supported"
+  where
+    mungeArg :: String -> String
+    mungeArg "distrosync" = "distro-sync"
+    mungeArg arg = arg
 
--- FIXME pull non-fedora copr repo file
-addCoprRepo :: Bool -> Bool -> String -> IO ()
-addCoprRepo dryrun debug repo = do
-  case stripInfix ":" repo of
-    Nothing -> error' $ "invalid copr: " ++ repo
-    Just (copr_owner,copr_repo) -> do
-      let repourl = "https://download.copr.fedorainfracloud.org/results" +/+ copr_owner +/+ copr_repo
-      unlessM (httpExists' repourl) $ error' $ "no such copr repo: " ++ repourl
-      distro <- do
-        isFedora <- grep_ "ID=fedora" "/etc/os-release"
-        return $ if isFedora then "fedora" else "epel" -- FIXME!
-      template <- getDataFileName coprRepoTemplate
-      repodef <- cmd "sed" ["-e", "s/@COPR_OWNER@/" ++ copr_owner ++ "/g", "-e", "s/@COPR_REPO@/" ++ copr_repo ++ "/g", "-e", "s/@DISTRO@/" ++ distro ++ "/", template]
-      let repofile = ("_copr:" ++) $
-                     replace "COLON" ":" $
-                     replace "OWNER" copr_owner $
-                     replace "REPO" copr_repo coprRepoTemplate
-      exists <- doesFileExist repofile
-      if exists
-        then error' $ "repo already defined: " ++ repofile
-        else putStrLn $ "Setting up copr repo " ++ repo
-      withTempDir $ \ tmpdir -> do
-        let tmpfile = tmpdir </> repofile
-        unless dryrun $ writeFile tmpfile repodef
-        doSudo dryrun debug "cp" [tmpfile, repofile]
-        putStrLn ""
+addCoprRepo :: Bool -> Bool -> Maybe String -> Maybe String -> String -> IO ()
+addCoprRepo dryrun debug mosname mrelease repo = do
+  let (server,owner,project) =
+        case  splitOn "/" repo of
+          [] -> error' "empty repo string"
+          [_] -> error' $ "unqualified repo project:" +-+ repo
+          [o,p] -> (fedoraCopr, o , p)
+          [c,o,p] ->
+            if c == "redhat"
+            then ("copr.devel.redhat.com", o, p)
+            else
+              if '.' `elem` c
+              then (c, o, p)
+              else error' $ "unknown copr server:" +-+ repo
+          _ -> error' $ "unknown copr:" +-+ repo
+      repofile =
+        "_copr:" ++ server ++ ':' : mungeGroupFile owner ++ ':' : project <.> "repo"
+  whenM (doesFileExist repofile) $
+    error' $ "repo already defined: " ++ repofile
+  osName <- maybe getRpmOSName return mosname
+  osVersion <- maybe getRpmOsRelease return mrelease
+  let repofileUrl = "https://" ++ server +/+ "coprs" +/+ mungeGroupUrl owner +/+ project +/+ "repo" +/+ osName ++ '-' : osVersion +/+ mungeGroupFile owner ++ '-' : project <.> "repo"
+  (curlres,curlcontent) <- curlGetString repofileUrl []
+  unless (curlres == CurlOK) $
+    error' $ "downloading failed of" +-+ repofileUrl
+  putStrLn $ "Setting up copr repo " ++ repo
+  withTempDir $ \ tmpdir -> do
+    let tmpfile = tmpdir </> repofile
+    unless dryrun $ writeFile tmpfile $
+      maybe id (replace "$releasever") mrelease $
+      replace "enabled=1" "enabled=0" curlcontent
+    doSudo dryrun debug "cp" [tmpfile, repofile]
+    putStrLn ""
+  where
+    mungeGroupFile ('@':own) = "group_" ++ own
+    mungeGroupFile own = own
 
+    mungeGroupUrl ('@':own) = "g" +/+ own
+    mungeGroupUrl own = own
+
 addKojiRepo :: Bool -> Bool -> String -> IO ()
 addKojiRepo dryrun debug repo = do
-  let repourl = "https://kojipkgs.fedoraproject.org/repos" +/+ repo +/+ "/latest/x86_64/"
+  sysarch <- cmd "rpm" ["--eval", "%{_arch}"]
+  -- FIXME repo validation/sanity: not "-k list" or other dnf command
+  let repourl = "https://kojipkgs.fedoraproject.org/repos" +/+ repo +/+ "latest" +/+ sysarch ++ "/"
   unlessM (httpExists' repourl) $ error' $ "no such koji repo: " ++ repourl
   template <- getDataFileName kojiRepoTemplate
   repodef <- cmd "sed" ["-e", "s/@REPO@/" ++ repo ++ "/g", template]
@@ -247,3 +274,41 @@
   issudo <- isJust <$> lookupEnv "SUDO_USER"
   when issudo $
     warning "*No need to run dnf-repo directly with sudo*"
+
+getRpmOsRelease :: IO String
+getRpmOsRelease = do
+  -- not defined for fedora branches
+  let systemReleaseVer = "system-release(releasever)"
+  mReleaseVerPkg <- cmdMaybe "rpm" ["-q", "--whatprovides", systemReleaseVer]
+  case mReleaseVerPkg of
+    Just relverPkg -> do
+      mreleasever <- find (systemReleaseVer `isPrefixOf`) <$> cmdLines "rpm" ["-q", "--provides", relverPkg]
+      case mreleasever of
+        Just releasever -> return $ last (words releasever)
+        Nothing -> error' $ "failed to determine" +-+ systemReleaseVer
+    Nothing -> do
+      let systemRelease = "system-release"
+      msysreleasepkg <- cmdMaybe "rpm" ["-q", "--whatprovides", systemRelease]
+      case msysreleasepkg of
+        Just sysrelpkg -> do
+          let prefix = systemRelease ++ "("
+          msysrelease <- find (prefix `isPrefixOf`) <$> cmdLines "rpm" ["-q", "--provides", sysrelpkg]
+          case msysrelease of
+            Just sysrelease ->
+              -- "system-release(40)"
+              return $ init $ dropPrefix prefix sysrelease
+            Nothing -> error' $ "failed to determine" +-+ systemRelease
+        Nothing -> error' "failed to determine OS version"
+
+getRpmOSName :: IO String
+getRpmOSName = do
+  let osrelease = "/etc/os-release"
+      idkey = "ID="
+  osids <- grep ('^' : idkey) osrelease
+  case osids of
+    [] -> error' $ "failed to find ID in" +-+ osrelease
+    [osid] -> return $
+              dropSuffix "\"" $
+              dropPrefix "\"" $
+              dropPrefix idkey osid
+    oss -> error' $ "multiple IDs in" +-+ osrelease ++ ":" ++ unwords oss
diff --git a/src/YumRepoFile.hs b/src/YumRepoFile.hs
--- a/src/YumRepoFile.hs
+++ b/src/YumRepoFile.hs
@@ -25,7 +25,8 @@
 
 type RepoState = (String,(Bool,FilePath))
 
-data Mode = AddCopr String | AddKoji String | RepoURL String
+data Mode = AddCopr String (Maybe String) (Maybe String) | AddKoji String
+          | RepoURL String
           | EnableRepo String | DisableRepo String
           | ExpireRepo String | ClearExpires
           | DeleteRepo String
@@ -33,7 +34,7 @@
   deriving (Eq, Ord, Show)
 
 modePattern :: Mode -> Maybe String
-modePattern (AddCopr c) = Just c
+modePattern (AddCopr c _ _) = Just c
 modePattern (AddKoji k) = Just k
 modePattern (RepoURL _) = Nothing
 modePattern (EnableRepo r) = Just r
@@ -61,7 +62,7 @@
 
 data ChangeEnable = Disable String Bool
                   | Enable String Bool
-                  | Expire String
+                  | Expire String Bool
                   | UnExpire
                   | Delete FilePath Bool
                   | BaseURL String
@@ -84,7 +85,12 @@
     then "enable " ++ quote r
     else "with enabled " ++ quote r
   else Just $ Left $ quote r ++ " already enabled"
-printAction _ (Expire _) = Nothing
+printAction _ (Expire r s) =
+  if s
+  then
+    Just . Right $
+    "with enabled " ++ quote r
+  else Nothing
 printAction _ UnExpire =
   Just $ Right "unexpire:"
 printAction _ (Delete f s) =
@@ -105,7 +111,7 @@
 maybeRepoName :: ChangeEnable -> Maybe (ChangeEnable, String)
 maybeRepoName d@(Disable r _) = Just (d, r)
 maybeRepoName e@(Enable r _) = Just (e, r)
-maybeRepoName x@(Expire r) = Just (x, r)
+maybeRepoName x@(Expire r _) = Just (x, r)
 maybeRepoName UnExpire = Nothing
 maybeRepoName (Delete _ _) = Nothing
 maybeRepoName (BaseURL _) = Nothing
@@ -113,6 +119,7 @@
 changeRepo :: ChangeEnable -> [String]
 changeRepo (Disable r True) = ["--disablerepo", r]
 changeRepo (Enable r True) = ["--enablerepo", r]
+changeRepo (Expire r True) = ["--enablerepo", r]
 changeRepo (BaseURL url) = ["--repofrompath", repoUrlName ++ "," ++ url]
   where
     repoUrlName = replace "/" ":" $
@@ -128,7 +135,7 @@
 saveRepo _ = []
 
 expiring :: ChangeEnable -> Maybe String
-expiring (Expire r) = Just r
+expiring (Expire r _) = Just r
 expiring _ = Nothing
 
 deleting :: ChangeEnable -> Maybe String
@@ -153,7 +160,7 @@
       let results = nub $ mapMaybe (selectRepoMode mode acc) repostates
       in
         case results of
-          [] -> error' ("no match for repo pattern action: " ++ show mode)
+          [] -> []
           [_] -> acc ++ results
           _ ->
             acc ++
@@ -178,7 +185,7 @@
                    -> Maybe ChangeEnable
     selectRepoMode mode acc (name,(enabled,file)) =
       case mode of
-        AddCopr repo ->
+        AddCopr repo _ _ ->
           maybeChange repo isSuffixOf (not enabled) (Enable name)
         AddKoji repo ->
           maybeChange repo isSuffixOf (not enabled) (Enable name)
@@ -188,7 +195,7 @@
         DisableRepo pat ->
           maybeChange pat matchesRepo enabled (Disable name)
         ExpireRepo pat ->
-          maybeChange pat matchesRepo True (const (Expire name))
+          maybeChange pat matchesRepo True (Expire name)
         ClearExpires -> Just UnExpire
         DeleteRepo pat ->
           maybeChange pat matchesRepo
