]>
glassweightruler.freedombox.rocks Git - Ventoy.git/blob - SQUASHFS/squashfs-tools-4.4/squashfs-tools/pseudo.c
2 * Create a squashfs filesystem. This is a highly compressed read only
5 * Copyright (c) 2009, 2010, 2012, 2014, 2017, 2019
6 * Phillip Lougher <phillip@squashfs.org.uk>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2,
11 * or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #include <sys/types.h>
40 #include "progressbar.h"
45 extern int read_file(char *filename
, char *type
, int (parse_line
)(char *));
47 struct pseudo_dev
**pseudo_file
= NULL
;
48 struct pseudo
*pseudo
= NULL
;
51 static char *get_component(char *target
, char **targname
)
56 while(*target
!= '/' && *target
!= '\0')
59 *targname
= strndup(start
, target
- start
);
69 * Add pseudo device target to the set of pseudo devices. Pseudo_dev
70 * describes the pseudo device attributes.
72 struct pseudo
*add_pseudo(struct pseudo
*pseudo
, struct pseudo_dev
*pseudo_dev
,
73 char *target
, char *alltarget
)
78 target
= get_component(target
, &targname
);
81 pseudo
= malloc(sizeof(struct pseudo
));
90 for(i
= 0; i
< pseudo
->names
; i
++)
91 if(strcmp(pseudo
->name
[i
].name
, targname
) == 0)
94 if(i
== pseudo
->names
) {
95 /* allocate new name entry */
97 pseudo
->name
= realloc(pseudo
->name
, (i
+ 1) *
98 sizeof(struct pseudo_entry
));
99 if(pseudo
->name
== NULL
)
101 pseudo
->name
[i
].name
= targname
;
103 if(target
[0] == '\0') {
104 /* at leaf pathname component */
105 pseudo
->name
[i
].pseudo
= NULL
;
106 pseudo
->name
[i
].pathname
= strdup(alltarget
);
107 pseudo
->name
[i
].dev
= pseudo_dev
;
109 /* recurse adding child components */
110 pseudo
->name
[i
].dev
= NULL
;
111 pseudo
->name
[i
].pseudo
= add_pseudo(NULL
, pseudo_dev
,
115 /* existing matching entry */
118 if(pseudo
->name
[i
].pseudo
== NULL
) {
119 /* No sub-directory which means this is the leaf
120 * component of a pre-existing pseudo file.
122 if(target
[0] != '\0') {
124 * entry must exist as either a 'd' type or
125 * 'm' type pseudo file
127 if(pseudo
->name
[i
].dev
->type
== 'd' ||
128 pseudo
->name
[i
].dev
->type
== 'm')
129 /* recurse adding child components */
130 pseudo
->name
[i
].pseudo
=
131 add_pseudo(NULL
, pseudo_dev
,
134 ERROR_START("%s already exists as a "
136 pseudo
->name
[i
].name
);
137 ERROR_EXIT(". Ignoring %s!\n",
140 } else if(memcmp(pseudo_dev
, pseudo
->name
[i
].dev
,
141 sizeof(struct pseudo_dev
)) != 0) {
142 ERROR_START("%s already exists as a different "
143 "pseudo definition.", alltarget
);
144 ERROR_EXIT(" Ignoring!\n");
146 ERROR_START("%s already exists as an identical "
147 "pseudo definition!", alltarget
);
148 ERROR_EXIT(" Ignoring!\n");
151 if(target
[0] == '\0') {
153 * sub-directory exists, which means we can only
154 * add a pseudo file of type 'd' or type 'm'
156 if(pseudo
->name
[i
].dev
== NULL
&&
157 (pseudo_dev
->type
== 'd' ||
158 pseudo_dev
->type
== 'm')) {
159 pseudo
->name
[i
].pathname
=
161 pseudo
->name
[i
].dev
= pseudo_dev
;
163 ERROR_START("%s already exists as a "
164 "different pseudo definition.",
165 pseudo
->name
[i
].name
);
166 ERROR_EXIT(" Ignoring %s!\n",
170 /* recurse adding child components */
171 add_pseudo(pseudo
->name
[i
].pseudo
, pseudo_dev
,
181 * Find subdirectory in pseudo directory referenced by pseudo, matching
182 * filename. If filename doesn't exist or if filename is a leaf file
185 struct pseudo
*pseudo_subdir(char *filename
, struct pseudo
*pseudo
)
192 for(i
= 0; i
< pseudo
->names
; i
++)
193 if(strcmp(filename
, pseudo
->name
[i
].name
) == 0)
194 return pseudo
->name
[i
].pseudo
;
200 struct pseudo_entry
*pseudo_readdir(struct pseudo
*pseudo
)
205 while(pseudo
->count
< pseudo
->names
) {
206 if(pseudo
->name
[pseudo
->count
].dev
!= NULL
)
207 return &pseudo
->name
[pseudo
->count
++];
216 int pseudo_exec_file(struct pseudo_dev
*dev
, int *child
)
222 ERROR("Executing dynamic pseudo file, pipe failed\n");
228 ERROR("Executing dynamic pseudo file, fork failed\n");
234 close(STDOUT_FILENO
);
235 res
= dup(pipefd
[1]);
239 execl("/bin/sh", "sh", "-c", dev
->command
, (char *) NULL
);
253 void add_pseudo_file(struct pseudo_dev
*dev
)
255 pseudo_file
= realloc(pseudo_file
, (pseudo_count
+ 1) *
256 sizeof(struct pseudo_dev
*));
257 if(pseudo_file
== NULL
)
260 dev
->pseudo_id
= pseudo_count
;
261 pseudo_file
[pseudo_count
++] = dev
;
265 struct pseudo_dev
*get_pseudo_file(int pseudo_id
)
267 return pseudo_file
[pseudo_id
];
271 int read_pseudo_def(char *def
)
275 unsigned int major
= 0, minor
= 0, mode
;
277 char suid
[100], sgid
[100]; /* overflow safe */
278 char *filename
, *name
;
279 char *orig_def
= def
;
281 struct pseudo_dev
*dev
;
284 * Scan for filename, don't use sscanf() and "%s" because
285 * that can't handle filenames with spaces.
287 * Filenames with spaces should either escape (backslash) the
288 * space or use double quotes.
290 filename
= malloc(strlen(def
) + 1);
294 for(name
= filename
; (quoted
|| !isspace(*def
)) && *def
!= '\0';) {
310 /* Skip any leading slashes (/) */
311 for(name
= filename
; *name
== '/'; name
++);
314 ERROR("Not enough or invalid arguments in pseudo file "
315 "definition \"%s\"\n", orig_def
);
319 n
= sscanf(def
, " %c %o %99s %99s %n", &type
, &mode
, suid
, sgid
,
324 ERROR("Not enough or invalid arguments in pseudo file "
325 "definition \"%s\"\n", orig_def
);
332 ERROR("Couldn't parse filename, type or octal mode\n");
333 ERROR("If the filename has spaces, either quote it, or "
334 "backslash the spaces\n");
337 ERROR("Read filename, type and mode, but failed to "
338 "read or match uid\n");
341 ERROR("Read filename, type, mode and uid, but failed "
342 "to read or match gid\n");
352 n
= sscanf(def
, "%u %u %n", &major
, &minor
, &bytes
);
356 ERROR("Not enough or invalid arguments in %s device "
357 "pseudo file definition \"%s\"\n", type
== 'b' ?
358 "block" : "character", orig_def
);
360 ERROR("Read filename, type, mode, uid and gid, "
361 "but failed to read or match major\n");
363 ERROR("Read filename, type, mode, uid, gid "
364 "and major, but failed to read or "
370 ERROR("Major %d out of range\n", major
);
374 if(minor
> 0xfffff) {
375 ERROR("Minor %d out of range\n", minor
);
383 * Check for trailing junk after expected arguments
386 ERROR("Unexpected tailing characters in pseudo file "
387 "definition \"%s\"\n", orig_def
);
393 ERROR("Not enough arguments in dynamic file pseudo "
394 "definition \"%s\"\n", orig_def
);
395 ERROR("Expected command, which can be an executable "
396 "or a piece of shell script\n");
402 ERROR("Not enough arguments in symlink pseudo "
403 "definition \"%s\"\n", orig_def
);
404 ERROR("Expected symlink\n");
408 if(strlen(def
) > 65535) {
409 ERROR("Symlink pseudo definition %s is greater than 65535"
415 ERROR("Unsupported type %c\n", type
);
421 ERROR("Mode %o out of range\n", mode
);
425 uid
= strtoll(suid
, &ptr
, 10);
427 if(uid
< 0 || uid
> ((1LL << 32) - 1)) {
428 ERROR("Uid %s out of range\n", suid
);
432 struct passwd
*pwuid
= getpwnam(suid
);
436 ERROR("Uid %s invalid uid or unknown user\n", suid
);
441 gid
= strtoll(sgid
, &ptr
, 10);
443 if(gid
< 0 || gid
> ((1LL << 32) - 1)) {
444 ERROR("Gid %s out of range\n", sgid
);
448 struct group
*grgid
= getgrnam(sgid
);
452 ERROR("Gid %s invalid uid or unknown user\n", sgid
);
471 /* permissions on symlinks are always rwxrwxrwx */
472 mode
= 0777 | S_IFLNK
;
476 dev
= malloc(sizeof(struct pseudo_dev
));
487 dev
->command
= strdup(def
);
488 add_pseudo_file(dev
);
491 dev
->symlink
= strdup(def
);
493 pseudo
= add_pseudo(pseudo
, dev
, name
, name
);
499 ERROR("Pseudo definitions should be of the format\n");
500 ERROR("\tfilename d mode uid gid\n");
501 ERROR("\tfilename m mode uid gid\n");
502 ERROR("\tfilename b mode uid gid major minor\n");
503 ERROR("\tfilename c mode uid gid major minor\n");
504 ERROR("\tfilename f mode uid gid command\n");
505 ERROR("\tfilename s mode uid gid symlink\n");
511 int read_pseudo_file(char *filename
)
513 return read_file(filename
, "pseudo", read_pseudo_def
);
517 struct pseudo
*get_pseudo()
523 #ifdef SQUASHFS_TRACE
524 static void dump_pseudo(struct pseudo
*pseudo
, char *string
)
529 for(i
= 0; i
< pseudo
->names
; i
++) {
530 struct pseudo_entry
*entry
= &pseudo
->name
[i
];
532 res
= asprintf(&path
, "%s/%s", string
, entry
->name
);
534 BAD_ERROR("asprintf failed in dump_pseudo\n");
538 ERROR("%s %c 0%o %d %d %d %d\n", path
, entry
->dev
->type
,
539 entry
->dev
->mode
& ~S_IFMT
, entry
->dev
->uid
,
540 entry
->dev
->gid
, entry
->dev
->major
,
543 dump_pseudo(entry
->pseudo
, path
);
553 dump_pseudo(pseudo
, NULL
);