6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
25 * Copyright 2015 Gary Mills
26 */
27
28 /*
29 * Copyright 2017 Jason King. All rights reserved.
30 * Use is subject to license terms.
31 */
32
33 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
34 /* All Rights Reserved */
35
36 /* Copyright (c) 1987, 1988 Microsoft Corporation */
37 /* All Rights Reserved */
38
39 /*
40 * List files or directories
41 */
42
43 #include <sys/param.h>
44 #include <sys/types.h>
45 #include <sys/mkdev.h>
213 int cycle_detected; /* cycle detected visiting this directory */
214 struct ditem *myancinfo; /* this directory's ancestry info */
215 struct dchain *dc_next; /* next directory in the chain */
216 };
217
218 static struct dchain *dfirst; /* start of the dir chain */
219 static struct dchain *cdfirst; /* start of the current dir chain */
220 static struct dchain *dtemp; /* temporary - used for linking */
221 static char *curdir; /* the current directory */
222
223 static int first = 1; /* true if first line is not yet printed */
224 static int nfiles = 0; /* number of flist entries in current use */
225 static int nargs = 0; /* number of flist entries used for arguments */
226 static int maxfils = 0; /* number of flist/lbuf entries allocated */
227 static int maxn = 0; /* number of flist entries with lbufs asigned */
228 static int quantn = 64; /* allocation growth quantum */
229
230 static struct lbuf *nxtlbf; /* ptr to next lbuf to be assigned */
231 static struct lbuf **flist; /* ptr to list of lbuf pointers */
232 static struct lbuf *gstat(char *, int, struct ditem *);
233 static char *getname(uid_t);
234 static char *getgroup(gid_t);
235 static char *makename(char *, char *);
236 static void pentry(struct lbuf *);
237 static void column(void);
238 static void pmode(mode_t aflag);
239 static void selection(int *);
240 static void new_line(void);
241 static void rddir(char *, struct ditem *);
242 static int strcol(unsigned char *);
243 static void pem(struct lbuf **, struct lbuf **, int);
244 static void pdirectory(char *, int, int, int, struct ditem *);
245 static struct cachenode *findincache(struct cachenode **, long);
246 static void csi_pprintf(unsigned char *);
247 static void pprintf(char *, char *);
248 static int compar(struct lbuf **pp1, struct lbuf **pp2);
249 static void record_ancestry(char *, struct stat *, struct lbuf *,
250 int, struct ditem *);
251 static void ls_color_init(void);
252 static ls_color_t *ls_color_find(const char *, mode_t);
759 statreq++;
760 Cflg = 0;
761 xflg = 0;
762 mflg = 0;
763 atflg = 0;
764 continue;
765 case 'L':
766 Lflg++;
767 /* -H and -L are mutually exclusive */
768 Hflg = 0;
769 continue;
770 case 'm':
771 Cflg = 0;
772 mflg = 1;
773 #ifdef XPG4
774 lflg = 0;
775 #endif
776 continue;
777 case 'n':
778 nflg++;
779 lflg++;
780 statreq++;
781 Cflg = 0;
782 xflg = 0;
783 mflg = 0;
784 atflg = 0;
785 continue;
786 case 'o':
787 oflg++;
788 lflg++;
789 statreq++;
790 continue;
791 case 'p':
792 pflg++;
793 statreq++;
794 continue;
795 case 'q':
796 qflg = 1;
797 bflg = 0;
798 continue;
799 case 'r':
800 rflg = -1;
801 continue;
802 case 'R':
803 Rflg++;
804 statreq++;
1224 else
1225 row = 0;
1226
1227 nrows = (lp - slp - 1) / ncols + 1;
1228 for (i = 0; i < nrows; i++, row++) {
1229 for (col = 0; col < ncols; col++) {
1230 ep = slp + (nrows * col) + row;
1231 if (ep < lp)
1232 pentry(*ep);
1233 }
1234 new_line();
1235 }
1236 }
1237
1238 /*
1239 * print one output entry;
1240 * if uid/gid is not found in the appropriate
1241 * file(passwd/group), then print uid/gid instead of
1242 * user/group name;
1243 */
1244 static void
1245 pentry(struct lbuf *ap)
1246 {
1247 struct lbuf *p;
1248 char *dmark = ""; /* Used if -p or -F option active */
1249 char *cp;
1250 char *str;
1251
1252 if (noflist) {
1253 (void) printf("%s\n", (ap->lflags & ISARG) ? ap->ln.namep :
1254 ap->ln.lname);
1255 return;
1256 }
1257
1258 p = ap;
1259 column();
1260 if (iflg) {
1261 if (mflg && !lflg)
1262 curcol += printf("%llu ", (long long)p->lnum);
1263 else
1264 curcol += printf("%10llu ", (long long)p->lnum);
1265 }
1266 if (sflg) {
1267 curcol += printf((mflg && !lflg) ? "%lld " :
1268 (p->lblocks < 10000) ? "%4lld " : "%lld ",
1269 (p->ltype != 'b' && p->ltype != 'c') ?
1270 p->lblocks : 0LL);
1271 }
1272 if (lflg) {
1273 (void) putchar(p->ltype);
1274 curcol++;
1275 pmode(p->lflags);
1276
1277 /* ACL: additional access mode flag */
1278 (void) putchar(p->acl);
1279 curcol++;
1280
1281 curcol += printf("%3lu ", (ulong_t)p->lnl);
1282 if (oflg) {
1283 if (!nflg) {
1284 cp = getname(p->luid);
1285 curcol += printf("%-8s ", cp);
1286 } else
1287 curcol += printf("%-8lu ", (ulong_t)p->luid);
1288 }
1289 if (gflg) {
1290 if (!nflg) {
1291 cp = getgroup(p->lgid);
1292 curcol += printf("%-8s ", cp);
1293 } else
1294 curcol += printf("%-8lu ", (ulong_t)p->lgid);
1295 }
1296 if (p->ltype == 'b' || p->ltype == 'c') {
1297 curcol += printf("%3u, %2u",
1298 (uint_t)major((dev_t)p->lsize),
1299 (uint_t)minor((dev_t)p->lsize));
1300 } else if (hflg) {
1301 char numbuf[NN_NUMBUF_SZ];
1302
1303 nicenum_scale(p->lsize, 1, numbuf, sizeof (numbuf),
1304 nicenum_flags);
1305
1306 curcol += printf("%7s", numbuf);
1307 } else {
1308 uint64_t bsize = p->lsize / block_size;
1309
1310 /*
1311 * Round up only when using blocks > 1 byte, otherwise
1312 * 'normal' sizes display 1 byte too large.
1313 */
1314 if (p->lsize % block_size != 0)
1315 bsize++;
1409 for (i = 0; i < sacnt; i++) {
1410 if (p->exttr[i].name != NULL) {
1411 (void) printf("%s", p->exttr[i].name);
1412 k--;
1413 if (vopt && (k != 0))
1414 (void) printf(",");
1415 }
1416 }
1417 }
1418 (void) printf("}\n");
1419 }
1420 /* Display file timestamps and extended system attribute timestamps */
1421 if (tmflg && alltm) {
1422 new_line();
1423 print_time(p);
1424 new_line();
1425 }
1426 if (vflg) {
1427 new_line();
1428 if (p->aclp) {
1429 acl_printacl(p->aclp, num_cols, Vflg);
1430 }
1431 }
1432 /* Free extended system attribute lists */
1433 if (saflg || tmflg)
1434 free_sysattr(p);
1435 }
1436
1437 /* print various r,w,x permissions */
1438 static void
1439 pmode(mode_t aflag)
1440 {
1441 /* these arrays are declared static to allow initializations */
1442 static int m0[] = { 1, S_IRUSR, 'r', '-' };
1443 static int m1[] = { 1, S_IWUSR, 'w', '-' };
1444 static int m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR,
1445 'x', S_ISUID, 'S', '-' };
1446 static int m3[] = { 1, S_IRGRP, 'r', '-' };
1447 static int m4[] = { 1, S_IWGRP, 'w', '-' };
1448 static int m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP,
1449 'x', S_ISGID|LS_NOTREG, 'S',
2197 } else if (val < c->val) {
2198 parent = &c->lesschild;
2199 c = c->lesschild;
2200 } else {
2201 parent = &c->grtrchild;
2202 c = c->grtrchild;
2203 }
2204 }
2205
2206 /* not in the cache, make a new entry for it */
2207 c = calloc(1, sizeof (struct cachenode));
2208 if (c == NULL) {
2209 perror("ls");
2210 exit(2);
2211 }
2212 *parent = c;
2213 c->val = val;
2214 return (c);
2215 }
2216
2217 /*
2218 * get name from cache, or passwd file for a given uid;
2219 * lastuid is set to uid.
2220 */
2221 static char *
2222 getname(uid_t uid)
2223 {
2224 struct passwd *pwent;
2225 struct cachenode *c;
2226
2227 if ((uid == lastuid) && lastuname)
2228 return (lastuname);
2229
2230 c = findincache(&names, uid);
2231 if (c->initted == 0) {
2232 if ((pwent = getpwuid(uid)) != NULL) {
2233 SCPYN(&c->name[0], pwent->pw_name);
2234 } else {
2235 (void) sprintf(&c->name[0], "%-8u", (int)uid);
2236 }
|
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
25 * Copyright 2015 Gary Mills
26 *
27 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
28 */
29
30 /*
31 * Copyright 2017 Jason King. All rights reserved.
32 * Use is subject to license terms.
33 */
34
35 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
36 /* All Rights Reserved */
37
38 /* Copyright (c) 1987, 1988 Microsoft Corporation */
39 /* All Rights Reserved */
40
41 /*
42 * List files or directories
43 */
44
45 #include <sys/param.h>
46 #include <sys/types.h>
47 #include <sys/mkdev.h>
215 int cycle_detected; /* cycle detected visiting this directory */
216 struct ditem *myancinfo; /* this directory's ancestry info */
217 struct dchain *dc_next; /* next directory in the chain */
218 };
219
220 static struct dchain *dfirst; /* start of the dir chain */
221 static struct dchain *cdfirst; /* start of the current dir chain */
222 static struct dchain *dtemp; /* temporary - used for linking */
223 static char *curdir; /* the current directory */
224
225 static int first = 1; /* true if first line is not yet printed */
226 static int nfiles = 0; /* number of flist entries in current use */
227 static int nargs = 0; /* number of flist entries used for arguments */
228 static int maxfils = 0; /* number of flist/lbuf entries allocated */
229 static int maxn = 0; /* number of flist entries with lbufs asigned */
230 static int quantn = 64; /* allocation growth quantum */
231
232 static struct lbuf *nxtlbf; /* ptr to next lbuf to be assigned */
233 static struct lbuf **flist; /* ptr to list of lbuf pointers */
234 static struct lbuf *gstat(char *, int, struct ditem *);
235 static char *get_sid_name(uid_t, boolean_t, boolean_t);
236 static char *getname(uid_t);
237 static char *getgroup(gid_t);
238 static char *makename(char *, char *);
239 static void pentry(struct lbuf *);
240 static void column(void);
241 static void pmode(mode_t aflag);
242 static void selection(int *);
243 static void new_line(void);
244 static void rddir(char *, struct ditem *);
245 static int strcol(unsigned char *);
246 static void pem(struct lbuf **, struct lbuf **, int);
247 static void pdirectory(char *, int, int, int, struct ditem *);
248 static struct cachenode *findincache(struct cachenode **, long);
249 static void csi_pprintf(unsigned char *);
250 static void pprintf(char *, char *);
251 static int compar(struct lbuf **pp1, struct lbuf **pp2);
252 static void record_ancestry(char *, struct stat *, struct lbuf *,
253 int, struct ditem *);
254 static void ls_color_init(void);
255 static ls_color_t *ls_color_find(const char *, mode_t);
762 statreq++;
763 Cflg = 0;
764 xflg = 0;
765 mflg = 0;
766 atflg = 0;
767 continue;
768 case 'L':
769 Lflg++;
770 /* -H and -L are mutually exclusive */
771 Hflg = 0;
772 continue;
773 case 'm':
774 Cflg = 0;
775 mflg = 1;
776 #ifdef XPG4
777 lflg = 0;
778 #endif
779 continue;
780 case 'n':
781 nflg++;
782 if (nflg == 1) {
783 lflg++;
784 statreq++;
785 Cflg = 0;
786 xflg = 0;
787 mflg = 0;
788 atflg = 0;
789 }
790 continue;
791 case 'o':
792 oflg++;
793 lflg++;
794 statreq++;
795 continue;
796 case 'p':
797 pflg++;
798 statreq++;
799 continue;
800 case 'q':
801 qflg = 1;
802 bflg = 0;
803 continue;
804 case 'r':
805 rflg = -1;
806 continue;
807 case 'R':
808 Rflg++;
809 statreq++;
1229 else
1230 row = 0;
1231
1232 nrows = (lp - slp - 1) / ncols + 1;
1233 for (i = 0; i < nrows; i++, row++) {
1234 for (col = 0; col < ncols; col++) {
1235 ep = slp + (nrows * col) + row;
1236 if (ep < lp)
1237 pentry(*ep);
1238 }
1239 new_line();
1240 }
1241 }
1242
1243 /*
1244 * print one output entry;
1245 * if uid/gid is not found in the appropriate
1246 * file(passwd/group), then print uid/gid instead of
1247 * user/group name;
1248 */
1249 #define DUMP_EPHEMERAL(x) printf("%-8lu ", (ulong_t)(x))
1250 static void
1251 pentry(struct lbuf *ap)
1252 {
1253 struct lbuf *p;
1254 char *dmark = ""; /* Used if -p or -F option active */
1255 char *cp;
1256 char *str;
1257
1258 if (noflist) {
1259 (void) printf("%s\n", (ap->lflags & ISARG) ? ap->ln.namep :
1260 ap->ln.lname);
1261 return;
1262 }
1263
1264 p = ap;
1265 column();
1266 if (iflg) {
1267 if (mflg && !lflg)
1268 curcol += printf("%llu ", (long long)p->lnum);
1269 else
1270 curcol += printf("%10llu ", (long long)p->lnum);
1271 }
1272 if (sflg) {
1273 curcol += printf((mflg && !lflg) ? "%lld " :
1274 (p->lblocks < 10000) ? "%4lld " : "%lld ",
1275 (p->ltype != 'b' && p->ltype != 'c') ?
1276 p->lblocks : 0LL);
1277 }
1278 if (lflg) {
1279 boolean_t res;
1280
1281 (void) putchar(p->ltype);
1282 curcol++;
1283 pmode(p->lflags);
1284
1285 /* ACL: additional access mode flag */
1286 (void) putchar(p->acl);
1287 curcol++;
1288
1289 curcol += printf("%3lu ", (ulong_t)p->lnl);
1290 if (oflg) {
1291 boolean_t usr = B_TRUE;
1292
1293 if (nflg == 0) { /* -n not specified; resolve */
1294 if (p->luid > MAXUID) {
1295 res = B_FALSE;
1296 cp = get_sid_name(p->luid, usr, res);
1297 } else {
1298 cp = getname(p->luid);
1299 }
1300 curcol += printf("%-8s ", cp);
1301
1302 } else if (nflg == 1) { /* -n specified; force SID's */
1303 if (p->luid > MAXUID) {
1304 res = B_TRUE;
1305
1306 cp = get_sid_name(p->luid, usr, res);
1307 curcol += printf("%-8s ", cp);
1308 } else {
1309 curcol += DUMP_EPHEMERAL(p->luid);
1310 }
1311 } else /* -nn specified; force ephemerals */
1312 curcol += DUMP_EPHEMERAL(p->luid);
1313 }
1314 if (gflg) {
1315 boolean_t usr = B_FALSE;
1316
1317 if (nflg == 0) { /* -n not specified; resolve */
1318 if (p->lgid > MAXUID) {
1319 res = B_FALSE;
1320 cp = get_sid_name(p->lgid, usr, res);
1321 } else {
1322 cp = getgroup(p->lgid);
1323 }
1324 curcol += printf("%-8s ", cp);
1325
1326 } else if (nflg == 1) { /* -n specified; force SID's */
1327 if (p->lgid > MAXUID) {
1328 res = B_TRUE;
1329
1330 cp = get_sid_name(p->lgid, usr, res);
1331 curcol += printf("%-8s ", cp);
1332 } else {
1333 curcol += DUMP_EPHEMERAL(p->lgid);
1334 }
1335 } else /* -nn specified; force ephemerals */
1336 curcol += DUMP_EPHEMERAL(p->lgid);
1337 }
1338 if (p->ltype == 'b' || p->ltype == 'c') {
1339 curcol += printf("%3u, %2u",
1340 (uint_t)major((dev_t)p->lsize),
1341 (uint_t)minor((dev_t)p->lsize));
1342 } else if (hflg) {
1343 char numbuf[NN_NUMBUF_SZ];
1344
1345 nicenum_scale(p->lsize, 1, numbuf, sizeof (numbuf),
1346 nicenum_flags);
1347
1348 curcol += printf("%7s", numbuf);
1349 } else {
1350 uint64_t bsize = p->lsize / block_size;
1351
1352 /*
1353 * Round up only when using blocks > 1 byte, otherwise
1354 * 'normal' sizes display 1 byte too large.
1355 */
1356 if (p->lsize % block_size != 0)
1357 bsize++;
1451 for (i = 0; i < sacnt; i++) {
1452 if (p->exttr[i].name != NULL) {
1453 (void) printf("%s", p->exttr[i].name);
1454 k--;
1455 if (vopt && (k != 0))
1456 (void) printf(",");
1457 }
1458 }
1459 }
1460 (void) printf("}\n");
1461 }
1462 /* Display file timestamps and extended system attribute timestamps */
1463 if (tmflg && alltm) {
1464 new_line();
1465 print_time(p);
1466 new_line();
1467 }
1468 if (vflg) {
1469 new_line();
1470 if (p->aclp) {
1471 int flgs = ACL_SID_FMT;
1472
1473 flgs |= Vflg ? ACL_COMPACT_FMT : 0;
1474 flgs |= (nflg == 1) ? ACL_NORESOLVE : 0;
1475 flgs |= (nflg >= 2) ? ACL_EPHEMERAL : 0;
1476
1477 acl_printacl(p->aclp, num_cols, flgs);
1478 }
1479 }
1480 /* Free extended system attribute lists */
1481 if (saflg || tmflg)
1482 free_sysattr(p);
1483 }
1484
1485 /* print various r,w,x permissions */
1486 static void
1487 pmode(mode_t aflag)
1488 {
1489 /* these arrays are declared static to allow initializations */
1490 static int m0[] = { 1, S_IRUSR, 'r', '-' };
1491 static int m1[] = { 1, S_IWUSR, 'w', '-' };
1492 static int m2[] = { 3, S_ISUID|S_IXUSR, 's', S_IXUSR,
1493 'x', S_ISUID, 'S', '-' };
1494 static int m3[] = { 1, S_IRGRP, 'r', '-' };
1495 static int m4[] = { 1, S_IWGRP, 'w', '-' };
1496 static int m5[] = { 4, S_ISGID|S_IXGRP, 's', S_IXGRP,
1497 'x', S_ISGID|LS_NOTREG, 'S',
2245 } else if (val < c->val) {
2246 parent = &c->lesschild;
2247 c = c->lesschild;
2248 } else {
2249 parent = &c->grtrchild;
2250 c = c->grtrchild;
2251 }
2252 }
2253
2254 /* not in the cache, make a new entry for it */
2255 c = calloc(1, sizeof (struct cachenode));
2256 if (c == NULL) {
2257 perror("ls");
2258 exit(2);
2259 }
2260 *parent = c;
2261 c->val = val;
2262 return (c);
2263 }
2264
2265 /*
2266 * SID MAX String Length: "http://stackoverflow.com/questions/1140528/"
2267 */
2268 #define SID_STR_MAX 185 /* +1 for null char */
2269 static char *
2270 get_sid_name(uid_t id, boolean_t user, boolean_t res)
2271 {
2272 static char *sid = NULL;
2273 char *p = NULL;
2274
2275 if (sid_string_by_id(id, user, &sid, res)) {
2276 if ((p = getname(id)) == NULL) {
2277 /*
2278 * getname() already converts to ephemeral if id
2279 * is not found in passwd or group file(s). This
2280 * should be an extreme case.
2281 */
2282 static char buf[SID_STR_MAX] = {'\0'};
2283
2284 (void) sprintf(buf, "%-8u", (int)id);
2285 p = buf;
2286 }
2287 } else
2288 p = sid;
2289
2290 return (p);
2291 }
2292
2293 /*
2294 * get name from cache, or passwd file for a given uid;
2295 * lastuid is set to uid.
2296 */
2297 static char *
2298 getname(uid_t uid)
2299 {
2300 struct passwd *pwent;
2301 struct cachenode *c;
2302
2303 if ((uid == lastuid) && lastuname)
2304 return (lastuname);
2305
2306 c = findincache(&names, uid);
2307 if (c->initted == 0) {
2308 if ((pwent = getpwuid(uid)) != NULL) {
2309 SCPYN(&c->name[0], pwent->pw_name);
2310 } else {
2311 (void) sprintf(&c->name[0], "%-8u", (int)uid);
2312 }
|