Skip to content

Commit 0b06fcd

Browse files
committed
bin/xbps-create: record file mode, owner, and group
1 parent 33c01e6 commit 0b06fcd

2 files changed

Lines changed: 99 additions & 3 deletions

File tree

bin/xbps-create/main.c

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2323
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2424
*/
25+
26+
#define _DEFAULT_SOURCE
27+
2528
#include <sys/types.h>
2629
#include <sys/param.h>
2730
#include <sys/stat.h>
@@ -41,6 +44,7 @@
4144
#include <libgen.h>
4245
#include <locale.h>
4346
#include <dirent.h>
47+
#include <fnmatch.h>
4448

4549
#include <xbps.h>
4650
#include "queue.h"
@@ -66,6 +70,7 @@ struct xentry {
6670
char *file, *target;
6771
char sha256[XBPS_SHA256_SIZE];
6872
ino_t inode;
73+
mode_t mode;
6974
};
7075

7176
static TAILQ_HEAD(xentry_head, xentry) xentry_list =
@@ -109,6 +114,9 @@ usage(bool fail)
109114
" 'vi:/usr/bin/vi:/usr/bin/vim foo:/usr/bin/foo:/usr/bin/blah'\n"
110115
" --build-options A string with the used build options\n"
111116
" --compression Compression format: none, gzip, bzip2, lz4, xz, zstd (default)\n"
117+
" --chown Set the ownership of files and directories.\n"
118+
" This expects a blank-separated list of <pattern>:<user>:<group>,\n"
119+
" where '<pattern>' is an fnmatch(3) pattern.\n"
112120
" --shlib-provides List of provided shared libraries (blank separated list,\n"
113121
" e.g 'libfoo.so.1 libblah.so.2')\n"
114122
" --shlib-requires List of required shared libraries (blank separated list,\n"
@@ -245,6 +253,68 @@ process_one_alternative(const char *altgrname, const char *val)
245253
}
246254
}
247255

256+
static bool
257+
process_chown_pattern(const char *key, const char *fpat, const char *user, const char *group) {
258+
xbps_object_iterator_t iter;
259+
xbps_object_t obj;
260+
const char *fname;
261+
bool match = false;
262+
263+
if ((iter = xbps_array_iter_from_dict(pkg_filesd, key)) != NULL) {
264+
while ((obj = xbps_object_iterator_next(iter))) {
265+
xbps_dictionary_get_cstring_nocopy(obj, "file", &fname);
266+
if (fnmatch(fpat, fname, 0) == 0) {
267+
match = true;
268+
if (user != NULL)
269+
xbps_dictionary_set_cstring(obj, "user", user);
270+
if (group != NULL)
271+
xbps_dictionary_set_cstring(obj, "group", group);
272+
}
273+
}
274+
}
275+
return match;
276+
}
277+
278+
static void
279+
process_chown_patterns(const char *val) {
280+
char *raw, *itm, *fpat, *user, *group;
281+
282+
if (val == NULL)
283+
return;
284+
285+
raw = strdup(val);
286+
287+
while ((itm = strsep(&raw, " "))) {
288+
fpat = strsep(&itm, ":");
289+
if (fpat == NULL || strlen(fpat) == 0) {
290+
xbps_warn_printf("%s: skipping chown pattern `:%s': empty pattern\n", _PROGNAME, itm);
291+
continue;
292+
}
293+
294+
user = strsep(&itm, ":");
295+
if (strlen(user) == 0 || strcmp(user, "root") == 0)
296+
user = NULL;
297+
group = strsep(&itm, ":");
298+
if (strlen(group) == 0 || strcmp(group, "root") == 0)
299+
group = NULL;
300+
301+
if (itm != NULL)
302+
xbps_warn_printf("%s: chown pattern contains extra data: %s\n", _PROGNAME, itm);
303+
304+
if (user == NULL && group == NULL) {
305+
xbps_warn_printf("%s: skipping chown pattern `%s': user and group empty or root\n", _PROGNAME, fpat);
306+
continue;
307+
}
308+
309+
if (!(process_chown_pattern("dirs", fpat, user, group) ||
310+
process_chown_pattern("files", fpat, user, group) ||
311+
process_chown_pattern("links", fpat, user, group))) {
312+
xbps_warn_printf("%s: chown pattern %s matched nothing\n", _PROGNAME, fpat);
313+
}
314+
}
315+
316+
free(raw);
317+
}
248318

249319
static void
250320
process_dict_of_arrays(const char *key UNUSED, const char *val)
@@ -396,6 +466,10 @@ ftw_cb(const char *fpath, const struct stat *sb, const struct dirent *dir UNUSED
396466
goto out;
397467
}
398468

