From nobody Fri Sep 04 14:28:56 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hbzNm5dK4z6qmFQ for ; Fri, 04 Sep 2026 14:28:56 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hbzNm3m6gz3TVY for ; Fri, 04 Sep 2026 14:28:56 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788532136; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=u77o+7yEUXeltmJnTawJq27lC+xa3Xm0/ErfXy6ms78=; b=t18YUvUtFHdFAdTHjApZmN5CyGblk/YQgLMrjYQ2gG2Oqy47ZYBzN0ilseVyAt58aQ5QNI 0Ho/O3/tvNTdrh1x+rhbzRqG5JEJ29qQ+CNmWl0GjkJSV1ROi8eNAm7RUh0Xyrls3qDet1 lklVwZTas/3ApeiEudcw8jPu7g0u5UTv9z0LSlWCLlpqKdfut1EowNAOt+TQMXywZm2Iy9 MXT1klmhJJhM+yjx2GekBLCzvTeKNwpYUzc3d45vDiNvr0GbxXqJqiT1C9YBPok4S3aCq5 OLNtu/X/zhI62Zpgn8VUXKYwC1CyCbE7v6tigKHCQhJEQAB3POUjb+I74ujsnA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1788532136; a=rsa-sha256; cv=none; b=gx1vZbIXzzAXpV4cY8xGxJZspKkLQpxj45eXqELIJvA6JzkXgi6mEnlFByOnhH6W+Gl0dO +M+OInusm3OilWNNzAggVgqMoo9aiq8ovMP2OGhs7a2hbBfM5L4ut82QNpciVlDyX8cWmr CA84Lk96jJ3rSCBNH0vPa7Z5GC/tPRLzvVab0IK5cXx47Dl1CVTnfCGzQ2EkNUiToaRpTK RIzYlF8juRmtGPMOxAtxd+Tgz6MWtUmjYETjoTLmmizG5HSsOgc1sdQMGKHS0o/NeX6Mm3 OwdZpzU+ABbsSvtXO+uszd1b0U42/v9vvYUN9s0qY58pN8NIFx82uwkgaigJRQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1788532136; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=u77o+7yEUXeltmJnTawJq27lC+xa3Xm0/ErfXy6ms78=; b=f52GNplgxMQ0/CFKV7dfwWtxGZKLs5JDFkpd2kKS805ReRGLkkz1baySN2YLHppMx0wauH vVCkGgpAfk8BdGFUqiKVmznmSBJlfY1ldCgNnFutFzrI/Z/8Le0z9dsVx0lfJ8d8aC8zoP OqZH4mkwMjjaR3vns2ERLIXROrCQNz04+hVwmTS+tUh9QUD6jt7JeZzBvljEjTsbqNcDfZ tA55WEXnD+pvgmMRZy3AwzmBp+VmMUdrOQhTFHx7QtMy2c4gH7g2ieWUeufjojkFNuq+79 EFTrBR8kHt52Y2pnUwClVbZKK+F5kRPsPE3C0mlPVffL1+LNVFVp6Z4Pg3uN/w== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hbzNm26J4z12xf for ; Fri, 04 Sep 2026 14:28:56 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 34a28 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Fri, 04 Sep 2026 14:28:56 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Baptiste Daroussin Subject: git: 6b6aa45f9a1a - main - pw: fix at job removal when deleting a user List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: bapt X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 6b6aa45f9a1a35acb7fef68824c1a5eb08503909 Auto-Submitted: auto-generated Date: Fri, 04 Sep 2026 14:28:56 +0000 Message-Id: <6a9ad5a8.34a28.102d7d48@gitrepo.freebsd.org> The branch main has been updated by bapt: URL: https://cgit.FreeBSD.org/src/commit/?id=6b6aa45f9a1a35acb7fef68824c1a5eb08503909 commit 6b6aa45f9a1a35acb7fef68824c1a5eb08503909 Author: Baptiste Daroussin AuthorDate: 2026-09-04 12:12:03 +0000 Commit: Baptiste Daroussin CommitDate: 2026-09-04 14:28:47 +0000 pw: fix at job removal when deleting a user rmat() used stat() with a path relative to the current working directory, so it never found the job files in /var/at/jobs and the at(1) jobs of a deleted user were never removed. ef7d0eb9489f also broke it by introducing a typo: /usr/sbin/atrm instead of /usr/bin/artm. Use fstatat() with the directory fd to stat the job files relative to the at jobs directory, and unlinkat() them directly instead of spawning atrm. Those changes allow us to make it works with pw -R. MFC After: 1 week --- usr.sbin/pw/pw_user.c | 27 +++++++++++++-------------- usr.sbin/pw/tests/pw_userdel_test.sh | 29 +++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c index 269344232912..9c48ef3fcb5e 100644 --- a/usr.sbin/pw/pw_user.c +++ b/usr.sbin/pw/pw_user.c @@ -680,31 +680,30 @@ pw_checkname(char *name, int gecos) static void rmat(uid_t uid) { - DIR *d = opendir("/var/at/jobs"); + DIR *d; struct dirent *e; - const char *argv[] = { "/usr/sbin/atrm", NULL, NULL }; + int atfd; - if (d == NULL) + atfd = openat(conf.rootfd, "var/at/jobs", O_DIRECTORY | O_CLOEXEC); + if (atfd == -1) return; + d = fdopendir(atfd); + if (d == NULL) { + close(atfd); + return; + } while ((e = readdir(d)) != NULL) { struct stat st; - pid_t pid; if (strncmp(e->d_name, ".lock", 5) == 0) continue; - if (stat(e->d_name, &st) != 0) + if (fstatat(atfd, e->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0) continue; if (S_ISDIR(st.st_mode) || st.st_uid != uid) continue; - argv[1] = e->d_name; - if (posix_spawn(&pid, argv[0], NULL, NULL, - (char *const *) argv, environ)) { - warn("Failed to execute '%s %s'", - argv[0], argv[1]); - } else - (void) waitpid(pid, NULL, 0); - } + if (unlinkat(atfd, e->d_name, 0) != 0) + warn("Failed to remove at job '%s'", e->d_name); } closedir(d); } @@ -1008,7 +1007,7 @@ pw_user_del(int argc, char **argv, char *arg1) unlinkat(conf.rootfd, file + 1, 0); /* Remove at jobs */ - if (!PWALTDIR() && getpwuid(id) == NULL) + if (PWALTDIR() != PWF_ALT && GETPWUID(id) == NULL) rmat(id); /* Remove home directory and contents */ diff --git a/usr.sbin/pw/tests/pw_userdel_test.sh b/usr.sbin/pw/tests/pw_userdel_test.sh index 2e11c3534d58..647384615fb4 100755 --- a/usr.sbin/pw/tests/pw_userdel_test.sh +++ b/usr.sbin/pw/tests/pw_userdel_test.sh @@ -82,6 +82,34 @@ home_regular_dir_body() { [ ! -d ${HOME}/foo ] || atf_fail "Home has not been removed" } +atf_test_case delete_at_jobs cleanup +delete_at_jobs_body() { + populate_root_etc_skel + + mkdir -p ${HOME}/var/at/jobs + + atf_check -s exit:0 ${RPW} useradd foo + + uid=$(awk -F: '/^foo:/ {print $3}' ${HOME}/etc/master.passwd) + + job="c00001000000000" + atf_check -s exit:0 touch ${HOME}/var/at/jobs/${job} + atf_check -s exit:0 chown ${uid} ${HOME}/var/at/jobs/${job} + + # A job owned by root must not be removed + otherjob="c00002000000000" + atf_check -s exit:0 touch ${HOME}/var/at/jobs/${otherjob} + atf_check -s exit:0 chown 0 ${HOME}/var/at/jobs/${otherjob} + + atf_check -s exit:0 ${RPW} userdel foo + + [ ! -e ${HOME}/var/at/jobs/${job} ] || atf_fail "at job not removed" + [ -e ${HOME}/var/at/jobs/${otherjob} ] || atf_fail "at job of another user was removed" +} +delete_at_jobs_cleanup() { + rm -rf ${HOME}/var/at/jobs +} + atf_init_test_cases() { atf_add_test_case rmuser_seperate_group atf_add_test_case user_do_not_try_to_delete_root_if_user_unknown @@ -90,4 +118,5 @@ atf_init_test_cases() { atf_add_test_case home_not_a_dir atf_add_test_case home_shared atf_add_test_case home_regular_dir + atf_add_test_case delete_at_jobs }