diff --git a/app/pdump/main.c b/app/pdump/main.c
index f6865bdbd..d29de0321 100644
--- a/app/pdump/main.c
+++ b/app/pdump/main.c
@@ -24,6 +24,7 @@
 #include <rte_kvargs.h>
 #include <rte_mempool.h>
 #include <rte_ring.h>
+#include <rte_string_fns.h>
 #include <rte_pdump.h>
 
 #define CMD_LINE_OPT_PDUMP "pdump"
@@ -408,17 +409,15 @@ launch_args_parse(int argc, char **argv, char *prgname)
 			if (!strncmp(long_option[option_index].name,
 					CMD_LINE_OPT_SER_SOCK_PATH,
 					sizeof(CMD_LINE_OPT_SER_SOCK_PATH))) {
-				snprintf(server_socket_path,
-					sizeof(server_socket_path), "%s",
-					optarg);
+				strlcpy(server_socket_path, optarg,
+					sizeof(server_socket_path));
 			}
 
 			if (!strncmp(long_option[option_index].name,
 					CMD_LINE_OPT_CLI_SOCK_PATH,
 					sizeof(CMD_LINE_OPT_CLI_SOCK_PATH))) {
-				snprintf(client_socket_path,
-					sizeof(client_socket_path), "%s",
-					optarg);
+				strlcpy(client_socket_path, optarg,
+					sizeof(client_socket_path));
 			}
 
 			break;
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index 97d22b860..2192bdcdf 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -658,9 +658,8 @@ launch_args_parse(int argc, char** argv)
 			if (!strcmp(lgopts[opt_idx].name, "cmdline-file")) {
 				printf("CLI commands to be read from %s\n",
 				       optarg);
-				snprintf(cmdline_filename,
-					 sizeof(cmdline_filename), "%s",
-					 optarg);
+				strlcpy(cmdline_filename, optarg,
+					sizeof(cmdline_filename));
 			}
 			if (!strcmp(lgopts[opt_idx].name, "auto-start")) {
 				printf("Auto-start selected\n");
diff --git a/config/common_base b/config/common_base
index ad03cf433..20d4cbcf2 100644
--- a/config/common_base
+++ b/config/common_base
@@ -76,6 +76,7 @@ CONFIG_RTE_EAL_VFIO=n
 CONFIG_RTE_MAX_VFIO_GROUPS=64
 CONFIG_RTE_MALLOC_DEBUG=n
 CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES=n
+CONFIG_RTE_USE_LIBBSD=n
 
 #
 # Recognize/ignore the AVX/AVX512 CPU flags for performance/power testing.
diff --git a/config/meson.build b/config/meson.build
index f8c67578d..77af5d897 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -38,6 +38,13 @@ if numa_dep.found() and cc.has_header('numaif.h')
 	dpdk_extra_ldflags += '-lnuma'
 endif
 
+# check for strlcpy
+if host_machine.system() == 'linux' and cc.find_library('bsd', required: false).found()
+	dpdk_conf.set('RTE_USE_LIBBSD', 1)
+	add_project_link_arguments('-lbsd', language: 'c')
+	dpdk_extra_ldflags += '-lbsd'
+endif
+
 # add -include rte_config to cflags
 add_project_arguments('-include', 'rte_config.h', language: 'c')
 
diff --git a/devtools/cocci/strlcpy.cocci b/devtools/cocci/strlcpy.cocci
new file mode 100644
index 000000000..335e27128
--- /dev/null
+++ b/devtools/cocci/strlcpy.cocci
@@ -0,0 +1,8 @@
+@use_strlcpy@
+identifier src, dst;
+expression size;
+@@
+(
+- snprintf(dst, size, "%s", src)
++ strlcpy(dst, src, size)
+)
diff --git a/drivers/net/bonding/rte_eth_bond_pmd.c b/drivers/net/bonding/rte_eth_bond_pmd.c
index c34c3251f..f958ece72 100644
--- a/drivers/net/bonding/rte_eth_bond_pmd.c
+++ b/drivers/net/bonding/rte_eth_bond_pmd.c
@@ -617,7 +617,7 @@ mode6_debug(const char __attribute__((unused)) *info, struct ether_hdr *eth_h,
 	uint16_t offset = get_vlan_offset(eth_h, &ether_type);
 
 #ifdef RTE_LIBRTE_BOND_DEBUG_ALB
-	snprintf(buf, 16, "%s", info);
+	strlcpy(buf, info, 16);
 #endif
 
 	if (ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
diff --git a/drivers/net/failsafe/failsafe_args.c b/drivers/net/failsafe/failsafe_args.c
index 366dbea16..ea934f92a 100644
--- a/drivers/net/failsafe/failsafe_args.c
+++ b/drivers/net/failsafe/failsafe_args.c
@@ -14,6 +14,7 @@
 #include <rte_devargs.h>
 #include <rte_malloc.h>
 #include <rte_kvargs.h>
+#include <rte_string_fns.h>
 
 #include "failsafe_private.h"
 
@@ -340,7 +341,7 @@ fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
 		a = b + 1;
 	}
 out:
-	snprintf(params, DEVARGS_MAXLEN, "%s", buffer);
+	strlcpy(params, buffer, DEVARGS_MAXLEN);
 	return 0;
 }
 
@@ -392,7 +393,7 @@ failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
 	ret = 0;
 	priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
 	/* default parameters */
-	n = snprintf(mut_params, sizeof(mut_params), "%s", params);
+	n = strlcpy(mut_params, params, sizeof(mut_params));
 	if (n >= sizeof(mut_params)) {
 		ERROR("Parameter string too long (>=%zu)",
 				sizeof(mut_params));
diff --git a/drivers/net/mlx4/mlx4_ethdev.c b/drivers/net/mlx4/mlx4_ethdev.c
index 3bc692731..c92dd6d43 100644
--- a/drivers/net/mlx4/mlx4_ethdev.c
+++ b/drivers/net/mlx4/mlx4_ethdev.c
@@ -120,7 +120,7 @@ mlx4_get_ifname(const struct priv *priv, char (*ifname)[IF_NAMESIZE])
 			goto try_dev_id;
 		dev_port_prev = dev_port;
 		if (dev_port == (priv->port - 1u))
-			snprintf(match, sizeof(match), "%s", name);
+			strlcpy(match, name, sizeof(match));
 	}
 	closedir(dir);
 	if (match[0] == '\0') {
diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c
index 666507691..894a045ec 100644
--- a/drivers/net/mlx5/mlx5_ethdev.c
+++ b/drivers/net/mlx5/mlx5_ethdev.c
@@ -163,7 +163,7 @@ priv_get_ifname(const struct priv *priv, char (*ifname)[IF_NAMESIZE])
 			goto try_dev_id;
 		dev_port_prev = dev_port;
 		if (dev_port == (priv->port - 1u))
-			snprintf(match, sizeof(match), "%s", name);
+			strlcpy(match, name, sizeof(match));
 	}
 	closedir(dir);
 	if (match[0] == '\0')
diff --git a/drivers/net/mrvl/mrvl_qos.c b/drivers/net/mrvl/mrvl_qos.c
index fbb368131..edc4d92d6 100644
--- a/drivers/net/mrvl/mrvl_qos.c
+++ b/drivers/net/mrvl/mrvl_qos.c
@@ -190,7 +190,7 @@ get_entry_values(const char *entry, uint8_t *tab,
 		return -1;
 
 	/* Copy the entry to safely use rte_strsplit(). */
-	snprintf(entry_cpy, RTE_DIM(entry_cpy), "%s", entry);
+	strlcpy(entry_cpy, entry, RTE_DIM(entry_cpy));
 
 	/*
 	 * If there are more tokens than array size, rte_strsplit will
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index f09db0ea9..fbba9aa63 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -15,6 +15,7 @@
 #include <rte_net.h>
 #include <rte_debug.h>
 #include <rte_ip.h>
+#include <rte_string_fns.h>
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -1548,7 +1549,7 @@ set_interface_name(const char *key __rte_unused,
 	char *name = (char *)extra_args;
 
 	if (value)
-		snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s", value);
+		strlcpy(name, value, RTE_ETH_NAME_MAX_LEN - 1);
 	else
 		snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s%d",
 			 DEFAULT_TAP_NAME, (tap_unit - 1));
@@ -1564,7 +1565,7 @@ set_remote_iface(const char *key __rte_unused,
 	char *name = (char *)extra_args;
 
 	if (value)
-		snprintf(name, RTE_ETH_NAME_MAX_LEN, "%s", value);
+		strlcpy(name, value, RTE_ETH_NAME_MAX_LEN);
 
 	return 0;
 }
diff --git a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
index 097ec3469..3e26ae86b 100644
--- a/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_flow_classification_be.c
@@ -8,6 +8,7 @@
 #include <rte_malloc.h>
 #include <rte_table_hash.h>
 #include <rte_byteorder.h>
+#include <rte_string_fns.h>
 #include <pipeline.h>
 
 #include "pipeline_flow_classification_be.h"
@@ -280,8 +281,7 @@ pipeline_fc_parse_args(struct pipeline_flow_classification *p,
 				"\"%s\" is too long", params->name,
 				arg_name);
 
-			snprintf(key_mask_str, mask_str_len + 1, "%s",
-				arg_value);
+			strlcpy(key_mask_str, arg_value, mask_str_len + 1);
 
 			continue;
 		}
diff --git a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
index b2bbaedda..1c44e75df 100644
--- a/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_passthrough_be.c
@@ -8,6 +8,7 @@
 #include <rte_common.h>
 #include <rte_malloc.h>
 #include <rte_byteorder.h>
+#include <rte_string_fns.h>
 #include <rte_table_stub.h>
 #include <rte_table_hash.h>
 #include <rte_pipeline.h>
@@ -524,8 +525,7 @@ pipeline_passthrough_parse_args(struct pipeline_passthrough_params *p,
 				"\"%s\" too long", params->name,
 				arg_name);
 
-			snprintf(dma_mask_str, mask_str_len + 1,
-				"%s", arg_value);
+			strlcpy(dma_mask_str, arg_value, mask_str_len + 1);
 
 			p->dma_enabled = 1;
 
diff --git a/examples/load_balancer/config.c b/examples/load_balancer/config.c
index b5b66368d..972c85c5b 100644
--- a/examples/load_balancer/config.c
+++ b/examples/load_balancer/config.c
@@ -121,7 +121,7 @@ str_to_unsigned_array(
 	int i, num_splits = 0;
 
 	/* copy s so we don't modify original string */
-	snprintf(str, sizeof(str), "%s", s);
+	strlcpy(str, s, sizeof(str));
 	num_splits = rte_strsplit(str, sizeof(str), splits, num_vals, separator);
 
 	errno = 0;
diff --git a/lib/librte_cmdline/cmdline_parse.c b/lib/librte_cmdline/cmdline_parse.c
index e88e4e110..961f9befd 100644
--- a/lib/librte_cmdline/cmdline_parse.c
+++ b/lib/librte_cmdline/cmdline_parse.c
@@ -251,7 +251,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)
 	}
 
 #ifdef RTE_LIBRTE_CMDLINE_DEBUG