469+
// symlinks don't have a mode on linux
470+
if (!S_ISLNK(sb->st_mode))
471+
xe->mode = sb->st_mode;
472+
399473
if (S_ISLNK(sb->st_mode)) {
400474
char buf[PATH_MAX];
401475
ssize_t len;
@@ -530,7 +604,6 @@ ftw_cb(const char *fpath, const struct stat *sb, const struct dirent *dir UNUSED
530604
xbps_dictionary_set_uint64(fileinfo, "inode", sb->st_ino);
531605
xe->inode = sb->st_ino;
532606
xe->size = (uint64_t)sb->st_size;
533-
534607
} else if (S_ISDIR(sb->st_mode)) {
535608
/* directory */
536609
xbps_dictionary_set_cstring_nocopy(fileinfo, "type", "dirs");
@@ -650,6 +723,8 @@ process_xentry(enum entry_type type, const char *mutable_files)
650723
xbps_dictionary_set_cstring(d, "sha256", xe->sha256);
651724
if (xe->size)
652725
xbps_dictionary_set_uint64(d, "size", xe->size);
726+
if (xe->mode)
727+
xbps_dictionary_set_uint32(d, "mode", xe->mode);
653728

654729
xbps_array_add(a, d);
655730
xbps_object_release(d);
@@ -832,6 +907,7 @@ main(int argc, char **argv)
832907
{ "build-options", required_argument, NULL, '2' },
833908
{ "built-with", required_argument, NULL, 'B' },
834909
{ "changelog", required_argument, NULL, 'c'},
910+
{ "chown", required_argument, NULL, '6'},
835911
{ "compression", required_argument, NULL, '3' },
836912
{ "config-files", required_argument, NULL, 'F' },
837913
{ "conflicts", required_argument, NULL, 'C' },
@@ -865,7 +941,7 @@ main(int argc, char **argv)
865941
const char *provides, *pkgver, *replaces, *reverts, *desc, *ldesc;
866942
const char *arch, *config_files, *mutable_files, *version, *changelog;
867943
const char *buildopts, *shlib_provides, *shlib_requires, *alternatives;
868-
const char *compression, *tags = NULL, *srcrevs = NULL, *sourcepkg = NULL;
944+
const char *compression, *tags = NULL, *srcrevs = NULL, *sourcepkg = NULL, *chownlst;
869945
char pkgname[XBPS_NAME_SIZE], *binpkg, *tname, *p, cwd[PATH_MAX-1];
870946
bool quiet = false, preserve = false;
871947
int c, pkg_fd;
@@ -874,7 +950,7 @@ main(int argc, char **argv)
874950
arch = conflicts = deps = homepage = license = maint = compression = NULL;
875951
provides = pkgver = replaces = reverts = desc = ldesc = bwith = NULL;
876952
buildopts = config_files = mutable_files = shlib_provides = NULL;
877-
alternatives = shlib_requires = changelog = NULL;
953+
alternatives = shlib_requires = changelog = chownlst = NULL;
878954

879955
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
880956
if (optarg && strcmp(optarg, "") == 0)
@@ -965,6 +1041,9 @@ main(int argc, char **argv)
9651041
case '5':
9661042
sourcepkg = optarg;
9671043
break;
1044+
case '6':
1045+
chownlst = optarg;
1046+
break;
9681047
case '?':
9691048
default:
9701049
usage(true);
@@ -1081,6 +1160,7 @@ main(int argc, char **argv)
10811160
die("xbps_dictionary_create");
10821161

10831162
process_destdir(mutable_files);
1163+
process_chown_patterns(chownlst);
10841164

10851165
/* Back to original cwd after file tree walk processing */
10861166
if (chdir(p) == -1)

bin/xbps-create/xbps-create.1

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,22 @@ is a relative path, the symlink will be created relative to
8181
.Em target .
8282
.It Fl -build-options Ar string
8383
A string containing the build options used in package.
84+
.It Fl -chown Ar list
85+
Set the ownership of package files and directories.
86+
This expects a whitespace-separated list of
87+
.Ar <pattern>:<user>:<group> ,
88+
where
89+
.Ar <pattern>
90+
is an
91+
.Xr fnmatch 3
92+
pattern.
93+
If
94+
.Ar <user>
95+
or
96+
.Ar <group>
97+
are empty, root is assumed.
98+
Example:
99+
.Ar '/usr/lib/foo/*:foo:foo /usr/bin/foo::foo'
84100
.It Fl -compression Ar none | gzip | bzip2 | xz | lz4 | zstd
85101
Set the binary package compression format. If unset, defaults to
86102
.Ar zstd .

0 commit comments

Comments
 (0)