-	snprintf(debug_buf, (linelen>64 ? 64 : linelen), "%s", buf);
+	strlcpy(debug_buf, buf, (linelen > 64 ? 64 : linelen));
 	debug_printf("Parse line : len=%d, <%s>\n", linelen, debug_buf);
 #endif
 
@@ -436,7 +436,7 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state,
 				if ((unsigned)(comp_len + 1) > size)
 					return 0;
 
-				snprintf(dst, size, "%s", comp_buf);
+				strlcpy(dst, comp_buf, size);
 				dst[comp_len] = 0;
 				return 2;
 			}
@@ -513,7 +513,7 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state,
 					continue;
 				}
 				(*state)++;
-				l=snprintf(dst, size, "%s", tmpbuf);
+				l=strlcpy(dst, tmpbuf, size);
 				if (l>=0 && token_hdr.ops->get_help) {
 					token_hdr.ops->get_help(token_p, tmpbuf,
 								sizeof(tmpbuf));
diff --git a/lib/librte_cmdline/cmdline_parse_etheraddr.c b/lib/librte_cmdline/cmdline_parse_etheraddr.c
index 8d2811926..24e04755c 100644
--- a/lib/librte_cmdline/cmdline_parse_etheraddr.c
+++ b/lib/librte_cmdline/cmdline_parse_etheraddr.c
@@ -102,7 +102,7 @@ cmdline_parse_etheraddr(__attribute__((unused)) cmdline_parse_token_hdr_t *tk,
 			(token_len != ETHER_ADDRSTRLENSHORT - 1))
 		return -1;
 
-	snprintf(ether_str, token_len+1, "%s", buf);
+	strlcpy(ether_str, buf, token_len + 1);
 
 	tmp = my_ether_aton(ether_str);
 	if (tmp == NULL)
diff --git a/lib/librte_cmdline/cmdline_parse_ipaddr.c b/lib/librte_cmdline/cmdline_parse_ipaddr.c
index ae6ea1007..d34436abc 100644
--- a/lib/librte_cmdline/cmdline_parse_ipaddr.c
+++ b/lib/librte_cmdline/cmdline_parse_ipaddr.c
@@ -277,7 +277,7 @@ cmdline_parse_ipaddr(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
 	if (token_len >= INET6_ADDRSTRLEN+4)
 		return -1;
 
-	snprintf(ip_str, token_len+1, "%s", buf);
+	strlcpy(ip_str, buf, token_len + 1);
 
 	/* convert the network prefix */
 	if (tk2->ipaddr_data.flags & CMDLINE_IPADDR_NETWORK) {
diff --git a/lib/librte_cmdline/cmdline_parse_portlist.c b/lib/librte_cmdline/cmdline_parse_portlist.c
index 5952f3438..ad43b522e 100644
--- a/lib/librte_cmdline/cmdline_parse_portlist.c
+++ b/lib/librte_cmdline/cmdline_parse_portlist.c
@@ -94,7 +94,7 @@ cmdline_parse_portlist(__attribute__((unused)) cmdline_parse_token_hdr_t *tk,
 	if (token_len >= PORTLIST_TOKEN_SIZE)
 		return -1;
 
-	snprintf(portlist_str, token_len+1, "%s", buf);
+	strlcpy(portlist_str, buf, token_len + 1);
 
 	if (pl) {
 		pl->map = 0;
diff --git a/lib/librte_cmdline/cmdline_parse_string.c b/lib/librte_cmdline/cmdline_parse_string.c
index abde0412a..9cf41d0f7 100644
--- a/lib/librte_cmdline/cmdline_parse_string.c
+++ b/lib/librte_cmdline/cmdline_parse_string.c
@@ -125,10 +125,10 @@ cmdline_parse_string(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
 	if (res) {
 		if ((sd->str != NULL) && (strcmp(sd->str, TOKEN_STRING_MULTI) == 0))
 			/* we are sure that token_len is < STR_MULTI_TOKEN_SIZE-1 */
-			snprintf(res, STR_MULTI_TOKEN_SIZE, "%s", buf);
+			strlcpy(res, buf, STR_MULTI_TOKEN_SIZE);
 		else
 			/* we are sure that token_len is < STR_TOKEN_SIZE-1 */
-			snprintf(res, STR_TOKEN_SIZE, "%s", buf);
+			strlcpy(res, buf, STR_TOKEN_SIZE);
 
 		*((char *)res + token_len) = 0;
 	}
diff --git a/lib/librte_eal/common/eal_common_bus.c b/lib/librte_eal/common/eal_common_bus.c
index 3e022d510..0943851cc 100644
--- a/lib/librte_eal/common/eal_common_bus.c
+++ b/lib/librte_eal/common/eal_common_bus.c
@@ -36,6 +36,7 @@
 
 #include <rte_bus.h>
 #include <rte_debug.h>
+#include <rte_string_fns.h>
 
 #include "eal_private.h"
 
@@ -212,7 +213,7 @@ rte_bus_find_by_device_name(const char *str)
 	char name[RTE_DEV_NAME_MAX_LEN];
 	char *c;
 
-	snprintf(name, sizeof(name), "%s", str);
+	strlcpy(name, str, sizeof(name));
 	c = strchr(name, ',');
 	if (c != NULL)
 		c[0] = '\0';
diff --git a/lib/librte_eal/common/include/rte_string_fns.h b/lib/librte_eal/common/include/rte_string_fns.h
index e97047a47..ff4c98b2a 100644
--- a/lib/librte_eal/common/include/rte_string_fns.h
+++ b/lib/librte_eal/common/include/rte_string_fns.h
@@ -45,6 +45,20 @@ int
 rte_strsplit(char *string, int stringlen,
              char **tokens, int maxtokens, char delim);
 
+/* pull in a strlcpy function */
+#ifdef RTE_EXEC_ENV_BSDAPP
+#include <string.h>
+
+#else /* non-BSD platforms */
+#ifdef RTE_USE_LIBBSD
+#include <bsd/string.h>
+
+#else /* no BSD header files, create own */
+#define strlcpy(dst, src, size) snprintf(dst, size, "%s", src)
+
+#endif /* RTE_USE_LIBBSD */
+#endif /* BSDAPP */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_pdump/rte_pdump.c b/lib/librte_pdump/rte_pdump.c
index ec8a5d84c..41a9deeba 100644
--- a/lib/librte_pdump/rte_pdump.c
+++ b/lib/librte_pdump/rte_pdump.c
@@ -17,6 +17,7 @@
 #include <rte_lcore.h>
 #include <rte_log.h>
 #include <rte_errno.h>
+#include <rte_string_fns.h>
 
 #include "rte_pdump.h"
 
@@ -401,9 +402,9 @@ pdump_get_socket_path(char *buffer, int bufsz, enum rte_pdump_socktype type)
 	int ret = 0;
 
 	if (type == RTE_PDUMP_SOCKET_SERVER && server_socket_dir[0] != 0)
-		snprintf(dir, sizeof(dir), "%s", server_socket_dir);
+		strlcpy(dir, server_socket_dir, sizeof(dir));
 	else if (type == RTE_PDUMP_SOCKET_CLIENT && client_socket_dir[0] != 0)
-		snprintf(dir, sizeof(dir), "%s", client_socket_dir);
+		strlcpy(dir, client_socket_dir, sizeof(dir));
 	else {
 		if (getuid() != 0) {
 			dir_home = getenv(SOCKET_PATH_HOME);
@@ -891,10 +892,10 @@ rte_pdump_set_socket_dir(const char *path, enum rte_pdump_socktype type)
 	if (path != NULL) {
 		if (type == RTE_PDUMP_SOCKET_SERVER) {
 			count = sizeof(server_socket_dir);
-			ret = snprintf(server_socket_dir, count, "%s", path);
+			ret = strlcpy(server_socket_dir, path, count);
 		} else {
 			count = sizeof(client_socket_dir);
-			ret = snprintf(client_socket_dir, count, "%s", path);
+			ret = strlcpy(client_socket_dir, path, count);
 		}
 
 		if (ret < 0  || ret >= count) {
diff --git a/test/test/test_cmdline_cirbuf.c b/test/test/test_cmdline_cirbuf.c
index e9193f66c..8ac326cb0 100644
--- a/test/test/test_cmdline_cirbuf.c
+++ b/test/test/test_cmdline_cirbuf.c
@@ -483,7 +483,7 @@ test_cirbuf_string_get_del_partial(void)
 	memset(tmp, 0, sizeof(tmp));
 	memset(tmp2, 0, sizeof(tmp));
 
-	snprintf(tmp2, sizeof(tmp2), "%s", CIRBUF_STR_HEAD);
+	strlcpy(tmp2, CIRBUF_STR_HEAD, sizeof(tmp2));
 
 	/*
 	 * initialize circular buffer
diff --git a/test/test/test_eal_flags.c b/test/test/test_eal_flags.c
index 37c42efe8..93eb7a481 100644
--- a/test/test/test_eal_flags.c
+++ b/test/test/test_eal_flags.c
@@ -1151,11 +1151,12 @@ test_memory_flags(void)
 	/* add one extra socket */
 	for (i = 0; i < num_sockets + 1; i++) {
 		snprintf(buf, sizeof(buf), "%s%s", invalid_socket_mem, DEFAULT_MEM_SIZE);
-		snprintf(invalid_socket_mem, sizeof(invalid_socket_mem), "%s", buf);
+		strlcpy(invalid_socket_mem, buf, sizeof(invalid_socket_mem));
 
 		if (num_sockets + 1 - i > 1) {
 			snprintf(buf, sizeof(buf), "%s,", invalid_socket_mem);
-			snprintf(invalid_socket_mem, sizeof(invalid_socket_mem), "%s", buf);
+			strlcpy(invalid_socket_mem, buf,
+				sizeof(invalid_socket_mem));
 		}
 	}
 
@@ -1167,11 +1168,12 @@ test_memory_flags(void)
 	/* add one extra socket */
 	for (i = 0; i < num_sockets; i++) {
 		snprintf(buf, sizeof(buf), "%s%s", valid_socket_mem, DEFAULT_MEM_SIZE);
-		snprintf(valid_socket_mem, sizeof(valid_socket_mem), "%s", buf);
+		strlcpy(valid_socket_mem, buf, sizeof(valid_socket_mem));
 
 		if (num_sockets - i > 1) {
 			snprintf(buf, sizeof(buf), "%s,", valid_socket_mem);
-			snprintf(valid_socket_mem, sizeof(valid_socket_mem), "%s", buf);
+			strlcpy(valid_socket_mem, buf,
+				sizeof(valid_socket_mem));
 		}
 	}
 
diff --git a/test/test/test_malloc.c b/test/test/test_malloc.c
index d23192cf1..ccc5feaec 100644
--- a/test/test/test_malloc.c
+++ b/test/test/test_malloc.c
@@ -378,7 +378,7 @@ test_realloc(void)
 		printf("NULL pointer returned from rte_zmalloc\n");
 		return -1;
 	}
-	snprintf(ptr1, size1, "%s" ,hello_str);
+	strlcpy(ptr1, hello_str, size1);
 	char *ptr2 = rte_realloc(ptr1, size2, RTE_CACHE_LINE_SIZE);
 	if (!ptr2){
 		rte_free(ptr1);
